{"model_name":"gpt-5-thinking","codes":{"1":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - start).count();\n    }\n};\n\nstruct Solver {\n    int n;\n    vector<int> x, y;\n    vector<int> r;\n    vector<Rect> rects;\n\n    // aspect ratio limit: width/height and height/width should be <= AR_LIMIT\n    static constexpr int AR_LIMIT = 50;\n    static constexpr int LIMIT_COORD = 10000;\n\n    mt19937_64 rng;\n    Timer timer;\n    double time_limit;\n\n    Solver(int n_, vector<int> x_, vector<int> y_, vector<int> r_, double tl=4.9)\n        : n(n_), x(move(x_)), y(move(y_)), r(move(r_)), time_limit(tl) {\n        rects.resize(n);\n        // seed RNG with time\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        seed ^= (uint64_t)(uintptr_t)this;\n        rng.seed(seed);\n    }\n\n    inline ll area_of(const Rect &rc) const {\n        return (ll)(rc.c - rc.a) * (ll)(rc.d - rc.b);\n    }\n\n    // Compute maximum expansions in each direction for rectangle i against others:\n    // leftMax = how much we can decrease 'a' (grow left) without overlap\n    // rightMax = how much we can increase 'c' (grow right)\n    // downMax = how much we can decrease 'b' (grow down)\n    // upMax = how much we can increase 'd' (grow up)\n    // We do a single O(n) scan to get all four.\n    inline void compute_allowed_expansions(int i, int &leftMax, int &rightMax, int &downMax, int &upMax) const {\n        const Rect &ri = rects[i];\n        int LBound = 0;\n        int RBound = LIMIT_COORD;\n        int DBound = 0;\n        int UBound = LIMIT_COORD;\n\n        for (int j = 0; j < n; ++j) {\n            if (j == i) continue;\n            const Rect &rj = rects[j];\n\n            // Vertical overlap check for horizontal expansion:\n            // overlap on Y iff !(ri.d <= rj.b || rj.d <= ri.b)\n            if (!(ri.d <= rj.b || rj.d <= ri.b)) {\n                // rj is to the right\n                if (rj.a >= ri.c) {\n                    if (rj.a < RBound) RBound = rj.a;\n                }\n                // rj is to the left\n                if (rj.c <= ri.a) {\n                    if (rj.c > LBound) LBound = rj.c;\n                }\n            }\n\n            // Horizontal overlap check for vertical expansion:\n            // overlap on X iff !(ri.c <= rj.a || rj.c <= ri.a)\n            if (!(ri.c <= rj.a || rj.c <= ri.a)) {\n                // rj is above\n                if (rj.b >= ri.d) {\n                    if (rj.b < UBound) UBound = rj.b;\n                }\n                // rj is below\n                if (rj.d <= ri.b) {\n                    if (rj.d > DBound) DBound = rj.d;\n                }\n            }\n        }\n\n        leftMax = max(0, rects[i].a - LBound);\n        rightMax = max(0, RBound - rects[i].c);\n        downMax = max(0, rects[i].b - DBound);\n        upMax = max(0, UBound - rects[i].d);\n    }\n\n    // clamp value within [lo, hi]\n    template <class T>\n    inline T clampv(T v, T lo, T hi) const {\n        if (v < lo) return lo;\n        if (v > hi) return hi;\n        return v;\n    }\n\n    // expand horizontally (left/right) by delta units in total (rounded near),\n    // split between left and right to keep seed near centered. Respect per-side limits.\n    // Return actual area increment (h * applied_delta).\n    inline ll expand_horiz(int i, int delta, int leftMax, int rightMax) {\n        if (delta <= 0 || (leftMax + rightMax) <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int h = ri.d - ri.b;\n\n        int maxDelta = min(delta, leftMax + rightMax);\n        // compute left/right distances to balance around seed\n        int leftDist = x[i] - ri.a;\n        int rightDist = ri.c - x[i] - 1;\n        int diff = rightDist - leftDist; // want l - r = diff\n\n        // l = (delta + diff)/2 rounded\n        int lWanted = (maxDelta + diff) / 2;\n        // adjust rounding\n        if (((maxDelta + diff) & 1) != 0) {\n            // decide rounding direction based on which keeps more balanced\n            // we can just round to nearest\n            // but integer division already floors; add 1 with 50% chance to reduce bias\n        }\n        int l = clampv(lWanted, 0, maxDelta);\n        l = min(l, leftMax);\n        int r = maxDelta - l;\n        if (r > rightMax) {\n            r = rightMax;\n            l = maxDelta - r;\n            l = min(l, leftMax);\n        }\n        // Apply\n        if (l > 0) ri.a -= l;\n        if (r > 0) ri.c += r;\n        return (ll)h * (ll)(l + r);\n    }\n\n    inline ll expand_vert(int i, int delta, int downMax, int upMax) {\n        if (delta <= 0 || (downMax + upMax) <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int h = ri.d - ri.b;\n\n        int maxDelta = min(delta, downMax + upMax);\n        int downDist = y[i] - ri.b;\n        int upDist = ri.d - y[i] - 1;\n        int diff = upDist - downDist; // want d - u = diff? Actually we want down - up = downDist - upDist\n        // For vertical, analogous: l -> down, r -> up\n        // We want: (downTake) - (upTake) = downDist - upDist => downTake = (delta + downDist - upDist)/2\n        int dWanted = (maxDelta + (downDist - upDist)) / 2;\n        int d = clampv(dWanted, 0, maxDelta);\n        d = min(d, downMax);\n        int u = maxDelta - d;\n        if (u > upMax) {\n            u = upMax;\n            d = maxDelta - u;\n            d = min(d, downMax);\n        }\n        if (d > 0) rects[i].b -= d;\n        if (u > 0) rects[i].d += u;\n        return (ll)w * (ll)(d + u);\n    }\n\n    inline ll shrink_horiz(int i, int delta) {\n        if (delta <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int h = ri.d - ri.b;\n        // Max shrink limited by keeping seed inside and width >= 1\n        int shrinkLeftMax = x[i] - ri.a;          // can move 'a' right up to xi\n        int shrinkRightMax = ri.c - (x[i] + 1);   // can move 'c' left down to xi+1\n        int cap = shrinkLeftMax + shrinkRightMax;\n        if (cap <= 0) return 0;\n\n        int maxDelta = min(delta, cap);\n        // Keep seed centered: desire leftTake - rightTake = leftDist - rightDist\n        int leftDist = x[i] - ri.a;\n        int rightDist = ri.c - x[i] - 1;\n        int lWanted = (maxDelta + (leftDist - rightDist)) / 2;\n        int l = clampv(lWanted, 0, maxDelta);\n        l = min(l, shrinkLeftMax);\n        int r = maxDelta - l;\n        if (r > shrinkRightMax) {\n            r = shrinkRightMax;\n            l = maxDelta - r;\n            l = min(l, shrinkLeftMax);\n        }\n        if (l > 0) ri.a += l;\n        if (r > 0) ri.c -= r;\n        return (ll)h * (ll)(l + r);\n    }\n\n    inline ll shrink_vert(int i, int delta) {\n        if (delta <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int h = ri.d - ri.b;\n        int shrinkDownMax = y[i] - ri.b;\n        int shrinkUpMax = ri.d - (y[i] + 1);\n        int cap = shrinkDownMax + shrinkUpMax;\n        if (cap <= 0) return 0;\n\n        int maxDelta = min(delta, cap);\n        int downDist = y[i] - ri.b;\n        int upDist = ri.d - y[i] - 1;\n        int dWanted = (maxDelta + (downDist - upDist)) / 2;\n        int d = clampv(dWanted, 0, maxDelta);\n        d = min(d, shrinkDownMax);\n        int u = maxDelta - d;\n        if (u > shrinkUpMax) {\n            u = shrinkUpMax;\n            d = maxDelta - u;\n            d = min(d, shrinkDownMax);\n        }\n        if (d > 0) ri.b += d;\n        if (u > 0) ri.d -= u;\n        return (ll)w * (ll)(d + u);\n    }\n\n    // Adjust rectangle i towards its target area r[i].\n    // Returns true if rectangle changed.\n    bool adjust_one(int i) {\n        Rect &ri = rects[i];\n        ll s = area_of(ri);\n        ll target = r[i];\n        int w = ri.c - ri.a;\n        int h = ri.d - ri.b;\n\n        if (w <= 0 || h <= 0) return false; // shouldn't happen\n\n        bool changed = false;\n\n        // Allowed expansions\n        int leftMax, rightMax, downMax, upMax;\n        compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n\n        // Aspect ratio guard: restrict total width/height increase permitted to keep w/h <= AR_LIMIT etc.\n        // width limit\n        ll maxWidthByAR = min<ll>(LIMIT_COORD, (ll)AR_LIMIT * (ll)h);\n        int widthAddAR = 0;\n        if ((ll)w < maxWidthByAR) widthAddAR = (int)(maxWidthByAR - (ll)w);\n        int totalHorizCap = min(leftMax + rightMax, widthAddAR);\n        // height limit\n        ll maxHeightByAR = min<ll>(LIMIT_COORD, (ll)AR_LIMIT * (ll)w);\n        int heightAddAR = 0;\n        if ((ll)h < maxHeightByAR) heightAddAR = (int)(maxHeightByAR - (ll)h);\n        int totalVertCap = min(downMax + upMax, heightAddAR);\n\n        s = area_of(ri); // recompute to ensure accuracy\n\n        if (s < target) {\n            // Choose which dimension first to move aspect ratio towards 1 (or sqrt(target) heuristic)\n            bool canHor = (totalHorizCap > 0);\n            bool canVer = (totalVertCap > 0);\n            // current ratio\n            double ratio = (double)w / (double)h;\n            // expand order: if ratio >= 1 expand vertical first to balance; else horizontal first\n            bool horizFirst;\n            if (canHor && canVer) {\n                if (ratio > 1.0) horizFirst = false;\n                else if (ratio < 1.0) horizFirst = true;\n                else {\n                    // tie-break: pick the one with more area capacity\n                    ll capH = (ll)h * (ll)totalHorizCap;\n                    ll capV = (ll)w * (ll)totalVertCap;\n                    horizFirst = (capH >= capV);\n                }\n            } else if (canHor) horizFirst = true;\n            else if (canVer) horizFirst = false;\n            else horizFirst = true; // cannot expand anyway\n\n            if (horizFirst && canHor) {\n                ll incNeed = target - s;\n                // delta = round(incNeed / h)\n                int delta = (int)llround((double)incNeed / (double)h);\n                delta = clampv(delta, 0, totalHorizCap);\n                if (delta > 0) {\n                    expand_horiz(i, delta, leftMax, rightMax);\n                    changed = true;\n                }\n                s = area_of(ri);\n            }\n            if (s < target && canVer) {\n                // recompute allowed for vertical since [a,c] changed\n                compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n                w = rects[i].c - rects[i].a;\n                h = rects[i].d - rects[i].b;\n                // recompute AR constraint on height\n                maxHeightByAR = min<ll>(LIMIT_COORD, (ll)AR_LIMIT * (ll)w);\n                heightAddAR = 0;\n                if ((ll)h < maxHeightByAR) heightAddAR = (int)(maxHeightByAR - (ll)h);\n                totalVertCap = min(downMax + upMax, heightAddAR);\n\n                if (totalVertCap > 0) {\n                    ll incNeed = target - s;\n                    int delta = (int)llround((double)incNeed / (double)w);\n                    delta = clampv(delta, 0, totalVertCap);\n                    if (delta > 0) {\n                        expand_vert(i, delta, downMax, upMax);\n                        changed = true;\n                    }\n                    s = area_of(ri);\n                }\n            }\n\n            // If still s < target but delta rounded to 0 and there is some capacity,\n            // try a micro-step of +1 in the best direction (improves p monotonically for s<r).\n            if (s < target) {\n                // recompute allowed quickly\n                compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n                w = rects[i].c - rects[i].a;\n                h = rects[i].d - rects[i].b;\n                // apply AR constraints\n                maxWidthByAR = min<ll>(LIMIT_COORD, (ll)AR_LIMIT * (ll)h);\n                widthAddAR = 0;\n                if ((ll)w < maxWidthByAR) widthAddAR = (int)(maxWidthByAR - (ll)w);\n                totalHorizCap = min(leftMax + rightMax, widthAddAR);\n                maxHeightByAR = min<ll>(LIMIT_COORD, (ll)AR_LIMIT * (ll)w);\n                heightAddAR = 0;\n                if ((ll)h < maxHeightByAR) heightAddAR = (int)(maxHeightByAR - (ll)h);\n                totalVertCap = min(downMax + upMax, heightAddAR);\n\n                ll bestImprove = -1;\n                int bestMove = -1; // 0=L,1=R,2=D,3=U\n                // Evaluate closeness improvement |s' - r| -> smaller is better\n                auto clos = [&](ll si){ return llabs(si - target); };\n                ll curClos = clos(s);\n                if (leftMax > 0 && totalHorizCap > 0) {\n                    ll s2 = s + h;\n                    ll improve = curClos - clos(s2);\n                    if (improve > bestImprove) bestImprove = improve, bestMove = 0;\n                }\n                if (rightMax > 0 && totalHorizCap > 0) {\n                    ll s2 = s + h;\n                    ll improve = curClos - clos(s2);\n                    if (improve > bestImprove) bestImprove = improve, bestMove = 1;\n                }\n                if (downMax > 0 && totalVertCap > 0) {\n                    ll s2 = s + w;\n                    ll improve = curClos - clos(s2);\n                    if (improve > bestImprove) bestImprove = improve, bestMove = 2;\n                }\n                if (upMax > 0 && totalVertCap > 0) {\n                    ll s2 = s + w;\n                    ll improve = curClos - clos(s2);\n                    if (improve > bestImprove) bestImprove = improve, bestMove = 3;\n                }\n                if (bestImprove > 0 && bestMove >= 0) {\n                    if (bestMove == 0) { rects[i].a -= 1; changed = true; }\n                    else if (bestMove == 1) { rects[i].c += 1; changed = true; }\n                    else if (bestMove == 2) { rects[i].b -= 1; changed = true; }\n                    else if (bestMove == 3) { rects[i].d += 1; changed = true; }\n                }\n            }\n        } else if (s > target) {\n            // Shrink towards target. No need to check overlaps.\n            ll decNeed = s - target;\n\n            // choose dimension to shrink first to balance aspect ratio (if ratio > 1 shrink width first)\n            bool canShrinkH = ((x[i] - ri.a) + (ri.c - (x[i] + 1))) > 0;\n            bool canShrinkV = ((y[i] - ri.b) + (ri.d - (y[i] + 1))) > 0;\n            double ratio = (double)w / (double)h;\n            bool shrinkHFirst;\n            if (canShrinkH && canShrinkV) {\n                if (ratio > 1.0) shrinkHFirst = true;\n                else if (ratio < 1.0) shrinkHFirst = false;\n                else {\n                    // tie-break: larger rate (reduces area faster)\n                    shrinkHFirst = (h >= w);\n                }\n            } else if (canShrinkH) shrinkHFirst = true;\n            else if (canShrinkV) shrinkHFirst = false;\n            else shrinkHFirst = true;\n\n            if (shrinkHFirst && canShrinkH) {\n                int delta = (int)llround((double)decNeed / (double)h);\n                if (delta > 0) {\n                    ll dec = shrink_horiz(i, delta);\n                    if (dec > 0) changed = true;\n                }\n                s = area_of(ri);\n            }\n            if (s > target && canShrinkV) {\n                ll decNeed2 = s - target;\n                int delta2 = (int)llround((double)decNeed2 / (double)w);\n                if (delta2 > 0) {\n                    ll dec = shrink_vert(i, delta2);\n                    if (dec > 0) changed = true;\n                }\n                s = area_of(ri);\n            }\n\n            // micro-shrink if rounding yielded 0\n            if (s > target) {\n                int shrinkLeftMax = x[i] - rects[i].a;\n                int shrinkRightMax = rects[i].c - (x[i] + 1);\n                int shrinkDownMax = y[i] - rects[i].b;\n                int shrinkUpMax = rects[i].d - (y[i] + 1);\n                ll bestImprove = -1;\n                int bestMove = -1; // 0=a+1,1=c-1,2=b+1,3=d-1\n                auto clos = [&](ll si){ return llabs(si - target); };\n                ll curClos = clos(s);\n                if (shrinkLeftMax > 0) {\n                    ll s2 = s - h;\n                    ll improve = curClos - clos(s2);\n                    if (improve > bestImprove) bestImprove = improve, bestMove = 0;\n                }\n                if (shrinkRightMax > 0) {\n                    ll s2 = s - h;\n                    ll improve = curClos - clos(s2);\n                    if (improve > bestImprove) bestImprove = improve, bestMove = 1;\n                }\n                if (shrinkDownMax > 0) {\n                    ll s2 = s - w;\n                    ll improve = curClos - clos(s2);\n                    if (improve > bestImprove) bestImprove = improve, bestMove = 2;\n                }\n                if (shrinkUpMax > 0) {\n                    ll s2 = s - w;\n                    ll improve = curClos - clos(s2);\n                    if (improve > bestImprove) bestImprove = improve, bestMove = 3;\n                }\n                if (bestImprove > 0 && bestMove >= 0) {\n                    if (bestMove == 0) { rects[i].a += 1; changed = true; }\n                    else if (bestMove == 1) { rects[i].c -= 1; changed = true; }\n                    else if (bestMove == 2) { rects[i].b += 1; changed = true; }\n                    else if (bestMove == 3) { rects[i].d -= 1; changed = true; }\n                }\n            }\n        }\n        // Final safety clamps (should be unnecessary if code is correct)\n        ri.a = clampv(ri.a, 0, LIMIT_COORD - 1);\n        ri.c = clampv(ri.c, ri.a + 1, LIMIT_COORD);\n        ri.b = clampv(ri.b, 0, LIMIT_COORD - 1);\n        ri.d = clampv(ri.d, ri.b + 1, LIMIT_COORD);\n        // ensure seed inside\n        if (!(ri.a <= x[i] && x[i] < ri.c && ri.b <= y[i] && y[i] < ri.d)) {\n            // If something bad happened, reset to unit square\n            ri.a = x[i];\n            ri.b = y[i];\n            ri.c = x[i] + 1;\n            ri.d = y[i] + 1;\n            changed = true;\n        }\n        return changed;\n    }\n\n    void solve() {\n        // Initialize all rectangles as unit squares centered at (xi+0.5, yi+0.5)\n        for (int i = 0; i < n; ++i) {\n            rects[i] = Rect{ x[i], y[i], x[i] + 1, y[i] + 1 };\n        }\n\n        // Initial pass: process in descending target area r_i so big ones claim space first\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        stable_sort(order.begin(), order.end(), [&](int a, int b){\n            return r[a] > r[b];\n        });\n\n        for (int id : order) {\n            if (timer.elapsed() > time_limit * 0.4) break; // leave time for improvements\n            adjust_one(id);\n        }\n\n        // Iterative improvement passes until time limit\n        vector<int> idx(n);\n        iota(idx.begin(), idx.end(), 0);\n\n        // We can bias towards ones far from target area\n        auto pass = [&]() {\n            // Optionally sort by |si - ri|\n            // But shuffling is fine; here we pick a hybrid: partial shuffle\n            shuffle(idx.begin(), idx.end(), rng);\n            for (int k = 0; k < n; ++k) {\n                if ((k & 31) == 0 && timer.elapsed() > time_limit) return;\n                int i = idx[k];\n                adjust_one(i);\n            }\n        };\n\n        while (timer.elapsed() < time_limit) {\n            pass();\n        }\n    }\n\n    void output() const {\n        for (int i = 0; i < n; ++i) {\n            const Rect &rc = rects[i];\n            // Output a b c d\n            cout << rc.a << ' ' << rc.b << ' ' << rc.c << ' ' << rc.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    if (!(cin >> n)) return 0;\n    vector<int> x(n), y(n), r(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> x[i] >> y[i] >> r[i];\n    }\n\n    Solver solver(n, x, y, r, 4.85);\n    solver.solve();\n    solver.output();\n\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Fast RNG (xorshift)\nstruct XorShift64 {\n    uint64_t x;\n    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    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int randint(int l, int r) { // inclusive l..r\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Params {\n    double wP;        // weight for immediate p\n    double wDeg;      // weight for degree of next cell\n    double wPot;      // weight for precomputed potential\n    double wTwinPot;  // penalty weight for twin potential\n    double wTwinDeg;  // penalty weight for twin degree\n    double wLook;     // weight for 2-ply lookahead\n    double noise;     // random noise amplitude\n    int avoidDeadMinLen; // avoid moving into dead-end (deg==0) before this many steps, if alternatives exist\n};\n\nstruct PathResult {\n    long long score;\n    string moves;\n    int lengthTiles; // number of tiles visited\n};\n\n// Global constants\nstatic const int H = 50, W = 50, N = H * W;\n\n// Utility to get id from (i,j)\ninline int id_of(int i, int j) { return i * W + j; }\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto time_start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.95; // seconds (precompute+runs)\n\n    int si, sj;\n    if (!(cin >> si >> sj)) {\n        // No input\n        cout << \"\\n\";\n        return 0;\n    }\n\n    vector<int> tile(N), pval(N);\n    int maxTile = -1;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int t; cin >> t;\n            tile[id_of(i, j)] = t;\n            if (t > maxTile) maxTile = t;\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            int pv; cin >> pv;\n            pval[id_of(i, j)] = pv;\n        }\n    }\n\n    // Build tileCells and twin mapping\n    vector<vector<int>> tileCells(M);\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int id = id_of(i, j);\n            tileCells[tile[id]].push_back(id);\n        }\n    }\n    vector<int> twin(N, -1);\n    for (int t = 0; t < M; t++) {\n        if (tileCells[t].size() == 2) {\n            int a = tileCells[t][0];\n            int b = tileCells[t][1];\n            twin[a] = b;\n            twin[b] = a;\n        }\n    }\n\n    // Build allowed neighbor list: edges only across different tiles\n    vector<array<int, 4>> coord(N);\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) coord[id_of(i,j)] = {i,j,0,0}; // only i,j used\n    vector<vector<int>> NB(N);\n    vector<char> UD(N), LR(N); // not used; we will compute moves by coord difference\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = id_of(i, j);\n            // up\n            if (i-1 >= 0) {\n                int v = id_of(i-1, j);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n            // down\n            if (i+1 < H) {\n                int v = id_of(i+1, j);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n            // left\n            if (j-1 >= 0) {\n                int v = id_of(i, j-1);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n            // right\n            if (j+1 < W) {\n                int v = id_of(i, j+1);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n        }\n    }\n\n    // Precompute static potentials: BFS to depth 3 on allowed graph, with decays for p\n    vector<double> pot(N, 0.0);\n    {\n        static const double w1 = 1.0, w2 = 0.6, w3 = 0.3;\n        vector<char> seen(N, 0);\n        vector<int> frontier, nextf;\n        frontier.reserve(64);\n        nextf.reserve(128);\n\n        for (int s = 0; s < N; s++) {\n            fill(seen.begin(), seen.end(), 0);\n            seen[s] = 1;\n            double sum = 0.0;\n\n            frontier.clear();\n            for (int v : NB[s]) if (!seen[v]) { seen[v] = 1; frontier.push_back(v); sum += w1 * pval[v]; }\n\n            // depth 2\n            nextf.clear();\n            for (int v : frontier) {\n                for (int u : NB[v]) if (!seen[u]) { seen[u] = 1; nextf.push_back(u); sum += w2 * pval[u]; }\n            }\n            // depth 3\n            frontier.swap(nextf);\n            nextf.clear();\n            for (int v : frontier) {\n                for (int u : NB[v]) if (!seen[u]) { seen[u] = 1; nextf.push_back(u); sum += w3 * pval[u]; }\n            }\n\n            pot[s] = sum;\n        }\n    }\n\n    // Precompute deg0 for convenience\n    vector<int> deg0(N);\n    for (int i = 0; i < N; i++) deg0[i] = (int)NB[i].size();\n\n    // RNG seed from input to diversify per test\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)si + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    seed ^= (uint64_t)sj + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    XorShift64 rng(seed);\n\n    // helper lambdas\n    auto dynamicDeg = [&](int cell, const vector<char>& tileUsed, int extraTile1 = -1, int extraTile2 = -1) -> int {\n        int cnt = 0;\n        for (int w : NB[cell]) {\n            int tt = tile[w];\n            if (tileUsed[tt]) continue;\n            if (tt == extraTile1 || tt == extraTile2) continue;\n            cnt++;\n        }\n        return cnt;\n    };\n\n    auto direction_char = [&](int u, int v) -> char {\n        int ui = u / W, uj = u % W;\n        int vi = v / W, vj = v % W;\n        if (vi == ui - 1 && vj == uj) return 'U';\n        if (vi == ui + 1 && vj == uj) return 'D';\n        if (vi == ui && vj == uj - 1) return 'L';\n        if (vi == ui && vj == uj + 1) return 'R';\n        // Should not happen if v is neighbor\n        return 'U';\n    };\n\n    // Parameter presets (will also randomize slightly)\n    vector<Params> presets;\n    presets.push_back(Params{1.00, 1.50, 0.050, 0.040, 0.30, 0.40, 1.5, 500});\n    presets.push_back(Params{1.20, 0.80, 0.080, 0.050, 0.20, 0.50, 1.2, 300});\n    presets.push_back(Params{1.00, 1.00, 0.060, 0.040, 0.25, 0.35, 1.5, 700});\n    presets.push_back(Params{1.00, 0.80, 0.030, 0.020, 0.20, 0.60, 1.0, 400});\n    presets.push_back(Params{1.00, 0.50, 0.100, 0.070, 0.15, 0.60, 1.2, 800});\n    presets.push_back(Params{1.40, 0.60, 0.040, 0.030, 0.20, 0.30, 1.5, 200});\n    presets.push_back(Params{1.00, 1.20, 0.070, 0.060, 0.25, 0.45, 1.0, 600});\n\n    auto build_path = [&](const Params& baseParam) -> PathResult {\n        // Slight random variation per run\n        Params P = baseParam;\n        auto jitter = [&](double v, double f=0.15) {\n            // multiply by 1 +/- up to f\n            double m = 1.0 + (rng.next_double() * 2.0 - 1.0) * f;\n            return v * m;\n        };\n        P.wP       = jitter(P.wP,       0.10);\n        P.wDeg     = jitter(P.wDeg,     0.20);\n        P.wPot     = jitter(P.wPot,     0.25);\n        P.wTwinPot = jitter(P.wTwinPot, 0.25);\n        P.wTwinDeg = jitter(P.wTwinDeg, 0.20);\n        P.wLook    = jitter(P.wLook,    0.25);\n        P.noise    = jitter(P.noise,    0.40);\n        int avoidLimit = P.avoidDeadMinLen;\n\n        vector<char> tileUsed(M, 0);\n        int start = id_of(si, sj);\n        tileUsed[tile[start]] = 1;\n\n        long long score = pval[start];\n        int pos = start;\n        string moves;\n        moves.reserve(2000);\n\n        // We'll build until stuck\n        for (int step = 0; ; step++) {\n            // List candidate neighbors whose tile not yet visited\n            vector<int> cand;\n            cand.reserve(4);\n            for (int v : NB[pos]) {\n                int t = tile[v];\n                if (!tileUsed[t]) cand.push_back(v);\n            }\n            if (cand.empty()) break;\n\n            // Precompute degAfter for candidates and check for any non-dead options\n            vector<int> degAfter(cand.size(), 0);\n            bool hasNonDead = false;\n            for (size_t i = 0; i < cand.size(); i++) {\n                degAfter[i] = dynamicDeg(cand[i], tileUsed);\n                if (degAfter[i] > 0) hasNonDead = true;\n            }\n\n            double bestVal = -1e100;\n            int bestV = -1;\n\n            for (size_t idx = 0; idx < cand.size(); idx++) {\n                int v = cand[idx];\n                if (step < avoidLimit && hasNonDead && degAfter[idx] == 0) {\n                    // avoid entering a dead end early if alternatives exist\n                    continue;\n                }\n                double val = 0.0;\n\n                // immediate gain and local features\n                val += P.wP * pval[v];\n                val += P.wPot * pot[v];\n\n                // degree after stepping into v (available next moves)\n                val += P.wDeg * degAfter[idx];\n\n                // penalty for blocking via twin\n                int tv = twin[v];\n                if (tv != -1) {\n                    // twin degree and potential (approximate loss)\n                    int dTwin = dynamicDeg(tv, tileUsed);\n                    val -= P.wTwinDeg * dTwin;\n                    val -= P.wTwinPot * pot[tv];\n                }\n\n                // 2-ply lookahead: best child of v\n                if (degAfter[idx] > 0 && P.wLook > 1e-9) {\n                    double best2 = -1e100;\n                    for (int w : NB[v]) {\n                        int tw = tile[w];\n                        if (tileUsed[tw]) continue;\n                        // deg after moving to w, with v's tile considered newly visited\n                        int deg2 = dynamicDeg(w, tileUsed, tile[v]);\n                        double val2 = 0.0;\n                        val2 += P.wP * pval[w];\n                        val2 += P.wPot * pot[w];\n                        val2 += P.wDeg * deg2;\n                        int t2 = twin[w];\n                        if (t2 != -1) {\n                            int dtwin2 = dynamicDeg(t2, tileUsed, tile[v]);\n                            val2 -= P.wTwinDeg * dtwin2;\n                            val2 -= P.wTwinPot * pot[t2];\n                        }\n                        if (val2 > best2) best2 = val2;\n                    }\n                    if (best2 > -1e90) val += P.wLook * best2;\n                }\n\n                // noise\n                val += (rng.next_double() * 2.0 - 1.0) * P.noise;\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestV = v;\n                }\n            }\n\n            if (bestV == -1) {\n                // If all candidates were dead-ends and we avoided them, but we must choose one; pick the best ignoring avoid\n                bestVal = -1e100;\n                for (int v : cand) {\n                    double val = P.wP * pval[v] + P.wPot * pot[v] + (rng.next_double() * 2.0 - 1.0) * P.noise;\n                    if (val > bestVal) bestVal = val, bestV = v;\n                }\n                if (bestV == -1) break;\n            }\n\n            // Take the move\n            tileUsed[tile[bestV]] = 1;\n            score += pval[bestV];\n            moves.push_back(direction_char(pos, bestV));\n            pos = bestV;\n        }\n\n        PathResult res;\n        res.score = score;\n        res.moves = moves;\n        res.lengthTiles = (int)moves.size() + 1;\n        return res;\n    };\n\n    // Run multiple randomized attempts within time limit\n    long long bestScore = -1;\n    string bestMoves;\n    int runs = 0;\n\n    // Ensure at least one run with default\n    {\n        Params P = presets[0];\n        PathResult r = build_path(P);\n        bestScore = r.score;\n        bestMoves = r.moves;\n        runs++;\n    }\n\n    while (true) {\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - time_start).count();\n        if (elapsed > TIME_LIMIT) break;\n\n        // Pick a preset randomly\n        Params baseP = presets[rng.randint(0, (int)presets.size()-1)];\n\n        // Mildly adapt avoidDeadMinLen with elapsed (later runs may allow more dead-ends to grab value)\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        if (progress > 0.6) {\n            baseP.avoidDeadMinLen = max(0, baseP.avoidDeadMinLen - (int)((progress - 0.6) * 800));\n        }\n\n        PathResult r = build_path(baseP);\n        if (r.score > bestScore) {\n            bestScore = r.score;\n            bestMoves = r.moves;\n        }\n        runs++;\n    }\n\n    // Output best path\n    cout << bestMoves << '\\n';\n\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int H = 30;\n    static constexpr int W = 30;\n    static constexpr int N = H * W;\n    // true generation range\n    static constexpr double WMIN = 1000.0;\n    static constexpr double WMAX = 9000.0;\n    // per-edge deviation clamp\n    static constexpr double DEV_CLAMP = 3000.0;\n\n    // base parameters: row-segment for horizontals, col-segment for verticals\n    // Hseg[i][s] for s=0..2: j in [0..9], [10..19], [20..28]\n    // Vseg[j][s] for s=0..2: i in [0..9], [10..19], [20..28]\n    array<array<double, 3>, H> Hseg;\n    array<array<double, 3>, W> Vseg;\n\n    // per-edge deviations\n    double dev_h[H][W-1];\n    double dev_v[H-1][W];\n\n    // query counter\n    int qid;\n\n    Solver() {\n        // initialize bases to center of allowed range\n        double init = 5000.0;\n        for (int i = 0; i < H; i++) Hseg[i] = {init, init, init};\n        for (int j = 0; j < W; j++) Vseg[j] = {init, init, init};\n        for (int i = 0; i < H; i++) for (int j = 0; j < W-1; j++) dev_h[i][j] = 0.0;\n        for (int i = 0; i < H-1; i++) for (int j = 0; j < W; j++) dev_v[i][j] = 0.0;\n        qid = 0;\n    }\n\n    static inline int segH_from_j(int j) {\n        if (j < 10) return 0;\n        if (j < 20) return 1;\n        return 2; // 20..28\n    }\n    static inline int segV_from_i(int i) {\n        if (i < 10) return 0;\n        if (i < 20) return 1;\n        return 2; // 20..28\n    }\n\n    inline double wh(int i, int j) const { // horizontal edge (i,j)-(i,j+1), j in [0..28]\n        int s = segH_from_j(j);\n        double x = Hseg[i][s] + dev_h[i][j];\n        if (x < WMIN) x = WMIN;\n        if (x > WMAX) x = WMAX;\n        return x;\n    }\n    inline double wv(int i, int j) const { // vertical edge (i,j)-(i+1,j), i in [0..28]\n        int s = segV_from_i(i);\n        double x = Vseg[j][s] + dev_v[i][j];\n        if (x < WMIN) x = WMIN;\n        if (x > WMAX) x = WMAX;\n        return x;\n    }\n\n    struct Node {\n        double d;\n        int i, j;\n        bool operator<(const Node& other) const {\n            return d > other.d; // for min-heap\n        }\n    };\n\n    // compute shortest path under current estimates using Dijkstra\n    string compute_path(int si, int sj, int ti, int tj, double &pred_len) {\n        static double dist[H][W];\n        static int pi[H][W], pj[H][W];\n        static char pdir[H][W];\n\n        for (int i = 0; i < H; i++) {\n            for (int j = 0; j < W; j++) {\n                dist[i][j] = numeric_limits<double>::infinity();\n                pi[i][j] = pj[i][j] = -1;\n                pdir[i][j] = 0;\n            }\n        }\n\n        priority_queue<Node> pq;\n        dist[si][sj] = 0.0;\n        pq.push({0.0, si, sj});\n\n        while (!pq.empty()) {\n            Node cur = pq.top(); pq.pop();\n            int i = cur.i, j = cur.j;\n            if (cur.d != dist[i][j]) continue;\n            if (i == ti && j == tj) break;\n\n            // neighbors: U,D,L,R\n            if (i > 0) {\n                double w = wv(i-1, j);\n                double nd = cur.d + w;\n                if (nd < dist[i-1][j]) {\n                    dist[i-1][j] = nd;\n                    pi[i-1][j] = i; pj[i-1][j] = j; pdir[i-1][j] = 'U';\n                    pq.push({nd, i-1, j});\n                }\n            }\n            if (i+1 < H) {\n                double w = wv(i, j);\n                double nd = cur.d + w;\n                if (nd < dist[i+1][j]) {\n                    dist[i+1][j] = nd;\n                    pi[i+1][j] = i; pj[i+1][j] = j; pdir[i+1][j] = 'D';\n                    pq.push({nd, i+1, j});\n                }\n            }\n            if (j > 0) {\n                double w = wh(i, j-1);\n                double nd = cur.d + w;\n                if (nd < dist[i][j-1]) {\n                    dist[i][j-1] = nd;\n                    pi[i][j-1] = i; pj[i][j-1] = j; pdir[i][j-1] = 'L';\n                    pq.push({nd, i, j-1});\n                }\n            }\n            if (j+1 < W) {\n                double w = wh(i, j);\n                double nd = cur.d + w;\n                if (nd < dist[i][j+1]) {\n                    dist[i][j+1] = nd;\n                    pi[i][j+1] = i; pj[i][j+1] = j; pdir[i][j+1] = 'R';\n                    pq.push({nd, i, j+1});\n                }\n            }\n        }\n\n        // reconstruct path\n        string rev;\n        int ci = ti, cj = tj;\n        while (!(ci == si && cj == sj)) {\n            char c = pdir[ci][cj];\n            rev.push_back(c);\n            int ni = pi[ci][cj], nj = pj[ci][cj];\n            ci = ni; cj = nj;\n        }\n        reverse(rev.begin(), rev.end());\n        pred_len = dist[ti][tj];\n        return rev;\n    }\n\n    struct EdgeUse {\n        bool isH; // true: horizontal; false: vertical\n        int i, j; // for horizontal: edge (i,j)-(i,j+1), j in [0..28]; for vertical: (i,j)-(i+1,j), i in [0..28]\n    };\n\n    // parse path into edges, compute predicted length and feature counts\n    void parse_path_and_features(int si, int sj, const string &path,\n                                 vector<EdgeUse> &edges,\n                                 vector<array<int,3>> &countHseg, // size H: counts per segment\n                                 vector<array<int,3>> &countVseg, // size W: counts per segment\n                                 double &S_pred) {\n        edges.clear();\n        countHseg.assign(H, {0,0,0});\n        countVseg.assign(W, {0,0,0});\n        int i = si, j = sj;\n        S_pred = 0.0;\n\n        for (char c : path) {\n            if (c == 'U') {\n                // use vertical edge (i-1,j)\n                int ei = i - 1, ej = j;\n                edges.push_back({false, ei, ej});\n                int s = segV_from_i(ei);\n                countVseg[ej][s] += 1;\n                double w = wv(ei, ej);\n                S_pred += w;\n                i -= 1;\n            } else if (c == 'D') {\n                int ei = i, ej = j;\n                edges.push_back({false, ei, ej});\n                int s = segV_from_i(ei);\n                countVseg[ej][s] += 1;\n                double w = wv(ei, ej);\n                S_pred += w;\n                i += 1;\n            } else if (c == 'L') {\n                int ei = i, ej = j - 1;\n                edges.push_back({true, ei, ej});\n                int s = segH_from_j(ej);\n                countHseg[ei][s] += 1;\n                double w = wh(ei, ej);\n                S_pred += w;\n                j -= 1;\n            } else if (c == 'R') {\n                int ei = i, ej = j;\n                edges.push_back({true, ei, ej});\n                int s = segH_from_j(ej);\n                countHseg[ei][s] += 1;\n                double w = wh(ei, ej);\n                S_pred += w;\n                j += 1;\n            }\n        }\n    }\n\n    // Update parameters using normalized LMS; devs receive larger share\n    void update_from_observation(int si, int sj, const string &path, long long y) {\n        vector<EdgeUse> edges;\n        vector<array<int,3>> countH; // per row segments\n        vector<array<int,3>> countV; // per col segments\n        double S_pred = 0.0;\n        parse_path_and_features(si, sj, path, edges, countH, countV, S_pred);\n\n        // Error\n        double delta = (double)y - S_pred;\n        int L = (int)edges.size();\n\n        // Compute norms for base features\n        double n_base = 0.0;\n        for (int i = 0; i < H; i++) {\n            for (int s = 0; s < 3; s++) {\n                int c = countH[i][s];\n                if (c) n_base += (double)c * (double)c;\n            }\n        }\n        for (int j = 0; j < W; j++) {\n            for (int s = 0; s < 3; s++) {\n                int c = countV[j][s];\n                if (c) n_base += (double)c * (double)c;\n            }\n        }\n        if (n_base < 1e-9) n_base = 0.0;\n\n        // Learning rates schedule\n        double t = (double)qid / 1000.0; // 0 ... ~1\n        // linearly decrease learning rates over time\n        double eta_dev = (1.0 - t) * 0.75 + t * 0.35;   // from 0.75 to 0.35\n        double eta_base = (1.0 - t) * 0.24 + t * 0.10;  // from 0.24 to 0.10\n        double lambda = 1.0;\n\n        // compute step sizes\n        double alpha_dev = 0.0;\n        if (L > 0) alpha_dev = eta_dev * delta / ( (double)L + lambda );\n\n        double alpha_base = 0.0;\n        if (n_base > 0.0) alpha_base = eta_base * delta / ( n_base + lambda );\n\n        // Update base parameters\n        if (alpha_base != 0.0) {\n            for (int i = 0; i < H; i++) {\n                for (int s = 0; s < 3; s++) {\n                    int c = countH[i][s];\n                    if (c) {\n                        Hseg[i][s] += alpha_base * c;\n                        if (Hseg[i][s] < WMIN) Hseg[i][s] = WMIN;\n                        else if (Hseg[i][s] > WMAX) Hseg[i][s] = WMAX;\n                    }\n                }\n            }\n            for (int j = 0; j < W; j++) {\n                for (int s = 0; s < 3; s++) {\n                    int c = countV[j][s];\n                    if (c) {\n                        Vseg[j][s] += alpha_base * c;\n                        if (Vseg[j][s] < WMIN) Vseg[j][s] = WMIN;\n                        else if (Vseg[j][s] > WMAX) Vseg[j][s] = WMAX;\n                    }\n                }\n            }\n        }\n\n        // Update per-edge deviations\n        if (alpha_dev != 0.0) {\n            for (const auto &e : edges) {\n                if (e.isH) {\n                    dev_h[e.i][e.j] += alpha_dev;\n                    if (dev_h[e.i][e.j] < -DEV_CLAMP) dev_h[e.i][e.j] = -DEV_CLAMP;\n                    else if (dev_h[e.i][e.j] > DEV_CLAMP) dev_h[e.i][e.j] = DEV_CLAMP;\n                } else {\n                    dev_v[e.i][e.j] += alpha_dev;\n                    if (dev_v[e.i][e.j] < -DEV_CLAMP) dev_v[e.i][e.j] = -DEV_CLAMP;\n                    else if (dev_v[e.i][e.j] > DEV_CLAMP) dev_v[e.i][e.j] = DEV_CLAMP;\n                }\n            }\n        }\n\n        // Small deviation decay towards 0 to regularize\n        double decay = (1.0 - t) * 0.0007 + t * 0.0018; // from ~7e-4 to ~1.8e-3\n        if (decay > 0.0) {\n            double mul = 1.0 - decay;\n            for (int i = 0; i < H; i++) {\n                for (int j = 0; j < W-1; j++) {\n                    dev_h[i][j] *= mul;\n                }\n            }\n            for (int i = 0; i < H-1; i++) {\n                for (int j = 0; j < W; j++) {\n                    dev_v[i][j] *= mul;\n                }\n            }\n        }\n\n        qid++;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int k = 0; k < 1000; k++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) {\n            return 0; // input ended unexpectedly\n        }\n\n        double pred_len = 0.0;\n        string path = solver.compute_path(si, sj, ti, tj, pred_len);\n\n        // Output path and flush\n        cout << path << '\\n' << flush;\n\n        long long observed_len;\n        if (!(cin >> observed_len)) {\n            return 0; // interactive judge ended\n        }\n\n        // Update model\n        solver.update_from_observation(si, sj, path, observed_len);\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\nusing namespace std;\n\n// Timer\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\n// Xorshift RNG\nstruct XorShift64 {\n    uint64_t x;\n    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    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n    inline double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n};\n\n// Constants for problem\nstatic const int N_FIX = 20;       // N is fixed to 20\nstatic const int LMIN = 2;\nstatic const int LMAX = 12;\nstatic const int LCOUNT = LMAX - LMIN + 1;\n\n// Key type\nusing u64 = uint64_t;\n\n// Hash map for keys per length\nusing FlatMap = boost::unordered_flat_map<u64,int>;\n\n// Pack a string (vector<uint8_t> codes) into a 64-bit key (3 bits per char)\nstatic inline u64 pack_key(const vector<uint8_t>& codes) {\n    u64 k = 0;\n    for (uint8_t c : codes) {\n        k = (k << 3) | (u64)c;\n    }\n    return k;\n}\nstatic inline u64 pack_key_str(const string& s) {\n    u64 k = 0;\n    for (char ch : s) {\n        uint8_t c = (uint8_t)(ch - 'A'); // 'A'..'H' -> 0..7\n        k = (k << 3) | (u64)c;\n    }\n    return k;\n}\n\n// Main solver\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) {\n        return 0;\n    }\n    vector<string> inputS(M);\n    for (int i = 0; i < M; ++i) cin >> inputS[i];\n\n    // Timer\n    Timer timer;\n    double TIME_LIMIT = 2.85; // seconds; keep margin under 3.0\n\n    // Build unique strings by (length, key)\n    // Map (lenIdx,key) -> uid\n    struct UKeyHasher {\n        size_t operator()(const pair<int,u64>& p) const {\n            // combine lenIdx and key\n            return std::hash<u64>()((p.second << 4) ^ (u64)p.first);\n        }\n    };\n    struct UKeyEq {\n        bool operator()(const pair<int,u64>& a, const pair<int,u64>& b) const {\n            return a.first == b.first && a.second == b.second;\n        }\n    };\n    boost::unordered_flat_map<pair<int,u64>, int, UKeyHasher, UKeyEq> uniqMap;\n    uniqMap.reserve(M*2);\n\n    struct Unique {\n        int len;\n        u64 key;\n        int weight;\n        vector<uint8_t> codes;\n    };\n    vector<Unique> uniqs;\n    uniqs.reserve(M);\n\n    for (int i = 0; i < M; ++i) {\n        const string& s = inputS[i];\n        int L = (int)s.size();\n        int lenIdx = L - LMIN;\n        vector<uint8_t> codes(L);\n        for (int j = 0; j < L; ++j) codes[j] = (uint8_t)(s[j] - 'A');\n        u64 key = pack_key(codes);\n        auto pr = make_pair(lenIdx, key);\n        auto it = uniqMap.find(pr);\n        if (it == uniqMap.end()) {\n            int uid = (int)uniqs.size();\n            uniqMap.emplace(pr, uid);\n            Unique u;\n            u.len = L;\n            u.key = key;\n            u.weight = 1;\n            u.codes = std::move(codes);\n            uniqs.push_back(std::move(u));\n        } else {\n            uniqs[it->second].weight += 1;\n        }\n    }\n    int K = (int)uniqs.size();\n\n    // Build per-length map from key->uid\n    array<FlatMap, LCOUNT> key2uid;\n    for (int li = 0; li < LCOUNT; ++li) {\n        key2uid[li].reserve( (size_t)max(8, K / LCOUNT * 2) );\n    }\n    for (int uid = 0; uid < K; ++uid) {\n        int li = uniqs[uid].len - LMIN;\n        key2uid[li].emplace(uniqs[uid].key, uid);\n    }\n\n    // Precompute shift amounts for bit updates: shift[li][t] = 3*(L-1 - t)\n    int shiftAmt[LCOUNT][LMAX+1]; // t up to L-1, we allocate to len 13 for simplicity\n    for (int li = 0; li < LCOUNT; ++li) {\n        int L = LMIN + li;\n        for (int t = 0; t < L; ++t) {\n            shiftAmt[li][t] = 3 * (L - 1 - t);\n        }\n    }\n\n    // Grid and line representations\n    // g[i][j] in 0..7\n    uint8_t g[N_FIX][N_FIX];\n\n    XorShift64 rng(123456789);\n\n    // Initialize grid: random\n    for (int i = 0; i < N_FIX; ++i) {\n        for (int j = 0; j < N_FIX; ++j) {\n            g[i][j] = (uint8_t)rng.next_int(0,7);\n        }\n    }\n\n    // Seed: embed some unique strings randomly to improve starting score\n    int seeds = min(200, max(60, K/2)); // heuristic\n    for (int t = 0; t < seeds; ++t) {\n        int uid = rng.next_int(0, K-1);\n        const auto& u = uniqs[uid];\n        int L = u.len;\n        if (L > N_FIX) continue; // shouldn't happen, L<=12\n        int dir = rng.next_int(0,1); // 0: row, 1: col\n        int line = rng.next_int(0, N_FIX-1);\n        int start = rng.next_int(0, N_FIX-1);\n        if (dir == 0) {\n            // row\n            int i = line;\n            for (int p = 0; p < L; ++p) {\n                int j = (start + p) % N_FIX;\n                g[i][j] = u.codes[p];\n            }\n        } else {\n            int j = line;\n            for (int p = 0; p < L; ++p) {\n                int i = (start + p) % N_FIX;\n                g[i][j] = u.codes[p];\n            }\n        }\n    }\n\n    // lineChars[40][20]: first 20 rows, next 20 columns\n    uint8_t lineChars[2*N_FIX][N_FIX];\n    for (int i = 0; i < N_FIX; ++i) {\n        for (int j = 0; j < N_FIX; ++j) {\n            lineChars[i][j] = g[i][j];\n            lineChars[N_FIX + j][i] = g[i][j];\n        }\n    }\n\n    // windowsKey and windowsUid\n    // [li][line][start]\n    u64 windowsKey[LCOUNT][2*N_FIX][N_FIX];\n    int  windowsUid[LCOUNT][2*N_FIX][N_FIX];\n    for (int li = 0; li < LCOUNT; ++li) {\n        for (int line = 0; line < 2*N_FIX; ++line) {\n            for (int s = 0; s < N_FIX; ++s) {\n                windowsKey[li][line][s] = 0;\n                windowsUid[li][line][s] = -1;\n            }\n        }\n    }\n\n    // occCount per unique\n    vector<int> occCount(K, 0);\n    vector<char> present(K, 0);\n    long long scoreC = 0;\n\n    // Initialize windowsKey, windowsUid, and occCount\n    for (int li = 0; li < LCOUNT; ++li) {\n        int L = LMIN + li;\n        for (int line = 0; line < 2*N_FIX; ++line) {\n            for (int s = 0; s < N_FIX; ++s) {\n                u64 key = 0;\n                for (int r = 0; r < L; ++r) {\n                    int idx = s + r;\n                    if (idx >= N_FIX) idx -= N_FIX;\n                    key = (key << 3) | (u64)lineChars[line][idx];\n                }\n                windowsKey[li][line][s] = key;\n                auto it = key2uid[li].find(key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    windowsUid[li][line][s] = uid;\n                    if (occCount[uid] == 0) {\n                        scoreC += uniqs[uid].weight;\n                        present[uid] = 1;\n                    }\n                    occCount[uid] += 1;\n                } else {\n                    windowsUid[li][line][s] = -1;\n                }\n            }\n        }\n    }\n\n    // SA / hill climbing\n    // Pre-allocate arrays for delta accumulation per uid\n    vector<int> deltaOcc(K, 0);\n    vector<int> lastStamp(K, -1);\n    vector<int> touched; touched.reserve(512);\n    int stamp = 0;\n\n    auto eval_delta_for_letter = [&](int i, int j, uint8_t newCode) -> long long {\n        uint8_t oldCode = g[i][j];\n        if (newCode == oldCode) return 0;\n        int lineRow = i;\n        int posRow = j;\n        int lineCol = N_FIX + j;\n        int posCol = i;\n        int ocxor = (int)(oldCode ^ newCode);\n\n        ++stamp;\n        touched.clear();\n        long long deltaScore = 0;\n\n        auto accumulate_line = [&](int line, int pos) {\n            for (int li = 0; li < LCOUNT; ++li) {\n                int L = LMIN + li;\n                for (int t = 0; t < L; ++t) {\n                    int s = pos - t;\n                    if (s < 0) s += N_FIX;\n                    int old_uid = windowsUid[li][line][s];\n                    if (old_uid >= 0) {\n                        if (lastStamp[old_uid] != stamp) {\n                            lastStamp[old_uid] = stamp;\n                            deltaOcc[old_uid] = 0;\n                            touched.push_back(old_uid);\n                        }\n                        deltaOcc[old_uid] -= 1;\n                    }\n                    u64 old_key = windowsKey[li][line][s];\n                    int shift = shiftAmt[li][t];\n                    u64 new_key = old_key ^ ((u64)ocxor << shift);\n                    auto it = key2uid[li].find(new_key);\n                    if (it != key2uid[li].end()) {\n                        int uid = it->second;\n                        if (lastStamp[uid] != stamp) {\n                            lastStamp[uid] = stamp;\n                            deltaOcc[uid] = 0;\n                            touched.push_back(uid);\n                        }\n                        deltaOcc[uid] += 1;\n                    }\n                }\n            }\n        };\n\n        accumulate_line(lineRow, posRow);\n        accumulate_line(lineCol, posCol);\n\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto apply_letter = [&](int i, int j, uint8_t newCode) {\n        uint8_t oldCode = g[i][j];\n        if (newCode == oldCode) return;\n        g[i][j] = newCode;\n        // update lineChars\n        lineChars[i][j] = newCode;\n        lineChars[N_FIX + j][i] = newCode;\n\n        int lineRow = i;\n        int posRow = j;\n        int lineCol = N_FIX + j;\n        int posCol = i;\n        int ocxor = (int)(oldCode ^ newCode);\n\n        auto update_line = [&](int line, int pos) {\n            for (int li = 0; li < LCOUNT; ++li) {\n                int L = LMIN + li;\n                for (int t = 0; t < L; ++t) {\n                    int s = pos - t;\n                    if (s < 0) s += N_FIX;\n                    int old_uid = windowsUid[li][line][s];\n                    u64 old_key = windowsKey[li][line][s];\n                    int shift = shiftAmt[li][t];\n                    u64 new_key = old_key ^ ((u64)ocxor << shift);\n                    auto it = key2uid[li].find(new_key);\n                    int new_uid = (it == key2uid[li].end() ? -1 : it->second);\n\n                    // update occCount and scoreC\n                    if (old_uid >= 0) {\n                        occCount[old_uid] -= 1;\n                        if (occCount[old_uid] == 0) {\n                            scoreC -= uniqs[old_uid].weight;\n                            present[old_uid] = 0;\n                        }\n                    }\n                    if (new_uid >= 0) {\n                        if (occCount[new_uid] == 0) {\n                            scoreC += uniqs[new_uid].weight;\n                            present[new_uid] = 1;\n                        }\n                        occCount[new_uid] += 1;\n                    }\n\n                    windowsKey[li][line][s] = new_key;\n                    windowsUid[li][line][s] = new_uid;\n                }\n            }\n        };\n\n        update_line(lineRow, posRow);\n        update_line(lineCol, posCol);\n    };\n\n    // Annealing parameters\n    double T0 = 3.0;   // initial temperature\n    double T1 = 0.01;  // final temperature\n    long long bestScore = scoreC;\n    // Keep best grid in case SA ends worse (unlikely with greedy accept, but safe)\n    uint8_t bestGrid[N_FIX][N_FIX];\n    memcpy(bestGrid, g, sizeof(g));\n\n    // Main loop\n    while (timer.elapsed() < TIME_LIMIT) {\n        int i = rng.next_int(0, N_FIX-1);\n        int j = rng.next_int(0, N_FIX-1);\n        uint8_t oldCode = g[i][j];\n\n        long long bestDelta = LLONG_MIN;\n        uint8_t bestCode = oldCode;\n\n        // try all 7 alternatives\n        for (uint8_t nc = 0; nc < 8; ++nc) {\n            if (nc == oldCode) continue;\n            long long delta = eval_delta_for_letter(i, j, nc);\n            if (delta > bestDelta) {\n                bestDelta = delta;\n                bestCode = nc;\n            }\n        }\n\n        double t = timer.elapsed() / TIME_LIMIT;\n        if (t > 1.0) break;\n        double T = T0 + (T1 - T0) * t;\n\n        bool accept = false;\n        if (bestDelta >= 0) accept = true;\n        else {\n            double prob = exp((double)bestDelta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n        if (accept && bestCode != oldCode) {\n            apply_letter(i, j, bestCode);\n            if (scoreC > bestScore) {\n                bestScore = scoreC;\n                memcpy(bestGrid, g, sizeof(g));\n            }\n        }\n    }\n\n    // Output best grid\n    // Convert codes back to letters\n    for (int i = 0; i < N_FIX; ++i) {\n        string out;\n        out.resize(N_FIX);\n        for (int j = 0; j < N_FIX; ++j) {\n            char ch = (char)('A' + bestGrid[i][j]);\n            out[j] = ch;\n        }\n        cout << out << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist;\n    vector<int> matchL, matchR;\n\n    HopcroftKarp(int nL_, int nR_) : nL(nL_), nR(nR_), g(nL_), dist(nL_), matchL(nL_, -1), matchR(nR_, -1) {}\n\n    void add_edge(int u, int v) {\n        g[u].push_back(v);\n    }\n\n    bool bfs() {\n        queue<int> q;\n        for (int i = 0; i < nL; ++i) {\n            if (matchL[i] == -1) {\n                dist[i] = 0;\n                q.push(i);\n            } else {\n                dist[i] = -1;\n            }\n        }\n        bool found = false;\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; // there exists an augmenting path\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    bool dfs(int u) {\n        for (int v : g[u]) {\n            int u2 = matchR[v];\n            if (u2 == -1 || (dist[u2] == dist[u] + 1 && dfs(u2))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int max_matching() {\n        int res = 0;\n        while (bfs()) {\n            for (int i = 0; i < nL; ++i) {\n                if (matchL[i] == -1) {\n                    if (dfs(i)) ++res;\n                }\n            }\n        }\n        return res;\n    }\n\n    pair<vector<char>, vector<char>> min_vertex_cover() {\n        // Find Z: vertices reachable from unmatched left vertices in the alternating graph\n        vector<char> visL(nL, 0), visR(nR, 0);\n        queue<int> q;\n        for (int u = 0; u < nL; ++u) {\n            if (matchL[u] == -1) {\n                visL[u] = 1;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                if (matchL[u] != v) {\n                    // unmatched edge u -> v\n                    if (!visR[v]) {\n                        visR[v] = 1;\n                        int u2 = matchR[v];\n                        if (u2 != -1 && !visL[u2]) {\n                            visL[u2] = 1;\n                            q.push(u2);\n                        }\n                    }\n                }\n            }\n        }\n        vector<char> coverL(nL, 0), coverR(nR, 0);\n        for (int u = 0; u < nL; ++u) {\n            if (!visL[u]) coverL[u] = 1;\n        }\n        for (int v = 0; v < nR; ++v) {\n            if (visR[v]) coverR[v] = 1;\n        }\n        return {coverL, coverR};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, si, sj;\n    if (!(cin >> N >> si >> sj)) {\n        return 0;\n    }\n    vector<string> c(N);\n    for (int i = 0; i < N; ++i) cin >> c[i];\n\n    const int H = N, W = N;\n    const int M = H * W;\n    auto id = [&](int i, int j) { return i * W + j; };\n\n    vector<int> w(M, -1);\n    vector<char> isRoad(M, 0);\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            if (c[i][j] != '#') {\n                isRoad[id(i,j)] = 1;\n                w[id(i,j)] = c[i][j] - '0';\n            }\n        }\n    }\n\n    // Build row segments\n    vector<int> rowSegId(M, -1), colSegId(M, -1);\n    vector<vector<int>> rowSegCells;\n    for (int i = 0; i < H; ++i) {\n        int j = 0;\n        while (j < W) {\n            if (isRoad[id(i,j)] && (j == 0 || !isRoad[id(i, j-1)])) {\n                int j2 = j;\n                int segId = (int)rowSegCells.size();\n                rowSegCells.emplace_back();\n                while (j2 < W && isRoad[id(i,j2)]) {\n                    rowSegId[id(i,j2)] = segId;\n                    rowSegCells.back().push_back(id(i,j2));\n                    ++j2;\n                }\n                j = j2;\n            } else {\n                ++j;\n            }\n        }\n    }\n    // Build column segments\n    vector<vector<int>> colSegCells;\n    for (int j = 0; j < W; ++j) {\n        int i = 0;\n        while (i < H) {\n            if (isRoad[id(i,j)] && (i == 0 || !isRoad[id(i-1, j)])) {\n                int i2 = i;\n                int segId = (int)colSegCells.size();\n                colSegCells.emplace_back();\n                while (i2 < H && isRoad[id(i2,j)]) {\n                    colSegId[id(i2,j)] = segId;\n                    colSegCells.back().push_back(id(i2,j));\n                    ++i2;\n                }\n                i = i2;\n            } else {\n                ++i;\n            }\n        }\n    }\n\n    int nR = (int)rowSegCells.size();\n    int nC = (int)colSegCells.size();\n\n    // Build bipartite graph: row segments -> column segments (edges for each road cell)\n    HopcroftKarp hk(nR, nC);\n    // To avoid any accidental duplicate edges (shouldn't happen), we can use a marker if needed.\n    // But in this construction each row seg intersects a column seg at most once.\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int u = id(i,j);\n            if (!isRoad[u]) continue;\n            int rseg = rowSegId[u];\n            int cseg = colSegId[u];\n            if (rseg >= 0 && cseg >= 0) {\n                hk.add_edge(rseg, cseg);\n            }\n        }\n    }\n\n    hk.max_matching();\n    auto [chooseRow_char, chooseCol_char] = hk.min_vertex_cover();\n\n    vector<char> chooseRow = chooseRow_char;\n    vector<char> chooseCol = chooseCol_char;\n\n    // Coverage flags\n    vector<char> coveredRow(nR, 0), coveredCol(nC, 0);\n\n    // Dijkstra helpers\n    const int INF = 1e9;\n    vector<int> dist(M, INF), prv(M, -1);\n    vector<char> prvDir(M, 0);\n\n    auto inb = [&](int i, int j){ return (0 <= i && i < H && 0 <= j && j < W); };\n\n    int start = id(si, sj);\n    int cur = start;\n\n    auto mark_covered_at_cell = [&](int u) {\n        int rs = rowSegId[u];\n        int cs = colSegId[u];\n        int changed = 0;\n        if (rs >= 0 && chooseRow[rs] && !coveredRow[rs]) { coveredRow[rs] = 1; changed++; }\n        if (cs >= 0 && chooseCol[cs] && !coveredCol[cs]) { coveredCol[cs] = 1; changed++; }\n        return changed;\n    };\n\n    long long remain = 0;\n    for (int i = 0; i < nR; ++i) if (chooseRow[i]) remain++;\n    for (int i = 0; i < nC; ++i) if (chooseCol[i]) remain++;\n\n    // Mark coverage at start\n    remain -= mark_covered_at_cell(cur);\n\n    string ans;\n\n    auto reconstruct_and_apply = [&](int s, int t, string &route) {\n        // reconstruct path from s to t using prv/prvDir arrays (computed by latest Dijkstra)\n        vector<char> moves;\n        int x = t;\n        if (s == t) return; // no moves\n        while (x != s && x != -1) {\n            moves.push_back(prvDir[x]);\n            x = prv[x];\n        }\n        if (x != s) {\n            // Shouldn't happen if Dijkstra found a path; but guard\n            return;\n        }\n        reverse(moves.begin(), moves.end());\n        // simulate moves to update coverage and append to route\n        int i = cur / W, j = cur % W;\n        for (char mv : moves) {\n            if (mv == 'U') --i;\n            else if (mv == 'D') ++i;\n            else if (mv == 'L') --j;\n            else if (mv == 'R') ++j;\n            int nid = id(i,j);\n            remain -= mark_covered_at_cell(nid);\n            route.push_back(mv);\n        }\n        cur = id(i,j);\n    };\n\n    // Dijkstra to nearest target (union of uncovered chosen segments), preferring intersection\n    auto dijkstra_to_next_target = [&]() -> int {\n        // initialize\n        for (int k = 0; k < M; ++k) {\n            dist[k] = INF;\n            prv[k] = -1;\n            prvDir[k] = 0;\n        }\n        struct Node { int d, u; };\n        struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n        priority_queue<Node, vector<Node>, Cmp> pq;\n        dist[cur] = 0;\n        pq.push({0, cur});\n\n        auto is_target_union = [&](int u)->bool {\n            int rs = rowSegId[u];\n            int cs = colSegId[u];\n            if (rs >= 0 && chooseRow[rs] && !coveredRow[rs]) return true;\n            if (cs >= 0 && chooseCol[cs] && !coveredCol[cs]) return true;\n            return false;\n        };\n        auto is_target_intersection = [&](int u)->bool {\n            int rs = rowSegId[u];\n            int cs = colSegId[u];\n            bool r = (rs >= 0 && chooseRow[rs] && !coveredRow[rs]);\n            bool c = (cs >= 0 && chooseCol[cs] && !coveredCol[cs]);\n            return r && c;\n        };\n\n        int best_union_idx = -1, best_union_dist = INF;\n        int best_inter_idx = -1, best_inter_dist = INF;\n        const int LOOKAHEAD_MARGIN = 25; // additive margin to search for an intersection\n        int limit = INF;\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n\n            // Early stopping conditions\n            if (best_inter_idx != -1 && d >= best_inter_dist) break;\n            if (best_union_idx != -1 && d > limit) break;\n\n            // Check target membership\n            if (is_target_union(u)) {\n                if (d < best_union_dist) {\n                    best_union_dist = d;\n                    best_union_idx = u;\n                    limit = best_union_dist + LOOKAHEAD_MARGIN;\n                }\n                if (is_target_intersection(u)) {\n                    if (d < best_inter_dist) {\n                        best_inter_dist = d;\n                        best_inter_idx = u;\n                        // We can keep going until queue's top >= best_inter_dist for correctness of early stop above\n                    }\n                }\n            }\n\n            int ui = u / W, uj = u % W;\n            // neighbors\n            // U\n            if (ui-1 >= 0) {\n                int v = id(ui-1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'U';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            // D\n            if (ui+1 < H) {\n                int v = id(ui+1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'D';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            // L\n            if (uj-1 >= 0) {\n                int v = id(ui, uj-1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'L';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            // R\n            if (uj+1 < W) {\n                int v = id(ui, uj+1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'R';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n        }\n\n        if (best_inter_idx != -1) return best_inter_idx;\n        if (best_union_idx != -1) return best_union_idx;\n        // Fallback: if somehow no target found (shouldn't happen), return current\n        return cur;\n    };\n\n    auto dijkstra_to_single = [&](int target) {\n        for (int k = 0; k < M; ++k) {\n            dist[k] = INF;\n            prv[k] = -1;\n            prvDir[k] = 0;\n        }\n        struct Node { int d, u; };\n        struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n        priority_queue<Node, vector<Node>, Cmp> pq;\n        dist[cur] = 0;\n        pq.push({0, cur});\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (u == target) break;\n            int ui = u / W, uj = u % W;\n            // neighbors\n            if (ui-1 >= 0) {\n                int v = id(ui-1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'U';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            if (ui+1 < H) {\n                int v = id(ui+1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'D';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            if (uj-1 >= 0) {\n                int v = id(ui, uj-1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'L';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            if (uj+1 < W) {\n                int v = id(ui, uj+1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'R';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n        }\n    };\n\n    // Greedy routing\n    while (remain > 0) {\n        int dest = dijkstra_to_next_target();\n        // Reconstruct and apply path to dest\n        reconstruct_and_apply(cur, dest, ans);\n        // In rare fallback case dest == cur and no coverage changed, to avoid infinite loop, break.\n        if (cur == dest) {\n            // Try to find any uncovered segment cell explicitly\n            int fallbackDest = -1;\n            for (int u = 0; u < M; ++u) {\n                if (!isRoad[u]) continue;\n                int rs = rowSegId[u], cs = colSegId[u];\n                bool target = (rs >= 0 && chooseRow[rs] && !coveredRow[rs]) ||\n                              (cs >= 0 && chooseCol[cs] && !coveredCol[cs]);\n                if (target) { fallbackDest = u; break; }\n            }\n            if (fallbackDest == -1) break; // should not happen\n            dijkstra_to_single(fallbackDest);\n            reconstruct_and_apply(cur, fallbackDest, ans);\n        }\n    }\n\n    // Return to start\n    if (cur != start) {\n        dijkstra_to_single(start);\n        reconstruct_and_apply(cur, start, ans);\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct FastRNG {\n    uint64_t x;\n    FastRNG(uint64_t seed=88172645463393265ull) : x(seed) {}\n    uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    double drand() { return (next() >> 11) * (1.0/9007199254740992.0); } // [0,1)\n    double gauss() { // Box-Muller\n        double u1 = max(1e-12, drand());\n        double u2 = drand();\n        return sqrt(-2.0*log(u1)) * cos(2.0*M_PI*u2);\n    }\n    double uni(double a, double b){ return a + (b-a)*drand(); }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K, R;\n    if(!(cin >> N >> M >> K >> R)) return 0;\n\n    vector<vector<int>> D(N, vector<int>(K));\n    vector<double> sumD(N, 0.0);\n    vector<double> meanD(K, 0.0);\n    for(int i=0;i<N;i++){\n        double s=0.0;\n        for(int k=0;k<K;k++){\n            cin >> D[i][k];\n            s += D[i][k];\n            meanD[k] += D[i][k];\n        }\n        sumD[i] = s;\n    }\n    for(int k=0;k<K;k++) meanD[k] /= N;\n\n    vector<vector<int>> G(N);\n    vector<int> indeg(N, 0);\n    for(int e=0;e<R;e++){\n        int u,v; cin >> u >> v; --u; --v;\n        G[u].push_back(v);\n        indeg[v]++;\n    }\n    // Longest path dp (unweighted edges)\n    vector<int> dp(N, 1), outdeg(N);\n    for(int i=N-1;i>=0;--i){\n        int best=0;\n        for(int v: G[i]) best = max(best, dp[v]);\n        dp[i] = 1 + best;\n        outdeg[i] = (int)G[i].size();\n    }\n    int dpMax = *max_element(dp.begin(), dp.end());\n    double sumDmax = *max_element(sumD.begin(), sumD.end());\n    int outMax = *max_element(outdeg.begin(), outdeg.end());\n    if(sumDmax <= 0) sumDmax = 1.0;\n    if(dpMax <= 0) dpMax = 1;\n    if(outMax <= 0) outMax = 1;\n\n    // Base priority for tasks (normalized linear combination)\n    vector<double> basePri(N);\n    const double wDepth = 1.0;\n    const double wOut = 0.3;\n    const double wDiff = 0.2;\n    for(int i=0;i<N;i++){\n        double nd = (double)dp[i] / dpMax;\n        double no = (double)outdeg[i] / outMax;\n        double nf = sumD[i] / sumDmax;\n        basePri[i] = wDepth*nd + wOut*no + wDiff*nf;\n    }\n\n    // Ready tasks as a max-heap by base priority\n    struct Node { double key; int id; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.key < b.key; } };\n    priority_queue<Node, vector<Node>, Cmp> readyPQ;\n    vector<char> in_ready(N, 0), started(N, 0), done(N, 0);\n\n    for(int i=0;i<N;i++){\n        if(indeg[i]==0){\n            readyPQ.push({basePri[i], i});\n            in_ready[i]=1;\n        }\n    }\n\n    // Member state\n    vector<int> workerTask(M, -1);\n    vector<int> workerStart(M, 0);\n\n    // Skill estimates\n    FastRNG rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    vector<vector<double>> S(M, vector<double>(K, 0.0));\n    // Initialize: scale meanD by ~1.5, add tiny noise to break ties\n    for(int j=0;j<M;j++){\n        for(int k=0;k<K;k++){\n            double val = meanD[k] * 1.5 + rng.uni(-0.5, 0.5);\n            if(val < 0) val = 0;\n            S[j][k] = val;\n        }\n    }\n    vector<int> obsCnt(M, 0);\n\n    auto softplus_sum = [&](const vector<int>& dvec, const vector<double>& svec, double beta)->double{\n        double res=0.0;\n        for(int k=0;k<K;k++){\n            double x = dvec[k] - svec[k];\n            // softplus(beta*x)/beta with numeric stability\n            double bx = beta * x;\n            if (bx > 30.0) {\n                res += (bx) / beta; // ~x\n            } else if (bx < -30.0) {\n                // ~0\n            } else {\n                res += log1p(exp(bx)) / beta;\n            }\n        }\n        return res;\n    };\n    auto sigmoid_beta = [&](double x, double beta)->double{\n        double bx = beta * x;\n        if (bx >= 0) {\n            double e = exp(-bx);\n            return 1.0 / (1.0 + e);\n        } else {\n            double e = exp(bx);\n            return e / (1.0 + e);\n        }\n    };\n    auto relu_sum = [&](const vector<int>& dvec, const vector<double>& svec)->double{\n        double w=0.0;\n        for(int k=0;k<K;k++){\n            double z = (double)dvec[k] - svec[k];\n            if(z > 0) w += z;\n        }\n        return w;\n    };\n    auto predict_time = [&](int i, int j)->double{\n        double w = relu_sum(D[i], S[j]);\n        double p = (w <= 0.0 ? 1.0 : w + 1.0);\n        if (p < 1.0) p = 1.0;\n        return p;\n    };\n\n    const double beta = 0.2;   // softplus/sigmoid smoothing\n    const double Smax = 100.0; // clamp\n    const double baseLR = 0.4; // learning rate base\n\n    auto update_skill = [&](int j, int i, int t){\n        // SGD on smoothed hinge\n        double wsoft = softplus_sum(D[i], S[j], beta);\n        double pred = wsoft + 1.0;\n        double target = max(1, t);\n        double err = pred - target;\n        double lr = baseLR / sqrt((double)obsCnt[j] + 1.0);\n        if (t <= 1) lr *= 0.25; // reduce noisy updates on t=1\n        // Optional: cap err influence\n        if (err > 10) err = 10;\n        if (err < -10) err = -10;\n        for(int k=0;k<K;k++){\n            double g = sigmoid_beta((double)D[i][k] - S[j][k], beta); // d softplus / d s = -sigmoid, we use +g*err\n            double delta = lr * err * g;\n            double ns = S[j][k] + delta;\n            if (ns < 0) ns = 0;\n            if (ns > Smax) ns = Smax;\n            S[j][k] = ns;\n        }\n        obsCnt[j]++;\n    };\n\n    int finishedCount = 0;\n    int day = 0;\n\n    while(true){\n        day++;\n\n        // Build list of free workers\n        vector<int> freeWorkers;\n        freeWorkers.reserve(M);\n        for(int j=0;j<M;j++) if(workerTask[j] == -1) freeWorkers.push_back(j);\n\n        vector<pair<int,int>> assignments; // (worker, task)\n\n        if(!freeWorkers.empty()){\n            // Extract a pool of top-priority ready tasks\n            int poolTarget = min((int)readyPQ.size(), max( (int)freeWorkers.size() * 8, 16 ));\n            poolTarget = min(poolTarget, 200); // cap\n            vector<int> pool; pool.reserve(poolTarget);\n            vector<Node> stash; stash.reserve(poolTarget);\n            for(int c=0;c<poolTarget; ++c){\n                if(readyPQ.empty()) break;\n                Node nd = readyPQ.top(); readyPQ.pop();\n                // Keep it in stash (to reinsert later if not assigned)\n                stash.push_back(nd);\n                pool.push_back(nd.id);\n            }\n\n            // Greedy assignment: pick best pairs by predicted time\n            int C = (int)pool.size();\n            if(C > 0){\n                // Precompute predicted times matrix (C x free)\n                // For efficient greedy, we keep best task per worker, then global best\n                vector<char> taskTaken(C, 0);\n                vector<int> bestTaskIdxForWorker(freeWorkers.size(), -1);\n                vector<double> bestCostForWorker(freeWorkers.size(), 1e100);\n\n                // Precompute all costs on the fly when needed\n                auto recompute_best_for = [&](int widx){\n                    int j = freeWorkers[widx];\n                    int besti = -1;\n                    double bestc = 1e100;\n                    for(int pi=0; pi<C; ++pi){\n                        if(taskTaken[pi]) continue;\n                        int ti = pool[pi];\n                        double cost = predict_time(ti, j);\n                        if(cost < bestc){\n                            bestc = cost; besti = pi;\n                        }\n                    }\n                    bestTaskIdxForWorker[widx] = besti;\n                    bestCostForWorker[widx] = bestc;\n                };\n                // Initialize best per worker\n                for(int widx=0; widx<(int)freeWorkers.size(); ++widx){\n                    recompute_best_for(widx);\n                }\n                // Global greedy via heap of workers by their best cost\n                struct WNode { double cost; int widx; int tpi; };\n                struct WCmp { bool operator()(const WNode& a, const WNode& b) const { return a.cost > b.cost; } };\n                priority_queue<WNode, vector<WNode>, WCmp> pq;\n                for(int widx=0; widx<(int)freeWorkers.size(); ++widx){\n                    if(bestTaskIdxForWorker[widx] != -1){\n                        pq.push({bestCostForWorker[widx], widx, bestTaskIdxForWorker[widx]});\n                    }\n                }\n                vector<char> workerTaken(freeWorkers.size(), 0);\n                while(!pq.empty()){\n                    auto top = pq.top(); pq.pop();\n                    int widx = top.widx;\n                    int tpi = top.tpi;\n                    if(workerTaken[widx]) continue;\n                    if(tpi == -1) continue;\n                    if(taskTaken[tpi]) {\n                        // Recompute and push again\n                        recompute_best_for(widx);\n                        if(bestTaskIdxForWorker[widx] != -1){\n                            pq.push({bestCostForWorker[widx], widx, bestTaskIdxForWorker[widx]});\n                        }\n                        continue;\n                    }\n                    // Assign this pair\n                    int j = freeWorkers[widx];\n                    int ti = pool[tpi];\n                    assignments.emplace_back(j, ti);\n                    workerTaken[widx] = 1;\n                    taskTaken[tpi] = 1;\n                    // We stop if we've assigned all free workers\n                    if((int)assignments.size() >= (int)freeWorkers.size()) break;\n                    // Other workers who had this task as best will refresh when popped\n                }\n\n                // Reinsert unassigned tasks back into readyPQ\n                for(int pi=0; pi<C; ++pi){\n                    if(!taskTaken[pi]){\n                        // put back\n                        readyPQ.push({basePri[pool[pi]], pool[pi]});\n                    } else {\n                        // This one is assigned; mark it out of ready\n                        in_ready[pool[pi]] = 0; // will mark started below\n                    }\n                }\n            } else {\n                // No ready tasks yet: no assignments\n            }\n        }\n\n        // Emit output: m a1 b1 ...\n        cout << assignments.size();\n        for(auto &p: assignments){\n            int j = p.first;\n            int i = p.second;\n            cout << \" \" << (j+1) << \" \" << (i+1);\n            // update state\n            workerTask[j] = i;\n            workerStart[j] = day;\n            started[i] = 1;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        // Read feedback\n        int ncomp;\n        if(!(cin >> ncomp)) return 0;\n        if(ncomp == -1){\n            // finished or day limit\n            return 0;\n        }\n        vector<int> fins(ncomp);\n        for(int idx=0; idx<ncomp; ++idx){\n            int fj; cin >> fj; --fj;\n            fins[idx] = fj;\n        }\n        sort(fins.begin(), fins.end());\n        fins.erase(unique(fins.begin(), fins.end()), fins.end());\n        // Process completions\n        for(int fj : fins){\n            int i = workerTask[fj];\n            if(i < 0){\n                // Should not happen, but be safe\n                continue;\n            }\n            int t = day - workerStart[fj] + 1;\n            // Learn\n            update_skill(fj, i, t);\n            // Update state\n            workerTask[fj] = -1;\n            done[i] = 1;\n            finishedCount++;\n            // Unlock children for next day\n            for(int v: G[i]){\n                indeg[v]--;\n                if(indeg[v] == 0 && !started[v] && !done[v] && !in_ready[v]){\n                    readyPQ.push({basePri[v], v});\n                    in_ready[v] = 1;\n                }\n            }\n        }\n        // Loop to next day\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 88172645463393265ull) { x = seed; }\n    inline uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int randint(int l, int r) { // inclusive\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    inline double drand() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstatic inline int manhattan(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\nstruct Order {\n    int id; // 0-based original index\n    int ax, ay, cx, cy; // pickup (a,b), drop (c,d)\n};\n\nstruct Event {\n    int oid; // 0..m-1 (index in selected array)\n    bool is_pick; // true: pickup, false: drop\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 1000;\n    vector<Order> all(N);\n    for (int i = 0; i < N; ++i) {\n        int a, b, c, d;\n        if (!(cin >> a >> b >> c >> d)) {\n            return 0;\n        }\n        all[i] = {i, a, b, c, d};\n    }\n    const int OFFICE_X = 400;\n    const int OFFICE_Y = 400;\n    const int M = 50; // number of orders to choose\n\n    auto s_cost = [&](const Order& o)->long long {\n        long long s = 0;\n        s += manhattan(OFFICE_X, OFFICE_Y, o.ax, o.ay);\n        s += manhattan(o.ax, o.ay, o.cx, o.cy);\n        s += manhattan(o.cx, o.cy, OFFICE_X, OFFICE_Y);\n        return s;\n    };\n\n    // Select 50 orders with smallest s_cost\n    vector<pair<long long,int>> score_idx;\n    score_idx.reserve(N);\n    for (int i = 0; i < N; ++i) score_idx.emplace_back(s_cost(all[i]), i);\n    nth_element(score_idx.begin(), score_idx.begin() + M, score_idx.end());\n    score_idx.resize(M);\n    sort(score_idx.begin(), score_idx.end()); // deterministic\n\n    vector<int> selected_orig_ids;\n    selected_orig_ids.reserve(M);\n    for (auto &p : score_idx) selected_orig_ids.push_back(p.second);\n\n    // Build arrays for selected orders, remap to 0..M-1\n    vector<Order> sel(M);\n    for (int i = 0; i < M; ++i) sel[i] = all[selected_orig_ids[i]];\n    // coords arrays for faster access\n    vector<int> px(M), py(M), dx(M), dy(M);\n    for (int i = 0; i < M; ++i) {\n        px[i] = sel[i].ax; py[i] = sel[i].ay;\n        dx[i] = sel[i].cx; dy[i] = sel[i].cy;\n    }\n\n    // Build initial route: greedy\n    vector<Event> seq;\n    seq.reserve(2*M);\n    vector<char> picked(M, 0), delivered(M, 0);\n    int curx = OFFICE_X, cury = OFFICE_Y;\n    int remain_delivered = 0;\n    const double alpha_pick_penalty = 0.2; // small penalty for pickup: add alpha * pick->drop\n    while (remain_delivered < M) {\n        int best_oid = -1;\n        bool best_is_pick = true;\n        double best_score = 1e100;\n\n        // Candidates: unvisited pickups\n        for (int i = 0; i < M; ++i) if (!picked[i]) {\n            int nx = px[i], ny = py[i];\n            int base = manhattan(curx, cury, nx, ny);\n            int pd = manhattan(px[i], py[i], dx[i], dy[i]);\n            double sc = base + alpha_pick_penalty * pd;\n            if (sc < best_score) {\n                best_score = sc;\n                best_oid = i;\n                best_is_pick = true;\n            }\n        }\n        // Candidates: deliveries whose pickup done and not delivered\n        for (int i = 0; i < M; ++i) if (picked[i] && !delivered[i]) {\n            int nx = dx[i], ny = dy[i];\n            int base = manhattan(curx, cury, nx, ny);\n            double sc = base; // no extra penalty\n            if (sc < best_score) {\n                best_score = sc;\n                best_oid = i;\n                best_is_pick = false;\n            }\n        }\n\n        // If no deliverable delivery yet (at the very beginning), best_is_pick will be true; otherwise, pick the best candidate.\n        if (best_oid == -1) {\n            // Shouldn't happen; fallback: pick closest pickup\n            int bestd = INT_MAX, bi = -1;\n            for (int i = 0; i < M; ++i) if (!picked[i]) {\n                int d = manhattan(curx, cury, px[i], py[i]);\n                if (d < bestd) { bestd = d; bi = i; }\n            }\n            best_oid = bi;\n            best_is_pick = true;\n        }\n\n        if (best_is_pick) {\n            picked[best_oid] = 1;\n            seq.push_back({best_oid, true});\n            curx = px[best_oid]; cury = py[best_oid];\n        } else {\n            delivered[best_oid] = 1;\n            seq.push_back({best_oid, false});\n            curx = dx[best_oid]; cury = dy[best_oid];\n            remain_delivered++;\n        }\n    }\n\n    // Utility lambdas for route cost and coords\n    auto coord_of_event = [&](const Event &e) -> pair<int,int> {\n        if (e.is_pick) return {px[e.oid], py[e.oid]};\n        else return {dx[e.oid], dy[e.oid]};\n    };\n    auto route_cost = [&](const vector<Event> &s)->long long {\n        long long t = 0;\n        int lx = OFFICE_X, ly = OFFICE_Y;\n        for (auto &e : s) {\n            auto [nx, ny] = coord_of_event(e);\n            t += manhattan(lx, ly, nx, ny);\n            lx = nx; ly = ny;\n        }\n        t += manhattan(lx, ly, OFFICE_X, OFFICE_Y);\n        return t;\n    };\n\n    int L = (int)seq.size(); // should be 2*M\n    // Build pos arrays\n    vector<int> posPick(M, -1), posDel(M, -1);\n    for (int i = 0; i < L; ++i) {\n        if (seq[i].is_pick) posPick[seq[i].oid] = i;\n        else posDel[seq[i].oid] = i;\n    }\n\n    // SA preparation\n    RNG rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n    long long cur_cost = route_cost(seq);\n    long long best_cost = cur_cost;\n    vector<Event> best_seq = seq;\n\n    auto get_coord_by_index = [&](int idx)->pair<int,int>{\n        // idx in [0..L-1]\n        const Event &e = seq[idx];\n        if (e.is_pick) return {px[e.oid], py[e.oid]};\n        else return {dx[e.oid], dy[e.oid]};\n    };\n\n    auto delta_move_single = [&](int p, int q)->long long {\n        // Move event at position p to position q in the sequence after removal.\n        // Valid q in [0..L'] inclusive, where L' = L-1.\n        // First check precedence validity.\n        const Event &ev = seq[p];\n        int oid = ev.oid;\n        if (ev.is_pick) {\n            int pos_del_prime = posDel[oid] - 1; // after removal\n            if (q > pos_del_prime) return (long long)4e18; // invalid\n        } else {\n            int pos_pick_prime = posPick[oid]; // pickup before p\n            if (q <= pos_pick_prime) return (long long)4e18; // invalid\n        }\n        // Compute removal delta\n        auto curr = get_coord_by_index(p);\n        pair<int,int> prevc, nextc;\n        if (p == 0) prevc = {OFFICE_X, OFFICE_Y};\n        else prevc = get_coord_by_index(p-1);\n        if (p == L-1) nextc = {OFFICE_X, OFFICE_Y};\n        else nextc = get_coord_by_index(p+1);\n        long long old_edges = (long long)manhattan(prevc.first, prevc.second, curr.first, curr.second)\n                            + (long long)manhattan(curr.first, curr.second, nextc.first, nextc.second);\n        long long new_edges = (long long)manhattan(prevc.first, prevc.second, nextc.first, nextc.second);\n        long long delta = new_edges - old_edges;\n\n        // Compute insertion delta into position q after removal\n        // After removal, new length L' = L-1. q in [0..L'] inclusive for inserting at end.\n        pair<int,int> prev2, next2;\n        if (q == 0) {\n            prev2 = {OFFICE_X, OFFICE_Y};\n        } else {\n            int j1 = q - 1;\n            int orig1 = (j1 < p ? j1 : j1 + 1);\n            prev2 = get_coord_by_index(orig1);\n        }\n        if (q == L-1) { // note: after removal, L' = L-1; q==L-1 means insert at end (after last index L'-1). But we allow q == L-1 as end.\n            // Inserting at end: next is office\n            next2 = {OFFICE_X, OFFICE_Y};\n        } else {\n            int orig2 = (q < p ? q : q + 1);\n            next2 = get_coord_by_index(orig2);\n        }\n        long long add_edges = (long long)manhattan(prev2.first, prev2.second, curr.first, curr.second)\n                            + (long long)manhattan(curr.first, curr.second, next2.first, next2.second);\n        long long rem_edge = (long long)manhattan(prev2.first, prev2.second, next2.first, next2.second);\n        delta += add_edges - rem_edge;\n\n        return delta;\n    };\n\n    auto apply_move_single = [&](int p, int q) {\n        // Actually perform the move; update seq, L, posPick/posDel\n        Event ev = seq[p];\n        // remove\n        seq.erase(seq.begin() + p);\n        // insert\n        seq.insert(seq.begin() + q, ev);\n        // recompute pos arrays\n        L = (int)seq.size();\n        fill(posPick.begin(), posPick.end(), -1);\n        fill(posDel.begin(), posDel.end(), -1);\n        for (int i = 0; i < L; ++i) {\n            if (seq[i].is_pick) posPick[seq[i].oid] = i;\n            else posDel[seq[i].oid] = i;\n        }\n    };\n\n    // SA loop\n    const double TIME_LIMIT = 1.95; // seconds\n    auto start_time = chrono::high_resolution_clock::now();\n    const double T0 = 500.0;\n    const double T1 = 0.5;\n    long long iter = 0;\n\n    // Precompute an array of candidate positions to reduce branch issues? We'll sample each iteration.\n    while (true) {\n        ++iter;\n        if ((iter & 1023) == 0) {\n            auto now = chrono::high_resolution_clock::now();\n            double elapsed = chrono::duration<double>(now - start_time).count();\n            if (elapsed > TIME_LIMIT) break;\n        }\n        // Temperature schedule: linear in time\n        auto now = chrono::high_resolution_clock::now();\n        double elapsed = chrono::duration<double>(now - start_time).count();\n        double t = (elapsed / TIME_LIMIT);\n        if (t > 1.0) t = 1.0;\n        double temp = T0 + (T1 - T0) * t;\n\n        // Propose a random single-event move\n        int p = rng.randint(0, L-1);\n        int Lp = L - 1;\n        if (Lp <= 0) break;\n        int q = rng.randint(0, Lp); // insertion position after removal, in [0..L-1]\n        // Avoid null move (reinserting in same spot)\n        if (q == p) continue;\n\n        long long d = delta_move_single(p, q);\n        if (d == (long long)4e18) continue; // invalid\n\n        bool accept = false;\n        if (d <= 0) accept = true;\n        else {\n            double prob = exp(- (double)d / temp);\n            if (prob > rng.drand()) accept = true;\n        }\n        if (accept) {\n            apply_move_single(p, q);\n            cur_cost += d;\n            if (cur_cost < best_cost) {\n                best_cost = cur_cost;\n                best_seq = seq;\n            }\n        }\n    }\n\n    // Use best sequence\n    seq = best_seq;\n    L = (int)seq.size();\n\n    // Output\n    // First line: m and selected original ids (1-based)\n    cout << M;\n    for (int i = 0; i < M; ++i) cout << ' ' << (selected_orig_ids[i] + 1);\n    cout << '\\n';\n\n    // Second line: n and route coordinates\n    int n = 2*M + 2;\n    cout << n << ' ' << OFFICE_X << ' ' << OFFICE_Y;\n    for (int i = 0; i < L; ++i) {\n        auto [x, y] = coord_of_event(seq[i]);\n        cout << ' ' << x << ' ' << y;\n    }\n    cout << ' ' << OFFICE_X << ' ' << OFFICE_Y << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\n#include <boost/dynamic_bitset.hpp>\nusing namespace std;\n\n// Constants fixed by the problem\nstatic constexpr int N = 400;\nstatic constexpr int M = 5 * (N - 1);\n\n// DSU with dynamic cut-bitsets per component\nstruct DSU {\n    vector<int> parent, sz;\n    vector<boost::dynamic_bitset<unsigned long long>> inc; // cut edges per component\n    DSU(int n, int mbits, const vector<pair<int,int>>& edge_uv) : parent(n), sz(n,1), inc(n, boost::dynamic_bitset<unsigned long long>(mbits)) {\n        iota(parent.begin(), parent.end(), 0);\n    }\n    int find(int x){\n        while(parent[x]!=x){\n            parent[x]=parent[parent[x]];\n            x=parent[x];\n        }\n        return x;\n    }\n    // Merge roots a,b; ensure we merge smaller into larger\n    int unite(int a, int b){\n        a=find(a); b=find(b);\n        if(a==b) return a;\n        if(sz[a] < sz[b]) swap(a,b);\n        // a is new root\n        inc[a] ^= inc[b];\n        parent[b] = a;\n        sz[a] += sz[b];\n        return a;\n    }\n};\n\nstruct Edge {\n    int u, v;\n    int d; // rounded Euclidean distance\n    bool in_mst = false;\n    bool is_nn = false; // among top-K nearest of an endpoint by d\n};\n\nstatic inline int round_int(double x) {\n    return (int)llround(x);\n}\n\n// Helper: count number of set bits strictly after pos (pos is current edge index) up to a cap\nstatic inline int count_suffix_capped(const boost::dynamic_bitset<unsigned long long>& bs, int pos, int cap) {\n    int c = 0;\n    // find_next returns index of next set bit strictly greater than pos\n    auto idx = bs.find_next(pos);\n    while (idx != boost::dynamic_bitset<unsigned long long>::npos) {\n        ++c;\n        if (c >= cap) break;\n        idx = bs.find_next(idx);\n    }\n    return c;\n}\n\n// Helper: check if there exists a set bit strictly after pos\nstatic inline bool has_future(const boost::dynamic_bitset<unsigned long long>& bs, int pos) {\n    auto idx = bs.find_next(pos);\n    return idx != boost::dynamic_bitset<unsigned long long>::npos;\n}\n\n// Build MST of the given sparse graph E (edges) with weights = d (geometric rounded)\nstatic vector<int> build_mst_indices(const vector<Edge>& edges) {\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    // Sort by d ascending; tie-break by index for determinism\n    stable_sort(idx.begin(), idx.end(), [&](int a, int b){\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n    // DSU for MST\n    vector<int> par(N), rnk(N,0);\n    iota(par.begin(), par.end(), 0);\n    function<int(int)> fnd = [&](int x){ return par[x]==x ? x : par[x]=fnd(par[x]); };\n    auto uni = [&](int a, int b)->bool {\n        a=fnd(a); b=fnd(b);\n        if(a==b) return false;\n        if(rnk[a]<rnk[b]) swap(a,b);\n        par[b]=a;\n        if(rnk[a]==rnk[b]) rnk[a]++;\n        return true;\n    };\n    vector<int> chosen;\n    chosen.reserve(N-1);\n    for (int id : idx) {\n        int u = edges[id].u, v = edges[id].v;\n        if (uni(u, v)) {\n            chosen.push_back(id);\n            if ((int)chosen.size() == N-1) break;\n        }\n    }\n    return chosen;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Read coordinates\n    vector<int> x(N), y(N);\n    for (int i = 0; i < N; i++) {\n        if (!(cin >> x[i] >> y[i])) {\n            return 0; // Defensive: exit if input not available\n        }\n    }\n\n    // Read all edges' endpoints\n    vector<Edge> edges(M);\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        edges[i].u = u;\n        edges[i].v = v;\n        long long dx = x[u] - x[v];\n        long long dy = y[u] - y[v];\n        double dist = sqrt((double)dx * dx + (double)dy * dy);\n        edges[i].d = round_int(dist);\n        if (edges[i].d <= 0) edges[i].d = 1; // Just in case, to avoid division by zero\n    }\n\n    // Precompute per-vertex the nearest K edges by d\n    const int KNN = 3;\n    vector<vector<pair<int,int>>> adj(N); // (d, edge_index)\n    for (int i = 0; i < M; i++) {\n        adj[edges[i].u].push_back({edges[i].d, i});\n        adj[edges[i].v].push_back({edges[i].d, i});\n    }\n    for (int v = 0; v < N; v++) {\n        auto &lst = adj[v];\n        nth_element(lst.begin(), lst.begin() + min(KNN, (int)lst.size()), lst.end(),\n                    [](const auto& a, const auto& b){ return a.first < b.first; });\n        sort(lst.begin(), lst.begin() + min(KNN, (int)lst.size()),\n             [](const auto& a, const auto& b){ return a.first < b.first; });\n        for (int j = 0; j < (int)lst.size() && j < KNN; j++) {\n            edges[lst[j].second].is_nn = true;\n        }\n    }\n\n    // Offline MST on d to guide threshold\n    auto mst_idx = build_mst_indices(edges);\n    vector<char> in_mst_flag(M, 0);\n    for (int id : mst_idx) in_mst_flag[id] = 1;\n    for (int i = 0; i < M; i++) edges[i].in_mst = in_mst_flag[i];\n\n    // Quantiles of d for light guidance\n    vector<int> all_d;\n    all_d.reserve(M);\n    for (auto &e : edges) all_d.push_back(e.d);\n    vector<int> sd = all_d;\n    nth_element(sd.begin(), sd.begin() + M/4, sd.end());\n    int q25 = sd[M/4];\n    sd = all_d;\n    nth_element(sd.begin(), sd.begin() + (3*M)/4, sd.end());\n    int q75 = sd[(3*M)/4];\n\n    // DSU setup and component cut-bitsets\n    DSU dsu(N, M, {});\n    // Initialize inc bitsets: for each edge i=(u,v), it's incident to both u and v\n    for (int i = 0; i < M; i++) {\n        dsu.inc[edges[i].u].set(i);\n        dsu.inc[edges[i].v].set(i);\n    }\n\n    // Heuristic thresholds\n    const double thrStart = 1.22;\n    const double thrEnd   = 2.02;\n    const double kAlpha   = 0.78;     // added by opportunity scarcity\n    const double mstAdd   = 0.20;     // boost if in offline MST\n    const double nnAdd    = 0.08;     // boost if near-neighbor edge\n    const double smallDAdd = 0.05;    // boost for small d\n    const double largeDPen = 0.03;    // slight penalty for very large d\n    const double thrCap    = 2.60;\n    const int    kCapCount = 200;     // cap for counting future cross edges for speed/stability\n\n    // Online processing\n    for (int i = 0; i < M; i++) {\n        int l;\n        if (!(cin >> l)) return 0; // End if unexpected input issue\n\n        const Edge &e = edges[i];\n        int ru = dsu.find(e.u);\n        int rv = dsu.find(e.v);\n\n        int decision = 0;\n\n        if (ru == rv) {\n            // Internal edge -> reject to avoid cycles\n            decision = 0;\n        } else {\n            // Forced acceptance if this is the last chance for either component\n            bool must_accept = (!has_future(dsu.inc[ru], i) || !has_future(dsu.inc[rv], i));\n\n            if (must_accept) {\n                decision = 1;\n                dsu.unite(ru, rv);\n            } else {\n                // Heuristic acceptance based on ratio and opportunity\n                double r = (double)l / (double)e.d;\n                double t = (double)i / (double)M;\n                double thr = thrStart + (thrEnd - thrStart) * t;\n\n                // Future opportunities (fewer -> higher threshold)\n                int k1 = count_suffix_capped(dsu.inc[ru], i, kCapCount);\n                int k2 = count_suffix_capped(dsu.inc[rv], i, kCapCount);\n                int kmin = min(k1, k2);\n                thr += kAlpha / sqrt((double)kmin + 1.0);\n\n                // Offline hints\n                if (e.in_mst) thr += mstAdd;\n                if (e.is_nn)  thr += nnAdd;\n                if (e.d <= q25) thr += smallDAdd;\n                else if (e.d >= q75) thr -= largeDPen;\n\n                if (thr > thrCap) thr = thrCap;\n\n                if (r <= thr) {\n                    decision = 1;\n                    dsu.unite(ru, rv);\n                } else {\n                    decision = 0;\n                }\n            }\n        }\n\n        cout << decision << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pet {\n    int x, y, t;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) {\n        return 0;\n    }\n    vector<Pet> pets(N);\n    for (int i = 0; i < N; i++) {\n        int px, py, pt;\n        cin >> px >> py >> pt;\n        // convert to 0-index\n        pets[i] = {px - 1, py - 1, pt};\n    }\n    int M;\n    cin >> M;\n    vector<int> hx(M), hy(M);\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        hx[i] = x - 1;\n        hy[i] = y - 1;\n    }\n\n    const int H = 30, W = 30;\n    auto inb = [&](int x, int y)->bool { return 0 <= x && x < H && 0 <= y && y < W; };\n\n    // blocked grid\n    vector<vector<char>> blocked(H, vector<char>(W, 0));\n\n    // occupancy at start of each turn\n    vector<vector<int>> pet_here(H, vector<int>(W, 0));\n    vector<vector<int>> human_here(H, vector<int>(W, 0));\n\n    auto rebuild_human_here = [&]() {\n        for (int i = 0; i < H; i++) fill(human_here[i].begin(), human_here[i].end(), 0);\n        for (int i = 0; i < M; i++) {\n            human_here[hx[i]][hy[i]]++;\n        }\n    };\n    auto rebuild_pet_here = [&]() {\n        for (int i = 0; i < H; i++) fill(pet_here[i].begin(), pet_here[i].end(), 0);\n        for (int i = 0; i < N; i++) {\n            pet_here[pets[i].x][pets[i].y]++;\n        }\n    };\n\n    rebuild_human_here();\n    rebuild_pet_here();\n\n    // per-human closed flag\n    vector<char> closed(M, 0);\n\n    // directions: U, R, D, L order preference can be customized per human\n    const int dx4[4] = {-1, 0, 1, 0};\n    const int dy4[4] = {0, 1, 0, -1};\n    const char blockChar[4] = {'u','r','d','l'};\n\n    // Per-human preferred direction order: bias towards nearest edge\n    vector<array<int,4>> prefDir(M);\n    for (int i = 0; i < M; i++) {\n        // bias towards top/bottom and left/right depending on which side is closer\n        // Build an order: primary vertical, then primary horizontal, then the others\n        int topDist = hx[i];\n        int bottomDist = (H-1) - hx[i];\n        int leftDist = hy[i];\n        int rightDist = (W-1) - hy[i];\n\n        int firstV = (topDist <= bottomDist ? 0 : 2);   // 0: up, 2: down\n        int firstH = (leftDist <= rightDist ? 3 : 1);   // 3: left, 1: right (note: our order is U,R,D,L so map index)\n        // Construct a simple order: primary vertical, primary horizontal, other vertical, other horizontal\n        int otherV = firstV ^ 2; // swap up/down\n        int otherH = firstH ^ 2; // swap left/right (since 1^2=3,3^2=1)\n\n        prefDir[i] = { firstV, firstH, otherV, otherH };\n    }\n\n    auto count_open_neighbors = [&](int x, int y)->int {\n        int c = 0;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (!blocked[nx][ny]) c++;\n        }\n        return c;\n    };\n\n    auto can_block = [&](int tx, int ty)->bool {\n        if (!inb(tx, ty)) return false;\n        if (blocked[tx][ty]) return false;\n        // target cannot contain human or pet\n        if (human_here[tx][ty] > 0) return false;\n        if (pet_here[tx][ty] > 0) return false;\n        // no pet in 4-neighbors of target\n        for (int k = 0; k < 4; k++) {\n            int ax = tx + dx4[k], ay = ty + dy4[k];\n            if (!inb(ax, ay)) continue;\n            if (pet_here[ax][ay] > 0) return false;\n        }\n        return true;\n    };\n\n    for (int turn = 0; turn < 300; turn++) {\n        string actions(M, '.');\n\n        // Decide actions\n        for (int i = 0; i < M; i++) {\n            if (closed[i]) {\n                actions[i] = '.';\n                continue;\n            }\n            int x = hx[i], y = hy[i];\n\n            // Check how many in-bounds open neighbors remain\n            int openN = count_open_neighbors(x, y);\n\n            if (openN == 0) {\n                closed[i] = 1;\n                actions[i] = '.';\n                continue;\n            }\n\n            // If closing the last opening would seal the cell and a pet is on our cell, don't close now.\n            bool petOnMyCell = (pet_here[x][y] > 0);\n            if (openN == 1 && petOnMyCell) {\n                actions[i] = '.';\n                continue;\n            }\n\n            // Try to block one neighbor, in preferred direction order, if legal now.\n            bool did = false;\n            for (int order = 0; order < 4 && !did; order++) {\n                int d = prefDir[i][order];\n                int nx = x + dx4[d], ny = y + dy4[d];\n                if (!inb(nx, ny)) continue;\n                if (blocked[nx][ny]) continue;\n                if (can_block(nx, ny)) {\n                    actions[i] = blockChar[d];\n                    did = true;\n                }\n            }\n            if (!did) {\n                actions[i] = '.';\n            }\n        }\n\n        // Output actions and flush\n        cout << actions << '\\n' << flush;\n\n        // Apply blocks to our local grid immediately (simultaneous actions)\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'u' || c == 'd' || c == 'l' || c == 'r') {\n                int d = -1;\n                if (c == 'u') d = 0;\n                else if (c == 'r') d = 1;\n                else if (c == 'd') d = 2;\n                else if (c == 'l') d = 3;\n                int tx = hx[i] + dx4[d], ty = hy[i] + dy4[d];\n                if (inb(tx, ty)) {\n                    blocked[tx][ty] = 1;\n                }\n            }\n            // No movement in this strategy\n        }\n\n        // Read pets' moves for this turn\n        for (int i = 0; i < N; i++) {\n            string s;\n            cin >> s;\n            if (s == \".\") continue;\n            for (char mv : s) {\n                if (mv == 'U') pets[i].x -= 1;\n                else if (mv == 'D') pets[i].x += 1;\n                else if (mv == 'L') pets[i].y -= 1;\n                else if (mv == 'R') pets[i].y += 1;\n                // We trust the judge not to move pets into blocked/out-of-bounds squares.\n            }\n        }\n\n        // Rebuild occupancy for next turn\n        rebuild_pet_here();\n        // humans didn't move\n        // but we keep human_here in case of future movement; rebuild once per turn to be safe\n        rebuild_human_here();\n\n        // Update closed flags opportunistically after new blocks\n        for (int i = 0; i < M; i++) {\n            if (!closed[i]) {\n                if (count_open_neighbors(hx[i], hy[i]) == 0) {\n                    closed[i] = 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static auto st = steady_clock::now();\n    auto cur = steady_clock::now();\n    return duration<double>(cur - st).count();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj, ti, tj;\n    double p;\n    if (!(cin >> si >> sj >> ti >> tj >> p)) {\n        return 0;\n    }\n    vector<string> h(20);\n    for (int i = 0; i < 20; i++) cin >> h[i];\n    vector<string> v(19);\n    for (int i = 0; i < 19; i++) cin >> v[i];\n\n    const int H = 20, W = 20, N = H * W;\n    auto id = [&](int r, int c) { return r * W + c; };\n    int s_id = id(si, sj);\n    int t_id = id(ti, tj);\n\n    // Directions: 0=U,1=D,2=L,3=R\n    const char DIRC[4] = {'U','D','L','R'};\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n\n    // Build neighbor mapping with walls.\n    // dest[u][dir] = v if moving from u in dir is possible, else -1.\n    static int dest[400][4];\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = id(i, j);\n            // U\n            if (i > 0 && v[i-1][j] == '0') dest[u][0] = id(i-1, j);\n            else dest[u][0] = -1;\n            // D\n            if (i < H-1 && v[i][j] == '0') dest[u][1] = id(i+1, j);\n            else dest[u][1] = -1;\n            // L\n            if (j > 0 && h[i][j-1] == '0') dest[u][2] = id(i, j-1);\n            else dest[u][2] = -1;\n            // R\n            if (j < W-1 && h[i][j] == '0') dest[u][3] = id(i, j+1);\n            else dest[u][3] = -1;\n        }\n    }\n\n    // If already at target: output empty string (length 0 is allowed).\n    if (s_id == t_id) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    // Build a shortest path from s to t via BFS for initialization.\n    vector<int> par(N, -1);\n    vector<int> pdir(N, -1);\n    deque<int> dq;\n    dq.push_back(s_id);\n    par[s_id] = s_id;\n    while (!dq.empty() && par[t_id] == -1) {\n        int u = dq.front(); dq.pop_front();\n        int r = u / W, c = u % W;\n        for (int d = 0; d < 4; d++) {\n            int vtx = dest[u][d];\n            if (vtx == -1) continue;\n            if (par[vtx] != -1) continue;\n            par[vtx] = u;\n            pdir[vtx] = d;\n            dq.push_back(vtx);\n        }\n    }\n    vector<int> pathdirs;\n    if (par[t_id] != -1) {\n        int cur = t_id;\n        while (cur != s_id) {\n            pathdirs.push_back(pdir[cur]);\n            cur = par[cur];\n        }\n        reverse(pathdirs.begin(), pathdirs.end());\n    } else {\n        // Should not happen (guaranteed reachable), but fallback: random walk-ish\n        // Use a naive greedy towards target ignoring walls (still better than nothing).\n        int cr = si, cc = sj;\n        vector<int> tmp;\n        for (int k = 0; k < 400; k++) {\n            if (cr == ti && cc == tj) break;\n            int bestd = -1;\n            int bestdist = 1e9;\n            for (int d = 0; d < 4; d++) {\n                int nr = cr + dr[d], nc = cc + dc[d];\n                if (nr < 0 || nr >= H || nc < 0 || nc >= W) continue;\n                if (dest[id(cr,cc)][d] == -1) continue;\n                int md = abs(nr - ti) + abs(nc - tj);\n                if (md < bestdist) {\n                    bestdist = md; bestd = d;\n                }\n            }\n            if (bestd == -1) break;\n            tmp.push_back(bestd);\n            cr += dr[bestd]; cc += dc[bestd];\n        }\n        pathdirs = tmp;\n    }\n\n    int L = 200;\n    string seq;\n    seq.reserve(L);\n    if (!pathdirs.empty()) {\n        while ((int)seq.size() < L) {\n            for (int d: pathdirs) {\n                seq.push_back(DIRC[d]);\n                if ((int)seq.size() >= L) break;\n            }\n        }\n    } else {\n        // Fallback: simple greedy towards target repeated\n        int needD = max(0, ti - si), needU = max(0, si - ti);\n        int needR = max(0, tj - sj), needL = max(0, sj - tj);\n        vector<char> gseq;\n        for (int i = 0; i < needD; i++) gseq.push_back('D');\n        for (int i = 0; i < needU; i++) gseq.push_back('U');\n        for (int i = 0; i < needR; i++) gseq.push_back('R');\n        for (int i = 0; i < needL; i++) gseq.push_back('L');\n        if (gseq.empty()) gseq.push_back('R');\n        while ((int)seq.size() < L) {\n            for (char ch: gseq) {\n                seq.push_back(ch);\n                if ((int)seq.size() >= L) break;\n            }\n        }\n    }\n\n    // Utilities: map char to dir index\n    auto c2d = [](char c)->int {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        return 3; // 'R'\n    };\n\n    // Transition application functions\n    const double q = 1.0 - p;\n\n    auto apply_right = [&](int dir, const double* vin, double* vout) {\n        // vout = P^dir * vin (with absorbing target)\n        // clear\n        for (int i = 0; i < N; i++) vout[i] = 0.0;\n        // accumulate\n        for (int u = 0; u < N; u++) {\n            double val = vin[u];\n            if (val == 0.0) continue;\n            if (u == t_id) {\n                vout[t_id] += val;\n            } else {\n                int d = dest[u][dir];\n                if (d >= 0) {\n                    vout[d] += val * q;\n                    vout[u] += val * p;\n                } else {\n                    vout[u] += val;\n                }\n            }\n        }\n    };\n\n    auto apply_right_and_dot = [&](int dir, const double* vin, double* vout, const double* gvec) -> double {\n        // vout = P^dir * vin; return gvec dot vout\n        double sum = 0.0;\n        for (int i = 0; i < N; i++) vout[i] = 0.0;\n        for (int u = 0; u < N; u++) {\n            double val = vin[u];\n            if (val == 0.0) continue;\n            if (u == t_id) {\n                vout[t_id] += val;\n                sum += gvec[t_id] * val;\n            } else {\n                int d = dest[u][dir];\n                if (d >= 0) {\n                    double toD = val * q;\n                    double toS = val * p;\n                    vout[d] += toD;\n                    vout[u] += toS;\n                    sum += gvec[d] * toD + gvec[u] * toS;\n                } else {\n                    vout[u] += val;\n                    sum += gvec[u] * val;\n                }\n            }\n        }\n        return sum;\n    };\n\n    auto apply_left = [&](int dir, const double* gcur, double* gprev) {\n        // gprev = (P^dir)^T * gcur (with absorbing target)\n        for (int i = 0; i < N; i++) gprev[i] = 0.0;\n        // contribution from absorbing target self-loop\n        gprev[t_id] += gcur[t_id];\n        for (int u = 0; u < N; u++) {\n            if (u == t_id) continue;\n            int d = dest[u][dir];\n            if (d >= 0) {\n                gprev[u] += p * gcur[u] + q * gcur[d];\n            } else {\n                gprev[u] += gcur[u];\n            }\n        }\n    };\n\n    // Coordinate ascent optimization\n    const double TL = 1.95; // seconds\n    double start_time = now_sec();\n\n    // Buffers\n    vector<array<double, 400>> g(L); // g[t]\n    array<double, 400> gtmp;\n\n    array<double, 400> vcur;\n    array<double, 400> vtmp;\n    array<double, 400> vbest;\n\n    auto compute_backward_g = [&](const string& seq_str) {\n        // weights: for t = 0..L-2 -> 1; t = L-1 -> (401 - L)\n        for (int i = 0; i < N; i++) g[L-1][i] = 0.0;\n        g[L-1][t_id] = double(401 - L);\n        for (int t = L-2; t >= 0; t--) {\n            // g[t] = e_target + (P^{a_{t+1}})^T g[t+1]\n            // start with e_target (weight 1.0)\n            for (int i = 0; i < N; i++) g[t][i] = 0.0;\n            g[t][t_id] = 1.0;\n            int dir_next = c2d(seq_str[t+1]);\n            apply_left(dir_next, g[t+1].data(), gtmp.data());\n            for (int i = 0; i < N; i++) g[t][i] += gtmp[i];\n        }\n    };\n\n    auto forward_pass = [&](string& seq_str, double& score_out, bool& changed_out) {\n        // Use g computed for the current seq_str.\n        // Build new sequence greedily maximizing g[t]^T (P^a v_{t}).\n        for (int i = 0; i < N; i++) vcur[i] = 0.0;\n        vcur[s_id] = 1.0;\n        double score = 0.0;\n        bool changed = false;\n\n        for (int t = 0; t < L; t++) {\n            int old_dir = c2d(seq_str[t]);\n            double best_val = -1e300;\n            int best_dir = old_dir;\n            // Evaluate all 4 actions\n            for (int d = 0; d < 4; d++) {\n                double val = apply_right_and_dot(d, vcur.data(), vtmp.data(), g[t].data());\n                if (val > best_val + 1e-12 || (abs(val - best_val) <= 1e-12 && d == old_dir)) {\n                    best_val = val;\n                    best_dir = d;\n                    // copy vtmp to vbest\n                    for (int i = 0; i < N; i++) vbest[i] = vtmp[i];\n                }\n            }\n            if (best_dir != old_dir) {\n                changed = true;\n                seq_str[t] = DIRC[best_dir];\n            }\n            // advance vcur\n            for (int i = 0; i < N; i++) vcur[i] = vbest[i];\n            // accumulate E[S] using identity: sum_{t=1..L-1} F_t + (401-L) F_L\n            double Ft = vcur[t_id];\n            if (t < L - 1) score += Ft;\n            else score += double(401 - L) * Ft;\n        }\n        score_out = score;\n        changed_out = changed;\n    };\n\n    // Initial g and forward pass to compute score\n    compute_backward_g(seq);\n    double best_score = -1e300;\n    bool dummy_changed = false;\n    string best_seq = seq;\n    {\n        double s0;\n        forward_pass(seq, s0, dummy_changed);\n        best_score = s0;\n        best_seq = seq;\n    }\n\n    // Iterate passes until no improvement or time runs out\n    for (int iter = 0; iter < 1000000; iter++) {\n        if (now_sec() - start_time > TL) break;\n        compute_backward_g(seq);\n        double sc;\n        bool ch;\n        forward_pass(seq, sc, ch);\n        if (sc > best_score + 1e-9) {\n            best_score = sc;\n            best_seq = seq;\n        } else {\n            // No improvement; stop\n            break;\n        }\n    }\n\n    cout << best_seq << \"\\n\";\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer utility\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\n// Random\nstruct XorShift {\n    uint64_t x=88172645463393265ull;\n    inline uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline int randint(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n    inline double rand01() {\n        return (next_u32() & 0xFFFFFF) / double(0x1000000);\n    }\n} rng;\n\n// Directions: 0=left,1=up,2=right,3=down\nstatic const int di[4] = {0,-1,0,1};\nstatic const int dj[4] = {-1,0,1,0};\n\n// The \"to\" mapping from the statement, indexed by tile state 0..7 and entry direction d\nstatic const int TO[8][4] = {\n    {1,0,-1,-1},   // 0: L<->U\n    {3,-1,-1,0},   // 1: L<->D\n    {-1,-1,3,2},   // 2: R<->D\n    {-1,2,1,-1},   // 3: U<->R\n    {1,0,3,2},     // 4: L<->U and R<->D\n    {3,2,1,0},     // 5: L<->D and R<->U\n    {2,-1,0,-1},   // 6: L<->R (horizontal)\n    {-1,3,-1,1},   // 7: U<->D (vertical)\n};\n\n// Presence P[t][s] = (to[t][s] != -1)\nstatic bool PRES[8][4];\n\n// Rotate mapping: apply 90\u00b0 CCW once\ninline int rot_once(int t) {\n    if (t < 4) return (t + 1) & 3;\n    if (t < 6) return 9 - t; // 4<->5\n    return 13 - t;           // 6<->7\n}\n// Rotate t by r times 90\u00b0 CCW\ninline int rotate_t(int t, int r) {\n    if (t < 4) return (t + r) & 3;\n    if (t < 6) return (r & 1) ? 9 - t : t;\n    return (r & 1) ? 13 - t : t;\n}\n\n// Build next-state mapping for current oriented grid.\n// States are indexed as idx = ((i*30 + j) * 4 + d).\n// Only states with TO[t][d] != -1 are \"allowed\". For allowed states:\n//   compute d2 = TO[t][d]; next cell (i2,j2) = (i+di[d2], j+dj[d2])\n//   if out-of-bounds -> next = -1\n//   else if TO[t2][(d2+2)%4] != -1 -> next = id of (i2,j2,(d2+2)%4)\n//   else next = -1\n// Return lengths of top two cycles.\nstruct LoopEval {\n    long long L1 = 0, L2 = 0;\n    long long product() const { return (L2 == 0 ? 0LL : L1 * L2); }\n};\n\nstatic inline int state_id(int i, int j, int d) {\n    return ((i * 30 + j) << 2) | d;\n}\n\nLoopEval evaluate_loops(const array<array<int,30>,30>& eff) {\n    const int N = 30, M = 30;\n    const int TOT = N * M * 4;\n    static vector<int> next_state; next_state.assign(TOT, -2); // -2: not set; -1: dead; >=0: next\n    static vector<char> allowed; allowed.assign(TOT, 0);\n\n    // Build next mapping\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < M; ++j) {\n            int t = eff[i][j];\n            for (int d = 0; d < 4; ++d) {\n                int idx = state_id(i,j,d);\n                int d2 = TO[t][d];\n                if (d2 == -1) {\n                    allowed[idx] = 0;\n                    next_state[idx] = -1;\n                    continue;\n                }\n                allowed[idx] = 1;\n                int i2 = i + di[d2], j2 = j + dj[d2];\n                if (i2 < 0 || i2 >= N || j2 < 0 || j2 >= M) {\n                    next_state[idx] = -1;\n                    continue;\n                }\n                int t2 = eff[i2][j2];\n                int d_rev = (d2 + 2) & 3;\n                if (TO[t2][d_rev] == -1) {\n                    next_state[idx] = -1;\n                } else {\n                    next_state[idx] = state_id(i2, j2, d_rev);\n                }\n            }\n        }\n    }\n\n    // Detect cycles in the directed graph of allowed states\n    static vector<int> visited; visited.assign(TOT, 0);\n    static vector<int> seen_step; seen_step.assign(TOT, -1);\n    static vector<int> seen_mark; seen_mark.assign(TOT, -1);\n    int pass = 0;\n    long long best1 = 0, best2 = 0;\n\n    vector<int> path; path.reserve(2048);\n\n    for (int idx0 = 0; idx0 < TOT; ++idx0) {\n        if (!allowed[idx0] || visited[idx0]) continue;\n        ++pass;\n        path.clear();\n        int cur = idx0;\n        while (true) {\n            if (cur < 0 || !allowed[cur] || next_state[cur] == -1) {\n                // no cycle\n                for (int x : path) visited[x] = 1;\n                break;\n            }\n            if (seen_mark[cur] == pass) {\n                // Found a cycle\n                int start_step = seen_step[cur];\n                long long cyc_len = (long long)path.size() - start_step;\n                if (cyc_len > best1) { best2 = best1; best1 = cyc_len; }\n                else if (cyc_len > best2) { best2 = cyc_len; }\n                for (int x : path) visited[x] = 1;\n                break;\n            }\n            if (visited[cur]) {\n                // Already processed elsewhere\n                for (int x : path) visited[x] = 1;\n                break;\n            }\n            // Visit\n            seen_mark[cur] = pass;\n            seen_step[cur] = (int)path.size();\n            path.push_back(cur);\n            cur = next_state[cur];\n        }\n    }\n    LoopEval le; le.L1 = best1; le.L2 = best2;\n    return le;\n}\n\n// Compatibility score S1: sum over internal edges where both sides present, minus boundary penalties\nstruct CompatScorer {\n    int N=30, M=30;\n    int Wedge = 1;\n    int Wb = 1; // boundary penalty per present on outer side\n\n    // Compute initial S1 using unique edges (right and down) and all boundaries\n    long long compute_all(const array<array<int,30>,30>& eff) const {\n        long long s = 0;\n        for (int i=0;i<N;i++){\n            for (int j=0;j<M;j++){\n                int t = eff[i][j];\n                // right edge\n                if (j+1 < M) {\n                    if (PRES[t][2] && PRES[eff[i][j+1]][0]) s += Wedge;\n                } else {\n                    if (PRES[t][2]) s -= Wb;\n                }\n                // down edge\n                if (i+1 < N) {\n                    if (PRES[t][3] && PRES[eff[i+1][j]][1]) s += Wedge;\n                } else {\n                    if (PRES[t][3]) s -= Wb;\n                }\n                // left boundary\n                if (j==0 && PRES[t][0]) s -= Wb;\n                // up boundary\n                if (i==0 && PRES[t][1]) s -= Wb;\n            }\n        }\n        return s;\n    }\n\n    // Delta when changing tile (i,j) from curT to newT (only immediate neighborhood edges change)\n    long long delta_change(const array<array<int,30>,30>& eff, int i, int j, int curT, int newT) const {\n        long long delta = 0;\n        // Right edge (i,j)-(i,j+1)\n        if (j+1 < M) {\n            int tR = eff[i][j+1];\n            int old = (PRES[curT][2] && PRES[tR][0]) ? Wedge : 0;\n            int neu = (PRES[newT][2] && PRES[tR][0]) ? Wedge : 0;\n            delta += (neu - old);\n        } else {\n            int old = PRES[curT][2] ? -Wb : 0;\n            int neu = PRES[newT][2] ? -Wb : 0;\n            delta += (neu - old);\n        }\n        // Down edge (i,j)-(i+1,j)\n        if (i+1 < N) {\n            int tD = eff[i+1][j];\n            int old = (PRES[curT][3] && PRES[tD][1]) ? Wedge : 0;\n            int neu = (PRES[newT][3] && PRES[tD][1]) ? Wedge : 0;\n            delta += (neu - old);\n        } else {\n            int old = PRES[curT][3] ? -Wb : 0;\n            int neu = PRES[newT][3] ? -Wb : 0;\n            delta += (neu - old);\n        }\n        // Left edge (i,j-1)-(i,j) anchored at (i,j-1)\n        if (j-1 >= 0) {\n            int tL = eff[i][j-1];\n            int old = (PRES[tL][2] && PRES[curT][0]) ? Wedge : 0;\n            int neu = (PRES[tL][2] && PRES[newT][0]) ? Wedge : 0;\n            delta += (neu - old);\n        } else {\n            int old = PRES[curT][0] ? -Wb : 0;\n            int neu = PRES[newT][0] ? -Wb : 0;\n            delta += (neu - old);\n        }\n        // Up edge (i-1,j)-(i,j) anchored at (i-1,j)\n        if (i-1 >= 0) {\n            int tU = eff[i-1][j];\n            int old = (PRES[tU][3] && PRES[curT][1]) ? Wedge : 0;\n            int neu = (PRES[tU][3] && PRES[newT][1]) ? Wedge : 0;\n            delta += (neu - old);\n        } else {\n            int old = PRES[curT][1] ? -Wb : 0;\n            int neu = PRES[newT][1] ? -Wb : 0;\n            delta += (neu - old);\n        }\n        return delta;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Precompute PRES\n    for (int t=0;t<8;t++) for (int d=0;d<4;d++) PRES[t][d] = (TO[t][d] != -1);\n\n    const int N = 30, M = 30;\n    array<array<int,30>,30> base{}; // input tile ids\n    for (int i=0;i<N;i++){\n        string s; if(!(cin>>s)){ return 0; }\n        for (int j=0;j<M;j++){\n            base[i][j] = s[j] - '0';\n        }\n    }\n\n    Timer timer;\n    double TIME_LIMIT = 1.95; // seconds\n\n    // r[i][j] rotations 0..3; eff[i][j] actual tile index after rotation\n    array<array<int,30>,30> rot{};\n    array<array<int,30>,30> eff{};\n\n    // Initialize rotations randomly, but try to make a simple boundary-friendly bias\n    for (int i=0;i<N;i++){\n        for (int j=0;j<M;j++){\n            int t = base[i][j];\n            int r0 = rng.randint(0,3);\n            // A tiny boundary-friendly tweak for single-curves and straights:\n            if (t < 4) {\n                // Avoid mapping that uses \"up\" on the top row or \"left\" on the left column etc.\n                if (i==0 || i==N-1 || j==0 || j==M-1) {\n                    // Try 4 rotations and pick the one with least boundary presences\n                    int bestR = 0, bestBad = 1e9;\n                    for (int rr=0; rr<4; rr++){\n                        int tt = rotate_t(t, rr);\n                        int bad = 0;\n                        if (i==0 && PRES[tt][1]) bad++;\n                        if (i==N-1 && PRES[tt][3]) bad++;\n                        if (j==0 && PRES[tt][0]) bad++;\n                        if (j==M-1 && PRES[tt][2]) bad++;\n                        if (bad < bestBad) { bestBad = bad; bestR = rr; }\n                    }\n                    r0 = bestR;\n                }\n            } else if (t >= 6) {\n                // Straight: choose orientation to avoid going out on closest boundary if near edge\n                if (i==0 || i==N-1) {\n                    // prefer horizontal\n                    r0 = 0; // no toggle\n                } else if (j==0 || j==M-1) {\n                    // prefer vertical\n                    r0 = 1; // toggle once\n                }\n            }\n            rot[i][j] = r0;\n            eff[i][j] = rotate_t(t, r0);\n        }\n    }\n\n    // Phase 1: Coordinate descent on compatibility score S1\n    CompatScorer scorer;\n    long long s1 = scorer.compute_all(eff);\n    // Iteratively improve\n    {\n        vector<pair<int,int>> order; order.reserve(N*M);\n        for (int i=0;i<N;i++) for (int j=0;j<M;j++) order.emplace_back(i,j);\n        int iter = 0;\n        double phase1_limit = min(0.8, TIME_LIMIT*0.5); // 0.5~0.8s for phase 1\n        while (timer.elapsed() < phase1_limit) {\n            ++iter;\n            // Randomize visiting order for diversification\n            shuffle(order.begin(), order.end(), std::mt19937(rng.next_u32()));\n            bool improved_any = false;\n            for (auto &p : order) {\n                int i = p.first, j = p.second;\n                int t = base[i][j];\n                int curR = rot[i][j];\n                int curT = eff[i][j];\n                long long bestDelta = 0;\n                int bestR = curR;\n                // Try 4 rotations\n                for (int rr=0; rr<4; rr++) {\n                    if (rr == curR) continue;\n                    int newT = rotate_t(t, rr);\n                    long long delta = scorer.delta_change(eff, i, j, curT, newT);\n                    if (delta > bestDelta) {\n                        bestDelta = delta; bestR = rr;\n                    }\n                }\n                if (bestR != curR) {\n                    int newT = rotate_t(t, bestR);\n                    s1 += scorer.delta_change(eff, i, j, curT, newT);\n                    rot[i][j] = bestR;\n                    eff[i][j] = newT;\n                    improved_any = true;\n                }\n            }\n            if (!improved_any) break;\n        }\n    }\n\n    // Phase 2: Limited SA on true objective (L1*L2)\n    LoopEval bestEval = evaluate_loops(eff);\n    long long bestScore = bestEval.product();\n    auto bestRot = rot;\n    auto bestEff = eff;\n\n    // SA parameters\n    double startT = 5.0;\n    double endT = 0.1;\n    int SA_ITERS = 20000; // limit iterations\n    double t0 = timer.elapsed();\n    double SA_TIME = max(0.2, TIME_LIMIT - t0 - 0.02); // leave margin\n    if (SA_TIME > 0.01) {\n        for (int it = 0; it < SA_ITERS; ++it) {\n            double elapsed = timer.elapsed() - t0;\n            if (elapsed > SA_TIME) break;\n            double progress = elapsed / SA_TIME;\n            double T = startT + (endT - startT) * progress;\n\n            int i = rng.randint(0,N-1);\n            int j = rng.randint(0,M-1);\n            int t = base[i][j];\n            int oldR = rot[i][j];\n            int newR = (oldR + rng.randint(1,3)) & 3; // change to a different rotation\n            if (newR == oldR) continue;\n            int oldT = eff[i][j];\n            int newT = rotate_t(t, newR);\n\n            rot[i][j] = newR;\n            eff[i][j] = newT;\n\n            LoopEval curEval = evaluate_loops(eff);\n            long long curScore = curEval.product();\n            long long diff = curScore - bestScore;\n\n            bool accept = false;\n            if (curScore >= bestScore) {\n                accept = true;\n            } else {\n                double prob = exp((double)diff / max(1.0, T));\n                if (rng.rand01() < prob) accept = true;\n            }\n            if (accept) {\n                if (curScore > bestScore) {\n                    bestScore = curScore;\n                    bestEval = curEval;\n                    bestRot = rot;\n                    bestEff = eff;\n                }\n            } else {\n                // revert\n                rot[i][j] = oldR;\n                eff[i][j] = oldT;\n            }\n        }\n    }\n\n    // Output best found rotations as a 900-char string\n    // r_{i,j} is number of 90deg CCW rotations (0..3)\n    // We keep bestRot stored; output in row-major\n    {\n        string out;\n        out.reserve(N*M);\n        for (int i=0;i<N;i++) {\n            for (int j=0;j<M;j++) {\n                out.push_back(char('0' + bestRot[i][j]));\n            }\n        }\n        cout << out << \"\\n\";\n    }\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n_) : n(n_), p(n_), sz(n_, 0) {\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n    void set_size(int i, int s) { sz[i] = s; }\n    int size(int i) { return sz[find(i)]; }\n};\n\nstruct Eval {\n    int largestTree = 0;\n    int largestCC = 0;\n    int cyclesInLargestCC = 0;\n    int totalEdges = 0;\n    int loops2x2 = 0;\n};\n\nstruct ScoreKey {\n    // Lexicographic: larger is better (cycles and loops are negated for comparison)\n    int largestTree;\n    int largestCC;\n    int negCyclesInLargestCC;\n    int totalEdges;\n    int negLoops2x2;\n};\n\nstatic inline int hexchar_to_int(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    if ('a' <= c && c <= 'f') return 10 + (c - 'a');\n    if ('A' <= c && c <= 'F') return 10 + (c - 'A');\n    return 0;\n}\n\nstruct Board {\n    int N;\n    vector<int> a; // size N*N, 0 is empty\n    int zr, zc;\n};\n\nstatic inline bool in_bounds(int N, int r, int c) {\n    return (0 <= r && r < N && 0 <= c && c < N);\n}\n\nEval evaluate_board(const Board& B) {\n    const int N = B.N;\n    const int n2 = N*N;\n    const int L = 1, U = 2, R = 4, D = 8;\n\n    // Occupied nodes (exclude the empty square)\n    vector<char> occ(n2, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int id = i*N + j;\n            if (B.a[id] != 0) occ[id] = 1;\n        }\n    }\n\n    // Build edges\n    vector<pair<int,int>> edges;\n    edges.reserve(2*N*(N-1));\n    int totalEdges = 0;\n    // Vertical matches\n    for (int i = 0; i < N-1; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int id1 = i*N + j;\n            int id2 = (i+1)*N + j;\n            int m1 = B.a[id1], m2 = B.a[id2];\n            if ((m1 & D) && (m2 & U)) {\n                edges.emplace_back(id1, id2);\n                totalEdges++;\n            }\n        }\n    }\n    // Horizontal matches\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N-1; ++j) {\n            int id1 = i*N + j;\n            int id2 = i*N + (j+1);\n            int m1 = B.a[id1], m2 = B.a[id2];\n            if ((m1 & R) && (m2 & L)) {\n                edges.emplace_back(id1, id2);\n                totalEdges++;\n            }\n        }\n    }\n\n    // Count 2x2 loops\n    int loops2x2 = 0;\n    for (int i = 0; i < N-1; ++i) {\n        for (int j = 0; j < N-1; ++j) {\n            int id00 = i*N + j;\n            int id10 = (i+1)*N + j;\n            int id01 = i*N + (j+1);\n            int id11 = (i+1)*N + (j+1);\n            int m00 = B.a[id00], m10 = B.a[id10], m01 = B.a[id01], m11 = B.a[id11];\n            bool v1 = (m00 & D) && (m10 & U);\n            bool v2 = (m01 & D) && (m11 & U);\n            bool h1 = (m00 & R) && (m01 & L);\n            bool h2 = (m10 & R) && (m11 & L);\n            if (v1 && v2 && h1 && h2) loops2x2++;\n        }\n    }\n\n    // DSU for components\n    DSU dsu(n2);\n    for (int i = 0; i < n2; ++i) {\n        dsu.p[i] = i;\n        dsu.sz[i] = occ[i] ? 1 : 0;\n    }\n    for (auto &e : edges) {\n        int u = e.first, v = e.second;\n        if (occ[u] && occ[v]) dsu.unite(u, v);\n    }\n    // Count component sizes and edges per component\n    vector<int> compEdges(n2, 0);\n    for (auto &e : edges) {\n        int u = e.first, v = e.second;\n        if (!(occ[u] && occ[v])) continue;\n        int ru = dsu.find(u);\n        compEdges[ru]++;\n    }\n\n    int largestCC = 0;\n    int largestTree = 0;\n    int cyclesInLargestCC = 0;\n\n    // Iterate over roots\n    vector<char> seen(n2, 0);\n    for (int id = 0; id < n2; ++id) {\n        if (!occ[id]) continue;\n        int r = dsu.find(id);\n        if (seen[r]) continue;\n        seen[r] = 1;\n        int V = dsu.sz[r];\n        int E = compEdges[r];\n        if (V > largestCC) {\n            largestCC = V;\n            cyclesInLargestCC = E - (V - 1);\n        } else if (V == largestCC) {\n            // Prefer fewer cycles for largestCC tie\n            int cyc = E - (V - 1);\n            if (cyc < cyclesInLargestCC) {\n                cyclesInLargestCC = cyc;\n            }\n        }\n        if (E == V - 1) {\n            if (V > largestTree) largestTree = V;\n        }\n    }\n\n    Eval ev;\n    ev.largestTree = largestTree;\n    ev.largestCC = largestCC;\n    ev.cyclesInLargestCC = max(0, cyclesInLargestCC);\n    ev.totalEdges = totalEdges;\n    ev.loops2x2 = loops2x2;\n    return ev;\n}\n\nstatic inline ScoreKey make_key(const Eval& ev) {\n    ScoreKey k;\n    k.largestTree = ev.largestTree;\n    k.largestCC = ev.largestCC;\n    k.negCyclesInLargestCC = -ev.cyclesInLargestCC;\n    k.totalEdges = ev.totalEdges;\n    k.negLoops2x2 = -ev.loops2x2;\n    return k;\n}\n\nstatic inline bool better_key(const ScoreKey& a, const ScoreKey& b) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.negCyclesInLargestCC != b.negCyclesInLargestCC) return a.negCyclesInLargestCC > b.negCyclesInLargestCC;\n    if (a.totalEdges != b.totalEdges) return a.totalEdges > b.totalEdges;\n    if (a.negLoops2x2 != b.negLoops2x2) return a.negLoops2x2 > b.negLoops2x2;\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    int T;\n    if (!(cin >> N >> T)) return 0;\n    vector<string> ts(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> ts[i];\n    }\n\n    Board B;\n    B.N = N;\n    B.a.assign(N*N, 0);\n    B.zr = -1; B.zc = -1;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int v = hexchar_to_int(ts[i][j]);\n            B.a[i*N + j] = v;\n            if (v == 0) { B.zr = i; B.zc = j; }\n        }\n    }\n\n    // Random generator\n    std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    auto eval_cur = evaluate_board(B);\n\n    string ans;\n    ans.reserve(T);\n\n    auto opposite = [&](char mv) -> char {\n        if (mv == 'U') return 'D';\n        if (mv == 'D') return 'U';\n        if (mv == 'L') return 'R';\n        if (mv == 'R') return 'L';\n        return '?';\n    };\n\n    char lastMove = '?';\n    const double eps_base = 0.02;\n\n    // Directions: U,D,L,R as empty movement (tile moves into empty)\n    const int dr[4] = {-1, +1, 0, 0};\n    const int dc[4] = {0, 0, -1, +1};\n    const char mvch[4] = {'U', 'D', 'L', 'R'};\n\n    for (int step = 0; step < T; ++step) {\n        // Legal moves\n        vector<int> cand;\n        cand.reserve(4);\n        for (int k = 0; k < 4; ++k) {\n            int nr = B.zr + dr[k];\n            int nc = B.zc + dc[k];\n            if (!in_bounds(N, nr, nc)) continue;\n            char m = mvch[k];\n            if (lastMove != '?' && m == opposite(lastMove)) continue; // avoid immediate reverse\n            cand.push_back(k);\n        }\n        if (cand.empty()) {\n            // Only possible when last move led to a corner with only opposite allowed; allow reverse\n            for (int k = 0; k < 4; ++k) {\n                int nr = B.zr + dr[k];\n                int nc = B.zc + dc[k];\n                if (in_bounds(N, nr, nc)) cand.push_back(k);\n            }\n        }\n\n        // Epsilon-greedy exploration\n        bool explore = false;\n        if (!cand.empty()) {\n            uniform_real_distribution<double> dist01(0.0, 1.0);\n            double rnd = dist01(rng);\n            if (rnd < eps_base) explore = true;\n        }\n\n        int best_k = -1;\n        ScoreKey best_key = {-1, -1, INT_MIN, -1, INT_MIN};\n\n        if (!explore) {\n            // Choose best by lexicographic key\n            for (int k : cand) {\n                int nr = B.zr + dr[k];\n                int nc = B.zc + dc[k];\n                int zidx = B.zr * N + B.zc;\n                int nidx = nr * N + nc;\n                // Apply move: swap empty with neighbor\n                swap(B.a[zidx], B.a[nidx]);\n                int oldzr = B.zr, oldzc = B.zc;\n                B.zr = nr; B.zc = nc;\n\n                Eval ev = evaluate_board(B);\n                ScoreKey key = make_key(ev);\n\n                // Revert\n                B.zr = oldzr; B.zc = oldzc;\n                swap(B.a[zidx], B.a[nidx]);\n\n                if (best_k == -1 || better_key(key, best_key)) {\n                    best_k = k;\n                    best_key = key;\n                } else if (!better_key(best_key, key)) {\n                    // Tie: randomize\n                    if (uniform_int_distribution<int>(0, 1)(rng) == 0) {\n                        best_k = k;\n                        best_key = key;\n                    }\n                }\n            }\n        } else {\n            // Random move among candidates\n            best_k = cand[uniform_int_distribution<int>(0, (int)cand.size()-1)(rng)];\n        }\n\n        if (best_k == -1) {\n            // Fallback: pick any legal move\n            for (int k = 0; k < 4; ++k) {\n                int nr = B.zr + dr[k];\n                int nc = B.zc + dc[k];\n                if (in_bounds(N, nr, nc)) {\n                    best_k = k; break;\n                }\n            }\n        }\n\n        // Execute chosen move\n        int nr = B.zr + dr[best_k];\n        int nc = B.zc + dc[best_k];\n        int zidx = B.zr * N + B.zc;\n        int nidx = nr * N + nc;\n        swap(B.a[zidx], B.a[nidx]);\n        B.zr = nr; B.zc = nc;\n        lastMove = mvch[best_k];\n        ans.push_back(lastMove);\n        // Optional: update current eval if needed (not strictly necessary)\n        // eval_cur = evaluate_board(B);\n    }\n\n    cout << ans << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int x, y;\n};\n\nstatic const int KMAX = 100;\n\n// Build geometric weights (unnormalized), w[i] = r^i for i=0..m-1\nstatic vector<long double> geometric_weights(int m, long double r) {\n    vector<long double> w(m);\n    long double v = 1.0L;\n    for (int i = 0; i < m; ++i) {\n        w[i] = v;\n        v *= r;\n    }\n    return w;\n}\n\n// Normalize weights to sum to 1\nstatic void normalize(vector<long double>& w) {\n    long double s = 0;\n    for (auto &x : w) s += x;\n    if (s <= 0) return;\n    for (auto &x : w) x /= s;\n}\n\n// Given weights summing to 1 and total N, compute integer targets via largest fractional parts\nstatic vector<int> targets_from_weights(const vector<long double>& w, int N) {\n    int m = (int)w.size();\n    vector<int> tgt(m);\n    vector<pair<long double,int>> frac; frac.reserve(m);\n    long double sum_floor = 0;\n    for (int i = 0; i < m; ++i) {\n        long double val = (long double)N * w[i];\n        int f = (int)floor(val);\n        tgt[i] = f;\n        sum_floor += f;\n        frac.emplace_back(val - f, i);\n    }\n    int rem = N - (int)sum_floor;\n    // Add 1 to the top 'rem' fractional parts\n    nth_element(frac.begin(), frac.begin() + max(0, rem), frac.end(),\n                [](const auto& a, const auto& b){ return a.first > b.first; });\n    for (int k = 0; k < rem; ++k) {\n        tgt[frac[k].second]++;\n    }\n    return tgt;\n}\n\n// Build the list of \"safe cut positions\" as indices j representing a cut between arr[j] and arr[j+1] when gap >= 2,\n// plus sentinel -1 (before first) and N-1 (after last).\nstatic vector<int> build_safe_indices(const vector<int>& arr) {\n    int N = (int)arr.size();\n    vector<int> safe;\n    safe.reserve(N+2);\n    safe.push_back(-1);\n    for (int j = 0; j + 1 < N; ++j) {\n        if (arr[j+1] - arr[j] >= 2) {\n            safe.push_back(j);\n        }\n    }\n    safe.push_back(N-1);\n    return safe;\n}\n\n// Choose the safe index j >= (pos-1) closest to target t\nstatic int choose_nearest_safe(const vector<int>& safe, int t, int min_j) {\n    // binary search for first >= t\n    int lo = 0, hi = (int)safe.size();\n    while (lo < hi) {\n        int mid = (lo + hi) >> 1;\n        if (safe[mid] < t) lo = mid + 1;\n        else hi = mid;\n    }\n    int best = -1;\n    long long bestDist = (1LL<<60);\n    // candidate lo\n    for (int k = lo - 1; k <= lo; ++k) {\n        if (k < 0 || k >= (int)safe.size()) continue;\n        int cand = safe[k];\n        if (cand < min_j) continue;\n        long long dist = llabs((long long)cand - (long long)t);\n        if (dist < bestDist) {\n            bestDist = dist;\n            best = cand;\n        }\n    }\n    if (best == -1) {\n        // If nothing found above min_j due to all safe < min_j, fallback to first >= min_j\n        int idx = lower_bound(safe.begin(), safe.end(), min_j) - safe.begin();\n        if (idx >= (int)safe.size()) idx = (int)safe.size() - 1;\n        best = safe[idx];\n    }\n    return best;\n}\n\n// Plan integer x-line positions given sorted arr (x- or y- coordinates) and target counts.\n// Returns a vector of line coordinates (integers). Lines may be outside the data range for zero-count columns/rows.\nstatic vector<int> plan_lines_from_targets(const vector<int>& arr_sorted, const vector<int>& targets, bool isX) {\n    int N = (int)arr_sorted.size();\n    int L = (int)targets.size(); // number of lines = columns/rows - 1\n    vector<int> safe = build_safe_indices(arr_sorted);\n    vector<int> lines; lines.reserve(L);\n\n    int pos = 0; // next index of point that will belong to next segment\n    int leftExtra = 0;  // number of extra empty lines placed on the far left/bottom\n    int rightExtra = 0; // number of extra empty lines placed on the far right/top\n\n    int minV = arr_sorted.front();\n    int maxV = arr_sorted.back();\n\n    for (int i = 0; i < L; ++i) {\n        int c = targets[i];\n        if (pos >= N) {\n            // no points left; place remaining lines to the far right/top\n            int coord = maxV + 1 + rightExtra;\n            lines.push_back(coord);\n            rightExtra++;\n            continue;\n        }\n        if (c <= 0) {\n            // Create an empty segment by placing a line to the far left/bottom\n            int coord = minV - 1 - leftExtra;\n            lines.push_back(coord);\n            leftExtra++;\n            continue;\n        }\n        // Desired last index on the left side\n        int desired = pos + c - 1;\n        if (desired < pos - 1) desired = pos - 1;\n        if (desired > N - 1) desired = N - 1;\n\n        int j = choose_nearest_safe(safe, desired, pos - 1);\n        // j is the last index included on the left side (could be -1 or N-1)\n        int coord;\n        if (j == -1) {\n            coord = minV - 1 - leftExtra;\n            leftExtra++;\n        } else if (j >= 0 && j < N - 1) {\n            // choose an integer strictly between arr_sorted[j] and arr_sorted[j+1]\n            // arr_sorted[j+1] - arr_sorted[j] >= 2 by construction\n            // we can pick arr_sorted[j] + 1 safely\n            coord = arr_sorted[j] + 1;\n        } else { // j == N-1\n            coord = maxV + 1 + rightExtra;\n            rightExtra++;\n        }\n        lines.push_back(coord);\n        // Advance pos: j+1 points have been assigned to the left side of this line since this segment started at pos\n        // But careful: pos is the start of current segment; after placing this line, left side extends to j inclusive -> new pos = j+1\n        // However, if we placed a far-left line (j = -1), pos remains unchanged (0 points assigned)\n        if (j >= pos - 1) {\n            pos = max(pos, j + 1);\n        }\n    }\n    // sort the line coordinates to get a proper monotone sequence for binary search\n    sort(lines.begin(), lines.end());\n    // also ensure uniqueness is not required by the problem, duplicates are allowed but wasteful;\n    // we don't strictly need to enforce uniqueness here.\n\n    return lines;\n}\n\n// Compute predicted expected matches using a Poisson model.\n// Given N, C columns, R rows, geometric ratios rx and ry,\n// returns predicted sum_d min(a_d, expected b_d)\nstatic long double predicted_matches(int N, int C, int R, long double rx, long double ry, const array<int,11>& a) {\n    vector<long double> s = geometric_weights(C, rx);\n    vector<long double> w = geometric_weights(R, ry);\n    normalize(s);\n    normalize(w);\n\n    static long double fact[21];\n    static bool fact_init = false;\n    if (!fact_init) {\n        fact[0] = 1.0L;\n        for (int i = 1; i <= 20; ++i) fact[i] = fact[i-1] * (long double)i;\n        fact_init = true;\n    }\n\n    // expected_b[d] = sum_{cells} P(Poisson(m_ij) = d), m_ij = N*s_i*w_j\n    long double expected_b[11] = {};\n    for (int i = 0; i < C; ++i) {\n        for (int j = 0; j < R; ++j) {\n            long double m = (long double)N * s[i] * w[j];\n            // For computational stability: if m > 100, P(d<=10) is negligible\n            if (m <= 100.0L) {\n                long double em = expl(-m);\n                long double powm = 1.0L; // m^0\n                for (int d = 1; d <= 10; ++d) {\n                    powm *= m; // m^d\n                    long double p = em * powm / fact[d];\n                    expected_b[d] += p;\n                }\n            }\n        }\n    }\n    long double sum_min = 0;\n    for (int d = 1; d <= 10; ++d) {\n        sum_min += min((long double)a[d], expected_b[d]);\n    }\n    return sum_min;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, K;\n    if (!(cin >> N >> K)) {\n        return 0;\n    }\n    array<int,11> a{}; // a[1..10]\n    for (int d = 1; d <= 10; ++d) cin >> a[d];\n    vector<Point> pts(N);\n    for (int i = 0; i < N; ++i) cin >> pts[i].x >> pts[i].y;\n\n    // Prepare sorted coordinate arrays\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; ++i) {\n        xs[i] = pts[i].x;\n        ys[i] = pts[i].y;\n    }\n    sort(xs.begin(), xs.end());\n    sort(ys.begin(), ys.end());\n\n    // Parameter search over vertical/horizontal split and geometric ratios\n    // We'll try a reasonable grid of options and pick the best predicted combination.\n    vector<long double> rset = {0.85L, 0.88L, 0.91L, 0.94L, 0.97L};\n    int bestV = K/2; // number of vertical lines initially\n    long double bestRx = 0.91L, bestRy = 0.91L;\n    long double bestPred = -1e100;\n\n    // Reasonable search ranges: ensure both families get at least a few lines\n    for (int v = max(1, K/3); v <= K - 1; v += 2) {\n        int h = K - v;\n        int C = v + 1;\n        int R = h + 1;\n        if (C < 2 || R < 2) continue;\n        // avoid extremely skewed splits\n        if (min(C, R) < 5) continue;\n\n        for (long double rx : rset) {\n            for (long double ry : rset) {\n                long double pred = predicted_matches(N, C, R, rx, ry, a);\n                if (pred > bestPred) {\n                    bestPred = pred;\n                    bestV = v;\n                    bestRx = rx;\n                    bestRy = ry;\n                }\n            }\n        }\n    }\n\n    int V = bestV;          // number of vertical lines\n    int H = K - V;          // number of horizontal lines\n    int C = V + 1;          // number of columns\n    int R = H + 1;          // number of rows\n\n    // Build geometric weights and compute targets\n    vector<long double> sw = geometric_weights(C, bestRx);\n    vector<long double> ww = geometric_weights(R, bestRy);\n    normalize(sw);\n    normalize(ww);\n\n    // Create integer targets for column and row totals\n    vector<int> colTargets = targets_from_weights(sw, N);\n    vector<int> rowTargets = targets_from_weights(ww, N);\n\n    // Reorder targets to put zeros at the ends (helps with planning lines outside range)\n    // Sort columns counts descending, rows descending\n    stable_sort(colTargets.begin(), colTargets.end(), greater<int>());\n    stable_sort(rowTargets.begin(), rowTargets.end(), greater<int>());\n\n    // Plan vertical and horizontal line positions\n    vector<int> xlines = plan_lines_from_targets(xs, vector<int>(colTargets.begin(), colTargets.end()-1), true);\n    vector<int> ylines = plan_lines_from_targets(ys, vector<int>(rowTargets.begin(), rowTargets.end()-1), false);\n\n    // Ensure we have exactly V vertical and H horizontal lines\n    if ((int)xlines.size() != V) {\n        // If mismatch occurs (shouldn't), pad outside\n        int minX = xs.front(), maxX = xs.back();\n        while ((int)xlines.size() < V) xlines.push_back(maxX + 1000 + (int)xlines.size());\n        while ((int)xlines.size() > V) xlines.pop_back();\n        sort(xlines.begin(), xlines.end());\n    }\n    if ((int)ylines.size() != H) {\n        int minY = ys.front(), maxY = ys.back();\n        while ((int)ylines.size() < H) ylines.push_back(maxY + 1000 + (int)ylines.size());\n        while ((int)ylines.size() > H) ylines.pop_back();\n        sort(ylines.begin(), ylines.end());\n    }\n\n    // Compute actual cell counts\n    // Columns are determined by number of xlines < xi, rows by number of ylines < yi\n    vector<int> cellCounts(C * R, 0);\n    for (const auto& p : pts) {\n        int ci = int(lower_bound(xlines.begin(), xlines.end(), p.x) - xlines.begin());\n        int ri = int(lower_bound(ylines.begin(), ylines.end(), p.y) - ylines.begin());\n        if (ci < 0) ci = 0;\n        if (ci > V) ci = V;\n        if (ri < 0) ri = 0;\n        if (ri > H) ri = H;\n        cellCounts[ri * C + ci] += 1;\n    }\n\n    // Count b_d\n    array<int, 11> b{}; // b[1..10]\n    for (int idx = 0; idx < C * R; ++idx) {\n        int cval = cellCounts[idx];\n        if (cval >= 1 && cval <= 10) b[cval]++;\n    }\n\n    // Output lines\n    // Each line is specified by two integer points. For vertical lines x = x0, we output (x0, -1e9 + t) to (x0, 1e9 - t)\n    // For horizontal lines y = y0, output (-1e9 + t, y0) to (1e9 - t, y0)\n    cout << (V + H) << \"\\n\";\n    // Vertical lines\n    for (int i = 0; i < V; ++i) {\n        int x0 = xlines[i];\n        // ensure distinct endpoints (using different y to avoid identical points)\n        long long y1 = -1000000000LL + i + 7;\n        long long y2 = 1000000000LL - i - 7;\n        cout << x0 << \" \" << y1 << \" \" << x0 << \" \" << y2 << \"\\n\";\n    }\n    // Horizontal lines\n    for (int j = 0; j < H; ++j) {\n        int y0 = ylines[j];\n        long long x1 = -1000000000LL + j + 13;\n        long long x2 = 1000000000LL - j - 13;\n        cout << x1 << \" \" << y0 << \" \" << x2 << \" \" << y0 << \"\\n\";\n    }\n\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Operation {\n    int x1,y1,x2,y2,x3,y3,x4,y4;\n};\n\n// Global-like context (wrapped into a class-like namespace by static vars/functions)\nstruct Solver {\n    int N, M;\n    vector<uint8_t> occ; // N*N occupancy grid\n    vector<pair<int,int>> points; // all dots as they appear (initial + added)\n    int c; // center coordinate (N-1)/2\n\n    // used unit segments\n    vector<uint8_t> usedH; // size N*(N-1): seg (x,y)-(x+1,y), x in [0..N-2], y in [0..N-1]\n    vector<uint8_t> usedV; // size (N-1)*N: seg (x,y)-(x,y+1), y in [0..N-2], x in [0..N-1]\n    vector<uint8_t> usedD1; // size (N-1)*(N-1): seg (x,y)-(x+1,y+1), x,y in [0..N-2]\n    vector<uint8_t> usedD2; // size (N-1)*(N-1): seg (x,y)-(x+1,y-1), x in [0..N-2], y in [1..N-1] mapped to index (y-1)*(N-1)+x\n\n    inline int idx(int x, int y) const { return y*N + x; }\n    inline int idxH(int x, int y) const { return y*(N-1) + x; }\n    inline int idxV(int x, int y) const { return y*N + x; }\n    inline int idxD1_fromPoints(int x0, int y0, int x1, int y1) const {\n        // slope +1 segment normalized: (min x, min y)\n        int x = min(x0, x1);\n        int y = min(y0, y1);\n        return y*(N-1) + x;\n    }\n    inline int idxD2_fromPoints(int x0, int y0, int x1, int y1) const {\n        // slope -1 segment normalized: (min x, max y), then (y-1)*(N-1)+x\n        int x = min(x0, x1);\n        int y = max(y0, y1); // this y is in [1..N-1]\n        return (y-1)*(N-1) + x;\n    }\n\n    inline int weight(int x, int y) const {\n        int dx = x - c;\n        int dy = y - c;\n        return dx*dx + dy*dy + 1;\n    }\n\n    struct Candidate {\n        // type 0: axis-aligned rectangle\n        // type 1: 45\u00b0 square (diamond)\n        int type;\n        int p1x, p1y;\n        int w;\n        // axis-aligned fields\n        int xL, xR, yB, yT;\n        // diamond fields\n        int xc, yc, d;\n    };\n\n    struct CandCmp {\n        bool operator()(const Candidate& a, const Candidate& b) const {\n            if (a.w != b.w) return a.w < b.w; // max-heap by weight\n            // tie-breaker: prefer larger span (more \"outer\")\n            int aa = (a.type==0) ? ((a.xR - a.xL) + (a.yT - a.yB)) : (2*a.d);\n            int bb = (b.type==0) ? ((b.xR - b.xL) + (b.yT - b.yB)) : (2*b.d);\n            if (aa != bb) return aa < bb;\n            // small deterministic tie-break\n            if (a.p1x != b.p1x) return a.p1x < b.p1x;\n            return a.p1y < b.p1y;\n        }\n    };\n\n    priority_queue<Candidate, vector<Candidate>, CandCmp> pq;\n    vector<Operation> ops;\n\n    Solver(int N_, int M_) : N(N_), M(M_) {\n        c = (N - 1) / 2;\n        occ.assign(N*N, 0);\n        usedH.assign(N*(N-1), 0);\n        usedV.assign((N-1)*N, 0);\n        usedD1.assign((N-1)*(N-1), 0);\n        usedD2.assign((N-1)*(N-1), 0);\n    }\n\n    inline bool isInside(int x, int y) const {\n        return (0 <= x && x < N && 0 <= y && y < N);\n    }\n\n    bool validateAxis(const Candidate& cd) const {\n        // Preconds: cd.type==0\n        // Check p1 empty\n        if (!isInside(cd.p1x, cd.p1y)) return false;\n        if (occ[idx(cd.p1x, cd.p1y)]) return false;\n        // Check other three corners occupied\n        int cntExist = 0;\n        int cx[4] = {cd.xL, cd.xR, cd.xR, cd.xL};\n        int cy[4] = {cd.yB, cd.yB, cd.yT, cd.yT};\n        for (int i=0;i<4;i++) {\n            if (cx[i]==cd.p1x && cy[i]==cd.p1y) continue;\n            if (!isInside(cx[i],cy[i])) return false;\n            if (!occ[idx(cx[i], cy[i])]) return false;\n            cntExist++;\n        }\n        if (cntExist != 3) return false;\n\n        // Boundary interior points must be empty\n        for (int x = cd.xL+1; x <= cd.xR-1; ++x) {\n            if (occ[idx(x, cd.yB)]) return false;\n            if (occ[idx(x, cd.yT)]) return false;\n        }\n        for (int y = cd.yB+1; y <= cd.yT-1; ++y) {\n            if (occ[idx(cd.xL, y)]) return false;\n            if (occ[idx(cd.xR, y)]) return false;\n        }\n\n        // Check used segments\n        for (int x = cd.xL; x <= cd.xR-1; ++x) {\n            if (usedH[idxH(x, cd.yB)]) return false;\n            if (usedH[idxH(x, cd.yT)]) return false;\n        }\n        for (int y = cd.yB; y <= cd.yT-1; ++y) {\n            if (usedV[idxV(cd.xL, y)]) return false;\n            if (usedV[idxV(cd.xR, y)]) return false;\n        }\n        return true;\n    }\n\n    bool validateDiamond(const Candidate& cd) const {\n        // Preconds: cd.type==1\n        int xc = cd.xc, yc = cd.yc, d = cd.d;\n        if (d <= 0) return false;\n        // four corners\n        int tx = xc, ty = yc + d; // top\n        int rx = xc + d, ry = yc; // right\n        int bx = xc, by = yc - d; // bottom\n        int lx = xc - d, ly = yc; // left\n\n        // Ensure inside\n        if (!isInside(cd.p1x, cd.p1y)) return false;\n        if (!isInside(tx,ty) || !isInside(rx,ry) || !isInside(bx,by) || !isInside(lx,ly)) return false;\n\n        // p1 empty\n        if (occ[idx(cd.p1x, cd.p1y)]) return false;\n\n        // other three corners occupied\n        int cornersX[4] = {tx, rx, bx, lx};\n        int cornersY[4] = {ty, ry, by, ly};\n        int cntExist = 0;\n        for (int i=0;i<4;i++) {\n            if (cornersX[i]==cd.p1x && cornersY[i]==cd.p1y) continue;\n            if (!occ[idx(cornersX[i], cornersY[i])]) return false;\n            cntExist++;\n        }\n        if (cntExist != 3) return false;\n\n        // Perimeter interior points empty\n        // top->right: (xc+k, yc+d-k) for k=1..d-1\n        for (int k=1; k<=d-1; ++k) {\n            if (occ[idx(xc + k, yc + d - k)]) return false;\n        }\n        // right->bottom: (xc+d-k, yc - k) for k=1..d-1\n        for (int k=1; k<=d-1; ++k) {\n            if (occ[idx(xc + d - k, yc - k)]) return false;\n        }\n        // bottom->left: (xc - k, yc - d + k) for k=1..d-1\n        for (int k=1; k<=d-1; ++k) {\n            if (occ[idx(xc - k, yc - d + k)]) return false;\n        }\n        // left->top: (xc - d + k, yc + k) for k=1..d-1\n        for (int k=1; k<=d-1; ++k) {\n            if (occ[idx(xc - d + k, yc + k)]) return false;\n        }\n\n        // Check used diagonal segments\n        // top->right: slope -1, segments between (xc+k, yc+d-k) -> (xc+k+1, yc+d-k-1), k=0..d-1\n        for (int k=0; k<=d-1; ++k) {\n            int x0 = xc + k, y0 = yc + d - k;\n            int x1 = xc + k + 1, y1 = yc + d - k - 1;\n            int id = idxD2_fromPoints(x0,y0,x1,y1);\n            if (usedD2[id]) return false;\n        }\n        // right->bottom: slope +1, between (xc+d-k, yc-k) -> (xc+d-k-1, yc-k-1)\n        for (int k=0; k<=d-1; ++k) {\n            int x0 = xc + d - k, y0 = yc - k;\n            int x1 = xc + d - k - 1, y1 = yc - k - 1;\n            int id = idxD1_fromPoints(x0,y0,x1,y1);\n            if (usedD1[id]) return false;\n        }\n        // bottom->left: slope -1, between (xc - k, yc - d + k) -> (xc - k - 1, yc - d + k + 1)\n        for (int k=0; k<=d-1; ++k) {\n            int x0 = xc - k, y0 = yc - d + k;\n            int x1 = xc - k - 1, y1 = yc - d + k + 1;\n            int id = idxD2_fromPoints(x0,y0,x1,y1);\n            if (usedD2[id]) return false;\n        }\n        // left->top: slope +1, between (xc - d + k, yc + k) -> (xc - d + k + 1, yc + k + 1)\n        for (int k=0; k<=d-1; ++k) {\n            int x0 = xc - d + k, y0 = yc + k;\n            int x1 = xc - d + k + 1, y1 = yc + k + 1;\n            int id = idxD1_fromPoints(x0,y0,x1,y1);\n            if (usedD1[id]) return false;\n        }\n\n        return true;\n    }\n\n    bool validate(const Candidate& cd) const {\n        if (cd.type == 0) return validateAxis(cd);\n        else return validateDiamond(cd);\n    }\n\n    void markUsedSegments(const Candidate& cd) {\n        if (cd.type == 0) {\n            // Horizontal edges\n            for (int x = cd.xL; x <= cd.xR-1; ++x) {\n                usedH[idxH(x, cd.yB)] = 1;\n                usedH[idxH(x, cd.yT)] = 1;\n            }\n            // Vertical edges\n            for (int y = cd.yB; y <= cd.yT-1; ++y) {\n                usedV[idxV(cd.xL, y)] = 1;\n                usedV[idxV(cd.xR, y)] = 1;\n            }\n        } else {\n            int xc = cd.xc, yc = cd.yc, d = cd.d;\n            // top->right\n            for (int k=0; k<=d-1; ++k) {\n                int x0 = xc + k, y0 = yc + d - k;\n                int x1 = xc + k + 1, y1 = yc + d - k - 1;\n                int id = idxD2_fromPoints(x0,y0,x1,y1);\n                usedD2[id] = 1;\n            }\n            // right->bottom\n            for (int k=0; k<=d-1; ++k) {\n                int x0 = xc + d - k, y0 = yc - k;\n                int x1 = xc + d - k - 1, y1 = yc - k - 1;\n                int id = idxD1_fromPoints(x0,y0,x1,y1);\n                usedD1[id] = 1;\n            }\n            // bottom->left\n            for (int k=0; k<=d-1; ++k) {\n                int x0 = xc - k, y0 = yc - d + k;\n                int x1 = xc - k - 1, y1 = yc - d + k + 1;\n                int id = idxD2_fromPoints(x0,y0,x1,y1);\n                usedD2[id] = 1;\n            }\n            // left->top\n            for (int k=0; k<=d-1; ++k) {\n                int x0 = xc - d + k, y0 = yc + k;\n                int x1 = xc - d + k + 1, y1 = yc + k + 1;\n                int id = idxD1_fromPoints(x0,y0,x1,y1);\n                usedD1[id] = 1;\n            }\n        }\n    }\n\n    void emitOperation(const Candidate& cd) {\n        Operation op;\n        if (cd.type == 0) {\n            // cw order: LL -> LR -> UR -> UL\n            int LLx = cd.xL, LLy = cd.yB;\n            int LRx = cd.xR, LRy = cd.yB;\n            int URx = cd.xR, URy = cd.yT;\n            int ULx = cd.xL, ULy = cd.yT;\n            array<pair<int,int>,4> seq = {{{LLx,LLy},{LRx,LRy},{URx,URy},{ULx,ULy}}};\n            int pos = 0;\n            for (int i=0;i<4;i++) if (seq[i].first==cd.p1x && seq[i].second==cd.p1y) { pos=i; break; }\n            auto get = [&](int k)->pair<int,int> { return seq[(pos + k) % 4]; };\n            auto p1 = get(0);\n            auto p2 = get(1);\n            auto p3 = get(2);\n            auto p4 = get(3);\n            op = {p1.first,p1.second,p2.first,p2.second,p3.first,p3.second,p4.first,p4.second};\n        } else {\n            // diamond cw top->right->bottom->left\n            int tx = cd.xc, ty = cd.yc + cd.d; // top\n            int rx = cd.xc + cd.d, ry = cd.yc; // right\n            int bx = cd.xc, by = cd.yc - cd.d; // bottom\n            int lx = cd.xc - cd.d, ly = cd.yc; // left\n            array<pair<int,int>,4> seq = {{{tx,ty},{rx,ry},{bx,by},{lx,ly}}};\n            int pos = 0;\n            for (int i=0;i<4;i++) if (seq[i].first==cd.p1x && seq[i].second==cd.p1y) { pos=i; break; }\n            auto get = [&](int k)->pair<int,int> { return seq[(pos + k) % 4]; };\n            auto p1 = get(0);\n            auto p2 = get(1);\n            auto p3 = get(2);\n            auto p4 = get(3);\n            op = {p1.first,p1.second,p2.first,p2.second,p3.first,p3.second,p4.first,p4.second};\n        }\n        ops.push_back(op);\n    }\n\n    void pushAxisCandidateFromPair(int x1, int y1, int x2, int y2) {\n        if (x1 == x2 || y1 == y2) return; // need diagonal pair\n        int xL = min(x1, x2), xR = max(x1, x2);\n        int yB = min(y1, y2), yT = max(y1, y2);\n        int c1x = x1, c1y = y2; // (x1,y2)\n        int c2x = x2, c2y = y1; // (x2,y1)\n        bool occ1 = occ[idx(c1x, c1y)];\n        bool occ2 = occ[idx(c2x, c2y)];\n        if (occ1 == occ2) return; // need exactly one occupied\n        Candidate cd;\n        cd.type = 0;\n        if (!occ1) { cd.p1x = c1x; cd.p1y = c1y; }\n        else       { cd.p1x = c2x; cd.p1y = c2y; }\n        cd.xL = xL; cd.xR = xR; cd.yB = yB; cd.yT = yT;\n        cd.w = weight(cd.p1x, cd.p1y);\n        if (validate(cd)) pq.push(cd);\n    }\n\n    void pushDiamondCandidateFromVerticalPair(int x, int y1, int y2) {\n        if (y1 == y2) return;\n        int dAbs = abs(y2 - y1);\n        if (dAbs % 2 != 0) return;\n        int d = dAbs / 2;\n        if (d == 0) return;\n        int yc = (y1 + y2) / 2;\n        int xc = x;\n        int lx = xc - d, ly = yc;\n        int rx = xc + d, ry = yc;\n        if (!isInside(lx,ly) || !isInside(rx,ry)) return;\n        bool occL = occ[idx(lx,ly)];\n        bool occR = occ[idx(rx,ry)];\n        if (occL == occR) return; // need exactly one\n        Candidate cd;\n        cd.type = 1;\n        cd.xc = xc; cd.yc = yc; cd.d = d;\n        if (!occL) { cd.p1x = lx; cd.p1y = ly; }\n        else       { cd.p1x = rx; cd.p1y = ry; }\n        cd.w = weight(cd.p1x, cd.p1y);\n        if (validate(cd)) pq.push(cd);\n    }\n\n    void pushDiamondCandidateFromHorizontalPair(int y, int x1, int x2) {\n        if (x1 == x2) return;\n        int dAbs = abs(x2 - x1);\n        if (dAbs % 2 != 0) return;\n        int d = dAbs / 2;\n        if (d == 0) return;\n        int xc = (x1 + x2) / 2;\n        int yc = y;\n        int tx = xc, ty = yc + d;\n        int bx = xc, by = yc - d;\n        if (!isInside(tx,ty) || !isInside(bx,by)) return;\n        bool occT = occ[idx(tx,ty)];\n        bool occB = occ[idx(bx,by)];\n        if (occT == occB) return;\n        Candidate cd;\n        cd.type = 1;\n        cd.xc = xc; cd.yc = yc; cd.d = d;\n        if (!occT) { cd.p1x = tx; cd.p1y = ty; }\n        else       { cd.p1x = bx; cd.p1y = by; }\n        cd.w = weight(cd.p1x, cd.p1y);\n        if (validate(cd)) pq.push(cd);\n    }\n\n    void initialCandidates() {\n        int P = (int)points.size();\n        for (int i=0;i<P;i++) {\n            auto [x1,y1] = points[i];\n            for (int j=i+1;j<P;j++) {\n                auto [x2,y2] = points[j];\n                // Axis-aligned rectangle candidates\n                pushAxisCandidateFromPair(x1,y1,x2,y2);\n                // Diamond candidates from vertical/horizontal pairs\n                if (x1 == x2) {\n                    pushDiamondCandidateFromVerticalPair(x1, y1, y2);\n                }\n                if (y1 == y2) {\n                    pushDiamondCandidateFromHorizontalPair(y1, x1, x2);\n                }\n            }\n        }\n    }\n\n    void generateFromNewPoint(int nx, int ny) {\n        int P = (int)points.size() - 1; // existing points excluding the newly appended? We'll iterate all previous\n        for (int i=0;i<P;i++) {\n            int x2 = points[i].first;\n            int y2 = points[i].second;\n            // Axis-aligned: (nx,ny) with (x2,y2) as diagonal corners\n            if (nx != x2 && ny != y2) {\n                pushAxisCandidateFromPair(nx,ny,x2,y2);\n            }\n            // Diamond: vertical/horizontal pairs\n            if (nx == x2) {\n                pushDiamondCandidateFromVerticalPair(nx, ny, y2);\n            }\n            if (ny == y2) {\n                pushDiamondCandidateFromHorizontalPair(ny, nx, x2);\n            }\n        }\n    }\n\n    void solve() {\n        // initial candidates\n        initialCandidates();\n\n        auto start = chrono::steady_clock::now();\n        const double TIME_LIMIT = 4.90; // seconds\n\n        while (!pq.empty()) {\n            // time check\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - start).count();\n            if (elapsed > TIME_LIMIT) break;\n\n            Candidate cd = pq.top(); pq.pop();\n            if (!validate(cd)) continue;\n\n            // Commit this operation\n            // place p1\n            occ[idx(cd.p1x, cd.p1y)] = 1;\n            points.emplace_back(cd.p1x, cd.p1y);\n            // mark used segments\n            markUsedSegments(cd);\n            // record output operation\n            emitOperation(cd);\n            // generate new candidates involving the new point\n            generateFromNewPoint(cd.p1x, cd.p1y);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) {\n        return 0;\n    }\n    Solver solver(N, M);\n    solver.points.reserve(N*N);\n    for (int i=0;i<M;i++) {\n        int x,y; cin >> x >> y;\n        solver.points.emplace_back(x,y);\n        solver.occ[solver.idx(x,y)] = 1;\n    }\n\n    solver.solve();\n\n    // Output\n    cout << solver.ops.size() << '\\n';\n    for (auto &op : solver.ops) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << ' '\n             << op.x3 << ' ' << op.y3 << ' ' << op.x4 << ' ' << op.y4 << '\\n';\n    }\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\n// DSU for at most 100 cells\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    void reset(int m) { n=m; p.resize(n); sz.assign(n,1); iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\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; sz[a]+=sz[b];\n        return true;\n    }\n    int size(int x){ return sz[find(x)]; }\n};\n\nstruct EvalWeights {\n    double w_comp;      // weight for sum of squares of component sizes\n    double w_sumDist;   // weight for sum of distances of all candies to their corners\n    double w_newDist;   // extra weight for new candy's distance to its corner\n    double w_adjNewSame; // reward per same-color neighbor for new candy\n    double w_adjNewDiff; // penalty per different-color neighbor for new candy\n};\n\n// Directions: F=0, B=1, L=2, R=3\nstatic const int dr[4] = {-1, +1, 0, 0};\nstatic const int dc[4] = {0, 0, -1, +1};\n\nstruct Simulator {\n    static const int H = 10;\n    static const int W = 10;\n\n    // Board: 0 empty, 1..3 flavors\n    array<array<int,W>,H> board;\n\n    Simulator() { for (int i=0;i<H;i++) for (int j=0;j<W;j++) board[i][j]=0; }\n\n    // Map empty index (1-based) to coordinates in row-major of empty cells\n    pair<int,int> emptyIndexToRC(int p) const {\n        int cnt=0;\n        for(int r=0;r<H;r++){\n            for(int c=0;c<W;c++){\n                if(board[r][c]==0){\n                    ++cnt;\n                    if(cnt==p) return {r,c};\n                }\n            }\n        }\n        // Should not happen\n        return {-1,-1};\n    }\n\n    // Simulate tilt on a given board; also compute the new position of a \"tracked\" cell src\n    // tracked cell coordinates assumed valid in inputBoard; returns destBoard & new pos for the tracked cell\n    struct SimResult {\n        array<array<int,W>,H> b;\n        int new_r, new_c;\n    };\n\n    SimResult simulateTilt(const array<array<int,W>,H>& inputBoard, int dir, int src_r, int src_c) const {\n        SimResult res;\n        res.b = {}; // zero init\n        // compute new pos of tracked candy by stable compression rule\n        if (dir == 0) { // F: compress up\n            int cnt = 0;\n            for (int r = 0; r <= src_r; ++r) if (inputBoard[r][src_c] != 0) ++cnt;\n            res.new_r = cnt-1;\n            res.new_c = src_c;\n            // build compressed board\n            for (int c=0;c<W;c++){\n                int to = 0;\n                for (int r=0;r<H;r++){\n                    int v = inputBoard[r][c];\n                    if (v!=0) res.b[to++][c] = v;\n                }\n            }\n        } else if (dir == 1) { // B: compress down\n            int cnt = 0;\n            for (int r = src_r; r < H; ++r) if (inputBoard[r][src_c] != 0) ++cnt;\n            res.new_r = H-1 - (cnt-1);\n            res.new_c = src_c;\n            for (int c=0;c<W;c++){\n                int to = H-1;\n                for (int r=H-1;r>=0;r--){\n                    int v = inputBoard[r][c];\n                    if (v!=0) res.b[to--][c] = v;\n                }\n            }\n        } else if (dir == 2) { // L: compress left\n            int cnt = 0;\n            for (int c=0; c<=src_c; ++c) if (inputBoard[src_r][c] != 0) ++cnt;\n            res.new_r = src_r;\n            res.new_c = cnt-1;\n            for (int r=0;r<H;r++){\n                int to = 0;\n                for (int c=0;c<W;c++){\n                    int v = inputBoard[r][c];\n                    if (v!=0) res.b[r][to++] = v;\n                }\n            }\n        } else { // R: compress right\n            int cnt = 0;\n            for (int c=src_c; c<W; ++c) if (inputBoard[src_r][c] != 0) ++cnt;\n            res.new_r = src_r;\n            res.new_c = W-1 - (cnt-1);\n            for (int r=0;r<H;r++){\n                int to = W-1;\n                for (int c=W-1;c>=0;c--){\n                    int v = inputBoard[r][c];\n                    if (v!=0) res.b[r][to--] = v;\n                }\n            }\n        }\n        return res;\n    }\n\n    // Evaluate board using component squares + distance-to-corner, etc.\n    // corners[color] = target corner coordinates for color in 1..3\n    double evaluate(const array<array<int,W>,H>& b, const EvalWeights& w,\n                    const array<pair<int,int>, 4>& cornerOf, const array<int, 4>& colorCornerMap,\n                    int new_candy_color, int new_r, int new_c) const\n    {\n        // Sum of squared component sizes (for all colors separately)\n        DSU dsu(H*W);\n        auto id = [](int r,int c){ return r*10 + c; };\n        for (int r=0;r<H;r++){\n            for (int c=0;c<W;c++){\n                int v = b[r][c];\n                if (v==0) continue;\n                // Right neighbor\n                if (c+1<W && b[r][c+1]==v) dsu.unite(id(r,c), id(r,c+1));\n                // Down neighbor\n                if (r+1<H && b[r+1][c]==v) dsu.unite(id(r,c), id(r+1,c));\n            }\n        }\n        // accumulate component sizes\n        vector<int> compSize(H*W, 0);\n        vector<char> seen(H*W, 0);\n        for (int r=0;r<H;r++){\n            for (int c=0;c<W;c++){\n                if (b[r][c]==0) continue;\n                int root = dsu.find(id(r,c));\n                compSize[root]++;\n            }\n        }\n        long long sumSq = 0;\n        for (int i=0;i<H*W;i++){\n            if (compSize[i]>0) {\n                long long s = compSize[i];\n                sumSq += s*s;\n            }\n        }\n\n        // Distance to corners\n        long long sumDist = 0;\n        for (int r=0;r<H;r++){\n            for (int c=0;c<W;c++){\n                int v = b[r][c];\n                if (v==0) continue;\n                // color v uses corner cornerOf[colorCornerMap[v]], where colorCornerMap[v] gives index 0..3 of chosen corner\n                int cornerIdx = colorCornerMap[v]; // 0..3\n                auto [tr, tc] = cornerOf[cornerIdx];\n                sumDist += abs(r - tr) + abs(c - tc);\n            }\n        }\n\n        // New candy terms\n        long long newDist = 0;\n        int adjSame = 0, adjDiff = 0;\n        if (0 <= new_r && new_r < H && 0 <= new_c && new_c < W) {\n            int cornerIdx = colorCornerMap[new_candy_color];\n            auto [tr, tc] = cornerOf[cornerIdx];\n            newDist = abs(new_r - tr) + abs(new_c - tc);\n\n            static const int dr4[4] = {-1,1,0,0};\n            static const int dc4[4] = {0,0,-1,1};\n            for (int k=0;k<4;k++){\n                int nr = new_r + dr4[k], nc = new_c + dc4[k];\n                if (0 <= nr && nr < H && 0 <= nc && nc < W) {\n                    int v = b[nr][nc];\n                    if (v == 0) continue;\n                    if (v == new_candy_color) adjSame++;\n                    else adjDiff++;\n                }\n            }\n        }\n\n        // Combine\n        double score = 0.0;\n        score += w.w_comp * (double)sumSq;\n        score -= w.w_sumDist * (double)sumDist;\n        score -= w.w_newDist * (double)newDist;\n        score += w.w_adjNewSame * (double)adjSame;\n        score -= w.w_adjNewDiff * (double)adjDiff;\n\n        return score;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Read all flavors\n    vector<int> f(100);\n    for (int i=0;i<100;i++){\n        if(!(cin>>f[i])) return 0;\n    }\n\n    Simulator sim;\n\n    // Choose corners\n    // Corners: 0: TL(0,0), 1: TR(0,9), 2: BL(9,0), 3: BR(9,9)\n    array<pair<int,int>, 4> corners = { pair<int,int>{0,0}, {0,9}, {9,0}, {9,9} };\n\n    // Map color -> cornerIdx (0..3), using 3 distinct corners; leave one unused.\n    // Simple fixed mapping:\n    // 1 -> TL (0), 2 -> TR (1), 3 -> BL (2)\n    array<int, 4> colorCornerMap = {0, 0, 1, 2}; // index 0 unused; color 1->0, 2->1, 3->2\n\n    // Main interactive loop\n    for (int t = 0; t < 100; t++) {\n        int p; \n        if(!(cin >> p)) return 0;\n\n        // Find placement position\n        auto [r, c] = sim.emptyIndexToRC(p);\n        // Place candy temporarily\n        auto board0 = sim.board;\n        int color = f[t];\n        board0[r][c] = color;\n\n        // Decide tilt direction (skip output when t==99 is allowed; we still compute for consistency)\n        // Prepare time-dependent weights\n        double progress = (t <= 98 ? (double)t / 98.0 : 1.0); // up to 1 near end\n        EvalWeights w;\n        // Emphasize comp later\n        w.w_comp = 3.0 + 12.0 * progress;       // ~3 .. 15\n        w.w_sumDist = 0.25;                      // small\n        w.w_newDist = 2.5 * (1.0 - progress) + 0.5; // bigger early, smaller late: 3.0 .. 0.5\n        w.w_adjNewSame = 3.0;                    // reward adjacency to same color\n        w.w_adjNewDiff = 0.5;                    // small penalty for adjacency to different colors\n\n        double bestScore = -1e100;\n        int bestDir = 0;\n        Simulator::SimResult bestRes;\n\n        for (int d = 0; d < 4; d++) {\n            // Simulate tilt d after placement\n            auto res = sim.simulateTilt(board0, d, r, c);\n            // Evaluate\n            double sc = sim.evaluate(res.b, w, corners, colorCornerMap, color, res.new_r, res.new_c);\n            // Tie-breaker: prefer directions that move the new candy closer to its corner and fewer moving pieces could be added\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestDir = d;\n                bestRes = res;\n            }\n        }\n\n        // Output for first 99 steps\n        if (t < 99) {\n            char outch = \"FBLR\"[bestDir];\n            cout << outch << '\\n' << flush;\n        }\n\n        // Update simulator board\n        sim.board = bestRes.b;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Utility timer (not strictly needed)\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nstatic inline int ceil_log2_int(int x) {\n    int l = 0;\n    int v = 1;\n    while (v < x) { v <<= 1; l++; }\n    return l;\n}\n\n// Build an L x A binary matrix alpha with column sums t[a],\n// trying to keep row sums near A/2 and pairwise distances large.\nstatic vector<vector<int>> build_alpha(int Lbits, int A, const vector<int>& t, mt19937_64 &rng) {\n    vector<vector<int>> alpha(Lbits, vector<int>(A, 0));\n    vector<int> rowSum(Lbits, 0);\n\n    // Initial greedy fill: for each column a, place t[a] ones in rows with smallest rowSum\n    for (int a = 0; a < A; ++a) {\n        int need = t[a];\n        vector<int> idx(Lbits);\n        iota(idx.begin(), idx.end(), 0);\n        stable_sort(idx.begin(), idx.end(), [&](int r1, int r2){\n            if (rowSum[r1] != rowSum[r2]) return rowSum[r1] < rowSum[r2];\n            return r1 < r2;\n        });\n        for (int k = 0; k < need; ++k) {\n            int r = idx[k];\n            alpha[r][a] = 1;\n            rowSum[r]++;\n        }\n    }\n\n    // Try local improvements: swap bits within columns to maximize min pairwise Hamming distance\n    auto min_pairwise_dist = [&]() {\n        int mind = INT_MAX;\n        for (int i = 0; i < Lbits; ++i) {\n            for (int j = i+1; j < Lbits; ++j) {\n                int d = 0;\n                for (int a = 0; a < A; ++a) if (alpha[i][a] != alpha[j][a]) d++;\n                mind = min(mind, d);\n            }\n        }\n        return mind;\n    };\n    int currentMinD = min_pairwise_dist();\n\n    // Limit local search iterations for speed; dims are tiny so it's enough\n    uniform_int_distribution<int> distA(0, A-1);\n    uniform_int_distribution<int> distR(0, Lbits-1);\n    for (int iter = 0; iter < 2000; ++iter) {\n        int a = distA(rng);\n        // pick two rows with different bits\n        int r1 = distR(rng), r2 = distR(rng);\n        if (r1 == r2) continue;\n        if (alpha[r1][a] == alpha[r2][a]) continue;\n        // try swapping: 1->0 on r1 and 0->1 on r2, preserving column sum\n        alpha[r1][a] ^= 1;\n        alpha[r2][a] ^= 1;\n\n        int newMinD = min_pairwise_dist();\n        // Row sum balancing heuristic: prefer row sums near A/2 (or within +-2)\n        auto penalty = [&](const vector<int>& rs) {\n            int p = 0;\n            int target = A/2;\n            for (int r = 0; r < Lbits; ++r) {\n                int d = abs(rs[r] - target);\n                p += d*d;\n            }\n            return p;\n        };\n        vector<int> rowSumNew = rowSum;\n        rowSumNew[r1] += (alpha[r1][a] ? 1 : -1);\n        rowSumNew[r2] += (alpha[r2][a] ? 1 : -1);\n        int oldPen = penalty(rowSum);\n        int newPen = penalty(rowSumNew);\n\n        bool accept = false;\n        if (newMinD > currentMinD) accept = true;\n        else if (newMinD == currentMinD && newPen <= oldPen) accept = true;\n\n        if (accept) {\n            currentMinD = newMinD;\n            rowSum = rowSumNew;\n        } else {\n            // revert\n            alpha[r1][a] ^= 1;\n            alpha[r2][a] ^= 1;\n        }\n    }\n\n    return alpha;\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    mt19937_64 rng(123456789);\n\n    // Parameters\n    int Lbits = ceil_log2_int(M); // number of bits to encode\n    Lbits = max(Lbits, 1); // safety\n    // Anchors count: use A = Lbits + 1 so we can set column sums t[a] = a\n    int A = Lbits + 1;\n\n    // Choose cluster size g based on eps and fit N<=100 later\n    int g_desired;\n    if (eps <= 0.06) g_desired = 8;\n    else if (eps <= 0.14) g_desired = 9;\n    else g_desired = 10;\n\n    // Column sums t[a] = a (0..Lbits), ensure A = Lbits+1\n    vector<int> t(A);\n    for (int a = 0; a < A; ++a) t[a] = a;\n\n    // Build alpha (depends only on Lbits, A, t)\n    auto alpha = build_alpha(Lbits, A, t, rng);\n\n    // Row sums: to estimate cluster vertex degrees\n    vector<int> rowSum(Lbits, 0);\n    for (int i = 0; i < Lbits; ++i) {\n        for (int a = 0; a < A; ++a) rowSum[i] += alpha[i][a];\n    }\n    int rowSumMax = 0;\n    for (int i = 0; i < Lbits; ++i) rowSumMax = max(rowSumMax, rowSum[i]);\n\n    // pads U to ensure anchor min degree > cluster max degree (with margin)\n    // Anchor min degree = (A-1) [anchor clique] + U + g * t_min = (A-1) + U (since t_min=0)\n    // Cluster vertex max degree \u2248 rowSumMax + (g-1) (if the bit=1); add margin\n    int margin = 3;\n    int g = g_desired;\n    int U = 0;\n    while (true) {\n        int clusterMaxDeg = rowSumMax + (g - 1);\n        int Utarget = max(0, clusterMaxDeg + margin - (A - 1));\n        int N0 = A + Lbits * g;\n        if (N0 > 100) {\n            g--;\n            if (g < 6) { g = 6; /* minimal fallback */ break; }\n            continue;\n        }\n        if (N0 + Utarget <= 100) {\n            U = Utarget;\n            break;\n        } else {\n            g--;\n            if (g < 6) {\n                // Force U to fit\n                U = max(0, 100 - (A + Lbits * g));\n                break;\n            }\n        }\n    }\n    int N = A + U + Lbits * g;\n    int T = N * (N - 1) / 2;\n\n    // Precompute pair index mapping\n    vector<int> offset(N+1, 0);\n    for (int i = 1; i <= N; ++i) {\n        offset[i] = offset[i-1] + (N - i);\n    }\n    auto idx = [&](int i, int j) -> int {\n        if (i > j) swap(i, j);\n        // Now i<j\n        return offset[i] + (j - i - 1);\n    };\n\n    // Vertex ranges\n    // Anchors: 0..A-1\n    // Pads: A..A+U-1\n    // Clusters: for bit i in [0..Lbits-1], vertices [A+U + i*g, A+U + (i+1)*g - 1]\n    auto is_anchor = [&](int v) { return v >= 0 && v < A; };\n    auto is_pad = [&](int v) { return v >= A && v < A + U; };\n    auto cluster_start = [&](int bit) { return A + U + bit * g; };\n    auto cluster_end = [&](int bit) { return A + U + (bit + 1) * g - 1; };\n\n    // Build base string: all '0'\n    string base(T, '0');\n\n    // Anchors fully connected (clique)\n    for (int i = 0; i < A; ++i) {\n        for (int j = i + 1; j < A; ++j) {\n            base[idx(i, j)] = '1';\n        }\n    }\n\n    // Anchors connected to all pads\n    for (int a = 0; a < A; ++a) {\n        for (int p = A; p < A + U; ++p) {\n            base[idx(a, p)] = '1';\n        }\n    }\n\n    // Anchor-to-cluster edges: for cluster i and anchor a, connect to all vertices if alpha[i][a]==1\n    for (int i = 0; i < Lbits; ++i) {\n        int s = cluster_start(i), e = cluster_end(i);\n        for (int a = 0; a < A; ++a) {\n            if (alpha[i][a]) {\n                for (int v = s; v <= e; ++v) {\n                    base[idx(a, v)] = '1';\n                }\n            }\n        }\n    }\n\n    // Precompute positions of internal edges for each cluster\n    vector<vector<int>> clusterEdgePos(Lbits);\n    for (int i = 0; i < Lbits; ++i) {\n        int s = cluster_start(i), e = cluster_end(i);\n        for (int u = s; u <= e; ++u) {\n            for (int v = u + 1; v <= e; ++v) {\n                clusterEdgePos[i].push_back(idx(u, v));\n            }\n        }\n    }\n\n    // Output N and M graphs\n    cout << N << \"\\n\";\n    cout.flush();\n    // For each k, copy base and set cluster internal edges according to bits of k\n    for (int k = 0; k < M; ++k) {\n        string out = base;\n        for (int i = 0; i < Lbits; ++i) {\n            int bit = (k >> i) & 1;\n            if (bit) {\n                for (int pos : clusterEdgePos[i]) out[pos] = '1';\n            } else {\n                for (int pos : clusterEdgePos[i]) out[pos] = '0';\n            }\n        }\n        cout << out << \"\\n\";\n    }\n    cout.flush();\n\n    // Precompute some constants for decoding\n    double log_p1 = log(max(1e-12, 1.0 - eps));\n    double log_q1 = log(max(1e-12, eps));\n    double log_p0 = log(max(1e-12, eps));\n    double log_q0 = log(max(1e-12, 1.0 - eps));\n\n    // Decoding 100 queries\n    for (int q = 0; q < 100; ++q) {\n        string H; cin >> H;\n\n        // Build adjacency and degree for H\n        vector<int> deg(N, 0);\n        static bool adj[105][105];\n        for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) adj[i][j] = false;\n\n        int pos = 0;\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                bool b = (H[pos++] == '1');\n                if (b) {\n                    adj[i][j] = adj[j][i] = true;\n                    deg[i]++; deg[j]++;\n                }\n            }\n        }\n\n        // Identify anchors: top A by degree\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        nth_element(ord.begin(), ord.begin() + A, ord.end(), [&](int x, int y){\n            return deg[x] > deg[y];\n        });\n        vector<int> anchors(ord.begin(), ord.begin() + A);\n        // Sort anchors by degree ascending to align with t[a] ascending (0..Lbits)\n        sort(anchors.begin(), anchors.end(), [&](int x, int y){\n            if (deg[x] != deg[y]) return deg[x] < deg[y];\n            return x < y;\n        });\n\n        // Map vertex -> anchor index [0..A-1], or -1 if not an anchor\n        vector<int> isAnchorIndex(N, -1);\n        for (int a = 0; a < A; ++a) isAnchorIndex[anchors[a]] = a;\n\n        // Prepare per-vertex anchor adjacency bit vector and distances to each cluster alpha row\n        // We'll compute distances for all non-anchor vertices\n        vector<array<int, 16>> distToRow(N); // store distances up to Lbits (<=7)\n        vector<int> isNonAnchor;\n        isNonAnchor.reserve(N - A);\n        for (int v = 0; v < N; ++v) if (isAnchorIndex[v] < 0) isNonAnchor.push_back(v);\n\n        for (int v : isNonAnchor) {\n            // anchor-adjacency vector: for anchor index a in 0..A-1 corresponds to anchors[a] vertex\n            // compute distance to each row i\n            for (int i = 0; i < Lbits; ++i) {\n                int d = 0;\n                for (int a = 0; a < A; ++a) {\n                    bool e = adj[v][anchors[a]];\n                    int bit = alpha[i][a];\n                    if ((int)e != bit) d++;\n                }\n                distToRow[v][i] = d;\n            }\n        }\n\n        // Global greedy assignment: fill each cluster with g vertices minimizing Hamming distance\n        // Build candidate list (i, v, dist)\n        struct Cand { int dist; int i; int v; };\n        vector<Cand> cands;\n        cands.reserve(isNonAnchor.size() * Lbits);\n        for (int v : isNonAnchor) {\n            for (int i = 0; i < Lbits; ++i) {\n                cands.push_back({distToRow[v][i], i, v});\n            }\n        }\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){\n            if (a.dist != b.dist) return a.dist < b.dist;\n            if (a.i != b.i) return a.i < b.i;\n            return a.v < b.v;\n        });\n        vector<int> assignedCount(Lbits, 0);\n        vector<char> used(N, 0);\n        vector<vector<int>> clusterVerts(Lbits);\n        for (auto &c : cands) {\n            if (assignedCount[c.i] >= g) continue;\n            if (used[c.v]) continue;\n            // avoid picking anchors accidentally\n            if (isAnchorIndex[c.v] >= 0) continue;\n            clusterVerts[c.i].push_back(c.v);\n            used[c.v] = 1;\n            assignedCount[c.i]++;\n            bool allFull = true;\n            for (int i = 0; i < Lbits; ++i) if (assignedCount[i] < g) { allFull = false; break; }\n            if (allFull) break;\n        }\n        // If still lacking for some cluster, fill arbitrarily from remaining non-anchors\n        for (int i = 0; i < Lbits; ++i) {\n            if ((int)clusterVerts[i].size() < g) {\n                for (int v : isNonAnchor) {\n                    if (!used[v]) {\n                        clusterVerts[i].push_back(v);\n                        used[v] = 1;\n                        if ((int)clusterVerts[i].size() >= g) break;\n                    }\n                }\n            }\n        }\n        // Truncate overfull (shouldn't happen here)\n        for (int i = 0; i < Lbits; ++i) {\n            if ((int)clusterVerts[i].size() > g) {\n                clusterVerts[i].resize(g);\n            }\n        }\n\n        // Count edges inside each cluster\n        vector<int> x(Lbits, 0), pairCount(Lbits, 0);\n        for (int i = 0; i < Lbits; ++i) {\n            auto &vec = clusterVerts[i];\n            int gi = (int)vec.size();\n            pairCount[i] = gi * (gi - 1) / 2;\n            int cnt = 0;\n            for (int a = 0; a < gi; ++a) {\n                for (int b = a + 1; b < gi; ++b) {\n                    if (adj[vec[a]][vec[b]]) cnt++;\n                }\n            }\n            x[i] = cnt;\n        }\n\n        // ML decode over s in [0..M-1]\n        int bestS = 0;\n        double bestLL = -1e300;\n        for (int s = 0; s < M; ++s) {\n            double ll = 0.0;\n            for (int i = 0; i < Lbits; ++i) {\n                int bit = (s >> i) & 1;\n                int xi = x[i];\n                int ni = pairCount[i];\n                if (bit) {\n                    ll += xi * log_p1 + (ni - xi) * log_q1;\n                } else {\n                    ll += xi * log_p0 + (ni - xi) * log_q0;\n                }\n            }\n            if (ll > bestLL) {\n                bestLL = ll;\n                bestS = s;\n            }\n        }\n\n        cout << bestS << \"\\n\";\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstruct Edge {\n    int u, v;\n    ll w;\n};\nstruct AdjEdge {\n    int to;\n    int id;\n    ll w;\n};\n\n// Morton (Z-order) interleaving, good enough for spatial key\nstatic inline uint64_t part1by1(uint32_t x) {\n    uint64_t v = x & 0x0000ffffu;\n    v = (v | (v << 8)) & 0x00FF00FFu;\n    v = (v | (v << 4)) & 0x0F0F0F0Fu;\n    v = (v | (v << 2)) & 0x33333333u;\n    v = (v | (v << 1)) & 0x55555555u;\n    return v;\n}\nstatic inline uint64_t morton2D_32(uint32_t x, uint32_t y) {\n    return (part1by1(y) << 1) | part1by1(x);\n}\n\nint N, M, D, K;\nvector<Edge> edges;\nvector<vector<AdjEdge>> adj;\nvector<int> X, Y;\n\nconst ll INFLL = (ll)4e18;\n\nll dijkstra_exclude_target(int s, int t, int banned_edge_id, const vector<vector<AdjEdge>>& adj) {\n    // Early exit dijkstra from s to t ignoring one edge\n    const int n = adj.size();\n    static vector<ll> dist;\n    static vector<int> vis;\n    dist.assign(n, INFLL);\n    vis.assign(n, 0);\n    struct Node { ll d; int v; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n    dist[s] = 0;\n    pq.push({0, s});\n    while (!pq.empty()) {\n        auto [dcur, u] = pq.top(); pq.pop();\n        if (vis[u]) continue;\n        vis[u] = 1;\n        if (u == t) return dcur;\n        for (const auto& ae : adj[u]) {\n            if (ae.id == banned_edge_id) continue;\n            int v = ae.to;\n            ll nd = dcur + ae.w;\n            if (dist[v] > nd) {\n                dist[v] = nd;\n                pq.push({nd, v});\n            }\n        }\n    }\n    return dist[t];\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> D >> K;\n    edges.resize(M);\n    for (int i = 0; i < M; i++) {\n        int u, v; ll w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[i] = {u, v, w};\n    }\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n\n    adj.assign(N, {});\n    for (int i = 0; i < M; i++) {\n        auto &e = edges[i];\n        adj[e.u].push_back({e.v, i, e.w});\n        adj[e.v].push_back({e.u, i, e.w});\n    }\n\n    auto time_start = chrono::steady_clock::now();\n\n    // Compute edge importance imp[e] = max(0, dist_no_e(u,v) - w)\n    vector<ll> importance(M, 0);\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        ll w = edges[i].w;\n        ll alt = dijkstra_exclude_target(u, v, i, adj);\n        if (alt >= INFLL/2) {\n            // In 2-edge-connected graphs, this should not happen, but guard anyway\n            importance[i] = (ll)1e9; // very large, but won't break since we clamp\n        } else {\n            ll imp = alt - w;\n            if (imp < 0) imp = 0;\n            importance[i] = imp;\n        }\n    }\n\n    // Spatial key: Morton (Z) order of edge midpoints\n    vector<uint64_t> zkey(M);\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        // midpoints\n        int mx = (X[u] + X[v]) >> 1;\n        int my = (Y[u] + Y[v]) >> 1;\n        // coords in [0..1000], safe for 10 bits\n        uint32_t x = (uint32_t)mx;\n        uint32_t y = (uint32_t)my;\n        zkey[i] = morton2D_32(x, y);\n    }\n\n    // Order edges: primary by -importance (descending), secondary by spatial key (ascending), tertiary by id\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    stable_sort(order.begin(), order.end(), [&](int a, int b) {\n        if (importance[a] != importance[b]) return importance[a] > importance[b];\n        if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n        return a < b;\n    });\n\n    // Target per day\n    vector<int> target(D, M / D);\n    for (int i = 0; i < M % D; i++) target[i]++;\n\n    // State for assignment\n    vector<vector<int>> cnt(N, vector<int>(D, 0));          // cnt[v][d] = #edges at v on day d\n    vector<vector<double>> sumImp(N, vector<double>(D, 0)); // sum of importance at v/day\n    vector<double> daySumImp(D, 0.0);\n    vector<int> remaining = target;\n\n    vector<int> assign(M, -1);\n    vector<vector<int>> dayEdges(D);\n    dayEdges.reserve(D);\n    for (int d = 0; d < D; d++) dayEdges[d].reserve(target[d]);\n\n    // Greedy assignment\n    for (int idx = 0; idx < M; idx++) {\n        int e = order[idx];\n        int u = edges[e].u, v = edges[e].v;\n        ll imp = importance[e];\n\n        int prefer = (int)(zkey[e] % (uint64_t)D);\n\n        // Select day with lexicographic minimization:\n        // (cnt[u][d] + cnt[v][d], sumImp[u][d] + sumImp[v][d], daySumImp[d], distance to prefer, -remaining[d])\n        int best_d = -1;\n        int best_conf = INT_MAX;\n        double best_localSum = 1e300;\n        double best_daySum = 1e300;\n        int best_dist = INT_MAX;\n        int best_remaining = -1;\n\n        for (int d = 0; d < D; d++) {\n            if (remaining[d] <= 0) continue;\n            int conf = cnt[u][d] + cnt[v][d];\n            double localSum = sumImp[u][d] + sumImp[v][d];\n            double globSum = daySumImp[d];\n            // ring distance preference around prefer\n            int dist1 = (d >= prefer) ? (d - prefer) : (prefer - d);\n            // We can pick minimal absolute distance in ring; simpler use dist1\n            int rem = remaining[d];\n\n            if (conf < best_conf) {\n                best_conf = conf;\n                best_localSum = localSum;\n                best_daySum = globSum;\n                best_d = d;\n                best_dist = dist1;\n                best_remaining = rem;\n            } else if (conf == best_conf) {\n                if (localSum < best_localSum - 1e-12) {\n                    best_localSum = localSum;\n                    best_daySum = globSum;\n                    best_d = d;\n                    best_dist = dist1;\n                    best_remaining = rem;\n                } else if (fabs(localSum - best_localSum) <= 1e-12) {\n                    if (globSum < best_daySum - 1e-12) {\n                        best_daySum = globSum;\n                        best_d = d;\n                        best_dist = dist1;\n                        best_remaining = rem;\n                    } else if (fabs(globSum - best_daySum) <= 1e-12) {\n                        // Prefer closer to prefer and more remaining\n                        if (best_dist != dist1 ? (dist1 < best_dist) : (rem > best_remaining)) {\n                            best_d = d;\n                            best_dist = dist1;\n                            best_remaining = rem;\n                        }\n                    }\n                }\n            }\n        }\n\n        if (best_d == -1) {\n            // Fallback: if no remaining (shouldn't happen because sum target = M)\n            // Place on any day not exceeding K (hard limit), choosing minimal conflict.\n            int fallback_d = -1;\n            int best_con2 = INT_MAX;\n            for (int d = 0; d < D; d++) {\n                if ((int)dayEdges[d].size() >= K) continue;\n                int conf = cnt[u][d] + cnt[v][d];\n                if (conf < best_con2) {\n                    best_con2 = conf;\n                    fallback_d = d;\n                }\n            }\n            if (fallback_d == -1) {\n                // As last resort, ignore K and place anywhere minimal conf\n                for (int d = 0; d < D; d++) {\n                    int conf = cnt[u][d] + cnt[v][d];\n                    if (conf < best_con2) {\n                        best_con2 = conf;\n                        fallback_d = d;\n                    }\n                }\n            }\n            best_d = fallback_d;\n        }\n\n        assign[e] = best_d;\n        remaining[best_d]--;\n        cnt[u][best_d]++; cnt[v][best_d]++;\n        sumImp[u][best_d] += (double)imp;\n        sumImp[v][best_d] += (double)imp;\n        daySumImp[best_d] += (double)imp;\n        // track dayEdges and positions for later swaps\n        dayEdges[best_d].push_back(e);\n    }\n\n    // Prepare structures for local improvement\n    vector<vector<double>> S = sumImp; // rename for objective clarity\n    // Objective: sum_{v,d} S[v][d]^2\n    auto computeObj = [&]() -> long double {\n        long double obj = 0;\n        for (int v = 0; v < N; v++) {\n            for (int d = 0; d < D; d++) {\n                long double s = S[v][d];\n                obj += s * s;\n            }\n        }\n        return obj;\n    };\n    long double obj = computeObj();\n\n    // For fast removal from dayEdges, keep position map\n    vector<int> posInDay(M, -1);\n    for (int d = 0; d < D; d++) {\n        for (int i = 0; i < (int)dayEdges[d].size(); i++) {\n            posInDay[dayEdges[d][i]] = i;\n        }\n    }\n\n    // Local search under time budget\n    auto now = chrono::steady_clock::now();\n    double elapsed = chrono::duration<double>(now - time_start).count();\n    double T_budget = 5.80; // be safe under 6.0 s\n    double time_left = max(0.0, T_budget - elapsed);\n\n    mt19937 rng(1234567);\n    uniform_int_distribution<int> dayDist(0, D-1);\n\n    auto trySwap = [&](int e1, int d1, int e2, int d2) -> long double {\n        if (e1 == e2 || d1 == d2) return 0.0L;\n        int u1 = edges[e1].u, v1 = edges[e1].v;\n        int u2 = edges[e2].u, v2 = edges[e2].v;\n        double imp1 = (double)importance[e1];\n        double imp2 = (double)importance[e2];\n\n        // accumulate delta on keys (vertex, day) pairs\n        // Use small local vector to merge duplicates\n        struct Key { int v, d; };\n        vector<Key> keys;\n        vector<double> deltaS;\n\n        auto add_delta = [&](int v, int d, double ds) {\n            // merge into existing if present\n            for (size_t i = 0; i < keys.size(); i++) {\n                if (keys[i].v == v && keys[i].d == d) {\n                    deltaS[i] += ds;\n                    return;\n                }\n            }\n            keys.push_back({v, d});\n            deltaS.push_back(ds);\n        };\n\n        // e1 moves from d1 -> d2\n        add_delta(u1, d1, -imp1);\n        add_delta(v1, d1, -imp1);\n        add_delta(u1, d2, +imp1);\n        add_delta(v1, d2, +imp1);\n        // e2 moves from d2 -> d1\n        add_delta(u2, d2, -imp2);\n        add_delta(v2, d2, -imp2);\n        add_delta(u2, d1, +imp2);\n        add_delta(v2, d1, +imp2);\n\n        long double delta = 0.0L;\n        for (size_t i = 0; i < keys.size(); i++) {\n            int vv = keys[i].v, dd = keys[i].d;\n            long double oldS = (long double)S[vv][dd];\n            long double newS = oldS + (long double)deltaS[i];\n            delta += newS*newS - oldS*oldS;\n        }\n        return delta;\n    };\n\n    auto applySwap = [&](int e1, int d1, int e2, int d2) {\n        // Update S and cnt\n        int u1 = edges[e1].u, v1 = edges[e1].v;\n        int u2 = edges[e2].u, v2 = edges[e2].v;\n        double imp1 = (double)importance[e1];\n        double imp2 = (double)importance[e2];\n\n        // S updates\n        S[u1][d1] -= imp1; S[v1][d1] -= imp1;\n        S[u1][d2] += imp1; S[v1][d2] += imp1;\n        S[u2][d2] -= imp2; S[v2][d2] -= imp2;\n        S[u2][d1] += imp2; S[v2][d1] += imp2;\n\n        // cnt updates (#edges at v/day)\n        // For e1: d1 -> d2\n        cnt[u1][d1]--; cnt[v1][d1]--;\n        cnt[u1][d2]++; cnt[v1][d2]++;\n        // For e2: d2 -> d1\n        cnt[u2][d2]--; cnt[v2][d2]--;\n        cnt[u2][d1]++; cnt[v2][d1]++;\n\n        // daySumImp updates (not used in objective now, but keep consistent)\n        daySumImp[d1] += imp2 - imp1;\n        daySumImp[d2] += imp1 - imp2;\n\n        // Update dayEdges and positions\n        // remove e1 from d1\n        {\n            int p = posInDay[e1];\n            int last = dayEdges[d1].back();\n            dayEdges[d1][p] = last;\n            posInDay[last] = p;\n            dayEdges[d1].pop_back();\n        }\n        // remove e2 from d2\n        {\n            int p = posInDay[e2];\n            int last = dayEdges[d2].back();\n            dayEdges[d2][p] = last;\n            posInDay[last] = p;\n            dayEdges[d2].pop_back();\n        }\n        // add e1 to d2\n        posInDay[e1] = (int)dayEdges[d2].size();\n        dayEdges[d2].push_back(e1);\n        // add e2 to d1\n        posInDay[e2] = (int)dayEdges[d1].size();\n        dayEdges[d1].push_back(e2);\n\n        // update assignment\n        assign[e1] = d2;\n        assign[e2] = d1;\n    };\n\n    // Try random swaps; restrict attempts by time\n    // Make the number of attempts adaptive to time left and instance size\n    int baseAttempts = 200000; // upper bound\n    now = chrono::steady_clock::now();\n    elapsed = chrono::duration<double>(now - time_start).count();\n    time_left = max(0.0, T_budget - elapsed);\n\n    // Try to squeeze swaps within remaining time; keep it simple: stop on time overflow\n    for (int iter = 0; iter < baseAttempts; iter++) {\n        // time check\n        if ((iter & 1023) == 0) {\n            now = chrono::steady_clock::now();\n            elapsed = chrono::duration<double>(now - time_start).count();\n            if (elapsed > T_budget) break;\n        }\n        // pick two different days with content\n        int d1 = dayDist(rng), d2 = dayDist(rng);\n        if (d1 == d2) continue;\n        if (dayEdges[d1].empty() || dayEdges[d2].empty()) continue;\n        // pick random edges from those days\n        int e1 = dayEdges[d1][ (int)(rng() % dayEdges[d1].size()) ];\n        int e2 = dayEdges[d2][ (int)(rng() % dayEdges[d2].size()) ];\n        if (e1 == e2) continue;\n\n        long double delta = trySwap(e1, d1, e2, d2);\n        if (delta < -1e-9L) {\n            applySwap(e1, d1, e2, d2);\n            obj += delta;\n        }\n    }\n\n    // Output (1-indexed days)\n    // If any day is still over K (shouldn't happen with targets), it's okay; K is a cap; we ensured target <= K.\n    for (int i = 0; i < M; i++) {\n        if (i) cout << ' ';\n        cout << (assign[i] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct PairPos {\n    int a, b;\n};\n\nstruct Arrangement {\n    int D;\n    vector<int> occ;              // linear indices of occupied cells\n    vector<PairPos> dominos;      // candidate dominos (two positions) for sharing\n};\n\nstatic inline int idx3(int D, int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\n// Build minimal arrangement per z-layer and maximize adjacent dominos on the dominant axis.\nArrangement build_arrangement(const vector<string>& fz, const vector<string>& rz, int D) {\n    Arrangement arr;\n    arr.D = D;\n\n    for (int z = 0; z < D; ++z) {\n        // A: x where f(z,x)=1; B: y where r(z,y)=1\n        vector<int> A, B;\n        A.reserve(D);\n        B.reserve(D);\n        for (int x = 0; x < D; ++x) if (fz[z][x] == '1') A.push_back(x);\n        for (int y = 0; y < D; ++y) if (rz[z][y] == '1') B.push_back(y);\n        int Nx = (int)A.size();\n        int Ny = (int)B.size();\n        if (Nx == 0 || Ny == 0) {\n            // Problem guarantees this won't happen; still, be safe by putting one cell somewhere if it does.\n            int x = Nx ? A[0] : 0;\n            int y = Ny ? B[0] : 0;\n            arr.occ.push_back(idx3(D, x, y, z));\n            continue;\n        }\n\n        if (Nx >= Ny) {\n            // x-dominant: each x must appear exactly once.\n            // Build x-runs from fz[z], make disjoint adjacent pairs along x.\n            vector<pair<int,int>> pairsX;\n            vector<int> singlesX; // initially odd tail of runs; we will add more by splitting pairs if necessary\n            for (int x = 0; x < D; ) {\n                if (fz[z][x] != '1') { ++x; continue; }\n                int l = x;\n                while (x + 1 < D && fz[z][x + 1] == '1') ++x;\n                int r = x;\n                // Make disjoint adjacent pairs (l,l+1), (l+2,l+3), ...\n                for (int t = l; t + 1 <= r; t += 2) {\n                    pairsX.emplace_back(t, t + 1);\n                }\n                if (((r - l + 1) & 1) == 1) {\n                    singlesX.push_back(r); // leftover single\n                }\n                ++x;\n            }\n            int pmax = (int)pairsX.size();\n            int keep = min(pmax, Nx - Ny); // upper bound explained in analysis\n            vector<pair<int,int>> keptPairs;\n            keptPairs.reserve(keep);\n            for (int i = 0; i < keep; ++i) keptPairs.push_back(pairsX[i]);\n            // Split remaining pairs into singles\n            for (int i = keep; i < pmax; ++i) {\n                singlesX.push_back(pairsX[i].first);\n                singlesX.push_back(pairsX[i].second);\n            }\n            // Prepare assignment per y\n            int Q = Ny;\n            vector<vector<int>> y_to_x(Q);\n            int yPairCover = min(keep, Q);\n            // Assign one kept pair to each of first yPairCover y-rows\n            for (int i = 0; i < yPairCover; ++i) {\n                int y = B[i];\n                auto pr = keptPairs[i];\n                y_to_x[i].push_back(pr.first);\n                y_to_x[i].push_back(pr.second);\n                // record domino positions\n                arr.dominos.push_back({ idx3(D, pr.first, y, z), idx3(D, pr.second, y, z) });\n            }\n            // Ensure coverage: remaining y's get one single each\n            int singles_need = Q - yPairCover;\n            // Guarantee enough singles: Nx - 2*keep >= Ny - keep when keep <= Nx - Ny\n            // Assign singles to the rest y rows\n            for (int i = yPairCover; i < Q; ++i) {\n                if (singlesX.empty()) {\n                    // As a fallback (shouldn't happen), break one of the early pairs\n                    if (!keptPairs.empty()) {\n                        auto pr = keptPairs.back();\n                        keptPairs.pop_back();\n                        // remove corresponding domino we recorded (need to also pop from dominos and y_to_x)\n                        // But this is very unlikely; handle with minimal disturbance.\n                        // We will not pop earlier, instead just push singles now and skip pair; safe fallback:\n                        singlesX.push_back(pr.first);\n                        singlesX.push_back(pr.second);\n                    }\n                }\n                int x = singlesX.back(); singlesX.pop_back();\n                y_to_x[i].push_back(x);\n            }\n            // Distribute leftover kept pairs\n            int ptr = 0;\n            for (int i = yPairCover; i < keep; ++i) {\n                auto pr = keptPairs[i];\n                int y_idx = ptr % Q;\n                int y = B[y_idx];\n                y_to_x[y_idx].push_back(pr.first);\n                y_to_x[y_idx].push_back(pr.second);\n                ptr++;\n                // record domino\n                arr.dominos.push_back({ idx3(D, pr.first, y, z), idx3(D, pr.second, y, z) });\n            }\n            // Distribute leftover singles\n            ptr = 0;\n            while (!singlesX.empty()) {\n                int x = singlesX.back(); singlesX.pop_back();\n                int y_idx = ptr % Q;\n                y_to_x[y_idx].push_back(x);\n                ptr++;\n            }\n            // Emit occupied cells\n            for (int yi = 0; yi < Q; ++yi) {\n                int y = B[yi];\n                for (int x : y_to_x[yi]) {\n                    arr.occ.push_back(idx3(D, x, y, z));\n                }\n            }\n        } else {\n            // y-dominant: each y must appear exactly once.\n            // Build y-runs from rz[z], make disjoint adjacent pairs along y.\n            vector<pair<int,int>> pairsY;\n            vector<int> singlesY;\n            for (int y = 0; y < D; ) {\n                if (rz[z][y] != '1') { ++y; continue; }\n                int l = y;\n                while (y + 1 < D && rz[z][y + 1] == '1') ++y;\n                int r = y;\n                for (int t = l; t + 1 <= r; t += 2) {\n                    pairsY.emplace_back(t, t + 1);\n                }\n                if (((r - l + 1) & 1) == 1) {\n                    singlesY.push_back(r);\n                }\n                ++y;\n            }\n            int pmax = (int)pairsY.size();\n            int keep = min(pmax, Ny - Nx); // symmetric bound\n            vector<pair<int,int>> keptPairs;\n            keptPairs.reserve(keep);\n            for (int i = 0; i < keep; ++i) keptPairs.push_back(pairsY[i]);\n            for (int i = keep; i < pmax; ++i) {\n                singlesY.push_back(pairsY[i].first);\n                singlesY.push_back(pairsY[i].second);\n            }\n            // Prepare assignment per x\n            int P = Nx;\n            vector<vector<int>> x_to_y(P);\n            int xPairCover = min(keep, P);\n            // Assign one kept pair to first xPairCover x-columns\n            for (int i = 0; i < xPairCover; ++i) {\n                int x = A[i];\n                auto pr = keptPairs[i];\n                x_to_y[i].push_back(pr.first);\n                x_to_y[i].push_back(pr.second);\n                // record domino positions (along y)\n                arr.dominos.push_back({ idx3(D, x, pr.first, z), idx3(D, x, pr.second, z) });\n            }\n            // Ensure coverage: remaining x's get one single y each\n            for (int i = xPairCover; i < P; ++i) {\n                if (singlesY.empty()) {\n                    if (!keptPairs.empty()) {\n                        auto pr = keptPairs.back();\n                        keptPairs.pop_back();\n                        singlesY.push_back(pr.first);\n                        singlesY.push_back(pr.second);\n                    }\n                }\n                int y = singlesY.back(); singlesY.pop_back();\n                x_to_y[i].push_back(y);\n            }\n            // Distribute leftover kept pairs\n            int ptr = 0;\n            for (int i = xPairCover; i < keep; ++i) {\n                auto pr = keptPairs[i];\n                int x_idx = ptr % P;\n                int x = A[x_idx];\n                x_to_y[x_idx].push_back(pr.first);\n                x_to_y[x_idx].push_back(pr.second);\n                ptr++;\n                arr.dominos.push_back({ idx3(D, x, pr.first, z), idx3(D, x, pr.second, z) });\n            }\n            // Distribute leftover singles\n            ptr = 0;\n            while (!singlesY.empty()) {\n                int y = singlesY.back(); singlesY.pop_back();\n                int x_idx = ptr % P;\n                x_to_y[x_idx].push_back(y);\n                ptr++;\n            }\n            // Emit occupied cells\n            for (int xi = 0; xi < P; ++xi) {\n                int x = A[xi];\n                for (int y : x_to_y[xi]) {\n                    arr.occ.push_back(idx3(D, x, y, z));\n                }\n            }\n        }\n    }\n    return arr;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    if (!(cin >> D)) return 0;\n    vector<string> f[2], r[2];\n    for (int t = 0; t < 2; ++t) {\n        f[t].resize(D);\n        for (int i = 0; i < D; ++i) cin >> f[t][i];\n        r[t].resize(D);\n        for (int i = 0; i < D; ++i) cin >> r[t][i];\n    }\n\n    Arrangement A1 = build_arrangement(f[0], r[0], D);\n    Arrangement A2 = build_arrangement(f[1], r[1], D);\n\n    int N = D * D * D;\n    vector<int> b1(N, 0), b2(N, 0);\n\n    int M1 = (int)A1.dominos.size();\n    int M2 = (int)A2.dominos.size();\n    int K = min(M1, M2);\n\n    int nblocks = 0;\n\n    // Assign shared domino blocks with IDs 1..K\n    for (int i = 0; i < K; ++i) {\n        int id = ++nblocks;\n        auto p1 = A1.dominos[i];\n        auto p2 = A2.dominos[i];\n        b1[p1.a] = id; b1[p1.b] = id;\n        b2[p2.a] = id; b2[p2.b] = id;\n    }\n\n    // Mark used positions to avoid double assignment\n    // We can infer from b1/b2 arrays (non-zero means already assigned)\n    // Assign remaining occupied cells in A1 as unit blocks used only in object 1\n    for (int pos : A1.occ) {\n        if (b1[pos] == 0) {\n            int id = ++nblocks;\n            b1[pos] = id;\n        }\n    }\n    // Assign remaining occupied cells in A2 as unit blocks used only in object 2\n    for (int pos : A2.occ) {\n        if (b2[pos] == 0) {\n            int id = ++nblocks;\n            b2[pos] = id;\n        }\n    }\n\n    cout << nblocks << \"\\n\";\n    // Output b1 in x-major, then y, then z order\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            for (int z = 0; z < D; ++z) {\n                int p = idx3(D, x, y, z);\n                cout << b1[p] << ( (x==D-1 && y==D-1 && z==D-1) ? '\\n' : ' ' );\n            }\n        }\n    }\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            for (int z = 0; z < D; ++z) {\n                int p = idx3(D, x, y, z);\n                cout << b2[p] << ( (x==D-1 && y==D-1 && z==D-1) ? '\\n' : ' ' );\n            }\n        }\n    }\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge {\n    int u, v;\n    long long w;\n};\n\nstruct Solution {\n    vector<int> P;       // size N\n    vector<char> edgeOn; // size M\n    long long edgeSum = 0;\n    long long pSum = 0;\n    long long S = (1LL<<62);\n};\n\nstatic inline long long isq(long long x){ return x*x; }\n\nstatic inline int sqrt_ceil_ll(long long x) {\n    if (x <= 0) return 0;\n    long double dx = (long double)x;\n    long long r = (long long)floor(sqrt(dx) + 1e-12L);\n    while ((r+1) * (r+1) <= x) ++r;\n    while (r * r > x) --r;\n    if (r * r == x) return (int)r;\n    return (int)(r + 1);\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, M, K;\n    if(!(cin>>N>>M>>K)) return 0;\n    vector<long long> xs(N), ys(N);\n    for(int i=0;i<N;i++){ cin>>xs[i]>>ys[i]; }\n    vector<Edge> edges(M);\n    for(int j=0;j<M;j++){\n        int u,v; long long w;\n        cin>>u>>v>>w;\n        --u; --v;\n        edges[j] = {u,v,w};\n    }\n    vector<long long> ax(K), ay(K);\n    for(int k=0;k<K;k++){ cin>>ax[k]>>ay[k]; }\n\n    // adjacency\n    vector<vector<pair<int,int>>> adj(N);\n    for(int e=0;e<M;e++){\n        int u=edges[e].u, v=edges[e].v;\n        adj[u].push_back({v,e});\n        adj[v].push_back({u,e});\n    }\n\n    // Precompute squared distances station-resident and coverage lists/bitsets\n    const long long R2 = 5000LL*5000LL;\n    vector<vector<int>> covList(N);\n    vector<vector<uint64_t>> covBits(N);\n    int B = (K + 63) >> 6;\n    uint64_t lastMask = (K%64 == 0) ? ~0ULL : ((1ULL << (K%64)) - 1ULL);\n    vector<vector<int>> d2sr(N, vector<int>(K, 0));\n    for(int i=0;i<N;i++){\n        covBits[i].assign(B, 0ULL);\n        for(int k=0;k<K;k++){\n            long long dx = xs[i] - ax[k];\n            long long dy = ys[i] - ay[k];\n            long long d2 = dx*dx + dy*dy;\n            if (d2 > INT_MAX) d2 = INT_MAX; // safety\n            d2sr[i][k] = (int)d2;\n            if(d2 <= R2){\n                covList[i].push_back(k);\n                int blk = k >> 6;\n                int off = k & 63;\n                covBits[i][blk] |= (1ULL << off);\n            }\n        }\n    }\n\n    // All-pairs shortest paths (by weights) + parents to reconstruct paths\n    const long long INF = (1LL<<60);\n    vector<vector<long long>> distW(N, vector<long long>(N, INF));\n    vector<vector<int>> prevV(N, vector<int>(N, -1));\n    vector<vector<int>> prevE(N, vector<int>(N, -1));\n    auto dijkstra_from = [&](int s){\n        vector<long long>& d = distW[s];\n        vector<int>& pv = prevV[s];\n        vector<int>& pe = prevE[s];\n        fill(d.begin(), d.end(), INF);\n        fill(pv.begin(), pv.end(), -1);\n        fill(pe.begin(), pe.end(), -1);\n        d[s] = 0;\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        pq.push({0, s});\n        while(!pq.empty()){\n            auto [cd,u] = pq.top(); pq.pop();\n            if(cd != d[u]) continue;\n            for(auto [v,eid] : adj[u]){\n                long long nd = cd + edges[eid].w;\n                if(nd < d[v]){\n                    d[v] = nd;\n                    pv[v] = u;\n                    pe[v] = eid;\n                    pq.push({nd, v});\n                }\n            }\n        }\n    };\n    for(int i=0;i<N;i++) dijkstra_from(i);\n\n    // SPT from root 0\n    vector<int> parentSPT(N, -1);\n    vector<int> parentEdgeSPT(N, -1);\n    for(int v=0; v<N; v++){\n        parentSPT[v] = prevV[0][v];\n        parentEdgeSPT[v] = prevE[0][v];\n    }\n\n    auto build_Vset_from_edges = [&](const vector<char>& edgeOn)->vector<char>{\n        vector<char> inV(N, 0);\n        queue<int> q;\n        inV[0] = 1;\n        q.push(0);\n        while(!q.empty()){\n            int u = q.front(); q.pop();\n            for(auto [v,eid]: adj[u]){\n                if(edgeOn[eid] && !inV[v]){\n                    inV[v] = 1;\n                    q.push(v);\n                }\n            }\n        }\n        return inV;\n    };\n\n    auto assign_and_cost = [&](const vector<char>& edgeOn){\n        vector<char> inV = build_Vset_from_edges(edgeOn);\n        vector<int> assignTo(K, -1);\n        vector<int> bestD2(K, INT_MAX);\n        for(int k=0;k<K;k++){\n            int besti = -1;\n            int bestv = INT_MAX;\n            for(int i=0;i<N;i++){\n                if(!inV[i]) continue;\n                int d2 = d2sr[i][k];\n                if(d2 < bestv){\n                    bestv = d2; besti = i;\n                }\n            }\n            assignTo[k] = besti;\n            bestD2[k] = bestv;\n        }\n        vector<long long> maxD2(N, 0);\n        for(int k=0;k<K;k++){\n            int i = assignTo[k];\n            if(i<0) continue; // should not happen\n            if((long long)bestD2[k] > maxD2[i]) maxD2[i] = bestD2[k];\n        }\n        vector<int> P(N,0);\n        long long pSum = 0;\n        for(int i=0;i<N;i++){\n            if(!inV[i]) { P[i]=0; continue; }\n            int rad = sqrt_ceil_ll(maxD2[i]);\n            if (rad > 5000) rad = 5000; // safeguard, should not happen if covered\n            P[i] = rad;\n            pSum += 1LL*rad*rad;\n        }\n        long long edgeSum = 0;\n        for(int e=0;e<M;e++) if(edgeOn[e]) edgeSum += edges[e].w;\n        Solution sol;\n        sol.P = std::move(P);\n        sol.edgeOn = edgeOn;\n        sol.edgeSum = edgeSum;\n        sol.pSum = pSum;\n        sol.S = edgeSum + pSum;\n        return sol;\n    };\n\n    auto prune_unused_leaves = [&](vector<char>& edgeOn, const vector<int>& P){\n        vector<int> deg(N, 0);\n        vector<vector<int>> incEdges(N);\n        incEdges.assign(N, {});\n        for(int e=0;e<M;e++){\n            if(!edgeOn[e]) continue;\n            int u=edges[e].u, v=edges[e].v;\n            incEdges[u].push_back(e);\n            incEdges[v].push_back(e);\n        }\n        for(int i=0;i<N;i++){\n            int d=0;\n            for(int eid: incEdges[i]) if(edgeOn[eid]) d++;\n            deg[i]=d;\n        }\n        deque<int> dq;\n        for(int i=0;i<N;i++){\n            if(i==0) continue;\n            if(deg[i]==1 && P[i]==0) dq.push_back(i);\n        }\n        vector<char> removed(N,0);\n        while(!dq.empty()){\n            int v = dq.front(); dq.pop_front();\n            if(removed[v]) continue;\n            if(deg[v]!=1 || P[v]!=0) continue;\n            // find its unique edge\n            int euniq = -1, u = -1;\n            for(int eid : incEdges[v]){\n                if(edgeOn[eid]){\n                    euniq = eid;\n                    int a=edges[eid].u, b=edges[eid].v;\n                    u = (a==v? b : a);\n                    break;\n                }\n            }\n            if(euniq==-1) continue;\n            // remove edge\n            edgeOn[euniq] = 0;\n            deg[v]--; deg[u]--;\n            removed[v]=1;\n            if(u!=0 && deg[u]==1 && P[u]==0) dq.push_back(u);\n        }\n    };\n\n    // Build solution 1: Set cover + Metric MST\n    auto build_solution_setcover = [&](){\n        vector<char> selected(N, 0);\n        vector<char> uncovered(K, 1);\n        int remaining = K;\n        vector<long long> distRoot(N);\n        for(int i=0;i<N;i++) distRoot[i] = distW[0][i];\n\n        while(remaining > 0){\n            int besti = -1;\n            int bestc = -1;\n            long long tieRoot = (1LL<<60);\n            for(int i=0;i<N;i++){\n                if(selected[i]) continue;\n                int cnt = 0;\n                for(int k : covList[i]) if(uncovered[k]) cnt++;\n                if(cnt > bestc || (cnt==bestc && distRoot[i] < tieRoot)){\n                    bestc = cnt; tieRoot = distRoot[i]; besti = i;\n                }\n            }\n            if(besti==-1 || bestc<=0){\n                // Fallback: add any station that can cover someone not yet covered\n                for(int i=0;i<N && besti==-1;i++){\n                    if(selected[i]) continue;\n                    int cnt = 0;\n                    for(int k : covList[i]) if(uncovered[k]) { cnt=1; break; }\n                    if(cnt) besti = i;\n                }\n                if(besti==-1){\n                    // Should not happen; break\n                    break;\n                }\n            }\n            selected[besti] = 1;\n            for(int k : covList[besti]){\n                if(uncovered[k]){\n                    uncovered[k] = 0;\n                    remaining--;\n                }\n            }\n        }\n        // Remove redundant\n        vector<int> coverCnt(K, 0);\n        for(int i=0;i<N;i++){\n            if(!selected[i]) continue;\n            for(int k : covList[i]) coverCnt[k]++;\n        }\n        bool changed = true;\n        while(changed){\n            changed = false;\n            for(int i=0;i<N;i++){\n                if(!selected[i]) continue;\n                bool canRemove = true;\n                for(int k : covList[i]){\n                    if(coverCnt[k] <= 1){ canRemove=false; break; }\n                }\n                if(canRemove){\n                    selected[i] = 0;\n                    for(int k : covList[i]) coverCnt[k]--;\n                    changed = true;\n                }\n            }\n        }\n\n        // Terminals T = selected + root 0\n        vector<int> T;\n        T.push_back(0);\n        for(int i=0;i<N;i++) if(selected[i] && i!=0) T.push_back(i);\n        int TS = (int)T.size();\n\n        // Prim's MST on metric distW[T][T]\n        vector<char> used(TS, 0);\n        vector<long long> low(TS, INF);\n        vector<int> par(TS, -1);\n        used[0] = 1;\n        for(int i=1;i<TS;i++){\n            low[i] = distW[T[0]][T[i]];\n            par[i] = 0;\n        }\n        vector<pair<int,int>> mstPairs; mstPairs.reserve(TS-1);\n        for(int it=0; it<TS-1; it++){\n            int v=-1; long long best=INF;\n            for(int j=0;j<TS;j++){\n                if(!used[j] && low[j] < best){\n                    best = low[j]; v=j;\n                }\n            }\n            if(v==-1) break;\n            used[v] = 1;\n            mstPairs.emplace_back(T[par[v]], T[v]);\n            for(int j=0;j<TS;j++){\n                if(!used[j]){\n                    long long nd = distW[T[v]][T[j]];\n                    if(nd < low[j]){\n                        low[j] = nd; par[j] = v;\n                    }\n                }\n            }\n        }\n\n        // Build union of shortest paths for MST edges\n        vector<char> edgeOn(M, 0);\n        for(auto [u,v] : mstPairs){\n            int cur = v;\n            while(cur != u){\n                int eid = prevE[u][cur];\n                if(eid<0) break; // safety\n                edgeOn[eid] = 1;\n                int pu = prevV[u][cur];\n                if(pu<0) break;\n                cur = pu;\n            }\n        }\n\n        // Reduce cycles: MST inside union edges\n        // Collect union edges list\n        vector<int> unionEdges;\n        unionEdges.reserve(M);\n        for(int e=0;e<M;e++) if(edgeOn[e]) unionEdges.push_back(e);\n        // Kruskal on union edges\n        struct DSU {\n            int n;\n            vector<int> p, r;\n            DSU(int n):n(n),p(n),r(n,0){ iota(p.begin(), p.end(), 0); }\n            int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n            bool unite(int a,int b){\n                a=find(a); b=find(b);\n                if(a==b) return false;\n                if(r[a]<r[b]) swap(a,b);\n                p[b]=a;\n                if(r[a]==r[b]) r[a]++;\n                return true;\n            }\n        };\n        vector<int> ord = unionEdges;\n        sort(ord.begin(), ord.end(), [&](int e1, int e2){\n            return edges[e1].w < edges[e2].w;\n        });\n        DSU dsu(N);\n        vector<char> edgeOn2(M, 0);\n        for(int e: ord){\n            int u = edges[e].u, v = edges[e].v;\n            if(dsu.unite(u,v)){\n                edgeOn2[e] = 1;\n            }\n        }\n        // Prune leaves not in terminals T\n        vector<char> isTerm(N, 0);\n        for(int v: T) isTerm[v] = 1;\n        // prune non-terminal leaves\n        {\n            vector<int> deg(N,0);\n            vector<vector<int>> incEdges(N);\n            incEdges.assign(N, {});\n            for(int e=0;e<M;e++){\n                if(!edgeOn2[e]) continue;\n                int u=edges[e].u, v=edges[e].v;\n                incEdges[u].push_back(e);\n                incEdges[v].push_back(e);\n            }\n            for(int i=0;i<N;i++){\n                int d=0; for(int eid: incEdges[i]) if(edgeOn2[eid]) d++;\n                deg[i]=d;\n            }\n            deque<int> dq;\n            for(int i=0;i<N;i++){\n                if(deg[i]==1 && !isTerm[i]) dq.push_back(i);\n            }\n            vector<char> removed(N,0);\n            while(!dq.empty()){\n                int v = dq.front(); dq.pop_front();\n                if(removed[v]) continue;\n                if(deg[v]!=1 || isTerm[v]) continue;\n                int euniq=-1, u=-1;\n                for(int eid: incEdges[v]){\n                    if(edgeOn2[eid]){\n                        euniq = eid;\n                        int a=edges[eid].u, b=edges[eid].v;\n                        u = (a==v? b : a);\n                        break;\n                    }\n                }\n                if(euniq==-1) continue;\n                edgeOn2[euniq]=0;\n                deg[v]--; deg[u]--;\n                removed[v] = 1;\n                if(deg[u]==1 && !isTerm[u]) dq.push_back(u);\n            }\n        }\n\n        // Assign and compute cost\n        Solution sol = assign_and_cost(edgeOn2);\n\n        // prune unused leaves (Pi==0) to reduce edges further\n        vector<char> edgeOn3 = sol.edgeOn;\n        prune_unused_leaves(edgeOn3, sol.P);\n        Solution sol2 = assign_and_cost(edgeOn3);\n        return sol2;\n    };\n\n    // Build solution 2: SPT greedy coverage\n    auto build_solution_spt = [&](){\n        vector<char> inV(N, 0);\n        vector<char> edgeOn(M, 0);\n        inV[0] = 1;\n\n        vector<uint64_t> covered(B, 0ULL);\n        // cover root's coverage\n        for(int b=0;b<B;b++) covered[b] |= covBits[0][b];\n\n        auto allCovered = [&](){\n            for(int b=0;b<B;b++){\n                uint64_t mask = (b==B-1 ? lastMask : ~0ULL);\n                if( (covered[b] & mask) != mask ) return false;\n            }\n            return true;\n        };\n\n        vector<uint64_t> tmp(B);\n\n        while(!allCovered()){\n            int bestV = -1;\n            long long bestGain = -1;\n            long long bestIncW = (1LL<<60);\n\n            for(int v=0; v<N; v++){\n                if(inV[v]) continue;\n                // accumulate new nodes along SPT path\n                // clear tmp\n                for(int b=0;b<B;b++) tmp[b] = 0ULL;\n                long long incW = 0;\n                int cur = v;\n                bool anyNew = false;\n                while(cur != -1 && !inV[cur]){\n                    // OR coverage\n                    for(int b=0;b<B;b++) tmp[b] |= covBits[cur][b];\n                    // add edge weight to parent\n                    int pe = parentEdgeSPT[cur];\n                    if(pe >= 0) incW += edges[pe].w;\n                    cur = parentSPT[cur];\n                    anyNew = true;\n                }\n                if(!anyNew){\n                    continue;\n                }\n                // compute new gain: popcount((tmp) & ~covered)\n                long long gain = 0;\n                for(int b=0;b<B;b++){\n                    uint64_t mask = (b==B-1 ? lastMask : ~0ULL);\n                    uint64_t nc = (~covered[b]) & mask;\n                    uint64_t add = tmp[b] & nc;\n                    gain += __builtin_popcountll(add);\n                }\n                if(gain > bestGain || (gain==bestGain && incW < bestIncW)){\n                    bestGain = gain;\n                    bestIncW = incW;\n                    bestV = v;\n                }\n            }\n\n            if(bestV == -1){\n                // fallback: add any remaining node to progress\n                for(int v=0; v<N; v++){\n                    if(!inV[v]) { bestV=v; break; }\n                }\n                if(bestV==-1) break; // shouldn't happen\n            }\n\n            // add bestV path to inV/edgeOn, and update covered\n            // recompute tmp for bestV\n            for(int b=0;b<B;b++) tmp[b] = 0ULL;\n            int cur = bestV;\n            while(cur != -1 && !inV[cur]){\n                for(int b=0;b<B;b++) tmp[b] |= covBits[cur][b];\n                int pe = parentEdgeSPT[cur];\n                if(pe >= 0) edgeOn[pe] = 1;\n                inV[cur] = 1;\n                cur = parentSPT[cur];\n            }\n            // update covered\n            for(int b=0;b<B;b++) covered[b] |= tmp[b];\n        }\n\n        // Assign and compute cost\n        Solution sol = assign_and_cost(edgeOn);\n        // prune unused leaves\n        vector<char> edgeOn2 = sol.edgeOn;\n        prune_unused_leaves(edgeOn2, sol.P);\n        Solution sol2 = assign_and_cost(edgeOn2);\n        return sol2;\n    };\n\n    Solution sol1 = build_solution_setcover();\n    Solution sol2 = build_solution_spt();\n    Solution best = (sol1.S <= sol2.S ? sol1 : sol2);\n\n    // Output final solution: P and B\n    for(int i=0;i<N;i++){\n        if(i) cout << ' ';\n        cout << best.P[i];\n    }\n    cout << '\\n';\n    for(int j=0;j<M;j++){\n        if(j) cout << ' ';\n        cout << (best.edgeOn[j] ? 1 : 0);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Move {\n    int x1, y1, x2, y2;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 30;\n    vector<vector<int>> A(N);\n    for (int x = 0; x < N; ++x) {\n        A[x].resize(x + 1);\n        for (int y = 0; y <= x; ++y) cin >> A[x][y];\n    }\n\n    const int LIMIT = 10000;\n    vector<Move> ops;\n    ops.reserve(LIMIT);\n\n    // inQueue flags with triangular shape\n    vector<vector<char>> inQ(N);\n    for (int x = 0; x < N; ++x) inQ[x].assign(x + 1, 0);\n\n    auto isViolation = [&](int x, int y) -> bool {\n        if (x >= N - 1) return false;\n        int v = A[x][y];\n        int c1 = A[x + 1][y];\n        int c2 = A[x + 1][y + 1];\n        return v > min(c1, c2);\n    };\n\n    deque<pair<int,int>> q;\n\n    auto pushQ = [&](int x, int y) {\n        if (x < 0 || x >= N) return;\n        if (y < 0 || y > x) return;\n        if (inQ[x][y]) return;\n        inQ[x][y] = 1;\n        q.emplace_back(x, y);\n    };\n\n    // Initialize queue with current violations\n    for (int x = 0; x <= N - 2; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            if (isViolation(x, y)) pushQ(x, y);\n        }\n    }\n\n    auto recordSwap = [&](int x1, int y1, int x2, int y2) {\n        ops.push_back({x1, y1, x2, y2});\n    };\n\n    // Push parents of (x,y)\n    auto pushParents = [&](int x, int y) {\n        if (x <= 0) return;\n        // Parent (x-1, y-1) if y-1 >= 0\n        if (y - 1 >= 0) pushQ(x - 1, y - 1);\n        // Parent (x-1, y) if y <= x-1\n        if (y <= x - 1) pushQ(x - 1, y);\n    };\n\n    bool limit_hit = false;\n\n    // Main processing loop\n    while (!q.empty() && (int)ops.size() < LIMIT) {\n        auto [sx, sy] = q.front();\n        q.pop_front();\n        inQ[sx][sy] = 0;\n\n        // Sift down from (sx, sy)\n        int x = sx, y = sy;\n        while (x < N - 1) {\n            int cx1 = x + 1, cy1 = y;\n            int cx2 = x + 1, cy2 = y + 1;\n            int v = A[x][y];\n            int v1 = A[cx1][cy1];\n            int v2 = A[cx2][cy2];\n\n            int target_cx = -1, target_cy = -1;\n            int min_child = (v1 < v2) ? v1 : v2;\n            if (v <= min_child) break; // no violation at (x,y)\n\n            if (v1 < v2) {\n                target_cx = cx1; target_cy = cy1;\n            } else {\n                target_cx = cx2; target_cy = cy2;\n            }\n\n            if ((int)ops.size() >= LIMIT) { limit_hit = true; break; }\n\n            // Swap parent (x,y) with chosen child (target_cx, target_cy)\n            swap(A[x][y], A[target_cx][target_cy]);\n            recordSwap(x, y, target_cx, target_cy);\n\n            // (x,y) decreased; push its parents to propagate upwards if needed\n            pushParents(x, y);\n\n            // Continue sifting the larger value now at child\n            x = target_cx; y = target_cy;\n        }\n        if (limit_hit) break;\n\n        // Optionally, if (sx,sy) still violates (could after further changes), requeue\n        if (isViolation(sx, sy)) pushQ(sx, sy);\n    }\n\n    // Output\n    int K = min<int>(ops.size(), LIMIT);\n    cout << K << '\\n';\n    for (int i = 0; i < K; ++i) {\n        cout << ops[i].x1 << ' ' << ops[i].y1 << ' ' << ops[i].x2 << ' ' << ops[i].y2 << '\\n';\n    }\n\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int i, j;\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    const int H = D, W = D;\n    vector<vector<int>> obs(H, vector<int>(W, 0));\n    for (int k = 0; k < N; ++k) {\n        int r, c;\n        cin >> r >> c;\n        obs[r][c] = 1;\n    }\n    int ei = 0, ej = (D - 1) / 2; // entrance\n    // Ensure obstacles are not at entrance or its 3 neighbors by problem guarantee.\n\n    // Precompute BFS distances from entrance ignoring containers (only obstacles)\n    const int INF = 1e9;\n    vector<vector<int>> dist(H, vector<int>(W, INF));\n    deque<Pos> dq;\n    dist[ei][ej] = 0;\n    dq.push_back({ei, ej});\n    auto inside = [&](int i, int j){ return 0 <= i && i < H && 0 <= j && j < W; };\n    int di[4] = {-1, 0, 1, 0};\n    int dj[4] = {0, 1, 0, -1};\n    while (!dq.empty()) {\n        auto p = dq.front(); dq.pop_front();\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = p.i + di[dir], nj = p.j + dj[dir];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (dist[ni][nj] > dist[p.i][p.j] + 1) {\n                dist[ni][nj] = dist[p.i][p.j] + 1;\n                dq.push_back({ni, nj});\n            }\n        }\n    }\n    // Build 'order' of positions sorted by distance ascending (excluding entrance, excluding obstacles)\n    vector<Pos> order;\n    order.reserve(H*W);\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            if (obs[i][j]) continue;\n            if (i == ei && j == ej) continue;\n            // dist is guaranteed finite by problem\n            order.push_back({i, j});\n        }\n    }\n    sort(order.begin(), order.end(), [&](const Pos &a, const Pos &b){\n        if (dist[a.i][a.j] != dist[b.i][b.j]) return dist[a.i][a.j] < dist[b.i][b.j];\n        if (a.i != b.i) return a.i < b.i;\n        return a.j < b.j;\n    });\n    int M = (int)order.size(); // D^2 - 1 - N\n\n    // rankIndex: map cell to index in order\n    vector<vector<int>> rankIndex(H, vector<int>(W, -1));\n    for (int idx = 0; idx < (int)order.size(); ++idx) {\n        rankIndex[order[idx].i][order[idx].j] = idx;\n    }\n\n    // Placement state\n    // empty[i][j] indicates currently empty (no container) and not obstacle; entrance is always empty.\n    vector<vector<char>> empty(H, vector<char>(W, 0));\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) empty[i][j] = (!obs[i][j]);\n    // entrance is empty too (already true).\n    // labelAt[i][j] stores label t placed at that cell, or -1 if empty or entrance\n    vector<vector<int>> labelAt(H, vector<int>(W, -1));\n\n    auto compute_articulation = [&]()->vector<vector<char>> {\n        // Build graph of current empties including entrance; obstacles and filled cells excluded.\n        // Map each empty cell to a vertex id\n        vector<vector<int>> id(H, vector<int>(W, -1));\n        vector<Pos> nodes;\n        nodes.reserve(H*W);\n        int vid = 0;\n        for (int i = 0; i < H; ++i) {\n            for (int j = 0; j < W; ++j) {\n                if (empty[i][j]) {\n                    id[i][j] = vid++;\n                    nodes.push_back({i,j});\n                }\n            }\n        }\n        int n = vid;\n        vector<vector<int>> g(n);\n        for (auto &p : nodes) {\n            int u = id[p.i][p.j];\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = p.i + di[dir], nj = p.j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                if (!empty[ni][nj]) continue;\n                int v = id[ni][nj];\n                g[u].push_back(v);\n            }\n        }\n        // Tarjan articulation\n        vector<int> tin(n, -1), low(n, -1), parent(n, -1);\n        vector<char> isArt(n, 0);\n        int timer = 0;\n        function<void(int)> dfs = [&](int u){\n            tin[u] = low[u] = timer++;\n            int child = 0;\n            for (int v : g[u]) {\n                if (tin[v] == -1) {\n                    parent[v] = u;\n                    ++child;\n                    dfs(v);\n                    low[u] = min(low[u], low[v]);\n                    if (parent[u] != -1 && low[v] >= tin[u]) isArt[u] = 1;\n                } else if (v != parent[u]) {\n                    low[u] = min(low[u], tin[v]);\n                }\n            }\n            if (parent[u] == -1 && child > 1) isArt[u] = 1;\n        };\n        // Run from any vertex (graph should be connected, but be robust)\n        for (int u = 0; u < n; ++u) if (tin[u] == -1) dfs(u);\n\n        vector<vector<char>> art(H, vector<char>(W, 0));\n        for (auto &p : nodes) {\n            int u = id[p.i][p.j];\n            art[p.i][p.j] = isArt[u];\n        }\n        return art;\n    };\n\n    auto choose_position = [&](int label)->Pos {\n        // Compute safe set (non-articulation empties), exclude entrance from candidates\n        vector<vector<char>> isArt = compute_articulation();\n        int bestCost = INT_MAX;\n        Pos best{-1,-1};\n        // Heuristic: prefer cells with rankIndex close to label\n        for (int idx = 0; idx < (int)order.size(); ++idx) {\n            int i = order[idx].i, j = order[idx].j;\n            if (!empty[i][j]) continue;          // already filled\n            if (isArt[i][j]) continue;           // avoid articulation to keep connectivity\n            // Also ensure it's reachable: since empty graph is connected and includes entrance, all empties are reachable.\n            int cost = abs(idx - label);\n            // Slight tie-breakers: prefer smaller dist if cost equal\n            if (cost < bestCost) {\n                bestCost = cost;\n                best = {i, j};\n            } else if (cost == bestCost) {\n                // tie-break: closer to entrance\n                int d1 = dist[i][j];\n                int d2 = dist[best.i][best.j];\n                if (d1 < d2) best = {i, j};\n            }\n        }\n        // As a fallback (should not happen), if none found, pick any empty non-entrance.\n        if (best.i == -1) {\n            for (int idx = 0; idx < (int)order.size(); ++idx) {\n                int i = order[idx].i, j = order[idx].j;\n                if (!empty[i][j]) continue;\n                best = {i, j};\n                break;\n            }\n        }\n        return best;\n    };\n\n    // Online placement loop\n    for (int d = 0; d < M; ++d) {\n        int t;\n        cin >> t;\n\n        Pos p = choose_position(t);\n        // place container\n        empty[p.i][p.j] = 0;\n        labelAt[p.i][p.j] = t;\n\n        // Output placement and flush\n        cout << p.i << ' ' << p.j << '\\n' << flush;\n    }\n\n    // Retrieval planning: greedy by smallest label on the frontier\n    // occ[i][j] true if container present (i.e., labelAt != -1). Entrance has no container.\n    vector<vector<char>> occ(H, vector<char>(W, 0));\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        if (obs[i][j]) continue;\n        if (i == ei && j == ej) continue;\n        if (labelAt[i][j] >= 0) occ[i][j] = 1;\n    }\n    // Min-heap by label\n    struct Node {\n        int label;\n        int i, j;\n        bool operator<(const Node& other) const {\n            return label > other.label; // for min-heap using priority_queue\n        }\n    };\n    priority_queue<Node> pq;\n    vector<vector<char>> inFrontier(H, vector<char>(W, 0));\n\n    auto try_push_frontier = [&](int i, int j){\n        if (!inside(i,j)) return;\n        if (obs[i][j]) return;\n        if (!occ[i][j]) return; // already empty / removed\n        if (inFrontier[i][j]) return;\n        inFrontier[i][j] = 1;\n        pq.push(Node{labelAt[i][j], i, j});\n    };\n\n    // Initialize frontier with neighbors of entrance\n    for (int dir = 0; dir < 4; ++dir) {\n        int ni = ei + di[dir], nj = ej + dj[dir];\n        if (!inside(ni, nj)) continue;\n        if (obs[ni][nj]) continue;\n        if (occ[ni][nj]) try_push_frontier(ni, nj);\n    }\n\n    vector<pair<int,int>> retrieval;\n    retrieval.reserve(M);\n\n    for (int step = 0; step < M; ++step) {\n        // Pop smallest label in the current frontier\n        while (!pq.empty() && !occ[pq.top().i][pq.top().j]) pq.pop();\n        if (pq.empty()) {\n            // As a fallback safety (shouldn't happen), scan all containers adjacent to any empty cell connected to entrance.\n            // But normally pq should never be empty.\n            // We'll break if that happens to avoid infinite loop.\n            break;\n        }\n        Node cur = pq.top(); pq.pop();\n        int ci = cur.i, cj = cur.j;\n        // Remove this container\n        occ[ci][cj] = 0;\n        retrieval.emplace_back(ci, cj);\n\n        // New empty cell added; push its container neighbors to frontier\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = ci + di[dir], nj = cj + dj[dir];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (occ[ni][nj]) try_push_frontier(ni, nj);\n        }\n    }\n\n    // Output retrieval order\n    for (auto &p : retrieval) {\n        cout << p.first << ' ' << p.second << '\\n';\n    }\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point start;\n    Timer() { start = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - start).count();\n        }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    if (!(cin >> n >> m)) {\n        return 0;\n    }\n    const int N = n * n;\n\n    vector<int> grid(N);\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int c; cin >> c;\n            grid[i*n + j] = c;\n        }\n    }\n\n    // Helpers\n    auto inb = [&](int r, int c)->bool { return (0 <= r && r < n && 0 <= c && c < n); };\n    const int dr[4] = {1, -1, 0, 0};\n    const int dc[4] = {0, 0, 1, -1};\n\n    // Color stats\n    vector<int> sizeCount(m+1, 0);\n    vector<int> boundaryCount(m+1, 0);\n    vector<char> isBC(m+1, 0), isIC(m+1, 0);\n\n    // degSame per cell\n    vector<int> degSame(N, 0);\n\n    // isBoundary position\n    vector<char> isBoundaryPos(N, 0);\n\n    // Compute sizeCount, boundaryCount, isBoundaryPos\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j;\n            int c = grid[id];\n            sizeCount[c]++;\n            if (i == 0 || j == 0 || i == n-1 || j == n-1) {\n                isBoundaryPos[id] = 1;\n                boundaryCount[c]++;\n            }\n        }\n    }\n    for (int c = 1; c <= m; ++c) isBC[c] = (boundaryCount[c] > 0);\n    for (int c = 1; c <= m; ++c) isIC[c] = !isBC[c];\n\n    // degSame\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j;\n            int c = grid[id];\n            int d = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int nid = ni*n + nj;\n                if (grid[nid] == c) d++;\n            }\n            degSame[id] = d;\n        }\n    }\n\n    // pairCount[u][v] stores number of adjacency edges between u<v\n    vector<vector<int>> pairCount(m+1, vector<int>(m+1, 0));\n    auto add_pair = [&](int a, int b, int delta){\n        if (a == b) return;\n        if (a == 0 || b == 0) return; // we track only 1..m pairs\n        if (a > b) swap(a, b);\n        pairCount[a][b] += delta;\n        if (pairCount[a][b] < 0) pairCount[a][b] = 0; // safety\n    };\n    // Initialize pair counts\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j+1 < n; ++j) {\n            int a = grid[i*n + j];\n            int b = grid[i*n + j + 1];\n            if (a != b) add_pair(a, b, +1);\n        }\n    }\n    for (int i = 0; i+1 < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int a = grid[i*n + j];\n            int b = grid[(i+1)*n + j];\n            if (a != b) add_pair(a, b, +1);\n        }\n    }\n    // Original adjacencies record (1..m only)\n    vector<vector<char>> origAdj(m+1, vector<char>(m+1, 0));\n    for (int a = 1; a <= m; ++a) for (int b = a+1; b <= m; ++b)\n        if (pairCount[a][b] > 0) origAdj[a][b] = 1;\n\n    // Precompute \"adjacent to interior\" per cell\n    vector<char> adjToIC(N, 0);\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j;\n            bool flag = false;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int nid = ni*n + nj;\n                int d = grid[nid];\n                if (d != 0 && isIC[d]) { flag = true; break; }\n            }\n            adjToIC[id] = flag ? 1 : 0;\n        }\n    }\n\n    auto hasZeroNeighbor = [&](int id)->bool {\n        int i = id / n, j = id % n;\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            if (grid[ni*n + nj] == 0) return true;\n        }\n        return false;\n    };\n\n    auto can_remove_leaf = [&](int id)->bool {\n        int c = grid[id];\n        if (c == 0) return false;\n        if (!isBC[c]) return false; // only boundary colors\n        if (adjToIC[id]) return false; // don't touch cells adjacent to interior colors\n        if (!(isBoundaryPos[id] || hasZeroNeighbor(id))) return false; // keep 0 connected to outside\n        if (sizeCount[c] <= 1) return false; // don't delete the last cell of a color\n        if (isBoundaryPos[id] && boundaryCount[c] <= 1) return false; // keep BC's adjacency to outside\n        if (degSame[id] > 1) return false;\n\n        // Check adjacency preservation: for each neighbor color d, ensure pairCount stays > 0 after removal\n        int i = id / n, j = id % n;\n        // accumulate counts per neighbor color\n        array<int, 128> dcols; // We\u2019ll store in a small vector below; this is unused.\n        // Compact small map: vector of pair<color, count>\n        array<int, 4> neighColor;\n        array<int, 4> neighId;\n        int t = 0;\n        vector<pair<int,int>> cnt; cnt.reserve(4);\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int nid = ni*n + nj;\n            int d = grid[nid];\n            if (d == 0 || d == c) continue;\n            bool found = false;\n            for (auto &pr : cnt) if (pr.first == d) { pr.second++; found = true; break; }\n            if (!found) cnt.emplace_back(d, 1);\n        }\n        for (auto &pr : cnt) {\n            int d = pr.first, cc = pr.second;\n            int u = c, v = d;\n            if (u > v) swap(u, v);\n            int pc = pairCount[u][v];\n            if (pc <= cc) return false; // would delete last (or all) contact(s) with d\n        }\n        return true;\n    };\n\n    auto remove_cell = [&](int id) {\n        int c = grid[id];\n        int i = id / n, j = id % n;\n        // update pair counts for neighbors of different color\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int nid = ni*n + nj;\n            int d = grid[nid];\n            if (d != 0 && d != c) {\n                int a = c, b = d;\n                if (a > b) swap(a, b);\n                if (a >= 1 && b >= 1) {\n                    if (pairCount[a][b] > 0) pairCount[a][b]--;\n                }\n            }\n        }\n        // update degSame for same-color neighbors\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int nid = ni*n + nj;\n            if (grid[nid] == c) {\n                degSame[nid]--;\n            }\n        }\n        if (isBoundaryPos[id]) boundaryCount[c]--;\n        sizeCount[c]--;\n        grid[id] = 0;\n        degSame[id] = 0;\n    };\n\n    Timer timer;\n    const double TIME_LIMIT = 1.95;\n\n    // Phase 1: peel leaves from boundary colors (not adjacent to interior)\n    deque<int> Q;\n    vector<char> inQ(N, 0);\n\n    for (int id = 0; id < N; ++id) {\n        int c = grid[id];\n        if (c == 0) continue;\n        if (!isBC[c]) continue;\n        if (!isBoundaryPos[id]) continue; // initially only boundary are accessible\n        if (can_remove_leaf(id)) {\n            Q.push_back(id);\n            inQ[id] = 1;\n        }\n    }\n\n    while (!Q.empty() && timer.elapsed() < TIME_LIMIT * 0.75) {\n        int id = Q.front(); Q.pop_front();\n        inQ[id] = 0;\n        if (grid[id] == 0) continue;\n        if (!can_remove_leaf(id)) continue;\n        // Remove and push neighbors as candidates\n        int i = id / n, j = id % n;\n        remove_cell(id);\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int nid = ni*n + nj;\n            if (grid[nid] == 0) continue;\n            int c = grid[nid];\n            if (!isBC[c]) continue;\n            if (!inQ[nid] && can_remove_leaf(nid)) {\n                Q.push_back(nid);\n                inQ[nid] = 1;\n            }\n        }\n    }\n\n    // Phase 2: remove deg==2 non-articulation nodes, still safe (not adjacent to IC, preserve pairs, accessible)\n    vector<int> seen(N, -1);\n    int stamp = 0;\n    auto connected_without = [&](int c, int p, int n1, int n2)->bool {\n        if (n1 == n2) return true;\n        stamp++;\n        deque<int> dq;\n        dq.push_back(n1);\n        seen[n1] = stamp;\n        while (!dq.empty()) {\n            int u = dq.front(); dq.pop_front();\n            int ui = u / n, uj = u % n;\n            for (int k = 0; k < 4; ++k) {\n                int vi = ui + dr[k], vj = uj + dc[k];\n                if (!inb(vi, vj)) continue;\n                int v = vi*n + vj;\n                if (v == p) continue;\n                if (grid[v] != c) continue;\n                if (seen[v] == stamp) continue;\n                if (v == n2) return true;\n                seen[v] = stamp;\n                dq.push_back(v);\n            }\n        }\n        return false;\n    };\n\n    auto can_remove_deg2 = [&](int id)->bool {\n        int c = grid[id];\n        if (c == 0) return false;\n        if (!isBC[c]) return false;\n        if (adjToIC[id]) return false;\n        if (!(isBoundaryPos[id] || hasZeroNeighbor(id))) return false;\n        if (sizeCount[c] <= 1) return false;\n        if (isBoundaryPos[id] && boundaryCount[c] <= 1) return false;\n        if (degSame[id] != 2) return false;\n\n        // Check adjacency preservation for all neighbor colors d\n        int i = id / n, j = id % n;\n        vector<pair<int,int>> cnt; cnt.reserve(4);\n        array<int,2> sameNei = {-1,-1};\n        int sn = 0;\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int nid = ni*n + nj;\n            int d = grid[nid];\n            if (d == c) {\n                if (sn < 2) sameNei[sn++] = nid;\n            } else if (d != 0) {\n                bool found = false;\n                for (auto &pr : cnt) if (pr.first == d) { pr.second++; found = true; break; }\n                if (!found) cnt.emplace_back(d, 1);\n            }\n        }\n        for (auto &pr : cnt) {\n            int d = pr.first, cc = pr.second;\n            int a = c, b = d;\n            if (a > b) swap(a, b);\n            int pc = pairCount[a][b];\n            if (pc <= cc) return false;\n        }\n        if (sn != 2) return false; // deg==2 implies exactly 2 same-color neighbors\n        // Connectivity test: neighbors must remain connected without this cell\n        if (!connected_without(c, id, sameNei[0], sameNei[1])) return false;\n\n        return true;\n    };\n\n    bool improved = true;\n    while (improved && timer.elapsed() < TIME_LIMIT * 0.98) {\n        improved = false;\n        for (int id = 0; id < N; ++id) {\n            if (grid[id] == 0) continue;\n            if (timer.elapsed() > TIME_LIMIT * 0.98) break;\n            if (can_remove_deg2(id)) {\n                int i = id / n, j = id % n;\n                remove_cell(id);\n                improved = true;\n                // Optional: after removal, some neighbors may now become leaves, but deg2 loop continues anyway.\n            }\n        }\n    }\n\n    // Output final grid\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            if (j) cout << ' ';\n            cout << grid[i*n + j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto ed = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(ed - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, D, Q;\n    if (!(cin >> N >> D >> Q)) return 0;\n\n    // PRNG with deterministic seed from N,D,Q to keep runs reproducible\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    seed ^= (uint64_t)D + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    seed ^= (uint64_t)Q + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    mt19937_64 rng(seed);\n    uniform_int_distribution<int> bit01(0, 1);\n\n    vector<int> score(N, 0);\n    vector<int> a(N);\n    string resp;\n\n    // Queries: random Rademacher vector per query (\u00b11 for each item), both sides non-empty.\n    for (int q = 0; q < Q; q++) {\n        int nL = 0, nR = 0;\n        while (true) {\n            nL = nR = 0;\n            for (int i = 0; i < N; i++) {\n                int b = bit01(rng);\n                a[i] = (b ? +1 : -1);\n                if (a[i] == +1) nL++;\n                else nR++;\n            }\n            if (nL > 0 && nR > 0) break; // extremely unlikely to fail, but guard anyway\n        }\n        // Prepare indices\n        cout << nL << ' ' << nR << ' ';\n        for (int i = 0, cnt = 0; i < N; i++) if (a[i] == +1) {\n            cout << i;\n            cnt++;\n            if (cnt < nL || nR > 0) cout << ' ';\n        }\n        for (int i = 0, cnt = 0; i < N; i++) if (a[i] == -1) {\n            cout << i;\n            cnt++;\n            if (cnt < nR) cout << ' ';\n        }\n        cout << \"\\n\" << flush;\n\n        if (!(cin >> resp)) return 0;\n        int y = 0;\n        if (resp[0] == '>') y = +1;\n        else if (resp[0] == '<') y = -1;\n        else if (resp[0] == '=') y = 0; // rare, ignore\n        else y = 0;\n\n        if (y != 0) {\n            for (int i = 0; i < N; i++) {\n                score[i] += y * a[i];\n            }\n        }\n    }\n\n    // Build positive weight estimates (direction only matters).\n    vector<double> w(N);\n    int maxAbsScore = 0;\n    for (int i = 0; i < N; i++) maxAbsScore = max(maxAbsScore, abs(score[i]));\n    if (maxAbsScore == 0) {\n        // fallback: if all responses were '=', use uniform small weights\n        for (int i = 0; i < N; i++) w[i] = 1.0;\n    } else {\n        for (int i = 0; i < N; i++) {\n            // Clamp negatives to small positive to avoid bias from per-bin counts if we added a constant\n            w[i] = (score[i] > 0) ? (double)score[i] : 1e-6;\n        }\n    }\n\n    // Order items by decreasing estimated weight\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    // Break ties randomly for stability\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        return w[i] > w[j];\n    });\n\n    // LPT assignment\n    vector<int> assign(N, -1);\n    vector<double> binSum(D, 0.0);\n    vector<vector<int>> bins(D);\n    for (int idx : ord) {\n        int best = 0;\n        double bestSum = binSum[0];\n        for (int b = 1; b < D; b++) {\n            if (binSum[b] < bestSum) {\n                bestSum = binSum[b];\n                best = b;\n            }\n        }\n        assign[idx] = best;\n        binSum[best] += w[idx];\n        bins[best].push_back(idx);\n    }\n\n    // Local improvements: move and swap between heaviest and lightest bins\n    auto recompute_extremes = [&]() -> pair<int,int> {\n        int h = 0, l = 0;\n        for (int b = 1; b < D; b++) {\n            if (binSum[b] > binSum[h]) h = b;\n            if (binSum[b] < binSum[l]) l = b;\n        }\n        return {h, l};\n    };\n\n    // Time budget for local search (~0.15 sec)\n    Timer timer;\n    const double TIME_BUDGET = 0.15;\n    int iter = 0;\n    while (iter < 100000) {\n        iter++;\n        if (timer.elapsed() > TIME_BUDGET) break;\n\n        auto [h, l] = recompute_extremes();\n        double gap = binSum[h] - binSum[l];\n        if (gap <= 0) break;\n\n        // Try single move: pick i in h with w_i < gap, closest to gap/2\n        int best_i = -1, best_i_pos = -1;\n        double best_delta = 0.0; // we look for negative delta\n        double target = gap * 0.5;\n        for (int pos = 0; pos < (int)bins[h].size(); pos++) {\n            int i = bins[h][pos];\n            double wi = w[i];\n            if (wi < gap) {\n                double delta = -2.0 * wi * gap + 2.0 * wi * wi; // change in s_h^2 + s_l^2\n                if (best_i == -1 || delta < best_delta || (abs(delta - best_delta) < 1e-12 && fabs(wi - target) < fabs(w[best_i] - target))) {\n                    best_delta = delta;\n                    best_i = i;\n                    best_i_pos = pos;\n                }\n            }\n        }\n        if (best_i != -1 && best_delta < -1e-12) {\n            // perform move h -> l\n            double wi = w[best_i];\n            // remove i from bins[h]\n            bins[h].erase(bins[h].begin() + best_i_pos);\n            assign[best_i] = l;\n            bins[l].push_back(best_i);\n            binSum[h] -= wi;\n            binSum[l] += wi;\n            continue;\n        }\n\n        // Try pair swap: pick i in h and j in l with 0 < d < gap and d close to gap/2\n        int best_ip = -1, best_jp = -1;\n        int best_i2 = -1, best_j2 = -1;\n        double best_delta2 = 0.0;\n        for (int pi = 0; pi < (int)bins[h].size(); pi++) {\n            int i = bins[h][pi];\n            double wi = w[i];\n            for (int pj = 0; pj < (int)bins[l].size(); pj++) {\n                int j = bins[l][pj];\n                double wj = w[j];\n                double d = wi - wj;\n                if (d <= 0 || d >= gap) continue;\n                double delta = 2.0 * (d*d - d*gap); // change in s_h^2 + s_l^2\n                // We want the most negative delta\n                if (best_i2 == -1 || delta < best_delta2 ||\n                    (abs(delta - best_delta2) < 1e-12 && fabs(d - target) < fabs((w[best_i2] - w[best_j2]) - target))) {\n                    best_delta2 = delta;\n                    best_ip = pi;\n                    best_jp = pj;\n                    best_i2 = i;\n                    best_j2 = j;\n                }\n            }\n        }\n        if (best_i2 != -1 && best_delta2 < -1e-12) {\n            // perform swap between h and l\n            int i = best_i2, j = best_j2;\n            double wi = w[i], wj = w[j];\n            // Remove i from bins[h], j from bins[l]\n            bins[h].erase(bins[h].begin() + best_ip);\n            // careful: after erasing from h, indices in l unaffected\n            bins[l].erase(bins[l].begin() + best_jp);\n            // add swapped\n            bins[h].push_back(j);\n            bins[l].push_back(i);\n            assign[i] = l;\n            assign[j] = h;\n            binSum[h] += (wj - wi);\n            binSum[l] += (wi - wj);\n            continue;\n        }\n\n        // No improving move/swap found between extremes -> stop\n        break;\n    }\n\n    // Output final assignment line\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << assign[i];\n    }\n    cout << '\\n' << flush;\n\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    if (!(cin >> n >> m)) return 0;\n    vector<vector<int>> st(m);\n    int per = n / m;\n    for (int i = 0; i < m; ++i) {\n        st[i].resize(per);\n        for (int j = 0; j < per; ++j) cin >> st[i][j];\n    }\n\n    vector<pair<int,int>> ops; // (v, i): i=0 for extraction, i in [1..m] for move\n    ops.reserve(5000);\n\n    auto carry_chain = [&](int &t) {\n        bool changed = true;\n        while (changed && t <= n) {\n            changed = false;\n            for (int i = 0; i < m; ++i) {\n                if (!st[i].empty() && st[i].back() == t) {\n                    // Extract t\n                    st[i].pop_back();\n                    ops.emplace_back(t, 0);\n                    ++t;\n                    changed = true;\n                    if (t > n) break;\n                }\n            }\n        }\n    };\n\n    int t = 1;\n    carry_chain(t);\n\n    auto choose_destination = [&](int src, int topBlock) -> int {\n        int dest = -1;\n        int bestTop = -1; // we want maximum top\n        int INF_TOP = n + 1; // treat empty as +infty\n        for (int i = 0; i < m; ++i) {\n            if (i == src) continue;\n            int topVal = st[i].empty() ? INF_TOP : st[i].back();\n            if (topVal > bestTop) {\n                bestTop = topVal;\n                dest = i;\n            }\n        }\n        if (dest == -1) {\n            // Should not happen when m>=2, but fallback to any other\n            dest = (src == 0 ? 1 : 0);\n        }\n        return dest;\n    };\n\n    while (t <= n) {\n        // Find t\n        int src = -1, idx = -1;\n        for (int i = 0; i < m; ++i) {\n            // scan from top down for slight speedup\n            for (int j = (int)st[i].size() - 1; j >= 0; --j) {\n                if (st[i][j] == t) {\n                    src = i;\n                    idx = j;\n                    break;\n                }\n            }\n            if (src != -1) break;\n        }\n        if (src == -1) {\n            // Should not happen\n            break;\n        }\n\n        if (idx == (int)st[src].size() - 1) {\n            // Already top, extract\n            st[src].pop_back();\n            ops.emplace_back(t, 0);\n            ++t;\n            carry_chain(t);\n            continue;\n        }\n\n        // Move the suffix above t as one block\n        int jv = idx + 1; // bottom index of moved block\n        int movedCount = (int)st[src].size() - jv;\n        int topBlock = st[src].back(); // top of moved block\n        int dest = choose_destination(src, topBlock);\n\n        int v = st[src][jv]; // bottom of moved block\n        // Append block to dest\n        // Copy suffix [jv..end)\n        for (int k = jv; k < (int)st[src].size(); ++k) {\n            st[dest].push_back(st[src][k]);\n        }\n        st[src].resize(jv);\n        ops.emplace_back(v, dest + 1); // stacks are 1-indexed in output\n\n        // After moving, t becomes top of src; extraction will be handled by carry_chain\n        carry_chain(t);\n    }\n\n    // Output operations\n    // Ensure we don't exceed operation cap\n    if ((int)ops.size() > 5000) {\n        // Fallback: truncate (invalid), but this should never happen with this strategy.\n        ops.resize(5000);\n    }\n    for (auto &p : ops) {\n        cout << p.first << ' ' << p.second << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge {\n    int u, v;\n    char ch_uv, ch_vu;\n};\n\nstruct Adj {\n    int to;\n    int eid;\n    char ch; // move char from current node to 'to'\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n\n    vector<string> hWall(max(0, N-1));\n    for (int i = 0; i < N-1; i++) cin >> hWall[i];\n    vector<string> vWall(N);\n    for (int i = 0; i < N; i++) cin >> vWall[i];\n\n    vector<vector<int>> d(N, vector<int>(N));\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) cin >> d[i][j];\n    }\n\n    auto inb = [&](int i, int j) -> bool {\n        return 0 <= i && i < N && 0 <= j && j < N;\n    };\n    auto canMove = [&](int i, int j, int di, int dj) -> bool {\n        int ni = i + di, nj = j + dj;\n        if (!inb(ni, nj)) return false;\n        if (di == 0 && dj == 1) { // right\n            return vWall[i][j] == '0';\n        } else if (di == 0 && dj == -1) { // left\n            return vWall[i][j-1] == '0';\n        } else if (di == 1 && dj == 0) { // down\n            return hWall[i][j] == '0';\n        } else if (di == -1 && dj == 0) { // up\n            return hWall[i-1][j] == '0';\n        }\n        return false;\n    };\n\n    int V = N * N;\n    auto id = [&](int i, int j) { return i * N + j; };\n    auto coord = [&](int v) { return pair<int,int>(v / N, v % N); };\n\n    // Build full adjacency for BFS (unweighted)\n    vector<vector<int>> adjGrid(V);\n    vector<vector<char>> adjDir(V);\n    int di[4] = {0, 1, 0, -1};\n    int dj[4] = {1, 0, -1, 0};\n    char dc[4] = {'R','D','L','U'};\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int u = id(i,j);\n        for (int k = 0; k < 4; k++) {\n            int ni = i + di[k], nj = j + dj[k];\n            if (!inb(ni, nj)) continue;\n            if (canMove(i, j, di[k], dj[k])) {\n                int v = id(ni, nj);\n                adjGrid[u].push_back(v);\n                adjDir[u].push_back(dc[k]);\n            }\n        }\n    }\n\n    // BFS to get shortest distances and a parent tree\n    vector<int> dist(V, -1), par(V, -1);\n    vector<char> stepFromPar(V, '?'); // direction from parent to node\n    deque<int> dq;\n    int root = 0;\n    dist[root] = 0;\n    dq.push_back(root);\n    while (!dq.empty()) {\n        int u = dq.front(); dq.pop_front();\n        for (int idx = 0; idx < (int)adjGrid[u].size(); idx++) {\n            int v = adjGrid[u][idx];\n            if (dist[v] >= 0) continue;\n            dist[v] = dist[u] + 1;\n            par[v] = u;\n            stepFromPar[v] = adjDir[u][idx];\n            dq.push_back(v);\n        }\n    }\n\n    // children list (tree)\n    vector<vector<int>> children(V);\n    for (int v = 0; v < V; v++) {\n        if (v == root) continue;\n        children[par[v]].push_back(v);\n    }\n\n    // Tree edges\n    int E = V - 1;\n    vector<Edge> edges;\n    edges.reserve(E);\n    vector<int> edgeIdToParent(V, -1); // edge id from parent to this node (for v != root)\n    for (int vtx = 0; vtx < V; vtx++) {\n        if (vtx == root) continue;\n        int p = par[vtx];\n        auto [pi, pj] = coord(p);\n        auto [vi, vj] = coord(vtx);\n        char ch_pv;\n        if (vi == pi && vj == pj + 1) ch_pv = 'R';\n        else if (vi == pi && vj == pj - 1) ch_pv = 'L';\n        else if (vi == pi + 1 && vj == pj) ch_pv = 'D';\n        else if (vi == pi - 1 && vj == pj) ch_pv = 'U';\n        else ch_pv = '?';\n\n        char ch_vp;\n        if (ch_pv == 'R') ch_vp = 'L';\n        else if (ch_pv == 'L') ch_vp = 'R';\n        else if (ch_pv == 'U') ch_vp = 'D';\n        else if (ch_pv == 'D') ch_vp = 'U';\n        else ch_vp = '?';\n\n        Edge e{p, vtx, ch_pv, ch_vp};\n        int eid = (int)edges.size();\n        edges.push_back(e);\n        edgeIdToParent[vtx] = eid;\n    }\n\n    // Precompute sqrt(d) and dist-weighted sum for alpha hint (not strictly needed for binary search)\n    vector<long double> wsqrt(V);\n    long double sumW = 0.0;\n    for (int v = 0; v < V; v++) {\n        auto [i, j] = coord(v);\n        wsqrt[v] = sqrtl((long double)d[i][j]);\n        if (dist[v] > 0) sumW += wsqrt[v] * (long double)dist[v];\n    }\n\n    auto compute_length = [&](long double alpha, vector<long long>* out_sminus1 = nullptr) -> long long {\n        long long base = 2LL * (V - 1);\n        long long extra = 0;\n        if (out_sminus1) out_sminus1->assign(V, 0);\n        for (int v = 0; v < V; v++) {\n            if (v == root) continue; // ignore root as extra; costless and useless\n            long double x = alpha * wsqrt[v];\n            long long s1 = (long long)floorl(x + 1e-18L);\n            if (s1 < 0) s1 = 0;\n            if (out_sminus1) (*out_sminus1)[v] = s1;\n            extra += 2LL * (long long)dist[v] * s1;\n        }\n        return base + extra;\n    };\n\n    const long long Lmax = 100000;\n\n    // Binary search alpha\n    long double lo = 0.0L, hi = 1.0L;\n    // ensure hi is enough\n    while (true) {\n        long long Lh = compute_length(hi);\n        if (Lh > Lmax) break;\n        if (hi > 1e12L) break; // safety\n        hi *= 2.0L;\n    }\n    for (int it = 0; it < 50; it++) {\n        long double mid = (lo + hi) * 0.5L;\n        long long Lm = compute_length(mid);\n        if (Lm <= Lmax) lo = mid; else hi = mid;\n    }\n\n    vector<long long> sminus1; // s_i - 1 for each node (root zero)\n    long long Lfinal = compute_length(lo, &sminus1);\n    // Safety: If due to numeric we overshoot, reduce greedily far nodes\n    if (Lfinal > Lmax) {\n        // Build list of nodes with sminus1 > 0, sorted by dist descending (drop costly ones first)\n        vector<int> idx;\n        for (int v = 0; v < V; v++) if (v != root && sminus1[v] > 0) idx.push_back(v);\n        sort(idx.begin(), idx.end(), [&](int a, int b){\n            if (dist[a] != dist[b]) return dist[a] > dist[b];\n            return a < b;\n        });\n        for (int v : idx) {\n            while (sminus1[v] > 0 && Lfinal > Lmax) {\n                sminus1[v]--;\n                Lfinal -= 2LL * dist[v];\n            }\n            if (Lfinal <= Lmax) break;\n        }\n    }\n    // Optional: try to fill remaining budget by giving extra to cheap, high-d nodes\n    // (very light heuristic; keeps computation simple)\n    long long remLen = Lmax - Lfinal;\n    if (remLen >= 2) {\n        // candidates sorted by score = d / (dist+1) roughly; only v != root and dist>0\n        vector<int> cand;\n        cand.reserve(V);\n        for (int v = 0; v < V; v++) if (v != root && dist[v] > 0) cand.push_back(v);\n        sort(cand.begin(), cand.end(), [&](int a, int b){\n            auto [ai, aj] = coord(a);\n            auto [bi, bj] = coord(b);\n            long double ra = (long double)d[ai][aj] / (long double)dist[a];\n            long double rb = (long double)d[bi][bj] / (long double)dist[b];\n            if (ra != rb) return ra > rb;\n            return a < b;\n        });\n        for (int v : cand) {\n            if (remLen < 2LL * dist[v]) continue;\n            // add one\n            sminus1[v]++;\n            remLen -= 2LL * dist[v];\n            if (remLen < 2) break;\n        }\n        Lfinal = Lmax - remLen;\n    }\n\n    // Compute subtree sums of extra for multiplicities\n    vector<long long> subExtra(V, 0);\n    vector<int> order(V);\n    iota(order.begin(), order.end(), 0);\n    // process in descending dist so children before parent\n    sort(order.begin(), order.end(), [&](int a, int b){\n        if (dist[a] != dist[b]) return dist[a] > dist[b];\n        return a < b;\n    });\n    for (int v : order) {\n        long long sumc = 0;\n        for (int c : children[v]) sumc += subExtra[c];\n        if (v == root) subExtra[v] = sumc; // root's own sminus1 ignored\n        else subExtra[v] = sumc + sminus1[v];\n    }\n\n    // Edge multiplicities: m_e = 2 * (1 + subExtra[child])\n    int M = (int)edges.size();\n    vector<long long> rem(M, 0);\n    for (int v = 0; v < V; v++) {\n        if (v == root) continue;\n        int eid = edgeIdToParent[v];\n        long long m = 2LL * (1 + subExtra[v]);\n        rem[eid] = m;\n    }\n\n    // Build adjacency for Euler using only tree edges with multiplicities\n    vector<vector<Adj>> adj(V);\n    adj.assign(V, {});\n    for (int eid = 0; eid < M; eid++) {\n        auto &e = edges[eid];\n        adj[e.u].push_back(Adj{e.v, eid, e.ch_uv});\n        adj[e.v].push_back(Adj{e.u, eid, e.ch_vu});\n    }\n\n    // Hierholzer's algorithm with selection of neighbor edge having max remaining multiplicity\n    vector<int> st;\n    st.reserve(Lfinal + 5);\n    vector<int> out;\n    out.reserve(Lfinal + 5);\n    st.push_back(root);\n    // For speed, degrees are small (<=4), we can scan adjacency per step.\n    // We'll maintain rem in vector<long long> rem.\n    while (!st.empty()) {\n        int v = st.back();\n        int bestIdx = -1;\n        long long bestRem = -1;\n        for (int idx = 0; idx < (int)adj[v].size(); idx++) {\n            int eid = adj[v][idx].eid;\n            if (rem[eid] > 0) {\n                if (rem[eid] > bestRem) {\n                    bestRem = rem[eid];\n                    bestIdx = idx;\n                }\n            }\n        }\n        if (bestIdx != -1) {\n            // consume one traversal of this edge\n            int eid = adj[v][bestIdx].eid;\n            int to = adj[v][bestIdx].to;\n            rem[eid]--;\n            st.push_back(to);\n        } else {\n            out.push_back(v);\n            st.pop_back();\n        }\n    }\n    // out contains the Euler tour vertices in reverse\n    reverse(out.begin(), out.end());\n\n    // Build move string from consecutive vertices\n    string ans;\n    ans.reserve(out.size() > 0 ? out.size()-1 : 0);\n    for (size_t i = 0; i + 1 < out.size(); i++) {\n        int a = out[i], b = out[i+1];\n        auto [ai, aj] = coord(a);\n        auto [bi, bj] = coord(b);\n        char ch = '?';\n        if (bi == ai && bj == aj + 1) ch = 'R';\n        else if (bi == ai && bj == aj - 1) ch = 'L';\n        else if (bi == ai + 1 && bj == aj) ch = 'D';\n        else if (bi == ai - 1 && bj == aj) ch = 'U';\n        else {\n            // Should never happen; fallback: find in adj list\n            bool found = false;\n            for (auto &ad : adj[a]) if (ad.to == b) { ch = ad.ch; found = true; break; }\n            if (!found) ch = 'U'; // arbitrary\n        }\n        ans.push_back(ch);\n    }\n\n    // Safety: ensure constraints\n    if (!ans.empty()) {\n        // Make sure start/end at root: Euler guarantees it if graph even and connected.\n        // Ensure length <= 100000\n        if ((int)ans.size() > 100000) {\n            // truncate (shouldn't happen). Keep at least something valid.\n            ans.resize(100000);\n        }\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, r;\n    DSU(int n=0): n(n), p(n), r(n,0) { iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n    bool unite(int a, int b){\n        a = find(a); b = find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n    bool same(int a, int b){ return find(a)==find(b); }\n};\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed=88172645463393265ull){ x=seed; }\n    uint64_t next(){\n        x ^= x<<7;\n        x ^= x>>9;\n        return x;\n    }\n    int next_int(int l, int r){ // inclusive\n        return l + (int)(next() % (uint64_t)(r-l+1));\n    }\n    double next_double(){ return (next() >> 11) * (1.0 / (1ull<<53)); }\n};\n\nstruct Pos { short i, j; };\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, M;\n    if(!(cin >> N >> M)) return 0;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> A(N);\n    for(int i=0;i<N;i++) cin >> A[i];\n    vector<string> t(M);\n    for(int k=0;k<M;k++) cin >> t[k]; // M=200, each length 5\n\n    // Collect positions for each uppercase letter\n    vector<vector<Pos>> pos(26);\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            int c = A[i][j]-'A';\n            pos[c].push_back(Pos{(short)i,(short)j});\n        }\n    }\n\n    // Precompute overlap matrix f[i][j]: longest k in [0..4] suffix of t[i] length k equals prefix of t[j] length k\n    vector<array<short, 26>> dummy; // not used\n    vector<vector<int>> f(M, vector<int>(M, 0));\n    auto overlap = [&](const string& a, const string& b)->int{\n        // lengths are 5\n        // check k from 4 to 1\n        for(int k=4;k>=1;k--){\n            bool ok=true;\n            for(int x=0;x<k;x++){\n                if(a[5-k+x] != b[x]){ ok=false; break; }\n            }\n            if(ok) return k;\n        }\n        return 0;\n    };\n    for(int i=0;i<M;i++){\n        for(int j=0;j<M;j++){\n            if(i==j) continue;\n            f[i][j] = overlap(t[i], t[j]);\n        }\n    }\n\n    auto sum_overlaps = [&](const vector<int>& pi)->int{\n        int s=0;\n        for(int i=0;i+1<(int)pi.size();i++) s += f[pi[i]][pi[i+1]];\n        return s;\n    };\n\n    XorShift rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Initial candidate 1: Greedy arc packing to form chains\n    vector<int> best_pi;\n    int best_score = -1;\n\n    {\n        struct Arc { int u, v; int w; uint64_t r; };\n        vector<Arc> arcs;\n        arcs.reserve((size_t)M*(M-1));\n        for(int i=0;i<M;i++){\n            for(int j=0;j<M;j++){\n                if(i==j) continue;\n                Arc a{ i, j, f[i][j], rng.next() };\n                arcs.push_back(a);\n            }\n        }\n        sort(arcs.begin(), arcs.end(), [](const Arc& a, const Arc& b){\n            if(a.w != b.w) return a.w > b.w;\n            return a.r < b.r;\n        });\n        vector<int> succ(M, -1), pred(M, -1);\n        DSU uf(M);\n        for(const auto& e : arcs){\n            int u=e.u, v=e.v;\n            if(succ[u]!=-1) continue;\n            if(pred[v]!=-1) continue;\n            if(uf.same(u, v)) continue; // would create a cycle\n            succ[u]=v;\n            pred[v]=u;\n            uf.unite(u, v);\n        }\n        // Extract chains\n        vector<char> used(M, 0);\n        vector<vector<int>> chains;\n        for(int i=0;i<M;i++){\n            if(pred[i]==-1){ // head of chain\n                vector<int> chain;\n                int cur=i;\n                while(cur!=-1){\n                    chain.push_back(cur);\n                    used[cur]=1;\n                    cur = succ[cur];\n                }\n                chains.push_back(move(chain));\n            }\n        }\n        // Any remaining nodes (in case of anomalies) -> singletons\n        for(int i=0;i<M;i++){\n            if(!used[i]){\n                chains.push_back(vector<int>{i});\n                used[i]=1;\n            }\n        }\n        int C = (int)chains.size();\n        // Build chain order greedily\n        vector<int> head(C), tail(C);\n        for(int c=0;c<C;c++){\n            head[c] = chains[c].front();\n            tail[c] = chains[c].back();\n        }\n        // Compute inBest for chains\n        vector<int> inBest(C, 0);\n        for(int j=0;j<C;j++){\n            int best=0;\n            for(int i=0;i<C;i++){\n                if(i==j) continue;\n                best = max(best, f[tail[i]][head[j]]);\n            }\n            inBest[j]=best;\n        }\n        int start = 0;\n        int minIn = INT_MAX;\n        for(int j=0;j<C;j++){\n            if(inBest[j] < minIn){\n                minIn = inBest[j];\n                start = j;\n            }\n        }\n        vector<char> usedChain(C, 0);\n        vector<int> orderChains; orderChains.reserve(C);\n        int cur = start; usedChain[cur]=1; orderChains.push_back(cur);\n        for(int step=1; step<C; step++){\n            int bestW=-1, bestJ=-1;\n            for(int j=0;j<C;j++){\n                if(usedChain[j]) continue;\n                int w = f[tail[cur]][head[j]];\n                if(w>bestW){ bestW=w; bestJ=j; }\n            }\n            if(bestJ==-1){\n                // pick any remaining\n                for(int j=0;j<C;j++){ if(!usedChain[j]){ bestJ=j; break; } }\n            }\n            usedChain[bestJ]=1;\n            orderChains.push_back(bestJ);\n            cur = bestJ;\n        }\n        vector<int> pi;\n        pi.reserve(M);\n        for(int idx : orderChains){\n            for(int node : chains[idx]) pi.push_back(node);\n        }\n        int score = sum_overlaps(pi);\n        if(score > best_score){\n            best_score = score;\n            best_pi = pi;\n        }\n    }\n\n    // Initial candidate 2: nearest neighbor greedy from several starts\n    {\n        // Precompute best outgoing for tie breaks\n        vector<int> bestOut(M, 0), bestIn(M, 0);\n        for(int i=0;i<M;i++){\n            int bo=0, bi=0;\n            for(int j=0;j<M;j++){\n                if(i==j) continue;\n                bo = max(bo, f[i][j]);\n                bi = max(bi, f[j][i]);\n            }\n            bestOut[i]=bo; bestIn[i]=bi;\n        }\n        auto build_from_start = [&](int s)->vector<int>{\n            vector<char> used(M,0);\n            vector<int> pi; pi.reserve(M);\n            int cur = s; used[cur]=1; pi.push_back(cur);\n            for(int k=1;k<M;k++){\n                int bestW=-1, bestJ=-1;\n                int bestTie=-1;\n                for(int j=0;j<M;j++){\n                    if(used[j]) continue;\n                    int w = f[cur][j];\n                    int tie = bestOut[j]; // or bestIn, choose out\n                    if(w > bestW || (w==bestW && tie > bestTie)){\n                        bestW=w; bestJ=j; bestTie=tie;\n                    }\n                }\n                if(bestJ==-1){\n                    for(int j=0;j<M;j++){ if(!used[j]){ bestJ=j; break; } }\n                }\n                used[bestJ]=1;\n                pi.push_back(bestJ);\n                cur=bestJ;\n            }\n            return pi;\n        };\n        // Try multiple starts (all or subset)\n        int trials = min(M, 40); // try 40 starts to save time\n        vector<int> startList;\n        startList.reserve(trials);\n        // pick some deterministic plus random starts\n        for(int i=0;i<trials;i++){\n            startList.push_back(i);\n        }\n        // Some random additional\n        for(int i=trials;i<min(M, trials+10);i++){\n            startList.push_back(rng.next_int(0, M-1));\n        }\n        for(int s : startList){\n            vector<int> pi = build_from_start(s);\n            int score = sum_overlaps(pi);\n            if(score > best_score){\n                best_score = score;\n                best_pi = move(pi);\n            }\n        }\n    }\n\n    // Local search: insertion-based hill climbing to improve sum of overlaps\n    vector<int> pi = best_pi;\n    int curSum = sum_overlaps(pi);\n\n    auto getEdge = [&](int a, int b)->int{\n        if(a<0 || b<0) return 0;\n        return f[a][b];\n    };\n\n    auto compute_insert_delta = [&](const vector<int>& p, int i, int j2)->int{\n        // i in [0..M-1], j2 in [0..M-1] inclusive of end position (len = M-1)\n        int Mloc = (int)p.size();\n        int x = p[i];\n        int delta = 0;\n        // Removal\n        if(i > 0) delta -= getEdge(p[i-1], p[i]);\n        if(i < Mloc-1) delta -= getEdge(p[i], p[i+1]);\n        if(i > 0 && i < Mloc-1) delta += getEdge(p[i-1], p[i+1]);\n\n        int len = Mloc - 1;\n        if(j2 < 0 || j2 > len) return INT_MIN/4; // invalid\n        auto getAfter = [&](int k)->int{\n            // k in [0..len-1]\n            if(k < i) return p[k];\n            else return p[k+1];\n        };\n        int L = -1, R = -1;\n        if(j2 > 0) L = getAfter(j2-1);\n        if(j2 < len) R = getAfter(j2);\n        // Replace boundary edge L->R by L->x and x->R\n        if(L != -1 && R != -1){\n            delta -= getEdge(L, R);\n            delta += getEdge(L, x);\n            delta += getEdge(x, R);\n        }else if(L == -1 && R != -1){\n            delta += getEdge(x, R);\n        }else if(L != -1 && R == -1){\n            delta += getEdge(L, x);\n        }else{\n            // len==0, inserting single element into empty? won't happen here\n        }\n        return delta;\n    };\n\n    auto apply_insert = [&](vector<int>& p, int i, int j2){\n        int x = p[i];\n        p.erase(p.begin()+i);\n        p.insert(p.begin()+j2, x);\n    };\n\n    auto start_time = chrono::high_resolution_clock::now();\n    double TIME_LIMIT = 1.75; // seconds budget for local search to be safe\n    auto elapsed = [&](){\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - start_time).count();\n    };\n\n    // First-improvement loop\n    while(true){\n        if(elapsed() > TIME_LIMIT) break;\n        bool improved = false;\n        // To diversify, randomize iteration order sometimes\n        vector<int> idx(M);\n        iota(idx.begin(), idx.end(), 0);\n        if(rng.next_int(0, 1)) {\n            shuffle(idx.begin(), idx.end(), std::mt19937((uint32_t)rng.next()));\n        }\n        for(int ii=0; ii<M; ii++){\n            if(elapsed() > TIME_LIMIT) break;\n            int i = idx[ii];\n            int len = M-1;\n            // j2 in [0..len], but skip \"no-op\" position:\n            // After removing i, inserting back at position i is no-op. So skip j2==i.\n            for(int j2=0; j2<=len; j2++){\n                if(j2 == i) continue;\n                int delta = compute_insert_delta(pi, i, j2);\n                if(delta > 0){\n                    apply_insert(pi, i, j2);\n                    curSum += delta;\n                    improved = true;\n                    break;\n                }\n            }\n            if(improved) break;\n        }\n        if(!improved) break;\n    }\n\n    // Build the string S from the permutation pi\n    string S;\n    S.reserve(5 * M); // approximate\n    S += t[pi[0]];\n    for(int k=1;k<M;k++){\n        int a = pi[k-1], b = pi[k];\n        int ov = f[a][b];\n        for(int x=ov; x<5; x++) S.push_back(t[b][x]);\n    }\n\n    // Map S to grid positions minimizing total cost via DP\n    int L = (int)S.size();\n    vector<int> letters(L);\n    for(int i=0;i<L;i++) letters[i] = S[i]-'A';\n\n    // parent pointers: for each step, for each candidate pos index at that step, store selected prev index\n    vector<vector<int>> parent(L); // parent[l][qidx] = index in pos[letters[l-1]]\n    vector<int> prev_dp_idx; // not needed entire; keep dp arrays\n    vector<int> dp_prev, dp_curr;\n    vector<pair<int,int>> coords_prev, coords_curr; // not necessary, we can access pos arrays\n\n    // Initialize for step 0\n    int c0 = letters[0];\n    int P0 = pos[c0].size();\n    if(P0 == 0){\n        // In case letter does not exist (should not happen due to guarantee), fallback: pick any cell 0,0\n        // But problem guarantees presence.\n    }\n    dp_prev.assign(P0, INT_MAX/4);\n    parent[0].assign(P0, -1);\n    for(int q=0;q<P0;q++){\n        int ii = pos[c0][q].i, jj = pos[c0][q].j;\n        int dist = abs(ii - si) + abs(jj - sj);\n        dp_prev[q] = dist + 1;\n    }\n\n    for(int l=1;l<L;l++){\n        int c = letters[l];\n        int Pc = pos[c].size();\n        int cp = letters[l-1];\n        int Pp = pos[cp].size();\n        dp_curr.assign(Pc, INT_MAX/4);\n        parent[l].assign(Pc, -1);\n        // For each current candidate, find best previous\n        for(int q=0;q<Pc;q++){\n            int qi = pos[c][q].i, qj = pos[c][q].j;\n            int best = INT_MAX/4;\n            int bestp = -1;\n            // iterate previous candidates\n            for(int p=0;p<Pp;p++){\n                int pi_i = pos[cp][p].i, pi_j = pos[cp][p].j;\n                int dist = abs(qi - pi_i) + abs(qj - pi_j);\n                int cand = dp_prev[p] + dist + 1;\n                if(cand < best){\n                    best = cand;\n                    bestp = p;\n                }\n            }\n            dp_curr[q] = best;\n            parent[l][q] = bestp;\n        }\n        dp_prev.swap(dp_curr);\n    }\n\n    // Choose best last position\n    int last_letter = letters[L-1];\n    int P_last = pos[last_letter].size();\n    int best_last_idx = 0;\n    int best_cost = INT_MAX/4;\n    for(int q=0;q<P_last;q++){\n        if(dp_prev[q] < best_cost){\n            best_cost = dp_prev[q];\n            best_last_idx = q;\n        }\n    }\n\n    // Reconstruct path\n    vector<pair<int,int>> ops(L);\n    int idx = best_last_idx;\n    for(int l=L-1; l>=0; l--){\n        int c = letters[l];\n        int ii = pos[c][idx].i, jj = pos[c][idx].j;\n        ops[l] = {ii, jj};\n        if(l>0){\n            idx = parent[l][idx];\n            if(idx < 0) idx = 0; // safety\n        }\n    }\n\n    // Output\n    // L is number of operations (length of S), guaranteed < 5000\n    for(int l=0;l<L;l++){\n        cout << ops[l].first << \" \" << ops[l].second << \"\\n\";\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer for time management\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::steady_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\n// Utilities\nstatic inline int cell_id(int i, int j, int N) { return i * N + j; }\nstatic inline pair<int,int> cell_ij(int id, int N) { return {id / N, id % N}; }\n\nstruct Shape {\n    int id;\n    vector<pair<int,int>> offsets; // relative cells (di,dj)\n    int H=0, W=0;\n    vector<vector<int>> shiftsCells; // per shift index, list of covered global cell ids\n    // For each global cell id (0..N*N-1), list of shift indices that cover it\n    vector<vector<int>> coverShiftsByCell; // size N*N; sparse per shape\n};\n\nstruct Problem {\n    int N, M;\n    double eps;\n    vector<Shape> shapes;\n};\n\nstruct State {\n    int N, M;\n    const Problem* prob;\n\n    // Known v values per cell; -1 unknown, >=0 known\n    vector<int> known; // size N*N\n    vector<int> drilledCells; // list of cell ids drilled\n    vector<int> vDrilled; // same order as drilledCells\n    vector<int> drilledIndexOf; // size N*N, maps cell id -> index in drilledCells or -1\n\n    // Active candidate shifts per shape: active[k][p] bool\n    vector<vector<uint8_t>> active; // per shape k, size Pk\n    vector<int> activeCount; // per shape k: number of active candidates\n\n    // For computation on drilled cells\n    int D = 0;\n    vector<vector<int>> anyCoverKD;  // M x D : 0/1 whether shape k could cover drilled cell d\n    vector<vector<int>> mustCoverKD; // M x D : 0/1 whether shape k must cover drilled cell d (all candidates cover it)\n    vector<int> sumAnyD;  // size D\n    vector<int> sumMustD; // size D\n\n    // caches per enumeration run: for each shape k, for each shift p, list of drilled indices it covers\n    vector<vector<vector<int>>> coverDrilledCache; // M x Pk x (#drilled covered indices)\n\n    // Operation count\n    int opCount = 0;\n    int opLimit;\n\n    // Random\n    mt19937 rng;\n\n    // Time management\n    Timer timer;\n    double timeLimitSec = 2.7; // keep some margin\n\n    State(const Problem* pr) {\n        prob = pr;\n        N = pr->N;\n        M = pr->M;\n        known.assign(N*N, -1);\n        drilledIndexOf.assign(N*N, -1);\n        active.resize(M);\n        activeCount.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            active[k].assign(Pk, 1);\n            activeCount[k] = Pk;\n        }\n        rng.seed(chrono::high_resolution_clock::now().time_since_epoch().count());\n        opLimit = 2 * N * N; // per problem\n    }\n\n    void flush() { cout.flush(); }\n\n    int drill_cell(int ci) {\n        if (known[ci] != -1) return known[ci];\n        auto [i,j] = cell_ij(ci, N);\n        cout << \"q 1 \" << i << \" \" << j << \"\\n\";\n        flush();\n        string s;\n        if (!(cin >> s)) {\n            // Should not happen; safeguard\n            exit(0);\n        }\n        int val = stoi(s);\n        known[ci] = val;\n        drilledIndexOf[ci] = (int)drilledCells.size();\n        drilledCells.push_back(ci);\n        vDrilled.push_back(val);\n        ++opCount;\n        // zero elimination\n        if (val == 0) {\n            // Eliminate all active shifts covering this cell\n            for (int k = 0; k < M; ++k) {\n                if (activeCount[k] == 0) continue;\n                const vector<int>& listShifts = prob->shapes[k].coverShiftsByCell[ci];\n                for (int p : listShifts) {\n                    if (active[k][p]) {\n                        active[k][p] = 0;\n                        --activeCount[k];\n                    }\n                }\n            }\n        }\n        return val;\n    }\n\n    // recompute D and per-drilled coverage bounds from current active sets\n    void recomputeCoverageBounds() {\n        D = (int)drilledCells.size();\n        anyCoverKD.assign(M, vector<int>(D, 0));\n        mustCoverKD.assign(M, vector<int>(D, 0));\n        sumAnyD.assign(D, 0);\n        sumMustD.assign(D, 0);\n        // For each shape k, for each drilled cell d, compute how many active shifts cover it\n        for (int k = 0; k < M; ++k) {\n            if (activeCount[k] == 0) continue; // Infeasible but handle\n            for (int d = 0; d < D; ++d) {\n                int c = drilledCells[d];\n                int count = 0;\n                const vector<int>& listShifts = prob->shapes[k].coverShiftsByCell[c];\n                for (int p : listShifts) if (active[k][p]) ++count;\n                anyCoverKD[k][d] = (count > 0) ? 1 : 0;\n                mustCoverKD[k][d] = (count == activeCount[k]) ? 1 : 0;\n                sumAnyD[d] += anyCoverKD[k][d];\n                sumMustD[d] += mustCoverKD[k][d];\n            }\n        }\n    }\n\n    // Prepare coverDrilledCache for current drilled set\n    void buildCoverDrilledCache() {\n        D = (int)drilledCells.size();\n        coverDrilledCache.clear();\n        coverDrilledCache.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            coverDrilledCache[k].resize(Pk);\n        }\n        // Build mapping cell id -> drilled index is already drilledIndexOf\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            for (int p = 0; p < Pk; ++p) {\n                if (!active[k][p]) { coverDrilledCache[k][p].clear(); continue; }\n                const vector<int>& cells = prob->shapes[k].shiftsCells[p];\n                vector<int>& vect = coverDrilledCache[k][p];\n                vect.clear();\n                // For each covered cell, if it is drilled, add its drilled index\n                for (int c : cells) {\n                    int d = drilledIndexOf[c];\n                    if (d >= 0) vect.push_back(d);\n                }\n                sort(vect.begin(), vect.end()); // for membership scan\n                vect.erase(unique(vect.begin(), vect.end()), vect.end());\n            }\n        }\n    }\n\n    // Choose shapes order for DFS. Optional: for target cell constraint\n    vector<int> chooseOrder(int targetCell = -1, int requireCovered = -1) {\n        // requireCovered: -1 no special, 0 force uncovered, 1 force covered\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        // prefer shapes with smaller activeCount; if force covered on targetCell, prioritize shapes that can cover it\n        auto canCover = [&](int k)->int {\n            if (targetCell < 0) return 0;\n            const auto& list = prob->shapes[k].coverShiftsByCell[targetCell];\n            for (int p : list) if (active[k][p]) return 1;\n            return 0;\n        };\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b){\n            // For requireCovered==1, shapes that can cover target come first\n            int ca = canCover(a), cb = canCover(b);\n            if (requireCovered == 1) {\n                if (ca != cb) return ca > cb;\n            } else if (requireCovered == 0) {\n                // force uncovered doesn't need special ordering\n            }\n            if (activeCount[a] != activeCount[b]) return activeCount[a] < activeCount[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    // Check if any active candidate remains for every shape; if not, something went wrong\n    bool allShapesHaveCandidates() const {\n        for (int k = 0; k < M; ++k) if (activeCount[k] <= 0) return false;\n        return true;\n    }\n\n    struct DFSContext {\n        State* st;\n        vector<int> order; // shape order\n        vector<int> cur; // current sums at drilled cells, size D\n        vector<int> assign; // chosen shift index per shape (or -1)\n        int solutionsLimit;\n        int solutionsFound;\n        vector<int> lastAssignment;\n        vector<int> unionCounts; // size N*N; count of solutions covering each cell\n        bool respectTime;\n        int targetCell; // -1 no target\n        int requireCovered; // -1 none, 0 force uncovered, 1 force covered\n        bool coveredYet; // for target requireCovered=1\n        vector<int> canCoverRemain; // prefix: for pruning target coverage\n        // cache pointers for speed\n        vector<vector<vector<int>>> *coverDrilledCachePtr;\n        vector<vector<int>> *anyCoverKDPtr;\n        vector<vector<int>> *mustCoverKDPtr;\n        vector<int> *sumAnyDPtr;\n        vector<int> *sumMustDPtr;\n\n        DFSContext(State* st_, const vector<int>& order_, int solLim, bool respectTime_,\n                   int targetCell_ = -1, int requireCovered_ = -1)\n            : st(st_), order(order_), solutionsLimit(solLim), solutionsFound(0),\n              respectTime(respectTime_), targetCell(targetCell_), requireCovered(requireCovered_) {\n            int D = (int)st->drilledCells.size();\n            cur.assign(D, 0);\n            assign.assign(st->M, -1);\n            lastAssignment.assign(st->M, -1);\n            unionCounts.assign(st->N*st->N, 0);\n            coveredYet = false;\n            canCoverRemain.assign(st->M+1, 0); // we'll compute cumulative suffix later if needed\n            coverDrilledCachePtr = &st->coverDrilledCache;\n            anyCoverKDPtr = &st->anyCoverKD;\n            mustCoverKDPtr = &st->mustCoverKD;\n            sumAnyDPtr = &st->sumAnyD;\n            sumMustDPtr = &st->sumMustD;\n        }\n\n        bool canShapeCoverTarget(int k) const {\n            if (targetCell < 0) return false;\n            const auto& list = st->prob->shapes[k].coverShiftsByCell[targetCell];\n            for (int p : list) if (st->active[k][p]) return true;\n            return false;\n        }\n\n        // Prepare suffix counts of shapes that can potentially cover target cell\n        void prepareCoverRemain() {\n            if (requireCovered != 1 || targetCell < 0) return;\n            vector<int> seq = order;\n            int m = st->M;\n            canCoverRemain.assign(m+1, 0);\n            for (int pos = m-1; pos >= 0; --pos) {\n                int k = seq[pos];\n                int add = canShapeCoverTarget(k) ? 1 : 0;\n                canCoverRemain[pos] = canCoverRemain[pos+1] + add;\n            }\n        }\n\n        // Build union and record a solution\n        void recordSolution() {\n            // Build union from assignments\n            vector<uint8_t> covered(st->N*st->N, 0);\n            for (int pos = 0; pos < st->M; ++pos) {\n                int k = order[pos];\n                int p = assign[k];\n                if (p < 0) return; // shouldn't happen\n                const vector<int>& cells = st->prob->shapes[k].shiftsCells[p];\n                for (int c : cells) covered[c] = 1;\n            }\n            for (int c = 0; c < st->N*st->N; ++c) if (covered[c]) ++unionCounts[c];\n            lastAssignment = assign;\n            ++solutionsFound;\n        }\n\n        // Viability check for choosing shape k shift p\n        bool viableChoice(int k, int p) {\n            // For requireCovered=0 (force uncovered), disallow shifts that cover target cell\n            if (requireCovered == 0 && targetCell >= 0) {\n                // check if this shift covers target cell\n                const vector<int>& cells = st->prob->shapes[k].shiftsCells[p];\n                // quick: iterate cells\n                for (int c : cells) if (c == targetCell) return false;\n            }\n\n            // For requireCovered=1, we will prune later if impossible to cover target\n\n            const vector<vector<int>>& anyCoverKD = *anyCoverKDPtr;\n            const vector<vector<int>>& mustCoverKD = *mustCoverKDPtr;\n            const vector<int>& sumAnyD = *sumAnyDPtr;\n            const vector<int>& sumMustD = *sumMustDPtr;\n            const vector<int>& vDrilled = st->vDrilled;\n            const vector<int>& cur = this->cur;\n\n            const vector<int>& coverD = (*coverDrilledCachePtr)[k][p];\n            int D = (int)st->drilledCells.size();\n\n            // We'll scan d=0..D-1 and see if rem' within [lb_excl, ub_excl]\n            int ptr = 0;\n            for (int d = 0; d < D; ++d) {\n                int cover = 0;\n                if (ptr < (int)coverD.size() && coverD[ptr] == d) { cover = 1; ++ptr; }\n                int remp = vDrilled[d] - (cur[d] + cover);\n                if (remp < 0) return false;\n                int ub_excl = sumAnyD[d] - anyCoverKD[k][d];\n                int lb_excl = sumMustD[d] - mustCoverKD[k][d];\n                if (remp < lb_excl) return false;\n                if (remp > ub_excl) return false;\n            }\n            return true;\n        }\n\n        void dfs(int pos) {\n            if (solutionsFound >= solutionsLimit) return;\n            if (respectTime && st->timer.elapsed() > st->timeLimitSec) return;\n            if (pos == st->M) {\n                // Target constraint check for requireCovered=1\n                if (requireCovered == 1 && targetCell >= 0) {\n                    // ensure at least one chosen shift covers target\n                    bool cov = false;\n                    for (int k = 0; k < st->M && !cov; ++k) {\n                        int kk = order[k];\n                        int p = assign[kk];\n                        if (p < 0) continue;\n                        const vector<int>& cells = st->prob->shapes[kk].shiftsCells[p];\n                        for (int c : cells) { if (c == targetCell) { cov = true; break; } }\n                    }\n                    if (!cov) return;\n                }\n                // Valid solution\n                recordSolution();\n                return;\n            }\n            int k = order[pos];\n\n            // If requireCovered==1 and target not yet covered: prune if no remaining shapes can cover it\n            if (requireCovered == 1 && targetCell >= 0) {\n                bool coveredNow = false;\n                // check coveredYet quickly by partial assignment\n                for (int t = 0; t < pos; ++t) {\n                    int kk = order[t];\n                    int psel = assign[kk];\n                    if (psel < 0) continue;\n                    const vector<int>& cells = st->prob->shapes[kk].shiftsCells[psel];\n                    for (int c : cells) if (c == targetCell) { coveredNow = true; break; }\n                    if (coveredNow) break;\n                }\n                if (!coveredNow) {\n                    int remCoverable = 0;\n                    for (int t = pos; t < st->M; ++t) {\n                        int kk = order[t];\n                        const auto& list = st->prob->shapes[kk].coverShiftsByCell[targetCell];\n                        bool ok = false;\n                        for (int p : list) if (st->active[kk][p]) { ok = true; break; }\n                        if (ok) ++remCoverable;\n                    }\n                    if (remCoverable == 0) return;\n                }\n            }\n\n            // Enumerate candidate shifts for shape k with simple ordering:\n            // Prefer shifts that influence drilled cells tightly; but we keep natural order\n            const int Pk = (int)st->prob->shapes[k].shiftsCells.size();\n\n            // Heuristic: try shifts that do/don't cover target first to reach target satisfaction quickly\n            vector<int> candidates;\n            candidates.reserve(st->activeCount[k]);\n            if (requireCovered == 1 && targetCell >= 0) {\n                // try those that cover target first\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) {\n                    const vector<int>& cells = st->prob->shapes[k].shiftsCells[p];\n                    bool cov = false;\n                    for (int c : cells) { if (c == targetCell) { cov = true; break; } }\n                    if (cov) candidates.push_back(p);\n                }\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) {\n                    const vector<int>& cells = st->prob->shapes[k].shiftsCells[p];\n                    bool cov = false;\n                    for (int c : cells) { if (c == targetCell) { cov = true; break; } }\n                    if (!cov) candidates.push_back(p);\n                }\n            } else {\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) candidates.push_back(p);\n            }\n\n            for (int p : candidates) {\n                if (!viableChoice(k, p)) continue;\n                // Choose\n                assign[k] = p;\n                // Update cur\n                const vector<int>& coverD = (*coverDrilledCachePtr)[k][p];\n                for (int d : coverD) ++cur[d];\n                dfs(pos+1);\n                for (int d : coverD) --cur[d];\n                assign[k] = -1;\n                if (solutionsFound >= solutionsLimit) return;\n                if (respectTime && st->timer.elapsed() > st->timeLimitSec) return;\n            }\n        }\n    };\n\n    // Enumerate up to L solutions (time limited) to collect union counts and one assignment\n    void enumerateSolutionsLimited(int L, vector<int>& oneAssignOut, vector<int>& unionCountsOut, int& found) {\n        recomputeCoverageBounds();\n        buildCoverDrilledCache();\n        vector<int> order = chooseOrder();\n        DFSContext ctx(this, order, L, true);\n        ctx.prepareCoverRemain();\n        ctx.dfs(0);\n        found = ctx.solutionsFound;\n        oneAssignOut = ctx.lastAssignment;\n        unionCountsOut = ctx.unionCounts;\n    }\n\n    // Forced alternative existence for target cell c; wantStatus: 0 force uncovered, 1 force covered\n    bool existsAlternativeForCell(int c, int wantStatus) {\n        // Quick contradictions with drilled known:\n        if (known[c] == 0 && wantStatus == 1) return false;\n        if (known[c] > 0 && wantStatus == 0) return false;\n\n        recomputeCoverageBounds();\n        buildCoverDrilledCache();\n\n        // Quick pre-check: if wantStatus==1 and no shape can possibly cover c with active candidates, impossible\n        bool anyShapeCanCover = false;\n        for (int k = 0; k < M; ++k) {\n            const auto& list = prob->shapes[k].coverShiftsByCell[c];\n            bool ok = false;\n            for (int p : list) if (active[k][p]) { ok = true; break; }\n            if (ok) { anyShapeCanCover = true; break; }\n        }\n        if (wantStatus == 1 && !anyShapeCanCover) return false;\n\n        // For wantStatus==0, if there exists a shape for which all active candidates cover c (mustCover), then impossible\n        for (int k = 0; k < M; ++k) {\n            const auto& list = prob->shapes[k].coverShiftsByCell[c];\n            int coverCount = 0;\n            for (int p : list) if (active[k][p]) ++coverCount;\n            if (activeCount[k] > 0 && coverCount == activeCount[k]) { // must cover\n                if (wantStatus == 0) return false;\n            }\n        }\n\n        int L = 1; // only need to know if at least one alternative exists\n        int requireCovered = (wantStatus == 1) ? 1 : 0;\n        vector<int> order = chooseOrder(c, requireCovered);\n        DFSContext ctx(this, order, L, true, c, requireCovered);\n        ctx.prepareCoverRemain();\n        ctx.dfs(0);\n        return ctx.solutionsFound >= 1;\n    }\n\n    // Build union set from an assignment (shift indices per shape)\n    vector<uint8_t> buildUnionFromAssignment(const vector<int>& assign) {\n        vector<uint8_t> covered(N*N, 0);\n        for (int k = 0; k < M; ++k) {\n            int p = assign[k];\n            if (p < 0) continue;\n            const vector<int>& cells = prob->shapes[k].shiftsCells[p];\n            for (int c : cells) covered[c] = 1;\n        }\n        return covered;\n    }\n\n    // Attempt to resolve union and drill ambiguous cells until unique\n    vector<uint8_t> solveUnion() {\n        // Initial coarse drilling: grid sampling\n        int step = (N >= 18 ? 4 : (N >= 14 ? 3 : 3));\n        for (int i = 0; i < N; i += step) {\n            for (int j = 0; j < N; j += step) {\n                if (opCount >= opLimit) break;\n                int c = cell_id(i, j, N);\n                if (known[c] == -1) {\n                    drill_cell(c);\n                }\n            }\n        }\n\n        // Ensure feasibility\n        if (!allShapesHaveCandidates()) {\n            // Should not happen often; fallback: drill all\n            for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) {\n                int c = cell_id(i,j,N);\n                if (known[c] == -1) drill_cell(c);\n            }\n        }\n\n        vector<int> oneAssign, unionCounts;\n        int found = 0;\n\n        while (true) {\n            if (opCount >= opLimit - 1) break; // reserve for answer\n            if (timer.elapsed() > timeLimitSec) break;\n\n            // Enumerate a limited set of solutions\n            enumerateSolutionsLimited(100, oneAssign, unionCounts, found);\n\n            if (found == 0) {\n                // No feasible solutions found within limit/time; drill a random cell to get more info\n                // Choose a cell not drilled with small chance of being covered (heuristic: minimal sum of potential coverage)\n                vector<int> candidateCells;\n                for (int c = 0; c < N*N; ++c) if (known[c] == -1) candidateCells.push_back(c);\n                if (candidateCells.empty()) break;\n                int bestC = candidateCells[rng() % candidateCells.size()];\n                // Simple heuristic: choose random if time low\n                drill_cell(bestC);\n                continue;\n            }\n\n            // Build best union from oneAssign\n            vector<uint8_t> baseUnion = buildUnionFromAssignment(oneAssign);\n\n            // Fast acceptance check: if unionCounts show unanimity across found solutions\n            bool unanimous = true;\n            for (int c = 0; c < N*N; ++c) {\n                if (known[c] == 0 && baseUnion[c] != 0) { unanimous = false; break; }\n                if (known[c] > 0 && baseUnion[c] != 1) { unanimous = false; break; }\n                if (unionCounts[c] != 0 && unionCounts[c] != found) {\n                    unanimous = false;\n                    break;\n                }\n            }\n            // Even if unanimity among sampled solutions, we still need a rigorous uniqueness check.\n            // Try to find any cell whose union can be flipped by a full DFS with target constraint.\n            int ambiguousCell = -1;\n            // We'll prioritize cells with unknown and near 50-50 in unionCounts; else scan all\n            vector<pair<int,int>> candidates; // (priority score, cell)\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) {\n                int cnt = unionCounts[c];\n                int score = found ? abs(found - 2*cnt) : 0; // lower score -> more ambiguous\n                candidates.emplace_back(score, c);\n            }\n            sort(candidates.begin(), candidates.end(),\n                 [&](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            bool alternativeFound = false;\n            // First try top-K ambiguous cells by sample (speed), then fallback to all unknown cells if needed\n            int K = min<int>(50, (int)candidates.size());\n            for (int idx = 0; idx < K; ++idx) {\n                int c = candidates[idx].second;\n                int want = baseUnion[c] ? 0 : 1;\n                if (existsAlternativeForCell(c, want)) {\n                    ambiguousCell = c;\n                    alternativeFound = true;\n                    break;\n                }\n                if (timer.elapsed() > timeLimitSec) break;\n            }\n            if (!alternativeFound) {\n                // Rigorous sweep over all unknown cells if time allows\n                for (int c = 0; c < N*N && !alternativeFound; ++c) {\n                    if (known[c] != -1) continue;\n                    int want = baseUnion[c] ? 0 : 1;\n                    if (existsAlternativeForCell(c, want)) {\n                        ambiguousCell = c;\n                        alternativeFound = true;\n                        break;\n                    }\n                    if (timer.elapsed() > timeLimitSec) break;\n                }\n            }\n\n            if (!alternativeFound) {\n                // Union is unique under current constraints\n                return baseUnion;\n            } else {\n                // Drill the ambiguous cell to disambiguate\n                drill_cell(ambiguousCell);\n                // loop continues\n            }\n        }\n\n        // Fallback: if time or ops budget low, drill remaining cells to guarantee correctness\n        for (int c = 0; c < N*N; ++c) {\n            if (opCount >= opLimit - 1) break;\n            if (known[c] == -1) drill_cell(c);\n        }\n        // Now union is simply v>0\n        vector<uint8_t> unionFinal(N*N, 0);\n        for (int c = 0; c < N*N; ++c) {\n            unionFinal[c] = (known[c] > 0) ? 1 : 0;\n        }\n        return unionFinal;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem prob;\n    if (!(cin >> prob.N >> prob.M >> prob.eps)) {\n        return 0;\n    }\n    prob.shapes.resize(prob.M);\n    for (int k = 0; k < prob.M; ++k) {\n        prob.shapes[k].id = k;\n        int d; cin >> d;\n        vector<pair<int,int>> offs;\n        offs.reserve(d);\n        int minI = INT_MAX, minJ = INT_MAX, maxI = INT_MIN, maxJ = INT_MIN;\n        for (int t = 0; t < d; ++t) {\n            int ii, jj; cin >> ii >> jj;\n            offs.emplace_back(ii, jj);\n            minI = min(minI, ii);\n            minJ = min(minJ, jj);\n            maxI = max(maxI, ii);\n            maxJ = max(maxJ, jj);\n        }\n        // Normalize offsets to start at 0? Already specified that min is 0, but ensure\n        for (auto &p : offs) {\n            p.first -= minI;\n            p.second -= minJ;\n        }\n        prob.shapes[k].offsets = offs;\n        prob.shapes[k].H = maxI - minI + 1;\n        prob.shapes[k].W = maxJ - minJ + 1;\n    }\n\n    // Precompute shifts for each shape and which cells they cover\n    for (int k = 0; k < prob.M; ++k) {\n        auto &S = prob.shapes[k];\n        int maxDI = prob.N - S.H;\n        int maxDJ = prob.N - S.W;\n        for (int di = 0; di <= maxDI; ++di) {\n            for (int dj = 0; dj <= maxDJ; ++dj) {\n                vector<int> cells;\n                cells.reserve(S.offsets.size());\n                for (auto [oi, oj] : S.offsets) {\n                    int i = di + oi;\n                    int j = dj + oj;\n                    cells.push_back(cell_id(i,j, prob.N));\n                }\n                sort(cells.begin(), cells.end());\n                S.shiftsCells.push_back(move(cells));\n            }\n        }\n        // Build coverShiftsByCell mapping\n        S.coverShiftsByCell.assign(prob.N*prob.N, {});\n        for (int p = 0; p < (int)S.shiftsCells.size(); ++p) {\n            for (int c : S.shiftsCells[p]) {\n                S.coverShiftsByCell[c].push_back(p);\n            }\n        }\n    }\n\n    State st(&prob);\n\n    // Solve union using the strategy\n    vector<uint8_t> unionSet = st.solveUnion();\n\n    // Build answer: cells with unionSet[c] == 1\n    vector<int> ans;\n    ans.reserve(st.N*st.N);\n    for (int c = 0; c < st.N*st.N; ++c) {\n        if (unionSet[c]) ans.push_back(c);\n    }\n\n    // Ensure inclusion of all drilled with v>0\n    for (int idx = 0; idx < (int)st.drilledCells.size(); ++idx) {\n        int c = st.drilledCells[idx];\n        if (st.known[c] > 0 && !unionSet[c]) {\n            // Force include it\n            ans.push_back(c);\n            unionSet[c] = 1;\n        }\n    }\n    // Deduplicate ans (if forced adds duplicates)\n    sort(ans.begin(), ans.end());\n    ans.erase(unique(ans.begin(), ans.end()), ans.end());\n\n    // Output answer\n    cout << \"a \" << ans.size();\n    for (int c : ans) {\n        auto [i,j] = cell_ij(c, st.N);\n        cout << \" \" << i << \" \" << j;\n    }\n    cout << \"\\n\";\n    cout.flush();\n    string resp;\n    if (!(cin >> resp)) return 0;\n    // If incorrect, we could try again, but we trust the method; end here.\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Node {\n    long long g;\n    int i;\n    int k; // current k at the time of insertion\n    bool operator<(const Node& other) const {\n        if (g != other.g) return g < other.g; // max-heap by g\n        return i < other.i;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int W, D, N;\n    if (!(cin >> W >> D >> N)) return 0;\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    // For rank i, A_i[d] = a[d][i] (inputs are already sorted per day).\n    // Precompute S_i[k] = sum_d max(0, A_i[d] - k*W), for k=0..W.\n    vector<vector<long long>> S(N, vector<long long>(W + 1, 0));\n    for (int i = 0; i < N; i++) {\n        for (int k = 0; k <= W; k++) {\n            long long sum = 0;\n            long long base = 1LL * k * W;\n            for (int d = 0; d < D; d++) {\n                long long rem = 1LL * a[d][i] - base;\n                if (rem > 0) sum += rem;\n            }\n            S[i][k] = sum;\n        }\n    }\n    auto gain = [&](int i, int k) -> long long {\n        // improvement if we increase k -> k+1 (i.e., add W area)\n        if (k >= W) return 0;\n        return S[i][k] - S[i][k + 1];\n    };\n\n    // Greedy allocate heights: k_i >= 1, sum k_i = W\n    vector<int> k(N, 1);\n    int R = W - N;\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; i++) {\n        pq.push(Node{gain(i, k[i]), i, k[i]});\n    }\n    while (R > 0 && !pq.empty()) {\n        Node cur = pq.top(); pq.pop();\n        if (cur.k != k[cur.i]) continue; // outdated\n        if (k[cur.i] >= W) continue;\n        if (cur.g <= 0) break; // no further gain possible\n        // allocate one unit of height to index i\n        k[cur.i]++;\n        R--;\n        if (k[cur.i] < W) {\n            pq.push(Node{gain(cur.i, k[cur.i]), cur.i, k[cur.i]});\n        }\n    }\n    // If still remaining (all gains zero), just dump the rest to the last index\n    while (R > 0) {\n        k[N - 1]++;\n        R--;\n    }\n\n    // Sort k to get nondecreasing capacities vector (we'll build stripes in this order)\n    sort(k.begin(), k.end()); // k[i] are heights in rows\n\n    // Local search to refine under monotonic constraints using precomputed S\n    // K[i] in [1..W], sum K[i] = W\n    vector<int> K = k;\n    auto canDown = [&](int i) -> bool {\n        if (i < 0 || i >= N) return false;\n        if (K[i] <= 1) return false;\n        if (i == 0) return K[i] - 1 >= 1;\n        return K[i] - 1 >= K[i - 1];\n    };\n    auto canUp = [&](int j) -> bool {\n        if (j < 0 || j >= N) return false;\n        if (K[j] >= W) return false; // cannot exceed total height\n        if (j == N - 1) return true;\n        return (K[j] + 1 <= K[j + 1]);\n    };\n    auto dDown = [&](int i) -> long long {\n        // Cost change for decreasing K[i] by 1: S[i][K[i]-1] - S[i][K[i]]\n        return S[i][K[i] - 1] - S[i][K[i]];\n    };\n    auto dUp = [&](int j) -> long long {\n        // Cost change for increasing K[j] by 1: S[j][K[j] + 1] - S[j][K[j]]\n        return S[j][K[j] + 1] - S[j][K[j]];\n    };\n\n    const auto start_time = chrono::steady_clock::now();\n    const double TIME_LIMIT = 2.8; // seconds\n    int iter = 0;\n    while (true) {\n        iter++;\n        // time guard\n        if (iter % 50 == 0) {\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - start_time).count();\n            if (elapsed > TIME_LIMIT) break;\n        }\n        // Build allowed sets and their best two candidates\n        long long INF = (1LL<<60);\n        long long bestDD1 = INF, bestDD2 = INF;\n        int idxDD1 = -1, idxDD2 = -1;\n        for (int i = 0; i < N; i++) {\n            if (!canDown(i)) continue;\n            long long val = dDown(i);\n            if (val < bestDD1) {\n                bestDD2 = bestDD1; idxDD2 = idxDD1;\n                bestDD1 = val; idxDD1 = i;\n            } else if (val < bestDD2) {\n                bestDD2 = val; idxDD2 = i;\n            }\n        }\n        long long bestDU1 = INF, bestDU2 = INF;\n        int idxDU1 = -1, idxDU2 = -1;\n        for (int j = 0; j < N; j++) {\n            if (!canUp(j)) continue;\n            long long val = dUp(j);\n            if (val < bestDU1) {\n                bestDU2 = bestDU1; idxDU2 = idxDU1;\n                bestDU1 = val; idxDU1 = j;\n            } else if (val < bestDU2) {\n                bestDU2 = val; idxDU2 = j;\n            }\n        }\n        if (idxDD1 == -1 || idxDU1 == -1) break; // no feasible moves\n        // Choose best pair (i, j) with i != j minimizing dDown[i] + dUp[j]\n        long long bestDelta = INF;\n        int bestI = -1, bestJ = -1;\n        if (idxDD1 != idxDU1) {\n            bestDelta = bestDD1 + bestDU1;\n            bestI = idxDD1; bestJ = idxDU1;\n        } else {\n            // Need second best from either side\n            if (idxDU2 != -1) {\n                long long delta = bestDD1 + bestDU2;\n                if (delta < bestDelta) {\n                    bestDelta = delta; bestI = idxDD1; bestJ = idxDU2;\n                }\n            }\n            if (idxDD2 != -1) {\n                long long delta = bestDD2 + bestDU1;\n                if (delta < bestDelta) {\n                    bestDelta = delta; bestI = idxDD2; bestJ = idxDU1;\n                }\n            }\n        }\n        if (bestI == -1 || bestJ == -1) break;\n        if (bestDelta >= 0) break; // no improving move\n        // Apply the move\n        K[bestI] -= 1;\n        K[bestJ] += 1;\n        // Continue\n    }\n\n    // Construct rectangles: horizontal stripes across full width, in nondecreasing K order\n    // Height in grid units is K[i], sum to W\n    vector<array<int,4>> rect(N);\n    int cur_i = 0;\n    for (int i = 0; i < N; i++) {\n        int h = K[i];\n        int i0 = cur_i;\n        int i1 = cur_i + h;\n        int j0 = 0, j1 = W;\n        rect[i] = {i0, j0, i1, j1};\n        cur_i = i1;\n    }\n    // Safety: ensure cur_i == W\n    if (cur_i != W) {\n        // In rare pathological cases due to unexpected numeric issues, adjust last rectangle\n        rect.back()[2] += (W - cur_i);\n    }\n\n    // Output: same rectangles for all days; k-th reservation gets k-th rectangle (demands are sorted)\n    for (int d = 0; d < D; d++) {\n        for (int kidx = 0; kidx < N; kidx++) {\n            auto &r = rect[kidx];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << '\\n';\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic const ll MOD = 998244353LL;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    if (!(cin >> N >> M >> K)) return 0;\n\n    const int SZ = N * N; // 81\n    vector<ll> r(SZ);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            ll x; cin >> x;\n            r[i * N + j] = x; // already in [0, MOD-1]\n        }\n    }\n\n    // Read M stamps, each 3x3\n    // Flatten each stamp as array of 9 values (row-major 3x3)\n    vector<array<int, 9>> stamp(M);\n    for (int m = 0; m < M; ++m) {\n        for (int u = 0; u < 3; ++u) {\n            for (int v = 0; v < 3; ++v) {\n                int x; cin >> x;\n                stamp[m][u * 3 + v] = x;\n            }\n        }\n    }\n\n    const int P = N - 2;           // 7 positions per dimension\n    const int POS_CNT = P * P;     // 49\n    const int OPS = M * POS_CNT;   // 980\n\n    // Mapping pos index <-> (p,q)\n    vector<int> pos_p(POS_CNT), pos_q(POS_CNT);\n    for (int p = 0, idx = 0; p < P; ++p) {\n        for (int q = 0; q < P; ++q, ++idx) {\n            pos_p[idx] = p;\n            pos_q[idx] = q;\n        }\n    }\n\n    // Precompute operations: for each op, store cells (size 9) and s values (size 9)\n    vector<array<int, 9>> op_cells(OPS);\n    vector<array<int, 9>> op_svals(OPS);\n    vector<int> op_m(OPS), op_p(OPS), op_q(OPS);\n\n    for (int m = 0; m < M; ++m) {\n        for (int pos = 0; pos < POS_CNT; ++pos) {\n            int p = pos_p[pos], q = pos_q[pos];\n            int op = m * POS_CNT + pos;\n            op_m[op] = m;\n            op_p[op] = p;\n            op_q[op] = q;\n            for (int u = 0; u < 3; ++u) {\n                for (int v = 0; v < 3; ++v) {\n                    int k = u * 3 + v;\n                    int i = p + u, j = q + v;\n                    int cell = i * N + j; // 0..80\n                    op_cells[op][k] = cell;\n                    op_svals[op][k] = stamp[m][k];\n                }\n            }\n        }\n    }\n\n    // Precompute overlap operations list for each op:\n    // op1(m,p,q) overlaps any op2(m2, p2,q2) where |p2-p|<=2 and |q2-q|<=2\n    vector<vector<int>> overlOps(OPS);\n    overlOps.assign(OPS, {});\n    for (int op = 0; op < OPS; ++op) {\n        int m = op_m[op];\n        int p = op_p[op];\n        int q = op_q[op];\n        (void)m; // m unused here\n        for (int dp = -2; dp <= 2; ++dp) {\n            int p2 = p + dp;\n            if (p2 < 0 || p2 >= P) continue;\n            for (int dq = -2; dq <= 2; ++dq) {\n                int q2 = q + dq;\n                if (q2 < 0 || q2 >= P) continue;\n                int pos2 = p2 * P + q2;\n                for (int m2 = 0; m2 < M; ++m2) {\n                    int op2 = m2 * POS_CNT + pos2;\n                    overlOps[op].push_back(op2);\n                }\n            }\n        }\n    }\n\n    auto cell_gain = [&](ll rcur, int sval)->ll {\n        // Incremental gain for adding sval to a cell with current remainder rcur\n        // If sval >= MOD - rcur => wrap occurs => delta = sval - MOD, else delta = sval\n        // All values non-negative and <= MOD-1\n        return ( (ll)sval >= (MOD - rcur) ) ? ( (ll)sval - MOD ) : (ll)sval;\n    };\n\n    // Compute all op gains from scratch for current r\n    vector<ll> gain(OPS, 0);\n    auto recompute_all_gains = [&](){\n        for (int op = 0; op < OPS; ++op) {\n            ll sum = 0;\n            for (int k = 0; k < 9; ++k) {\n                int c = op_cells[op][k];\n                int sval = op_svals[op][k];\n                sum += cell_gain(r[c], sval);\n            }\n            gain[op] = sum;\n        }\n    };\n\n    recompute_all_gains();\n\n    // Two-step lookahead selection\n    const int T = 64; // number of top candidates to consider for 2-step lookahead\n\n    // For marking overlaps and changed cell remainders efficiently\n    vector<int> overlapMark(OPS, 0);\n    int overlapTag = 1;\n\n    vector<ll> tmpR(SZ, 0);\n    vector<int> tmpRMark(SZ, 0);\n    int tmpRTag = 1;\n\n    vector<tuple<int,int,int>> answer; // (m,p,q)\n\n    for (int step = 0; step < K; ++step) {\n        // Collect positive-gain operations\n        vector<pair<ll,int>> cand; cand.reserve(OPS);\n        for (int op = 0; op < OPS; ++op) {\n            if (gain[op] > 0) cand.emplace_back(gain[op], op);\n        }\n        if (cand.empty()) break;\n\n        // Sort descending by immediate gain\n        sort(cand.begin(), cand.end(), [&](const auto& a, const auto& b){\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        int take = min((int)cand.size(), T);\n\n        ll bestCombined = LLONG_MIN;\n        ll bestG1 = LLONG_MIN;\n        int bestOp = -1;\n\n        for (int idx = 0; idx < take; ++idx) {\n            int op1 = cand[idx].second;\n            ll g1 = cand[idx].first;\n\n            // Mark overlapped operations\n            ++overlapTag;\n            for (int t : overlOps[op1]) overlapMark[t] = overlapTag;\n\n            // Best unaffected op2 (base gains)\n            ll bestUn = 0; // we can choose to do nothing as second move\n            for (int j = 0; j < OPS; ++j) {\n                if (overlapMark[j] != overlapTag) {\n                    if (gain[j] > bestUn) bestUn = gain[j];\n                }\n            }\n\n            // Prepare hypothetical new remainders for op1's 9 cells\n            ++tmpRTag;\n            for (int k = 0; k < 9; ++k) {\n                int c = op_cells[op1][k];\n                int sval = op_svals[op1][k];\n                ll nr = r[c] + (ll)sval;\n                if (nr >= MOD) nr -= MOD;\n                tmpR[c] = nr;\n                tmpRMark[c] = tmpRTag;\n            }\n\n            // Best overlapped updated gain\n            ll bestOv = LLONG_MIN;\n            for (int t : overlOps[op1]) {\n                ll sum = 0;\n                // recompute op t gain under r'\n                for (int k = 0; k < 9; ++k) {\n                    int c2 = op_cells[t][k];\n                    ll rr = (tmpRMark[c2] == tmpRTag) ? tmpR[c2] : r[c2];\n                    int s2 = op_svals[t][k];\n                    sum += ((ll)s2 >= (MOD - rr)) ? ((ll)s2 - MOD) : (ll)s2;\n                }\n                if (sum > bestOv) bestOv = sum;\n            }\n\n            ll best2 = bestUn;\n            if (bestOv > best2) best2 = bestOv;\n            // ensure second step not negative\n            if (best2 < 0) best2 = 0;\n\n            ll combined = g1 + best2;\n\n            // Choose the op with highest combined; tie-break on larger g1\n            if (combined > bestCombined || (combined == bestCombined && g1 > bestG1)) {\n                bestCombined = combined;\n                bestG1 = g1;\n                bestOp = op1;\n            }\n        }\n\n        if (bestOp == -1) break; // no positive immediate gain found (shouldn't happen due to cand non-empty)\n        if (bestG1 <= 0) break;   // safety\n\n        // Apply bestOp\n        int msel = op_m[bestOp];\n        int psel = op_p[bestOp];\n        int qsel = op_q[bestOp];\n        answer.emplace_back(msel, psel, qsel);\n\n        for (int k = 0; k < 9; ++k) {\n            int c = op_cells[bestOp][k];\n            int sval = op_svals[bestOp][k];\n            ll nr = r[c] + (ll)sval;\n            if (nr >= MOD) nr -= MOD;\n            r[c] = nr;\n        }\n\n        // Recompute all gains from scratch for simplicity\n        recompute_all_gains();\n    }\n\n    // Output\n    cout << (int)answer.size() << '\\n';\n    for (auto &t : answer) {\n        int m, p, q;\n        tie(m, p, q) = t;\n        cout << m << ' ' << p << ' ' << q << '\\n';\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Simulator {\n    static constexpr int N = 5;\n    static constexpr int TOT = N*N;\n\n    // Input\n    int A[N][N];\n\n    // Precomputed: source row and index for each container id\n    int srcRow[TOT], srcIdx[TOT];\n    int dstRow[TOT];\n\n    // Grid: container id or -1 if empty\n    int occ[N][N];\n\n    // Spawn pointers per receiving row\n    int spawnIdx[N];\n\n    // Delivered flags per container id\n    bool delivered[TOT];\n\n    // Big crane state\n    int br = 0, bc = 0; // position\n    int hold = -1;      // held container id or -1\n\n    // Deposit target (interior cell), and forced-delivery flag\n    bool hasDepositTarget = false;\n    int dep_r = -1, dep_c = -1;\n    bool forceDeliverActive = false;\n\n    // Next target id (smallest not yet delivered)\n    int nextID = 0;\n    int deliveredCount = 0;\n\n    // Output strings\n    vector<string> S;\n\n    Simulator() {\n        memset(occ, -1, sizeof(occ));\n        memset(spawnIdx, 0, sizeof(spawnIdx));\n        memset(delivered, 0, sizeof(delivered));\n        S.assign(N, \"\");\n    }\n\n    void readInput() {\n        int n;\n        if (!(cin >> n)) exit(0);\n        // n will be 5\n        for (int i=0;i<N;i++){\n            for (int j=0;j<N;j++){\n                cin >> A[i][j];\n            }\n        }\n        // Precompute srcRow and srcIdx\n        for (int i=0;i<N;i++){\n            for (int j=0;j<N;j++){\n                int id = A[i][j];\n                srcRow[id] = i;\n                srcIdx[id] = j;\n            }\n        }\n        for (int id=0; id<TOT; id++){\n            dstRow[id] = id / N;\n        }\n    }\n\n    // Step 1: spawn containers at receiving gates if possible\n    void step1_spawn() {\n        for (int i=0;i<N;i++){\n            if (spawnIdx[i] >= N) continue; // no more to spawn\n            // can spawn if no container at (i,0) AND either no crane holding on that cell\n            // Only big crane remains; small cranes are bombed after first turn.\n            // If the big crane is at (i,0) and holding a container, spawning is blocked.\n            if (occ[i][0] == -1) {\n                if (!(br == i && bc == 0 && hold != -1)) {\n                    int id = A[i][spawnIdx[i]];\n                    occ[i][0] = id;\n                    spawnIdx[i]++;\n                }\n            }\n        }\n    }\n\n    // Step 2: apply big crane action and small cranes' B/dots (we only simulate big)\n    void applyBigAction(char act) {\n        if (act=='U') { br--; }\n        else if (act=='D') { br++; }\n        else if (act=='L') { bc--; }\n        else if (act=='R') { bc++; }\n        else if (act=='P') {\n            // Pick\n            if (hold != -1) {\n                // invalid in production: but we avoid generating invalid\n                // cerr << \"Invalid P: already holding\\n\";\n            } else {\n                if (occ[br][bc] == -1) {\n                    // cerr << \"Invalid P: no container\\n\";\n                } else {\n                    hold = occ[br][bc];\n                    occ[br][bc] = -1;\n                }\n            }\n        }\n        else if (act=='Q') {\n            // Drop\n            if (hold == -1) {\n                // cerr << \"Invalid Q: not holding\\n\";\n            } else {\n                if (occ[br][bc] != -1) {\n                    // cerr << \"Invalid Q: cell occupied\\n\";\n                } else {\n                    occ[br][bc] = hold;\n                    hold = -1;\n                    hasDepositTarget = false;\n                    forceDeliverActive = false;\n                }\n            }\n        }\n        // '.' or 'B' not used for big\n    }\n\n    // Step 3: dispatch containers at (i,4)\n    void step3_dispatch() {\n        for (int i=0;i<N;i++){\n            if (occ[i][4] != -1) {\n                int id = occ[i][4];\n                occ[i][4] = -1;\n                if (!delivered[id]) {\n                    delivered[id] = true;\n                    deliveredCount++;\n                }\n            }\n        }\n        while (nextID < TOT && delivered[nextID]) nextID++;\n    }\n\n    // Manhattan step towards target\n    char stepToward(int tr, int tc) {\n        if (br < tr) return 'D';\n        if (br > tr) return 'U';\n        if (bc < tc) return 'R';\n        if (bc > tc) return 'L';\n        return '.'; // already there\n    }\n\n    // Find nearest empty interior cell (columns 1..3). Return true if found and set (r,c).\n    bool findNearestEmptyInterior(int &r, int &c, int from_r, int from_c) {\n        int bestD = INT_MAX;\n        int bestR = -1, bestC = -1;\n        for (int i=0;i<N;i++){\n            for (int j=1;j<=3;j++){\n                if (occ[i][j] == -1) {\n                    int d = abs(i - from_r) + abs(j - from_c);\n                    if (d < bestD || (d == bestD && (i<bestR || (i==bestR && j<bestC)))) {\n                        bestD = d;\n                        bestR = i;\n                        bestC = j;\n                    }\n                }\n            }\n        }\n        if (bestD == INT_MAX) return false;\n        r = bestR; c = bestC;\n        return true;\n    }\n\n    // Decide big crane's action this turn\n    char decideAction() {\n        // If all delivered we don't need more actions, but we still must return something\n        if (deliveredCount >= TOT) return '.';\n\n        // If holding something\n        if (hold != -1) {\n            if (hold == nextID) {\n                // Deliver to its dispatch gate\n                int tr = dstRow[hold];\n                int tc = 4;\n                if (br == tr && bc == tc) {\n                    // Drop\n                    if (occ[br][bc] == -1) return 'Q';\n                    // Should not happen, but wait\n                    return '.';\n                } else {\n                    return stepToward(tr, tc);\n                }\n            } else {\n                // Not the target; deposit to interior or force deliver if full\n                if (forceDeliverActive) {\n                    int tr = dstRow[hold];\n                    int tc = 4;\n                    if (br == tr && bc == tc) {\n                        if (occ[br][bc] == -1) return 'Q';\n                        return '.';\n                    } else {\n                        return stepToward(tr, tc);\n                    }\n                }\n                if (!hasDepositTarget) {\n                    int r, c;\n                    if (findNearestEmptyInterior(r, c, br, bc)) {\n                        hasDepositTarget = true;\n                        dep_r = r; dep_c = c;\n                    } else {\n                        // No interior space: force dispatch this held container (out-of-order)\n                        forceDeliverActive = true;\n                        int tr = dstRow[hold], tc = 4;\n                        if (br == tr && bc == tc) {\n                            if (occ[br][bc] == -1) return 'Q';\n                            return '.';\n                        } else {\n                            return stepToward(tr, tc);\n                        }\n                    }\n                }\n                // Move to deposit target or drop\n                if (br == dep_r && bc == dep_c) {\n                    if (occ[br][bc] == -1) return 'Q';\n                    // Extremely unlikely: chosen cell became occupied\n                    // Try re-choose\n                    hasDepositTarget = false;\n                    return '.';\n                } else {\n                    return stepToward(dep_r, dep_c);\n                }\n            }\n        }\n\n        // Not holding: go fetch nextID\n        if (nextID >= TOT) return '.';\n        int s = srcRow[nextID];\n        int tr = s, tc = 0;\n        if (br == tr && bc == tc) {\n            // If container present: pick; else wait for spawn\n            if (occ[tr][tc] == -1) {\n                // No container yet: wait for spawn next turn\n                return '.';\n            } else {\n                // Pick whatever is at this gate (target or blocker)\n                return 'P';\n            }\n        } else {\n            return stepToward(tr, tc);\n        }\n    }\n\n    void run() {\n        // We will bomb small cranes at t=0 action\n        // Loop until all dispatched or we hit turn limit\n        const int MAX_TURNS = 10000;\n        for (int t=0; t<MAX_TURNS; t++) {\n            // Step 1: spawn\n            step1_spawn();\n\n            // Step 2: decide actions\n            char bigAct = decideAction();\n\n            // Record output for this turn\n            // Crane 0: big\n            S[0].push_back(bigAct);\n            // Small cranes: bomb at t==0, then dots\n            for (int i=1;i<N;i++){\n                if (t==0) S[i].push_back('B');\n                else S[i].push_back('.');\n            }\n\n            // Apply big action\n            applyBigAction(bigAct);\n\n            // Step 3: dispatch\n            step3_dispatch();\n\n            // Stop when done\n            if (deliveredCount >= TOT) break;\n        }\n\n        // Pad all strings to same length\n        size_t L = 0;\n        for (int i=0;i<N;i++) L = max(L, S[i].size());\n        for (int i=0;i<N;i++){\n            if (S[i].size() < L) S[i].append(L - S[i].size(), '.');\n        }\n    }\n\n    void output() {\n        for (int i=0;i<N;i++){\n            cout << S[i] << \"\\n\";\n        }\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Simulator sim;\n    sim.readInput();\n    sim.run();\n    sim.output();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct CandidateResult {\n    long long estCost = (1LL<<62);\n    int startIndex = -1;\n    int pathType = -1; // 0: row snake, 1: row snake reversed, 2: col snake, 3: col snake reversed\n};\n\nstatic inline vector<pair<int,int>> build_row_snake(int N){\n    vector<pair<int,int>> path;\n    path.reserve(N*N);\n    for(int i=0;i<N;i++){\n        if(i%2==0){\n            for(int j=0;j<N;j++) path.emplace_back(i,j);\n        }else{\n            for(int j=N-1;j>=0;j--) path.emplace_back(i,j);\n        }\n    }\n    return path;\n}\nstatic inline vector<pair<int,int>> build_col_snake(int N){\n    vector<pair<int,int>> path;\n    path.reserve(N*N);\n    for(int j=0;j<N;j++){\n        if(j%2==0){\n            for(int i=0;i<N;i++) path.emplace_back(i,j);\n        }else{\n            for(int i=N-1;i>=0;i--) path.emplace_back(i,j);\n        }\n    }\n    return path;\n}\n\nstruct EvalData {\n    vector<long long> arr;          // heights along path\n    vector<pair<int,int>> pos;      // coordinates along path\n    vector<long long> pre2;         // prefix sums over duplicated array (size 2M+1)\n    vector<long long> prefpre2;     // prefix of pre2 (size 2M+1)\n    vector<long long> minWinStart;  // sliding window minima of pre2 for windows of length M; index is start\n};\n\nstatic inline EvalData prepare_eval(const vector<pair<int,int>>& path, const vector<vector<int>>& h){\n    int M = (int)path.size();\n    EvalData ed;\n    ed.pos = path;\n    ed.arr.resize(M);\n    for(int k=0;k<M;k++){\n        ed.arr[k] = h[path[k].first][path[k].second];\n    }\n    // Build arr2 implicitly via modulo; pre2 over length 2M\n    ed.pre2.assign(2*M+1, 0);\n    for(int i=0;i<2*M;i++){\n        ed.pre2[i+1] = ed.pre2[i] + ed.arr[i%M];\n    }\n    // prefpre2\n    ed.prefpre2.assign(2*M+1, 0);\n    for(int i=0;i<2*M+1;i++){\n        ed.prefpre2[i] = (i==0 ? 0 : ed.prefpre2[i-1] + ed.pre2[i-1]);\n    }\n    // Sliding window minima of pre2 with window length M\n    // min over pre2[start .. start+M-1], for start from 0..(2M+1 - M)\n    int totalLen = 2*M+1;\n    int W = M;\n    ed.minWinStart.assign(totalLen - W + 1, 0); // length M+2\n    deque<int> dq;\n    for(int i=0;i<totalLen;i++){\n        while(!dq.empty() && ed.pre2[dq.back()] >= ed.pre2[i]) dq.pop_back();\n        dq.push_back(i);\n        int start = i - (W - 1);\n        if(dq.front() < start) dq.pop_front();\n        if(start >= 0){\n            ed.minWinStart[start] = ed.pre2[dq.front()];\n        }\n    }\n    return ed;\n}\n\n// Evaluate best start for a given path evaluation data.\n// base is sum |h|. Start position is index in path, reposition from (0,0).\nstatic inline pair<long long,int> evaluate_best_start(const EvalData& ed, long long base){\n    int M = (int)ed.arr.size();\n    long long bestCost = (1LL<<62);\n    int bestS = -1;\n\n    // Guarantee we have at least one valid start: start after minimal pre2 on first cycle\n    int fallbackS = 0;\n    {\n        long long mn = LLONG_MAX;\n        int arg = 0;\n        for(int i=0;i<=M;i++){\n            if(ed.pre2[i] < mn){\n                mn = ed.pre2[i];\n                arg = i;\n            }\n        }\n        fallbackS = arg % M;\n    }\n\n    bool found = false;\n    for(int s=0;s<M;s++){\n        // Valid if min pre2 on [s+1 .. s+M] >= pre2[s]\n        long long minInRange = ed.minWinStart[s+1]; // window length M starting at s+1\n        if(minInRange < ed.pre2[s]) continue; // not valid (would need to unload more than we have)\n        // Compute Dsum = sum_{u=1..M-1} (pre2[s+u] - pre2[s]) = (sum pre2 from s+1 to s+M-1) - (M-1)*pre2[s]\n        long long sumPre2Range = ed.prefpre2[s+M] - ed.prefpre2[s+1]; // sum of pre2[s+1..s+M-1]\n        long long dsum = sumPre2Range - (long long)(M-1) * ed.pre2[s];\n\n        // moves: (M-1) along path, plus reposition distance from (0,0) to start cell\n        int sx = ed.pos[s].first, sy = ed.pos[s].second;\n        int repositionDist = abs(sx - 0) + abs(sy - 0);\n        long long moveCost = 100LL * ((M-1) + repositionDist);\n\n        long long est = base + moveCost + dsum;\n\n        if(est < bestCost){\n            bestCost = est;\n            bestS = s;\n            found = true;\n        }\n    }\n    if(!found){\n        // fallback should always be valid by theory, but in case of any bug, use it\n        int s = fallbackS;\n        long long sumPre2Range = ed.prefpre2[s+M] - ed.prefpre2[s+1];\n        long long dsum = sumPre2Range - (long long)(M-1) * ed.pre2[s];\n        int sx = ed.pos[s].first, sy = ed.pos[s].second;\n        int repositionDist = abs(sx) + abs(sy);\n        long long moveCost = 100LL * ((M-1) + repositionDist);\n        long long est = base + moveCost + dsum;\n        bestCost = est;\n        bestS = s;\n    }\n    return {bestCost, bestS};\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N;\n    if(!(cin>>N)) return 0;\n    vector<vector<int>> h(N, vector<int>(N));\n    long long base = 0;\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            cin>>h[i][j];\n            base += llabs((long long)h[i][j]);\n        }\n    }\n\n    // Build candidate paths\n    vector<vector<pair<int,int>>> paths;\n    auto row_snake = build_row_snake(N);\n    auto col_snake = build_col_snake(N);\n    vector<pair<int,int>> row_rev = row_snake; reverse(row_rev.begin(), row_rev.end());\n    vector<pair<int,int>> col_rev = col_snake; reverse(col_rev.begin(), col_rev.end());\n\n    paths.push_back(row_snake);\n    paths.push_back(row_rev);\n    paths.push_back(col_snake);\n    paths.push_back(col_rev);\n\n    CandidateResult best;\n\n    // Evaluate each path\n    for(int ptype=0; ptype<(int)paths.size(); ptype++){\n        EvalData ed = prepare_eval(paths[ptype], h);\n        auto [estCost, startIndex] = evaluate_best_start(ed, base);\n        if(estCost < best.estCost){\n            best.estCost = estCost;\n            best.pathType = ptype;\n            best.startIndex = startIndex;\n        }\n    }\n\n    // Use best candidate\n    vector<pair<int,int>> path = paths[best.pathType];\n    int M = (int)path.size();\n    int s = best.startIndex;\n    if(s < 0) s = 0; // Just in case\n\n    vector<string> ops;\n    ops.reserve(N*N*3);\n\n    // Current position and current load\n    int cx = 0, cy = 0;\n    long long load = 0;\n\n    auto move_to = [&](int tx, int ty){\n        while(cy < ty){ ops.emplace_back(\"R\"); cy++; }\n        while(cy > ty){ ops.emplace_back(\"L\"); cy--; }\n        while(cx < tx){ ops.emplace_back(\"D\"); cx++; }\n        while(cx > tx){ ops.emplace_back(\"U\"); cx--; }\n    };\n\n    // Reposition to start (with zero load)\n    int sx = path[s].first, sy = path[s].second;\n    move_to(sx, sy);\n\n    // Traverse the path starting at s\n    for(int t=0;t<M;t++){\n        int idx = (s + t) % M;\n        int x = path[idx].first, y = path[idx].second;\n        // At (x,y), perform load/unload to zero the cell\n        int val = h[x][y];\n        if(val > 0){\n            // load val\n            ops.emplace_back(\"+\" + to_string(val));\n            load += val;\n            h[x][y] = 0;\n        }else if(val < 0){\n            int need = -val;\n            // by construction, load >= need\n            if(load < need){\n                // In theory should not happen. As a safety net, do partial (shouldn't be needed).\n                int give = (int)min<long long>(need, load);\n                if(give > 0) {\n                    ops.emplace_back(\"-\" + to_string(give));\n                    load -= give;\n                    h[x][y] += give;\n                }\n            }else{\n                ops.emplace_back(\"-\" + to_string(need));\n                load -= need;\n                h[x][y] = 0;\n            }\n        }\n        // Move to next cell unless last\n        if(t != M-1){\n            int nx = path[(idx+1)%M].first, ny = path[(idx+1)%M].second;\n            // next cell must be adjacent\n            if(nx == x){\n                if(ny == y+1){\n                    ops.emplace_back(\"R\"); cy++; // cx unchanged\n                }else if(ny == y-1){\n                    ops.emplace_back(\"L\"); cy--;\n                }else{\n                    // Should not happen with snake paths; as a fallback, use manhattan move (rare)\n                    move_to(nx, ny);\n                }\n            }else if(ny == y){\n                if(nx == x+1){\n                    ops.emplace_back(\"D\"); cx++;\n                }else if(nx == x-1){\n                    ops.emplace_back(\"U\"); cx--;\n                }else{\n                    move_to(nx, ny);\n                }\n            }else{\n                // Fallback (should not happen)\n                move_to(nx, ny);\n            }\n        }\n    }\n\n    // Output operations, one per line\n    for(auto &sop : ops){\n        cout << sop << '\\n';\n    }\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Heuristic for AHC035 \"Grain\".\n// Strategy:\n// - Always preserve max-gene carriers (X_l) every turn. In early turns, try to include up to two carriers per dimension.\n// - Fill the rest with high-V seeds, with a bonus for seeds carrying many/rare max genes.\n// - Arrange seeds on the grid prioritizing high-degree cells for important seeds.\n// - Improve arrangement with greedy local swapping to maximize an objective that:\n//      * puts important seeds (V + rare max genes) on high-degree positions,\n//      * encourages adjacency of carriers (same dim) and also \"one-carrier\" edges to spread genes.\n// Notes:\n// - We use bit masks for carrier sets (M <= 15).\n// - All weights are heuristic and tuned to be robust, not brittle.\n\nstruct RNG {\n    // Simple and fast xorshift RNG\n    uint64_t x;\n    RNG() {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        x = seed ^ (seed << 13);\n    }\n    inline uint32_t next_u32() {\n        uint64_t y = x;\n        y ^= (y << 7);\n        y ^= (y >> 9);\n        x = y;\n        return (uint32_t)(y & 0xffffffffu);\n    }\n    inline int randint(int lo, int hi) { // inclusive lo..hi\n        uint32_t r = next_u32();\n        return lo + (int)(r % (uint32_t)(hi - lo + 1));\n    }\n    inline double rand01() {\n        return (next_u32() / 4294967296.0);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    if (!(cin >> N >> M >> T)) return 0;\n\n    const int SEED_COUNT = 2 * N * (N - 1); // 60 when N=6\n    vector<vector<int>> X(SEED_COUNT, vector<int>(M, 0));\n    for (int i = 0; i < SEED_COUNT; i++) {\n        for (int j = 0; j < M; j++) cin >> X[i][j];\n    }\n\n    // Initial global maxima X_l (constant upper bound)\n    vector<int> Xmax(M, 0);\n    for (int l = 0; l < M; l++) {\n        int mx = 0;\n        for (int k = 0; k < SEED_COUNT; k++) mx = max(mx, X[k][l]);\n        Xmax[l] = mx;\n    }\n\n    // Precompute grid adjacency and degrees, position order by degree and center proximity\n    auto pos_id = [&](int i, int j) { return i * N + j; };\n    vector<vector<int>> neighbors(N*N);\n    vector<int> deg(N*N, 0);\n    vector<pair<int,int>> edges;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int u = pos_id(i,j);\n        if (i > 0)   { int v = pos_id(i-1,j); neighbors[u].push_back(v); }\n        if (i+1 < N) { int v = pos_id(i+1,j); neighbors[u].push_back(v); }\n        if (j > 0)   { int v = pos_id(i,j-1); neighbors[u].push_back(v); }\n        if (j+1 < N) { int v = pos_id(i,j+1); neighbors[u].push_back(v); }\n        deg[u] = (int)neighbors[u].size();\n    }\n    // Build undirected edges once\n    vector<vector<bool>> seen(N*N, vector<bool>(N*N,false));\n    for (int u = 0; u < N*N; u++) {\n        for (int v: neighbors[u]) if (!seen[u][v]) {\n            edges.emplace_back(u,v);\n            seen[u][v] = seen[v][u] = true;\n        }\n    }\n    // Position order (higher degree first, then closer to center)\n    vector<int> posOrder(N*N);\n    iota(posOrder.begin(), posOrder.end(), 0);\n    const double ci = (N-1)/2.0, cj = (N-1)/2.0;\n    sort(posOrder.begin(), posOrder.end(), [&](int a, int b){\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        int ai = a / N, aj = a % N;\n        int bi = b / N, bj = b % N;\n        double da = abs(ai - ci) + abs(aj - cj);\n        double db = abs(bi - ci) + abs(bj - cj);\n        if (da != db) return da < db;\n        return a < b;\n    });\n\n    RNG rng;\n\n    // Helper lambdas for objective components weights (tuned heuristics)\n    auto nodeWeightParams = [&](int t){\n        // For early turns, emphasize rare carriers more; later shift towards V a bit\n        struct P { double wV, wRare, wCnt, pairFactor, pairBoth, pairOne; };\n        if (t <= 2) {\n            return P{0.15, 90.0, 18.0, 220.0, 2.2, 0.9};\n        } else if (t <= 6) {\n            return P{0.18, 80.0, 16.0, 200.0, 2.0, 0.8};\n        } else {\n            return P{0.22, 70.0, 14.0, 180.0, 1.8, 0.75};\n        }\n    };\n    auto selectionParams = [&](int t){\n        struct Q { int carriersPerDim; double fillRare, fillCnt; };\n        if (t <= 2) {\n            return Q{2, 220.0, 22.0};\n        } else if (t <= 6) {\n            return Q{1, 200.0, 20.0};\n        } else {\n            return Q{1, 180.0, 18.0};\n        }\n    };\n    auto arrangementParams = [&](int t){\n        struct R { double wV, wRare, wCnt; };\n        if (t <= 2) return R{0.25, 100.0, 20.0};\n        if (t <= 6) return R{0.22, 90.0, 18.0};\n        return R{0.20, 80.0, 16.0};\n    };\n\n    // Main loop over turns\n    for (int t = 0; t < T; t++) {\n        // Compute V, carrier bit masks for current seeds\n        vector<int> V(SEED_COUNT, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            int s = 0;\n            for (int l = 0; l < M; l++) s += X[k][l];\n            V[k] = s;\n        }\n        // Carrier masks and counts per dimension\n        vector<uint16_t> bits(SEED_COUNT, 0);\n        vector<int> cnt(M, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            uint16_t m = 0;\n            for (int l = 0; l < M; l++) {\n                if (X[k][l] == Xmax[l]) { m |= (1u << l); }\n            }\n            bits[k] = m;\n            for (int l = 0; l < M; l++) if ( (m >> l) & 1u ) cnt[l]++;\n        }\n        // Dimension weights: emphasize rare carriers\n        vector<double> wdim(M, 0.0);\n        for (int l = 0; l < M; l++) {\n            if (cnt[l] > 0) wdim[l] = 1.0 / (double)cnt[l];\n            else wdim[l] = 0.0; // lost gene, can't be recovered\n        }\n        // Precompute sum of wdim per mask (2^M <= 32768; fine)\n        int MASKSZ = 1 << M;\n        vector<double> sumW(MASKSZ, 0.0);\n        for (int m = 1; m < MASKSZ; m++) {\n            int lb = __builtin_ctz(m);\n            int prev = m & (m - 1);\n            sumW[m] = sumW[prev] + wdim[lb];\n        }\n        // rareSum and carrierCount per seed\n        vector<double> rareSum(SEED_COUNT, 0.0);\n        vector<int> carrierCnt(SEED_COUNT, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            rareSum[k] = sumW[bits[k]];\n            carrierCnt[k] = __builtin_popcount((unsigned)bits[k]);\n        }\n\n        // Forced selection of carriers\n        auto selP = selectionParams(t);\n        int perDimCar = selP.carriersPerDim;\n        vector<int> selected;\n        selected.reserve(N*N);\n        vector<char> used(SEED_COUNT, 0);\n\n        auto include = [&](int k) {\n            if (k < 0 || k >= SEED_COUNT) return;\n            if (used[k]) return;\n            used[k] = 1;\n            selected.push_back(k);\n        };\n\n        // For each dimension, include top carriers (by V) up to perDimCar\n        for (int l = 0; l < M; l++) {\n            if (cnt[l] == 0) continue; // already lost\n            // Collect carriers for dim l\n            vector<int> cand;\n            cand.reserve(cnt[l]);\n            for (int k = 0; k < SEED_COUNT; k++) if ( (bits[k] >> l) & 1u ) cand.push_back(k);\n            // Sort by V descending\n            sort(cand.begin(), cand.end(), [&](int a, int b){\n                if (V[a] != V[b]) return V[a] > V[b];\n                return a < b;\n            });\n            int take = min(perDimCar, (int)cand.size());\n            for (int i = 0; i < take && (int)selected.size() < N*N; i++) include(cand[i]);\n        }\n\n        // Always include the current best-V seed\n        int bestVidx = (int)(max_element(V.begin(), V.end()) - V.begin());\n        include(bestVidx);\n\n        // Fill remaining slots with high-scoring seeds (V + rarity bonuses)\n        vector<int> rest;\n        rest.reserve(SEED_COUNT);\n        for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) rest.push_back(k);\n        vector<double> fillScore(SEED_COUNT, 0.0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            fillScore[k] = V[k] + selP.fillRare * rareSum[k] + selP.fillCnt * carrierCnt[k];\n        }\n        sort(rest.begin(), rest.end(), [&](int a, int b){\n            if (fillScore[a] != fillScore[b]) return fillScore[a] > fillScore[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n        for (int idx: rest) {\n            if ((int)selected.size() >= N*N) break;\n            include(idx);\n        }\n        // Safety: if for some reason we still don't have enough, fill with the best remaining\n        if ((int)selected.size() < N*N) {\n            vector<int> remain;\n            for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) remain.push_back(k);\n            sort(remain.begin(), remain.end(), [&](int a, int b){\n                if (V[a] != V[b]) return V[a] > V[b];\n                return a < b;\n            });\n            for (int idx: remain) {\n                if ((int)selected.size() >= N*N) break;\n                include(idx);\n            }\n        }\n\n        // Arrangement initial mapping by position order and seed priority\n        auto arrP = arrangementParams(t);\n        vector<double> arrScore(SEED_COUNT, 0.0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            arrScore[k] = arrP.wV * V[k] + arrP.wRare * rareSum[k] + arrP.wCnt * carrierCnt[k];\n        }\n        vector<int> toPlace = selected;\n        sort(toPlace.begin(), toPlace.end(), [&](int a, int b){\n            if (arrScore[a] != arrScore[b]) return arrScore[a] > arrScore[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        vector<int> assignPos(N*N, -1); // pos -> seed index\n        vector<int> invPos(SEED_COUNT, -1); // seed index -> pos or -1 if not placed\n        for (int p = 0; p < N*N; p++) {\n            int pos = posOrder[p];\n            int k = toPlace[p];\n            assignPos[pos] = k;\n            invPos[k] = pos;\n        }\n\n        // Prepare objective for local improvement\n        auto nodeP = nodeWeightParams(t);\n        vector<double> nodeWeight(SEED_COUNT, 0.0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            nodeWeight[k] = nodeP.wV * V[k] + nodeP.wRare * rareSum[k] + nodeP.wCnt * carrierCnt[k];\n        }\n\n        auto pairScore = [&](int ka, int kb)->double {\n            uint16_t ma = bits[ka], mb = bits[kb];\n            uint16_t both = (ma & mb);\n            uint16_t xone = (ma ^ mb);\n            double s = 0.0;\n            s += nodeP.pairBoth * sumW[both];\n            s += nodeP.pairOne  * sumW[xone];\n            return s;\n        };\n\n        auto totalObjective = [&]()->double {\n            double nodeTerm = 0.0;\n            for (int p = 0; p < N*N; p++) {\n                int k = assignPos[p];\n                nodeTerm += deg[p] * nodeWeight[k];\n            }\n            double pairTerm = 0.0;\n            for (auto &e: edges) {\n                int a = e.first, b = e.second;\n                int ka = assignPos[a], kb = assignPos[b];\n                pairTerm += pairScore(ka, kb);\n            }\n            return nodeTerm + nodeP.pairFactor * pairTerm;\n        };\n\n        // Greedy local swap improvement\n        // Limit iterations to keep well within time limits\n        int iters = 12000; // can adjust\n        double currentObj = totalObjective();\n        for (int it = 0; it < iters; it++) {\n            int a = rng.randint(0, N*N-1);\n            int b = rng.randint(0, N*N-1);\n            if (a == b) continue;\n            int ka = assignPos[a];\n            int kb = assignPos[b];\n\n            // Node term delta\n            double delta = 0.0;\n            delta += (deg[a] - deg[b]) * (nodeWeight[kb] - nodeWeight[ka]);\n\n            // Pair term delta (only for edges incident to a and b)\n            double deltaPair = 0.0;\n            for (int pa: neighbors[a]) if (pa != b) {\n                int kp = assignPos[pa];\n                deltaPair += pairScore(kb, kp) - pairScore(ka, kp);\n            }\n            for (int pb: neighbors[b]) if (pb != a) {\n                int kp = assignPos[pb];\n                deltaPair += pairScore(ka, kp) - pairScore(kb, kp);\n            }\n            // Edge (a,b) itself, if adjacent, swaps pairScore(ka,kb) -> pairScore(kb,ka), which is equal; delta 0.\n\n            delta += nodeP.pairFactor * deltaPair;\n\n            if (delta > 1e-9) {\n                // Accept swap\n                swap(assignPos[a], assignPos[b]);\n                invPos[ka] = b;\n                invPos[kb] = a;\n                currentObj += delta;\n            }\n        }\n\n        // Output the planting plan\n        // We need the 6x6 grid in row-major order of positions\n        // Our assignPos is indexed by pos id (i*N + j)\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int pos = i * N + j;\n                int k = assignPos[pos];\n                cout << k << (j + 1 == N ? '\\n' : ' ');\n            }\n        }\n        cout.flush();\n\n        // Read next generation seeds\n        for (int i = 0; i < SEED_COUNT; i++) {\n            for (int j = 0; j < M; j++) cin >> X[i][j];\n        }\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\n/*\nBaseline heuristic:\n- Use V' = 2: root (0) + one fingertip (1) with length 1.\n- Pair B = S\\T to C = T\\S greedily by nearest neighbor (global min selection).\n- Start root at best adjacency of first chosen source (near grid center with minimal initial rotations).\n- For each remaining task:\n    - From current root, choose the source whose best adjacency has minimal \"time\" = max(manhattan, rotSteps).\n    - Move/rotate to that adjacency; then pick.\n    - Move/rotate to the paired target adjacency; then drop.\n- Movement and rotation are performed simultaneously when possible; extra in-place rotations are added only if needed.\n- Picking/placing ('P') is issued after fully aligned (movement+rotation). We could merge P in the last rotate/move turn, but adding one turn per pick/place keeps logic simple and within 100k comfortably.\n*/\n\nstruct Pos { int x, y; };\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, V;\n    if (!(cin >> N >> M >> V)) return 0;\n    vector<string> ss(N), tt(N);\n    for (int i = 0; i < N; i++) cin >> ss[i];\n    for (int i = 0; i < N; i++) cin >> tt[i];\n\n    // Occupancy grid: current state, 1 if takoyaki present\n    vector<vector<int>> occ(N, vector<int>(N, 0));\n    vector<Pos> sources; // S \\ T (need to move out)\n    vector<Pos> targets; // T \\ S (need to fill)\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int s = ss[i][j] - '0';\n            int t = tt[i][j] - '0';\n            occ[i][j] = s;\n            if (s == 1 && t == 0) sources.push_back({i, j});\n            if (s == 0 && t == 1) targets.push_back({i, j});\n        }\n    }\n\n    int Dcnt = (int)sources.size();\n    // Sanity: sources and targets sizes equal\n    if ((int)targets.size() != Dcnt) {\n        // In unexpected cases, just output trivial design and no operations\n        cout << 2 << \"\\n\";\n        cout << 0 << \" \" << 1 << \"\\n\";\n        cout << 0 << \" \" << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Design tree: V' = 2; edge (0,1) with length 1\n    int Vp = 2;\n\n    // Pairing: greedy global min (O(D^3) with small constants: D <= 450 -> ~9e7 comparisons worst)\n    vector<int> tUsed(Dcnt, 0);\n    vector<int> pairTo(Dcnt, -1); // pairTo[i] = index in targets for sources[i]\n    // Precompute distances\n    vector<vector<int>> dist(Dcnt, vector<int>(Dcnt, 0));\n    for (int i = 0; i < Dcnt; i++) {\n        for (int j = 0; j < Dcnt; j++) {\n            dist[i][j] = abs(sources[i].x - targets[j].x) + abs(sources[i].y - targets[j].y);\n        }\n    }\n    vector<int> sUsed(Dcnt, 0);\n    for (int matched = 0; matched < Dcnt; matched++) {\n        int bestI = -1, bestJ = -1, bestD = INT_MAX;\n        for (int i = 0; i < Dcnt; i++) if (!sUsed[i]) {\n            for (int j = 0; j < Dcnt; j++) if (!tUsed[j]) {\n                int d = dist[i][j];\n                if (d < bestD) {\n                    bestD = d; bestI = i; bestJ = j;\n                }\n            }\n        }\n        if (bestI == -1) break;\n        sUsed[bestI] = 1;\n        tUsed[bestJ] = 1;\n        pairTo[bestI] = bestJ;\n    }\n    // In case some remain unmatched (shouldn't happen), pair arbitrarily\n    for (int i = 0, jptr = 0; i < Dcnt; i++) {\n        if (pairTo[i] == -1) {\n            while (jptr < Dcnt && tUsed[jptr]) jptr++;\n            if (jptr < Dcnt) {\n                pairTo[i] = jptr;\n                tUsed[jptr] = 1;\n                jptr++;\n            }\n        }\n    }\n\n    // Direction encoding: 0=E,1=D(S),2=W,3=U(N) consistent with sample\n    const int DX[4] = {0, 1, 0, -1};\n    const int DY[4] = {1, 0, -1, 0};\n    auto rotdist = [&](int cur, int req) {\n        int d = (req - cur + 4) % 4;\n        return min(d, 4 - d);\n    };\n\n    // For a cell c = (bx,by), valid root adjacencies (nx,ny) and required orientation dir:\n    auto enumerate_adj = [&](int bx, int by) -> vector<tuple<int,int,int>> {\n        vector<tuple<int,int,int>> res;\n        // left of b -> orientation East (0)\n        if (by - 1 >= 0) res.emplace_back(bx, by - 1, 0);\n        // right of b -> orientation West (2)\n        if (by + 1 < N) res.emplace_back(bx, by + 1, 2);\n        // above of b -> orientation South (1)\n        if (bx - 1 >= 0) res.emplace_back(bx - 1, by, 1);\n        // below of b -> orientation North (3)\n        if (bx + 1 < N) res.emplace_back(bx + 1, by, 3);\n        return res;\n    };\n\n    // Choose best adjacency for current root position and orientation\n    auto choose_best_adj = [&](int rx, int ry, int curdir, int bx, int by) {\n        auto cand = enumerate_adj(bx, by);\n        int bestIdx = -1;\n        long long bestCost = LLONG_MAX;\n        long long bestMove = LLONG_MAX;\n        long long bestRot = LLONG_MAX;\n        for (int i = 0; i < (int)cand.size(); i++) {\n            auto [nx, ny, ndir] = cand[i];\n            int d1 = abs(rx - nx) + abs(ry - ny);\n            int rd = rotdist(curdir, ndir);\n            long long cost = max(d1, rd); // rotations can be done during moves\n            if (cost < bestCost ||\n               (cost == bestCost && (d1 < bestMove ||\n               (d1 == bestMove && rd < bestRot)))) {\n                bestCost = cost; bestMove = d1; bestRot = rd; bestIdx = i;\n            }\n        }\n        if (bestIdx == -1) {\n            // Fallback: should not happen for valid grid\n            return tuple<int,int,int>(rx, ry, curdir);\n        }\n        return cand[bestIdx];\n    };\n\n    vector<string> ops; ops.reserve(100000);\n\n    // Simulate state\n    int rx, ry; // root position\n    int dir = 0; // orientation of the fingertip relative to root (0=E initially)\n    bool holding = false;\n\n    auto push_turn = [&](char moveCh, char rotCh, bool P) {\n        string s(2*Vp, '.'); // V' = 2 -> length = 4\n        s[0] = moveCh;       // movement\n        if (rotCh == 'L' || rotCh == 'R') s[1] = rotCh; else s[1] = '.';\n        s[2] = '.'; // root action always '.'\n        s[3] = (P ? 'P' : '.'); // fingertip action\n\n        // Apply movement\n        if (moveCh == 'U') rx -= 1;\n        else if (moveCh == 'D') rx += 1;\n        else if (moveCh == 'L') ry -= 1;\n        else if (moveCh == 'R') ry += 1;\n\n        // Clamp (shouldn't be necessary)\n        rx = max(0, min(N-1, rx));\n        ry = max(0, min(N-1, ry));\n\n        // Apply rotation\n        if (rotCh == 'L') dir = (dir + 3) % 4;\n        else if (rotCh == 'R') dir = (dir + 1) % 4;\n\n        // Apply pick/place\n        if (P) {\n            int fx = rx + DX[dir];\n            int fy = ry + DY[dir];\n            bool in = (0 <= fx && fx < N && 0 <= fy && fy < N);\n            if (in) {\n                if (!holding) {\n                    // pick if available\n                    if (occ[fx][fy] == 1) {\n                        occ[fx][fy] = 0; holding = true;\n                    } else {\n                        // no-op; avoid illegal place; we intentionally only call P at valid times\n                    }\n                } else {\n                    // place if empty\n                    if (occ[fx][fy] == 0) {\n                        occ[fx][fy] = 1; holding = false;\n                    } else {\n                        // cannot place; we intentionally avoid calling P here\n                    }\n                }\n            } else {\n                // out-of-grid; P would be illegal to place; we won't do this in our plan\n            }\n        }\n\n        ops.push_back(s);\n    };\n\n    auto rotate_step_char = [&](int cur, int req) -> char {\n        int d = (req - cur + 4) % 4;\n        if (d == 0) return '.';\n        if (d == 1) return 'R';\n        if (d == 3) return 'L';\n        // d == 2: choose 'R' (two steps will be emitted)\n        return 'R';\n    };\n\n    auto move_rotate_to = [&](int tx, int ty, int reqdir) {\n        // Move in Manhattan path (x then y), rotating on the way\n        while (rx != tx) {\n            char mv = (rx < tx ? 'D' : 'U');\n            char rot = rotate_step_char(dir, reqdir);\n            push_turn(mv, rot, false);\n            if ((int)ops.size() >= 100000) return;\n        }\n        while (ry != ty) {\n            char mv = (ry < ty ? 'R' : 'L');\n            char rot = rotate_step_char(dir, reqdir);\n            push_turn(mv, rot, false);\n            if ((int)ops.size() >= 100000) return;\n        }\n        // Final rotations if needed\n        while (dir != reqdir) {\n            char rot = rotate_step_char(dir, reqdir);\n            push_turn('.', rot, false);\n            if ((int)ops.size() >= 100000) return;\n        }\n    };\n\n    // Choose first source index and initial root position\n    int firstIdx = 0;\n    if (Dcnt > 0) {\n        // Pick the source closest to grid center\n        double cx = (N - 1) / 2.0, cy = (N - 1) / 2.0;\n        int besti = 0;\n        int bestd = INT_MAX;\n        for (int i = 0; i < Dcnt; i++) {\n            int d = abs(sources[i].x - (int)round(cx)) + abs(sources[i].y - (int)round(cy));\n            if (d < bestd) { bestd = d; besti = i; }\n        }\n        firstIdx = besti;\n    }\n\n    // Initial root position: best adjacency of first source, choosing minimal rotations from initial dir=0\n    if (Dcnt > 0) {\n        auto [nx, ny, ndir] = choose_best_adj(0, 0, 0, sources[firstIdx].x, sources[firstIdx].y);\n        // However we want to be near center; refine to pick best adjacency relative to center to reduce initial moves\n        // Try all adjacencies and pick the one with minimal rotdist from initial dir=0 and closeness to center\n        auto cand = enumerate_adj(sources[firstIdx].x, sources[firstIdx].y);\n        int bestIdx = 0;\n        long long bestScore = LLONG_MAX;\n        for (int i = 0; i < (int)cand.size(); i++) {\n            auto [ax, ay, adir] = cand[i];\n            long long rotc = rotdist(0, adir);\n            long long distc = llabs(ax - (N/2)) + llabs(ay - (N/2));\n            long long score = rotc * 10 + distc; // prioritize fewer initial rotations\n            if (score < bestScore) {\n                bestScore = score; bestIdx = i;\n            }\n        }\n        rx = get<0>(cand[bestIdx]);\n        ry = get<1>(cand[bestIdx]);\n        dir = 0; // initial orientation must be East by problem definition\n    } else {\n        // No work; just place root at (0,0)\n        rx = 0; ry = 0; dir = 0;\n    }\n\n    // Output the tree and initial root position\n    cout << Vp << \"\\n\";\n    cout << 0 << \" \" << 1 << \"\\n\"; // p_1=0, L=1\n    cout << rx << \" \" << ry << \"\\n\";\n\n    if (Dcnt == 0) {\n        // Already done; no operations\n        return 0;\n    }\n\n    // Task status\n    vector<char> done(Dcnt, 0);\n\n    // First task is chosen as firstIdx\n    int curTask = firstIdx;\n\n    // Helper to perform pick-drop for a task i\n    auto process_task = [&](int idx) {\n        if ((int)ops.size() >= 100000) return;\n        Pos b = sources[idx];\n        Pos c = targets[pairTo[idx]];\n        // Move to best adjacency of b\n        {\n            auto [tx, ty, reqdir] = choose_best_adj(rx, ry, dir, b.x, b.y);\n            move_rotate_to(tx, ty, reqdir);\n            if ((int)ops.size() >= 100000) return;\n            // Pick (only if valid)\n            int fx = rx + (int)(reqdir == 1 ? 1 : (reqdir == 3 ? -1 : 0));\n            int fy = ry + (int)(reqdir == 0 ? 1 : (reqdir == 2 ? -1 : 0));\n            bool canPick = (0 <= fx && fx < N && 0 <= fy && fy < N && !holding && occ[fx][fy] == 1);\n            push_turn('.', '.', canPick);\n        }\n        if ((int)ops.size() >= 100000) return;\n        // Move to best adjacency of c\n        {\n            auto [tx, ty, reqdir] = choose_best_adj(rx, ry, dir, c.x, c.y);\n            move_rotate_to(tx, ty, reqdir);\n            if ((int)ops.size() >= 100000) return;\n            // Place (only if valid)\n            int fx = rx + (int)(reqdir == 1 ? 1 : (reqdir == 3 ? -1 : 0));\n            int fy = ry + (int)(reqdir == 0 ? 1 : (reqdir == 2 ? -1 : 0));\n            bool canPlace = (0 <= fx && fx < N && 0 <= fy && fy < N && holding && occ[fx][fy] == 0);\n            push_turn('.', '.', canPlace);\n        }\n        done[idx] = 1;\n    };\n\n    // Do first task\n    process_task(curTask);\n\n    // For the rest: greedy next source based on best adjacency time from current pos\n    for (int it = 1; it < Dcnt; it++) {\n        if ((int)ops.size() >= 100000) break;\n        int besti = -1;\n        long long bestCost = LLONG_MAX, bestMove = LLONG_MAX, bestRot = LLONG_MAX;\n        for (int i = 0; i < Dcnt; i++) if (!done[i]) {\n            auto b = sources[i];\n            auto cand = enumerate_adj(b.x, b.y);\n            for (auto &t : cand) {\n                int nx, ny, ndir;\n                tie(nx, ny, ndir) = t;\n                long long d1 = llabs(rx - nx) + llabs(ry - ny);\n                long long rd = rotdist(dir, ndir);\n                long long cost = max(d1, rd);\n                if (cost < bestCost ||\n                   (cost == bestCost && (d1 < bestMove ||\n                   (d1 == bestMove && rd < bestRot)))) {\n                    bestCost = cost; bestMove = d1; bestRot = rd; besti = i;\n                }\n            }\n        }\n        if (besti == -1) break;\n        process_task(besti);\n    }\n\n    // Print operations\n    for (auto &s : ops) cout << s << \"\\n\";\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Constants\nstatic const int LIM = 100000;\nstatic const int PERIM_LIMIT = 400000;\n\nstruct Pt {\n    int x, y;\n    int w; // +1 mackerel, -1 sardine\n};\n\nstruct Rect {\n    int L, R, B, T; // inclusive bounds\n    long long perim() const {\n        long long w = (long long)R - L;\n        long long h = (long long)T - B;\n        if (w < 0) w = 0;\n        if (h < 0) h = 0;\n        return 2LL * (w + h);\n    }\n    void ensure_min_size() {\n        if (L < 0) L = 0;\n        if (B < 0) B = 0;\n        if (R > LIM) R = LIM;\n        if (T > LIM) T = LIM;\n        if (L >= R) {\n            if (L > 0) L = R - 1;\n            else R = L + 1;\n        }\n        if (B >= T) {\n            if (B > 0) B = T - 1;\n            else T = B + 1;\n        }\n        if (L < 0) L = 0;\n        if (R > LIM) R = LIM;\n        if (B < 0) B = 0;\n        if (T > LIM) T = LIM;\n    }\n};\n\nstruct ColData {\n    vector<int> xs;                   // unique x's sorted\n    vector<vector<int>> ys;           // ys per x sorted\n    vector<vector<int>> pref;         // prefix sums of weights per x\n};\n\nstruct RowData {\n    vector<int> ys;                   // unique y's sorted\n    vector<vector<int>> xs;           // xs per y sorted\n    vector<vector<int>> pref;         // prefix sums of weights per y\n};\n\nstatic inline int sum_by_range(const vector<int>& coord, const vector<int>& pref, int lo, int hi) {\n    // coord sorted ascending, pref size coord.size()+1\n    // sum of weights where coord in [lo, hi]\n    auto itL = lower_bound(coord.begin(), coord.end(), lo);\n    auto itR = upper_bound(coord.begin(), coord.end(), hi);\n    int l = (int)(itL - coord.begin());\n    int r = (int)(itR - coord.begin());\n    return pref[r] - pref[l];\n}\n\nstruct Refiner {\n    const ColData &col;\n    const RowData &row;\n\n    Refiner(const ColData& c, const RowData& r) : col(c), row(r) {}\n\n    // Sum over column at index xi (in col.xs) within y in [B,T]\n    inline int col_sum_idx(int xi, int B, int T) const {\n        if (xi < 0 || xi >= (int)col.xs.size()) return 0;\n        const auto &ysv = col.ys[xi];\n        const auto &pf = col.pref[xi];\n        if (ysv.empty()) return 0;\n        auto itL = lower_bound(ysv.begin(), ysv.end(), B);\n        auto itR = upper_bound(ysv.begin(), ysv.end(), T);\n        int l = (int)(itL - ysv.begin());\n        int r = (int)(itR - ysv.begin());\n        return pf[r] - pf[l];\n    }\n\n    // Sum over row at index yi (in row.ys) within x in [L,R]\n    inline int row_sum_idx(int yi, int L, int R) const {\n        if (yi < 0 || yi >= (int)row.ys.size()) return 0;\n        const auto &xsv = row.xs[yi];\n        const auto &pf = row.pref[yi];\n        if (xsv.empty()) return 0;\n        auto itL = lower_bound(xsv.begin(), xsv.end(), L);\n        auto itR = upper_bound(xsv.begin(), xsv.end(), R);\n        int l = (int)(itL - xsv.begin());\n        int r = (int)(itR - xsv.begin());\n        return pf[r] - pf[l];\n    }\n\n    // Compute current score inside rectangle by summing over columns (faster than scanning all points)\n    long long rect_sum(Rect r) const {\n        // iterate over present x in [L,R]\n        auto itL = lower_bound(col.xs.begin(), col.xs.end(), r.L);\n        auto itR = upper_bound(col.xs.begin(), col.xs.end(), r.R);\n        long long s = 0;\n        for (auto it = itL; it != itR; ++it) {\n            int xi = (int)(it - col.xs.begin());\n            s += col_sum_idx(xi, r.B, r.T);\n        }\n        return s;\n    }\n\n    // Compute best expansion/shrink for each side.\n    // Returns pair<delta, newCoord>. If delta <= 0, no beneficial move.\n    pair<long long,int> best_expand_left(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim;\n        if (remain < 2) return {0, r.L};\n        int kmax = (int)min<long long>(r.L, remain / 2); // how far we can move left\n        if (kmax <= 0) return {0, r.L};\n        // scan present x < L down to >= L - kmax\n        int idx = (int)(lower_bound(col.xs.begin(), col.xs.end(), r.L) - col.xs.begin()) - 1;\n        if (idx < 0) return {0, r.L};\n        int xLower = r.L - kmax;\n        long long best = 0;\n        int bestL = r.L;\n        long long run = 0;\n        for (int i = idx; i >= 0; --i) {\n            int x = col.xs[i];\n            if (x < xLower) break;\n            run += col_sum_idx(i, r.B, r.T);\n            if (run > best) {\n                best = run;\n                bestL = x;\n            }\n        }\n        return {best, bestL};\n    }\n\n    pair<long long,int> best_shrink_left(const Rect& r) const {\n        if (r.L >= r.R) return {0, r.L};\n        int targetMax = r.R - 1;\n        int iL = (int)(lower_bound(col.xs.begin(), col.xs.end(), r.L) - col.xs.begin());\n        int iR = (int)(upper_bound(col.xs.begin(), col.xs.end(), targetMax) - col.xs.begin()) - 1;\n        if (iL > iR) return {0, r.L}; // no present x in range\n        long long best = 0;\n        int bestL = r.L;\n        long long run = 0;\n        for (int i = iL; i <= iR; ++i) {\n            run += - (long long)col_sum_idx(i, r.B, r.T);\n            if (run > best) {\n                best = run;\n                // new L becomes just after this x\n                int newL = col.xs[i] + 1;\n                if (newL > targetMax) newL = targetMax;\n                bestL = newL;\n            }\n        }\n        return {best, bestL};\n    }\n\n    pair<long long,int> best_expand_right(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim;\n        if (remain < 2) return {0, r.R};\n        int kmax = (int)min<long long>(LIM - r.R, remain / 2);\n        if (kmax <= 0) return {0, r.R};\n        int idx = (int)(upper_bound(col.xs.begin(), col.xs.end(), r.R) - col.xs.begin());\n        if (idx >= (int)col.xs.size()) return {0, r.R};\n        int xUpper = r.R + kmax;\n        long long best = 0, run = 0;\n        int bestR = r.R;\n        for (int i = idx; i < (int)col.xs.size(); ++i) {\n            int x = col.xs[i];\n            if (x > xUpper) break;\n            run += col_sum_idx(i, r.B, r.T);\n            if (run > best) {\n                best = run;\n                bestR = x;\n            }\n        }\n        return {best, bestR};\n    }\n\n    pair<long long,int> best_shrink_right(const Rect& r) const {\n        if (r.L >= r.R) return {0, r.R};\n        int targetMin = r.L + 1;\n        int iL = (int)(lower_bound(col.xs.begin(), col.xs.end(), targetMin) - col.xs.begin());\n        int iR = (int)(upper_bound(col.xs.begin(), col.xs.end(), r.R) - col.xs.begin()) - 1;\n        if (iL > iR) return {0, r.R}; // no present x in range\n        long long best = 0, run = 0;\n        int bestR = r.R;\n        for (int i = iR; i >= iL; --i) {\n            run += - (long long)col_sum_idx(i, r.B, r.T);\n            if (run > best) {\n                best = run;\n                int newR = col.xs[i] - 1;\n                if (newR < targetMin) newR = targetMin;\n                bestR = newR;\n            }\n        }\n        return {best, bestR};\n    }\n\n    pair<long long,int> best_expand_bottom(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim;\n        if (remain < 2) return {0, r.B};\n        int kmax = (int)min<long long>(r.B, remain / 2);\n        if (kmax <= 0) return {0, r.B};\n        int idx = (int)(lower_bound(row.ys.begin(), row.ys.end(), r.B) - row.ys.begin()) - 1;\n        if (idx < 0) return {0, r.B};\n        int yLower = r.B - kmax;\n        long long best = 0, run = 0;\n        int bestB = r.B;\n        for (int i = idx; i >= 0; --i) {\n            int y = row.ys[i];\n            if (y < yLower) break;\n            run += row_sum_idx(i, r.L, r.R);\n            if (run > best) {\n                best = run;\n                bestB = y;\n            }\n        }\n        return {best, bestB};\n    }\n\n    pair<long long,int> best_shrink_bottom(const Rect& r) const {\n        if (r.B >= r.T) return {0, r.B};\n        int targetMax = r.T - 1;\n        int iL = (int)(lower_bound(row.ys.begin(), row.ys.end(), r.B) - row.ys.begin());\n        int iR = (int)(upper_bound(row.ys.begin(), row.ys.end(), targetMax) - row.ys.begin()) - 1;\n        if (iL > iR) return {0, r.B};\n        long long best = 0, run = 0;\n        int bestB = r.B;\n        for (int i = iL; i <= iR; ++i) {\n            run += - (long long)row_sum_idx(i, r.L, r.R);\n            if (run > best) {\n                best = run;\n                int newB = row.ys[i] + 1;\n                if (newB > targetMax) newB = targetMax;\n                bestB = newB;\n            }\n        }\n        return {best, bestB};\n    }\n\n    pair<long long,int> best_expand_top(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim;\n        if (remain < 2) return {0, r.T};\n        int kmax = (int)min<long long>(LIM - r.T, remain / 2);\n        if (kmax <= 0) return {0, r.T};\n        int idx = (int)(upper_bound(row.ys.begin(), row.ys.end(), r.T) - row.ys.begin());\n        if (idx >= (int)row.ys.size()) return {0, r.T};\n        int yUpper = r.T + kmax;\n        long long best = 0, run = 0;\n        int bestT = r.T;\n        for (int i = idx; i < (int)row.ys.size(); ++i) {\n            int y = row.ys[i];\n            if (y > yUpper) break;\n            run += row_sum_idx(i, r.L, r.R);\n            if (run > best) {\n                best = run;\n                bestT = y;\n            }\n        }\n        return {best, bestT};\n    }\n\n    pair<long long,int> best_shrink_top(const Rect& r) const {\n        if (r.B >= r.T) return {0, r.T};\n        int targetMin = r.B + 1;\n        int iL = (int)(lower_bound(row.ys.begin(), row.ys.end(), targetMin) - row.ys.begin());\n        int iR = (int)(upper_bound(row.ys.begin(), row.ys.end(), r.T) - row.ys.begin()) - 1;\n        if (iL > iR) return {0, r.T};\n        long long best = 0, run = 0;\n        int bestT = r.T;\n        for (int i = iR; i >= iL; --i) {\n            run += - (long long)row_sum_idx(i, r.L, r.R);\n            if (run > best) {\n                best = run;\n                int newT = row.ys[i] - 1;\n                if (newT < targetMin) newT = targetMin;\n                bestT = newT;\n            }\n        }\n        return {best, bestT};\n    }\n\n    // Greedy improvement loop\n    Rect refine(Rect r) const {\n        r.ensure_min_size();\n        long long curPerim = r.perim();\n        long long curScore = rect_sum(r);\n\n        // Loop until no improvement or iteration cap reached\n        for (int it = 0; it < 200; ++it) {\n            // Compute 8 candidates\n            array<long long, 8> delta{};\n            array<int, 8> newCoord{};\n            // 0:L+, 1:L-, 2:R+, 3:R-, 4:B+, 5:B-, 6:T+, 7:T-\n            // where + means expand outward, - means shrink inward\n            auto [d0, nl0] = best_expand_left(r, curPerim);\n            delta[0] = d0; newCoord[0] = nl0;\n            auto [d1, nl1] = best_shrink_left(r);\n            delta[1] = d1; newCoord[1] = nl1;\n\n            auto [d2, nr2] = best_expand_right(r, curPerim);\n            delta[2] = d2; newCoord[2] = nr2;\n            auto [d3, nr3] = best_shrink_right(r);\n            delta[3] = d3; newCoord[3] = nr3;\n\n            auto [d4, nb4] = best_expand_bottom(r, curPerim);\n            delta[4] = d4; newCoord[4] = nb4;\n            auto [d5, nb5] = best_shrink_bottom(r);\n            delta[5] = d5; newCoord[5] = nb5;\n\n            auto [d6, nt6] = best_expand_top(r, curPerim);\n            delta[6] = d6; newCoord[6] = nt6;\n            auto [d7, nt7] = best_shrink_top(r);\n            delta[7] = d7; newCoord[7] = nt7;\n\n            long long bestDelta = 0;\n            int bestMove = -1;\n            for (int k = 0; k < 8; ++k) {\n                if (delta[k] > bestDelta) {\n                    bestDelta = delta[k];\n                    bestMove = k;\n                }\n            }\n            if (bestDelta <= 0) break; // no improvement\n\n            // Commit the best move\n            if (bestMove == 0) { // expand left\n                int oldL = r.L;\n                r.L = newCoord[0];\n                curPerim += 2LL * (oldL - r.L);\n            } else if (bestMove == 1) { // shrink left\n                int oldL = r.L;\n                r.L = newCoord[1];\n                curPerim -= 2LL * (r.L - oldL);\n            } else if (bestMove == 2) { // expand right\n                int oldR = r.R;\n                r.R = newCoord[2];\n                curPerim += 2LL * (r.R - oldR);\n            } else if (bestMove == 3) { // shrink right\n                int oldR = r.R;\n                r.R = newCoord[3];\n                curPerim -= 2LL * (oldR - r.R);\n            } else if (bestMove == 4) { // expand bottom\n                int oldB = r.B;\n                r.B = newCoord[4];\n                curPerim += 2LL * (oldB - r.B);\n            } else if (bestMove == 5) { // shrink bottom\n                int oldB = r.B;\n                r.B = newCoord[5];\n                curPerim -= 2LL * (r.B - oldB);\n            } else if (bestMove == 6) { // expand top\n                int oldT = r.T;\n                r.T = newCoord[6];\n                curPerim += 2LL * (r.T - oldT);\n            } else if (bestMove == 7) { // shrink top\n                int oldT = r.T;\n                r.T = newCoord[7];\n                curPerim -= 2LL * (oldT - r.T);\n            }\n            // Keep within bounds and minimal size\n            r.ensure_min_size();\n\n            // Update score\n            curScore += bestDelta;\n        }\n        // sanity clamp to perimeter\n        if (r.perim() > PERIM_LIMIT) {\n            // In rare case of numerical mismatch, shrink uniformly to fit\n            while (r.perim() > PERIM_LIMIT && r.R - r.L > 1) --r.R;\n            while (r.perim() > PERIM_LIMIT && r.T - r.B > 1) --r.T;\n        }\n        r.ensure_min_size();\n        return r;\n    }\n};\n\n// Coarse grid maximum submatrix (Kadane O(G^3))\nRect coarse_best_rect(const vector<Pt>& pts, int G) {\n    const long long T = 100001; // number of integer coordinates (0..100000 inclusive)\n    // Build weights grid\n    vector<vector<int>> W(G, vector<int>(G, 0));\n    for (const auto& p : pts) {\n        int xi = (int)((long long)p.x * G / T);\n        int yi = (int)((long long)p.y * G / T);\n        if (xi < 0) xi = 0;\n        if (xi >= G) xi = G - 1;\n        if (yi < 0) yi = 0;\n        if (yi >= G) yi = G - 1;\n        W[yi][xi] += p.w;\n    }\n\n    // Kadane over rows\n    long long bestSum = LLONG_MIN;\n    int bestL = 0, bestR = G - 1, bestB = 0, bestT = G - 1;\n\n    vector<int> acc(G);\n    for (int top = 0; top < G; ++top) {\n        fill(acc.begin(), acc.end(), 0);\n        for (int bot = top; bot < G; ++bot) {\n            for (int j = 0; j < G; ++j) acc[j] += W[bot][j];\n\n            // 1D Kadane that works for all-negative\n            long long cur = LLONG_MIN;\n            long long sum = 0;\n            int curL = 0;\n            for (int j = 0; j < G; ++j) {\n                if (j == 0) {\n                    sum = acc[j];\n                    curL = 0;\n                } else {\n                    if (sum <= 0) {\n                        sum = acc[j];\n                        curL = j;\n                    } else {\n                        sum += acc[j];\n                    }\n                }\n                if (cur == LLONG_MIN || sum > cur) {\n                    cur = sum;\n                }\n            }\n\n            // To also keep track of best indices, re-run Kadane while storing positions\n            long long best1D = LLONG_MIN, s = 0;\n            int start = 0, l = 0, r = -1;\n            for (int j = 0; j < G; ++j) {\n                if (s <= 0) {\n                    s = acc[j];\n                    start = j;\n                } else {\n                    s += acc[j];\n                }\n                if (best1D == LLONG_MIN || s > best1D) {\n                    best1D = s;\n                    l = start;\n                    r = j;\n                }\n            }\n\n            if (best1D > bestSum) {\n                bestSum = best1D;\n                bestL = l; bestR = r; bestB = top; bestT = bot;\n            }\n        }\n    }\n\n    // Map grid indices to world coordinates using exact partition of [0..100000]\n    auto grid_left = [&](int i)->int {\n        return (int)(((long long)i * 100001) / G);\n    };\n    auto grid_right = [&](int i)->int {\n        long long val = ((long long)(i + 1) * 100001) / G - 1;\n        if (val < 0) val = 0;\n        if (val > LIM) val = LIM;\n        return (int)val;\n    };\n\n    Rect r;\n    r.L = grid_left(bestL);\n    r.R = grid_right(bestR);\n    r.B = grid_left(bestB); // same mapping for y\n    r.T = grid_right(bestT);\n    r.ensure_min_size();\n    return r;\n}\n\n// Compute exact score inside rectangle by scanning points\nlong long exact_rect_score(const Rect& r, const vector<Pt>& pts) {\n    long long s = 0;\n    for (const auto& p : pts) {\n        if (r.L <= p.x && p.x <= r.R && r.B <= p.y && p.y <= r.T) {\n            s += p.w;\n        }\n    }\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N;\n    if (!(cin >> N)) {\n        return 0;\n    }\n    vector<Pt> pts;\n    pts.reserve(2 * N);\n    for (int i = 0; i < N; ++i) {\n        int x, y; cin >> x >> y;\n        pts.push_back({x, y, +1});\n    }\n    for (int i = 0; i < N; ++i) {\n        int x, y; cin >> x >> y;\n        pts.push_back({x, y, -1});\n    }\n\n    // Preprocess columns (by x) and rows (by y)\n    vector<int> allX, allY;\n    allX.reserve(pts.size());\n    allY.reserve(pts.size());\n    for (auto &p : pts) { allX.push_back(p.x); allY.push_back(p.y); }\n    sort(allX.begin(), allX.end());\n    sort(allY.begin(), allY.end());\n    allX.erase(unique(allX.begin(), allX.end()), allX.end());\n    allY.erase(unique(allY.begin(), allY.end()), allY.end());\n\n    ColData col;\n    col.xs = allX;\n    col.ys.assign(col.xs.size(), {});\n    col.pref.assign(col.xs.size(), {});\n    RowData row;\n    row.ys = allY;\n    row.xs.assign(row.ys.size(), {});\n    row.pref.assign(row.ys.size(), {});\n\n    // Build mapping indices\n    // We'll use lower_bound per point (log factor is fine)\n    for (const auto& p : pts) {\n        int xi = (int)(lower_bound(col.xs.begin(), col.xs.end(), p.x) - col.xs.begin());\n        int yi = (int)(lower_bound(row.ys.begin(), row.ys.end(), p.y) - row.ys.begin());\n        // Append to both sides\n        col.ys[xi].push_back(p.y);\n        // Use weight vector later; We'll build pref after sorting by y\n        // For rows:\n        row.xs[yi].push_back(p.x);\n    }\n\n    // We need to store weights aligned with coords. Since multiple points can share same x and y across categories, but each coordinate pair is distinct.\n    // We will rebuild with weights by merging duplicates at identical (fixed axis coord, varying other axis coord).\n    // Approach: For each x, we need a map y->sumw at that x; For each y, a map x->sumw at that y.\n\n    // Build dictionary: For columns\n    {\n        // For each x, gather vector of pair<y,w>\n        vector<vector<pair<int,int>>> temp(col.xs.size());\n        temp.assign(col.xs.size(), {});\n        for (const auto& p : pts) {\n            int xi = (int)(lower_bound(col.xs.begin(), col.xs.end(), p.x) - col.xs.begin());\n            temp[xi].emplace_back(p.y, p.w);\n        }\n        for (size_t i = 0; i < col.xs.size(); ++i) {\n            auto &vec = temp[i];\n            if (vec.empty()) { col.ys[i].clear(); col.pref[i].clear(); continue; }\n            sort(vec.begin(), vec.end());\n            // Merge same y\n            vector<int> ysMerged;\n            vector<int> wsMerged;\n            ysMerged.reserve(vec.size());\n            wsMerged.reserve(vec.size());\n            for (size_t k = 0; k < vec.size(); ) {\n                int y = vec[k].first;\n                int s = 0;\n                size_t k2 = k;\n                while (k2 < vec.size() && vec[k2].first == y) {\n                    s += vec[k2].second;\n                    ++k2;\n                }\n                ysMerged.push_back(y);\n                wsMerged.push_back(s);\n                k = k2;\n            }\n            col.ys[i] = move(ysMerged);\n            col.pref[i].assign(wsMerged.size() + 1, 0);\n            for (size_t t = 0; t < wsMerged.size(); ++t) {\n                col.pref[i][t+1] = col.pref[i][t] + wsMerged[t];\n            }\n        }\n    }\n    // Build dictionary: For rows\n    {\n        vector<vector<pair<int,int>>> temp(row.ys.size());\n        temp.assign(row.ys.size(), {});\n        for (const auto& p : pts) {\n            int yi = (int)(lower_bound(row.ys.begin(), row.ys.end(), p.y) - row.ys.begin());\n            temp[yi].emplace_back(p.x, p.w);\n        }\n        for (size_t i = 0; i < row.ys.size(); ++i) {\n            auto &vec = temp[i];\n            if (vec.empty()) { row.xs[i].clear(); row.pref[i].clear(); continue; }\n            sort(vec.begin(), vec.end());\n            vector<int> xsMerged;\n            vector<int> wsMerged;\n            xsMerged.reserve(vec.size());\n            wsMerged.reserve(vec.size());\n            for (size_t k = 0; k < vec.size(); ) {\n                int x = vec[k].first;\n                int s = 0;\n                size_t k2 = k;\n                while (k2 < vec.size() && vec[k2].first == x) {\n                    s += vec[k2].second;\n                    ++k2;\n                }\n                xsMerged.push_back(x);\n                wsMerged.push_back(s);\n                k = k2;\n            }\n            row.xs[i] = move(xsMerged);\n            row.pref[i].assign(wsMerged.size() + 1, 0);\n            for (size_t t = 0; t < wsMerged.size(); ++t) {\n                row.pref[i][t+1] = row.pref[i][t] + wsMerged[t];\n            }\n        }\n    }\n\n    Refiner ref(col, row);\n\n    // Candidate rectangles:\n    vector<Rect> candidates;\n\n    // Full area candidate\n    Rect full; full.L = 0; full.R = LIM; full.B = 0; full.T = LIM;\n    full.ensure_min_size();\n    candidates.push_back(full);\n\n    // Coarse grid candidates\n    vector<int> Gs = {64, 96, 128};\n    for (int G : Gs) {\n        Rect r = coarse_best_rect(pts, G);\n        r.ensure_min_size();\n        candidates.push_back(r);\n    }\n\n    // Refine candidates and pick best by exact score\n    Rect bestRect = full;\n    long long bestScore = exact_rect_score(full, pts);\n    // Try refining full-area by shrinking (start refine)\n    {\n        Rect refined = ref.refine(full);\n        long long sc = exact_rect_score(refined, pts);\n        if (sc > bestScore) {\n            bestScore = sc; bestRect = refined;\n        }\n    }\n    for (size_t i = 1; i < candidates.size(); ++i) {\n        Rect seed = candidates[i];\n        // Ensure perimeter initially within limit; if not, shrink to fit\n        if (seed.perim() > PERIM_LIMIT) {\n            // Shrink on the larger dimension\n            while (seed.perim() > PERIM_LIMIT && seed.R - seed.L > 1) --seed.R;\n            while (seed.perim() > PERIM_LIMIT && seed.T - seed.B > 1) --seed.T;\n            seed.ensure_min_size();\n        }\n        Rect refined = ref.refine(seed);\n        long long sc = exact_rect_score(refined, pts);\n        if (sc > bestScore) {\n            bestScore = sc; bestRect = refined;\n        }\n    }\n\n    // As a safety: if bestScore < 0, fallback to full area (score 0 + 1 in judge)\n    if (bestScore < 0) bestRect = full;\n\n    // Output a 4-vertex rectangle polygon\n    // Vertices must be distinct and polygon non-self-intersecting.\n    // Use counterclockwise order.\n    cout << 4 << '\\n';\n    cout << bestRect.L << ' ' << bestRect.B << '\\n';\n    cout << bestRect.R << ' ' << bestRect.B << '\\n';\n    cout << bestRect.R << ' ' << bestRect.T << '\\n';\n    cout << bestRect.L << ' ' << bestRect.T << '\\n';\n\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Op {\n    int p;   // rectangle index\n    int r;   // rotation 0/1\n    char d;  // 'U' or 'L'\n    int b;   // base rectangle index or -1\n};\n\nstruct Column {\n    long long cw;   // column width (top rectangle width in its chosen rotation)\n    long long ch;   // accumulated height in this column\n    int top_id;     // top row rectangle id (first U in this column)\n    int last_id;    // last rectangle id placed in this column\n};\n\nstruct Param {\n    double lamW;            // weight for width increase\n    double lamH;            // weight for height increase (H overflow)\n    long long fudge;        // capacity reduction margin when checking fit\n    double newColBias;      // negative value makes new column more attractive\n    unsigned tieRand;       // random tie breaker seed\n};\n\nstruct PlanResult {\n    vector<Op> ops;\n    long long W_est;\n    long long H_est;\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\n// Build one plan using greedy column stacking\nPlanResult build_plan(\n    const vector<long long>& wp, const vector<long long>& hp,\n    const Param& P\n){\n    int N = (int)wp.size();\n    vector<Op> ops; ops.reserve(N);\n\n    vector<Column> cols;\n    cols.reserve(N);\n\n    long long W = 0;\n    long long H = 0;\n    int lastTopId = -1;\n\n    // rng for tie-breaking\n    uint64_t rng = splitmix64(P.tieRand + 0x123456789abcdefULL);\n\n    for (int i = 0; i < N; ++i) {\n        long long w0 = wp[i], h0 = hp[i];\n        long long w1 = h0, h1 = w0; // rotated\n\n        // Candidate stacking to existing columns\n        int bestCol = -1;\n        int bestRotStack = 0; // 0 or 1\n        long long bestNewColHeight = LLONG_MAX; // ch[j] + height\n        for (int j = 0; j < (int)cols.size(); ++j) {\n            long long cap = cols[j].cw - P.fudge;\n            if (cap < 0) cap = 0;\n            bool fit0 = (w0 <= cap);\n            bool fit1 = (w1 <= cap);\n            if (!fit0 && !fit1) continue;\n            int rot = -1;\n            long long hAdd = LLONG_MAX;\n            if (fit0 && fit1) {\n                // choose rotation that minimizes height\n                if (h0 < h1) { rot = 0; hAdd = h0; }\n                else if (h1 < h0) { rot = 1; hAdd = h1; }\n                else {\n                    // equal heights, break tie by smaller width to be safe\n                    if (w0 <= w1) { rot = 0; hAdd = h0; }\n                    else { rot = 1; hAdd = h1; }\n                }\n            } else if (fit0) { rot = 0; hAdd = h0; }\n            else { rot = 1; hAdd = h1; }\n            long long newColH = cols[j].ch + hAdd;\n            if (newColH < bestNewColHeight) {\n                bestNewColHeight = newColH;\n                bestCol = j;\n                bestRotStack = rot;\n            } else if (newColH == bestNewColHeight && bestCol != -1) {\n                // tie-break: prefer the column with smaller current height\n                // and tiny randomness\n                long long curBestH = cols[bestCol].ch;\n                long long curH = cols[j].ch;\n                if (curH < curBestH) {\n                    bestCol = j;\n                    bestRotStack = rot;\n                } else if (curH == curBestH) {\n                    rng = splitmix64(rng);\n                    if ((rng & 1ULL) == 0ULL) {\n                        bestCol = j;\n                        bestRotStack = rot;\n                    }\n                }\n            }\n        }\n\n        // Evaluate stacking delta\n        double stackDelta = 1e100;\n        int chosenStackRot = 0;\n        if (bestCol != -1) {\n            long long hAdd = (bestRotStack == 0 ? h0 : h1);\n            long long newH = max(H, bestNewColHeight);\n            long long dH = newH - H;\n            stackDelta = P.lamH * (double)dH; // W doesn't change\n            chosenStackRot = bestRotStack;\n        }\n\n        // Evaluate opening new column (both rotations)\n        double newColDelta = 1e100;\n        int chosenNewRot = 0;\n        long long chosenNewCW = 0, chosenNewCH = 0;\n        // rotation 0\n        {\n            long long addW = w0;\n            long long newCH = h0;\n            long long dH = max(0LL, newCH - H);\n            double s = P.lamW * (double)addW + P.lamH * (double)dH + P.newColBias;\n            newColDelta = s;\n            chosenNewRot = 0;\n            chosenNewCW = w0;\n            chosenNewCH = h0;\n        }\n        // rotation 1\n        {\n            long long addW = w1;\n            long long newCH = h1;\n            long long dH = max(0LL, newCH - H);\n            double s = P.lamW * (double)addW + P.lamH * (double)dH + P.newColBias;\n            if (s < newColDelta - 1e-12) {\n                newColDelta = s;\n                chosenNewRot = 1;\n                chosenNewCW = w1;\n                chosenNewCH = h1;\n            }\n        }\n\n        // Choose the better option\n        if (bestCol != -1 && stackDelta <= newColDelta) {\n            // Stack on bestCol\n            int rot = chosenStackRot;\n            Op op;\n            op.p = i;\n            op.r = rot;\n            op.d = 'L';\n            op.b = cols[bestCol].last_id;\n            ops.push_back(op);\n\n            long long hAdd = (rot == 0 ? h0 : h1);\n            cols[bestCol].ch += hAdd;\n            cols[bestCol].last_id = i;\n            H = max(H, cols[bestCol].ch);\n        } else {\n            // Open a new column with U\n            int rot = chosenNewRot;\n            Op op;\n            op.p = i;\n            op.r = rot;\n            op.d = 'U';\n            op.b = (lastTopId == -1 ? -1 : lastTopId);\n            ops.push_back(op);\n\n            Column c;\n            c.cw = chosenNewCW;\n            c.ch = chosenNewCH;\n            c.top_id = i;\n            c.last_id = i;\n            cols.push_back(c);\n\n            lastTopId = i;\n            W += chosenNewCW;\n            H = max(H, chosenNewCH);\n        }\n    }\n\n    return {ops, W, H};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    long long sigma;\n    if (!(cin >> N >> T >> sigma)) return 0;\n    vector<long long> wp(N), hp(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> wp[i] >> hp[i];\n    }\n\n    // Predefined parameter sets to diversify attempts\n    vector<Param> presets;\n    // Basic balanced\n    presets.push_back({1.0, 1.0, 0, 0.0, 1234567});\n    // Favor fewer columns slightly\n    presets.push_back({0.8, 1.2, 0, 0.0, 2345678});\n    // Favor more columns (reduce H) slightly\n    presets.push_back({1.2, 0.8, 0, 0.0, 3456789});\n    // Add margins proportional to sigma\n    presets.push_back({1.0, 1.0, (long long)(sigma / 4), 0.0, 4567890});\n    presets.push_back({1.0, 1.0, (long long)(sigma / 2), 0.0, 5678901});\n    // Encourage new columns with small bias\n    presets.push_back({1.0, 1.0, 0, - (double)(sigma) * 0.05, 6789012});\n    // Mixed: weight width more, and margin\n    presets.push_back({1.3, 0.9, (long long)(sigma / 3), 0.0, 7890123});\n    // Mixed: weight height more, and margin\n    presets.push_back({0.9, 1.3, (long long)(sigma / 3), 0.0, 8901234});\n    // Negative margin (optimistic fit)\n    presets.push_back({1.0, 1.0, - (long long)(sigma / 4), 0.0, 9012345});\n    // Heavier column bias\n    presets.push_back({1.1, 0.9, 0, - (double)(sigma) * 0.10, 9123456});\n\n    // Random jitter around presets if T is large\n    std::mt19937_64 rng(123456789);\n    std::uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    for (int t = 0; t < T; ++t) {\n        Param P;\n        if (t < (int)presets.size()) {\n            P = presets[t];\n        } else {\n            // randomize around a base\n            Param B = presets[t % presets.size()];\n            double j1 = (uni01(rng) - 0.5) * 0.4; // +-20%\n            double j2 = (uni01(rng) - 0.5) * 0.4;\n            P.lamW = max(0.2, B.lamW * (1.0 + j1));\n            P.lamH = max(0.2, B.lamH * (1.0 + j2));\n            long long fj = (long long)((uni01(rng) - 0.5) * sigma); // ~[-0.5sigma,0.5sigma]\n            P.fudge = B.fudge + fj / 4;\n            P.newColBias = B.newColBias + (uni01(rng) - 0.5) * (sigma * 0.05);\n            P.tieRand = (unsigned)rng();\n        }\n\n        PlanResult res = build_plan(wp, hp, P);\n\n        // Optional comment line for debugging\n        cout << \"# est_W \" << res.W_est << \" est_H \" << res.H_est\n             << \" params lW=\" << fixed << setprecision(2) << P.lamW\n             << \" lH=\" << P.lamH << \" fudge=\" << P.fudge\n             << \" bias=\" << P.newColBias << \"\\n\";\n\n        // Output operations\n        cout << res.ops.size() << \"\\n\";\n        for (auto &op : res.ops) {\n            cout << op.p << \" \" << op.r << \" \" << op.d << \" \" << op.b << \"\\n\";\n        }\n        cout.flush();\n\n        long long Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0; // read and ignore\n        // Optional: could adapt parameters using feedback, but we keep it simple.\n    }\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed_ms() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double, milli>(now - st).count();\n    }\n};\n\nstatic const uint16_t INF16 = (uint16_t)30000;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    if (!(cin >> N >> M >> H)) return 0;\n    vector<int> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n    vector<vector<int>> g(N);\n    vector<pair<int,int>> edges(M);\n    for (int i = 0; i < M; i++) {\n        int u, v; cin >> u >> v;\n        edges[i] = {u, v};\n        g[u].push_back(v);\n        g[v].push_back(u);\n    }\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n    Timer timer;\n    // 1) All-pairs shortest paths via BFS from each node.\n    vector<uint16_t> Dist((size_t)N * (size_t)N, INF16);\n    {\n        vector<int> q; q.reserve(N);\n        vector<int> dist(N);\n        for (int s = 0; s < N; s++) {\n            fill(dist.begin(), dist.end(), -1);\n            q.clear();\n            dist[s] = 0;\n            q.push_back(s);\n            for (size_t qi = 0; qi < q.size(); qi++) {\n                int u = q[qi];\n                for (int v : g[u]) {\n                    if (dist[v] == -1) {\n                        dist[v] = dist[u] + 1;\n                        q.push_back(v);\n                    }\n                }\n            }\n            for (int v = 0; v < N; v++) {\n                Dist[(size_t)s * N + v] = dist[v] >= 0 ? (uint16_t)dist[v] : INF16;\n            }\n        }\n    }\n\n    // Precompute balls within H for each vertex.\n    vector<vector<int>> withinH(N);\n    withinH.reserve(N);\n    for (int u = 0; u < N; u++) {\n        auto &vec = withinH[u];\n        vec.reserve(256);\n        const uint16_t* Du = &Dist[(size_t)u * N];\n        for (int v = 0; v < N; v++) if (Du[v] <= (uint16_t)H) vec.push_back(v);\n    }\n\n    // 2) Build roots with farthest-first until coverage (max dist <= H).\n    vector<int> roots;\n    roots.reserve(64);\n    vector<uint16_t> dR(N, INF16); // min dist to current roots\n    vector<char> isRoot(N, 0);\n\n    // Initial root: choose minimal A to place root in low-beauty area.\n    int s0 = min_element(A.begin(), A.end()) - A.begin();\n    roots.push_back(s0);\n    isRoot[s0] = 1;\n    {\n        const uint16_t* D0 = &Dist[(size_t)s0 * N];\n        for (int v = 0; v < N; v++) dR[v] = D0[v];\n    }\n\n    auto recompute_dR_from_roots = [&](vector<uint16_t> &dRref) {\n        fill(dRref.begin(), dRref.end(), INF16);\n        for (int r : roots) {\n            const uint16_t* Dr = &Dist[(size_t)r * N];\n            for (int v = 0; v < N; v++) {\n                uint16_t dv = Dr[v];\n                if (dv < dRref[v]) dRref[v] = dv;\n            }\n        }\n    };\n\n    // Greedy farthest-first with coverage-aware tie-break.\n    while (true) {\n        uint16_t dmax = 0;\n        int cntUncovered = 0;\n        for (int v = 0; v < N; v++) {\n            if (dR[v] > dmax) dmax = dR[v];\n            if (dR[v] > (uint16_t)H) cntUncovered++;\n        }\n        if (dmax <= (uint16_t)H) break;\n\n        // find all farthest nodes\n        vector<int> far;\n        far.reserve(32);\n        for (int v = 0; v < N; v++) if (dR[v] == dmax) far.push_back(v);\n\n        int bestCand = -1;\n        int bestCover = -1;\n        int bestA = INT_MAX;\n        for (int cand : far) {\n            // coverage over currently uncovered nodes\n            int cover = 0;\n            for (int u : withinH[cand]) {\n                if (dR[u] > (uint16_t)H) cover++;\n            }\n            if (cover > bestCover || (cover == bestCover && A[cand] < bestA)) {\n                bestCover = cover;\n                bestA = A[cand];\n                bestCand = cand;\n            }\n        }\n        if (bestCand == -1) {\n            // Fallback: pick a far one\n            bestCand = far[0];\n        }\n        if (!isRoot[bestCand]) {\n            roots.push_back(bestCand);\n            isRoot[bestCand] = 1;\n            const uint16_t* Dn = &Dist[(size_t)bestCand * N];\n            for (int v = 0; v < N; v++) {\n                uint16_t dv = Dn[v];\n                if (dv < dR[v]) dR[v] = dv;\n            }\n        } else {\n            // Should not happen often; avoid infinite loop\n            // find any uncovered node and add it\n            int cand2 = -1;\n            for (int v = 0; v < N; v++) if (dR[v] > (uint16_t)H) { cand2 = v; break; }\n            if (cand2 == -1) break;\n            roots.push_back(cand2);\n            isRoot[cand2] = 1;\n            const uint16_t* Dn = &Dist[(size_t)cand2 * N];\n            for (int v = 0; v < N; v++) {\n                uint16_t dv = Dn[v];\n                if (dv < dR[v]) dR[v] = dv;\n            }\n        }\n    }\n\n    // 3) Prune redundant roots (remove if safe).\n    auto compute_min1_min2 = [&](vector<uint16_t> &min1, vector<uint16_t> &min2, vector<int> &argmin) {\n        int k = (int)roots.size();\n        min1.assign(N, INF16);\n        min2.assign(N, INF16);\n        argmin.assign(N, -1);\n        for (int idx = 0; idx < k; idx++) {\n            int r = roots[idx];\n            const uint16_t* Dr = &Dist[(size_t)r * N];\n            for (int v = 0; v < N; v++) {\n                uint16_t d = Dr[v];\n                if (d < min1[v]) {\n                    min2[v] = min1[v];\n                    min1[v] = d;\n                    argmin[v] = r;\n                } else if (d < min2[v]) {\n                    min2[v] = d;\n                }\n            }\n        }\n    };\n\n    {\n        bool changed = true;\n        vector<uint16_t> m1, m2;\n        vector<int> arg;\n        while (changed) {\n            changed = false;\n            compute_min1_min2(m1, m2, arg);\n            // Try remove one root if safe\n            for (int i = 0; i < (int)roots.size(); i++) {\n                int r = roots[i];\n                bool safe = true;\n                for (int v = 0; v < N; v++) {\n                    if (arg[v] == r && m2[v] > (uint16_t)H) { safe = false; break; }\n                }\n                if (safe) {\n                    isRoot[r] = 0;\n                    roots.erase(roots.begin() + i);\n                    changed = true;\n                    break;\n                }\n            }\n        }\n        recompute_dR_from_roots(dR);\n    }\n\n    // 4) Local search: 1-1 swap of roots with coverage constraint to improve S = sum A*dist.\n    auto compute_score = [&](const vector<uint16_t> &dRref) -> long long {\n        long long S = 0;\n        for (int v = 0; v < N; v++) {\n            uint16_t d = dRref[v];\n            if (d > (uint16_t)H) d = (uint16_t)H; // should not happen\n            S += 1LL * A[v] * d;\n        }\n        return S;\n    };\n\n    auto recompute_min_data = [&](vector<uint16_t> &m1, vector<uint16_t> &m2, vector<int> &arg) {\n        compute_min1_min2(m1, m2, arg);\n    };\n\n    vector<uint16_t> m1, m2;\n    vector<int> arg;\n    recompute_min_data(m1, m2, arg);\n    long long Scur = compute_score(m1);\n\n    // Pre-allocate helpers for candidate intersection\n    vector<int> mark(N, -1), cnt(N, 0), visited;\n    visited.reserve(N);\n    int stamp = 0;\n\n    // Time/iteration limits for safety\n    int maxIter = 3;\n    for (int iter = 0; iter < maxIter; iter++) {\n        bool improved = false;\n        long long bestDelta = 0;\n        int bestRootIdx = -1;\n        int bestCand = -1;\n\n        // Early exit if close to time limit\n        if (timer.elapsed_ms() > 1500.0) break;\n\n        // Evaluate per root\n        for (int ir = 0; ir < (int)roots.size(); ir++) {\n            int r = roots[ir];\n            // Z_r: vertices that would be uncovered if r removed\n            vector<int> Z;\n            Z.reserve(64);\n            for (int v = 0; v < N; v++) {\n                if (arg[v] == r && m2[v] > (uint16_t)H) Z.push_back(v);\n            }\n\n            vector<int> candList;\n            candList.reserve(256);\n\n            if (Z.empty()) {\n                // Removing r is safe; consider moving it anywhere. To limit time,\n                // restrict candidates to a subset: we take neighbors within H of r,\n                // plus a few random samples if needed.\n                candList = withinH[r];\n                // Optionally add some random candidates (skip for determinism).\n            } else {\n                // Intersection of withinH sets of all v in Z\n                stamp++;\n                visited.clear();\n                for (int v : Z) {\n                    for (int c : withinH[v]) {\n                        if (mark[c] != stamp) { mark[c] = stamp; cnt[c] = 1; visited.push_back(c); }\n                        else cnt[c]++;\n                    }\n                }\n                for (int c : visited) {\n                    if (cnt[c] == (int)Z.size()) candList.push_back(c);\n                }\n                // If empty, no valid replacement for this r; skip\n            }\n\n            if (candList.empty()) continue;\n\n            // Evaluate each candidate c\n            // We can skip c equal to r (no change)\n            for (int c : candList) {\n                if (c == r) continue;\n                // Compute new score S' using d' = min(d_without_r, dist(c, v))\n                long long Snew = 0;\n                const uint16_t* Dc = &Dist[(size_t)c * N];\n                bool coverOK = true; // should be guaranteed by candList construction\n                for (int v = 0; v < N; v++) {\n                    uint16_t d_without = (arg[v] == r ? m2[v] : m1[v]);\n                    uint16_t dv = Dc[v];\n                    uint16_t dprime = dv < d_without ? dv : d_without;\n                    if (dprime > (uint16_t)H) { coverOK = false; break; }\n                    Snew += 1LL * A[v] * dprime;\n                }\n                if (!coverOK) continue;\n                long long delta = Snew - Scur;\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestRootIdx = ir;\n                    bestCand = c;\n                }\n            }\n        }\n\n        if (bestDelta > 0 && bestRootIdx != -1) {\n            int oldr = roots[bestRootIdx];\n            isRoot[oldr] = 0;\n            roots[bestRootIdx] = bestCand;\n            isRoot[bestCand] = 1;\n            recompute_min_data(m1, m2, arg);\n            Scur = compute_score(m1);\n            improved = true;\n        }\n\n        if (!improved) break;\n    }\n\n    // As a final cleanup, try pruning again in case swaps made some roots redundant\n    {\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            recompute_min_data(m1, m2, arg);\n            for (int i = 0; i < (int)roots.size(); i++) {\n                int r = roots[i];\n                bool safe = true;\n                for (int v = 0; v < N; v++) {\n                    if (arg[v] == r && m2[v] > (uint16_t)H) { safe = false; break; }\n                }\n                if (safe) {\n                    isRoot[r] = 0;\n                    roots.erase(roots.begin() + i);\n                    changed = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    // 5) Build parents via multi-source BFS from final roots.\n    vector<int> parent(N, -1);\n    vector<uint16_t> depth(N, INF16);\n    deque<int> dq;\n    for (int r : roots) {\n        depth[r] = 0;\n        parent[r] = -1;\n        dq.push_back(r);\n    }\n    while (!dq.empty()) {\n        int u = dq.front(); dq.pop_front();\n        if (depth[u] >= (uint16_t)H) continue; // do not go deeper than H\n        uint16_t nextd = depth[u] + 1;\n        for (int v : g[u]) {\n            if (depth[v] == INF16) {\n                depth[v] = nextd;\n                parent[v] = u;\n                dq.push_back(v);\n            }\n        }\n    }\n\n    // Safety: if any vertex remains unreachable (shouldn't happen), set it as a root.\n    for (int v = 0; v < N; v++) {\n        if (depth[v] == INF16) {\n            parent[v] = -1;\n            depth[v] = 0;\n        }\n    }\n\n    // Output\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << parent[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Structure to represent a safe cycle action\nstruct Action {\n    char d;       // 'L','R','U','D'\n    int p;        // row/column index\n    int k;        // length (number of shifts each way)\n    int cost;     // 2*k\n    vector<int> cover; // Oni IDs this action removes\n};\n\nstruct Plan {\n    vector<int> indices; // indices into candidate action array\n    int cost = INT_MAX;  // total operations\n};\n\nstatic inline char opposite(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\n// Build candidate actions from initial board, including all k from 1..safe width/height for each side.\n// Each action stores the list of Oni IDs it would remove (i.e., in that edge segment).\nvector<Action> build_candidates(const vector<string>& grid, const vector<pair<int,int>>& oni_pos,\n                                const vector<vector<int>>& oni_id) {\n    int N = grid.size();\n    vector<Action> acts;\n\n    // Precompute safe widths for rows\n    vector<int> Lsafe(N, 0), Rsafe(N, 0);\n    for (int r = 0; r < N; ++r) {\n        int firstF = N, lastF = -1;\n        for (int j = 0; j < N; ++j) if (grid[r][j] == 'o') {\n            firstF = min(firstF, j);\n            lastF = max(lastF, j);\n        }\n        Lsafe[r] = (firstF == N ? N : firstF);\n        Rsafe[r] = (lastF == -1 ? N : (N - 1 - lastF));\n    }\n    // Precompute safe heights for columns\n    vector<int> Usafe(N, 0), Dsafe(N, 0);\n    for (int c = 0; c < N; ++c) {\n        int firstF = N, lastF = -1;\n        for (int i = 0; i < N; ++i) if (grid[i][c] == 'o') {\n            firstF = min(firstF, i);\n            lastF = max(lastF, i);\n        }\n        Usafe[c] = (firstF == N ? N : firstF);\n        Dsafe[c] = (lastF == -1 ? N : (N - 1 - lastF));\n    }\n\n    // Build actions for rows\n    for (int r = 0; r < N; ++r) {\n        // Left: k = 1..Lsafe[r], segment [0..k-1]\n        for (int k = 1; k <= Lsafe[r]; ++k) {\n            vector<int> cov;\n            cov.reserve(k);\n            for (int j = 0; j < k; ++j) {\n                int id = oni_id[r][j];\n                if (id != -1) cov.push_back(id);\n            }\n            if (!cov.empty()) {\n                Action a; a.d = 'L'; a.p = r; a.k = k; a.cost = 2*k; a.cover = move(cov);\n                acts.push_back(move(a));\n            }\n        }\n        // Right: k = 1..Rsafe[r], segment [N-k..N-1]\n        for (int k = 1; k <= Rsafe[r]; ++k) {\n            vector<int> cov;\n            cov.reserve(k);\n            for (int j = N - k; j < N; ++j) {\n                int id = oni_id[r][j];\n                if (id != -1) cov.push_back(id);\n            }\n            if (!cov.empty()) {\n                Action a; a.d = 'R'; a.p = r; a.k = k; a.cost = 2*k; a.cover = move(cov);\n                acts.push_back(move(a));\n            }\n        }\n    }\n    // Build actions for columns\n    for (int c = 0; c < N; ++c) {\n        // Up: k = 1..Usafe[c], segment [0..k-1]\n        for (int k = 1; k <= Usafe[c]; ++k) {\n            vector<int> cov;\n            cov.reserve(k);\n            for (int i = 0; i < k; ++i) {\n                int id = oni_id[i][c];\n                if (id != -1) cov.push_back(id);\n            }\n            if (!cov.empty()) {\n                Action a; a.d = 'U'; a.p = c; a.k = k; a.cost = 2*k; a.cover = move(cov);\n                acts.push_back(move(a));\n            }\n        }\n        // Down: k = 1..Dsafe[c], segment [N-k..N-1]\n        for (int k = 1; k <= Dsafe[c]; ++k) {\n            vector<int> cov;\n            cov.reserve(k);\n            for (int i = N - k; i < N; ++i) {\n                int id = oni_id[i][c];\n                if (id != -1) cov.push_back(id);\n            }\n            if (!cov.empty()) {\n                Action a; a.d = 'D'; a.p = c; a.k = k; a.cost = 2*k; a.cover = move(cov);\n                acts.push_back(move(a));\n            }\n        }\n    }\n    return acts;\n}\n\nint selection_cost(const vector<int>& sel, const vector<Action>& acts) {\n    long long s = 0;\n    for (int idx : sel) s += acts[idx].cost;\n    if (s > INT_MAX) return INT_MAX;\n    return (int)s;\n}\n\nvector<int> prune_selection(vector<int> sel, const vector<Action>& acts, int M) {\n    // Remove redundant actions iteratively\n    vector<int> cover_count(M, 0);\n    for (int idx : sel) {\n        for (int id : acts[idx].cover) cover_count[id]++;\n    }\n    // Sort indices by cost descending to try removing expensive ones first\n    vector<int> order = sel;\n    sort(order.begin(), order.end(), [&](int a, int b){\n        if (acts[a].cost != acts[b].cost) return acts[a].cost > acts[b].cost;\n        return a < b;\n    });\n    vector<char> alive(acts.size(), 0);\n    for (int idx : sel) alive[idx] = 1;\n\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        for (int idx : order) {\n            if (!alive[idx]) continue;\n            bool canRemove = true;\n            for (int id : acts[idx].cover) {\n                if (cover_count[id] <= 1) { canRemove = false; break; }\n            }\n            if (canRemove) {\n                for (int id : acts[idx].cover) cover_count[id]--;\n                alive[idx] = 0;\n                changed = true;\n            }\n        }\n    }\n    vector<int> res;\n    res.reserve(sel.size());\n    for (int idx : sel) if (alive[idx]) res.push_back(idx);\n    return res;\n}\n\nvector<int> greedy_select(const vector<Action>& acts, int M, std::mt19937& rng) {\n    int A = (int)acts.size();\n    vector<int> order(A);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n\n    vector<char> covered(M, 0);\n    int remaining = M;\n    vector<int> sel;\n    sel.reserve(M);\n\n    // Quick map from randomized order to tie-breaking index\n    vector<int> rank_in_order(A, 0);\n    for (int i = 0; i < A; ++i) rank_in_order[order[i]] = i;\n\n    while (remaining > 0) {\n        int best = -1;\n        long long best_cost = 1;\n        long long best_gain = 0; // store comparator by cost/gain\n        for (int a = 0; a < A; ++a) {\n            // compute gain\n            int gain = 0;\n            for (int id : acts[a].cover) if (!covered[id]) gain++;\n            if (gain <= 0) continue;\n            long long cost = acts[a].cost;\n            if (best == -1) {\n                best = a; best_cost = cost; best_gain = gain;\n            } else {\n                // Compare cost/gain\n                // cost/gain < best_cost/best_gain  <=> cost*best_gain < best_cost*gain\n                long long lhs = cost * best_gain;\n                long long rhs = best_cost * (long long)gain;\n                if (lhs < rhs) {\n                    best = a; best_cost = cost; best_gain = gain;\n                } else if (lhs == rhs) {\n                    if (cost < best_cost) {\n                        best = a; best_cost = cost; best_gain = gain;\n                    } else if (cost == best_cost) {\n                        // tie-break by randomized order (earlier is preferred)\n                        if (rank_in_order[a] < rank_in_order[best]) {\n                            best = a; best_cost = cost; best_gain = gain;\n                        }\n                    }\n                }\n            }\n        }\n        if (best == -1) {\n            // Shouldn't happen if coverage is complete; break to avoid infinite loop.\n            break;\n        }\n        // Select best\n        sel.push_back(best);\n        for (int id : acts[best].cover) if (!covered[id]) { covered[id] = 1; --remaining; }\n    }\n    // Prune redundant sets\n    sel = prune_selection(sel, acts, M);\n    return sel;\n}\n\nvector<int> local_improvement(vector<int> sel, const vector<Action>& acts, int M, std::mt19937& rng, int iters=200) {\n    int A = (int)acts.size();\n    vector<char> inSel(A, 0);\n    for (int idx : sel) inSel[idx] = 1;\n    int bestCost = selection_cost(sel, acts);\n\n    for (int it = 0; it < iters; ++it) {\n        // pick a random candidate not in selection\n        int tries = 0;\n        int b = -1;\n        while (tries < 10) {\n            int x = rng() % A;\n            if (!inSel[x]) { b = x; break; }\n            ++tries;\n        }\n        if (b == -1) continue;\n        // Try adding and prune\n        vector<int> trial = sel;\n        trial.push_back(b);\n        trial = prune_selection(move(trial), acts, M);\n        int cst = selection_cost(trial, acts);\n        if (cst < bestCost) {\n            // improved\n            sel.swap(trial);\n            fill(inSel.begin(), inSel.end(), 0);\n            for (int idx : sel) inSel[idx] = 1;\n            bestCost = cst;\n        }\n    }\n    return sel;\n}\n\n// Build baseline per-Oni plan (simple safe cycle per Oni with minimal k).\n// Always <= 840 operations for N=20.\nvector<Action> build_baseline_actions(const vector<string>& grid,\n                                      const vector<pair<int,int>>& oni_pos) {\n    int N = grid.size();\n    vector<Action> acts;\n    acts.reserve(oni_pos.size());\n\n    // Precompute Fukunokami presence for fast direction checks\n    vector<vector<int>> fuku_row_prefix(N, vector<int>(N+1, 0));\n    vector<vector<int>> fuku_col_prefix(N, vector<int>(N+1, 0));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            fuku_row_prefix[i][j+1] = fuku_row_prefix[i][j] + (grid[i][j] == 'o');\n            fuku_col_prefix[j][i+1] = fuku_col_prefix[j][i] + (grid[i][j] == 'o');\n        }\n    }\n    auto no_fuku_row = [&](int r, int l, int rgt) -> bool { // inclusive l..rgt\n        if (l > rgt) return true;\n        return (fuku_row_prefix[r][rgt+1] - fuku_row_prefix[r][l]) == 0;\n    };\n    auto no_fuku_col = [&](int c, int top, int bot) -> bool {\n        if (top > bot) return true;\n        return (fuku_col_prefix[c][bot+1] - fuku_col_prefix[c][top]) == 0;\n    };\n\n    for (auto [i, j] : oni_pos) {\n        vector<pair<int,pair<char,int>>> cand; // cost, (dir, k)\n        // Up\n        if (no_fuku_col(j, 0, i-1)) {\n            int k = i + 1;\n            cand.push_back({2*k, {'U', k}});\n        }\n        // Down\n        if (no_fuku_col(j, i+1, N-1)) {\n            int k = N - i;\n            cand.push_back({2*k, {'D', k}});\n        }\n        // Left\n        if (no_fuku_row(i, 0, j-1)) {\n            int k = j + 1;\n            cand.push_back({2*k, {'L', k}});\n        }\n        // Right\n        if (no_fuku_row(i, j+1, N-1)) {\n            int k = N - j;\n            cand.push_back({2*k, {'R', k}});\n        }\n        if (cand.empty()) continue; // should not happen due to guarantees\n        // choose minimal cost\n        auto best = min_element(cand.begin(), cand.end(),\n                                [](auto& a, auto& b){ return a.first < b.first; });\n        Action a; a.d = best->second.first; a.p = (a.d == 'L' || a.d == 'R') ? i : j; a.k = best->second.second; a.cost = best->first;\n        acts.push_back(move(a));\n    }\n    return acts;\n}\n\n// Convert action list (selected indices) to the list of primitive operations\nvector<pair<char,int>> actions_to_ops(const vector<int>& sel, const vector<Action>& acts) {\n    vector<pair<char,int>> ops;\n    long long total = 0;\n    for (int idx : sel) total += acts[idx].cost;\n    ops.reserve((size_t)total);\n    for (int idx : sel) {\n        const auto& a = acts[idx];\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(a.d, a.p);\n        char od = opposite(a.d);\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(od, a.p);\n    }\n    return ops;\n}\nvector<pair<char,int>> actions_to_ops_direct(const vector<Action>& acts) {\n    vector<pair<char,int>> ops;\n    long long total = 0;\n    for (auto& a : acts) total += a.cost;\n    ops.reserve((size_t)total);\n    for (auto& a : acts) {\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(a.d, a.p);\n        char od = opposite(a.d);\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(od, a.p);\n    }\n    return ops;\n}\n\n// Simulator for verification\npair<int,int> simulate(const vector<string>& init, const vector<pair<char,int>>& ops) {\n    int N = init.size();\n    vector<string> g = init;\n    int rem_oni = 0, rem_fuku = 0;\n    for (auto& row : g) {\n        for (char ch : row) {\n            if (ch == 'x') rem_oni++;\n            else if (ch == 'o') rem_fuku++;\n        }\n    }\n    int removed_oni = 0, removed_fuku = 0;\n    for (auto [d,p] : ops) {\n        if (d == 'L') {\n            char out = g[p][0];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int j = 0; j < N-1; ++j) g[p][j] = g[p][j+1];\n            g[p][N-1] = '.';\n        } else if (d == 'R') {\n            char out = g[p][N-1];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\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            char out = g[0][p];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int i = 0; i < N-1; ++i) g[i][p] = g[i+1][p];\n            g[N-1][p] = '.';\n        } else { // 'D'\n            char out = g[N-1][p];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int i = N-1; i >= 1; --i) g[i][p] = g[i-1][p];\n            g[0][p] = '.';\n        }\n    }\n    int X = rem_oni - removed_oni;\n    int Y = removed_fuku;\n    return {X, Y};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n\n    // Collect Oni positions and ID map\n    vector<pair<int,int>> oni_pos;\n    vector<vector<int>> oni_id(N, vector<int>(N, -1));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (grid[i][j] == 'x') {\n                int id = (int)oni_pos.size();\n                oni_pos.emplace_back(i, j);\n                oni_id[i][j] = id;\n            }\n        }\n    }\n    int M = (int)oni_pos.size();\n\n    // Build candidates and run greedy multi-start with pruning and local improvement\n    vector<Action> candidates = build_candidates(grid, oni_pos, oni_id);\n\n    std::mt19937 rng(712367 + (uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    Plan bestPlan;\n    bestPlan.cost = INT_MAX;\n\n    int trials = 20; // number of random greedy restarts\n    for (int t = 0; t < trials; ++t) {\n        vector<int> sel = greedy_select(candidates, M, rng);\n        sel = local_improvement(sel, candidates, M, rng, 150);\n        int cst = selection_cost(sel, candidates);\n        if (cst < bestPlan.cost) {\n            bestPlan.indices = sel;\n            bestPlan.cost = cst;\n        }\n    }\n\n    // Build baseline plan as a fallback and also to compare\n    vector<Action> baselineActs = build_baseline_actions(grid, oni_pos);\n    int baselineCost = 0; for (auto& a : baselineActs) baselineCost += a.cost;\n\n    // Choose the better of greedy and baseline\n    vector<pair<char,int>> opsGreedy = actions_to_ops(bestPlan.indices, candidates);\n    auto checkGreedy = simulate(grid, opsGreedy);\n    bool greedyValid = (checkGreedy.second == 0); // Y == 0\n    // baseline\n    vector<pair<char,int>> opsBase = actions_to_ops_direct(baselineActs);\n    auto checkBase = simulate(grid, opsBase);\n    bool baseValid = (checkBase.second == 0);\n\n    // Prefer valid plans; among valid, choose fewer operations\n    vector<pair<char,int>> ops;\n    if (greedyValid && baseValid) {\n        if ((int)opsGreedy.size() <= (int)opsBase.size()) ops = move(opsGreedy);\n        else ops = move(opsBase);\n    } else if (greedyValid) {\n        ops = move(opsGreedy);\n    } else if (baseValid) {\n        ops = move(opsBase);\n    } else {\n        // As a last resort (shouldn't happen), output no moves\n        ops.clear();\n    }\n\n    // Output operations, one per line: \"d p\"\n    // Ensure not exceeding 4N^2 = 1600\n    if ((int)ops.size() > 4*N*N) {\n        // Truncate (shouldn't happen). But truncation may be invalid; better output baseline if valid and smaller.\n        if (baseValid && (int)opsBase.size() <= 4*N*N) {\n            ops = move(opsBase);\n        } else if (greedyValid && (int)opsGreedy.size() <= 4*N*N) {\n            ops = move(opsGreedy);\n        } else {\n            // emergency: no output\n            ops.clear();\n        }\n    }\n    for (auto &op : ops) {\n        cout << op.first << ' ' << op.second << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed_ms() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double, std::milli>(now - st).count();\n    }\n};\n\nstruct Candidate {\n    vector<int> a, b;\n    long long E = (1LL<<62);\n    vector<int> t;\n};\n\n// Build ascending-T cycle for a-edges, with random tie-breaking within equal T.\n// Also compute D[j] = 2*T[j] - T[prev_of_j_in_cycle], guaranteed >= 0 by ascending order.\nstatic void build_cycle_and_residuals(const vector<int>& T, mt19937_64 &rng,\n                                      vector<int>& a, vector<long long>& D,\n                                      vector<int>& order, vector<int>& pos) {\n    int N = (int)T.size();\n    order.resize(N);\n    iota(order.begin(), order.end(), 0);\n    // Random tie-breaking: shuffle then stable-sort by T\n    shuffle(order.begin(), order.end(), rng);\n    stable_sort(order.begin(), order.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    pos.assign(N, -1);\n    for (int k = 0; k < N; ++k) pos[order[k]] = k;\n\n    a.assign(N, 0);\n    D.assign(N, 0);\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    }\n    for (int k = 0; k < N; ++k) {\n        int j = order[k];\n        int prev = order[(k-1+N)%N];\n        long long Dj = 2LL * T[j] - (long long)T[prev];\n        if (Dj < 0) Dj = 0; // should not happen with ascending order, but guard\n        D[j] = Dj;\n    }\n}\n\n// Greedy assignment of b-edges (one per node) to minimize sum of abs residuals.\n// r is residual capacity array initialized to D.\nstatic void greedy_assign_b(const vector<int>& T, vector<long long>& r,\n                            mt19937_64 &rng, vector<int>& b) {\n    int N = (int)T.size();\n    b.assign(N, 0);\n    vector<int> items(N);\n    iota(items.begin(), items.end(), 0);\n    // Sort items by descending weight; tie-break randomly via initial shuffle\n    shuffle(items.begin(), items.end(), rng);\n    stable_sort(items.begin(), items.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] > T[j];\n        return i < j;\n    });\n\n    for (int idx = 0; idx < N; ++idx) {\n        int i = items[idx];\n        long long w = T[i];\n        long long bestDelta = (1LL<<62);\n        vector<int> cands;\n        cands.reserve(8);\n        for (int j = 0; j < N; ++j) {\n            long long rj = r[j];\n            long long delta = llabs(rj - w) - llabs(rj);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                cands.clear();\n                cands.push_back(j);\n            } else if (delta == bestDelta) {\n                cands.push_back(j);\n            }\n        }\n        // choose randomly among candidates\n        int j = cands[rng() % cands.size()];\n        b[i] = j;\n        r[j] -= w;\n    }\n}\n\n// Local improvement: move single items from oversupplied bins to undersupplied bins if it reduces sum|r|.\nstatic void local_improve_moves(const vector<int>& T, vector<long long>& r,\n                                vector<int>& b, mt19937_64 &rng, int max_passes = 3) {\n    int N = (int)T.size();\n    vector<vector<int>> itemsOfBin(N);\n    itemsOfBin.assign(N, {});\n    for (int i = 0; i < N; ++i) {\n        itemsOfBin[b[i]].push_back(i);\n    }\n\n    for (int pass = 0; pass < max_passes; ++pass) {\n        bool changed_any = false;\n        // Build lists of deficit and oversupply bins\n        vector<int> deficits, overs;\n        deficits.reserve(N);\n        overs.reserve(N);\n        for (int j = 0; j < N; ++j) {\n            if (r[j] < 0) deficits.push_back(j);\n            else if (r[j] > 0) overs.push_back(j);\n        }\n        // Shuffle order to add randomness\n        shuffle(deficits.begin(), deficits.end(), rng);\n        shuffle(overs.begin(), overs.end(), rng);\n\n        for (int k : deficits) {\n            long long bestGain = 0; // we want negative delta (gain)\n            int bestFromBin = -1;\n            int bestItem = -1;\n            for (int j : overs) {\n                // skip empty bins\n                if (itemsOfBin[j].empty()) continue;\n                long long rj = r[j], rk = r[k];\n                for (int ii : itemsOfBin[j]) {\n                    long long w = T[ii];\n                    long long delta = llabs(rj - w) + llabs(rk + w) - (llabs(rj) + llabs(rk));\n                    if (delta < bestGain) {\n                        bestGain = delta;\n                        bestFromBin = j;\n                        bestItem = ii;\n                    }\n                }\n            }\n            if (bestItem != -1) {\n                // apply move: from bestFromBin to k\n                int j = bestFromBin;\n                int ii = bestItem;\n                long long w = T[ii];\n                // update bins\n                r[j] -= w;\n                r[k] += w;\n                // update items lists\n                auto &vecJ = itemsOfBin[j];\n                auto &vecK = itemsOfBin[k];\n                // remove ii from vecJ\n                for (int idx = 0; idx < (int)vecJ.size(); ++idx) {\n                    if (vecJ[idx] == ii) {\n                        vecJ[idx] = vecJ.back();\n                        vecJ.pop_back();\n                        break;\n                    }\n                }\n                vecK.push_back(ii);\n                b[ii] = k;\n                changed_any = true;\n            }\n        }\n        if (!changed_any) break;\n    }\n}\n\n// Simulate rotor-router for L steps and compute t_i and E = sum |t_i - T_i|\nstatic long long simulate_error(const vector<int>& a, const vector<int>& b,\n                                int L, const vector<int>& T, vector<int>& t_out) {\n    int N = (int)a.size();\n    vector<int> t(N, 0);\n    int cur = 0;\n    for (int step = 0; step < L; ++step) {\n        t[cur] += 1;\n        if (t[cur] & 1) cur = a[cur];\n        else cur = b[cur];\n    }\n    long long E = 0;\n    for (int i = 0; i < N; ++i) {\n        E += llabs((long long)t[i] - (long long)T[i]);\n    }\n    t_out = move(t);\n    return E;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, L;\n    if (!(cin >> N >> L)) return 0;\n    vector<int> T(N);\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    Timer timer;\n    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    Candidate best;\n    best.a.assign(N, 0);\n    best.b.assign(N, 0);\n    best.t.assign(N, 0);\n    best.E = (1LL<<62);\n\n    // Time budget (ms)\n    const double TIME_LIMIT_MS = 1950.0;\n\n    // Generate multiple randomized candidates within time\n    int iter = 0;\n    while (true) {\n        double elapsed = timer.elapsed_ms();\n        if (elapsed > TIME_LIMIT_MS) break;\n        ++iter;\n\n        vector<int> a, b;\n        vector<long long> D;\n        vector<int> order, pos;\n        build_cycle_and_residuals(T, rng, a, D, order, pos);\n\n        // Residuals for assigning b\n        vector<long long> r = D;\n        b.assign(N, 0);\n        greedy_assign_b(T, r, rng, b);\n\n        // Local improvement but keep it cheap\n        local_improve_moves(T, r, b, rng, 2);\n\n        // Simulate\n        vector<int> t;\n        long long E = simulate_error(a, b, L, T, t);\n\n        if (E < best.E) {\n            best.a = a;\n            best.b = b;\n            best.E = E;\n            best.t = t;\n        }\n\n        // Try variations: modest extra random restarts\n        if (timer.elapsed_ms() > TIME_LIMIT_MS) break;\n    }\n\n    // Output best found\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    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x ? x : p[x]=find(p[x]); }\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; sz[a]+=sz[b];\n        return true;\n    }\n};\n\nstatic inline uint64_t morton_code(uint32_t x, uint32_t y) {\n    // Interleave lower 15 bits of x and y: bit 0 of x in bit 0, bit 0 of y in bit 1, etc.\n    // Works for coordinates up to < 2^15 (32768), and our coords <= 10000.\n    uint64_t code = 0;\n    for (int i = 0; i < 15; ++i) {\n        code |= (uint64_t)((x >> i) & 1u) << (2*i);\n        code |= (uint64_t)((y >> i) & 1u) << (2*i + 1);\n    }\n    return code;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, Q, L, W;\n    if (!(cin >> N >> M >> Q >> L >> W)) return 0;\n    vector<int> G(M);\n    for(int i=0;i<M;i++) cin >> G[i];\n    vector<int> lx(N), rx(N), ly(N), ry(N);\n    for(int i=0;i<N;i++){\n        cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n    }\n\n    // Estimated coordinates: centers\n    vector<int> xc(N), yc(N);\n    for(int i=0;i<N;i++){\n        xc[i] = (lx[i] + rx[i]) / 2;\n        yc[i] = (ly[i] + ry[i]) / 2;\n    }\n\n    // Sort by Morton (Z-order)\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    vector<uint64_t> code(N);\n    for(int i=0;i<N;i++){\n        code[i] = morton_code((uint32_t)xc[i], (uint32_t)yc[i]);\n    }\n    sort(ord.begin(), ord.end(), [&](int a, int b){ return code[a] < code[b]; });\n\n    // Build groups as contiguous segments along ord\n    vector<vector<int>> groups(M);\n    int ptr = 0;\n    for(int k=0;k<M;k++){\n        groups[k].reserve(G[k]);\n        for(int t=0; t<G[k]; ++t){\n            groups[k].push_back(ord[ptr++]);\n        }\n    }\n\n    auto dist2_est = [&](int u, int v)->long long{\n        long long dx = xc[u] - xc[v];\n        long long dy = yc[u] - yc[v];\n        return dx*dx + dy*dy;\n    };\n\n    // Query function\n    auto do_query = [&](const vector<int>& subset)->vector<pair<int,int>>{\n        int l = (int)subset.size();\n        cout << \"? \" << l;\n        for(int i=0;i<l;i++) cout << \" \" << subset[i];\n        cout << \"\\n\" << flush;\n        vector<pair<int,int>> res;\n        res.reserve(max(0, l-1));\n        for(int i=0;i<l-1;i++){\n            int a,b;\n            cin >> a >> b;\n            res.emplace_back(a,b);\n        }\n        return res;\n    };\n\n    int queries_used = 0;\n\n    // Storage for oracle edges per group\n    vector<vector<pair<int,int>>> oracle_edges(M);\n\n    // Step 1: fully query small groups (G_i <= L), prioritize larger first\n    vector<int> small_groups;\n    small_groups.reserve(M);\n    for(int k=0;k<M;k++) if (G[k] <= L && G[k] >= 2) small_groups.push_back(k);\n    sort(small_groups.begin(), small_groups.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 k : small_groups) {\n        if (queries_used >= Q) break;\n        // Query entire group of size G[k]\n        vector<int> subset = groups[k];\n        auto res = do_query(subset);\n        ++queries_used;\n        oracle_edges[k].insert(oracle_edges[k].end(), res.begin(), res.end());\n    }\n\n    // Step 2: Use remaining queries to query L-sized windows inside large groups\n    if (queries_used < Q) {\n        struct Window { long long score; int k; int start; };\n        vector<Window> cand;\n        for (int k = 0; k < M; ++k) {\n            if (G[k] > L) {\n                // Precompute neighbor sums to evaluate contiguous windows quickly\n                int sz = G[k];\n                const auto &grp = groups[k];\n                vector<long long> neigh(sz-1);\n                for (int i = 0; i < sz-1; ++i) {\n                    neigh[i] = dist2_est(grp[i], grp[i+1]);\n                }\n                vector<long long> pref(sz);\n                pref[0] = 0;\n                for (int i = 0; i < sz-1; ++i) pref[i+1] = pref[i] + neigh[i];\n                // Consider non-overlapping starts s = 0, L, 2L, ..., plus ensure last block\n                for (int s = 0; s + L <= sz; s += L) {\n                    long long score = pref[s+L-1] - pref[s];\n                    cand.push_back({score, k, s});\n                }\n                int last_s = sz - L;\n                if (last_s >= 0) {\n                    long long score = pref[last_s+L-1] - pref[last_s];\n                    cand.push_back({score, k, last_s});\n                }\n            }\n        }\n        sort(cand.begin(), cand.end(), [](const Window& a, const Window& b){\n            if (a.score != b.score) return a.score < b.score;\n            if (a.k != b.k) return a.k < b.k;\n            return a.start < b.start;\n        });\n        // Avoid querying same window twice\n        unordered_set<long long> usedWin; usedWin.reserve(cand.size()*2+1);\n        auto encKey = [&](int k, int s)->long long { return ((long long)k<<32) ^ (long long)s; };\n        for (auto &w : cand) {\n            if (queries_used >= Q) break;\n            long long key = encKey(w.k, w.start);\n            if (usedWin.count(key)) continue;\n            usedWin.insert(key);\n            vector<int> subset;\n            subset.reserve(L);\n            for (int i = w.start; i < w.start + L; ++i) subset.push_back(groups[w.k][i]);\n            auto res = do_query(subset);\n            ++queries_used;\n            oracle_edges[w.k].insert(oracle_edges[w.k].end(), res.begin(), res.end());\n        }\n    }\n\n    // After queries, build final answer\n    cout << \"!\" << \"\\n\";\n\n    // Helper: approximate MST edges via Prim using estimated positions\n    auto approx_mst_edges = [&](const vector<int>& nodes)->vector<pair<int,int>>{\n        int n = (int)nodes.size();\n        vector<char> used(n, 0);\n        const long long INF = (1LL<<60);\n        vector<long long> best(n, INF);\n        vector<int> parent(n, -1);\n        best[0] = 0;\n        vector<pair<int,int>> edges;\n        edges.reserve(max(0, n-1));\n        for (int it = 0; it < n; ++it) {\n            int v = -1;\n            long long bv = INF;\n            for (int i = 0; i < n; ++i) if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n            if (v == -1) break; // should not happen\n            used[v] = 1;\n            if (parent[v] != -1) {\n                edges.emplace_back(nodes[parent[v]], nodes[v]);\n            }\n            for (int u = 0; u < n; ++u) if (!used[u]) {\n                long long d2 = dist2_est(nodes[v], nodes[u]);\n                if (d2 < best[u]) {\n                    best[u] = d2;\n                    parent[u] = v;\n                }\n            }\n        }\n        return edges;\n    };\n\n    // To map node id to local index for DSU quickly\n    vector<int> id2pos(N, -1);\n\n    for (int k = 0; k < M; ++k) {\n        const auto &grp = groups[k];\n        int sz = (int)grp.size();\n\n        // Print city IDs for this group\n        for (int i = 0; i < sz; ++i) {\n            if (i) cout << \" \";\n            cout << grp[i];\n        }\n        cout << \"\\n\";\n\n        if (sz <= 1) {\n            // No edges for single-city group\n            continue;\n        }\n\n        // Prepare local index mapping\n        for (int i = 0; i < sz; ++i) id2pos[grp[i]] = i;\n\n        // Deduplicate oracle edges and keep only those within this group\n        vector<pair<int,int>> forced;\n        forced.reserve(oracle_edges[k].size());\n        {\n            unordered_set<long long> seen;\n            seen.reserve(oracle_edges[k].size()*2+1);\n            auto encEdge = [&](int a, int b)->long long {\n                if (a > b) swap(a,b);\n                return ((long long)a<<32) ^ (long long)b;\n            };\n            for (auto &e : oracle_edges[k]) {\n                int a = e.first, b = e.second;\n                if (a == b) continue;\n                if (id2pos[a] == -1 || id2pos[b] == -1) continue; // paranoid check\n                long long key = encEdge(a,b);\n                if (!seen.count(key)) {\n                    seen.insert(key);\n                    forced.emplace_back(a,b);\n                }\n            }\n        }\n\n        // Build approximate MST edges\n        vector<pair<int,int>> approx = approx_mst_edges(grp);\n\n        // Merge: include forced edges first, then approx edges to connect all\n        DSU dsu(sz);\n        vector<pair<int,int>> final_edges;\n        final_edges.reserve(sz - 1);\n\n        auto try_add = [&](int u, int v){\n            int iu = id2pos[u], iv = id2pos[v];\n            if (iu == -1 || iv == -1) return;\n            if (dsu.unite(iu, iv)) {\n                final_edges.emplace_back(u, v);\n            }\n        };\n\n        for (auto &e : forced) {\n            if ((int)final_edges.size() == sz-1) break;\n            try_add(e.first, e.second);\n        }\n        for (auto &e : approx) {\n            if ((int)final_edges.size() == sz-1) break;\n            try_add(e.first, e.second);\n        }\n\n        // Fallback if still not connected (should be rare)\n        if ((int)final_edges.size() < sz - 1) {\n            int root_id = grp[0];\n            for (int i = 1; i < sz && (int)final_edges.size() < sz-1; ++i) {\n                try_add(root_id, grp[i]);\n            }\n        }\n\n        // Print edges\n        for (auto &e : final_edges) {\n            cout << e.first << \" \" << e.second << \"\\n\";\n        }\n\n        // Clean mapping\n        for (int i = 0; i < sz; ++i) id2pos[grp[i]] = -1;\n    }\n\n    cout.flush();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Step {\n    char a; // 'M' or 'S'\n    char d; // 'U','D','L','R'\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    vector<pair<int,int>> P(M);\n    for (int k = 0; k < M; ++k) {\n        cin >> P[k].first >> P[k].second;\n    }\n\n    // Directions: 0:U, 1:D, 2:L, 3: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 i, int j) -> bool {\n        return (0 <= i && i < N && 0 <= j && j < N);\n    };\n\n    auto id = [&](int i, int j) -> int {\n        return i * N + j;\n    };\n\n    auto coord = [&](int idx) -> pair<int,int> {\n        return {idx / N, idx % N};\n    };\n\n    // Since we never alter, slide destinations are always to the boundary.\n    auto slide_dest = [&](int i, int j, int d) -> pair<int,int> {\n        if (d == 0) return make_pair(0, j);        // Up to row 0\n        if (d == 1) return make_pair(N - 1, j);    // Down to row N-1\n        if (d == 2) return make_pair(i, 0);        // Left to col 0\n        return make_pair(i, N - 1);                // Right to col N-1\n    };\n\n    // BFS between two points with Move and Slide only\n    auto bfs = [&](pair<int,int> s, pair<int,int> t) -> vector<Step> {\n        int NN = N * N;\n        vector<int> par(NN, -1);\n        vector<char> how(NN, 0);   // 'M' or 'S'\n        vector<char> hdir(NN, 0);  // 'U','D','L','R'\n        vector<char> vis(NN, 0);\n        queue<int> q;\n\n        int sId = id(s.first, s.second);\n        int tId = id(t.first, t.second);\n        vis[sId] = 1;\n        q.push(sId);\n\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            if (u == tId) break;\n            auto [ui, uj] = coord(u);\n\n            // Try Moves\n            for (int d = 0; d < 4; ++d) {\n                int vi = ui + di[d];\n                int vj = uj + dj[d];\n                if (!inside(vi, vj)) continue;\n                int v = id(vi, vj);\n                if (!vis[v]) {\n                    vis[v] = 1;\n                    par[v] = u;\n                    how[v] = 'M';\n                    hdir[v] = dch[d];\n                    q.push(v);\n                    if (v == tId) goto bfs_end;\n                }\n            }\n            // Try Slides\n            for (int d = 0; d < 4; ++d) {\n                auto [vi, vj] = slide_dest(ui, uj, d);\n                if (vi == ui && vj == uj) continue; // sliding into same cell is pointless\n                int v = id(vi, vj);\n                if (!vis[v]) {\n                    vis[v] = 1;\n                    par[v] = u;\n                    how[v] = 'S';\n                    hdir[v] = dch[d];\n                    q.push(v);\n                    if (v == tId) goto bfs_end;\n                }\n            }\n        }\n    bfs_end:;\n\n        vector<Step> path;\n        if (!vis[tId]) {\n            // Should not happen in an empty grid; fallback to empty\n            return path;\n        }\n        int cur = tId;\n        while (cur != sId) {\n            Step st{how[cur], hdir[cur]};\n            path.push_back(st);\n            cur = par[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    };\n\n    vector<Step> ans;\n    long long maxActions = 2LL * N * M; // hard cap\n\n    pair<int,int> cur = P[0];\n    for (int k = 1; k < M; ++k) {\n        auto path = bfs(cur, P[k]);\n        // Ensure we don't exceed the cap\n        if ((long long)ans.size() + (long long)path.size() > maxActions) {\n            long long rem = maxActions - (long long)ans.size();\n            rem = max(0LL, rem);\n            for (long long i = 0; i < rem; ++i) ans.push_back(path[i]);\n            // Reached cap; stop emitting further actions\n            break;\n        } else {\n            for (auto &st : path) ans.push_back(st);\n            cur = P[k];\n        }\n    }\n\n    // Output actions\n    for (auto &st : ans) {\n        cout << st.a << ' ' << st.d << '\\n';\n    }\n    return 0;\n}"},"2":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Solver {\n    static constexpr int LIMIT_COORD = 10000;\n\n    int n;\n    vector<int> x, y;\n    vector<int> r;\n    vector<Rect> rects;\n\n    mt19937_64 rng;\n    Timer timer;\n    double time_limit;\n\n    Solver(int n_, vector<int> x_, vector<int> y_, vector<int> r_, double tl=4.85)\n        : n(n_), x(move(x_)), y(move(y_)), r(move(r_)), time_limit(tl) {\n        rects.resize(n);\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        seed ^= (uint64_t)(uintptr_t)this;\n        rng.seed(seed);\n    }\n\n    inline ll area_of(const Rect &rc) const {\n        return (ll)(rc.c - rc.a) * (ll)(rc.d - rc.b);\n    }\n\n    // score p(s, r) = 1 - (1 - min/max)^2\n    inline double score_si_ri(ll s, ll ri) const {\n        if (s <= 0) return 0.0;\n        ll mn = (s < ri ? s : ri);\n        ll mx = (s > ri ? s : ri);\n        double t = (double)mn / (double)mx;\n        double d = (1.0 - t);\n        return 1.0 - d * d;\n    }\n\n    // Compute maximum expansions in each direction for rectangle i against others.\n    inline void compute_allowed_expansions(int i, int &leftMax, int &rightMax, int &downMax, int &upMax) const {\n        const Rect &ri = rects[i];\n        int LBound = 0;\n        int RBound = LIMIT_COORD;\n        int DBound = 0;\n        int UBound = LIMIT_COORD;\n\n        for (int j = 0; j < n; ++j) {\n            if (j == i) continue;\n            const Rect &rj = rects[j];\n\n            // For horizontal expansion: look at rectangles overlapping vertically.\n            if (!(ri.d <= rj.b || rj.d <= ri.b)) {\n                if (rj.a >= ri.c) {\n                    if (rj.a < RBound) RBound = rj.a;\n                }\n                if (rj.c <= ri.a) {\n                    if (rj.c > LBound) LBound = rj.c;\n                }\n            }\n            // For vertical expansion: look at rectangles overlapping horizontally.\n            if (!(ri.c <= rj.a || rj.c <= ri.a)) {\n                if (rj.b >= ri.d) {\n                    if (rj.b < UBound) UBound = rj.b;\n                }\n                if (rj.d <= ri.b) {\n                    if (rj.d > DBound) DBound = rj.d;\n                }\n            }\n        }\n\n        leftMax = max(0, ri.a - LBound);\n        rightMax = max(0, RBound - ri.c);\n        downMax = max(0, ri.b - DBound);\n        upMax = max(0, UBound - ri.d);\n    }\n\n    template <class T>\n    inline T clampv(T v, T lo, T hi) const {\n        if (v < lo) return lo;\n        if (v > hi) return hi;\n        return v;\n    }\n\n    inline ll expand_horiz(int i, int delta, int leftMax, int rightMax) {\n        if (delta <= 0 || (leftMax + rightMax) <= 0) return 0;\n        Rect &ri = rects[i];\n        int h = ri.d - ri.b;\n        int maxDelta = min(delta, leftMax + rightMax);\n        // Split to keep seed near center.\n        int leftDist = x[i] - ri.a;\n        int rightDist = ri.c - x[i] - 1;\n        int diff = rightDist - leftDist;\n        int l = clampv((maxDelta + diff) / 2, 0, maxDelta);\n        l = min(l, leftMax);\n        int rTake = maxDelta - l;\n        if (rTake > rightMax) {\n            rTake = rightMax;\n            l = maxDelta - rTake;\n            l = min(l, leftMax);\n        }\n        if (l > 0) ri.a -= l;\n        if (rTake > 0) ri.c += rTake;\n        return (ll)h * (ll)(l + rTake);\n    }\n\n    inline ll expand_vert(int i, int delta, int downMax, int upMax) {\n        if (delta <= 0 || (downMax + upMax) <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int maxDelta = min(delta, downMax + upMax);\n        int downDist = y[i] - ri.b;\n        int upDist = ri.d - y[i] - 1;\n        int d = clampv((maxDelta + (downDist - upDist)) / 2, 0, maxDelta);\n        d = min(d, downMax);\n        int uTake = maxDelta - d;\n        if (uTake > upMax) {\n            uTake = upMax;\n            d = maxDelta - uTake;\n            d = min(d, downMax);\n        }\n        if (d > 0) ri.b -= d;\n        if (uTake > 0) ri.d += uTake;\n        return (ll)w * (ll)(d + uTake);\n    }\n\n    inline ll shrink_horiz(int i, int delta) {\n        if (delta <= 0) return 0;\n        Rect &ri = rects[i];\n        int h = ri.d - ri.b;\n        int shrinkLeftMax = x[i] - ri.a;          // move 'a' right\n        int shrinkRightMax = ri.c - (x[i] + 1);   // move 'c' left\n        int cap = shrinkLeftMax + shrinkRightMax;\n        if (cap <= 0) return 0;\n\n        int maxDelta = min(delta, cap);\n        int leftDist = x[i] - ri.a;\n        int rightDist = ri.c - x[i] - 1;\n        int l = clampv((maxDelta + (leftDist - rightDist)) / 2, 0, maxDelta);\n        l = min(l, shrinkLeftMax);\n        int rTake = maxDelta - l;\n        if (rTake > shrinkRightMax) {\n            rTake = shrinkRightMax;\n            l = maxDelta - rTake;\n            l = min(l, shrinkLeftMax);\n        }\n        if (l > 0) ri.a += l;\n        if (rTake > 0) ri.c -= rTake;\n        return (ll)h * (ll)(l + rTake);\n    }\n\n    inline ll shrink_vert(int i, int delta) {\n        if (delta <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int shrinkDownMax = y[i] - ri.b;\n        int shrinkUpMax = ri.d - (y[i] + 1);\n        int cap = shrinkDownMax + shrinkUpMax;\n        if (cap <= 0) return 0;\n\n        int maxDelta = min(delta, cap);\n        int downDist = y[i] - ri.b;\n        int upDist = ri.d - y[i] - 1;\n        int d = clampv((maxDelta + (downDist - upDist)) / 2, 0, maxDelta);\n        d = min(d, shrinkDownMax);\n        int uTake = maxDelta - d;\n        if (uTake > shrinkUpMax) {\n            uTake = shrinkUpMax;\n            d = maxDelta - uTake;\n            d = min(d, shrinkDownMax);\n        }\n        if (d > 0) ri.b += d;\n        if (uTake > 0) ri.d -= uTake;\n        return (ll)w * (ll)(d + uTake);\n    }\n\n    // Adjust rectangle i towards its target area r[i], using multiple small macro-steps.\n    bool adjust_one(int i) {\n        Rect &rc = rects[i];\n        bool changed = false;\n\n        // small iteration to approach target better\n        for (int it = 0; it < 3; ++it) {\n            ll s = area_of(rc);\n            ll target = r[i];\n            int w = rc.c - rc.a;\n            int h = rc.d - rc.b;\n\n            int leftMax, rightMax, downMax, upMax;\n            compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n\n            if (s < target) {\n                // First try to grow along the smaller dimension to balance shape\n                bool tryH = (leftMax + rightMax) > 0;\n                bool tryV = (downMax + upMax) > 0;\n                // decide order by current ratio\n                bool horizFirst;\n                if (tryH && tryV) {\n                    if (w < h) horizFirst = true;\n                    else if (w > h) horizFirst = false;\n                    else horizFirst = true;\n                } else if (tryH) horizFirst = true;\n                else if (tryV) horizFirst = false;\n                else horizFirst = true;\n\n                if (horizFirst && tryH) {\n                    ll need = target - s;\n                    int delta = (int)min<ll>((ll)(leftMax + rightMax), need / max(1, h));\n                    if (delta > 0) {\n                        expand_horiz(i, delta, leftMax, rightMax);\n                        changed = true;\n                    }\n                }\n                // recompute dims/limits\n                s = area_of(rc);\n                if (s < target && tryV) {\n                    compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n                    w = rc.c - rc.a;\n                    ll need2 = target - s;\n                    int delta2 = (int)min<ll>((ll)(downMax + upMax), need2 / max(1, w));\n                    if (delta2 > 0) {\n                        expand_vert(i, delta2, downMax, upMax);\n                        changed = true;\n                    }\n                }\n                // micro-step if still below target\n                s = area_of(rc);\n                if (s < target) {\n                    compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n                    w = rc.c - rc.a; h = rc.d - rc.b;\n                    ll bestImprove = 0;\n                    int bestMove = -1;\n                    auto clos = [&](ll si){ return llabs(si - target); };\n                    ll curClos = clos(s);\n                    if (leftMax > 0) {\n                        ll s2 = s + h;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 0;\n                    }\n                    if (rightMax > 0) {\n                        ll s2 = s + h;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 1;\n                    }\n                    if (downMax > 0) {\n                        ll s2 = s + w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 2;\n                    }\n                    if (upMax > 0) {\n                        ll s2 = s + w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 3;\n                    }\n                    if (bestImprove > 0) {\n                        if (bestMove == 0) rc.a -= 1;\n                        else if (bestMove == 1) rc.c += 1;\n                        else if (bestMove == 2) rc.b -= 1;\n                        else if (bestMove == 3) rc.d += 1;\n                        changed = true;\n                    }\n                }\n            } else if (s > target) {\n                // Shrink towards target, avoid overshoot\n                ll over = s - target;\n                // Prefer shrinking along larger dimension\n                bool canH = ((x[i] - rc.a) + (rc.c - (x[i] + 1))) > 0;\n                bool canV = ((y[i] - rc.b) + (rc.d - (y[i] + 1))) > 0;\n                bool shrinkHFirst;\n                if (canH && canV) {\n                    if (w > h) shrinkHFirst = true;\n                    else if (w < h) shrinkHFirst = false;\n                    else shrinkHFirst = true;\n                } else if (canH) shrinkHFirst = true;\n                else if (canV) shrinkHFirst = false;\n                else shrinkHFirst = true;\n\n                if (shrinkHFirst && canH) {\n                    int delta = (int)(over / max(1, h));\n                    if (delta > 0) {\n                        ll dec = shrink_horiz(i, delta);\n                        if (dec > 0) changed = true;\n                    }\n                }\n                s = area_of(rc);\n                if (s > target && canV) {\n                    over = s - target;\n                    int delta2 = (int)(over / max(1, w));\n                    if (delta2 > 0) {\n                        ll dec2 = shrink_vert(i, delta2);\n                        if (dec2 > 0) changed = true;\n                    }\n                }\n                // micro-step\n                s = area_of(rc);\n                if (s > target) {\n                    int shrinkLeftMax = x[i] - rc.a;\n                    int shrinkRightMax = rc.c - (x[i] + 1);\n                    int shrinkDownMax = y[i] - rc.b;\n                    int shrinkUpMax = rc.d - (y[i] + 1);\n                    ll bestImprove = 0;\n                    int bestMove = -1;\n                    auto clos = [&](ll si){ return llabs(si - target); };\n                    ll curClos = clos(s);\n                    if (shrinkLeftMax > 0) {\n                        ll s2 = s - (ll)h;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 0;\n                    }\n                    if (shrinkRightMax > 0) {\n                        ll s2 = s - (ll)h;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 1;\n                    }\n                    if (shrinkDownMax > 0) {\n                        ll s2 = s - (ll)w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 2;\n                    }\n                    if (shrinkUpMax > 0) {\n                        ll s2 = s - (ll)w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 3;\n                    }\n                    if (bestImprove > 0) {\n                        if (bestMove == 0) rc.a += 1;\n                        else if (bestMove == 1) rc.c -= 1;\n                        else if (bestMove == 2) rc.b += 1;\n                        else if (bestMove == 3) rc.d -= 1;\n                        changed = true;\n                    }\n                }\n            } else {\n                break;\n            }\n\n            // Safety: keep inside and include seed\n            rc.a = clampv(rc.a, 0, LIMIT_COORD - 1);\n            rc.c = clampv(rc.c, rc.a + 1, LIMIT_COORD);\n            rc.b = clampv(rc.b, 0, LIMIT_COORD - 1);\n            rc.d = clampv(rc.d, rc.b + 1, LIMIT_COORD);\n            if (!(rc.a <= x[i] && x[i] < rc.c && rc.b <= y[i] && y[i] < rc.d)) {\n                // Reset to unit if something went wrong\n                rc.a = x[i]; rc.b = y[i]; rc.c = x[i] + 1; rc.d = y[i] + 1;\n                changed = true;\n            }\n        }\n        return changed;\n    }\n\n    void initial_setup() {\n        for (int i = 0; i < n; ++i) rects[i] = Rect{ x[i], y[i], x[i] + 1, y[i] + 1 };\n    }\n\n    // Utility: floor and ceil division for possibly negative numerators and positive denominator\n    static inline long long floordiv(long long a, long long b) {\n        if (b < 0) a = -a, b = -b;\n        if (a >= 0) return a / b;\n        else return - ((-a + b - 1) / b);\n    }\n    static inline long long ceildiv(long long a, long long b) {\n        return -floordiv(-a, b);\n    }\n\n    struct PairItem {\n        int i, j; // orientation-specific: for vertical: i left, j right; for horizontal: i bottom, j top\n        bool vertical; // true for vertical shared side; false for horizontal shared side\n    };\n\n    // Build adjacency pairs where two rectangles share a full side (exactly matching span).\n    void build_fullside_pairs(vector<PairItem>& pairs) const {\n        pairs.clear();\n        for (int i = 0; i < n; ++i) {\n            const Rect &ri = rects[i];\n            for (int j = i+1; j < n; ++j) {\n                const Rect &rj = rects[j];\n                // Vertical adjacency: i left of j\n                if (ri.c == rj.a && ri.b == rj.b && ri.d == rj.d) {\n                    pairs.push_back({i, j, true});\n                } else if (rj.c == ri.a && rj.b == ri.b && rj.d == ri.d) {\n                    pairs.push_back({j, i, true});\n                }\n                // Horizontal adjacency: i bottom of j\n                if (ri.d == rj.b && ri.a == rj.a && ri.c == rj.c) {\n                    pairs.push_back({i, j, false});\n                } else if (rj.d == ri.b && rj.a == ri.a && rj.c == ri.c) {\n                    pairs.push_back({j, i, false});\n                }\n            }\n        }\n    }\n\n    bool slide_pairs_pass() {\n        vector<PairItem> pairs;\n        build_fullside_pairs(pairs);\n        if (pairs.empty()) return false;\n\n        shuffle(pairs.begin(), pairs.end(), rng);\n\n        bool anyImproved = false;\n\n        for (const auto &pi : pairs) {\n            int i = pi.i, j = pi.j;\n            const Rect &ri = rects[i];\n            const Rect &rj = rects[j];\n\n            ll si0 = area_of(ri);\n            ll sj0 = area_of(rj);\n            double base = score_si_ri(si0, r[i]) + score_si_ri(sj0, r[j]);\n\n            int tmin = 0, tmax = 0;\n            int unit = 1;\n            if (pi.vertical) {\n                // shift vertical boundary: c_i' = c_i + t, a_j' = a_j + t\n                // constraints:\n                // t >= x_i + 1 - c_i; t <= x_j - a_j\n                tmin = (x[i] + 1) - ri.c;\n                tmax = x[j] - rj.a;\n                unit = ri.d - ri.b; // height\n            } else {\n                // shift horizontal boundary: d_i' = d_i + t, b_j' = b_j + t\n                // t >= y_i + 1 - d_i; t <= y_j - b_j\n                tmin = (y[i] + 1) - ri.d;\n                tmax = y[j] - rj.b;\n                unit = ri.c - ri.a; // width\n            }\n            if (tmin > tmax || unit <= 0) continue;\n\n            // Candidate t's\n            vector<int> cand;\n            auto push_cand = [&](long long t) {\n                if (t < tmin) t = tmin;\n                if (t > tmax) t = tmax;\n                int ti = (int)t;\n                if (cand.empty() || cand.back() != ti) {\n                    // avoid duplicates\n                    if (find(cand.begin(), cand.end(), ti) == cand.end())\n                        cand.push_back(ti);\n                }\n            };\n            push_cand(0);\n            push_cand(tmin);\n            push_cand(tmax);\n\n            // t to match i's target: si + unit*t ~ r[i]\n            long long di = (long long)r[i] - si0;\n            long long ti_floor = floordiv(di, unit);\n            long long ti_ceil = ceildiv(di, unit);\n            push_cand(ti_floor);\n            push_cand(ti_floor - 1);\n            push_cand(ti_floor + 1);\n            push_cand(ti_ceil);\n            push_cand(ti_ceil - 1);\n            push_cand(ti_ceil + 1);\n\n            // t to match j's target: sj - unit*t ~ r[j] => t ~ (sj - rj)/unit\n            long long dj = sj0 - (long long)r[j];\n            long long tj_floor = floordiv(dj, unit);\n            long long tj_ceil = ceildiv(dj, unit);\n            push_cand(tj_floor);\n            push_cand(tj_floor - 1);\n            push_cand(tj_floor + 1);\n            push_cand(tj_ceil);\n            push_cand(tj_ceil - 1);\n            push_cand(tj_ceil + 1);\n\n            // Evaluate candidates\n            double bestVal = base;\n            int bestT = 0;\n            for (int t : cand) {\n                ll si = si0 + (ll)unit * (ll)t;\n                ll sj = sj0 - (ll)unit * (ll)t;\n\n                // ensure positive area (unit >=1 and t is bounded by constraints, so safe)\n                double val = score_si_ri(si, r[i]) + score_si_ri(sj, r[j]);\n                if (val > bestVal + 1e-15) {\n                    bestVal = val;\n                    bestT = t;\n                }\n            }\n\n            if (bestT != 0) {\n                // commit\n                if (pi.vertical) {\n                    rects[i].c += bestT;\n                    rects[j].a += bestT;\n                } else {\n                    rects[i].d += bestT;\n                    rects[j].b += bestT;\n                }\n                anyImproved = true;\n            }\n\n            // Time guard\n            if (timer.elapsed() > time_limit * 0.90) break;\n        }\n        return anyImproved;\n    }\n\n    void expand_pass_random() {\n        vector<int> idx(n);\n        iota(idx.begin(), idx.end(), 0);\n        shuffle(idx.begin(), idx.end(), rng);\n        for (int k = 0; k < n; ++k) {\n            if ((k & 31) == 0 && timer.elapsed() > time_limit) return;\n            adjust_one(idx[k]);\n        }\n    }\n    void expand_pass_descR(const vector<int>& order) {\n        for (int id : order) {\n            if (timer.elapsed() > time_limit) return;\n            adjust_one(id);\n        }\n    }\n\n    void solve() {\n        initial_setup();\n\n        // Initial order: large r first to claim space\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        stable_sort(order.begin(), order.end(), [&](int a, int b){ return r[a] > r[b]; });\n\n        // Phase 1: expansion/shrink passes\n        double t1 = time_limit * 0.45;\n        while (timer.elapsed() < t1) {\n            expand_pass_descR(order);\n            expand_pass_random();\n        }\n\n        // Phase 2: pairwise boundary slides improving sum of local scores\n        double t2 = time_limit * 0.90;\n        while (timer.elapsed() < t2) {\n            bool improved = slide_pairs_pass();\n            if (!improved) break;\n        }\n\n        // Phase 3: final smoothing\n        while (timer.elapsed() < time_limit) {\n            expand_pass_random();\n            if (timer.elapsed() > time_limit) break;\n            bool improved = slide_pairs_pass();\n            if (!improved) break;\n        }\n    }\n\n    void output() const {\n        for (int i = 0; i < n; ++i) {\n            const Rect &rc = rects[i];\n            cout << rc.a << ' ' << rc.b << ' ' << rc.c << ' ' << rc.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    if (!(cin >> n)) return 0;\n    vector<int> x(n), y(n), r(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> x[i] >> y[i] >> r[i];\n    }\n\n    Solver solver(n, x, y, r, 4.85);\n    solver.solve();\n    solver.output();\n\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Fast RNG (xorshift)\nstruct XorShift64 {\n    uint64_t x;\n    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    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int randint(int l, int r) { // inclusive l..r\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Params {\n    double wP;        // weight for immediate p\n    double wDeg;      // weight for degree of next cell\n    double wPot;      // weight for precomputed potential\n    double wTwinPot;  // penalty weight for twin potential\n    double wTwinDeg;  // penalty weight for twin degree\n    double wLook;     // weight for 2-ply lookahead\n    double noise;     // random noise amplitude\n    int avoidDeadMinLen; // avoid moving into dead-end (deg==0) before this many steps, if alternatives exist\n};\n\nstruct PathResult {\n    long long score;\n    string moves;\n    int lengthTiles; // number of tiles visited\n};\n\n// Global constants\nstatic const int H = 50, W = 50, N = H * W;\n\n// Utility to get id from (i,j)\ninline int id_of(int i, int j) { return i * W + j; }\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto time_start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.95; // seconds (precompute+runs)\n\n    int si, sj;\n    if (!(cin >> si >> sj)) {\n        // No input\n        cout << \"\\n\";\n        return 0;\n    }\n\n    vector<int> tile(N), pval(N);\n    int maxTile = -1;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int t; cin >> t;\n            tile[id_of(i, j)] = t;\n            if (t > maxTile) maxTile = t;\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            int pv; cin >> pv;\n            pval[id_of(i, j)] = pv;\n        }\n    }\n\n    // Build tileCells and twin mapping\n    vector<vector<int>> tileCells(M);\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int id = id_of(i, j);\n            tileCells[tile[id]].push_back(id);\n        }\n    }\n    vector<int> twin(N, -1);\n    for (int t = 0; t < M; t++) {\n        if (tileCells[t].size() == 2) {\n            int a = tileCells[t][0];\n            int b = tileCells[t][1];\n            twin[a] = b;\n            twin[b] = a;\n        }\n    }\n\n    // Build allowed neighbor list: edges only across different tiles\n    vector<array<int, 4>> coord(N);\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) coord[id_of(i,j)] = {i,j,0,0}; // only i,j used\n    vector<vector<int>> NB(N);\n    vector<char> UD(N), LR(N); // not used; we will compute moves by coord difference\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = id_of(i, j);\n            // up\n            if (i-1 >= 0) {\n                int v = id_of(i-1, j);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n            // down\n            if (i+1 < H) {\n                int v = id_of(i+1, j);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n            // left\n            if (j-1 >= 0) {\n                int v = id_of(i, j-1);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n            // right\n            if (j+1 < W) {\n                int v = id_of(i, j+1);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n        }\n    }\n\n    // Precompute static potentials: BFS to depth 3 on allowed graph, with decays for p\n    vector<double> pot(N, 0.0);\n    {\n        static const double w1 = 1.0, w2 = 0.6, w3 = 0.3;\n        vector<char> seen(N, 0);\n        vector<int> frontier, nextf;\n        frontier.reserve(64);\n        nextf.reserve(128);\n\n        for (int s = 0; s < N; s++) {\n            fill(seen.begin(), seen.end(), 0);\n            seen[s] = 1;\n            double sum = 0.0;\n\n            frontier.clear();\n            for (int v : NB[s]) if (!seen[v]) { seen[v] = 1; frontier.push_back(v); sum += w1 * pval[v]; }\n\n            // depth 2\n            nextf.clear();\n            for (int v : frontier) {\n                for (int u : NB[v]) if (!seen[u]) { seen[u] = 1; nextf.push_back(u); sum += w2 * pval[u]; }\n            }\n            // depth 3\n            frontier.swap(nextf);\n            nextf.clear();\n            for (int v : frontier) {\n                for (int u : NB[v]) if (!seen[u]) { seen[u] = 1; nextf.push_back(u); sum += w3 * pval[u]; }\n            }\n\n            pot[s] = sum;\n        }\n    }\n\n    // Precompute deg0 for convenience\n    vector<int> deg0(N);\n    for (int i = 0; i < N; i++) deg0[i] = (int)NB[i].size();\n\n    // RNG seed from input to diversify per test\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)si + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    seed ^= (uint64_t)sj + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    XorShift64 rng(seed);\n\n    // helper lambdas\n    auto dynamicDeg = [&](int cell, const vector<char>& tileUsed, int extraTile1 = -1, int extraTile2 = -1) -> int {\n        int cnt = 0;\n        for (int w : NB[cell]) {\n            int tt = tile[w];\n            if (tileUsed[tt]) continue;\n            if (tt == extraTile1 || tt == extraTile2) continue;\n            cnt++;\n        }\n        return cnt;\n    };\n\n    auto direction_char = [&](int u, int v) -> char {\n        int ui = u / W, uj = u % W;\n        int vi = v / W, vj = v % W;\n        if (vi == ui - 1 && vj == uj) return 'U';\n        if (vi == ui + 1 && vj == uj) return 'D';\n        if (vi == ui && vj == uj - 1) return 'L';\n        if (vi == ui && vj == uj + 1) return 'R';\n        // Should not happen if v is neighbor\n        return 'U';\n    };\n\n    // Parameter presets (will also randomize slightly)\n    vector<Params> presets;\n    presets.push_back(Params{1.00, 1.50, 0.050, 0.040, 0.30, 0.40, 1.5, 500});\n    presets.push_back(Params{1.20, 0.80, 0.080, 0.050, 0.20, 0.50, 1.2, 300});\n    presets.push_back(Params{1.00, 1.00, 0.060, 0.040, 0.25, 0.35, 1.5, 700});\n    presets.push_back(Params{1.00, 0.80, 0.030, 0.020, 0.20, 0.60, 1.0, 400});\n    presets.push_back(Params{1.00, 0.50, 0.100, 0.070, 0.15, 0.60, 1.2, 800});\n    presets.push_back(Params{1.40, 0.60, 0.040, 0.030, 0.20, 0.30, 1.5, 200});\n    presets.push_back(Params{1.00, 1.20, 0.070, 0.060, 0.25, 0.45, 1.0, 600});\n\n    auto build_path = [&](const Params& baseParam) -> PathResult {\n        // Slight random variation per run\n        Params P = baseParam;\n        auto jitter = [&](double v, double f=0.15) {\n            // multiply by 1 +/- up to f\n            double m = 1.0 + (rng.next_double() * 2.0 - 1.0) * f;\n            return v * m;\n        };\n        P.wP       = jitter(P.wP,       0.10);\n        P.wDeg     = jitter(P.wDeg,     0.20);\n        P.wPot     = jitter(P.wPot,     0.25);\n        P.wTwinPot = jitter(P.wTwinPot, 0.25);\n        P.wTwinDeg = jitter(P.wTwinDeg, 0.20);\n        P.wLook    = jitter(P.wLook,    0.25);\n        P.noise    = jitter(P.noise,    0.40);\n        int avoidLimit = P.avoidDeadMinLen;\n\n        vector<char> tileUsed(M, 0);\n        int start = id_of(si, sj);\n        tileUsed[tile[start]] = 1;\n\n        long long score = pval[start];\n        int pos = start;\n        string moves;\n        moves.reserve(2000);\n\n        // We'll build until stuck\n        for (int step = 0; ; step++) {\n            // List candidate neighbors whose tile not yet visited\n            vector<int> cand;\n            cand.reserve(4);\n            for (int v : NB[pos]) {\n                int t = tile[v];\n                if (!tileUsed[t]) cand.push_back(v);\n            }\n            if (cand.empty()) break;\n\n            // Precompute degAfter for candidates and check for any non-dead options\n            vector<int> degAfter(cand.size(), 0);\n            bool hasNonDead = false;\n            for (size_t i = 0; i < cand.size(); i++) {\n                degAfter[i] = dynamicDeg(cand[i], tileUsed);\n                if (degAfter[i] > 0) hasNonDead = true;\n            }\n\n            double bestVal = -1e100;\n            int bestV = -1;\n\n            for (size_t idx = 0; idx < cand.size(); idx++) {\n                int v = cand[idx];\n                if (step < avoidLimit && hasNonDead && degAfter[idx] == 0) {\n                    // avoid entering a dead end early if alternatives exist\n                    continue;\n                }\n                double val = 0.0;\n\n                // immediate gain and local features\n                val += P.wP * pval[v];\n                val += P.wPot * pot[v];\n\n                // degree after stepping into v (available next moves)\n                val += P.wDeg * degAfter[idx];\n\n                // penalty for blocking via twin\n                int tv = twin[v];\n                if (tv != -1) {\n                    // twin degree and potential (approximate loss)\n                    int dTwin = dynamicDeg(tv, tileUsed);\n                    val -= P.wTwinDeg * dTwin;\n                    val -= P.wTwinPot * pot[tv];\n                }\n\n                // 2-ply lookahead: best child of v\n                if (degAfter[idx] > 0 && P.wLook > 1e-9) {\n                    double best2 = -1e100;\n                    for (int w : NB[v]) {\n                        int tw = tile[w];\n                        if (tileUsed[tw]) continue;\n                        // deg after moving to w, with v's tile considered newly visited\n                        int deg2 = dynamicDeg(w, tileUsed, tile[v]);\n                        double val2 = 0.0;\n                        val2 += P.wP * pval[w];\n                        val2 += P.wPot * pot[w];\n                        val2 += P.wDeg * deg2;\n                        int t2 = twin[w];\n                        if (t2 != -1) {\n                            int dtwin2 = dynamicDeg(t2, tileUsed, tile[v]);\n                            val2 -= P.wTwinDeg * dtwin2;\n                            val2 -= P.wTwinPot * pot[t2];\n                        }\n                        if (val2 > best2) best2 = val2;\n                    }\n                    if (best2 > -1e90) val += P.wLook * best2;\n                }\n\n                // noise\n                val += (rng.next_double() * 2.0 - 1.0) * P.noise;\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestV = v;\n                }\n            }\n\n            if (bestV == -1) {\n                // If all candidates were dead-ends and we avoided them, but we must choose one; pick the best ignoring avoid\n                bestVal = -1e100;\n                for (int v : cand) {\n                    double val = P.wP * pval[v] + P.wPot * pot[v] + (rng.next_double() * 2.0 - 1.0) * P.noise;\n                    if (val > bestVal) bestVal = val, bestV = v;\n                }\n                if (bestV == -1) break;\n            }\n\n            // Take the move\n            tileUsed[tile[bestV]] = 1;\n            score += pval[bestV];\n            moves.push_back(direction_char(pos, bestV));\n            pos = bestV;\n        }\n\n        PathResult res;\n        res.score = score;\n        res.moves = moves;\n        res.lengthTiles = (int)moves.size() + 1;\n        return res;\n    };\n\n    // Run multiple randomized attempts within time limit\n    long long bestScore = -1;\n    string bestMoves;\n    int runs = 0;\n\n    // Ensure at least one run with default\n    {\n        Params P = presets[0];\n        PathResult r = build_path(P);\n        bestScore = r.score;\n        bestMoves = r.moves;\n        runs++;\n    }\n\n    while (true) {\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - time_start).count();\n        if (elapsed > TIME_LIMIT) break;\n\n        // Pick a preset randomly\n        Params baseP = presets[rng.randint(0, (int)presets.size()-1)];\n\n        // Mildly adapt avoidDeadMinLen with elapsed (later runs may allow more dead-ends to grab value)\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        if (progress > 0.6) {\n            baseP.avoidDeadMinLen = max(0, baseP.avoidDeadMinLen - (int)((progress - 0.6) * 800));\n        }\n\n        PathResult r = build_path(baseP);\n        if (r.score > bestScore) {\n            bestScore = r.score;\n            bestMoves = r.moves;\n        }\n        runs++;\n    }\n\n    // Output best path\n    cout << bestMoves << '\\n';\n\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int H = 30;\n    static constexpr int W = 30;\n    static constexpr int N = H * W;\n    // true generation range\n    static constexpr double WMIN = 1000.0;\n    static constexpr double WMAX = 9000.0;\n    // per-edge deviation clamp\n    static constexpr double DEV_CLAMP = 3000.0;\n\n    // base parameters: row-segment for horizontals, col-segment for verticals\n    // Hseg[i][s] for s=0..2: j in [0..9], [10..19], [20..28]\n    // Vseg[j][s] for s=0..2: i in [0..9], [10..19], [20..28]\n    array<array<double, 3>, H> Hseg;\n    array<array<double, 3>, W> Vseg;\n\n    // per-edge deviations\n    double dev_h[H][W-1];\n    double dev_v[H-1][W];\n\n    // query counter\n    int qid;\n\n    Solver() {\n        // initialize bases to center of allowed range\n        double init = 5000.0;\n        for (int i = 0; i < H; i++) Hseg[i] = {init, init, init};\n        for (int j = 0; j < W; j++) Vseg[j] = {init, init, init};\n        for (int i = 0; i < H; i++) for (int j = 0; j < W-1; j++) dev_h[i][j] = 0.0;\n        for (int i = 0; i < H-1; i++) for (int j = 0; j < W; j++) dev_v[i][j] = 0.0;\n        qid = 0;\n    }\n\n    static inline int segH_from_j(int j) {\n        if (j < 10) return 0;\n        if (j < 20) return 1;\n        return 2; // 20..28\n    }\n    static inline int segV_from_i(int i) {\n        if (i < 10) return 0;\n        if (i < 20) return 1;\n        return 2; // 20..28\n    }\n\n    inline double wh(int i, int j) const { // horizontal edge (i,j)-(i,j+1), j in [0..28]\n        int s = segH_from_j(j);\n        double x = Hseg[i][s] + dev_h[i][j];\n        if (x < WMIN) x = WMIN;\n        if (x > WMAX) x = WMAX;\n        return x;\n    }\n    inline double wv(int i, int j) const { // vertical edge (i,j)-(i+1,j), i in [0..28]\n        int s = segV_from_i(i);\n        double x = Vseg[j][s] + dev_v[i][j];\n        if (x < WMIN) x = WMIN;\n        if (x > WMAX) x = WMAX;\n        return x;\n    }\n\n    struct Node {\n        double d;\n        int i, j;\n        bool operator<(const Node& other) const {\n            return d > other.d; // for min-heap\n        }\n    };\n\n    // compute shortest path under current estimates using Dijkstra\n    string compute_path(int si, int sj, int ti, int tj, double &pred_len) {\n        static double dist[H][W];\n        static int pi[H][W], pj[H][W];\n        static char pdir[H][W];\n\n        for (int i = 0; i < H; i++) {\n            for (int j = 0; j < W; j++) {\n                dist[i][j] = numeric_limits<double>::infinity();\n                pi[i][j] = pj[i][j] = -1;\n                pdir[i][j] = 0;\n            }\n        }\n\n        priority_queue<Node> pq;\n        dist[si][sj] = 0.0;\n        pq.push({0.0, si, sj});\n\n        while (!pq.empty()) {\n            Node cur = pq.top(); pq.pop();\n            int i = cur.i, j = cur.j;\n            if (cur.d != dist[i][j]) continue;\n            if (i == ti && j == tj) break;\n\n            // neighbors: U,D,L,R\n            if (i > 0) {\n                double w = wv(i-1, j);\n                double nd = cur.d + w;\n                if (nd < dist[i-1][j]) {\n                    dist[i-1][j] = nd;\n                    pi[i-1][j] = i; pj[i-1][j] = j; pdir[i-1][j] = 'U';\n                    pq.push({nd, i-1, j});\n                }\n            }\n            if (i+1 < H) {\n                double w = wv(i, j);\n                double nd = cur.d + w;\n                if (nd < dist[i+1][j]) {\n                    dist[i+1][j] = nd;\n                    pi[i+1][j] = i; pj[i+1][j] = j; pdir[i+1][j] = 'D';\n                    pq.push({nd, i+1, j});\n                }\n            }\n            if (j > 0) {\n                double w = wh(i, j-1);\n                double nd = cur.d + w;\n                if (nd < dist[i][j-1]) {\n                    dist[i][j-1] = nd;\n                    pi[i][j-1] = i; pj[i][j-1] = j; pdir[i][j-1] = 'L';\n                    pq.push({nd, i, j-1});\n                }\n            }\n            if (j+1 < W) {\n                double w = wh(i, j);\n                double nd = cur.d + w;\n                if (nd < dist[i][j+1]) {\n                    dist[i][j+1] = nd;\n                    pi[i][j+1] = i; pj[i][j+1] = j; pdir[i][j+1] = 'R';\n                    pq.push({nd, i, j+1});\n                }\n            }\n        }\n\n        // reconstruct path\n        string rev;\n        int ci = ti, cj = tj;\n        while (!(ci == si && cj == sj)) {\n            char c = pdir[ci][cj];\n            rev.push_back(c);\n            int ni = pi[ci][cj], nj = pj[ci][cj];\n            ci = ni; cj = nj;\n        }\n        reverse(rev.begin(), rev.end());\n        pred_len = dist[ti][tj];\n        return rev;\n    }\n\n    struct EdgeUse {\n        bool isH; // true: horizontal; false: vertical\n        int i, j; // for horizontal: edge (i,j)-(i,j+1), j in [0..28]; for vertical: (i,j)-(i+1,j), i in [0..28]\n    };\n\n    // parse path into edges, compute predicted length and feature counts\n    void parse_path_and_features(int si, int sj, const string &path,\n                                 vector<EdgeUse> &edges,\n                                 vector<array<int,3>> &countHseg, // size H: counts per segment\n                                 vector<array<int,3>> &countVseg, // size W: counts per segment\n                                 double &S_pred) {\n        edges.clear();\n        countHseg.assign(H, {0,0,0});\n        countVseg.assign(W, {0,0,0});\n        int i = si, j = sj;\n        S_pred = 0.0;\n\n        for (char c : path) {\n            if (c == 'U') {\n                // use vertical edge (i-1,j)\n                int ei = i - 1, ej = j;\n                edges.push_back({false, ei, ej});\n                int s = segV_from_i(ei);\n                countVseg[ej][s] += 1;\n                double w = wv(ei, ej);\n                S_pred += w;\n                i -= 1;\n            } else if (c == 'D') {\n                int ei = i, ej = j;\n                edges.push_back({false, ei, ej});\n                int s = segV_from_i(ei);\n                countVseg[ej][s] += 1;\n                double w = wv(ei, ej);\n                S_pred += w;\n                i += 1;\n            } else if (c == 'L') {\n                int ei = i, ej = j - 1;\n                edges.push_back({true, ei, ej});\n                int s = segH_from_j(ej);\n                countHseg[ei][s] += 1;\n                double w = wh(ei, ej);\n                S_pred += w;\n                j -= 1;\n            } else if (c == 'R') {\n                int ei = i, ej = j;\n                edges.push_back({true, ei, ej});\n                int s = segH_from_j(ej);\n                countHseg[ei][s] += 1;\n                double w = wh(ei, ej);\n                S_pred += w;\n                j += 1;\n            }\n        }\n    }\n\n    // Update parameters using normalized LMS; devs receive larger share\n    void update_from_observation(int si, int sj, const string &path, long long y) {\n        vector<EdgeUse> edges;\n        vector<array<int,3>> countH; // per row segments\n        vector<array<int,3>> countV; // per col segments\n        double S_pred = 0.0;\n        parse_path_and_features(si, sj, path, edges, countH, countV, S_pred);\n\n        // Error\n        double delta = (double)y - S_pred;\n        int L = (int)edges.size();\n\n        // Compute norms for base features\n        double n_base = 0.0;\n        for (int i = 0; i < H; i++) {\n            for (int s = 0; s < 3; s++) {\n                int c = countH[i][s];\n                if (c) n_base += (double)c * (double)c;\n            }\n        }\n        for (int j = 0; j < W; j++) {\n            for (int s = 0; s < 3; s++) {\n                int c = countV[j][s];\n                if (c) n_base += (double)c * (double)c;\n            }\n        }\n        if (n_base < 1e-9) n_base = 0.0;\n\n        // Learning rates schedule\n        double t = (double)qid / 1000.0; // 0 ... ~1\n        // linearly decrease learning rates over time\n        double eta_dev = (1.0 - t) * 0.75 + t * 0.35;   // from 0.75 to 0.35\n        double eta_base = (1.0 - t) * 0.24 + t * 0.10;  // from 0.24 to 0.10\n        double lambda = 1.0;\n\n        // compute step sizes\n        double alpha_dev = 0.0;\n        if (L > 0) alpha_dev = eta_dev * delta / ( (double)L + lambda );\n\n        double alpha_base = 0.0;\n        if (n_base > 0.0) alpha_base = eta_base * delta / ( n_base + lambda );\n\n        // Update base parameters\n        if (alpha_base != 0.0) {\n            for (int i = 0; i < H; i++) {\n                for (int s = 0; s < 3; s++) {\n                    int c = countH[i][s];\n                    if (c) {\n                        Hseg[i][s] += alpha_base * c;\n                        if (Hseg[i][s] < WMIN) Hseg[i][s] = WMIN;\n                        else if (Hseg[i][s] > WMAX) Hseg[i][s] = WMAX;\n                    }\n                }\n            }\n            for (int j = 0; j < W; j++) {\n                for (int s = 0; s < 3; s++) {\n                    int c = countV[j][s];\n                    if (c) {\n                        Vseg[j][s] += alpha_base * c;\n                        if (Vseg[j][s] < WMIN) Vseg[j][s] = WMIN;\n                        else if (Vseg[j][s] > WMAX) Vseg[j][s] = WMAX;\n                    }\n                }\n            }\n        }\n\n        // Update per-edge deviations\n        if (alpha_dev != 0.0) {\n            for (const auto &e : edges) {\n                if (e.isH) {\n                    dev_h[e.i][e.j] += alpha_dev;\n                    if (dev_h[e.i][e.j] < -DEV_CLAMP) dev_h[e.i][e.j] = -DEV_CLAMP;\n                    else if (dev_h[e.i][e.j] > DEV_CLAMP) dev_h[e.i][e.j] = DEV_CLAMP;\n                } else {\n                    dev_v[e.i][e.j] += alpha_dev;\n                    if (dev_v[e.i][e.j] < -DEV_CLAMP) dev_v[e.i][e.j] = -DEV_CLAMP;\n                    else if (dev_v[e.i][e.j] > DEV_CLAMP) dev_v[e.i][e.j] = DEV_CLAMP;\n                }\n            }\n        }\n\n        // Small deviation decay towards 0 to regularize\n        double decay = (1.0 - t) * 0.0007 + t * 0.0018; // from ~7e-4 to ~1.8e-3\n        if (decay > 0.0) {\n            double mul = 1.0 - decay;\n            for (int i = 0; i < H; i++) {\n                for (int j = 0; j < W-1; j++) {\n                    dev_h[i][j] *= mul;\n                }\n            }\n            for (int i = 0; i < H-1; i++) {\n                for (int j = 0; j < W; j++) {\n                    dev_v[i][j] *= mul;\n                }\n            }\n        }\n\n        qid++;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int k = 0; k < 1000; k++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) {\n            return 0; // input ended unexpectedly\n        }\n\n        double pred_len = 0.0;\n        string path = solver.compute_path(si, sj, ti, tj, pred_len);\n\n        // Output path and flush\n        cout << path << '\\n' << flush;\n\n        long long observed_len;\n        if (!(cin >> observed_len)) {\n            return 0; // interactive judge ended\n        }\n\n        // Update model\n        solver.update_from_observation(si, sj, path, observed_len);\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\nusing namespace std;\n\n// Timer\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\n// Xorshift RNG\nstruct XorShift64 {\n    uint64_t x;\n    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    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n    inline double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n};\n\n// Constants\nstatic const int N_FIX = 20;\nstatic const int LMIN = 2;\nstatic const int LMAX = 12;\nstatic const int LCOUNT = LMAX - LMIN + 1;\n\nusing u64 = uint64_t;\nusing FlatMap = boost::unordered_flat_map<u64,int>;\n\n// Pack key\nstatic inline u64 pack_key_str(const string& s) {\n    u64 k = 0;\n    for (char ch : s) k = (k << 3) | (u64)(ch - 'A');\n    return k;\n}\n\n// Main\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    vector<string> inputS(M);\n    for (int i = 0; i < M; ++i) cin >> inputS[i];\n\n    Timer timer;\n    double TIME_LIMIT = 2.90;\n\n    // Unique strings: (lenIdx,key) -> uid\n    struct UKeyHasher {\n        size_t operator()(const pair<int,u64>& p) const {\n            return std::hash<u64>()((p.second << 4) ^ (u64)p.first);\n        }\n    };\n    struct UKeyEq {\n        bool operator()(const pair<int,u64>& a, const pair<int,u64>& b) const {\n            return a.first == b.first && a.second == b.second;\n        }\n    };\n    boost::unordered_flat_map<pair<int,u64>, int, UKeyHasher, UKeyEq> uniqMap;\n    uniqMap.reserve(M*2);\n\n    struct Unique {\n        int len;\n        u64 key;\n        int weight;\n        vector<uint8_t> codes;\n    };\n    vector<Unique> uniqs;\n    uniqs.reserve(M);\n\n    for (int i = 0; i < M; ++i) {\n        const string& s = inputS[i];\n        int L = (int)s.size();\n        int li = L - LMIN;\n        u64 key = pack_key_str(s);\n        auto pr = make_pair(li, key);\n        auto it = uniqMap.find(pr);\n        if (it == uniqMap.end()) {\n            int uid = (int)uniqs.size();\n            uniqMap.emplace(pr, uid);\n            Unique u;\n            u.len = L;\n            u.key = key;\n            u.weight = 1;\n            u.codes.resize(L);\n            for (int j = 0; j < L; ++j) u.codes[j] = (uint8_t)(s[j] - 'A');\n            uniqs.push_back(std::move(u));\n        } else {\n            uniqs[it->second].weight += 1;\n        }\n    }\n    int K = (int)uniqs.size();\n\n    // Per length key->uid\n    array<FlatMap, LCOUNT> key2uid;\n    for (int li = 0; li < LCOUNT; ++li) key2uid[li].reserve(max(8, K / LCOUNT * 2));\n    for (int uid = 0; uid < K; ++uid) {\n        int li = uniqs[uid].len - LMIN;\n        key2uid[li].emplace(uniqs[uid].key, uid);\n    }\n\n    // Precompute shifts: shiftAmt[li][t] = 3 * (L-1 - t)\n    int shiftAmt[LCOUNT][LMAX];\n    for (int li = 0; li < LCOUNT; ++li) {\n        int L = LMIN + li;\n        for (int t = 0; t < L; ++t) shiftAmt[li][t] = 3 * (L - 1 - t);\n    }\n\n    // Grid initialization: random\n    XorShift64 rng(123456789);\n    uint8_t g[N_FIX][N_FIX];\n    for (int i = 0; i < N_FIX; ++i) for (int j = 0; j < N_FIX; ++j) g[i][j] = (uint8_t)rng.next_int(0,7);\n\n    // lineChars[0..19]=rows, [20..39]=columns\n    uint8_t lineChars[2*N_FIX][N_FIX];\n    for (int i = 0; i < N_FIX; ++i) {\n        for (int j = 0; j < N_FIX; ++j) {\n            lineChars[i][j] = g[i][j];\n            lineChars[N_FIX + j][i] = g[i][j];\n        }\n    }\n\n    // windows\n    u64 windowsKey[LCOUNT][2*N_FIX][N_FIX];\n    int  windowsUid[LCOUNT][2*N_FIX][N_FIX];\n    for (int li = 0; li < LCOUNT; ++li)\n        for (int ln = 0; ln < 2*N_FIX; ++ln)\n            for (int s = 0; s < N_FIX; ++s) {\n                windowsKey[li][ln][s] = 0;\n                windowsUid[li][ln][s] = -1;\n            }\n\n    vector<int> occCount(K, 0);\n    vector<char> present(K, 0);\n    long long scoreC = 0;\n\n    // Initialize windows and occCount\n    for (int li = 0; li < LCOUNT; ++li) {\n        int L = LMIN + li;\n        for (int ln = 0; ln < 2*N_FIX; ++ln) {\n            for (int s = 0; s < N_FIX; ++s) {\n                u64 key = 0;\n                for (int r = 0; r < L; ++r) {\n                    int idx = s + r;\n                    if (idx >= N_FIX) idx -= N_FIX;\n                    key = (key << 3) | (u64)lineChars[ln][idx];\n                }\n                windowsKey[li][ln][s] = key;\n                auto it = key2uid[li].find(key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    windowsUid[li][ln][s] = uid;\n                    if (occCount[uid] == 0) {\n                        scoreC += uniqs[uid].weight;\n                        present[uid] = 1;\n                    }\n                    occCount[uid] += 1;\n                } else {\n                    windowsUid[li][ln][s] = -1;\n                }\n            }\n        }\n    }\n\n    // SA helper structures\n    vector<int> deltaOcc(K, 0);\n    vector<int> lastStamp(K, -1);\n    vector<int> touched; touched.reserve(4096);\n    int stamp = 0;\n\n    auto eval_delta_for_letter = [&](int i, int j, uint8_t newCode) -> long long {\n        uint8_t oldCode = g[i][j];\n        if (newCode == oldCode) return 0;\n        int lineRow = i;\n        int posRow = j;\n        int lineCol = N_FIX + j;\n        int posCol = i;\n        int ocxor = (int)(oldCode ^ newCode);\n\n        ++stamp;\n        touched.clear();\n        long long deltaScore = 0;\n\n        auto accumulate_single_change = [&](int line, int pos, int ocxor_) {\n            for (int li = 0; li < LCOUNT; ++li) {\n                int L = LMIN + li;\n                for (int t = 0; t < L; ++t) {\n                    int s = pos - t;\n                    if (s < 0) s += N_FIX;\n                    int old_uid = windowsUid[li][line][s];\n                    if (old_uid >= 0) {\n                        if (lastStamp[old_uid] != stamp) {\n                            lastStamp[old_uid] = stamp;\n                            deltaOcc[old_uid] = 0;\n                            touched.push_back(old_uid);\n                        }\n                        deltaOcc[old_uid] -= 1;\n                    }\n                    u64 old_key = windowsKey[li][line][s];\n                    int shift = shiftAmt[li][t];\n                    u64 new_key = old_key ^ ((u64)ocxor_ << shift);\n                    auto it = key2uid[li].find(new_key);\n                    if (it != key2uid[li].end()) {\n                        int uid = it->second;\n                        if (lastStamp[uid] != stamp) {\n                            lastStamp[uid] = stamp;\n                            deltaOcc[uid] = 0;\n                            touched.push_back(uid);\n                        }\n                        deltaOcc[uid] += 1;\n                    }\n                }\n            }\n        };\n\n        accumulate_single_change(lineRow, posRow, ocxor);\n        accumulate_single_change(lineCol, posCol, ocxor);\n\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto apply_letter = [&](int i, int j, uint8_t newCode) {\n        uint8_t oldCode = g[i][j];\n        if (newCode == oldCode) return;\n        g[i][j] = newCode;\n        lineChars[i][j] = newCode;\n        lineChars[N_FIX + j][i] = newCode;\n\n        int lineRow = i;\n        int posRow = j;\n        int lineCol = N_FIX + j;\n        int posCol = i;\n        int ocxor = (int)(oldCode ^ newCode);\n\n        auto update_line_single = [&](int line, int pos, int ocxor_) {\n            for (int li = 0; li < LCOUNT; ++li) {\n                int L = LMIN + li;\n                for (int t = 0; t < L; ++t) {\n                    int s = pos - t;\n                    if (s < 0) s += N_FIX;\n                    int old_uid = windowsUid[li][line][s];\n                    u64 old_key = windowsKey[li][line][s];\n                    int shift = shiftAmt[li][t];\n                    u64 new_key = old_key ^ ((u64)ocxor_ << shift);\n                    auto it = key2uid[li].find(new_key);\n                    int new_uid = (it == key2uid[li].end() ? -1 : it->second);\n\n                    if (old_uid >= 0) {\n                        occCount[old_uid] -= 1;\n                        if (occCount[old_uid] == 0) {\n                            scoreC -= uniqs[old_uid].weight;\n                            present[old_uid] = 0;\n                        }\n                    }\n                    if (new_uid >= 0) {\n                        if (occCount[new_uid] == 0) {\n                            scoreC += uniqs[new_uid].weight;\n                            present[new_uid] = 1;\n                        }\n                        occCount[new_uid] += 1;\n                    }\n\n                    windowsKey[li][line][s] = new_key;\n                    windowsUid[li][line][s] = new_uid;\n                }\n            }\n        };\n\n        update_line_single(lineRow, posRow, ocxor);\n        update_line_single(lineCol, posCol, ocxor);\n    };\n\n    // Helpers for block paste\n    auto eval_delta_paste_line_aggregate = [&](int line, const vector<pair<int,int>>& posXor) {\n        // Aggregate multiple changes on the same line\n        // masks[li][s] = XOR mask to apply to windowsKey\n        u64 masks[LCOUNT][N_FIX];\n        bool used[LCOUNT][N_FIX];\n        for (int li = 0; li < LCOUNT; ++li) {\n            for (int s = 0; s < N_FIX; ++s) {\n                masks[li][s] = 0;\n                used[li][s] = false;\n            }\n        }\n        for (auto &px : posXor) {\n            int pos = px.first;\n            int ocxor = px.second;\n            if (ocxor == 0) continue;\n            for (int li = 0; li < LCOUNT; ++li) {\n                int Lw = LMIN + li;\n                for (int t = 0; t < Lw; ++t) {\n                    int s = pos - t;\n                    if (s < 0) s += N_FIX;\n                    used[li][s] = true;\n                    masks[li][s] ^= ((u64)ocxor << shiftAmt[li][t]);\n                }\n            }\n        }\n        // Apply to deltaOcc\n        for (int li = 0; li < LCOUNT; ++li) {\n            for (int s = 0; s < N_FIX; ++s) {\n                if (!used[li][s]) continue;\n                u64 m = masks[li][s];\n                if (m == 0) continue; // no net change for this window\n                int old_uid = windowsUid[li][line][s];\n                if (old_uid >= 0) {\n                    if (lastStamp[old_uid] != stamp) {\n                        lastStamp[old_uid] = stamp;\n                        deltaOcc[old_uid] = 0;\n                        touched.push_back(old_uid);\n                    }\n                    deltaOcc[old_uid] -= 1;\n                }\n                u64 old_key = windowsKey[li][line][s];\n                u64 new_key = old_key ^ m;\n                auto it = key2uid[li].find(new_key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    if (lastStamp[uid] != stamp) {\n                        lastStamp[uid] = stamp;\n                        deltaOcc[uid] = 0;\n                        touched.push_back(uid);\n                    }\n                    deltaOcc[uid] += 1;\n                }\n            }\n        }\n    };\n\n    auto eval_delta_paste_row = [&](int i, int start, const vector<uint8_t>& codes) -> long long {\n        // Build list of changed positions and ocxors on row i\n        vector<pair<int,int>> rowPosXor; rowPosXor.reserve((int)codes.size());\n        vector<pair<int,int>> colSingle; colSingle.reserve((int)codes.size());\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int j = start + p; if (j >= N_FIX) j -= N_FIX;\n            int ocxor = g[i][j] ^ codes[p];\n            if (ocxor == 0) continue;\n            rowPosXor.emplace_back(j, ocxor);\n            colSingle.emplace_back(N_FIX + j, i); // (line = N + j, pos = i)\n        }\n        if (rowPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        // aggregate on row line\n        eval_delta_paste_line_aggregate(i, rowPosXor);\n\n        // single changes on columns\n        for (auto &cp : colSingle) {\n            int line = cp.first;\n            int pos  = cp.second;\n            int j = line - N_FIX;\n            int ocxor = g[pos][j] ^ codes[( (j - start) >= 0 ? (j - start) : (j - start + N_FIX) )]; // but codes.size() <= 12 so j-start in 0..L-1 wrapping around only if start+len>20\n            // compute p index precisely:\n            int p = j - start; if (p < 0) p += N_FIX; // but only valid for p < codes.size()\n            if (p < 0 || p >= (int)codes.size()) continue; // safety\n            ocxor = g[pos][j] ^ codes[p];\n            for (int li = 0; li < LCOUNT; ++li) {\n                int Lw = LMIN + li;\n                for (int t = 0; t < Lw; ++t) {\n                    int s = pos - t;\n                    if (s < 0) s += N_FIX;\n                    int old_uid = windowsUid[li][line][s];\n                    if (old_uid >= 0) {\n                        if (lastStamp[old_uid] != stamp) {\n                            lastStamp[old_uid] = stamp;\n                            deltaOcc[old_uid] = 0;\n                            touched.push_back(old_uid);\n                        }\n                        deltaOcc[old_uid] -= 1;\n                    }\n                    u64 old_key = windowsKey[li][line][s];\n                    u64 new_key = old_key ^ ((u64)(ocxor) << shiftAmt[li][t]);\n                    auto it = key2uid[li].find(new_key);\n                    if (it != key2uid[li].end()) {\n                        int uid = it->second;\n                        if (lastStamp[uid] != stamp) {\n                            lastStamp[uid] = stamp;\n                            deltaOcc[uid] = 0;\n                            touched.push_back(uid);\n                        }\n                        deltaOcc[uid] += 1;\n                    }\n                }\n            }\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto eval_delta_paste_col = [&](int j, int start, const vector<uint8_t>& codes) -> long long {\n        // Build list of changed positions and ocxors on column j\n        vector<pair<int,int>> colPosXor; colPosXor.reserve((int)codes.size());\n        vector<pair<int,int>> rowSingle; rowSingle.reserve((int)codes.size());\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int i = start + p; if (i >= N_FIX) i -= N_FIX;\n            int ocxor = g[i][j] ^ codes[p];\n            if (ocxor == 0) continue;\n            colPosXor.emplace_back(i, ocxor); // pos along column\n            rowSingle.emplace_back(i, j); // row line index = i, pos = j\n        }\n        if (colPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        // aggregate on column line\n        eval_delta_paste_line_aggregate(N_FIX + j, colPosXor);\n\n        // single changes on rows\n        for (auto &rp : rowSingle) {\n            int i = rp.first, jj = rp.second;\n            int line = i;\n            int pos  = jj;\n            int p = i - start; if (p < 0) p += N_FIX;\n            if (p < 0 || p >= (int)codes.size()) continue;\n            int ocxor = g[i][jj] ^ codes[p];\n            for (int li = 0; li < LCOUNT; ++li) {\n                int Lw = LMIN + li;\n                for (int t = 0; t < Lw; ++t) {\n                    int s = pos - t;\n                    if (s < 0) s += N_FIX;\n                    int old_uid = windowsUid[li][line][s];\n                    if (old_uid >= 0) {\n                        if (lastStamp[old_uid] != stamp) {\n                            lastStamp[old_uid] = stamp;\n                            deltaOcc[old_uid] = 0;\n                            touched.push_back(old_uid);\n                        }\n                        deltaOcc[old_uid] -= 1;\n                    }\n                    u64 old_key = windowsKey[li][line][s];\n                    u64 new_key = old_key ^ ((u64)(ocxor) << shiftAmt[li][t]);\n                    auto it = key2uid[li].find(new_key);\n                    if (it != key2uid[li].end()) {\n                        int uid = it->second;\n                        if (lastStamp[uid] != stamp) {\n                            lastStamp[uid] = stamp;\n                            deltaOcc[uid] = 0;\n                            touched.push_back(uid);\n                        }\n                        deltaOcc[uid] += 1;\n                    }\n                }\n            }\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto apply_paste_row = [&](int i, int start, const vector<uint8_t>& codes) {\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int j = start + p; if (j >= N_FIX) j -= N_FIX;\n            if (g[i][j] != codes[p]) apply_letter(i, j, codes[p]);\n        }\n    };\n    auto apply_paste_col = [&](int j, int start, const vector<uint8_t>& codes) {\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int i = start + p; if (i >= N_FIX) i -= N_FIX;\n            if (g[i][j] != codes[p]) apply_letter(i, j, codes[p]);\n        }\n    };\n\n    // Track best grid\n    long long bestScore = scoreC;\n    uint8_t bestGrid[N_FIX][N_FIX];\n    memcpy(bestGrid, g, sizeof(g));\n\n    // Stage 1: Block paste greedy\n    double BLOCK_TIME = TIME_LIMIT * 0.58; // ~58% time for block moves\n    while (timer.elapsed() < BLOCK_TIME) {\n        // pick uid: bias toward absent and higher weight\n        int uid = -1;\n        int bestW = -1;\n        // 70% chance to aim for absent\n        bool wantAbsent = (rng.next_double() < 0.7);\n        for (int t = 0; t < 8; ++t) {\n            int cand = rng.next_int(0, K-1);\n            if (wantAbsent && present[cand]) continue;\n            int w = uniqs[cand].weight;\n            if (w > bestW) {\n                bestW = w;\n                uid = cand;\n            }\n        }\n        if (uid < 0) uid = rng.next_int(0, K-1);\n\n        const auto& u = uniqs[uid];\n        const auto& codes = u.codes;\n\n        long long bestDelta = LLONG_MIN;\n        bool bestIsRow = true; int bestLine = 0, bestStart = 0;\n\n        int tries = 12; // number of random placements to evaluate\n        for (int t = 0; t < tries; ++t) {\n            bool isRow = (rng.next_u32() & 1) == 0;\n            int line = rng.next_int(0, N_FIX-1);\n            int start = rng.next_int(0, N_FIX-1);\n            long long delta = isRow ? eval_delta_paste_row(line, start, codes)\n                                    : eval_delta_paste_col(line, start, codes);\n            if (delta > bestDelta) {\n                bestDelta = delta;\n                bestIsRow = isRow;\n                bestLine = line;\n                bestStart = start;\n            }\n        }\n\n        if (bestDelta > 0) {\n            if (bestIsRow) apply_paste_row(bestLine, bestStart, codes);\n            else apply_paste_col(bestLine, bestStart, codes);\n            if (scoreC > bestScore) {\n                bestScore = scoreC;\n                memcpy(bestGrid, g, sizeof(g));\n            }\n        }\n    }\n\n    // Stage 2: SA fine-tune with single-letter moves\n    double T0 = 1.0;\n    double T1 = 0.01;\n\n    while (timer.elapsed() < TIME_LIMIT) {\n        int i = rng.next_int(0, N_FIX-1);\n        int j = rng.next_int(0, N_FIX-1);\n        uint8_t oldCode = g[i][j];\n\n        long long bestDelta = LLONG_MIN;\n        uint8_t bestCode = oldCode;\n\n        for (uint8_t nc = 0; nc < 8; ++nc) {\n            if (nc == oldCode) continue;\n            long long delta = eval_delta_for_letter(i, j, nc);\n            if (delta > bestDelta) {\n                bestDelta = delta;\n                bestCode = nc;\n            }\n        }\n\n        double t = timer.elapsed() / TIME_LIMIT;\n        if (t > 1.0) break;\n        double T = T0 + (T1 - T0) * t;\n\n        bool accept = false;\n        if (bestDelta >= 0) accept = true;\n        else {\n            double prob = exp((double)bestDelta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n        if (accept && bestCode != oldCode) {\n            apply_letter(i, j, bestCode);\n            if (scoreC > bestScore) {\n                bestScore = scoreC;\n                memcpy(bestGrid, g, sizeof(g));\n            }\n        }\n    }\n\n    // Output best grid found\n    for (int i = 0; i < N_FIX; ++i) {\n        string out; out.resize(N_FIX);\n        for (int j = 0; j < N_FIX; ++j) out[j] = char('A' + bestGrid[i][j]);\n        cout << out << '\\n';\n    }\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist;\n    vector<int> matchL, matchR;\n\n    HopcroftKarp(int nL_, int nR_) : nL(nL_), nR(nR_), g(nL_), dist(nL_), matchL(nL_, -1), matchR(nR_, -1) {}\n\n    void add_edge(int u, int v) {\n        g[u].push_back(v);\n    }\n\n    bool bfs() {\n        queue<int> q;\n        for (int i = 0; i < nL; ++i) {\n            if (matchL[i] == -1) {\n                dist[i] = 0;\n                q.push(i);\n            } else {\n                dist[i] = -1;\n            }\n        }\n        bool found = false;\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; // there exists an augmenting path\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    bool dfs(int u) {\n        for (int v : g[u]) {\n            int u2 = matchR[v];\n            if (u2 == -1 || (dist[u2] == dist[u] + 1 && dfs(u2))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int max_matching() {\n        int res = 0;\n        while (bfs()) {\n            for (int i = 0; i < nL; ++i) {\n                if (matchL[i] == -1) {\n                    if (dfs(i)) ++res;\n                }\n            }\n        }\n        return res;\n    }\n\n    pair<vector<char>, vector<char>> min_vertex_cover() {\n        // Find Z: vertices reachable from unmatched left vertices in the alternating graph\n        vector<char> visL(nL, 0), visR(nR, 0);\n        queue<int> q;\n        for (int u = 0; u < nL; ++u) {\n            if (matchL[u] == -1) {\n                visL[u] = 1;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                if (matchL[u] != v) {\n                    // unmatched edge u -> v\n                    if (!visR[v]) {\n                        visR[v] = 1;\n                        int u2 = matchR[v];\n                        if (u2 != -1 && !visL[u2]) {\n                            visL[u2] = 1;\n                            q.push(u2);\n                        }\n                    }\n                }\n            }\n        }\n        vector<char> coverL(nL, 0), coverR(nR, 0);\n        for (int u = 0; u < nL; ++u) {\n            if (!visL[u]) coverL[u] = 1;\n        }\n        for (int v = 0; v < nR; ++v) {\n            if (visR[v]) coverR[v] = 1;\n        }\n        return {coverL, coverR};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, si, sj;\n    if (!(cin >> N >> si >> sj)) {\n        return 0;\n    }\n    vector<string> c(N);\n    for (int i = 0; i < N; ++i) cin >> c[i];\n\n    const int H = N, W = N;\n    const int M = H * W;\n    auto id = [&](int i, int j) { return i * W + j; };\n\n    vector<int> w(M, -1);\n    vector<char> isRoad(M, 0);\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            if (c[i][j] != '#') {\n                isRoad[id(i,j)] = 1;\n                w[id(i,j)] = c[i][j] - '0';\n            }\n        }\n    }\n\n    // Build row segments\n    vector<int> rowSegId(M, -1), colSegId(M, -1);\n    vector<vector<int>> rowSegCells;\n    for (int i = 0; i < H; ++i) {\n        int j = 0;\n        while (j < W) {\n            if (isRoad[id(i,j)] && (j == 0 || !isRoad[id(i, j-1)])) {\n                int j2 = j;\n                int segId = (int)rowSegCells.size();\n                rowSegCells.emplace_back();\n                while (j2 < W && isRoad[id(i,j2)]) {\n                    rowSegId[id(i,j2)] = segId;\n                    rowSegCells.back().push_back(id(i,j2));\n                    ++j2;\n                }\n                j = j2;\n            } else {\n                ++j;\n            }\n        }\n    }\n    // Build column segments\n    vector<vector<int>> colSegCells;\n    for (int j = 0; j < W; ++j) {\n        int i = 0;\n        while (i < H) {\n            if (isRoad[id(i,j)] && (i == 0 || !isRoad[id(i-1, j)])) {\n                int i2 = i;\n                int segId = (int)colSegCells.size();\n                colSegCells.emplace_back();\n                while (i2 < H && isRoad[id(i2,j)]) {\n                    colSegId[id(i2,j)] = segId;\n                    colSegCells.back().push_back(id(i2,j));\n                    ++i2;\n                }\n                i = i2;\n            } else {\n                ++i;\n            }\n        }\n    }\n\n    int nR = (int)rowSegCells.size();\n    int nC = (int)colSegCells.size();\n\n    // Build bipartite graph: row segments -> column segments (edges for each road cell)\n    HopcroftKarp hk(nR, nC);\n    // To avoid any accidental duplicate edges (shouldn't happen), we can use a marker if needed.\n    // But in this construction each row seg intersects a column seg at most once.\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int u = id(i,j);\n            if (!isRoad[u]) continue;\n            int rseg = rowSegId[u];\n            int cseg = colSegId[u];\n            if (rseg >= 0 && cseg >= 0) {\n                hk.add_edge(rseg, cseg);\n            }\n        }\n    }\n\n    hk.max_matching();\n    auto [chooseRow_char, chooseCol_char] = hk.min_vertex_cover();\n\n    vector<char> chooseRow = chooseRow_char;\n    vector<char> chooseCol = chooseCol_char;\n\n    // Coverage flags\n    vector<char> coveredRow(nR, 0), coveredCol(nC, 0);\n\n    // Dijkstra helpers\n    const int INF = 1e9;\n    vector<int> dist(M, INF), prv(M, -1);\n    vector<char> prvDir(M, 0);\n\n    auto inb = [&](int i, int j){ return (0 <= i && i < H && 0 <= j && j < W); };\n\n    int start = id(si, sj);\n    int cur = start;\n\n    auto mark_covered_at_cell = [&](int u) {\n        int rs = rowSegId[u];\n        int cs = colSegId[u];\n        int changed = 0;\n        if (rs >= 0 && chooseRow[rs] && !coveredRow[rs]) { coveredRow[rs] = 1; changed++; }\n        if (cs >= 0 && chooseCol[cs] && !coveredCol[cs]) { coveredCol[cs] = 1; changed++; }\n        return changed;\n    };\n\n    long long remain = 0;\n    for (int i = 0; i < nR; ++i) if (chooseRow[i]) remain++;\n    for (int i = 0; i < nC; ++i) if (chooseCol[i]) remain++;\n\n    // Mark coverage at start\n    remain -= mark_covered_at_cell(cur);\n\n    string ans;\n\n    auto reconstruct_and_apply = [&](int s, int t, string &route) {\n        // reconstruct path from s to t using prv/prvDir arrays (computed by latest Dijkstra)\n        vector<char> moves;\n        int x = t;\n        if (s == t) return; // no moves\n        while (x != s && x != -1) {\n            moves.push_back(prvDir[x]);\n            x = prv[x];\n        }\n        if (x != s) {\n            // Shouldn't happen if Dijkstra found a path; but guard\n            return;\n        }\n        reverse(moves.begin(), moves.end());\n        // simulate moves to update coverage and append to route\n        int i = cur / W, j = cur % W;\n        for (char mv : moves) {\n            if (mv == 'U') --i;\n            else if (mv == 'D') ++i;\n            else if (mv == 'L') --j;\n            else if (mv == 'R') ++j;\n            int nid = id(i,j);\n            remain -= mark_covered_at_cell(nid);\n            route.push_back(mv);\n        }\n        cur = id(i,j);\n    };\n\n    // Dijkstra to nearest target (union of uncovered chosen segments), preferring intersection\n    auto dijkstra_to_next_target = [&]() -> int {\n        // initialize\n        for (int k = 0; k < M; ++k) {\n            dist[k] = INF;\n            prv[k] = -1;\n            prvDir[k] = 0;\n        }\n        struct Node { int d, u; };\n        struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n        priority_queue<Node, vector<Node>, Cmp> pq;\n        dist[cur] = 0;\n        pq.push({0, cur});\n\n        auto is_target_union = [&](int u)->bool {\n            int rs = rowSegId[u];\n            int cs = colSegId[u];\n            if (rs >= 0 && chooseRow[rs] && !coveredRow[rs]) return true;\n            if (cs >= 0 && chooseCol[cs] && !coveredCol[cs]) return true;\n            return false;\n        };\n        auto is_target_intersection = [&](int u)->bool {\n            int rs = rowSegId[u];\n            int cs = colSegId[u];\n            bool r = (rs >= 0 && chooseRow[rs] && !coveredRow[rs]);\n            bool c = (cs >= 0 && chooseCol[cs] && !coveredCol[cs]);\n            return r && c;\n        };\n\n        int best_union_idx = -1, best_union_dist = INF;\n        int best_inter_idx = -1, best_inter_dist = INF;\n        const int LOOKAHEAD_MARGIN = 25; // additive margin to search for an intersection\n        int limit = INF;\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n\n            // Early stopping conditions\n            if (best_inter_idx != -1 && d >= best_inter_dist) break;\n            if (best_union_idx != -1 && d > limit) break;\n\n            // Check target membership\n            if (is_target_union(u)) {\n                if (d < best_union_dist) {\n                    best_union_dist = d;\n                    best_union_idx = u;\n                    limit = best_union_dist + LOOKAHEAD_MARGIN;\n                }\n                if (is_target_intersection(u)) {\n                    if (d < best_inter_dist) {\n                        best_inter_dist = d;\n                        best_inter_idx = u;\n                        // We can keep going until queue's top >= best_inter_dist for correctness of early stop above\n                    }\n                }\n            }\n\n            int ui = u / W, uj = u % W;\n            // neighbors\n            // U\n            if (ui-1 >= 0) {\n                int v = id(ui-1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'U';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            // D\n            if (ui+1 < H) {\n                int v = id(ui+1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'D';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            // L\n            if (uj-1 >= 0) {\n                int v = id(ui, uj-1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'L';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            // R\n            if (uj+1 < W) {\n                int v = id(ui, uj+1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'R';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n        }\n\n        if (best_inter_idx != -1) return best_inter_idx;\n        if (best_union_idx != -1) return best_union_idx;\n        // Fallback: if somehow no target found (shouldn't happen), return current\n        return cur;\n    };\n\n    auto dijkstra_to_single = [&](int target) {\n        for (int k = 0; k < M; ++k) {\n            dist[k] = INF;\n            prv[k] = -1;\n            prvDir[k] = 0;\n        }\n        struct Node { int d, u; };\n        struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n        priority_queue<Node, vector<Node>, Cmp> pq;\n        dist[cur] = 0;\n        pq.push({0, cur});\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (u == target) break;\n            int ui = u / W, uj = u % W;\n            // neighbors\n            if (ui-1 >= 0) {\n                int v = id(ui-1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'U';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            if (ui+1 < H) {\n                int v = id(ui+1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'D';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            if (uj-1 >= 0) {\n                int v = id(ui, uj-1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'L';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n            if (uj+1 < W) {\n                int v = id(ui, uj+1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd;\n                        prv[v] = u;\n                        prvDir[v] = 'R';\n                        pq.push({nd, v});\n                    }\n                }\n            }\n        }\n    };\n\n    // Greedy routing\n    while (remain > 0) {\n        int dest = dijkstra_to_next_target();\n        // Reconstruct and apply path to dest\n        reconstruct_and_apply(cur, dest, ans);\n        // In rare fallback case dest == cur and no coverage changed, to avoid infinite loop, break.\n        if (cur == dest) {\n            // Try to find any uncovered segment cell explicitly\n            int fallbackDest = -1;\n            for (int u = 0; u < M; ++u) {\n                if (!isRoad[u]) continue;\n                int rs = rowSegId[u], cs = colSegId[u];\n                bool target = (rs >= 0 && chooseRow[rs] && !coveredRow[rs]) ||\n                              (cs >= 0 && chooseCol[cs] && !coveredCol[cs]);\n                if (target) { fallbackDest = u; break; }\n            }\n            if (fallbackDest == -1) break; // should not happen\n            dijkstra_to_single(fallbackDest);\n            reconstruct_and_apply(cur, fallbackDest, ans);\n        }\n    }\n\n    // Return to start\n    if (cur != start) {\n        dijkstra_to_single(start);\n        reconstruct_and_apply(cur, start, ans);\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Fast RNG (not critical but useful if we randomize anything)\nstruct FastRNG {\n    uint64_t x;\n    FastRNG(uint64_t seed=88172645463393265ull) : x(seed) {}\n    uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    double drand() { return (next() >> 11) * (1.0/9007199254740992.0); } // [0,1)\n    double uni(double a, double b){ return a + (b-a)*drand(); }\n};\n\nstruct Hungarian {\n    // Solve min-cost assignment for an n x n matrix\n    // Returns minimal cost and assignment p (size n), p[i] is assigned column to row i\n    static pair<double, vector<int>> solve(const vector<vector<double>>& a) {\n        int n = (int)a.size();\n        const double INF = 1e100;\n        vector<double> u(n+1, 0), v(n+1, 0);\n        vector<int> p(n+1, 0), way(n+1, 0);\n        for (int i = 1; i <= n; ++i) {\n            p[0] = i;\n            int j0 = 0;\n            vector<double> minv(n+1, INF);\n            vector<char> used(n+1, false);\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                double delta = INF;\n                for (int j = 1; j <= n; ++j) if (!used[j]) {\n                    double cur = a[i0-1][j-1] - u[i0] - v[j];\n                    if (cur < minv[j]) { minv[j] = cur; way[j] = j0; }\n                    if (minv[j] < delta) { delta = minv[j]; j1 = j; }\n                }\n                for (int j = 0; j <= n; ++j) {\n                    if (used[j]) { u[p[j]] += delta; v[j] -= delta; }\n                    else { minv[j] -= delta; }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n        vector<int> assignment(n, -1);\n        for (int j = 1; j <= n; ++j) if (p[j]) assignment[p[j]-1] = j-1;\n        double value = -v[0];\n        return {value, assignment};\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K, R;\n    if(!(cin >> N >> M >> K >> R)) return 0;\n\n    vector<vector<int>> D(N, vector<int>(K));\n    vector<double> sumD(N, 0.0), meanD(K, 0.0);\n    for(int i=0;i<N;i++){\n        double s=0.0;\n        for(int k=0;k<K;k++){\n            cin >> D[i][k];\n            s += D[i][k];\n            meanD[k] += D[i][k];\n        }\n        sumD[i] = s;\n    }\n    for(int k=0;k<K;k++) meanD[k] /= N;\n\n    vector<vector<int>> G(N);\n    vector<int> indeg(N, 0);\n    for(int e=0;e<R;e++){\n        int u,v; cin >> u >> v; --u; --v;\n        G[u].push_back(v);\n        indeg[v]++;\n    }\n\n    // Longest path depth (unweighted since DAG with u<v)\n    vector<int> dp(N, 1), outdeg(N);\n    for(int i=N-1;i>=0;--i){\n        int best=0;\n        for(int v: G[i]) best = max(best, dp[v]);\n        dp[i] = 1 + best;\n        outdeg[i] = (int)G[i].size();\n    }\n    int dpMax = *max_element(dp.begin(), dp.end());\n    double sumDmax = *max_element(sumD.begin(), sumD.end());\n    int outMax = *max_element(outdeg.begin(), outdeg.end());\n    if(sumDmax <= 0) sumDmax = 1.0;\n    if(dpMax <= 0) dpMax = 1;\n    if(outMax <= 0) outMax = 1;\n\n    // Base priority: normalized combination\n    vector<double> basePri(N);\n    const double wDepth = 1.0;\n    const double wOut = 0.3;\n    const double wDiff = 0.2;\n    for(int i=0;i<N;i++){\n        double nd = (double)dp[i] / dpMax;\n        double no = (double)outdeg[i] / outMax;\n        double nf = sumD[i] / sumDmax;\n        basePri[i] = wDepth*nd + wOut*no + wDiff*nf;\n    }\n\n    // Ready queue by base priority\n    struct Node { double key; int id; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.key < b.key; } };\n    priority_queue<Node, vector<Node>, Cmp> readyPQ;\n    vector<char> in_ready(N, 0), started(N, 0), done(N, 0);\n\n    for(int i=0;i<N;i++){\n        if(indeg[i]==0){\n            readyPQ.push({basePri[i], i});\n            in_ready[i]=1;\n        }\n    }\n\n    // Worker state\n    vector<int> workerTask(M, -1);\n    vector<int> workerStart(M, 0);\n\n    // Skill estimates (real-valued)\n    FastRNG rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    vector<vector<double>> S(M, vector<double>(K, 0.0));\n    // Init: meanD * ~1.6 with small noise\n    for(int j=0;j<M;j++){\n        for(int k=0;k<K;k++){\n            double val = meanD[k] * 1.6 + rng.uni(-0.5, 0.5);\n            if(val < 0) val = 0;\n            S[j][k] = val;\n        }\n    }\n    vector<int> obsCnt(M, 0);\n\n    // Helper functions\n    auto relu_sum = [&](const vector<int>& dvec, const vector<double>& svec)->double{\n        double w=0.0;\n        for(int k=0;k<K;k++){\n            double z = (double)dvec[k] - svec[k];\n            if(z > 0) w += z;\n        }\n        return w;\n    };\n    auto expected_time_from_w = [&](double w)->double{\n        if (w <= 1e-12) return 1.0; // exact model for w==0\n        double sum = 0.0;\n        for(int r=-3;r<=3;r++){\n            double val = w + r;\n            if(val < 1.0) val = 1.0;\n            sum += val;\n        }\n        return sum / 7.0;\n    };\n    auto dEt_dw = [&](double w)->double{\n        // d/dw E[max(1, w+r)] = average over r of I(w+r > 1)\n        int cnt=0;\n        for(int r=-3;r<=3;r++){\n            if (w + r > 1.0) cnt++;\n        }\n        return cnt / 7.0;\n    };\n\n    // Softplus approximations\n    const double beta = 0.35;     // smoothing\n    const double invbeta = 1.0 / beta;\n    auto softplus_sum = [&](const vector<int>& dvec, const vector<double>& svec)->double{\n        double res=0.0;\n        for(int k=0;k<K;k++){\n            double x = dvec[k] - svec[k];\n            double bx = beta * x;\n            if (bx > 30.0) {\n                res += x; // ~x\n            } else if (bx < -30.0) {\n                // ~0\n            } else {\n                res += log1p(exp(bx)) * invbeta;\n            }\n        }\n        return res;\n    };\n    auto sigmoid_beta = [&](double x)->double{\n        double bx = beta * x;\n        if (bx >= 0) {\n            double e = exp(-bx);\n            return 1.0 / (1.0 + e);\n        } else {\n            double e = exp(bx);\n            return e / (1.0 + e);\n        }\n    };\n\n    auto predict_time = [&](int i, int j)->double{\n        double w = relu_sum(D[i], S[j]);\n        if (w <= 1e-12) return 1.0;\n        return expected_time_from_w(w);\n    };\n\n    const double Smax = 120.0;\n    const double baseLR = 0.5;\n\n    auto update_skill = [&](int j, int i, int t){\n        // wsoft (smooth approx to sum ReLU)\n        double wsoft = softplus_sum(D[i], S[j]);\n        // Stabilize near zero for prediction; but keep derivative fraction > 0 for updates\n        double pred;\n        if (wsoft < 0.05) pred = 1.0;\n        else pred = expected_time_from_w(wsoft);\n        double target = max(1, t);\n        double err = pred - target;\n\n        double gE = dEt_dw(wsoft); // in [0,1]\n        // Learning rate schedule\n        double lr = baseLR / sqrt((double)obsCnt[j] + 1.0);\n        if (t <= 1) lr *= 0.2;     // reduce noisy updates on t=1\n        else if (t >= 5) lr *= 1.1; // slightly larger for long tasks\n\n        // Cap error influence\n        if (err > 8) err = 8;\n        if (err < -8) err = -8;\n\n        double scale = lr * gE;\n        if (scale <= 0) { obsCnt[j]++; return; }\n\n        for(int k=0;k<K;k++){\n            double g = sigmoid_beta((double)D[i][k] - S[j][k]); // d wsoft / d s_k = -g\n            double delta = scale * err * g; // gradient descent step: s += lr * err * gE * g\n            double ns = S[j][k] + delta;\n            if (ns < 0) ns = 0;\n            if (ns > Smax) ns = Smax;\n            S[j][k] = ns;\n        }\n        obsCnt[j]++;\n    };\n\n    int day = 0;\n    int finishedCount = 0;\n\n    while(true){\n        day++;\n\n        // Free workers\n        vector<int> freeWorkers;\n        freeWorkers.reserve(M);\n        for(int j=0;j<M;j++) if(workerTask[j] == -1) freeWorkers.push_back(j);\n\n        vector<pair<int,int>> assignments; // (worker, task)\n\n        if(!freeWorkers.empty()){\n            // Extract pool of top-priority ready tasks\n            int readySz = (int)readyPQ.size();\n            int poolTarget = min(readySz, max((int)freeWorkers.size() * 12, 24));\n            poolTarget = min(poolTarget, 60); // cap to keep Hungarian fast\n            vector<int> pool; pool.reserve(poolTarget);\n            vector<Node> stash; stash.reserve(poolTarget);\n            for(int c=0;c<poolTarget; ++c){\n                if(readyPQ.empty()) break;\n                Node nd = readyPQ.top(); readyPQ.pop();\n                stash.push_back(nd);\n                pool.push_back(nd.id);\n            }\n\n            int F = (int)freeWorkers.size();\n            int P = (int)pool.size();\n\n            if(P > 0){\n                // Build cost matrix for Hungarian (square)\n                int n = max(F, P);\n                const double BIG = 1e6;\n                vector<vector<double>> cost(n, vector<double>(n, BIG));\n\n                for(int fi=0; fi<F; ++fi){\n                    int j = freeWorkers[fi];\n                    for(int pi=0; pi<P; ++pi){\n                        int ti = pool[pi];\n                        double c = predict_time(ti, j);\n                        cost[fi][pi] = c;\n                    }\n                    for(int ccol=P; ccol<n; ++ccol) cost[fi][ccol] = 100.0; // dummy task cost\n                }\n                // Dummy rows if any\n                for(int r=F; r<n; ++r){\n                    for(int c=0;c<n;c++) cost[r][c] = 0.0; // do nothing\n                }\n\n                auto res = Hungarian::solve(cost);\n                vector<int> assignCols = res.second;\n\n                vector<char> taskTaken(P, 0), workerTaken(F, 0);\n                for(int fi=0; fi<F; ++fi){\n                    int col = assignCols[fi];\n                    if(col >= 0 && col < P){\n                        // Assign this worker to this task\n                        int j = freeWorkers[fi];\n                        int ti = pool[col];\n                        assignments.emplace_back(j, ti);\n                        workerTaken[fi] = 1;\n                        taskTaken[col] = 1;\n                    }\n                }\n\n                // Reinsert unassigned tasks\n                for(int pi=0; pi<P; ++pi){\n                    if(!taskTaken[pi]){\n                        readyPQ.push({basePri[pool[pi]], pool[pi]});\n                    } else {\n                        in_ready[pool[pi]] = 0; // will be started now\n                    }\n                }\n            } else {\n                // No ready tasks\n            }\n        }\n\n        // Emit output\n        cout << assignments.size();\n        for(auto &p: assignments){\n            int j = p.first;\n            int i = p.second;\n            cout << \" \" << (j+1) << \" \" << (i+1);\n            workerTask[j] = i;\n            workerStart[j] = day;\n            started[i] = 1;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        // Read feedback\n        int ncomp;\n        if(!(cin >> ncomp)) return 0;\n        if(ncomp == -1){\n            // All done or day limit\n            return 0;\n        }\n        vector<int> fins(ncomp);\n        for(int idx=0; idx<ncomp; ++idx){\n            int fj; cin >> fj; --fj;\n            fins[idx] = fj;\n        }\n        sort(fins.begin(), fins.end());\n        fins.erase(unique(fins.begin(), fins.end()), fins.end());\n\n        // Process completions\n        for(int fj : fins){\n            int i = workerTask[fj];\n            if(i < 0) continue; // safety\n            int t = day - workerStart[fj] + 1;\n            update_skill(fj, i, t);\n            workerTask[fj] = -1;\n            done[i] = 1;\n            finishedCount++;\n            // Unlock children for next day\n            for(int v: G[i]){\n                indeg[v]--;\n                if(indeg[v] == 0 && !started[v] && !done[v] && !in_ready[v]){\n                    readyPQ.push({basePri[v], v});\n                    in_ready[v] = 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 88172645463393265ull) { x = seed; }\n    inline uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int randint(int l, int r) { // inclusive\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    inline double drand() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstatic inline int manhattan(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\nstruct Order {\n    int id; // 0-based original index\n    int ax, ay, cx, cy; // pickup (a,b), drop (c,d)\n};\n\nstruct Event {\n    int oid; // 0..M-1 (index in selected array)\n    bool is_pick; // true: pickup, false: drop\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 1000;\n    const int M = 50;\n    const int OFFICE_X = 400;\n    const int OFFICE_Y = 400;\n\n    vector<Order> all(N);\n    for (int i = 0; i < N; ++i) {\n        int a,b,c,d;\n        if (!(cin >> a >> b >> c >> d)) return 0;\n        all[i] = {i, a, b, c, d};\n    }\n\n    auto s_cost = [&](const Order& o)->long long {\n        long long s = 0;\n        s += manhattan(OFFICE_X, OFFICE_Y, o.ax, o.ay);\n        s += manhattan(o.ax, o.ay, o.cx, o.cy);\n        s += manhattan(o.cx, o.cy, OFFICE_X, OFFICE_Y);\n        return s;\n    };\n\n    // Rank orders by surrogate cost\n    vector<pair<long long,int>> score_idx;\n    score_idx.reserve(N);\n    for (int i = 0; i < N; ++i) score_idx.emplace_back(s_cost(all[i]), i);\n    sort(score_idx.begin(), score_idx.end());\n\n    // Choose top M initially\n    vector<int> selected_orig_ids(M);\n    for (int i = 0; i < M; ++i) selected_orig_ids[i] = score_idx[i].second;\n\n    // Build selected arrays and coords\n    vector<Order> sel(M);\n    for (int i = 0; i < M; ++i) sel[i] = all[selected_orig_ids[i]];\n    vector<int> px(M), py(M), dx(M), dy(M);\n    for (int i = 0; i < M; ++i) {\n        px[i] = sel[i].ax; py[i] = sel[i].ay;\n        dx[i] = sel[i].cx; dy[i] = sel[i].cy;\n    }\n\n    auto coord_pick = [&](int oid)->pair<int,int>{ return {px[oid], py[oid]}; };\n    auto coord_drop = [&](int oid)->pair<int,int>{ return {dx[oid], dy[oid]}; };\n\n    auto coord_of_event = [&](const Event &e) -> pair<int,int> {\n        return e.is_pick ? coord_pick(e.oid) : coord_drop(e.oid);\n    };\n\n    auto route_cost = [&](const vector<Event> &s)->long long {\n        long long t = 0;\n        int lx = OFFICE_X, ly = OFFICE_Y;\n        for (auto &e : s) {\n            auto [nx, ny] = e.is_pick ? coord_pick(e.oid) : coord_drop(e.oid);\n            t += manhattan(lx, ly, nx, ny);\n            lx = nx; ly = ny;\n        }\n        t += manhattan(lx, ly, OFFICE_X, OFFICE_Y);\n        return t;\n    };\n\n    // Initial route builders\n    auto build_route_greedy = [&]()->vector<Event> {\n        vector<Event> seq;\n        seq.reserve(2*M);\n        vector<char> picked(M, 0), delivered(M, 0);\n        int curx = OFFICE_X, cury = OFFICE_Y;\n        int delivered_cnt = 0;\n        const double alpha_pick_penalty = 0.2;\n        while (delivered_cnt < M) {\n            int best_oid = -1;\n            bool best_is_pick = true;\n            double best_score = 1e100;\n\n            for (int i = 0; i < M; ++i) if (!picked[i]) {\n                int nx = px[i], ny = py[i];\n                int base = manhattan(curx, cury, nx, ny);\n                int pd = manhattan(px[i], py[i], dx[i], dy[i]);\n                double sc = base + alpha_pick_penalty * pd;\n                if (sc < best_score) {\n                    best_score = sc;\n                    best_oid = i;\n                    best_is_pick = true;\n                }\n            }\n            for (int i = 0; i < M; ++i) if (picked[i] && !delivered[i]) {\n                int nx = dx[i], ny = dy[i];\n                int base = manhattan(curx, cury, nx, ny);\n                double sc = base;\n                if (sc < best_score) {\n                    best_score = sc;\n                    best_oid = i;\n                    best_is_pick = false;\n                }\n            }\n            if (best_oid == -1) {\n                int bestd = INT_MAX, bi = -1;\n                for (int i = 0; i < M; ++i) if (!picked[i]) {\n                    int d = manhattan(curx, cury, px[i], py[i]);\n                    if (d < bestd) { bestd = d; bi = i; }\n                }\n                best_oid = bi;\n                best_is_pick = true;\n            }\n            if (best_is_pick) {\n                picked[best_oid] = 1;\n                seq.push_back({best_oid, true});\n                curx = px[best_oid]; cury = py[best_oid];\n            } else {\n                delivered[best_oid] = 1;\n                seq.push_back({best_oid, false});\n                curx = dx[best_oid]; cury = dy[best_oid];\n                delivered_cnt++;\n            }\n        }\n        return seq;\n    };\n    auto build_route_pick_then_drop = [&]()->vector<Event> {\n        vector<Event> seq;\n        seq.reserve(2*M);\n        vector<char> visP(M, 0), visD(M, 0);\n        int curx = OFFICE_X, cury = OFFICE_Y;\n        // pickups\n        for (int k = 0; k < M; ++k) {\n            int best = -1, bestd = INT_MAX;\n            for (int i = 0; i < M; ++i) if (!visP[i]) {\n                int d = manhattan(curx, cury, px[i], py[i]);\n                if (d < bestd) { bestd = d; best = i; }\n            }\n            visP[best] = 1;\n            seq.push_back({best, true});\n            curx = px[best]; cury = py[best];\n        }\n        // deliveries\n        for (int k = 0; k < M; ++k) {\n            int best = -1, bestd = INT_MAX;\n            for (int i = 0; i < M; ++i) if (!visD[i]) {\n                int d = manhattan(curx, cury, dx[i], dy[i]);\n                if (d < bestd) { bestd = d; best = i; }\n            }\n            visD[best] = 1;\n            seq.push_back({best, false});\n            curx = dx[best]; cury = dy[best];\n        }\n        return seq;\n    };\n\n    vector<Event> seqA = build_route_greedy();\n    vector<Event> seqB = build_route_pick_then_drop();\n    long long costA = route_cost(seqA);\n    long long costB = route_cost(seqB);\n    vector<Event> seq = (costA <= costB) ? seqA : seqB;\n\n    int L = (int)seq.size(); // should be 2*M\n\n    // pos arrays\n    vector<int> posPick(M, -1), posDel(M, -1);\n    auto recompute_positions = [&](){\n        fill(posPick.begin(), posPick.end(), -1);\n        fill(posDel.begin(), posDel.end(), -1);\n        for (int i = 0; i < (int)seq.size(); ++i) {\n            if (seq[i].is_pick) posPick[seq[i].oid] = i;\n            else posDel[seq[i].oid] = i;\n        }\n        L = (int)seq.size();\n    };\n    recompute_positions();\n\n    RNG rng(chrono::high_resolution_clock::now().time_since_epoch().count()*11995408973635179863ull);\n\n    // Helpers for coords at index\n    auto get_coord_by_index = [&](int idx)->pair<int,int>{\n        const Event &e = seq[idx];\n        return e.is_pick ? coord_pick(e.oid) : coord_drop(e.oid);\n    };\n\n    // Delta for single-event relocation\n    auto delta_move_single = [&](int p, int q)->long long {\n        const Event &ev = seq[p];\n        int oid = ev.oid;\n        if (ev.is_pick) {\n            int pos_del_prime = posDel[oid] - 1; // after removal\n            if (q > pos_del_prime) return (long long)4e18; // invalid\n        } else {\n            int pos_pick_prime = posPick[oid];\n            if (q <= pos_pick_prime) return (long long)4e18; // invalid\n        }\n        auto curr = get_coord_by_index(p);\n        pair<int,int> prevc, nextc;\n        if (p == 0) prevc = {OFFICE_X, OFFICE_Y};\n        else prevc = get_coord_by_index(p-1);\n        if (p == L-1) nextc = {OFFICE_X, OFFICE_Y};\n        else nextc = get_coord_by_index(p+1);\n        long long old_edges = (long long)manhattan(prevc.first, prevc.second, curr.first, curr.second)\n                            + (long long)manhattan(curr.first, curr.second, nextc.first, nextc.second);\n        long long new_edges = (long long)manhattan(prevc.first, prevc.second, nextc.first, nextc.second);\n        long long delta = new_edges - old_edges;\n\n        pair<int,int> prev2, next2;\n        if (q == 0) prev2 = {OFFICE_X, OFFICE_Y};\n        else {\n            int j1 = q - 1;\n            int orig1 = (j1 < p ? j1 : j1 + 1);\n            prev2 = get_coord_by_index(orig1);\n        }\n        if (q == L-1) {\n            next2 = {OFFICE_X, OFFICE_Y};\n        } else {\n            int orig2 = (q < p ? q : q + 1);\n            next2 = get_coord_by_index(orig2);\n        }\n        long long add_edges = (long long)manhattan(prev2.first, prev2.second, curr.first, curr.second)\n                            + (long long)manhattan(curr.first, curr.second, next2.first, next2.second);\n        long long rem_edge = (long long)manhattan(prev2.first, prev2.second, next2.first, next2.second);\n        delta += add_edges - rem_edge;\n\n        return delta;\n    };\n\n    auto apply_move_single = [&](int p, int q) {\n        Event ev = seq[p];\n        seq.erase(seq.begin() + p);\n        seq.insert(seq.begin() + q, ev);\n        recompute_positions();\n    };\n\n    // Mapping helpers for pair removal (p1<p2)\n    auto get_after_removals_coord = [&](int p1, int p2, int k)->pair<int,int>{\n        int orig;\n        if (k < p1) orig = k;\n        else if (k < p2 - 1) orig = k + 1;\n        else orig = k + 2;\n        return get_coord_by_index(orig);\n    };\n    auto get_after_removals_and_pick_coord = [&](int p1, int p2, int i, const pair<int,int>& pickCoord, int k)->pair<int,int>{\n        if (k == i) return pickCoord;\n        if (k < i) return get_after_removals_coord(p1, p2, k);\n        return get_after_removals_coord(p1, p2, k - 1);\n    };\n\n    // Delta for pair relocation of the same order (remove both, insert at i<j)\n    auto delta_move_pair = [&](int oid, int i, int j)->long long {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        if (!(0 <= p1 && p1 < p2 && p2 < L)) return (long long)4e18;\n        // Removal delta for p1\n        auto curr1 = get_coord_by_index(p1);\n        pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n        long long delta = 0;\n        delta += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n               - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n               - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n        // Removal delta for p2 after removing p1\n        auto curr2 = get_coord_by_index(p2);\n        pair<int,int> prev2prime, next2prime;\n        if (p2 == p1 + 1) {\n            prev2prime = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        } else {\n            prev2prime = get_coord_by_index(p2 - 1);\n        }\n        next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n        delta += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n               - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n               - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n\n        // Insertion\n        int L2 = L - 2;\n        if (i < 0 || i > L2) return (long long)4e18;\n        if (j <= i || j > L2 + 1) return (long long)4e18;\n        auto pC = coord_pick(oid);\n        auto dC = coord_drop(oid);\n        pair<int,int> prevI = (i == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i - 1);\n        pair<int,int> nextI = (i == L2) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i);\n        long long delta_ins = 0;\n        delta_ins += (long long)manhattan(prevI.first, prevI.second, pC.first, pC.second)\n                   + (long long)manhattan(pC.first, pC.second, nextI.first, nextI.second)\n                   - (long long)manhattan(prevI.first, prevI.second, nextI.first, nextI.second);\n\n        pair<int,int> prevJ = (j == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j - 1);\n        pair<int,int> nextJ = (j == L2 + 1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j);\n        delta_ins += (long long)manhattan(prevJ.first, prevJ.second, dC.first, dC.second)\n                   + (long long)manhattan(dC.first, dC.second, nextJ.first, nextJ.second)\n                   - (long long)manhattan(prevJ.first, prevJ.second, nextJ.first, nextJ.second);\n\n        return delta + delta_ins;\n    };\n\n    auto apply_move_pair = [&](int oid, int i, int j) {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        // remove delivery first then pickup to keep indices valid\n        seq.erase(seq.begin() + p2);\n        seq.erase(seq.begin() + p1);\n        // insert pickup at i (in the sequence after both removals)\n        Event ep{oid, true};\n        if (i < 0) i = 0;\n        if (i > (int)seq.size()) i = (int)seq.size();\n        seq.insert(seq.begin() + i, ep);\n        // insert drop at j (in the sequence after inserting pickup)\n        Event ed{oid, false};\n        if (j < 0) j = 0;\n        if (j > (int)seq.size()) j = (int)seq.size();\n        seq.insert(seq.begin() + j, ed);\n        recompute_positions();\n    };\n\n    // Best insertion positions for a given pair after removing two positions (p1,p2)\n    auto best_insertion_after_removal = [&](int p1, int p2, const pair<int,int>& pC, const pair<int,int>& dC, long long &bestDelta, int &bestI, int &bestJ){\n        int L2 = L - 2;\n        bestDelta = (long long)4e18;\n        bestI = 0; bestJ = 1;\n        for (int i = 0; i <= L2; ++i) {\n            pair<int,int> prevI = (i == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i - 1);\n            pair<int,int> nextI = (i == L2) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i);\n            long long delta_pick = (long long)manhattan(prevI.first, prevI.second, pC.first, pC.second)\n                                 + (long long)manhattan(pC.first, pC.second, nextI.first, nextI.second)\n                                 - (long long)manhattan(prevI.first, prevI.second, nextI.first, nextI.second);\n            for (int j = i + 1; j <= L2 + 1; ++j) {\n                pair<int,int> prevJ = (j == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j - 1);\n                pair<int,int> nextJ = (j == L2 + 1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j);\n                long long delta_drop = (long long)manhattan(prevJ.first, prevJ.second, dC.first, dC.second)\n                                     + (long long)manhattan(dC.first, dC.second, nextJ.first, nextJ.second)\n                                     - (long long)manhattan(prevJ.first, prevJ.second, nextJ.first, nextJ.second);\n                long long tot = delta_pick + delta_drop;\n                if (tot < bestDelta) {\n                    bestDelta = tot;\n                    bestI = i; bestJ = j;\n                }\n            }\n        }\n    };\n\n    // Lightweight order exchange stage: try replacing a selected order with an outside candidate\n    vector<char> in_selected(N, 0);\n    for (int i = 0; i < M; ++i) in_selected[selected_orig_ids[i]] = 1;\n    vector<int> cand_pool;\n    int Kcand = min(200, N); // candidate pool size\n    for (int i = 0; i < Kcand; ++i) {\n        int id = score_idx[i].second;\n        if (!in_selected[id]) cand_pool.push_back(id);\n    }\n\n    auto total_cost = route_cost(seq);\n    auto start_time = chrono::high_resolution_clock::now();\n    const double TIME_LIMIT = 1.95;\n    const double REPLACE_LIMIT = 0.35;\n\n    auto elapsed_sec = [&](){\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - start_time).count();\n    };\n\n    // Try a few replacements within time budget\n    if (!cand_pool.empty()) {\n        while (elapsed_sec() < REPLACE_LIMIT) {\n            int rem_oid = rng.randint(0, M-1);\n            if (cand_pool.empty()) break;\n            int idx = rng.randint(0, (int)cand_pool.size()-1);\n            int add_orig = cand_pool[idx];\n            // Compute removal delta for rem_oid\n            int p1 = posPick[rem_oid];\n            int p2 = posDel[rem_oid];\n            if (p1 < 0 || p2 < 0) { recompute_positions(); continue; }\n            auto curr1 = get_coord_by_index(p1);\n            pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n            pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n            long long delta_rem = 0;\n            delta_rem += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n                       - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n                       - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n            auto curr2 = get_coord_by_index(p2);\n            pair<int,int> prev2prime, next2prime;\n            if (p2 == p1 + 1) {\n                prev2prime = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n            } else {\n                prev2prime = get_coord_by_index(p2 - 1);\n            }\n            next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n            delta_rem += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n                       - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n                       - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n\n            // Insertion best delta for add_orig after removing p1,p2\n            pair<int,int> newP = {all[add_orig].ax, all[add_orig].ay};\n            pair<int,int> newD = {all[add_orig].cx, all[add_orig].cy};\n            long long bestIns; int bi, bj;\n            best_insertion_after_removal(p1, p2, newP, newD, bestIns, bi, bj);\n            long long delta_tot = delta_rem + bestIns;\n\n            if (delta_tot < 0) {\n                // Apply replacement: remove rem_oid events and insert new ones at bi,bj, update selected arrays\n                // remove indices p2 then p1\n                seq.erase(seq.begin() + p2);\n                seq.erase(seq.begin() + p1);\n                // update sel coord arrays for rem_oid to new order\n                selected_orig_ids[rem_oid] = add_orig;\n                sel[rem_oid] = all[add_orig];\n                px[rem_oid] = newP.first; py[rem_oid] = newP.second;\n                dx[rem_oid] = newD.first; dy[rem_oid] = newD.second;\n                // insert\n                Event ep{rem_oid, true}, ed{rem_oid, false};\n                seq.insert(seq.begin() + bi, ep);\n                seq.insert(seq.begin() + bj, ed);\n                recompute_positions();\n                total_cost += delta_tot;\n                // Move membership marks\n                in_selected[add_orig] = 1;\n                // Find which was removed (we removed rem_oid mapping to old orig id, which is unknown now)\n                // We need to mark previously selected original id as not selected:\n                // Actually we already overwrote selected_orig_ids[rem_oid], but we need old id:\n                // To handle this, we can set after capturing old id above:\n                // Let's fix by keeping old id before overwrite.\n            } else {\n                // try another candidate\n            }\n\n            // Fix membership bookkeeping:\n            // The above missed old id; Let's correct with a small change:\n            // We'll store old id before overwrite.\n            // But we cannot change past code inside this loop; So adapt: do membership toggling properly in next iterations.\n\n            // To keep correctness, rebuild in_selected and cand_pool every few attempts could be simpler but cost is small.\n            // We'll rebuild now for safety:\n            fill(in_selected.begin(), in_selected.end(), 0);\n            for (int i = 0; i < M; ++i) in_selected[selected_orig_ids[i]] = 1;\n            cand_pool.clear();\n            for (int i = 0; i < Kcand; ++i) {\n                int id = score_idx[i].second;\n                if (!in_selected[id]) cand_pool.push_back(id);\n            }\n            if (cand_pool.empty()) break;\n        }\n    }\n\n    // SA preparation\n    long long cur_cost = route_cost(seq);\n    long long best_cost = cur_cost;\n    vector<Event> best_seq = seq;\n\n    const double T0 = 200.0;\n    const double T1 = 1.0;\n\n    auto delta_pair_best_wrapper = [&](int oid, long long &bestDelta, int &bi, int &bj)->long long {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        // removal delta\n        auto curr1 = get_coord_by_index(p1);\n        pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n        long long delta_rem = 0;\n        delta_rem += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n                   - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n                   - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n        auto curr2 = get_coord_by_index(p2);\n        pair<int,int> prev2prime, next2prime;\n        if (p2 == p1 + 1) {\n            prev2prime = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        } else {\n            prev2prime = get_coord_by_index(p2 - 1);\n        }\n        next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n        delta_rem += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n                   - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n                   - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n\n        long long bestIns; int iBest, jBest;\n        best_insertion_after_removal(p1, p2, coord_pick(oid), coord_drop(oid), bestIns, iBest, jBest);\n        bestDelta = delta_rem + bestIns;\n        bi = iBest; bj = jBest;\n        return bestDelta;\n    };\n\n    auto time_left = [&](){ return TIME_LIMIT - elapsed_sec(); };\n\n    // SA loop\n    while (elapsed_sec() < TIME_LIMIT) {\n        double tfrac = min(1.0, elapsed_sec() / TIME_LIMIT);\n        double temp = T0 + (T1 - T0) * tfrac;\n\n        int moveType = rng.randint(0, 99);\n        bool accepted = false;\n        long long d = 0;\n\n        if (moveType < 60) {\n            // Single-event relocation\n            int p = rng.randint(0, L - 1);\n            int Lp = L - 1;\n            if (Lp <= 0) continue;\n            int q = rng.randint(0, Lp);\n            if (q == p) continue;\n            d = delta_move_single(p, q);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_single(p, q);\n                cur_cost += d;\n                accepted = true;\n            }\n        } else if (moveType < 90) {\n            // Random pair relocation\n            int oid = rng.randint(0, M - 1);\n            int i = rng.randint(0, L - 2);\n            int j = rng.randint(i + 1, L - 1);\n            d = delta_move_pair(oid, i, j);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_pair(oid, i, j);\n                cur_cost += d;\n                accepted = true;\n            }\n        } else {\n            // Best pair relocation for a random order (O(L^2))\n            int oid = rng.randint(0, M - 1);\n            long long bestDelta; int bi, bj;\n            d = delta_pair_best_wrapper(oid, bestDelta, bi, bj);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_pair(oid, bi, bj);\n                cur_cost += d;\n                accepted = true;\n            }\n        }\n\n        if (accepted && cur_cost < best_cost) {\n            best_cost = cur_cost;\n            best_seq = seq;\n        }\n    }\n\n    // Use best sequence\n    seq = best_seq;\n    L = (int)seq.size();\n\n    // Output\n    cout << M;\n    for (int i = 0; i < M; ++i) cout << ' ' << (selected_orig_ids[i] + 1);\n    cout << '\\n';\n\n    int n = 2*M + 2;\n    cout << n << ' ' << OFFICE_X << ' ' << OFFICE_Y;\n    for (int i = 0; i < L; ++i) {\n        auto [x, y] = coord_of_event(seq[i]);\n        cout << ' ' << x << ' ' << y;\n    }\n    cout << ' ' << OFFICE_X << ' ' << OFFICE_Y << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\n#include <boost/dynamic_bitset.hpp>\nusing namespace std;\n\n// Constants fixed by the problem\nstatic constexpr int N = 400;\nstatic constexpr int M = 5 * (N - 1);\n\n// DSU with dynamic cut-bitsets per component\nstruct DSU {\n    vector<int> parent, sz;\n    vector<boost::dynamic_bitset<unsigned long long>> inc; // cut edges per component\n    DSU(int n, int mbits, const vector<pair<int,int>>& edge_uv) : parent(n), sz(n,1), inc(n, boost::dynamic_bitset<unsigned long long>(mbits)) {\n        iota(parent.begin(), parent.end(), 0);\n    }\n    int find(int x){\n        while(parent[x]!=x){\n            parent[x]=parent[parent[x]];\n            x=parent[x];\n        }\n        return x;\n    }\n    // Merge roots a,b; ensure we merge smaller into larger\n    int unite(int a, int b){\n        a=find(a); b=find(b);\n        if(a==b) return a;\n        if(sz[a] < sz[b]) swap(a,b);\n        // a is new root\n        inc[a] ^= inc[b];\n        parent[b] = a;\n        sz[a] += sz[b];\n        return a;\n    }\n};\n\nstruct Edge {\n    int u, v;\n    int d; // rounded Euclidean distance\n    bool in_mst = false;\n    bool is_nn = false; // among top-K nearest of an endpoint by d\n};\n\nstatic inline int round_int(double x) {\n    return (int)llround(x);\n}\n\n// Helper: count number of set bits strictly after pos (pos is current edge index) up to a cap\nstatic inline int count_suffix_capped(const boost::dynamic_bitset<unsigned long long>& bs, int pos, int cap) {\n    int c = 0;\n    // find_next returns index of next set bit strictly greater than pos\n    auto idx = bs.find_next(pos);\n    while (idx != boost::dynamic_bitset<unsigned long long>::npos) {\n        ++c;\n        if (c >= cap) break;\n        idx = bs.find_next(idx);\n    }\n    return c;\n}\n\n// Helper: check if there exists a set bit strictly after pos\nstatic inline bool has_future(const boost::dynamic_bitset<unsigned long long>& bs, int pos) {\n    auto idx = bs.find_next(pos);\n    return idx != boost::dynamic_bitset<unsigned long long>::npos;\n}\n\n// Build MST of the given sparse graph E (edges) with weights = d (geometric rounded)\nstatic vector<int> build_mst_indices(const vector<Edge>& edges) {\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    // Sort by d ascending; tie-break by index for determinism\n    stable_sort(idx.begin(), idx.end(), [&](int a, int b){\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n    // DSU for MST\n    vector<int> par(N), rnk(N,0);\n    iota(par.begin(), par.end(), 0);\n    function<int(int)> fnd = [&](int x){ return par[x]==x ? x : par[x]=fnd(par[x]); };\n    auto uni = [&](int a, int b)->bool {\n        a=fnd(a); b=fnd(b);\n        if(a==b) return false;\n        if(rnk[a]<rnk[b]) swap(a,b);\n        par[b]=a;\n        if(rnk[a]==rnk[b]) rnk[a]++;\n        return true;\n    };\n    vector<int> chosen;\n    chosen.reserve(N-1);\n    for (int id : idx) {\n        int u = edges[id].u, v = edges[id].v;\n        if (uni(u, v)) {\n            chosen.push_back(id);\n            if ((int)chosen.size() == N-1) break;\n        }\n    }\n    return chosen;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Read coordinates\n    vector<int> x(N), y(N);\n    for (int i = 0; i < N; i++) {\n        if (!(cin >> x[i] >> y[i])) {\n            return 0; // Defensive: exit if input not available\n        }\n    }\n\n    // Read all edges' endpoints\n    vector<Edge> edges(M);\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        edges[i].u = u;\n        edges[i].v = v;\n        long long dx = x[u] - x[v];\n        long long dy = y[u] - y[v];\n        double dist = sqrt((double)dx * dx + (double)dy * dy);\n        edges[i].d = round_int(dist);\n        if (edges[i].d <= 0) edges[i].d = 1; // Just in case, to avoid division by zero\n    }\n\n    // Precompute per-vertex the nearest K edges by d\n    const int KNN = 3;\n    vector<vector<pair<int,int>>> adj(N); // (d, edge_index)\n    for (int i = 0; i < M; i++) {\n        adj[edges[i].u].push_back({edges[i].d, i});\n        adj[edges[i].v].push_back({edges[i].d, i});\n    }\n    for (int v = 0; v < N; v++) {\n        auto &lst = adj[v];\n        nth_element(lst.begin(), lst.begin() + min(KNN, (int)lst.size()), lst.end(),\n                    [](const auto& a, const auto& b){ return a.first < b.first; });\n        sort(lst.begin(), lst.begin() + min(KNN, (int)lst.size()),\n             [](const auto& a, const auto& b){ return a.first < b.first; });\n        for (int j = 0; j < (int)lst.size() && j < KNN; j++) {\n            edges[lst[j].second].is_nn = true;\n        }\n    }\n\n    // Offline MST on d to guide threshold\n    auto mst_idx = build_mst_indices(edges);\n    vector<char> in_mst_flag(M, 0);\n    for (int id : mst_idx) in_mst_flag[id] = 1;\n    for (int i = 0; i < M; i++) edges[i].in_mst = in_mst_flag[i];\n\n    // Quantiles of d for light guidance\n    vector<int> all_d;\n    all_d.reserve(M);\n    for (auto &e : edges) all_d.push_back(e.d);\n    vector<int> sd = all_d;\n    nth_element(sd.begin(), sd.begin() + M/4, sd.end());\n    int q25 = sd[M/4];\n    sd = all_d;\n    nth_element(sd.begin(), sd.begin() + (3*M)/4, sd.end());\n    int q75 = sd[(3*M)/4];\n\n    // DSU setup and component cut-bitsets\n    DSU dsu(N, M, {});\n    // Initialize inc bitsets: for each edge i=(u,v), it's incident to both u and v\n    for (int i = 0; i < M; i++) {\n        dsu.inc[edges[i].u].set(i);\n        dsu.inc[edges[i].v].set(i);\n    }\n\n    // Heuristic thresholds\n    const double thrStart = 1.22;\n    const double thrEnd   = 2.02;\n    const double kAlpha   = 0.78;     // added by opportunity scarcity\n    const double mstAdd   = 0.20;     // boost if in offline MST\n    const double nnAdd    = 0.08;     // boost if near-neighbor edge\n    const double smallDAdd = 0.05;    // boost for small d\n    const double largeDPen = 0.03;    // slight penalty for very large d\n    const double thrCap    = 2.60;\n    const int    kCapCount = 200;     // cap for counting future cross edges for speed/stability\n\n    // Online processing\n    for (int i = 0; i < M; i++) {\n        int l;\n        if (!(cin >> l)) return 0; // End if unexpected input issue\n\n        const Edge &e = edges[i];\n        int ru = dsu.find(e.u);\n        int rv = dsu.find(e.v);\n\n        int decision = 0;\n\n        if (ru == rv) {\n            // Internal edge -> reject to avoid cycles\n            decision = 0;\n        } else {\n            // Forced acceptance if this is the last chance for either component\n            bool must_accept = (!has_future(dsu.inc[ru], i) || !has_future(dsu.inc[rv], i));\n\n            if (must_accept) {\n                decision = 1;\n                dsu.unite(ru, rv);\n            } else {\n                // Heuristic acceptance based on ratio and opportunity\n                double r = (double)l / (double)e.d;\n                double t = (double)i / (double)M;\n                double thr = thrStart + (thrEnd - thrStart) * t;\n\n                // Future opportunities (fewer -> higher threshold)\n                int k1 = count_suffix_capped(dsu.inc[ru], i, kCapCount);\n                int k2 = count_suffix_capped(dsu.inc[rv], i, kCapCount);\n                int kmin = min(k1, k2);\n                thr += kAlpha / sqrt((double)kmin + 1.0);\n\n                // Offline hints\n                if (e.in_mst) thr += mstAdd;\n                if (e.is_nn)  thr += nnAdd;\n                if (e.d <= q25) thr += smallDAdd;\n                else if (e.d >= q75) thr -= largeDPen;\n\n                if (thr > thrCap) thr = thrCap;\n\n                if (r <= thr) {\n                    decision = 1;\n                    dsu.unite(ru, rv);\n                } else {\n                    decision = 0;\n                }\n            }\n        }\n\n        cout << decision << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pet {\n    int x, y, t;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) {\n        return 0;\n    }\n    vector<Pet> pets(N);\n    for (int i = 0; i < N; i++) {\n        int px, py, pt;\n        cin >> px >> py >> pt;\n        // convert to 0-index\n        pets[i] = {px - 1, py - 1, pt};\n    }\n    int M;\n    cin >> M;\n    vector<int> hx(M), hy(M);\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        hx[i] = x - 1;\n        hy[i] = y - 1;\n    }\n\n    const int H = 30, W = 30;\n    auto inb = [&](int x, int y)->bool { return 0 <= x && x < H && 0 <= y && y < W; };\n\n    // blocked grid\n    vector<vector<char>> blocked(H, vector<char>(W, 0));\n\n    // occupancy at start of each turn\n    vector<vector<int>> pet_here(H, vector<int>(W, 0));\n    vector<vector<int>> human_here(H, vector<int>(W, 0));\n\n    auto rebuild_human_here = [&]() {\n        for (int i = 0; i < H; i++) fill(human_here[i].begin(), human_here[i].end(), 0);\n        for (int i = 0; i < M; i++) {\n            human_here[hx[i]][hy[i]]++;\n        }\n    };\n    auto rebuild_pet_here = [&]() {\n        for (int i = 0; i < H; i++) fill(pet_here[i].begin(), pet_here[i].end(), 0);\n        for (int i = 0; i < N; i++) {\n            pet_here[pets[i].x][pets[i].y]++;\n        }\n    };\n\n    rebuild_human_here();\n    rebuild_pet_here();\n\n    // per-human closed flag\n    vector<char> closed(M, 0);\n\n    // directions: U, R, D, L order preference can be customized per human\n    const int dx4[4] = {-1, 0, 1, 0};\n    const int dy4[4] = {0, 1, 0, -1};\n    const char blockChar[4] = {'u','r','d','l'};\n\n    // Per-human preferred direction order: bias towards nearest edge\n    vector<array<int,4>> prefDir(M);\n    for (int i = 0; i < M; i++) {\n        // bias towards top/bottom and left/right depending on which side is closer\n        // Build an order: primary vertical, then primary horizontal, then the others\n        int topDist = hx[i];\n        int bottomDist = (H-1) - hx[i];\n        int leftDist = hy[i];\n        int rightDist = (W-1) - hy[i];\n\n        int firstV = (topDist <= bottomDist ? 0 : 2);   // 0: up, 2: down\n        int firstH = (leftDist <= rightDist ? 3 : 1);   // 3: left, 1: right (note: our order is U,R,D,L so map index)\n        // Construct a simple order: primary vertical, primary horizontal, other vertical, other horizontal\n        int otherV = firstV ^ 2; // swap up/down\n        int otherH = firstH ^ 2; // swap left/right (since 1^2=3,3^2=1)\n\n        prefDir[i] = { firstV, firstH, otherV, otherH };\n    }\n\n    auto count_open_neighbors = [&](int x, int y)->int {\n        int c = 0;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (!blocked[nx][ny]) c++;\n        }\n        return c;\n    };\n\n    auto can_block = [&](int tx, int ty)->bool {\n        if (!inb(tx, ty)) return false;\n        if (blocked[tx][ty]) return false;\n        // target cannot contain human or pet\n        if (human_here[tx][ty] > 0) return false;\n        if (pet_here[tx][ty] > 0) return false;\n        // no pet in 4-neighbors of target\n        for (int k = 0; k < 4; k++) {\n            int ax = tx + dx4[k], ay = ty + dy4[k];\n            if (!inb(ax, ay)) continue;\n            if (pet_here[ax][ay] > 0) return false;\n        }\n        return true;\n    };\n\n    for (int turn = 0; turn < 300; turn++) {\n        string actions(M, '.');\n\n        // Decide actions\n        for (int i = 0; i < M; i++) {\n            if (closed[i]) {\n                actions[i] = '.';\n                continue;\n            }\n            int x = hx[i], y = hy[i];\n\n            // Check how many in-bounds open neighbors remain\n            int openN = count_open_neighbors(x, y);\n\n            if (openN == 0) {\n                closed[i] = 1;\n                actions[i] = '.';\n                continue;\n            }\n\n            // If closing the last opening would seal the cell and a pet is on our cell, don't close now.\n            bool petOnMyCell = (pet_here[x][y] > 0);\n            if (openN == 1 && petOnMyCell) {\n                actions[i] = '.';\n                continue;\n            }\n\n            // Try to block one neighbor, in preferred direction order, if legal now.\n            bool did = false;\n            for (int order = 0; order < 4 && !did; order++) {\n                int d = prefDir[i][order];\n                int nx = x + dx4[d], ny = y + dy4[d];\n                if (!inb(nx, ny)) continue;\n                if (blocked[nx][ny]) continue;\n                if (can_block(nx, ny)) {\n                    actions[i] = blockChar[d];\n                    did = true;\n                }\n            }\n            if (!did) {\n                actions[i] = '.';\n            }\n        }\n\n        // Output actions and flush\n        cout << actions << '\\n' << flush;\n\n        // Apply blocks to our local grid immediately (simultaneous actions)\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'u' || c == 'd' || c == 'l' || c == 'r') {\n                int d = -1;\n                if (c == 'u') d = 0;\n                else if (c == 'r') d = 1;\n                else if (c == 'd') d = 2;\n                else if (c == 'l') d = 3;\n                int tx = hx[i] + dx4[d], ty = hy[i] + dy4[d];\n                if (inb(tx, ty)) {\n                    blocked[tx][ty] = 1;\n                }\n            }\n            // No movement in this strategy\n        }\n\n        // Read pets' moves for this turn\n        for (int i = 0; i < N; i++) {\n            string s;\n            cin >> s;\n            if (s == \".\") continue;\n            for (char mv : s) {\n                if (mv == 'U') pets[i].x -= 1;\n                else if (mv == 'D') pets[i].x += 1;\n                else if (mv == 'L') pets[i].y -= 1;\n                else if (mv == 'R') pets[i].y += 1;\n                // We trust the judge not to move pets into blocked/out-of-bounds squares.\n            }\n        }\n\n        // Rebuild occupancy for next turn\n        rebuild_pet_here();\n        // humans didn't move\n        // but we keep human_here in case of future movement; rebuild once per turn to be safe\n        rebuild_human_here();\n\n        // Update closed flags opportunistically after new blocks\n        for (int i = 0; i < M; i++) {\n            if (!closed[i]) {\n                if (count_open_neighbors(hx[i], hy[i]) == 0) {\n                    closed[i] = 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static auto st = steady_clock::now();\n    auto cur = steady_clock::now();\n    return duration<double>(cur - st).count();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj, ti, tj;\n    double p;\n    if (!(cin >> si >> sj >> ti >> tj >> p)) {\n        return 0;\n    }\n    vector<string> h(20);\n    for (int i = 0; i < 20; i++) cin >> h[i];\n    vector<string> v(19);\n    for (int i = 0; i < 19; i++) cin >> v[i];\n\n    const int H = 20, W = 20, N = H * W;\n    auto id = [&](int r, int c) { return r * W + c; };\n    int s_id = id(si, sj);\n    int t_id = id(ti, tj);\n\n    // Directions: 0=U,1=D,2=L,3=R\n    const char DIRC[4] = {'U','D','L','R'};\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n\n    // Build neighbor mapping with walls.\n    // dest[u][dir] = v if moving from u in dir is possible, else -1.\n    static int dest[400][4];\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = id(i, j);\n            // U\n            if (i > 0 && v[i-1][j] == '0') dest[u][0] = id(i-1, j);\n            else dest[u][0] = -1;\n            // D\n            if (i < H-1 && v[i][j] == '0') dest[u][1] = id(i+1, j);\n            else dest[u][1] = -1;\n            // L\n            if (j > 0 && h[i][j-1] == '0') dest[u][2] = id(i, j-1);\n            else dest[u][2] = -1;\n            // R\n            if (j < W-1 && h[i][j] == '0') dest[u][3] = id(i, j+1);\n            else dest[u][3] = -1;\n        }\n    }\n\n    // If already at target: output empty string (length 0 is allowed).\n    if (s_id == t_id) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    // Build a shortest path from s to t via BFS for initialization.\n    vector<int> par(N, -1);\n    vector<int> pdir(N, -1);\n    deque<int> dq;\n    dq.push_back(s_id);\n    par[s_id] = s_id;\n    while (!dq.empty() && par[t_id] == -1) {\n        int u = dq.front(); dq.pop_front();\n        int r = u / W, c = u % W;\n        for (int d = 0; d < 4; d++) {\n            int vtx = dest[u][d];\n            if (vtx == -1) continue;\n            if (par[vtx] != -1) continue;\n            par[vtx] = u;\n            pdir[vtx] = d;\n            dq.push_back(vtx);\n        }\n    }\n    vector<int> pathdirs;\n    if (par[t_id] != -1) {\n        int cur = t_id;\n        while (cur != s_id) {\n            pathdirs.push_back(pdir[cur]);\n            cur = par[cur];\n        }\n        reverse(pathdirs.begin(), pathdirs.end());\n    } else {\n        // Should not happen (guaranteed reachable), but fallback: random walk-ish\n        // Use a naive greedy towards target ignoring walls (still better than nothing).\n        int cr = si, cc = sj;\n        vector<int> tmp;\n        for (int k = 0; k < 400; k++) {\n            if (cr == ti && cc == tj) break;\n            int bestd = -1;\n            int bestdist = 1e9;\n            for (int d = 0; d < 4; d++) {\n                int nr = cr + dr[d], nc = cc + dc[d];\n                if (nr < 0 || nr >= H || nc < 0 || nc >= W) continue;\n                if (dest[id(cr,cc)][d] == -1) continue;\n                int md = abs(nr - ti) + abs(nc - tj);\n                if (md < bestdist) {\n                    bestdist = md; bestd = d;\n                }\n            }\n            if (bestd == -1) break;\n            tmp.push_back(bestd);\n            cr += dr[bestd]; cc += dc[bestd];\n        }\n        pathdirs = tmp;\n    }\n\n    int L = 200;\n    string seq;\n    seq.reserve(L);\n    if (!pathdirs.empty()) {\n        while ((int)seq.size() < L) {\n            for (int d: pathdirs) {\n                seq.push_back(DIRC[d]);\n                if ((int)seq.size() >= L) break;\n            }\n        }\n    } else {\n        // Fallback: simple greedy towards target repeated\n        int needD = max(0, ti - si), needU = max(0, si - ti);\n        int needR = max(0, tj - sj), needL = max(0, sj - tj);\n        vector<char> gseq;\n        for (int i = 0; i < needD; i++) gseq.push_back('D');\n        for (int i = 0; i < needU; i++) gseq.push_back('U');\n        for (int i = 0; i < needR; i++) gseq.push_back('R');\n        for (int i = 0; i < needL; i++) gseq.push_back('L');\n        if (gseq.empty()) gseq.push_back('R');\n        while ((int)seq.size() < L) {\n            for (char ch: gseq) {\n                seq.push_back(ch);\n                if ((int)seq.size() >= L) break;\n            }\n        }\n    }\n\n    // Utilities: map char to dir index\n    auto c2d = [](char c)->int {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        return 3; // 'R'\n    };\n\n    // Transition application functions\n    const double q = 1.0 - p;\n\n    auto apply_right = [&](int dir, const double* vin, double* vout) {\n        // vout = P^dir * vin (with absorbing target)\n        // clear\n        for (int i = 0; i < N; i++) vout[i] = 0.0;\n        // accumulate\n        for (int u = 0; u < N; u++) {\n            double val = vin[u];\n            if (val == 0.0) continue;\n            if (u == t_id) {\n                vout[t_id] += val;\n            } else {\n                int d = dest[u][dir];\n                if (d >= 0) {\n                    vout[d] += val * q;\n                    vout[u] += val * p;\n                } else {\n                    vout[u] += val;\n                }\n            }\n        }\n    };\n\n    auto apply_right_and_dot = [&](int dir, const double* vin, double* vout, const double* gvec) -> double {\n        // vout = P^dir * vin; return gvec dot vout\n        double sum = 0.0;\n        for (int i = 0; i < N; i++) vout[i] = 0.0;\n        for (int u = 0; u < N; u++) {\n            double val = vin[u];\n            if (val == 0.0) continue;\n            if (u == t_id) {\n                vout[t_id] += val;\n                sum += gvec[t_id] * val;\n            } else {\n                int d = dest[u][dir];\n                if (d >= 0) {\n                    double toD = val * q;\n                    double toS = val * p;\n                    vout[d] += toD;\n                    vout[u] += toS;\n                    sum += gvec[d] * toD + gvec[u] * toS;\n                } else {\n                    vout[u] += val;\n                    sum += gvec[u] * val;\n                }\n            }\n        }\n        return sum;\n    };\n\n    auto apply_left = [&](int dir, const double* gcur, double* gprev) {\n        // gprev = (P^dir)^T * gcur (with absorbing target)\n        for (int i = 0; i < N; i++) gprev[i] = 0.0;\n        // contribution from absorbing target self-loop\n        gprev[t_id] += gcur[t_id];\n        for (int u = 0; u < N; u++) {\n            if (u == t_id) continue;\n            int d = dest[u][dir];\n            if (d >= 0) {\n                gprev[u] += p * gcur[u] + q * gcur[d];\n            } else {\n                gprev[u] += gcur[u];\n            }\n        }\n    };\n\n    // Coordinate ascent optimization\n    const double TL = 1.95; // seconds\n    double start_time = now_sec();\n\n    // Buffers\n    vector<array<double, 400>> g(L); // g[t]\n    array<double, 400> gtmp;\n\n    array<double, 400> vcur;\n    array<double, 400> vtmp;\n    array<double, 400> vbest;\n\n    auto compute_backward_g = [&](const string& seq_str) {\n        // weights: for t = 0..L-2 -> 1; t = L-1 -> (401 - L)\n        for (int i = 0; i < N; i++) g[L-1][i] = 0.0;\n        g[L-1][t_id] = double(401 - L);\n        for (int t = L-2; t >= 0; t--) {\n            // g[t] = e_target + (P^{a_{t+1}})^T g[t+1]\n            // start with e_target (weight 1.0)\n            for (int i = 0; i < N; i++) g[t][i] = 0.0;\n            g[t][t_id] = 1.0;\n            int dir_next = c2d(seq_str[t+1]);\n            apply_left(dir_next, g[t+1].data(), gtmp.data());\n            for (int i = 0; i < N; i++) g[t][i] += gtmp[i];\n        }\n    };\n\n    auto forward_pass = [&](string& seq_str, double& score_out, bool& changed_out) {\n        // Use g computed for the current seq_str.\n        // Build new sequence greedily maximizing g[t]^T (P^a v_{t}).\n        for (int i = 0; i < N; i++) vcur[i] = 0.0;\n        vcur[s_id] = 1.0;\n        double score = 0.0;\n        bool changed = false;\n\n        for (int t = 0; t < L; t++) {\n            int old_dir = c2d(seq_str[t]);\n            double best_val = -1e300;\n            int best_dir = old_dir;\n            // Evaluate all 4 actions\n            for (int d = 0; d < 4; d++) {\n                double val = apply_right_and_dot(d, vcur.data(), vtmp.data(), g[t].data());\n                if (val > best_val + 1e-12 || (abs(val - best_val) <= 1e-12 && d == old_dir)) {\n                    best_val = val;\n                    best_dir = d;\n                    // copy vtmp to vbest\n                    for (int i = 0; i < N; i++) vbest[i] = vtmp[i];\n                }\n            }\n            if (best_dir != old_dir) {\n                changed = true;\n                seq_str[t] = DIRC[best_dir];\n            }\n            // advance vcur\n            for (int i = 0; i < N; i++) vcur[i] = vbest[i];\n            // accumulate E[S] using identity: sum_{t=1..L-1} F_t + (401-L) F_L\n            double Ft = vcur[t_id];\n            if (t < L - 1) score += Ft;\n            else score += double(401 - L) * Ft;\n        }\n        score_out = score;\n        changed_out = changed;\n    };\n\n    // Initial g and forward pass to compute score\n    compute_backward_g(seq);\n    double best_score = -1e300;\n    bool dummy_changed = false;\n    string best_seq = seq;\n    {\n        double s0;\n        forward_pass(seq, s0, dummy_changed);\n        best_score = s0;\n        best_seq = seq;\n    }\n\n    // Iterate passes until no improvement or time runs out\n    for (int iter = 0; iter < 1000000; iter++) {\n        if (now_sec() - start_time > TL) break;\n        compute_backward_g(seq);\n        double sc;\n        bool ch;\n        forward_pass(seq, sc, ch);\n        if (sc > best_score + 1e-9) {\n            best_score = sc;\n            best_seq = seq;\n        } else {\n            // No improvement; stop\n            break;\n        }\n    }\n\n    cout << best_seq << \"\\n\";\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\n// RNG\nstruct XorShift {\n    uint64_t x;\n    XorShift() {\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        x = seed ^ (seed << 13) ^ (seed >> 7) ^ (seed << 17);\n        if (x == 0) x = 88172645463393265ull;\n    }\n    inline uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline int randint(int l, int r) { return l + (int)(next_u32() % (uint32_t)(r - l + 1)); }\n    inline double rand01() { return (next_u32() & 0xFFFFFF) / double(0x1000000); }\n} rng;\n\n// Directions: 0=left,1=up,2=right,3=down\nstatic const int di[4] = {0,-1,0,1};\nstatic const int dj[4] = {-1,0,1,0};\n\n// to[t][d] as in statement\nstatic const int TO[8][4] = {\n    {1, 0, -1, -1},\n    {3, -1, -1, 0},\n    {-1, -1, 3, 2},\n    {-1, 2, 1, -1},\n    {1, 0, 3, 2},\n    {3, 2, 1, 0},\n    {2, -1, 0, -1},\n    {-1, 3, -1, 1},\n};\n\n// Presence\nstatic bool PRES[8][4];\n\n// For each tile type, count of entry directions that exit to given dir\nstatic int OUT_COUNT_TO[8][4];\n\n// rotate mapping\ninline int rotate_t(int t, int r) {\n    if (t < 4) return (t + r) & 3;\n    if (t < 6) return (r & 1) ? 9 - t : t; // 4 <-> 5\n    return (r & 1) ? 13 - t : t;           // 6 <-> 7\n}\n\nstatic inline int state_id(int i, int j, int d) {\n    return ((i * 30 + j) << 2) | d;\n}\n\nstruct LoopEval {\n    long long L1=0, L2=0;\n    long long product() const { return (L2==0 ? 0LL : L1*L2); }\n};\n\n// Evaluate loops using the next-state graph on states (i,j,d)\nLoopEval evaluate_loops(const array<array<int,30>,30>& eff) {\n    const int N=30, M=30, TOT=N*M*4;\n    static int next_state[30*30*4];\n    static unsigned char allowed[30*30*4];\n    // Build next mapping\n    for (int i=0;i<N;i++){\n        for (int j=0;j<M;j++){\n            int t = eff[i][j];\n            for (int d=0; d<4; d++){\n                int idx = state_id(i,j,d);\n                int d2 = TO[t][d];\n                if (d2 == -1) {\n                    allowed[idx] = 0;\n                    next_state[idx] = -1;\n                    continue;\n                }\n                allowed[idx] = 1;\n                int i2 = i + di[d2], j2 = j + dj[d2];\n                if (i2 < 0 || i2 >= N || j2 < 0 || j2 >= M) {\n                    next_state[idx] = -1;\n                } else {\n                    int t2 = eff[i2][j2];\n                    int d_rev = (d2 + 2) & 3;\n                    if (TO[t2][d_rev] == -1) next_state[idx] = -1;\n                    else next_state[idx] = state_id(i2,j2,d_rev);\n                }\n            }\n        }\n    }\n\n    // Detect cycles\n    static unsigned char state_color[30*30*4]; // 0 unvisited,1 in-stack,2 done\n    static int seen_pass[30*30*4];\n    static int seen_pos[30*30*4];\n    static int pass_id = 1;\n    memset(state_color, 0, sizeof(state_color));\n    long long best1=0, best2=0;\n    vector<int> stack;\n    stack.reserve(4096);\n\n    for (int v0=0; v0<TOT; v0++){\n        if (!allowed[v0] || state_color[v0]) continue;\n        int v = v0;\n        stack.clear();\n        ++pass_id;\n        while (true) {\n            if (v < 0 || !allowed[v] || next_state[v] == -1) {\n                for (int x : stack) state_color[x] = 2;\n                break;\n            }\n            if (state_color[v] == 2) {\n                for (int x : stack) state_color[x] = 2;\n                break;\n            }\n            if (seen_pass[v] == pass_id) {\n                int cycle_len = (int)stack.size() - seen_pos[v];\n                long long L = cycle_len;\n                if (L > best1) { best2 = best1; best1 = L; }\n                else if (L > best2) { best2 = L; }\n                for (int x : stack) state_color[x] = 2;\n                break;\n            }\n            seen_pass[v] = pass_id;\n            seen_pos[v] = (int)stack.size();\n            stack.push_back(v);\n            v = next_state[v];\n        }\n    }\n    LoopEval le; le.L1 = best1; le.L2 = best2;\n    return le;\n}\n\n// Score2: number of valid next transitions (i,j,d) that lead to in-bounds neighbor accepting entry.\nstruct Score2 {\n    int N=30, M=30;\n    // Count outgoing valid states from tile (i,j) if its tile is t (uses neighbors from eff)\n    inline int count_outgoing(const array<array<int,30>,30>& eff, int i, int j, int t) const {\n        int s=0;\n        for (int d=0; d<4; d++){\n            int d2 = TO[t][d];\n            if (d2 == -1) continue;\n            int i2 = i + di[d2], j2 = j + dj[d2];\n            if (i2 < 0 || i2 >= N || j2 < 0 || j2 >= M) continue;\n            int t2 = eff[i2][j2];\n            int d_rev = (d2 + 2) & 3;\n            if (TO[t2][d_rev] != -1) s++;\n        }\n        return s;\n    }\n\n    // Compute full S2\n    long long compute_all(const array<array<int,30>,30>& eff) const {\n        long long s=0;\n        for (int i=0;i<N;i++){\n            for (int j=0;j<M;j++){\n                int t = eff[i][j];\n                s += count_outgoing(eff, i, j, t);\n            }\n        }\n        return s;\n    }\n\n    // Delta when changing (i,j) from curT to newT.\n    long long delta_change(const array<array<int,30>,30>& eff, int i, int j, int curT, int newT) const {\n        long long delta = 0;\n        // Outgoing from (i,j)\n        delta += count_outgoing(eff, i, j, newT) - count_outgoing(eff, i, j, curT);\n        // Incoming from neighbors whose next exits into (i,j)\n        // Left neighbor -> exit dir 2 (right), we need acceptance from our left (0)\n        if (j-1 >= 0) {\n            int tL = eff[i][j-1];\n            int c = OUT_COUNT_TO[tL][2];\n            delta += c * ( (PRES[newT][0] ? 1:0) - (PRES[curT][0] ? 1:0) );\n        }\n        // Right neighbor -> exit dir 0 (left), we need acceptance from our right (2)\n        if (j+1 < M) {\n            int tR = eff[i][j+1];\n            int c = OUT_COUNT_TO[tR][0];\n            delta += c * ( (PRES[newT][2] ? 1:0) - (PRES[curT][2] ? 1:0) );\n        }\n        // Up neighbor -> exit dir 3 (down), we need acceptance from our up (1)\n        if (i-1 >= 0) {\n            int tU = eff[i-1][j];\n            int c = OUT_COUNT_TO[tU][3];\n            delta += c * ( (PRES[newT][1] ? 1:0) - (PRES[curT][1] ? 1:0) );\n        }\n        // Down neighbor -> exit dir 1 (up), we need acceptance from our down (3)\n        if (i+1 < N) {\n            int tD = eff[i+1][j];\n            int c = OUT_COUNT_TO[tD][1];\n            delta += c * ( (PRES[newT][3] ? 1:0) - (PRES[curT][3] ? 1:0) );\n        }\n        return delta;\n    }\n};\n\n// Utility: pick a boundary-aware initial rotation\nstatic int boundary_friendly_rotation(int base_t, int i, int j) {\n    const int N=30, M=30;\n    int bestR = 0, bestBad = 1e9;\n    for (int r=0; r<4; r++){\n        int tt = rotate_t(base_t, r);\n        int bad = 0;\n        if (i==0 && PRES[tt][1]) bad++;\n        if (i==N-1 && PRES[tt][3]) bad++;\n        if (j==0 && PRES[tt][0]) bad++;\n        if (j==M-1 && PRES[tt][2]) bad++;\n        if (bad < bestBad) { bestBad = bad; bestR = r; }\n    }\n    return bestR;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Precompute PRES and OUT_COUNT_TO\n    for (int t=0;t<8;t++){\n        for (int d=0; d<4; d++){\n            PRES[t][d] = (TO[t][d] != -1);\n        }\n        for (int dir=0; dir<4; dir++){\n            int c=0;\n            for (int d=0; d<4; d++) if (TO[t][d] == dir) c++;\n            OUT_COUNT_TO[t][dir] = c;\n        }\n    }\n\n    const int N=30, M=30;\n    array<array<int,30>,30> base{};\n    for (int i=0;i<N;i++){\n        string s; if(!(cin>>s)) return 0;\n        for (int j=0;j<M;j++){\n            base[i][j] = s[j]-'0';\n        }\n    }\n\n    Timer timer;\n    const double TIME_LIMIT = 1.98;\n\n    array<array<int,30>,30> rot{};\n    array<array<int,30>,30> eff{};\n\n    // Initialize rotations: boundary-friendly with small randomization\n    for (int i=0;i<N;i++){\n        for (int j=0;j<M;j++){\n            int t0 = base[i][j];\n            int rr = boundary_friendly_rotation(t0, i, j);\n            // add small randomness\n            rr = (rr + rng.randint(0,3)) & 3;\n            rot[i][j] = rr;\n            eff[i][j] = rotate_t(t0, rr);\n        }\n    }\n\n    // Phase 1: Coordinate ascent on S2 (valid next transitions)\n    Score2 scorer2;\n    long long S2 = scorer2.compute_all(eff);\n    {\n        vector<pair<int,int>> order;\n        order.reserve(N*M);\n        for (int i=0;i<N;i++) for (int j=0;j<M;j++) order.emplace_back(i,j);\n        double t_end = min(0.55, TIME_LIMIT * 0.55); // ~0.5s\n        while (timer.elapsed() < t_end) {\n            shuffle(order.begin(), order.end(), std::mt19937(rng.next_u32()));\n            bool improved_any = false;\n            for (auto &p : order) {\n                int i = p.first, j = p.second;\n                int base_t = base[i][j];\n                int curR = rot[i][j];\n                int curT = eff[i][j];\n                long long bestDelta = 0;\n                int bestR = curR;\n                // Try 4 rotations\n                for (int r=0;r<4;r++){\n                    if (r == curR) continue;\n                    int newT = rotate_t(base_t, r);\n                    long long delta = scorer2.delta_change(eff, i, j, curT, newT);\n                    if (delta > bestDelta || (delta == bestDelta && rng.rand01() < 0.1)) {\n                        bestDelta = delta;\n                        bestR = r;\n                    }\n                }\n                if (bestR != curR) {\n                    int newT = rotate_t(base_t, bestR);\n                    S2 += scorer2.delta_change(eff, i, j, curT, newT);\n                    rot[i][j] = bestR;\n                    eff[i][j] = newT;\n                    improved_any = true;\n                }\n                if (timer.elapsed() >= t_end) break;\n            }\n            if (!improved_any) break;\n        }\n    }\n\n    // Evaluate initial loops\n    LoopEval initEval = evaluate_loops(eff);\n    long long currScore = initEval.product();\n    auto currRot = rot;\n    auto currEff = eff;\n\n    // Best state\n    long long bestScore = currScore;\n    auto bestRot = rot;\n    auto bestEff = eff;\n\n    // Phase 2: Simulated annealing with proper acceptance\n    double t0 = timer.elapsed();\n    double SA_TIME = max(0.35, TIME_LIMIT - t0 - 0.03); // leave margin\n    if (SA_TIME > 0.01) {\n        const int MAX_ITERS = 30000; // dynamic cutoff\n        double startT = 5.0, endT = 0.1;\n\n        for (int it=0; it<MAX_ITERS; ++it) {\n            double e = timer.elapsed() - t0;\n            if (e > SA_TIME) break;\n            double progress = e / SA_TIME;\n            double T = startT + (endT - startT) * progress;\n\n            // Pick a tile, slightly biased random\n            int i = rng.randint(0,N-1);\n            int j = rng.randint(0,M-1);\n\n            int tbase = base[i][j];\n            int oldR = rot[i][j];\n            int newR = (oldR + rng.randint(1,3)) & 3;\n            if (newR == oldR) continue;\n\n            int oldT = eff[i][j];\n            int newT = rotate_t(tbase, newR);\n\n            // Apply tentative change\n            rot[i][j] = newR;\n            eff[i][j] = newT;\n\n            LoopEval le = evaluate_loops(eff);\n            long long newScore = le.product();\n            long long diff = newScore - currScore;\n\n            bool accept = false;\n            if (diff >= 0) accept = true;\n            else {\n                double prob = exp((double)diff / max(1.0, T));\n                if (rng.rand01() < prob) accept = true;\n            }\n            if (accept) {\n                currScore = newScore;\n                currRot = rot;\n                currEff = eff;\n                if (newScore > bestScore) {\n                    bestScore = newScore;\n                    bestRot = rot;\n                    bestEff = eff;\n                }\n            } else {\n                // revert\n                rot[i][j] = oldR;\n                eff[i][j] = oldT;\n            }\n        }\n    }\n\n    // Output best rotations\n    {\n        string out;\n        out.reserve(N*M);\n        for (int i=0;i<N;i++){\n            for (int j=0;j<M;j++){\n                out.push_back(char('0' + bestRot[i][j]));\n            }\n        }\n        cout << out << \"\\n\";\n    }\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timing guard\nstatic inline double now_sec() {\n    using clk = chrono::high_resolution_clock;\n    return chrono::duration<double>(clk::now().time_since_epoch()).count();\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n_) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        p.resize(n);\n        sz.assign(n, 0);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Eval {\n    int largestTree = 0;\n    int largestCC = 0;\n    int cyclesInLargestCC = 0;\n    int totalEdges = 0;\n    int loops2x2 = 0;\n    int cyclesTotal = 0;\n};\n\nstruct ScoreKey {\n    // Larger is better.\n    int largestTree;\n    int negCyclesTotal;\n    int largestCC;\n    int negCyclesInLargestCC;\n    int totalEdges;\n    int negLoops2x2;\n    // For random tie-break\n    uint32_t tieRand;\n};\n\nstatic inline bool better_key(const ScoreKey& a, const ScoreKey& b) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.negCyclesTotal != b.negCyclesTotal) return a.negCyclesTotal > b.negCyclesTotal;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.negCyclesInLargestCC != b.negCyclesInLargestCC) return a.negCyclesInLargestCC > b.negCyclesInLargestCC;\n    if (a.totalEdges != b.totalEdges) return a.totalEdges > b.totalEdges;\n    if (a.negLoops2x2 != b.negLoops2x2) return a.negLoops2x2 > b.negLoops2x2;\n    return a.tieRand < b.tieRand; // smaller random wins deterministically if same seed, but randomizes a bit\n}\n\nstatic inline int hexchar_to_int(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    if ('a' <= c && c <= 'f') return 10 + (c - 'a');\n    if ('A' <= c && c <= 'F') return 10 + (c - 'A');\n    return 0;\n}\n\nstruct Board {\n    int N;\n    vector<int> a; // size N*N, value 0 is the empty\n    int zr, zc;\n\n    inline bool in_bounds(int r, int c) const {\n        return (0 <= r && r < N && 0 <= c && c < N);\n    }\n\n    // dir: 0=U,1=D,2=L,3=R (empty moves in that direction)\n    inline bool applyMove(int dir) {\n        static const int dr[4] = {-1, +1, 0, 0};\n        static const int dc[4] = {0, 0, -1, +1};\n        int nr = zr + dr[dir], nc = zc + dc[dir];\n        if (!in_bounds(nr, nc)) return false;\n        int zidx = zr * N + zc;\n        int nidx = nr * N + nc;\n        swap(a[zidx], a[nidx]);\n        zr = nr; zc = nc;\n        return true;\n    }\n};\n\nstruct Evaluator {\n    int N, n2;\n    DSU dsu;\n    vector<char> occ;\n    vector<int> deg;         // degree per vertex in matched graph\n    vector<int> compDegSum;  // sum of deg per component\n\n    Evaluator() {}\n    Evaluator(int N_) { init(N_); }\n    void init(int N_) {\n        N = N_; n2 = N*N;\n        dsu.init(n2);\n        occ.assign(n2, 0);\n        deg.assign(n2, 0);\n        compDegSum.assign(n2, 0);\n    }\n\n    Eval evaluate(const Board& B) {\n        const int L = 1, U = 2, R = 4, D = 8;\n        // reset\n        fill(occ.begin(), occ.end(), 0);\n        fill(deg.begin(), deg.end(), 0);\n        iota(dsu.p.begin(), dsu.p.end(), 0);\n        fill(dsu.sz.begin(), dsu.sz.end(), 0);\n\n        // mark occupied and init DSU sizes\n        for (int i = 0; i < N; ++i) {\n            int base = i * N;\n            for (int j = 0; j < N; ++j) {\n                int id = base + j;\n                if (B.a[id] != 0) {\n                    occ[id] = 1;\n                    dsu.sz[id] = 1;\n                } else {\n                    occ[id] = 0;\n                    dsu.sz[id] = 0;\n                }\n            }\n        }\n\n        int totalEdges = 0;\n        // Unite along matched edges and accumulate degrees\n        // Vertical\n        for (int i = 0; i < N-1; ++i) {\n            int base = i * N;\n            int base2 = (i+1) * N;\n            for (int j = 0; j < N; ++j) {\n                int id1 = base + j;\n                int id2 = base2 + j;\n                int m1 = B.a[id1], m2 = B.a[id2];\n                if ((m1 & D) && (m2 & U)) {\n                    totalEdges++;\n                    deg[id1]++; deg[id2]++;\n                    if (occ[id1] && occ[id2]) dsu.unite(id1, id2);\n                }\n            }\n        }\n        // Horizontal\n        for (int i = 0; i < N; ++i) {\n            int base = i * N;\n            for (int j = 0; j < N-1; ++j) {\n                int id1 = base + j;\n                int id2 = base + (j+1);\n                int m1 = B.a[id1], m2 = B.a[id2];\n                if ((m1 & R) && (m2 & L)) {\n                    totalEdges++;\n                    deg[id1]++; deg[id2]++;\n                    if (occ[id1] && occ[id2]) dsu.unite(id1, id2);\n                }\n            }\n        }\n\n        // Count 2x2 loops\n        int loops2x2 = 0;\n        for (int i = 0; i < N-1; ++i) {\n            int base = i * N;\n            int base2 = (i+1) * N;\n            for (int j = 0; j < N-1; ++j) {\n                int id00 = base + j;\n                int id01 = base + (j+1);\n                int id10 = base2 + j;\n                int id11 = base2 + (j+1);\n                int m00 = B.a[id00], m01 = B.a[id01], m10 = B.a[id10], m11 = B.a[id11];\n                bool v1 = (m00 & D) && (m10 & U);\n                bool v2 = (m01 & D) && (m11 & U);\n                bool h1 = (m00 & R) && (m01 & L);\n                bool h2 = (m10 & R) && (m11 & L);\n                if (v1 && v2 && h1 && h2) loops2x2++;\n            }\n        }\n\n        // Sum degrees per component\n        fill(compDegSum.begin(), compDegSum.end(), 0);\n        for (int id = 0; id < n2; ++id) {\n            if (!occ[id]) continue;\n            int r = dsu.find(id);\n            compDegSum[r] += deg[id];\n        }\n\n        int largestCC = 0;\n        int largestTree = 0;\n        int cyclesInLargestCC = 0;\n        int cyclesTotal = 0;\n\n        vector<char> seen(n2, 0);\n        for (int id = 0; id < n2; ++id) {\n            if (!occ[id]) continue;\n            int r = dsu.find(id);\n            if (seen[r]) continue;\n            seen[r] = 1;\n            int V = dsu.sz[r];\n            int E = compDegSum[r] / 2; // each edge counted twice in sums\n            int cyc = E - (V - 1);\n            if (V > largestCC) {\n                largestCC = V;\n                cyclesInLargestCC = max(0, cyc);\n            } else if (V == largestCC) {\n                cyclesInLargestCC = min(cyclesInLargestCC, max(0, cyc));\n            }\n            if (E == V - 1) {\n                if (V > largestTree) largestTree = V;\n            }\n            if (cyc > 0) cyclesTotal += cyc;\n        }\n\n        Eval ev;\n        ev.largestTree = largestTree;\n        ev.largestCC = largestCC;\n        ev.cyclesInLargestCC = cyclesInLargestCC;\n        ev.totalEdges = totalEdges;\n        ev.loops2x2 = loops2x2;\n        ev.cyclesTotal = cyclesTotal;\n        return ev;\n    }\n};\n\nstatic inline ScoreKey make_key(const Eval& ev, std::mt19937& rng) {\n    ScoreKey k;\n    k.largestTree = ev.largestTree;\n    k.negCyclesTotal = -ev.cyclesTotal;\n    k.largestCC = ev.largestCC;\n    k.negCyclesInLargestCC = -ev.cyclesInLargestCC;\n    k.totalEdges = ev.totalEdges;\n    k.negLoops2x2 = -ev.loops2x2;\n    k.tieRand = rng();\n    return k;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    if (!(cin >> N >> T)) return 0;\n    vector<string> ts(N);\n    for (int i = 0; i < N; ++i) cin >> ts[i];\n\n    Board B;\n    B.N = N;\n    B.a.assign(N*N, 0);\n    B.zr = -1; B.zc = -1;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int v = hexchar_to_int(ts[i][j]);\n            B.a[i*N + j] = v;\n            if (v == 0) { B.zr = i; B.zc = j; }\n        }\n    }\n\n    Evaluator evaluator(N);\n\n    string ans;\n    ans.reserve(T);\n\n    // Random source\n    std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Directions: 0=U,1=D,2=L,3=R\n    static const int dr[4] = {-1, +1, 0, 0};\n    static const int dc[4] = {0, 0, -1, +1};\n    static const char mvch[4] = {'U', 'D', 'L', 'R'};\n    static const int opp[4] = {1, 0, 3, 2};\n\n    // Shallow DFS lookahead depth\n    int maxDepth = (N <= 7 ? 5 : 4);\n\n    auto in_bounds = [&](int r, int c) -> bool {\n        return (0 <= r && r < N && 0 <= c && c < N);\n    };\n\n    double t_start = now_sec();\n    const double TIME_LIMIT = 2.95; // seconds\n\n    // Early check: if already perfect (unlikely)\n    Eval ev0 = evaluator.evaluate(B);\n    if (ev0.largestTree == N*N - 1) {\n        cout << \"\" << '\\n';\n        return 0;\n    }\n\n    // DFS search per step to choose next move\n    vector<int> curPath;\n    vector<int> bestPath;\n\n    // Pre-allocated space to avoid reallocation in recursion\n    curPath.reserve(16);\n    bestPath.reserve(16);\n\n    // Recursive DFS lambda\n    function<void(int,int,int,ScoreKey&,bool&)> dfs = [&](int depth, int maxD, int lastDir, ScoreKey& bestKey, bool& timeUp) {\n        if (timeUp) return;\n        if (depth == maxD) {\n            Eval ev = evaluator.evaluate(B);\n            ScoreKey key = make_key(ev, rng);\n            if (better_key(key, bestKey)) {\n                bestKey = key;\n                bestPath = curPath;\n            }\n            return;\n        }\n        // Candidate moves (avoid immediate reversal within this path)\n        // We do not reorder candidates to keep overhead small\n        for (int dir = 0; dir < 4; ++dir) {\n            if (lastDir != -1 && dir == opp[lastDir]) continue;\n            int nr = B.zr + dr[dir];\n            int nc = B.zc + dc[dir];\n            if (!in_bounds(nr, nc)) continue;\n\n            // Apply\n            bool ok = B.applyMove(dir);\n            if (!ok) continue; // shouldn't happen\n            curPath.push_back(dir);\n\n            // Time guard: every few nodes, check time\n            if ((depth & 3) == 0) {\n                double elapsed = now_sec() - t_start;\n                if (elapsed > TIME_LIMIT) {\n                    timeUp = true;\n                    // Undo and return\n                    curPath.pop_back();\n                    B.applyMove(opp[dir]);\n                    return;\n                }\n            }\n\n            dfs(depth+1, maxD, dir, bestKey, timeUp);\n\n            // Undo\n            curPath.pop_back();\n            B.applyMove(opp[dir]);\n            if (timeUp) return;\n        }\n    };\n\n    for (int step = 0; step < T; ++step) {\n        // Time safety: if close to limit, fall back to simple greedy or stop\n        double elapsed = now_sec() - t_start;\n        if (elapsed > TIME_LIMIT) break;\n\n        // Search best first move by depth-limited DFS\n        curPath.clear();\n        bestPath.clear();\n        ScoreKey bestKey = {-1, INT_MIN, -1, INT_MIN, -1, INT_MIN, 0};\n        bool timeUp = false;\n        dfs(0, maxDepth, -1, bestKey, timeUp);\n\n        int chosenDir = -1;\n        if (!bestPath.empty()) {\n            chosenDir = bestPath[0];\n        } else {\n            // Fallback: choose any legal move (prefer the best 1-step)\n            ScoreKey localBest = {-1, INT_MIN, -1, INT_MIN, -1, INT_MIN, 0};\n            for (int dir = 0; dir < 4; ++dir) {\n                int nr = B.zr + dr[dir];\n                int nc = B.zc + dc[dir];\n                if (!in_bounds(nr, nc)) continue;\n                B.applyMove(dir);\n                Eval ev = evaluator.evaluate(B);\n                ScoreKey key = make_key(ev, rng);\n                if (better_key(key, localBest)) {\n                    localBest = key;\n                    chosenDir = dir;\n                }\n                B.applyMove(opp[dir]);\n            }\n            if (chosenDir == -1) {\n                // No move available (should not occur), break\n                break;\n            }\n        }\n\n        // Execute move\n        B.applyMove(chosenDir);\n        ans.push_back(mvch[chosenDir]);\n\n        // Optional: early terminate if perfect tree achieved\n        Eval ev = evaluator.evaluate(B);\n        if (ev.largestTree == N*N - 1) {\n            // We can stop here to get better K in perfect cases\n            break;\n        }\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\n\nstruct Normal {\n    long long nx, ny; // gcd must be 1\n};\n\nstruct WeightSpec {\n    int mode;      // 0: uniform; 1: symmetric center-heavy (r<1); 2: monotonic (r<1)\n    long double r; // ratio parameter (unused for uniform)\n};\n\nstatic vector<long double> make_weights(int m, const WeightSpec& ws) {\n    vector<long double> w(m, 1.0L);\n    if (m <= 0) return w;\n    if (ws.mode == 0) {\n        for (int i = 0; i < m; ++i) w[i] = 1.0L;\n    } else if (ws.mode == 1) {\n        long double mid = (m - 1) * 0.5L;\n        for (int i = 0; i < m; ++i) {\n            long double d = fabsl((long double)i - mid);\n            w[i] = pow(ws.r, d);\n        }\n    } else if (ws.mode == 2) {\n        long double val = 1.0L;\n        for (int i = 0; i < m; ++i) {\n            w[i] = val;\n            val *= ws.r;\n        }\n    } else {\n        // fallback uniform\n        for (int i = 0; i < m; ++i) w[i] = 1.0L;\n    }\n    long double s = 0;\n    for (auto &x : w) s += x;\n    if (s > 0) for (auto &x : w) x /= s;\n    return w;\n}\n\n// Convert fractional weights to integer targets summing to N using largest remainder method.\nstatic vector<int> targets_from_weights(const vector<long double>& w, int N) {\n    int m = (int)w.size();\n    vector<int> tgt(m, 0);\n    vector<pair<long double,int>> frac; frac.reserve(m);\n    long double sum_floor = 0;\n    for (int i = 0; i < m; ++i) {\n        long double val = (long double)N * w[i];\n        int f = (int)floor(val);\n        tgt[i] = f;\n        sum_floor += f;\n        frac.emplace_back(val - f, i);\n    }\n    int rem = N - (int)sum_floor;\n    if (rem > 0) {\n        sort(frac.begin(), frac.end(), [](const auto& a, const auto& b){ return a.first > b.first; });\n        for (int k = 0; k < rem && k < m; ++k) {\n            tgt[frac[k].second]++;\n        }\n    }\n    return tgt;\n}\n\n// Build list of safe j where we can cut between arr[j] and arr[j+1] at an integer T (gap >= 2).\n// Plus sentinels -1 and N-1 (far outside).\nstatic vector<int> build_safe_indices(const vector<long long>& arr) {\n    int N = (int)arr.size();\n    vector<int> safe;\n    safe.reserve(N + 2);\n    safe.push_back(-1);\n    for (int j = 0; j + 1 < N; ++j) {\n        if (arr[j+1] - arr[j] >= 2) {\n            safe.push_back(j);\n        }\n    }\n    safe.push_back(N - 1);\n    return safe;\n}\n\n// Choose safe index j >= min_j that is closest to target t.\nstatic int choose_nearest_safe(const vector<int>& safe, int t, int min_j) {\n    int lo = 0, hi = (int)safe.size();\n    while (lo < hi) {\n        int mid = (lo + hi) >> 1;\n        if (safe[mid] < t) lo = mid + 1;\n        else hi = mid;\n    }\n    long long bestDist = (1LL<<60);\n    int best = -1;\n    // check candidate at lo\n    for (int k = lo - 1; k <= lo; ++k) {\n        if (k < 0 || k >= (int)safe.size()) continue;\n        int cand = safe[k];\n        if (cand < min_j) continue;\n        long long dist = llabs((long long)cand - (long long)t);\n        if (dist < bestDist) {\n            bestDist = dist;\n            best = cand;\n        }\n    }\n    if (best == -1) {\n        // fallback: first safe >= min_j\n        int idx = lower_bound(safe.begin(), safe.end(), min_j) - safe.begin();\n        if (idx >= (int)safe.size()) idx = (int)safe.size() - 1;\n        best = safe[idx];\n    }\n    return best;\n}\n\n// Plan line constants T from arr_sorted and per-segment targets inc (length L = num_lines).\n// Returns sorted vector of T (ascending).\nstatic vector<long long> plan_lines_from_targets_ll(const vector<long long>& arr_sorted, const vector<int>& inc) {\n    int N = (int)arr_sorted.size();\n    int L = (int)inc.size();\n    vector<int> safe = build_safe_indices(arr_sorted);\n    vector<long long> lines; lines.reserve(L);\n\n    int pos = 0; // index of next point not yet assigned to left segments\n    int leftExtra = 0, rightExtra = 0;\n    long long minV = arr_sorted.front();\n    long long maxV = arr_sorted.back();\n\n    int prev_j = -1;\n\n    for (int i = 0; i < L; ++i) {\n        int c = inc[i];\n        if (pos >= N) {\n            long long T = maxV + 1 + rightExtra;\n            lines.push_back(T);\n            rightExtra++;\n            continue;\n        }\n        if (c <= 0) {\n            // create empty segment at far left\n            long long T = minV - 1 - leftExtra;\n            lines.push_back(T);\n            leftExtra++;\n            continue;\n        }\n        int desired = pos + c - 1;\n        if (desired < pos - 1) desired = pos - 1;\n        if (desired > N - 1) desired = N - 1;\n        int j = choose_nearest_safe(safe, desired, pos - 1);\n        long long T;\n        if (j == -1) {\n            T = minV - 1 - leftExtra;\n            leftExtra++;\n        } else if (j >= 0 && j < N - 1) {\n            T = arr_sorted[j] + 1; // safe integer between\n        } else {\n            T = maxV + 1 + rightExtra;\n            rightExtra++;\n        }\n        lines.push_back(T);\n        if (j >= pos - 1) pos = max(pos, j + 1);\n        prev_j = j;\n    }\n    sort(lines.begin(), lines.end());\n    return lines;\n}\n\nstatic inline long long dotll(long long ax, long long ay, long long bx, long long by) {\n    return ax*bx + ay*by;\n}\n\n// Extended GCD: ax + by = g\nstatic long long extgcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) { x = (a >= 0 ? 1 : -1); y = 0; return llabs(a); }\n    long long x1, y1;\n    long long g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\n// For normal n=(nx,ny) and integer T with gcd(nx,ny)=1, find two integer points on the line nx*x + ny*y = T.\nstatic pair<pair<long long,long long>, pair<long long,long long>> line_endpoints(const Normal& n, long long T) {\n    long long nx = n.nx, ny = n.ny;\n    long long x0, y0;\n    long long g = extgcd(nx, ny, x0, y0); // nx*x0 + ny*y0 = g or -g\n    if (g < 0) { g = -g; x0 = -x0; y0 = -y0; }\n    // Adjust to exact T\n    // When gcd(nx,ny)=1, g=1. If not, T must be divisible by g. We assume gcd=1 in our normals.\n    long long mul = T / g;\n    long long px = x0 * mul;\n    long long py = y0 * mul;\n    // direction vector perpendicular to normal\n    long long dx = -ny;\n    long long dy = nx;\n    // Two distinct points\n    long long px2 = px + dx; long long py2 = py + dy;\n    return {{px, py}, {px2, py2}};\n}\n\nstruct Candidate {\n    vector<long long> Tx; // constants for family 1 (columns)\n    vector<long long> Ty; // constants for family 2 (rows)\n    Normal nx, ny;\n    long long score;\n};\n\n// Compute the score for given lines and normals.\n// u = n1 dot p, v = n2 dot p\nstatic long long evaluate_score(const vector<long long>& Tx, const vector<long long>& Ty,\n                                const vector<long long>& u, const vector<long long>& v,\n                                const array<int,11>& a) {\n    int V = (int)Tx.size();\n    int H = (int)Ty.size();\n    int C = V + 1;\n    int R = H + 1;\n    vector<int> counts(C * R, 0);\n    // map points\n    for (size_t i = 0; i < u.size(); ++i) {\n        int ci = (int)(lower_bound(Tx.begin(), Tx.end(), u[i]) - Tx.begin());\n        int ri = (int)(lower_bound(Ty.begin(), Ty.end(), v[i]) - Ty.begin());\n        if (ci < 0) ci = 0; if (ci > V) ci = V;\n        if (ri < 0) ri = 0; if (ri > H) ri = H;\n        counts[ri * C + ci] += 1;\n    }\n    array<int,11> b{}; // b[1..10]\n    for (int val : counts) {\n        if (val >= 1 && val <= 10) b[val]++;\n    }\n    long long s = 0;\n    for (int d = 1; d <= 10; ++d) {\n        s += min(a[d], b[d]);\n    }\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, K;\n    if (!(cin >> N >> K)) return 0;\n    array<int,11> a{}; // [1..10]\n    for (int d = 1; d <= 10; ++d) cin >> a[d];\n    vector<Point> pts(N);\n    for (int i = 0; i < N; ++i) cin >> pts[i].x >> pts[i].y;\n\n    // Orientation pairs (co-prime normals)\n    vector<pair<Normal,Normal>> orientations = {\n        {{1,0},{0,1}},\n        {{1,1},{1,-1}},\n        {{2,1},{1,2}},\n        {{3,1},{1,3}},\n        {{2,1},{1,-1}},\n    };\n\n    // Weight specs for columns/rows\n    vector<WeightSpec> weightOptions = {\n        {0, 1.0L},   // uniform\n        {1, 0.90L},  // symmetric center-heavy\n        {1, 0.85L},  // stronger symmetric center-heavy\n        {2, 0.90L},  // monotonic\n    };\n\n    // Total lines to use (<= K)\n    vector<int> kList;\n    for (int x : {40, 60, 80, 100}) if (x <= K) kList.push_back(x);\n    if (kList.empty()) kList.push_back(min(K, 40));\n\n    // V/H balance options as portions\n    vector<long double> alphaList = {0.4L, 0.5L, 0.6L};\n\n    Candidate best;\n    best.score = -1;\n\n    // For each orientation, precompute u and v arrays and their sorted versions\n    for (auto &orn : orientations) {\n        Normal nx = orn.first;\n        Normal ny = orn.second;\n        // Ensure gcd=1 (safety)\n        auto gcd1 = [](long long a, long long b){ return std::gcd(llabs(a), llabs(b)); };\n        if (gcd1(nx.nx, nx.ny) != 1) continue;\n        if (gcd1(ny.nx, ny.ny) != 1) continue;\n\n        // Compute u, v\n        vector<long long> u(N), v(N);\n        for (int i = 0; i < N; ++i) {\n            u[i] = nx.nx * (long long)pts[i].x + nx.ny * (long long)pts[i].y;\n            v[i] = ny.nx * (long long)pts[i].x + ny.ny * (long long)pts[i].y;\n        }\n        // Sorted arrays for safe indices\n        vector<long long> uSorted = u, vSorted = v;\n        sort(uSorted.begin(), uSorted.end());\n        sort(vSorted.begin(), vSorted.end());\n\n        vector<int> safeU = build_safe_indices(uSorted);\n        vector<int> safeV = build_safe_indices(vSorted);\n\n        for (int kUse : kList) {\n            // balances\n            for (long double alpha : alphaList) {\n                int V = (int)llround(alpha * kUse);\n                if (V < 1) V = 1;\n                if (V > kUse - 1) V = kUse - 1;\n                int H = kUse - V;\n                if (H < 1) continue;\n\n                int C = V + 1;\n                int R = H + 1;\n\n                // For each weight option pair\n                for (const auto &wc : weightOptions) {\n                    vector<long double> wcol = make_weights(C, wc);\n                    vector<int> colCounts = targets_from_weights(wcol, N);\n                    // Avoid too many inner zeros clustered: not necessary as plan handles zeros to outsides.\n\n                    for (const auto &wr : weightOptions) {\n                        vector<long double> wrow = make_weights(R, wr);\n                        vector<int> rowCounts = targets_from_weights(wrow, N);\n\n                        // Convert per-column counts (C) to per-line increments (C-1):\n                        vector<int> colInc(colCounts.begin(), colCounts.end() - 1);\n                        vector<int> rowInc(rowCounts.begin(), rowCounts.end() - 1);\n\n                        // Plan lines using safe positions\n                        vector<long long> Tx = plan_lines_from_targets_ll(uSorted, colInc);\n                        vector<long long> Ty = plan_lines_from_targets_ll(vSorted, rowInc);\n\n                        // Evaluate\n                        long long sc = evaluate_score(Tx, Ty, u, v, a);\n\n                        if (sc > best.score) {\n                            best.score = sc;\n                            best.Tx = move(Tx);\n                            best.Ty = move(Ty);\n                            best.nx = nx;\n                            best.ny = ny;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Fallback if somehow nothing chosen\n    if (best.score < 0) {\n        // trivial: no cuts\n        cout << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Output lines: from normals and constants to two integer points\n    int V = (int)best.Tx.size();\n    int H = (int)best.Ty.size();\n    cout << (V + H) << \"\\n\";\n\n    // Family 1 (columns)\n    for (int i = 0; i < V; ++i) {\n        auto ep = line_endpoints(best.nx, best.Tx[i]);\n        auto [p, q] = ep;\n        cout << p.first << \" \" << p.second << \" \" << q.first << \" \" << q.second << \"\\n\";\n    }\n    // Family 2 (rows)\n    for (int j = 0; j < H; ++j) {\n        auto ep = line_endpoints(best.ny, best.Ty[j]);\n        auto [p, q] = ep;\n        cout << p.first << \" \" << p.second << \" \" << q.first << \" \" << q.second << \"\\n\";\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Operation {\n    int x1,y1,x2,y2,x3,y3,x4,y4;\n};\n\n// Global-like context (wrapped into a class-like namespace by static vars/functions)\nstruct Solver {\n    int N, M;\n    vector<uint8_t> occ; // N*N occupancy grid\n    vector<pair<int,int>> points; // all dots as they appear (initial + added)\n    int c; // center coordinate (N-1)/2\n\n    // used unit segments\n    vector<uint8_t> usedH; // size N*(N-1): seg (x,y)-(x+1,y), x in [0..N-2], y in [0..N-1]\n    vector<uint8_t> usedV; // size (N-1)*N: seg (x,y)-(x,y+1), y in [0..N-2], x in [0..N-1]\n    vector<uint8_t> usedD1; // size (N-1)*(N-1): seg (x,y)-(x+1,y+1), x,y in [0..N-2]\n    vector<uint8_t> usedD2; // size (N-1)*(N-1): seg (x,y)-(x+1,y-1), x in [0..N-2], y in [1..N-1] mapped to index (y-1)*(N-1)+x\n\n    inline int idx(int x, int y) const { return y*N + x; }\n    inline int idxH(int x, int y) const { return y*(N-1) + x; }\n    inline int idxV(int x, int y) const { return y*N + x; }\n    inline int idxD1_fromPoints(int x0, int y0, int x1, int y1) const {\n        // slope +1 segment normalized: (min x, min y)\n        int x = min(x0, x1);\n        int y = min(y0, y1);\n        return y*(N-1) + x;\n    }\n    inline int idxD2_fromPoints(int x0, int y0, int x1, int y1) const {\n        // slope -1 segment normalized: (min x, max y), then (y-1)*(N-1)+x\n        int x = min(x0, x1);\n        int y = max(y0, y1); // this y is in [1..N-1]\n        return (y-1)*(N-1) + x;\n    }\n\n    inline int weight(int x, int y) const {\n        int dx = x - c;\n        int dy = y - c;\n        return dx*dx + dy*dy + 1;\n    }\n\n    struct Candidate {\n        // type 0: axis-aligned rectangle\n        // type 1: 45\u00b0 square (diamond)\n        int type;\n        int p1x, p1y;\n        int w;\n        // axis-aligned fields\n        int xL, xR, yB, yT;\n        // diamond fields\n        int xc, yc, d;\n    };\n\n    struct CandCmp {\n        bool operator()(const Candidate& a, const Candidate& b) const {\n            if (a.w != b.w) return a.w < b.w; // max-heap by weight\n            // tie-breaker: prefer larger span (more \"outer\")\n            int aa = (a.type==0) ? ((a.xR - a.xL) + (a.yT - a.yB)) : (2*a.d);\n            int bb = (b.type==0) ? ((b.xR - b.xL) + (b.yT - b.yB)) : (2*b.d);\n            if (aa != bb) return aa < bb;\n            // small deterministic tie-break\n            if (a.p1x != b.p1x) return a.p1x < b.p1x;\n            return a.p1y < b.p1y;\n        }\n    };\n\n    priority_queue<Candidate, vector<Candidate>, CandCmp> pq;\n    vector<Operation> ops;\n\n    Solver(int N_, int M_) : N(N_), M(M_) {\n        c = (N - 1) / 2;\n        occ.assign(N*N, 0);\n        usedH.assign(N*(N-1), 0);\n        usedV.assign((N-1)*N, 0);\n        usedD1.assign((N-1)*(N-1), 0);\n        usedD2.assign((N-1)*(N-1), 0);\n    }\n\n    inline bool isInside(int x, int y) const {\n        return (0 <= x && x < N && 0 <= y && y < N);\n    }\n\n    bool validateAxis(const Candidate& cd) const {\n        // Preconds: cd.type==0\n        // Check p1 empty\n        if (!isInside(cd.p1x, cd.p1y)) return false;\n        if (occ[idx(cd.p1x, cd.p1y)]) return false;\n        // Check other three corners occupied\n        int cntExist = 0;\n        int cx[4] = {cd.xL, cd.xR, cd.xR, cd.xL};\n        int cy[4] = {cd.yB, cd.yB, cd.yT, cd.yT};\n        for (int i=0;i<4;i++) {\n            if (cx[i]==cd.p1x && cy[i]==cd.p1y) continue;\n            if (!isInside(cx[i],cy[i])) return false;\n            if (!occ[idx(cx[i], cy[i])]) return false;\n            cntExist++;\n        }\n        if (cntExist != 3) return false;\n\n        // Boundary interior points must be empty\n        for (int x = cd.xL+1; x <= cd.xR-1; ++x) {\n            if (occ[idx(x, cd.yB)]) return false;\n            if (occ[idx(x, cd.yT)]) return false;\n        }\n        for (int y = cd.yB+1; y <= cd.yT-1; ++y) {\n            if (occ[idx(cd.xL, y)]) return false;\n            if (occ[idx(cd.xR, y)]) return false;\n        }\n\n        // Check used segments\n        for (int x = cd.xL; x <= cd.xR-1; ++x) {\n            if (usedH[idxH(x, cd.yB)]) return false;\n            if (usedH[idxH(x, cd.yT)]) return false;\n        }\n        for (int y = cd.yB; y <= cd.yT-1; ++y) {\n            if (usedV[idxV(cd.xL, y)]) return false;\n            if (usedV[idxV(cd.xR, y)]) return false;\n        }\n        return true;\n    }\n\n    bool validateDiamond(const Candidate& cd) const {\n        // Preconds: cd.type==1\n        int xc = cd.xc, yc = cd.yc, d = cd.d;\n        if (d <= 0) return false;\n        // four corners\n        int tx = xc, ty = yc + d; // top\n        int rx = xc + d, ry = yc; // right\n        int bx = xc, by = yc - d; // bottom\n        int lx = xc - d, ly = yc; // left\n\n        // Ensure inside\n        if (!isInside(cd.p1x, cd.p1y)) return false;\n        if (!isInside(tx,ty) || !isInside(rx,ry) || !isInside(bx,by) || !isInside(lx,ly)) return false;\n\n        // p1 empty\n        if (occ[idx(cd.p1x, cd.p1y)]) return false;\n\n        // other three corners occupied\n        int cornersX[4] = {tx, rx, bx, lx};\n        int cornersY[4] = {ty, ry, by, ly};\n        int cntExist = 0;\n        for (int i=0;i<4;i++) {\n            if (cornersX[i]==cd.p1x && cornersY[i]==cd.p1y) continue;\n            if (!occ[idx(cornersX[i], cornersY[i])]) return false;\n            cntExist++;\n        }\n        if (cntExist != 3) return false;\n\n        // Perimeter interior points empty\n        // top->right: (xc+k, yc+d-k) for k=1..d-1\n        for (int k=1; k<=d-1; ++k) {\n            if (occ[idx(xc + k, yc + d - k)]) return false;\n        }\n        // right->bottom: (xc+d-k, yc - k) for k=1..d-1\n        for (int k=1; k<=d-1; ++k) {\n            if (occ[idx(xc + d - k, yc - k)]) return false;\n        }\n        // bottom->left: (xc - k, yc - d + k) for k=1..d-1\n        for (int k=1; k<=d-1; ++k) {\n            if (occ[idx(xc - k, yc - d + k)]) return false;\n        }\n        // left->top: (xc - d + k, yc + k) for k=1..d-1\n        for (int k=1; k<=d-1; ++k) {\n            if (occ[idx(xc - d + k, yc + k)]) return false;\n        }\n\n        // Check used diagonal segments\n        // top->right: slope -1, segments between (xc+k, yc+d-k) -> (xc+k+1, yc+d-k-1), k=0..d-1\n        for (int k=0; k<=d-1; ++k) {\n            int x0 = xc + k, y0 = yc + d - k;\n            int x1 = xc + k + 1, y1 = yc + d - k - 1;\n            int id = idxD2_fromPoints(x0,y0,x1,y1);\n            if (usedD2[id]) return false;\n        }\n        // right->bottom: slope +1, between (xc+d-k, yc-k) -> (xc+d-k-1, yc-k-1)\n        for (int k=0; k<=d-1; ++k) {\n            int x0 = xc + d - k, y0 = yc - k;\n            int x1 = xc + d - k - 1, y1 = yc - k - 1;\n            int id = idxD1_fromPoints(x0,y0,x1,y1);\n            if (usedD1[id]) return false;\n        }\n        // bottom->left: slope -1, between (xc - k, yc - d + k) -> (xc - k - 1, yc - d + k + 1)\n        for (int k=0; k<=d-1; ++k) {\n            int x0 = xc - k, y0 = yc - d + k;\n            int x1 = xc - k - 1, y1 = yc - d + k + 1;\n            int id = idxD2_fromPoints(x0,y0,x1,y1);\n            if (usedD2[id]) return false;\n        }\n        // left->top: slope +1, between (xc - d + k, yc + k) -> (xc - d + k + 1, yc + k + 1)\n        for (int k=0; k<=d-1; ++k) {\n            int x0 = xc - d + k, y0 = yc + k;\n            int x1 = xc - d + k + 1, y1 = yc + k + 1;\n            int id = idxD1_fromPoints(x0,y0,x1,y1);\n            if (usedD1[id]) return false;\n        }\n\n        return true;\n    }\n\n    bool validate(const Candidate& cd) const {\n        if (cd.type == 0) return validateAxis(cd);\n        else return validateDiamond(cd);\n    }\n\n    void markUsedSegments(const Candidate& cd) {\n        if (cd.type == 0) {\n            // Horizontal edges\n            for (int x = cd.xL; x <= cd.xR-1; ++x) {\n                usedH[idxH(x, cd.yB)] = 1;\n                usedH[idxH(x, cd.yT)] = 1;\n            }\n            // Vertical edges\n            for (int y = cd.yB; y <= cd.yT-1; ++y) {\n                usedV[idxV(cd.xL, y)] = 1;\n                usedV[idxV(cd.xR, y)] = 1;\n            }\n        } else {\n            int xc = cd.xc, yc = cd.yc, d = cd.d;\n            // top->right\n            for (int k=0; k<=d-1; ++k) {\n                int x0 = xc + k, y0 = yc + d - k;\n                int x1 = xc + k + 1, y1 = yc + d - k - 1;\n                int id = idxD2_fromPoints(x0,y0,x1,y1);\n                usedD2[id] = 1;\n            }\n            // right->bottom\n            for (int k=0; k<=d-1; ++k) {\n                int x0 = xc + d - k, y0 = yc - k;\n                int x1 = xc + d - k - 1, y1 = yc - k - 1;\n                int id = idxD1_fromPoints(x0,y0,x1,y1);\n                usedD1[id] = 1;\n            }\n            // bottom->left\n            for (int k=0; k<=d-1; ++k) {\n                int x0 = xc - k, y0 = yc - d + k;\n                int x1 = xc - k - 1, y1 = yc - d + k + 1;\n                int id = idxD2_fromPoints(x0,y0,x1,y1);\n                usedD2[id] = 1;\n            }\n            // left->top\n            for (int k=0; k<=d-1; ++k) {\n                int x0 = xc - d + k, y0 = yc + k;\n                int x1 = xc - d + k + 1, y1 = yc + k + 1;\n                int id = idxD1_fromPoints(x0,y0,x1,y1);\n                usedD1[id] = 1;\n            }\n        }\n    }\n\n    void emitOperation(const Candidate& cd) {\n        Operation op;\n        if (cd.type == 0) {\n            // cw order: LL -> LR -> UR -> UL\n            int LLx = cd.xL, LLy = cd.yB;\n            int LRx = cd.xR, LRy = cd.yB;\n            int URx = cd.xR, URy = cd.yT;\n            int ULx = cd.xL, ULy = cd.yT;\n            array<pair<int,int>,4> seq = {{{LLx,LLy},{LRx,LRy},{URx,URy},{ULx,ULy}}};\n            int pos = 0;\n            for (int i=0;i<4;i++) if (seq[i].first==cd.p1x && seq[i].second==cd.p1y) { pos=i; break; }\n            auto get = [&](int k)->pair<int,int> { return seq[(pos + k) % 4]; };\n            auto p1 = get(0);\n            auto p2 = get(1);\n            auto p3 = get(2);\n            auto p4 = get(3);\n            op = {p1.first,p1.second,p2.first,p2.second,p3.first,p3.second,p4.first,p4.second};\n        } else {\n            // diamond cw top->right->bottom->left\n            int tx = cd.xc, ty = cd.yc + cd.d; // top\n            int rx = cd.xc + cd.d, ry = cd.yc; // right\n            int bx = cd.xc, by = cd.yc - cd.d; // bottom\n            int lx = cd.xc - cd.d, ly = cd.yc; // left\n            array<pair<int,int>,4> seq = {{{tx,ty},{rx,ry},{bx,by},{lx,ly}}};\n            int pos = 0;\n            for (int i=0;i<4;i++) if (seq[i].first==cd.p1x && seq[i].second==cd.p1y) { pos=i; break; }\n            auto get = [&](int k)->pair<int,int> { return seq[(pos + k) % 4]; };\n            auto p1 = get(0);\n            auto p2 = get(1);\n            auto p3 = get(2);\n            auto p4 = get(3);\n            op = {p1.first,p1.second,p2.first,p2.second,p3.first,p3.second,p4.first,p4.second};\n        }\n        ops.push_back(op);\n    }\n\n    void pushAxisCandidateFromPair(int x1, int y1, int x2, int y2) {\n        if (x1 == x2 || y1 == y2) return; // need diagonal pair\n        int xL = min(x1, x2), xR = max(x1, x2);\n        int yB = min(y1, y2), yT = max(y1, y2);\n        int c1x = x1, c1y = y2; // (x1,y2)\n        int c2x = x2, c2y = y1; // (x2,y1)\n        bool occ1 = occ[idx(c1x, c1y)];\n        bool occ2 = occ[idx(c2x, c2y)];\n        if (occ1 == occ2) return; // need exactly one occupied\n        Candidate cd;\n        cd.type = 0;\n        if (!occ1) { cd.p1x = c1x; cd.p1y = c1y; }\n        else       { cd.p1x = c2x; cd.p1y = c2y; }\n        cd.xL = xL; cd.xR = xR; cd.yB = yB; cd.yT = yT;\n        cd.w = weight(cd.p1x, cd.p1y);\n        if (validate(cd)) pq.push(cd);\n    }\n\n    void pushDiamondCandidateFromVerticalPair(int x, int y1, int y2) {\n        if (y1 == y2) return;\n        int dAbs = abs(y2 - y1);\n        if (dAbs % 2 != 0) return;\n        int d = dAbs / 2;\n        if (d == 0) return;\n        int yc = (y1 + y2) / 2;\n        int xc = x;\n        int lx = xc - d, ly = yc;\n        int rx = xc + d, ry = yc;\n        if (!isInside(lx,ly) || !isInside(rx,ry)) return;\n        bool occL = occ[idx(lx,ly)];\n        bool occR = occ[idx(rx,ry)];\n        if (occL == occR) return; // need exactly one\n        Candidate cd;\n        cd.type = 1;\n        cd.xc = xc; cd.yc = yc; cd.d = d;\n        if (!occL) { cd.p1x = lx; cd.p1y = ly; }\n        else       { cd.p1x = rx; cd.p1y = ry; }\n        cd.w = weight(cd.p1x, cd.p1y);\n        if (validate(cd)) pq.push(cd);\n    }\n\n    void pushDiamondCandidateFromHorizontalPair(int y, int x1, int x2) {\n        if (x1 == x2) return;\n        int dAbs = abs(x2 - x1);\n        if (dAbs % 2 != 0) return;\n        int d = dAbs / 2;\n        if (d == 0) return;\n        int xc = (x1 + x2) / 2;\n        int yc = y;\n        int tx = xc, ty = yc + d;\n        int bx = xc, by = yc - d;\n        if (!isInside(tx,ty) || !isInside(bx,by)) return;\n        bool occT = occ[idx(tx,ty)];\n        bool occB = occ[idx(bx,by)];\n        if (occT == occB) return;\n        Candidate cd;\n        cd.type = 1;\n        cd.xc = xc; cd.yc = yc; cd.d = d;\n        if (!occT) { cd.p1x = tx; cd.p1y = ty; }\n        else       { cd.p1x = bx; cd.p1y = by; }\n        cd.w = weight(cd.p1x, cd.p1y);\n        if (validate(cd)) pq.push(cd);\n    }\n\n    void initialCandidates() {\n        int P = (int)points.size();\n        for (int i=0;i<P;i++) {\n            auto [x1,y1] = points[i];\n            for (int j=i+1;j<P;j++) {\n                auto [x2,y2] = points[j];\n                // Axis-aligned rectangle candidates\n                pushAxisCandidateFromPair(x1,y1,x2,y2);\n                // Diamond candidates from vertical/horizontal pairs\n                if (x1 == x2) {\n                    pushDiamondCandidateFromVerticalPair(x1, y1, y2);\n                }\n                if (y1 == y2) {\n                    pushDiamondCandidateFromHorizontalPair(y1, x1, x2);\n                }\n            }\n        }\n    }\n\n    void generateFromNewPoint(int nx, int ny) {\n        int P = (int)points.size() - 1; // existing points excluding the newly appended? We'll iterate all previous\n        for (int i=0;i<P;i++) {\n            int x2 = points[i].first;\n            int y2 = points[i].second;\n            // Axis-aligned: (nx,ny) with (x2,y2) as diagonal corners\n            if (nx != x2 && ny != y2) {\n                pushAxisCandidateFromPair(nx,ny,x2,y2);\n            }\n            // Diamond: vertical/horizontal pairs\n            if (nx == x2) {\n                pushDiamondCandidateFromVerticalPair(nx, ny, y2);\n            }\n            if (ny == y2) {\n                pushDiamondCandidateFromHorizontalPair(ny, nx, x2);\n            }\n        }\n    }\n\n    void solve() {\n        // initial candidates\n        initialCandidates();\n\n        auto start = chrono::steady_clock::now();\n        const double TIME_LIMIT = 4.90; // seconds\n\n        while (!pq.empty()) {\n            // time check\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - start).count();\n            if (elapsed > TIME_LIMIT) break;\n\n            Candidate cd = pq.top(); pq.pop();\n            if (!validate(cd)) continue;\n\n            // Commit this operation\n            // place p1\n            occ[idx(cd.p1x, cd.p1y)] = 1;\n            points.emplace_back(cd.p1x, cd.p1y);\n            // mark used segments\n            markUsedSegments(cd);\n            // record output operation\n            emitOperation(cd);\n            // generate new candidates involving the new point\n            generateFromNewPoint(cd.p1x, cd.p1y);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) {\n        return 0;\n    }\n    Solver solver(N, M);\n    solver.points.reserve(N*N);\n    for (int i=0;i<M;i++) {\n        int x,y; cin >> x >> y;\n        solver.points.emplace_back(x,y);\n        solver.occ[solver.idx(x,y)] = 1;\n    }\n\n    solver.solve();\n\n    // Output\n    cout << solver.ops.size() << '\\n';\n    for (auto &op : solver.ops) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << ' '\n             << op.x3 << ' ' << op.y3 << ' ' << op.x4 << ' ' << op.y4 << '\\n';\n    }\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    void reset(int m){ n=m; p.resize(n); sz.assign(n,1); iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\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; sz[a]+=sz[b];\n        return true;\n    }\n    int size(int x){ return sz[find(x)]; }\n};\n\nstruct Simulator {\n    static const int H = 10;\n    static const int W = 10;\n    array<array<int,W>,H> board;\n\n    Simulator() { for (int r=0;r<H;r++) for (int c=0;c<W;c++) board[r][c]=0; }\n\n    pair<int,int> emptyIndexToRC(int p) const {\n        int cnt=0;\n        for(int r=0;r<H;r++){\n            for(int c=0;c<W;c++){\n                if(board[r][c]==0){\n                    ++cnt;\n                    if(cnt==p) return {r,c};\n                }\n            }\n        }\n        return {-1,-1};\n    }\n\n    struct SimResult {\n        array<array<int,W>,H> b;\n        int new_r, new_c;\n    };\n\n    // dir: 0=F,1=B,2=L,3=R\n    SimResult simulateTilt(const array<array<int,W>,H>& inputBoard, int dir, int src_r, int src_c) const {\n        SimResult res;\n        for (int r=0;r<H;r++) for (int c=0;c<W;c++) res.b[r][c]=0;\n\n        if (dir == 0) { // F\n            int cnt = 0;\n            for (int r=0; r<=src_r; ++r) if (inputBoard[r][src_c]!=0) ++cnt;\n            res.new_r = cnt-1; res.new_c = src_c;\n            for (int c=0;c<W;c++){\n                int to=0;\n                for (int r=0;r<H;r++){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[to++][c] = v;\n                }\n            }\n        } else if (dir == 1) { // B\n            int cnt = 0;\n            for (int r=src_r; r<H; ++r) if (inputBoard[r][src_c]!=0) ++cnt;\n            res.new_r = H-1-(cnt-1); res.new_c = src_c;\n            for (int c=0;c<W;c++){\n                int to=H-1;\n                for (int r=H-1;r>=0;r--){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[to--][c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            int cnt = 0;\n            for (int c=0; c<=src_c; ++c) if (inputBoard[src_r][c]!=0) ++cnt;\n            res.new_r = src_r; res.new_c = cnt-1;\n            for (int r=0;r<H;r++){\n                int to=0;\n                for (int c=0;c<W;c++){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[r][to++] = v;\n                }\n            }\n        } else { // R\n            int cnt = 0;\n            for (int c=src_c; c<W; ++c) if (inputBoard[src_r][c]!=0) ++cnt;\n            res.new_r = src_r; res.new_c = W-1-(cnt-1);\n            for (int r=0;r<H;r++){\n                int to=W-1;\n                for (int c=W-1;c>=0;c--){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[r][to--] = v;\n                }\n            }\n        }\n        return res;\n    }\n};\n\nstatic const int H = Simulator::H;\nstatic const int W = Simulator::W;\n\n// Compute sum of squared component sizes for same-color connectivity\nlong long sumSqComponents(const array<array<int,W>,H>& b) {\n    DSU dsu(H*W);\n    auto id = [](int r,int c){ return r*W + c; };\n    for (int r=0;r<H;r++){\n        for (int c=0;c<W;c++){\n            int v = b[r][c];\n            if (!v) continue;\n            if (r+1<H && b[r+1][c]==v) dsu.unite(id(r,c), id(r+1,c));\n            if (c+1<W && b[r][c+1]==v) dsu.unite(id(r,c), id(r,c+1));\n        }\n    }\n    vector<int> cnt(H*W,0);\n    for (int r=0;r<H;r++) for (int c=0;c<W;c++) if (b[r][c]!=0) cnt[dsu.find(id(r,c))]++;\n    long long ans=0;\n    for (int i=0;i<H*W;i++) if (cnt[i]>0) ans += 1LL*cnt[i]*cnt[i];\n    return ans;\n}\n\n// Count number of undirected equal-color adjacent pairs\nlong long adjacencyPairs(const array<array<int,W>,H>& b) {\n    long long cnt=0;\n    for (int r=0;r<H;r++){\n        for (int c=0;c<W;c++){\n            int v = b[r][c];\n            if (!v) continue;\n            if (r+1<H && b[r+1][c]==v) cnt++;\n            if (c+1<W && b[r][c+1]==v) cnt++;\n        }\n    }\n    return cnt;\n}\n\n// Movement distance for a tilt from board0 (before tilt)\nlong long totalMovementDistance(const array<array<int,W>,H>& b0, int dir) {\n    long long mv=0;\n    if (dir==0){ // F\n        for (int c=0;c<W;c++){\n            vector<int> rows;\n            rows.reserve(H);\n            for (int r=0;r<H;r++) if (b0[r][c]!=0) rows.push_back(r);\n            for (int i=0;i<(int)rows.size();i++){\n                mv += rows[i] - i;\n            }\n        }\n    } else if (dir==1){ // B\n        for (int c=0;c<W;c++){\n            vector<int> rows;\n            rows.reserve(H);\n            for (int r=0;r<H;r++) if (b0[r][c]!=0) rows.push_back(r);\n            int k = (int)rows.size();\n            for (int i=0;i<k;i++){\n                int newr = H - k + i;\n                mv += newr - rows[i];\n            }\n        }\n    } else if (dir==2){ // L\n        for (int r=0;r<H;r++){\n            vector<int> cols;\n            cols.reserve(W);\n            for (int c=0;c<W;c++) if (b0[r][c]!=0) cols.push_back(c);\n            for (int j=0;j<(int)cols.size();j++){\n                mv += cols[j] - j;\n            }\n        }\n    } else { // R\n        for (int r=0;r<H;r++){\n            vector<int> cols;\n            cols.reserve(W);\n            for (int c=0;c<W;c++) if (b0[r][c]!=0) cols.push_back(c);\n            int k = (int)cols.size();\n            for (int j=0;j<k;j++){\n                int newc = W - k + j;\n                mv += newc - cols[j];\n            }\n        }\n    }\n    return mv;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> f(100);\n    for (int i=0;i<100;i++){\n        if(!(cin>>f[i])) return 0;\n    }\n\n    Simulator sim;\n\n    // Precompute manhattan distances from all cells to 4 corners\n    array<pair<int,int>,4> corners = { pair<int,int>{0,0}, {0,9}, {9,0}, {9,9} };\n    int distToCorner[4][H][W];\n    for (int k=0;k<4;k++){\n        auto [tr,tc] = corners[k];\n        for (int r=0;r<H;r++) for (int c=0;c<W;c++) distToCorner[k][r][c] = abs(r-tr)+abs(c-tc);\n    }\n\n    // Prepare all 4P3=24 mappings: map[1]=corner for color1, map[2]=..., map[3]=...\n    vector<array<int,4>> mappings;\n    array<int,4> perm = {0,1,2,3};\n    sort(perm.begin(), perm.end());\n    do{\n        array<int,4> m = {0, perm[0], perm[1], perm[2]};\n        mappings.push_back(m);\n    }while(next_permutation(perm.begin(), perm.end()));\n    // current mapping (for potential future use / tie-breaks), start with some default\n    array<int,4> currentMap = mappings[0];\n\n    for (int t=0;t<100;t++){\n        int p; if(!(cin>>p)) return 0;\n\n        // Place the new candy at p-th empty\n        auto [r,c] = sim.emptyIndexToRC(p);\n        auto board0 = sim.board;\n        int color = f[t];\n        board0[r][c] = color;\n\n        // Progress-based weights\n        double progress = (t<=99 ? (double)t/99.0 : 1.0);\n\n        double w_comp       = 6.0 + 24.0*progress;            // emphasize components more later\n        double w_compDelta  = 2.0 + 6.0*progress;             // reward immediate merges\n        double w_adjDelta   = 4.0 + 12.0*progress;            // reward new adjacencies\n        double w_sumDist    = 0.30 - 0.15*progress;           // small pull to corners; decrease over time\n        double w_newAbs     = 1.5*(1.0-progress) + 0.2;       // absolute new dist (bigger early)\n        double w_newDelta   = 2.4*(1.0 - 0.3*progress);       // encourage immediate reduction\n        double w_adjNewSame = 1.5 + 2.5*progress;             // local merging for the new candy\n        double w_adjNewDiff = 0.4 + 0.2*progress;             // avoid bad neighbors\n        double w_move       = 0.03 + 0.25*progress;           // stability penalty (small early, bigger late)\n\n        // Precompute mapping-independent quantities per direction\n        long long sumSq0 = sumSqComponents(board0);\n        long long adjBefore = adjacencyPairs(board0);\n\n        array<Simulator::SimResult,4> ress;\n        array<long long,4> sumSqAfter;\n        array<long long,4> adjAfter;\n        array<long long,4> moveDist;\n        array<int,4> adjNewSame;\n        array<int,4> adjNewDiff;\n\n        static const int dr4[4] = {-1,1,0,0};\n        static const int dc4[4] = {0,0,-1,1};\n\n        for (int d=0; d<4; d++){\n            ress[d] = sim.simulateTilt(board0, d, r, c);\n            sumSqAfter[d] = sumSqComponents(ress[d].b);\n            adjAfter[d]   = adjacencyPairs(ress[d].b);\n            moveDist[d]   = totalMovementDistance(board0, d);\n\n            // new candy neighborhood\n            int nr = ress[d].new_r, nc = ress[d].new_c;\n            int same=0, diff=0;\n            if (0<=nr && nr<H && 0<=nc && nc<W) {\n                for (int k=0;k<4;k++){\n                    int rr = nr + dr4[k], cc = nc + dc4[k];\n                    if (0<=rr && rr<H && 0<=cc && cc<W) {\n                        int v = ress[d].b[rr][cc];\n                        if (!v) continue;\n                        if (v == color) same++;\n                        else diff++;\n                    }\n                }\n            }\n            adjNewSame[d] = same;\n            adjNewDiff[d] = diff;\n        }\n\n        // Evaluate all mappings and directions\n        double bestScore = -1e100;\n        int bestDir = 0;\n        array<int,4> bestMap = currentMap;\n\n        // Precompute newDistBefore for each mapping (depends only on (r,c) and mapping)\n        for (const auto& cmap : mappings) {\n            int cornerIdx = cmap[color];\n            int newDistBefore = distToCorner[cornerIdx][r][c];\n\n            for (int d=0; d<4; d++){\n                // mapping-dependent sums\n                long long sumDistAfter = 0;\n                const auto& B = ress[d].b;\n                for (int rr=0; rr<H; rr++){\n                    for (int cc=0; cc<W; cc++){\n                        int v = B[rr][cc];\n                        if (!v) continue;\n                        int idx = cmap[v];\n                        sumDistAfter += distToCorner[idx][rr][cc];\n                    }\n                }\n                int nr = ress[d].new_r, nc = ress[d].new_c;\n                int newDistAfter = (0<=nr && nr<H && 0<=nc && nc<W) ? distToCorner[cornerIdx][nr][nc] : 0;\n\n                double score = 0.0;\n                score += w_comp * (double)sumSqAfter[d];\n                score += w_compDelta * (double)(sumSqAfter[d] - sumSq0);\n                score += w_adjDelta * (double)(adjAfter[d] - adjBefore);\n                score -= w_sumDist * (double)sumDistAfter;\n                // new-candy terms\n                score -= w_newAbs * (double)newDistAfter;\n                score += w_newDelta * (double)(newDistBefore - newDistAfter);\n                score += w_adjNewSame * (double)adjNewSame[d];\n                score -= w_adjNewDiff * (double)adjNewDiff[d];\n                // movement penalty\n                score -= w_move * (double)moveDist[d];\n\n                // slight tie-breaker: prefer keeping current mapping (consistency)\n                if (cmap == currentMap) score += 0.1;\n\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestDir = d;\n                    bestMap = cmap;\n                }\n            }\n        }\n\n        // Output for first 99 steps\n        if (t < 99) {\n            static const char dirs[4] = {'F','B','L','R'};\n            cout << dirs[bestDir] << '\\n' << flush;\n        }\n\n        // Update board and adopt the mapping that justified the choice\n        sim.board = ress[bestDir].b;\n        currentMap = bestMap;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Utility timer (not strictly needed)\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nstatic inline int ceil_log2_int(int x) {\n    int l = 0;\n    int v = 1;\n    while (v < x) { v <<= 1; l++; }\n    return l;\n}\n\n// Build an L x A binary matrix alpha with column sums t[a],\n// trying to keep row sums near A/2 and pairwise distances large.\nstatic vector<vector<int>> build_alpha(int Lbits, int A, const vector<int>& t, mt19937_64 &rng) {\n    vector<vector<int>> alpha(Lbits, vector<int>(A, 0));\n    vector<int> rowSum(Lbits, 0);\n\n    // Initial greedy fill: for each column a, place t[a] ones in rows with smallest rowSum\n    for (int a = 0; a < A; ++a) {\n        int need = t[a];\n        vector<int> idx(Lbits);\n        iota(idx.begin(), idx.end(), 0);\n        stable_sort(idx.begin(), idx.end(), [&](int r1, int r2){\n            if (rowSum[r1] != rowSum[r2]) return rowSum[r1] < rowSum[r2];\n            return r1 < r2;\n        });\n        for (int k = 0; k < need; ++k) {\n            int r = idx[k];\n            alpha[r][a] = 1;\n            rowSum[r]++;\n        }\n    }\n\n    // Try local improvements: swap bits within columns to maximize min pairwise Hamming distance\n    auto min_pairwise_dist = [&]() {\n        int mind = INT_MAX;\n        for (int i = 0; i < Lbits; ++i) {\n            for (int j = i+1; j < Lbits; ++j) {\n                int d = 0;\n                for (int a = 0; a < A; ++a) if (alpha[i][a] != alpha[j][a]) d++;\n                mind = min(mind, d);\n            }\n        }\n        return mind;\n    };\n    int currentMinD = min_pairwise_dist();\n\n    // Limit local search iterations for speed; dims are tiny so it's enough\n    uniform_int_distribution<int> distA(0, A-1);\n    uniform_int_distribution<int> distR(0, Lbits-1);\n    for (int iter = 0; iter < 2000; ++iter) {\n        int a = distA(rng);\n        // pick two rows with different bits\n        int r1 = distR(rng), r2 = distR(rng);\n        if (r1 == r2) continue;\n        if (alpha[r1][a] == alpha[r2][a]) continue;\n        // try swapping: 1->0 on r1 and 0->1 on r2, preserving column sum\n        alpha[r1][a] ^= 1;\n        alpha[r2][a] ^= 1;\n\n        int newMinD = min_pairwise_dist();\n        // Row sum balancing heuristic: prefer row sums near A/2 (or within +-2)\n        auto penalty = [&](const vector<int>& rs) {\n            int p = 0;\n            int target = A/2;\n            for (int r = 0; r < Lbits; ++r) {\n                int d = abs(rs[r] - target);\n                p += d*d;\n            }\n            return p;\n        };\n        vector<int> rowSumNew = rowSum;\n        rowSumNew[r1] += (alpha[r1][a] ? 1 : -1);\n        rowSumNew[r2] += (alpha[r2][a] ? 1 : -1);\n        int oldPen = penalty(rowSum);\n        int newPen = penalty(rowSumNew);\n\n        bool accept = false;\n        if (newMinD > currentMinD) accept = true;\n        else if (newMinD == currentMinD && newPen <= oldPen) accept = true;\n\n        if (accept) {\n            currentMinD = newMinD;\n            rowSum = rowSumNew;\n        } else {\n            // revert\n            alpha[r1][a] ^= 1;\n            alpha[r2][a] ^= 1;\n        }\n    }\n\n    return alpha;\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    mt19937_64 rng(123456789);\n\n    // Parameters\n    int Lbits = ceil_log2_int(M); // number of bits to encode\n    Lbits = max(Lbits, 1); // safety\n    // Anchors count: use A = Lbits + 1 so we can set column sums t[a] = a\n    int A = Lbits + 1;\n\n    // Choose cluster size g based on eps and fit N<=100 later\n    int g_desired;\n    if (eps <= 0.06) g_desired = 8;\n    else if (eps <= 0.14) g_desired = 9;\n    else g_desired = 10;\n\n    // Column sums t[a] = a (0..Lbits), ensure A = Lbits+1\n    vector<int> t(A);\n    for (int a = 0; a < A; ++a) t[a] = a;\n\n    // Build alpha (depends only on Lbits, A, t)\n    auto alpha = build_alpha(Lbits, A, t, rng);\n\n    // Row sums: to estimate cluster vertex degrees\n    vector<int> rowSum(Lbits, 0);\n    for (int i = 0; i < Lbits; ++i) {\n        for (int a = 0; a < A; ++a) rowSum[i] += alpha[i][a];\n    }\n    int rowSumMax = 0;\n    for (int i = 0; i < Lbits; ++i) rowSumMax = max(rowSumMax, rowSum[i]);\n\n    // pads U to ensure anchor min degree > cluster max degree (with margin)\n    // Anchor min degree = (A-1) [anchor clique] + U + g * t_min = (A-1) + U (since t_min=0)\n    // Cluster vertex max degree \u2248 rowSumMax + (g-1) (if the bit=1); add margin\n    int margin = 3;\n    int g = g_desired;\n    int U = 0;\n    while (true) {\n        int clusterMaxDeg = rowSumMax + (g - 1);\n        int Utarget = max(0, clusterMaxDeg + margin - (A - 1));\n        int N0 = A + Lbits * g;\n        if (N0 > 100) {\n            g--;\n            if (g < 6) { g = 6; /* minimal fallback */ break; }\n            continue;\n        }\n        if (N0 + Utarget <= 100) {\n            U = Utarget;\n            break;\n        } else {\n            g--;\n            if (g < 6) {\n                // Force U to fit\n                U = max(0, 100 - (A + Lbits * g));\n                break;\n            }\n        }\n    }\n    int N = A + U + Lbits * g;\n    int T = N * (N - 1) / 2;\n\n    // Precompute pair index mapping\n    vector<int> offset(N+1, 0);\n    for (int i = 1; i <= N; ++i) {\n        offset[i] = offset[i-1] + (N - i);\n    }\n    auto idx = [&](int i, int j) -> int {\n        if (i > j) swap(i, j);\n        // Now i<j\n        return offset[i] + (j - i - 1);\n    };\n\n    // Vertex ranges\n    // Anchors: 0..A-1\n    // Pads: A..A+U-1\n    // Clusters: for bit i in [0..Lbits-1], vertices [A+U + i*g, A+U + (i+1)*g - 1]\n    auto is_anchor = [&](int v) { return v >= 0 && v < A; };\n    auto is_pad = [&](int v) { return v >= A && v < A + U; };\n    auto cluster_start = [&](int bit) { return A + U + bit * g; };\n    auto cluster_end = [&](int bit) { return A + U + (bit + 1) * g - 1; };\n\n    // Build base string: all '0'\n    string base(T, '0');\n\n    // Anchors fully connected (clique)\n    for (int i = 0; i < A; ++i) {\n        for (int j = i + 1; j < A; ++j) {\n            base[idx(i, j)] = '1';\n        }\n    }\n\n    // Anchors connected to all pads\n    for (int a = 0; a < A; ++a) {\n        for (int p = A; p < A + U; ++p) {\n            base[idx(a, p)] = '1';\n        }\n    }\n\n    // Anchor-to-cluster edges: for cluster i and anchor a, connect to all vertices if alpha[i][a]==1\n    for (int i = 0; i < Lbits; ++i) {\n        int s = cluster_start(i), e = cluster_end(i);\n        for (int a = 0; a < A; ++a) {\n            if (alpha[i][a]) {\n                for (int v = s; v <= e; ++v) {\n                    base[idx(a, v)] = '1';\n                }\n            }\n        }\n    }\n\n    // Precompute positions of internal edges for each cluster\n    vector<vector<int>> clusterEdgePos(Lbits);\n    for (int i = 0; i < Lbits; ++i) {\n        int s = cluster_start(i), e = cluster_end(i);\n        for (int u = s; u <= e; ++u) {\n            for (int v = u + 1; v <= e; ++v) {\n                clusterEdgePos[i].push_back(idx(u, v));\n            }\n        }\n    }\n\n    // Output N and M graphs\n    cout << N << \"\\n\";\n    cout.flush();\n    // For each k, copy base and set cluster internal edges according to bits of k\n    for (int k = 0; k < M; ++k) {\n        string out = base;\n        for (int i = 0; i < Lbits; ++i) {\n            int bit = (k >> i) & 1;\n            if (bit) {\n                for (int pos : clusterEdgePos[i]) out[pos] = '1';\n            } else {\n                for (int pos : clusterEdgePos[i]) out[pos] = '0';\n            }\n        }\n        cout << out << \"\\n\";\n    }\n    cout.flush();\n\n    // Precompute some constants for decoding\n    double log_p1 = log(max(1e-12, 1.0 - eps));\n    double log_q1 = log(max(1e-12, eps));\n    double log_p0 = log(max(1e-12, eps));\n    double log_q0 = log(max(1e-12, 1.0 - eps));\n\n    // Decoding 100 queries\n    for (int q = 0; q < 100; ++q) {\n        string H; cin >> H;\n\n        // Build adjacency and degree for H\n        vector<int> deg(N, 0);\n        static bool adj[105][105];\n        for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) adj[i][j] = false;\n\n        int pos = 0;\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                bool b = (H[pos++] == '1');\n                if (b) {\n                    adj[i][j] = adj[j][i] = true;\n                    deg[i]++; deg[j]++;\n                }\n            }\n        }\n\n        // Identify anchors: top A by degree\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        nth_element(ord.begin(), ord.begin() + A, ord.end(), [&](int x, int y){\n            return deg[x] > deg[y];\n        });\n        vector<int> anchors(ord.begin(), ord.begin() + A);\n        // Sort anchors by degree ascending to align with t[a] ascending (0..Lbits)\n        sort(anchors.begin(), anchors.end(), [&](int x, int y){\n            if (deg[x] != deg[y]) return deg[x] < deg[y];\n            return x < y;\n        });\n\n        // Map vertex -> anchor index [0..A-1], or -1 if not an anchor\n        vector<int> isAnchorIndex(N, -1);\n        for (int a = 0; a < A; ++a) isAnchorIndex[anchors[a]] = a;\n\n        // Prepare per-vertex anchor adjacency bit vector and distances to each cluster alpha row\n        // We'll compute distances for all non-anchor vertices\n        vector<array<int, 16>> distToRow(N); // store distances up to Lbits (<=7)\n        vector<int> isNonAnchor;\n        isNonAnchor.reserve(N - A);\n        for (int v = 0; v < N; ++v) if (isAnchorIndex[v] < 0) isNonAnchor.push_back(v);\n\n        for (int v : isNonAnchor) {\n            // anchor-adjacency vector: for anchor index a in 0..A-1 corresponds to anchors[a] vertex\n            // compute distance to each row i\n            for (int i = 0; i < Lbits; ++i) {\n                int d = 0;\n                for (int a = 0; a < A; ++a) {\n                    bool e = adj[v][anchors[a]];\n                    int bit = alpha[i][a];\n                    if ((int)e != bit) d++;\n                }\n                distToRow[v][i] = d;\n            }\n        }\n\n        // Global greedy assignment: fill each cluster with g vertices minimizing Hamming distance\n        // Build candidate list (i, v, dist)\n        struct Cand { int dist; int i; int v; };\n        vector<Cand> cands;\n        cands.reserve(isNonAnchor.size() * Lbits);\n        for (int v : isNonAnchor) {\n            for (int i = 0; i < Lbits; ++i) {\n                cands.push_back({distToRow[v][i], i, v});\n            }\n        }\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){\n            if (a.dist != b.dist) return a.dist < b.dist;\n            if (a.i != b.i) return a.i < b.i;\n            return a.v < b.v;\n        });\n        vector<int> assignedCount(Lbits, 0);\n        vector<char> used(N, 0);\n        vector<vector<int>> clusterVerts(Lbits);\n        for (auto &c : cands) {\n            if (assignedCount[c.i] >= g) continue;\n            if (used[c.v]) continue;\n            // avoid picking anchors accidentally\n            if (isAnchorIndex[c.v] >= 0) continue;\n            clusterVerts[c.i].push_back(c.v);\n            used[c.v] = 1;\n            assignedCount[c.i]++;\n            bool allFull = true;\n            for (int i = 0; i < Lbits; ++i) if (assignedCount[i] < g) { allFull = false; break; }\n            if (allFull) break;\n        }\n        // If still lacking for some cluster, fill arbitrarily from remaining non-anchors\n        for (int i = 0; i < Lbits; ++i) {\n            if ((int)clusterVerts[i].size() < g) {\n                for (int v : isNonAnchor) {\n                    if (!used[v]) {\n                        clusterVerts[i].push_back(v);\n                        used[v] = 1;\n                        if ((int)clusterVerts[i].size() >= g) break;\n                    }\n                }\n            }\n        }\n        // Truncate overfull (shouldn't happen here)\n        for (int i = 0; i < Lbits; ++i) {\n            if ((int)clusterVerts[i].size() > g) {\n                clusterVerts[i].resize(g);\n            }\n        }\n\n        // Count edges inside each cluster\n        vector<int> x(Lbits, 0), pairCount(Lbits, 0);\n        for (int i = 0; i < Lbits; ++i) {\n            auto &vec = clusterVerts[i];\n            int gi = (int)vec.size();\n            pairCount[i] = gi * (gi - 1) / 2;\n            int cnt = 0;\n            for (int a = 0; a < gi; ++a) {\n                for (int b = a + 1; b < gi; ++b) {\n                    if (adj[vec[a]][vec[b]]) cnt++;\n                }\n            }\n            x[i] = cnt;\n        }\n\n        // ML decode over s in [0..M-1]\n        int bestS = 0;\n        double bestLL = -1e300;\n        for (int s = 0; s < M; ++s) {\n            double ll = 0.0;\n            for (int i = 0; i < Lbits; ++i) {\n                int bit = (s >> i) & 1;\n                int xi = x[i];\n                int ni = pairCount[i];\n                if (bit) {\n                    ll += xi * log_p1 + (ni - xi) * log_q1;\n                } else {\n                    ll += xi * log_p0 + (ni - xi) * log_q0;\n                }\n            }\n            if (ll > bestLL) {\n                bestLL = ll;\n                bestS = s;\n            }\n        }\n\n        cout << bestS << \"\\n\";\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Edge {\n    int u, v;\n    ll w;\n};\nstruct AdjEdge {\n    int to;\n    int id;\n    ll w;\n};\n\nstatic inline uint64_t part1by1(uint32_t x) {\n    uint64_t v = x & 0x0000ffffu;\n    v = (v | (v << 8)) & 0x00FF00FFu;\n    v = (v | (v << 4)) & 0x0F0F0F0Fu;\n    v = (v | (v << 2)) & 0x33333333u;\n    v = (v | (v << 1)) & 0x55555555u;\n    return v;\n}\nstatic inline uint64_t morton2D_32(uint32_t x, uint32_t y) {\n    return (part1by1(y) << 1) | part1by1(x);\n}\n\nconst ll INFLL = (ll)4e18;\n\nint N, M, D, K;\nvector<Edge> edges;\nvector<vector<AdjEdge>> adj;\nvector<int> Xcoord, Ycoord;\n\n// Fast Dijkstra from s to t while ignoring one banned edge\nll dijkstra_exclude_target(int s, int t, int banned_edge_id) {\n    static vector<ll> dist;\n    static vector<char> vis;\n    dist.assign(N, INFLL);\n    vis.assign(N, 0);\n    struct Node { ll d; int v; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n    dist[s] = 0;\n    pq.push({0, s});\n    while (!pq.empty()) {\n        auto [dcur, u] = pq.top(); pq.pop();\n        if (vis[u]) continue;\n        vis[u] = 1;\n        if (u == t) return dcur;\n        for (const auto &ae : adj[u]) {\n            if (ae.id == banned_edge_id) continue;\n            int v = ae.to;\n            ll nd = dcur + ae.w;\n            if (dist[v] > nd) {\n                dist[v] = nd;\n                pq.push({nd, v});\n            }\n        }\n    }\n    return dist[t];\n}\n\nstruct DSU {\n    vector<int> p, r;\n    int comps;\n    DSU() {}\n    DSU(int n) { init(n); }\n    void init(int n) { p.resize(n); r.assign(n,0); iota(p.begin(), p.end(), 0); comps = n; }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n    bool unite(int a, int b){\n        a = find(a); b = find(b);\n        if (a == b) return false;\n        if (r[a] < r[b]) swap(a, b);\n        p[b] = a;\n        if (r[a] == r[b]) r[a]++;\n        comps--;\n        return true;\n    }\n};\n\nvoid compute_components_for_day(int day, const vector<int>& assign, vector<int>& compId, int& compCount) {\n    compId.assign(N, -1);\n    compCount = 0;\n    deque<int> dq;\n    for (int i = 0; i < N; i++) {\n        if (compId[i] != -1) continue;\n        compId[i] = compCount;\n        dq.push_back(i);\n        while (!dq.empty()) {\n            int u = dq.front(); dq.pop_front();\n            for (const auto& ae : adj[u]) {\n                if (assign[ae.id] == day) continue; // removed that day\n                int v = ae.to;\n                if (compId[v] == -1) {\n                    compId[v] = compCount;\n                    dq.push_back(v);\n                }\n            }\n        }\n        compCount++;\n    }\n}\n\n// Tarjan bridges for day 'day' on the complement graph (edges with assign != day).\n// Returns isBridge[edge_id] (true if edge is a bridge in the complement for this day)\nvoid compute_bridges_for_day(int day, const vector<int>& assign, vector<char>& isBridge) {\n    isBridge.assign(M, false);\n    vector<int> tin(N, -1), low(N, -1);\n    int timer = 0;\n    function<void(int,int)> dfs = [&](int u, int peid) {\n        tin[u] = low[u] = timer++;\n        for (const auto& ae : adj[u]) {\n            int id = ae.id;\n            if (assign[id] == day) continue; // absent that day\n            if (id == peid) continue;\n            int v = ae.to;\n            if (tin[v] == -1) {\n                dfs(v, id);\n                low[u] = min(low[u], low[v]);\n                if (low[v] > tin[u]) {\n                    isBridge[id] = true;\n                }\n            } else {\n                low[u] = min(low[u], tin[v]);\n            }\n        }\n    };\n    for (int i = 0; i < N; i++) {\n        if (tin[i] == -1) dfs(i, -1);\n    }\n}\n\n// Compute isBridge for all days\nvoid precompute_bridges_all_days(const vector<int>& assign, vector<vector<char>>& isBridgeDays) {\n    isBridgeDays.assign(D, vector<char>(M, false));\n    for (int d = 0; d < D; d++) {\n        compute_bridges_for_day(d, assign, isBridgeDays[d]);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> D >> K;\n    edges.resize(M);\n    for (int i = 0; i < M; i++) {\n        int u, v; ll w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[i] = {u, v, w};\n    }\n    Xcoord.resize(N);\n    Ycoord.resize(N);\n    for (int i = 0; i < N; i++) cin >> Xcoord[i] >> Ycoord[i];\n\n    adj.assign(N, {});\n    for (int i = 0; i < M; i++) {\n        auto &e = edges[i];\n        adj[e.u].push_back({e.v, i, e.w});\n        adj[e.v].push_back({e.u, i, e.w});\n    }\n\n    auto time_start = chrono::steady_clock::now();\n    const double T_budget = 5.75; // keep some margin\n\n    // Compute per-edge importance\n    vector<ll> importance(M, 0);\n    for (int i = 0; i < M; i++) {\n        const auto &e = edges[i];\n        ll alt = dijkstra_exclude_target(e.u, e.v, i);\n        if (alt >= INFLL/2) {\n            importance[i] = (ll)1e9; // extremely important if somehow disconnects graph (shouldn't happen)\n        } else {\n            ll imp = alt - e.w;\n            if (imp < 0) imp = 0;\n            importance[i] = imp;\n        }\n        if ((i & 63) == 0) {\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - time_start).count();\n            if (elapsed > T_budget) break; // safeguard\n        }\n    }\n\n    // Spatial key\n    vector<uint64_t> zkey(M);\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        int mx = (Xcoord[u] + Xcoord[v]) >> 1;\n        int my = (Ycoord[u] + Ycoord[v]) >> 1;\n        zkey[i] = morton2D_32((uint32_t)mx, (uint32_t)my);\n    }\n\n    // Order edges by importance desc, then spatial key asc\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    stable_sort(order.begin(), order.end(), [&](int a, int b){\n        if (importance[a] != importance[b]) return importance[a] > importance[b];\n        if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n        return a < b;\n    });\n\n    // Target per day (balanced, never exceeds K since K > ceil(M/D))\n    vector<int> target(D, M / D);\n    for (int i = 0; i < M % D; i++) target[i]++;\n\n    // State\n    vector<int> assign(M, -1);\n    vector<vector<int>> dayEdges(D);\n    for (int d = 0; d < D; d++) dayEdges[d].reserve(target[d]);\n    vector<vector<int>> cnt(N, vector<int>(D, 0));\n    vector<vector<double>> S(N, vector<double>(D, 0.0)); // sumImp per vertex/day\n    vector<double> daySumImp(D, 0.0);\n    vector<int> remaining = target;\n\n    // Initial greedy assignment\n    for (int idx = 0; idx < M; idx++) {\n        int e = order[idx];\n        int u = edges[e].u, v = edges[e].v;\n        ll imp = importance[e];\n        int prefer = (int)(zkey[e] % (uint64_t)D);\n\n        int best_d = -1;\n        int best_conf = INT_MAX;\n        double best_localSum = 1e300;\n        double best_daySum = 1e300;\n        int best_dist = INT_MAX;\n        int best_remaining = -1;\n\n        for (int d = 0; d < D; d++) {\n            if (remaining[d] <= 0) continue;\n            int conf = cnt[u][d] + cnt[v][d];\n            double localSum = S[u][d] + S[v][d];\n            double globSum = daySumImp[d];\n            int dist1 = (d >= prefer) ? (d - prefer) : (prefer - d);\n            int rem = remaining[d];\n\n            if (conf < best_conf ||\n                (conf == best_conf && (localSum < best_localSum - 1e-12 ||\n                                       (fabs(localSum - best_localSum) <= 1e-12 && (globSum < best_daySum - 1e-12 ||\n                                                                                   (fabs(globSum - best_daySum) <= 1e-12 && (dist1 < best_dist ||\n                                                                                                                             (dist1 == best_dist && rem > best_remaining)))))))) {\n                best_conf = conf;\n                best_localSum = localSum;\n                best_daySum = globSum;\n                best_dist = dist1;\n                best_remaining = rem;\n                best_d = d;\n            }\n        }\n\n        if (best_d == -1) {\n            // Fallback: place where size < K if possible\n            int fb = -1, best_c2 = INT_MAX;\n            for (int d = 0; d < D; d++) {\n                if ((int)dayEdges[d].size() >= K) continue;\n                int conf = cnt[u][d] + cnt[v][d];\n                if (conf < best_c2) { best_c2 = conf; fb = d; }\n            }\n            if (fb == -1) {\n                for (int d = 0; d < D; d++) {\n                    int conf = cnt[u][d] + cnt[v][d];\n                    if (conf < best_c2) { best_c2 = conf; fb = d; }\n                }\n            }\n            best_d = fb;\n        }\n\n        assign[e] = best_d;\n        remaining[best_d]--;\n        cnt[u][best_d]++; cnt[v][best_d]++;\n        S[u][best_d] += (double)imp;\n        S[v][best_d] += (double)imp;\n        daySumImp[best_d] += (double)imp;\n        dayEdges[best_d].push_back(e);\n    }\n\n    // For fast removal from dayEdges\n    vector<int> posInDay(M, -1);\n    for (int d = 0; d < D; d++) {\n        for (int i = 0; i < (int)dayEdges[d].size(); i++) posInDay[dayEdges[d][i]] = i;\n    }\n\n    auto moveEdge = [&](int e, int from, int to) {\n        if (from == to) return;\n        int u = edges[e].u, v = edges[e].v;\n        double imp = (double)importance[e];\n        // remove from day 'from'\n        {\n            int p = posInDay[e];\n            int last = dayEdges[from].back();\n            dayEdges[from][p] = last;\n            posInDay[last] = p;\n            dayEdges[from].pop_back();\n        }\n        // add to day 'to'\n        posInDay[e] = (int)dayEdges[to].size();\n        dayEdges[to].push_back(e);\n\n        // update counters\n        cnt[u][from]--; cnt[v][from]--;\n        cnt[u][to]++; cnt[v][to]++;\n        S[u][from] -= imp; S[v][from] -= imp;\n        S[u][to] += imp; S[v][to] += imp;\n        daySumImp[from] -= imp; daySumImp[to] += imp;\n        assign[e] = to;\n    };\n\n    auto now = chrono::steady_clock::now();\n    double elapsed = chrono::duration<double>(now - time_start).count();\n\n    // Connectivity enforcement\n    // Precompute bridges per day, used to avoid moving an edge into a day where it would be a bridge.\n    vector<vector<char>> isBridgeDays;\n    precompute_bridges_all_days(assign, isBridgeDays);\n\n    int maxPass = 4;\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool changedAny = false;\n        for (int d = 0; d < D; d++) {\n            // time check\n            if ((d & 3) == 0) {\n                now = chrono::steady_clock::now();\n                elapsed = chrono::duration<double>(now - time_start).count();\n                if (elapsed > T_budget) break;\n            }\n\n            // compute components for day d\n            vector<int> compId;\n            int compCount = 0;\n            compute_components_for_day(d, assign, compId, compCount);\n            if (compCount <= 1) continue;\n\n            // Edges in day d that connect different components\n            vector<int> crossEdges;\n            crossEdges.reserve(dayEdges[d].size());\n            for (int e : dayEdges[d]) {\n                int u = edges[e].u, v = edges[e].v;\n                if (compId[u] != compId[v]) crossEdges.push_back(e);\n            }\n            if (crossEdges.empty()) continue;\n\n            // Sort cross edges by increasing importance to move \"cheap\" ones first\n            sort(crossEdges.begin(), crossEdges.end(), [&](int a, int b){\n                if (importance[a] != importance[b]) return importance[a] < importance[b];\n                return a < b;\n            });\n\n            DSU dsu(compCount);\n            // union existing edges in complement implicitly; we'll only track unions by \"restored\" edges\n            // We'll greedily \"restore\" edges by moving them out of day d until connected\n            for (int e : crossEdges) {\n                int cu = dsu.find(compId[edges[e].u]);\n                int cv = dsu.find(compId[edges[e].v]);\n                if (cu == cv) continue;\n\n                // choose target day\n                int bestDaySafe = -1;\n                int bestDayAny = -1;\n                // tie-breaking by lexicographic cost\n                auto better = [&](int currBest, int cand) {\n                    if (currBest == -1) return true;\n                    int u = edges[e].u, v = edges[e].v;\n                    int cb_conf = cnt[u][currBest] + cnt[v][currBest];\n                    int cd_conf = cnt[u][cand] + cnt[v][cand];\n                    if (cd_conf != cb_conf) return cd_conf < cb_conf;\n                    double cb_local = S[u][currBest] + S[v][currBest];\n                    double cd_local = S[u][cand] + S[v][cand];\n                    if (fabs(cd_local - cb_local) > 1e-12) return cd_local < cb_local;\n                    double cb_day = daySumImp[currBest], cd_day = daySumImp[cand];\n                    if (fabs(cd_day - cb_day) > 1e-12) return cd_day < cb_day;\n                    // fallback: smaller size\n                    return dayEdges[cand].size() < dayEdges[currBest].size();\n                };\n\n                for (int tday = 0; tday < D; tday++) {\n                    if (tday == d) continue;\n                    if ((int)dayEdges[tday].size() >= K) continue;\n                    if (assign[e] == tday) continue;\n                    bool safe = !isBridgeDays[tday][e]; // removing e from tday won't disconnect\n                    if (safe) {\n                        if (better(bestDaySafe, tday)) bestDaySafe = tday;\n                    } else {\n                        if (better(bestDayAny, tday)) bestDayAny = tday;\n                    }\n                }\n                int tday = (bestDaySafe != -1 ? bestDaySafe : bestDayAny);\n                if (tday == -1) continue; // couldn't move due to K (rare)\n                moveEdge(e, d, tday);\n                dsu.unite(cu, cv);\n                changedAny = true;\n                if (dsu.comps == 1) break;\n            }\n        }\n        // time check\n        now = chrono::steady_clock::now();\n        elapsed = chrono::duration<double>(now - time_start).count();\n        if (elapsed > T_budget) break;\n\n        if (!changedAny) break; // stable\n\n        // Recompute bridges for all days after changes\n        precompute_bridges_all_days(assign, isBridgeDays);\n\n        // Optional: early exit if all connected\n        bool allConn = true;\n        for (int d = 0; d < D; d++) {\n            vector<int> compId;\n            int compCount = 0;\n            compute_components_for_day(d, assign, compId, compCount);\n            if (compCount > 1) { allConn = false; break; }\n        }\n        if (allConn) break;\n    }\n\n    // After enforcing connectivity, recompute bridges for safety before LS\n    precompute_bridges_all_days(assign, isBridgeDays);\n\n    // Objective for local search: sum of squares of per-vertex/day importance sums\n    auto computeObj = [&]() -> long double {\n        long double obj = 0;\n        for (int v = 0; v < N; v++) {\n            for (int d = 0; d < D; d++) {\n                long double s = (long double)S[v][d];\n                obj += s * s;\n            }\n        }\n        return obj;\n    };\n    long double obj = computeObj();\n\n    // Local search with connectivity-safe swaps\n    auto trySwapDelta = [&](int e1, int d1, int e2, int d2) -> long double {\n        int u1 = edges[e1].u, v1 = edges[e1].v;\n        int u2 = edges[e2].u, v2 = edges[e2].v;\n        double imp1 = (double)importance[e1];\n        double imp2 = (double)importance[e2];\n\n        // Change on S for only the affected (vertex, day) cells\n        struct Key { int v, d; };\n        vector<Key> keys;\n        vector<double> deltaS;\n        auto add_delta = [&](int v, int d, double ds) {\n            for (size_t i = 0; i < keys.size(); i++) {\n                if (keys[i].v == v && keys[i].d == d) { deltaS[i] += ds; return; }\n            }\n            keys.push_back({v,d}); deltaS.push_back(ds);\n        };\n        // e1: d1 -> d2\n        add_delta(u1, d1, -imp1); add_delta(v1, d1, -imp1);\n        add_delta(u1, d2, +imp1); add_delta(v1, d2, +imp1);\n        // e2: d2 -> d1\n        add_delta(u2, d2, -imp2); add_delta(v2, d2, -imp2);\n        add_delta(u2, d1, +imp2); add_delta(v2, d1, +imp2);\n\n        long double delta = 0.0L;\n        for (size_t i = 0; i < keys.size(); i++) {\n            int vv = keys[i].v, dd = keys[i].d;\n            long double oldS = (long double)S[vv][dd];\n            long double newS = oldS + (long double)deltaS[i];\n            delta += newS*newS - oldS*oldS;\n        }\n        return delta;\n    };\n\n    auto applySwap = [&](int e1, int d1, int e2, int d2) {\n        // update S, cnt\n        int u1 = edges[e1].u, v1 = edges[e1].v;\n        int u2 = edges[e2].u, v2 = edges[e2].v;\n        double imp1 = (double)importance[e1];\n        double imp2 = (double)importance[e2];\n\n        S[u1][d1] -= imp1; S[v1][d1] -= imp1;\n        S[u1][d2] += imp1; S[v1][d2] += imp1;\n        S[u2][d2] -= imp2; S[v2][d2] -= imp2;\n        S[u2][d1] += imp2; S[v2][d1] += imp2;\n\n        cnt[u1][d1]--; cnt[v1][d1]--;\n        cnt[u1][d2]++; cnt[v1][d2]++;\n        cnt[u2][d2]--; cnt[v2][d2]--;\n        cnt[u2][d1]++; cnt[v2][d1]++;\n\n        daySumImp[d1] += imp2 - imp1;\n        daySumImp[d2] += imp1 - imp2;\n\n        // move in dayEdges\n        {\n            int p = posInDay[e1];\n            int last = dayEdges[d1].back();\n            dayEdges[d1][p] = last;\n            posInDay[last] = p;\n            dayEdges[d1].pop_back();\n        }\n        {\n            int p = posInDay[e2];\n            int last = dayEdges[d2].back();\n            dayEdges[d2][p] = last;\n            posInDay[last] = p;\n            dayEdges[d2].pop_back();\n        }\n        posInDay[e1] = (int)dayEdges[d2].size();\n        dayEdges[d2].push_back(e1);\n        posInDay[e2] = (int)dayEdges[d1].size();\n        dayEdges[d1].push_back(e2);\n\n        assign[e1] = d2;\n        assign[e2] = d1;\n    };\n\n    now = chrono::steady_clock::now();\n    elapsed = chrono::duration<double>(now - time_start).count();\n    double time_left = T_budget - elapsed;\n    if (time_left > 0.15) {\n        mt19937 rng(1234567);\n        uniform_int_distribution<int> dayDist(0, D-1);\n\n        int attempts = 200000; // cap\n        int accepted = 0;\n        for (int it = 0; it < attempts; it++) {\n            if ((it & 1023) == 0) {\n                now = chrono::steady_clock::now();\n                elapsed = chrono::duration<double>(now - time_start).count();\n                if (elapsed > T_budget) break;\n            }\n\n            int d1 = dayDist(rng), d2 = dayDist(rng);\n            if (d1 == d2) continue;\n            if (dayEdges[d1].empty() || dayEdges[d2].empty()) continue;\n\n            int e1 = dayEdges[d1][ (int)(rng() % dayEdges[d1].size()) ];\n            int e2 = dayEdges[d2][ (int)(rng() % dayEdges[d2].size()) ];\n            if (e1 == e2) continue;\n\n            // Connectivity-safe check via current bridges\n            if (isBridgeDays[d2][e1]) continue; // removing e1 from d2 would disconnect\n            if (isBridgeDays[d1][e2]) continue; // removing e2 from d1 would disconnect\n\n            long double delta = trySwapDelta(e1, d1, e2, d2);\n            if (delta < -1e-9L) {\n                applySwap(e1, d1, e2, d2);\n                obj += delta;\n                accepted++;\n                // recompute bridges for affected days to keep safety guarantees\n                compute_bridges_for_day(d1, assign, isBridgeDays[d1]);\n                compute_bridges_for_day(d2, assign, isBridgeDays[d2]);\n            }\n        }\n    }\n\n    // Final output (1-indexed days)\n    for (int i = 0; i < M; i++) {\n        if (i) cout << ' ';\n        cout << (assign[i] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Hopcroft-Karp for bipartite matching (left: 0..nL-1, right: 0..nR-1)\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> adj; // adj[u] -> list of right vertices\n    vector<int> dist, matchL, matchR;\n\n    HopcroftKarp(int nL=0, int nR=0): nL(nL), nR(nR), adj(nL) {}\n\n    void init(int _nL, int _nR) {\n        nL = _nL; nR = _nR;\n        adj.assign(nL, {});\n    }\n\n    void addEdge(int u, int v) {\n        // u in [0, nL), v in [0, nR)\n        adj[u].push_back(v);\n    }\n\n    bool bfs() {\n        dist.assign(nL, -1);\n        queue<int> q;\n        for (int u = 0; u < nL; ++u) {\n            if (matchL[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        bool found = false;\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : adj[u]) {\n                int w = matchR[v];\n                if (w >= 0) {\n                    if (dist[w] < 0) {\n                        dist[w] = dist[u] + 1;\n                        q.push(w);\n                    }\n                } else {\n                    found = true;\n                }\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for (int v : adj[u]) {\n            int w = matchR[v];\n            if (w < 0 || (dist[w] == dist[u] + 1 && dfs(w))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int maxMatching(vector<int>* outMatchL = nullptr, vector<int>* outMatchR = nullptr) {\n        matchL.assign(nL, -1);\n        matchR.assign(nR, -1);\n        int matching = 0;\n        while (bfs()) {\n            for (int u = 0; u < nL; ++u) {\n                if (matchL[u] == -1) {\n                    if (dfs(u)) matching++;\n                }\n            }\n        }\n        if (outMatchL) *outMatchL = matchL;\n        if (outMatchR) *outMatchR = matchR;\n        return matching;\n    }\n};\n\nstatic inline int idx3(int D, int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\nstruct Arrangement {\n    int D;\n    vector<char> present;     // size D^3, 1 if occupied\n    vector<pair<int,int>> dominos; // pairs of linear indices\n};\n\nstruct LayerData {\n    vector<int> A; // xs with f[z][x] == '1'\n    vector<int> B; // ys with r[z][y] == '1'\n};\n\n// Build an arrangement prioritizing vertical alignment and then maximize dominos via 3D maximum matching.\nArrangement build_arrangement(const vector<string>& fz, const vector<string>& rz, int D) {\n    int N = D * D * D;\n    Arrangement arr;\n    arr.D = D;\n    arr.present.assign(N, 0);\n\n    // Precompute layer data\n    vector<LayerData> layers(D);\n    for (int z = 0; z < D; ++z) {\n        for (int x = 0; x < D; ++x) if (fz[z][x] == '1') layers[z].A.push_back(x);\n        for (int y = 0; y < D; ++y) if (rz[z][y] == '1') layers[z].B.push_back(y);\n    }\n\n    // prevOcc[x][y] indicates whether (x,y,z-1) was occupied\n    vector<vector<char>> prevOcc(D, vector<char>(D, 0));\n\n    // Random engine (fixed seed for determinism)\n    uint32_t rng_state = 123456789u;\n    auto rng = [&]() -> uint32_t {\n        rng_state ^= rng_state << 13;\n        rng_state ^= rng_state >> 17;\n        rng_state ^= rng_state << 5;\n        return rng_state;\n    };\n\n    for (int z = 0; z < D; ++z) {\n        auto& A = layers[z].A;\n        auto& B = layers[z].B;\n        int Nx = (int)A.size();\n        int Ny = (int)B.size();\n\n        // Maps from coordinate to local index\n        array<int, 32> xId{}; array<int, 32> yId{};\n        xId.fill(-1); yId.fill(-1);\n        for (int i = 0; i < Nx; ++i) xId[A[i]] = i;\n        for (int j = 0; j < Ny; ++j) yId[B[j]] = j;\n\n        if (Nx >= Ny) {\n            // x-dominant: create mapping x -> y, surjective onto all y\n            // Stage 1: match y to x using prevOcc to preserve vertical matches\n            HopcroftKarp hk(Ny, Nx);\n            for (int j = 0; j < Ny; ++j) {\n                int y = B[j];\n                for (int i = 0; i < Nx; ++i) {\n                    int x = A[i];\n                    if (prevOcc[x][y]) hk.addEdge(j, i);\n                }\n            }\n            vector<int> matchY, matchX;\n            hk.maxMatching(&matchY, &matchX); // matchY[j] = i or -1\n\n            vector<int> xToY(Nx, -1);\n            vector<int> yCovered(Ny, 0);\n            vector<int> loadY(Ny, 0);\n            vector<char> usedX(Nx, 0);\n\n            // Assign matched y->x\n            for (int j = 0; j < Ny; ++j) {\n                int i = matchY[j];\n                if (i != -1) {\n                    xToY[i] = j;\n                    usedX[i] = 1;\n                    yCovered[j] = 1;\n                    loadY[j]++;\n                }\n            }\n\n            // Precompute pref count for x (how many y had prevOcc)\n            vector<int> prefCountX(Nx, 0);\n            for (int i = 0; i < Nx; ++i) {\n                int x = A[i];\n                int cnt = 0;\n                for (int j = 0; j < Ny; ++j) if (prevOcc[x][B[j]]) cnt++;\n                prefCountX[i] = cnt;\n            }\n\n            // Assign uncovered y to some unused x (pick x with minimal prefCount to break least prefs)\n            for (int j = 0; j < Ny; ++j) if (!yCovered[j]) {\n                int pick_i = -1;\n                int bestScore = INT_MAX;\n                for (int i = 0; i < Nx; ++i) if (!usedX[i]) {\n                    int score = prefCountX[i] * 10 + (int)(rng() & 7u); // small randomness for tie\n                    if (score < bestScore) {\n                        bestScore = score;\n                        pick_i = i;\n                    }\n                }\n                if (pick_i == -1) {\n                    // Should not happen; fallback: move from some x\n                    for (int i = 0; i < Nx; ++i) {\n                        if (xToY[i] != -1) { pick_i = i; break; }\n                    }\n                }\n                if (pick_i == -1) pick_i = 0;\n                if (xToY[pick_i] != -1) {\n                    loadY[xToY[pick_i]]--;\n                }\n                xToY[pick_i] = j;\n                usedX[pick_i] = 1;\n                yCovered[j] = 1;\n                loadY[j]++;\n            }\n\n            // Stage 2: assign remaining x to a y to create potential in-layer adjacency and/or vertical preservation\n            // Keep track per y the list of xs assigned so far\n            vector<vector<int>> xsPerY(Ny);\n            for (int i = 0; i < Nx; ++i) if (xToY[i] != -1) {\n                xsPerY[xToY[i]].push_back(i);\n            }\n\n            for (int i = 0; i < Nx; ++i) if (!usedX[i]) {\n                int x = A[i];\n                int bestY = 0;\n                int bestScore = -1e9;\n                for (int j = 0; j < Ny; ++j) {\n                    int y = B[j];\n                    int sc = 0;\n                    if (prevOcc[x][y]) sc += 100;\n                    // in-layer adjacency: neighbor x' assigned to same y\n                    for (int xi : xsPerY[j]) {\n                        if (abs(A[xi] - x) == 1) { sc += 10; break; }\n                    }\n                    // favor less loaded y\n                    sc -= loadY[j];\n                    // slight randomness\n                    sc += (int)(rng() & 3u);\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestY = j;\n                    }\n                }\n                xToY[i] = bestY;\n                loadY[bestY]++;\n                xsPerY[bestY].push_back(i);\n                usedX[i] = 1;\n            }\n\n            // Emit cells for this layer\n            for (int i = 0; i < Nx; ++i) {\n                int x = A[i];\n                int j = xToY[i];\n                int y = B[j];\n                int p = idx3(D, x, y, z);\n                arr.present[p] = 1;\n            }\n        } else {\n            // y-dominant: create mapping y -> x, surjective onto all x\n            // Stage 1: match x to y using prevOcc\n            HopcroftKarp hk(Nx, Ny); // left: X, right: Y\n            for (int i = 0; i < Nx; ++i) {\n                int x = A[i];\n                for (int j = 0; j < Ny; ++j) {\n                    int y = B[j];\n                    if (prevOcc[x][y]) hk.addEdge(i, j);\n                }\n            }\n            vector<int> matchX, matchY;\n            hk.maxMatching(&matchX, &matchY); // matchX[i] = j or -1\n\n            vector<int> yToX(Ny, -1);\n            vector<char> usedY(Ny, 0);\n            vector<int> loadX(Nx, 0);\n            vector<vector<int>> ysPerX(Nx);\n\n            // Assign matched x->y\n            for (int i = 0; i < Nx; ++i) {\n                int j = matchX[i];\n                if (j != -1) {\n                    yToX[j] = i;\n                    usedY[j] = 1;\n                    loadX[i]++;\n                    ysPerX[i].push_back(j);\n                }\n            }\n\n            // Assign unmatched x to some unused y (prefer y with no prevOcc for any x to keep prefs for others)\n            // Precompute prefCountY[j] = number of x with prevOcc[x][y]\n            vector<int> prefCountY(Ny, 0);\n            for (int j = 0; j < Ny; ++j) {\n                int y = B[j];\n                int cnt = 0;\n                for (int i = 0; i < Nx; ++i) if (prevOcc[A[i]][y]) cnt++;\n                prefCountY[j] = cnt;\n            }\n            for (int i = 0; i < Nx; ++i) {\n                if (matchX[i] != -1) continue;\n                // pick unused y\n                int pick_j = -1;\n                int bestScore = INT_MAX;\n                for (int j = 0; j < Ny; ++j) if (!usedY[j]) {\n                    int score = prefCountY[j] * 10 + (int)(rng() & 7u);\n                    if (score < bestScore) {\n                        bestScore = score;\n                        pick_j = j;\n                    }\n                }\n                if (pick_j == -1) {\n                    // fallback: pick any y\n                    for (int j = 0; j < Ny; ++j) if (usedY[j] == 0) { pick_j = j; break; }\n                    if (pick_j == -1) pick_j = 0;\n                }\n                yToX[pick_j] = i;\n                usedY[pick_j] = 1;\n                loadX[i]++;\n                ysPerX[i].push_back(pick_j);\n            }\n\n            // Stage 2: assign remaining y (duplicates) to some x to help adjacency/vertical\n            for (int j = 0; j < Ny; ++j) if (!usedY[j]) {\n                int y = B[j];\n                int bestX = 0;\n                int bestScore = -1e9;\n                for (int i = 0; i < Nx; ++i) {\n                    int x = A[i];\n                    int sc = 0;\n                    if (prevOcc[x][y]) sc += 100;\n                    // in-layer adjacency along y: is there y' adjacent already assigned to this x?\n                    for (int yj : ysPerX[i]) {\n                        if (abs(B[yj] - y) == 1) { sc += 10; break; }\n                    }\n                    sc -= loadX[i];\n                    sc += (int)(rng() & 3u);\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestX = i;\n                    }\n                }\n                yToX[j] = bestX;\n                usedY[j] = 1;\n                loadX[bestX]++;\n                ysPerX[bestX].push_back(j);\n            }\n\n            // Emit cells for this layer\n            for (int j = 0; j < Ny; ++j) {\n                int i = yToX[j];\n                int x = A[i];\n                int y = B[j];\n                int p = idx3(D, x, y, z);\n                arr.present[p] = 1;\n            }\n        }\n\n        // Update prevOcc for next layer\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) prevOcc[x][y] = 0;\n        for (int x = 0; x < D; ++x) {\n            for (int y = 0; y < D; ++y) {\n                int p = idx3(D, x, y, z);\n                if (arr.present[p]) prevOcc[x][y] = 1;\n            }\n        }\n    }\n\n    // Now compute maximum matching on 3D adjacency graph to extract dominos\n    // Partition by parity of x+y+z (even -> left)\n    vector<int> leftId(N, -1), rightId(N, -1);\n    vector<int> leftPos, rightPos;\n    leftPos.reserve(N); rightPos.reserve(N);\n    int nL = 0, nR = 0;\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            for (int z = 0; z < D; ++z) {\n                int p = idx3(D, x, y, z);\n                if (!arr.present[p]) continue;\n                if (((x + y + z) & 1) == 0) {\n                    leftId[p] = nL++;\n                    leftPos.push_back(p);\n                } else {\n                    rightId[p] = nR++;\n                    rightPos.push_back(p);\n                }\n            }\n        }\n    }\n\n    HopcroftKarp hk3(nL, nR);\n    hk3.adj.assign(nL, {});\n    // Build adjacency edges\n    const int dx[6] = {1,-1,0,0,0,0};\n    const int dy[6] = {0,0,1,-1,0,0};\n    const int dz[6] = {0,0,0,0,1,-1};\n    for (int idx = 0; idx < nL; ++idx) {\n        int p = leftPos[idx];\n        int x = p / (D*D);\n        int y = (p / D) % D;\n        int z = p % D;\n        for (int dir = 0; dir < 6; ++dir) {\n            int nx = x + dx[dir];\n            int ny = y + dy[dir];\n            int nz = z + dz[dir];\n            if (0 <= nx && nx < D && 0 <= ny && ny < D && 0 <= nz && nz < D) {\n                int q = idx3(D, nx, ny, nz);\n                if (!arr.present[q]) continue;\n                int rid = rightId[q];\n                if (rid != -1) hk3.addEdge(idx, rid);\n            }\n        }\n    }\n\n    vector<int> mL, mR;\n    hk3.maxMatching(&mL, &mR);\n    vector<char> matched(N, 0);\n    arr.dominos.clear();\n    for (int u = 0; u < nL; ++u) {\n        int v = mL[u];\n        if (v != -1) {\n            int p = leftPos[u];\n            int q = rightPos[v];\n            arr.dominos.emplace_back(p, q);\n            matched[p] = matched[q] = 1;\n        }\n    }\n    // Note: unmatched cells remain for unit blocks assignment later\n\n    return arr;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    if (!(cin >> D)) return 0;\n    vector<string> f[2], r[2];\n    for (int t = 0; t < 2; ++t) {\n        f[t].resize(D);\n        for (int i = 0; i < D; ++i) cin >> f[t][i];\n        r[t].resize(D);\n        for (int i = 0; i < D; ++i) cin >> r[t][i];\n    }\n\n    Arrangement A1 = build_arrangement(f[0], r[0], D);\n    Arrangement A2 = build_arrangement(f[1], r[1], D);\n\n    int N = D * D * D;\n    vector<int> b1(N, 0), b2(N, 0);\n\n    int M1 = (int)A1.dominos.size();\n    int M2 = (int)A2.dominos.size();\n    int K = min(M1, M2);\n\n    int nblocks = 0;\n\n    // Assign shared dominos with IDs 1..K\n    for (int i = 0; i < K; ++i) {\n        int id = ++nblocks;\n        auto p1 = A1.dominos[i];\n        auto p2 = A2.dominos[i];\n        b1[p1.first] = id; b1[p1.second] = id;\n        b2[p2.first] = id; b2[p2.second] = id;\n    }\n\n    // Mark matched cells to avoid double-assigning\n    vector<char> used1(N, 0), used2(N, 0);\n    for (int i = 0; i < K; ++i) {\n        used1[A1.dominos[i].first] = used1[A1.dominos[i].second] = 1;\n        used2[A2.dominos[i].first] = used2[A2.dominos[i].second] = 1;\n    }\n\n    // Assign remaining dominos in A1\n    for (int i = K; i < M1; ++i) {\n        int id = ++nblocks;\n        auto pr = A1.dominos[i];\n        b1[pr.first] = id; b1[pr.second] = id;\n        used1[pr.first] = used1[pr.second] = 1;\n    }\n    // Assign remaining dominos in A2\n    for (int i = K; i < M2; ++i) {\n        int id = ++nblocks;\n        auto pr = A2.dominos[i];\n        b2[pr.first] = id; b2[pr.second] = id;\n        used2[pr.first] = used2[pr.second] = 1;\n    }\n\n    // Assign remaining single cells in A1\n    for (int p = 0; p < N; ++p) {\n        if (A1.present[p] && !used1[p]) {\n            int id = ++nblocks;\n            b1[p] = id;\n            used1[p] = 1;\n        }\n    }\n    // Assign remaining single cells in A2\n    for (int p = 0; p < N; ++p) {\n        if (A2.present[p] && !used2[p]) {\n            int id = ++nblocks;\n            b2[p] = id;\n            used2[p] = 1;\n        }\n    }\n\n    // Output\n    cout << nblocks << \"\\n\";\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            for (int z = 0; z < D; ++z) {\n                int p = idx3(D, x, y, z);\n                cout << b1[p] << ( (x==D-1 && y==D-1 && z==D-1) ? '\\n' : ' ' );\n            }\n        }\n    }\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            for (int z = 0; z < D; ++z) {\n                int p = idx3(D, x, y, z);\n                cout << b2[p] << ( (x==D-1 && y==D-1 && z==D-1) ? '\\n' : ' ' );\n            }\n        }\n    }\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge {\n    int u, v;\n    long long w;\n};\n\nstruct Solution {\n    vector<int> P;       // size N\n    vector<char> edgeOn; // size M\n    long long edgeSum = 0;\n    long long pSum = 0;\n    long long S = (1LL<<62);\n};\n\nstatic inline long long isq(long long x){ return x*x; }\n\nstatic inline int sqrt_ceil_ll(long long x) {\n    if (x <= 0) return 0;\n    long double dx = (long double)x;\n    long long r = (long long)floor(sqrt(dx) + 1e-12L);\n    while ((r+1) * (r+1) <= x) ++r;\n    while (r * r > x) --r;\n    if (r * r == x) return (int)r;\n    return (int)(r + 1);\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, M, K;\n    if(!(cin>>N>>M>>K)) return 0;\n    vector<long long> xs(N), ys(N);\n    for(int i=0;i<N;i++){ cin>>xs[i]>>ys[i]; }\n    vector<Edge> edges(M);\n    for(int j=0;j<M;j++){\n        int u,v; long long w;\n        cin>>u>>v>>w;\n        --u; --v;\n        edges[j] = {u,v,w};\n    }\n    vector<long long> ax(K), ay(K);\n    for(int k=0;k<K;k++){ cin>>ax[k]>>ay[k]; }\n\n    // adjacency\n    vector<vector<pair<int,int>>> adj(N);\n    for(int e=0;e<M;e++){\n        int u=edges[e].u, v=edges[e].v;\n        adj[u].push_back({v,e});\n        adj[v].push_back({u,e});\n    }\n\n    // Precompute squared distances station-resident and coverage lists/bitsets\n    const long long R2 = 5000LL*5000LL;\n    vector<vector<int>> covList(N);\n    vector<vector<uint64_t>> covBits(N);\n    int B = (K + 63) >> 6;\n    uint64_t lastMask = (K%64 == 0) ? ~0ULL : ((1ULL << (K%64)) - 1ULL);\n    vector<vector<int>> d2sr(N, vector<int>(K, 0));\n    for(int i=0;i<N;i++){\n        covBits[i].assign(B, 0ULL);\n        for(int k=0;k<K;k++){\n            long long dx = xs[i] - ax[k];\n            long long dy = ys[i] - ay[k];\n            long long d2 = dx*dx + dy*dy;\n            if (d2 > INT_MAX) d2 = INT_MAX; // safety\n            d2sr[i][k] = (int)d2;\n            if(d2 <= R2){\n                covList[i].push_back(k);\n                int blk = k >> 6;\n                int off = k & 63;\n                covBits[i][blk] |= (1ULL << off);\n            }\n        }\n    }\n\n    // All-pairs shortest paths (by weights) + parents to reconstruct paths\n    const long long INF = (1LL<<60);\n    vector<vector<long long>> distW(N, vector<long long>(N, INF));\n    vector<vector<int>> prevV(N, vector<int>(N, -1));\n    vector<vector<int>> prevE(N, vector<int>(N, -1));\n    auto dijkstra_from = [&](int s){\n        vector<long long>& d = distW[s];\n        vector<int>& pv = prevV[s];\n        vector<int>& pe = prevE[s];\n        fill(d.begin(), d.end(), INF);\n        fill(pv.begin(), pv.end(), -1);\n        fill(pe.begin(), pe.end(), -1);\n        d[s] = 0;\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        pq.push({0, s});\n        while(!pq.empty()){\n            auto [cd,u] = pq.top(); pq.pop();\n            if(cd != d[u]) continue;\n            for(auto [v,eid] : adj[u]){\n                long long nd = cd + edges[eid].w;\n                if(nd < d[v]){\n                    d[v] = nd;\n                    pv[v] = u;\n                    pe[v] = eid;\n                    pq.push({nd, v});\n                }\n            }\n        }\n    };\n    for(int i=0;i<N;i++) dijkstra_from(i);\n\n    // SPT from root 0\n    vector<int> parentSPT(N, -1);\n    vector<int> parentEdgeSPT(N, -1);\n    for(int v=0; v<N; v++){\n        parentSPT[v] = prevV[0][v];\n        parentEdgeSPT[v] = prevE[0][v];\n    }\n\n    auto build_Vset_from_edges = [&](const vector<char>& edgeOn)->vector<char>{\n        vector<char> inV(N, 0);\n        queue<int> q;\n        inV[0] = 1;\n        q.push(0);\n        while(!q.empty()){\n            int u = q.front(); q.pop();\n            for(auto [v,eid]: adj[u]){\n                if(edgeOn[eid] && !inV[v]){\n                    inV[v] = 1;\n                    q.push(v);\n                }\n            }\n        }\n        return inV;\n    };\n\n    auto assign_and_cost = [&](const vector<char>& edgeOn){\n        vector<char> inV = build_Vset_from_edges(edgeOn);\n        vector<int> assignTo(K, -1);\n        vector<int> bestD2(K, INT_MAX);\n        for(int k=0;k<K;k++){\n            int besti = -1;\n            int bestv = INT_MAX;\n            for(int i=0;i<N;i++){\n                if(!inV[i]) continue;\n                int d2 = d2sr[i][k];\n                if(d2 < bestv){\n                    bestv = d2; besti = i;\n                }\n            }\n            assignTo[k] = besti;\n            bestD2[k] = bestv;\n        }\n        vector<long long> maxD2(N, 0);\n        for(int k=0;k<K;k++){\n            int i = assignTo[k];\n            if(i<0) continue; // should not happen\n            if((long long)bestD2[k] > maxD2[i]) maxD2[i] = bestD2[k];\n        }\n        vector<int> P(N,0);\n        long long pSum = 0;\n        for(int i=0;i<N;i++){\n            if(!inV[i]) { P[i]=0; continue; }\n            int rad = sqrt_ceil_ll(maxD2[i]);\n            if (rad > 5000) rad = 5000; // safeguard, should not happen if covered\n            P[i] = rad;\n            pSum += 1LL*rad*rad;\n        }\n        long long edgeSum = 0;\n        for(int e=0;e<M;e++) if(edgeOn[e]) edgeSum += edges[e].w;\n        Solution sol;\n        sol.P = std::move(P);\n        sol.edgeOn = edgeOn;\n        sol.edgeSum = edgeSum;\n        sol.pSum = pSum;\n        sol.S = edgeSum + pSum;\n        return sol;\n    };\n\n    auto prune_unused_leaves = [&](vector<char>& edgeOn, const vector<int>& P){\n        vector<int> deg(N, 0);\n        vector<vector<int>> incEdges(N);\n        incEdges.assign(N, {});\n        for(int e=0;e<M;e++){\n            if(!edgeOn[e]) continue;\n            int u=edges[e].u, v=edges[e].v;\n            incEdges[u].push_back(e);\n            incEdges[v].push_back(e);\n        }\n        for(int i=0;i<N;i++){\n            int d=0;\n            for(int eid: incEdges[i]) if(edgeOn[eid]) d++;\n            deg[i]=d;\n        }\n        deque<int> dq;\n        for(int i=0;i<N;i++){\n            if(i==0) continue;\n            if(deg[i]==1 && P[i]==0) dq.push_back(i);\n        }\n        vector<char> removed(N,0);\n        while(!dq.empty()){\n            int v = dq.front(); dq.pop_front();\n            if(removed[v]) continue;\n            if(deg[v]!=1 || P[v]!=0) continue;\n            // find its unique edge\n            int euniq = -1, u = -1;\n            for(int eid : incEdges[v]){\n                if(edgeOn[eid]){\n                    euniq = eid;\n                    int a=edges[eid].u, b=edges[eid].v;\n                    u = (a==v? b : a);\n                    break;\n                }\n            }\n            if(euniq==-1) continue;\n            // remove edge\n            edgeOn[euniq] = 0;\n            deg[v]--; deg[u]--;\n            removed[v]=1;\n            if(u!=0 && deg[u]==1 && P[u]==0) dq.push_back(u);\n        }\n    };\n\n    // Build solution 1: Set cover + Metric MST\n    auto build_solution_setcover = [&](){\n        vector<char> selected(N, 0);\n        vector<char> uncovered(K, 1);\n        int remaining = K;\n        vector<long long> distRoot(N);\n        for(int i=0;i<N;i++) distRoot[i] = distW[0][i];\n\n        while(remaining > 0){\n            int besti = -1;\n            int bestc = -1;\n            long long tieRoot = (1LL<<60);\n            for(int i=0;i<N;i++){\n                if(selected[i]) continue;\n                int cnt = 0;\n                for(int k : covList[i]) if(uncovered[k]) cnt++;\n                if(cnt > bestc || (cnt==bestc && distRoot[i] < tieRoot)){\n                    bestc = cnt; tieRoot = distRoot[i]; besti = i;\n                }\n            }\n            if(besti==-1 || bestc<=0){\n                // Fallback: add any station that can cover someone not yet covered\n                for(int i=0;i<N && besti==-1;i++){\n                    if(selected[i]) continue;\n                    int cnt = 0;\n                    for(int k : covList[i]) if(uncovered[k]) { cnt=1; break; }\n                    if(cnt) besti = i;\n                }\n                if(besti==-1){\n                    // Should not happen; break\n                    break;\n                }\n            }\n            selected[besti] = 1;\n            for(int k : covList[besti]){\n                if(uncovered[k]){\n                    uncovered[k] = 0;\n                    remaining--;\n                }\n            }\n        }\n        // Remove redundant\n        vector<int> coverCnt(K, 0);\n        for(int i=0;i<N;i++){\n            if(!selected[i]) continue;\n            for(int k : covList[i]) coverCnt[k]++;\n        }\n        bool changed = true;\n        while(changed){\n            changed = false;\n            for(int i=0;i<N;i++){\n                if(!selected[i]) continue;\n                bool canRemove = true;\n                for(int k : covList[i]){\n                    if(coverCnt[k] <= 1){ canRemove=false; break; }\n                }\n                if(canRemove){\n                    selected[i] = 0;\n                    for(int k : covList[i]) coverCnt[k]--;\n                    changed = true;\n                }\n            }\n        }\n\n        // Terminals T = selected + root 0\n        vector<int> T;\n        T.push_back(0);\n        for(int i=0;i<N;i++) if(selected[i] && i!=0) T.push_back(i);\n        int TS = (int)T.size();\n\n        // Prim's MST on metric distW[T][T]\n        vector<char> used(TS, 0);\n        vector<long long> low(TS, INF);\n        vector<int> par(TS, -1);\n        used[0] = 1;\n        for(int i=1;i<TS;i++){\n            low[i] = distW[T[0]][T[i]];\n            par[i] = 0;\n        }\n        vector<pair<int,int>> mstPairs; mstPairs.reserve(TS-1);\n        for(int it=0; it<TS-1; it++){\n            int v=-1; long long best=INF;\n            for(int j=0;j<TS;j++){\n                if(!used[j] && low[j] < best){\n                    best = low[j]; v=j;\n                }\n            }\n            if(v==-1) break;\n            used[v] = 1;\n            mstPairs.emplace_back(T[par[v]], T[v]);\n            for(int j=0;j<TS;j++){\n                if(!used[j]){\n                    long long nd = distW[T[v]][T[j]];\n                    if(nd < low[j]){\n                        low[j] = nd; par[j] = v;\n                    }\n                }\n            }\n        }\n\n        // Build union of shortest paths for MST edges\n        vector<char> edgeOn(M, 0);\n        for(auto [u,v] : mstPairs){\n            int cur = v;\n            while(cur != u){\n                int eid = prevE[u][cur];\n                if(eid<0) break; // safety\n                edgeOn[eid] = 1;\n                int pu = prevV[u][cur];\n                if(pu<0) break;\n                cur = pu;\n            }\n        }\n\n        // Reduce cycles: MST inside union edges\n        // Collect union edges list\n        vector<int> unionEdges;\n        unionEdges.reserve(M);\n        for(int e=0;e<M;e++) if(edgeOn[e]) unionEdges.push_back(e);\n        // Kruskal on union edges\n        struct DSU {\n            int n;\n            vector<int> p, r;\n            DSU(int n):n(n),p(n),r(n,0){ iota(p.begin(), p.end(), 0); }\n            int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n            bool unite(int a,int b){\n                a=find(a); b=find(b);\n                if(a==b) return false;\n                if(r[a]<r[b]) swap(a,b);\n                p[b]=a;\n                if(r[a]==r[b]) r[a]++;\n                return true;\n            }\n        };\n        vector<int> ord = unionEdges;\n        sort(ord.begin(), ord.end(), [&](int e1, int e2){\n            return edges[e1].w < edges[e2].w;\n        });\n        DSU dsu(N);\n        vector<char> edgeOn2(M, 0);\n        for(int e: ord){\n            int u = edges[e].u, v = edges[e].v;\n            if(dsu.unite(u,v)){\n                edgeOn2[e] = 1;\n            }\n        }\n        // Prune leaves not in terminals T\n        vector<char> isTerm(N, 0);\n        for(int v: T) isTerm[v] = 1;\n        // prune non-terminal leaves\n        {\n            vector<int> deg(N,0);\n            vector<vector<int>> incEdges(N);\n            incEdges.assign(N, {});\n            for(int e=0;e<M;e++){\n                if(!edgeOn2[e]) continue;\n                int u=edges[e].u, v=edges[e].v;\n                incEdges[u].push_back(e);\n                incEdges[v].push_back(e);\n            }\n            for(int i=0;i<N;i++){\n                int d=0; for(int eid: incEdges[i]) if(edgeOn2[eid]) d++;\n                deg[i]=d;\n            }\n            deque<int> dq;\n            for(int i=0;i<N;i++){\n                if(deg[i]==1 && !isTerm[i]) dq.push_back(i);\n            }\n            vector<char> removed(N,0);\n            while(!dq.empty()){\n                int v = dq.front(); dq.pop_front();\n                if(removed[v]) continue;\n                if(deg[v]!=1 || isTerm[v]) continue;\n                int euniq=-1, u=-1;\n                for(int eid: incEdges[v]){\n                    if(edgeOn2[eid]){\n                        euniq = eid;\n                        int a=edges[eid].u, b=edges[eid].v;\n                        u = (a==v? b : a);\n                        break;\n                    }\n                }\n                if(euniq==-1) continue;\n                edgeOn2[euniq]=0;\n                deg[v]--; deg[u]--;\n                removed[v] = 1;\n                if(deg[u]==1 && !isTerm[u]) dq.push_back(u);\n            }\n        }\n\n        // Assign and compute cost\n        Solution sol = assign_and_cost(edgeOn2);\n\n        // prune unused leaves (Pi==0) to reduce edges further\n        vector<char> edgeOn3 = sol.edgeOn;\n        prune_unused_leaves(edgeOn3, sol.P);\n        Solution sol2 = assign_and_cost(edgeOn3);\n        return sol2;\n    };\n\n    // Build solution 2: SPT greedy coverage\n    auto build_solution_spt = [&](){\n        vector<char> inV(N, 0);\n        vector<char> edgeOn(M, 0);\n        inV[0] = 1;\n\n        vector<uint64_t> covered(B, 0ULL);\n        // cover root's coverage\n        for(int b=0;b<B;b++) covered[b] |= covBits[0][b];\n\n        auto allCovered = [&](){\n            for(int b=0;b<B;b++){\n                uint64_t mask = (b==B-1 ? lastMask : ~0ULL);\n                if( (covered[b] & mask) != mask ) return false;\n            }\n            return true;\n        };\n\n        vector<uint64_t> tmp(B);\n\n        while(!allCovered()){\n            int bestV = -1;\n            long long bestGain = -1;\n            long long bestIncW = (1LL<<60);\n\n            for(int v=0; v<N; v++){\n                if(inV[v]) continue;\n                // accumulate new nodes along SPT path\n                // clear tmp\n                for(int b=0;b<B;b++) tmp[b] = 0ULL;\n                long long incW = 0;\n                int cur = v;\n                bool anyNew = false;\n                while(cur != -1 && !inV[cur]){\n                    // OR coverage\n                    for(int b=0;b<B;b++) tmp[b] |= covBits[cur][b];\n                    // add edge weight to parent\n                    int pe = parentEdgeSPT[cur];\n                    if(pe >= 0) incW += edges[pe].w;\n                    cur = parentSPT[cur];\n                    anyNew = true;\n                }\n                if(!anyNew){\n                    continue;\n                }\n                // compute new gain: popcount((tmp) & ~covered)\n                long long gain = 0;\n                for(int b=0;b<B;b++){\n                    uint64_t mask = (b==B-1 ? lastMask : ~0ULL);\n                    uint64_t nc = (~covered[b]) & mask;\n                    uint64_t add = tmp[b] & nc;\n                    gain += __builtin_popcountll(add);\n                }\n                if(gain > bestGain || (gain==bestGain && incW < bestIncW)){\n                    bestGain = gain;\n                    bestIncW = incW;\n                    bestV = v;\n                }\n            }\n\n            if(bestV == -1){\n                // fallback: add any remaining node to progress\n                for(int v=0; v<N; v++){\n                    if(!inV[v]) { bestV=v; break; }\n                }\n                if(bestV==-1) break; // shouldn't happen\n            }\n\n            // add bestV path to inV/edgeOn, and update covered\n            // recompute tmp for bestV\n            for(int b=0;b<B;b++) tmp[b] = 0ULL;\n            int cur = bestV;\n            while(cur != -1 && !inV[cur]){\n                for(int b=0;b<B;b++) tmp[b] |= covBits[cur][b];\n                int pe = parentEdgeSPT[cur];\n                if(pe >= 0) edgeOn[pe] = 1;\n                inV[cur] = 1;\n                cur = parentSPT[cur];\n            }\n            // update covered\n            for(int b=0;b<B;b++) covered[b] |= tmp[b];\n        }\n\n        // Assign and compute cost\n        Solution sol = assign_and_cost(edgeOn);\n        // prune unused leaves\n        vector<char> edgeOn2 = sol.edgeOn;\n        prune_unused_leaves(edgeOn2, sol.P);\n        Solution sol2 = assign_and_cost(edgeOn2);\n        return sol2;\n    };\n\n    Solution sol1 = build_solution_setcover();\n    Solution sol2 = build_solution_spt();\n    Solution best = (sol1.S <= sol2.S ? sol1 : sol2);\n\n    // Output final solution: P and B\n    for(int i=0;i<N;i++){\n        if(i) cout << ' ';\n        cout << best.P[i];\n    }\n    cout << '\\n';\n    for(int j=0;j<M;j++){\n        if(j) cout << ' ';\n        cout << (best.edgeOn[j] ? 1 : 0);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Move {\n    int x1, y1, x2, y2;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 30;\n    vector<vector<int>> A(N);\n    for (int x = 0; x < N; ++x) {\n        A[x].resize(x + 1);\n        for (int y = 0; y <= x; ++y) cin >> A[x][y];\n    }\n\n    const int LIMIT = 10000;\n    vector<Move> ops;\n    ops.reserve(LIMIT);\n\n    // inQueue flags with triangular shape\n    vector<vector<char>> inQ(N);\n    for (int x = 0; x < N; ++x) inQ[x].assign(x + 1, 0);\n\n    auto isViolation = [&](int x, int y) -> bool {\n        if (x >= N - 1) return false;\n        int v = A[x][y];\n        int c1 = A[x + 1][y];\n        int c2 = A[x + 1][y + 1];\n        return v > min(c1, c2);\n    };\n\n    deque<pair<int,int>> q;\n\n    auto pushQ = [&](int x, int y) {\n        if (x < 0 || x >= N) return;\n        if (y < 0 || y > x) return;\n        if (inQ[x][y]) return;\n        inQ[x][y] = 1;\n        q.emplace_back(x, y);\n    };\n\n    // Initialize queue with current violations\n    for (int x = 0; x <= N - 2; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            if (isViolation(x, y)) pushQ(x, y);\n        }\n    }\n\n    auto recordSwap = [&](int x1, int y1, int x2, int y2) {\n        ops.push_back({x1, y1, x2, y2});\n    };\n\n    // Push parents of (x,y)\n    auto pushParents = [&](int x, int y) {\n        if (x <= 0) return;\n        // Parent (x-1, y-1) if y-1 >= 0\n        if (y - 1 >= 0) pushQ(x - 1, y - 1);\n        // Parent (x-1, y) if y <= x-1\n        if (y <= x - 1) pushQ(x - 1, y);\n    };\n\n    bool limit_hit = false;\n\n    // Main processing loop\n    while (!q.empty() && (int)ops.size() < LIMIT) {\n        auto [sx, sy] = q.front();\n        q.pop_front();\n        inQ[sx][sy] = 0;\n\n        // Sift down from (sx, sy)\n        int x = sx, y = sy;\n        while (x < N - 1) {\n            int cx1 = x + 1, cy1 = y;\n            int cx2 = x + 1, cy2 = y + 1;\n            int v = A[x][y];\n            int v1 = A[cx1][cy1];\n            int v2 = A[cx2][cy2];\n\n            int target_cx = -1, target_cy = -1;\n            int min_child = (v1 < v2) ? v1 : v2;\n            if (v <= min_child) break; // no violation at (x,y)\n\n            if (v1 < v2) {\n                target_cx = cx1; target_cy = cy1;\n            } else {\n                target_cx = cx2; target_cy = cy2;\n            }\n\n            if ((int)ops.size() >= LIMIT) { limit_hit = true; break; }\n\n            // Swap parent (x,y) with chosen child (target_cx, target_cy)\n            swap(A[x][y], A[target_cx][target_cy]);\n            recordSwap(x, y, target_cx, target_cy);\n\n            // (x,y) decreased; push its parents to propagate upwards if needed\n            pushParents(x, y);\n\n            // Continue sifting the larger value now at child\n            x = target_cx; y = target_cy;\n        }\n        if (limit_hit) break;\n\n        // Optionally, if (sx,sy) still violates (could after further changes), requeue\n        if (isViolation(sx, sy)) pushQ(sx, sy);\n    }\n\n    // Output\n    int K = min<int>(ops.size(), LIMIT);\n    cout << K << '\\n';\n    for (int i = 0; i < K; ++i) {\n        cout << ops[i].x1 << ' ' << ops[i].y1 << ' ' << ops[i].x2 << ' ' << ops[i].y2 << '\\n';\n    }\n\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int i, j; };\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    const int H = D, W = D;\n    const int ei = 0, ej = (D - 1) / 2; // entrance\n    const int INF = 1e9;\n\n    // Obstacles\n    vector<vector<char>> obs(H, vector<char>(W, 0));\n    for (int k = 0; k < N; ++k) {\n        int r, c;\n        cin >> r >> c;\n        obs[r][c] = 1;\n    }\n\n    auto inside = [&](int i, int j){ return 0 <= i && i < H && 0 <= j && j < W; };\n    int di[4] = {-1, 0, 1, 0};\n    int dj[4] = {0, 1, 0, -1};\n\n    // Precompute BFS distance from entrance (ignoring containers)\n    vector<vector<int>> dist(H, vector<int>(W, INF));\n    deque<Pos> dq;\n    dist[ei][ej] = 0;\n    dq.push_back({ei, ej});\n    while (!dq.empty()) {\n        auto p = dq.front(); dq.pop_front();\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = p.i + di[dir], nj = p.j + dj[dir];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (dist[ni][nj] > dist[p.i][p.j] + 1) {\n                dist[ni][nj] = dist[p.i][p.j] + 1;\n                dq.push_back({ni, nj});\n            }\n        }\n    }\n\n    // Build target order: increasing distance, tie by (i,j) to be deterministic\n    vector<Pos> order;\n    order.reserve(H*W);\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            if (obs[i][j]) continue;\n            if (i == ei && j == ej) continue;\n            order.push_back({i, j});\n        }\n    }\n    sort(order.begin(), order.end(), [&](const Pos &a, const Pos &b){\n        if (dist[a.i][a.j] != dist[b.i][b.j]) return dist[a.i][a.j] < dist[b.i][b.j];\n        if (a.i != b.i) return a.i < b.i;\n        return a.j < b.j;\n    });\n    int M = (int)order.size(); // number of containers\n\n    // rank index of each cell in the order\n    vector<vector<int>> rankIndex(H, vector<int>(W, -1));\n    for (int idx = 0; idx < (int)order.size(); ++idx) {\n        rankIndex[order[idx].i][order[idx].j] = idx;\n    }\n\n    // State during placement\n    vector<vector<char>> empty(H, vector<char>(W, 0)); // currently empty and not obstacle\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) empty[i][j] = !obs[i][j];\n    vector<vector<int>> labelAt(H, vector<int>(W, -1)); // label placed at cell (if any), -1 if none\n\n    auto compute_articulation = [&](const vector<vector<char>>& curEmpty)->vector<vector<char>> {\n        // Map empty cells to ids\n        vector<vector<int>> id(H, vector<int>(W, -1));\n        vector<Pos> nodes; nodes.reserve(H*W);\n        int vid = 0;\n        for (int i = 0; i < H; ++i)\n            for (int j = 0; j < W; ++j)\n                if (curEmpty[i][j]) { id[i][j] = vid++; nodes.push_back({i,j}); }\n\n        int n = vid;\n        vector<vector<int>> g(n);\n        g.assign(n, {});\n        for (auto &p : nodes) {\n            int u = id[p.i][p.j];\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = p.i + di[dir], nj = p.j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                if (!curEmpty[ni][nj]) continue;\n                int v = id[ni][nj];\n                g[u].push_back(v);\n            }\n        }\n        vector<int> tin(n, -1), low(n, -1), parent(n, -1);\n        vector<char> isArtV(n, 0);\n        int timer = 0;\n        function<void(int)> dfs = [&](int u){\n            tin[u] = low[u] = timer++;\n            int child = 0;\n            for (int v : g[u]) {\n                if (tin[v] == -1) {\n                    parent[v] = u;\n                    ++child;\n                    dfs(v);\n                    low[u] = min(low[u], low[v]);\n                    if (parent[u] != -1 && low[v] >= tin[u]) isArtV[u] = 1;\n                } else if (v != parent[u]) {\n                    low[u] = min(low[u], tin[v]);\n                }\n            }\n            if (parent[u] == -1 && child > 1) isArtV[u] = 1;\n        };\n        // Graph should be connected, but handle robustness\n        for (int u = 0; u < n; ++u) if (tin[u] == -1) dfs(u);\n\n        vector<vector<char>> isArt(H, vector<char>(W, 0));\n        for (auto &p : nodes) {\n            int u = id[p.i][p.j];\n            isArt[p.i][p.j] = isArtV[u];\n        }\n        return isArt;\n    };\n\n    auto count_safe_prefix = [&](const vector<vector<char>> &isArt, const vector<vector<char>> &curEmpty, int prefixLen, int excl_i = -1, int excl_j = -1)->int {\n        int cnt = 0;\n        int seen = 0;\n        // count among first `prefixLen` positions in the order (regardless of whether they are filled),\n        // only those that are currently empty and non-articulation.\n        for (int k = 0; k < (int)order.size(); ++k) {\n            int i = order[k].i, j = order[k].j;\n            if (k >= prefixLen) break;\n            if (!curEmpty[i][j]) continue;\n            if (i == excl_i && j == excl_j) continue;\n            if (!isArt[i][j]) cnt++;\n        }\n        return cnt;\n    };\n\n    // Choose placement for label with lookahead unlocking\n    int step = 0;\n    auto choose_position = [&](int label)->Pos {\n        // Current articulation on empties\n        vector<vector<char>> baseArt = compute_articulation(empty);\n\n        struct Cand { int i, j, idx, baseCost, deg; };\n        vector<Cand> cands;\n        cands.reserve(order.size());\n        for (int k = 0; k < (int)order.size(); ++k) {\n            int i = order[k].i, j = order[k].j;\n            if (!empty[i][j]) continue;\n            if (baseArt[i][j]) continue; // ensure connectivity preserved\n            int deg = 0;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + di[dir], nj = j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                if (empty[ni][nj]) deg++;\n            }\n            int cost = abs(k - label);\n            cands.push_back({i,j,k,cost,deg});\n        }\n\n        if (cands.empty()) {\n            // Fallback: choose any empty non-entrance cell\n            for (int k = 0; k < (int)order.size(); ++k) {\n                int i = order[k].i, j = order[k].j;\n                if (!empty[i][j]) continue;\n                return {i, j};\n            }\n        }\n\n        // Sort by closeness to target label, then by smaller deg (safe), then by distance\n        sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b){\n            if (a.baseCost != b.baseCost) return a.baseCost < b.baseCost;\n            if (a.deg != b.deg) return a.deg < b.deg;\n            if (dist[a.i][a.j] != dist[b.i][b.j]) return dist[a.i][a.j] < dist[b.i][b.j];\n            if (a.i != b.i) return a.i < b.i;\n            return a.j < b.j;\n        });\n\n        int K = min<int>(30, cands.size());       // evaluate top-K by base cost\n        int P = min<int>(24, (int)order.size());  // near-entrance prefix length\n        int baseSafePrefix = count_safe_prefix(baseArt, empty, P);\n\n        // Dynamic weight: emphasize unlocking early\n        int wUnlock = 3 + (int)(2LL * (M - step) / max(1, M)); // 5 early -> 3 late\n\n        long long bestScoreLL = LLONG_MIN;\n        Pos best{-1, -1};\n        int bestBaseCost = INT_MAX;\n        int bestDist = INT_MAX;\n\n        for (int z = 0; z < K; ++z) {\n            auto c = cands[z];\n            // Tentatively place here\n            empty[c.i][c.j] = 0;\n            // Recompute articulation after this tentative placement\n            vector<vector<char>> art2 = compute_articulation(empty);\n            // benefit: how many more safe cells appear in the early prefix\n            int afterSafe = count_safe_prefix(art2, empty, P);\n            int benefit = afterSafe - baseSafePrefix;\n\n            // Score: prefer small baseCost, but give bonus to unlocking early safe cells\n            // Also add a tiny bias for lower degree and closer to entrance\n            long long score = -(long long)c.baseCost + (long long)wUnlock * benefit;\n            // tie-breakers\n            // less degree tends to be safer structural choice\n            score -= (c.deg >= 3 ? 1 : 0);\n\n            // Restore\n            empty[c.i][c.j] = 1;\n\n            // Select best\n            if (score > bestScoreLL) {\n                bestScoreLL = score;\n                best = {c.i, c.j};\n                bestBaseCost = c.baseCost;\n                bestDist = dist[c.i][c.j];\n            } else if (score == bestScoreLL) {\n                if (c.baseCost < bestBaseCost) {\n                    best = {c.i, c.j};\n                    bestBaseCost = c.baseCost;\n                    bestDist = dist[c.i][c.j];\n                } else if (c.baseCost == bestBaseCost) {\n                    if (dist[c.i][c.j] < bestDist) {\n                        best = {c.i, c.j};\n                        bestDist = dist[c.i][c.j];\n                    }\n                }\n            }\n        }\n\n        // If lookahead somehow failed, fall back to cheapest candidate\n        if (best.i == -1) {\n            auto c = cands[0];\n            best = {c.i, c.j};\n        }\n        return best;\n    };\n\n    // Online placement\n    for (step = 0; step < M; ++step) {\n        int t;\n        cin >> t;\n        Pos p = choose_position(t);\n        // place container\n        empty[p.i][p.j] = 0;\n        labelAt[p.i][p.j] = t;\n        // Output and flush\n        cout << p.i << ' ' << p.j << '\\n' << flush;\n    }\n\n    // Retrieval: greedy smallest label from frontier\n    vector<vector<char>> occ(H, vector<char>(W, 0));\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        if (obs[i][j]) continue;\n        if (i == ei && j == ej) continue;\n        if (labelAt[i][j] >= 0) occ[i][j] = 1;\n    }\n\n    struct Node {\n        int label, i, j;\n        bool operator<(const Node& other) const {\n            return label > other.label; // min-heap behavior\n        }\n    };\n    priority_queue<Node> pq;\n    vector<vector<char>> inFrontier(H, vector<char>(W, 0));\n    auto try_push = [&](int i, int j){\n        if (!inside(i,j)) return;\n        if (obs[i][j]) return;\n        if (!occ[i][j]) return;\n        if (inFrontier[i][j]) return;\n        inFrontier[i][j] = 1;\n        pq.push(Node{labelAt[i][j], i, j});\n    };\n    // Init: neighbors of entrance\n    for (int dir = 0; dir < 4; ++dir) {\n        int ni = ei + di[dir], nj = ej + dj[dir];\n        if (!inside(ni, nj)) continue;\n        if (obs[ni][nj]) continue;\n        if (occ[ni][nj]) try_push(ni, nj);\n    }\n\n    vector<pair<int,int>> retrieval;\n    retrieval.reserve(M);\n\n    for (int step2 = 0; step2 < M; ++step2) {\n        while (!pq.empty() && !occ[pq.top().i][pq.top().j]) pq.pop();\n        if (pq.empty()) {\n            // Should never happen since the occupied region surrounds the empty component.\n            // As a robustness fallback, scan to find any frontier cell and push it.\n            bool pushed = false;\n            for (int i = 0; i < H && !pushed; ++i) for (int j = 0; j < W && !pushed; ++j) {\n                if (!occ[i][j]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + di[dir], nj = j + dj[dir];\n                    if (!inside(ni, nj)) continue;\n                    if (obs[ni][nj]) continue;\n                    if (!occ[ni][nj]) { try_push(i, j); pushed = true; break; }\n                }\n            }\n            // If still empty, break (shouldn't happen)\n            if (pq.empty()) break;\n        }\n        Node cur = pq.top(); pq.pop();\n        int ci = cur.i, cj = cur.j;\n        occ[ci][cj] = 0;\n        retrieval.emplace_back(ci, cj);\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = ci + di[dir], nj = cj + dj[dir];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (occ[ni][nj]) try_push(ni, nj);\n        }\n    }\n\n    for (auto &p : retrieval) {\n        cout << p.first << ' ' << p.second << '\\n';\n    }\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    if (!(cin >> n >> m)) return 0;\n    const int N = n * n;\n\n    vector<int> grid(N);\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            cin >> grid[i*n + j];\n        }\n    }\n\n    auto inb = [&](int r, int c)->bool { return (0 <= r && r < n && 0 <= c && c < n); };\n    const int dr[4] = {1, -1, 0, 0};\n    const int dc[4] = {0, 0, 1, -1};\n\n    // Color classification and counts\n    vector<int> sizeCount(m+1, 0);\n    vector<int> boundaryCount(m+1, 0);\n    vector<char> isBC(m+1, 0), isIC(m+1, 0);\n    vector<char> isBoundaryPos(N, 0);\n\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j;\n            int c = grid[id];\n            sizeCount[c]++;\n            if (i == 0 || j == 0 || i == n-1 || j == n-1) {\n                isBoundaryPos[id] = 1;\n                boundaryCount[c]++;\n            }\n        }\n    }\n    for (int c = 1; c <= m; ++c) isBC[c] = (boundaryCount[c] > 0);\n    for (int c = 1; c <= m; ++c) isIC[c] = !isBC[c]; // interior: originally not touching boundary\n\n    // Same-color degree per cell\n    vector<int> degSame(N, 0);\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j;\n            int c = grid[id];\n            int d = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                if (grid[ni*n + nj] == c) d++;\n            }\n            degSame[id] = d;\n        }\n    }\n\n    // Adjacency between non-zero colors: current pair edge counts and original adjacency record\n    vector<vector<int>> pairCount(m+1, vector<int>(m+1, 0));\n    auto add_pair = [&](int a, int b, int delta){\n        if (a == b) return;\n        if (a == 0 || b == 0) return;\n        if (a > b) swap(a, b);\n        pairCount[a][b] += delta;\n    };\n    // Initialize counts from grid edges\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j+1 < n; ++j) {\n            int a = grid[i*n + j], b = grid[i*n + j + 1];\n            if (a != b) add_pair(a, b, +1);\n        }\n    }\n    for (int i = 0; i+1 < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int a = grid[i*n + j], b = grid[(i+1)*n + j];\n            if (a != b) add_pair(a, b, +1);\n        }\n    }\n    vector<vector<char>> origAdj(m+1, vector<char>(m+1, 0));\n    for (int a = 1; a <= m; ++a) {\n        for (int b = a+1; b <= m; ++b) {\n            if (pairCount[a][b] > 0) origAdj[a][b] = 1;\n        }\n    }\n\n    // Current adjacency-to-0 edge counts per color (we maintain this dynamically)\n    vector<int> adj0Count(m+1, 0);\n    // Count border edges as c-0 edges\n    for (int j = 0; j < n; ++j) {\n        int c1 = grid[0*n + j];\n        if (c1 != 0) adj0Count[c1]++; // top\n        int c2 = grid[(n-1)*n + j];\n        if (c2 != 0) adj0Count[c2]++; // bottom\n    }\n    for (int i = 0; i < n; ++i) {\n        int c1 = grid[i*n + 0];\n        if (c1 != 0) adj0Count[c1]++; // left\n        int c2 = grid[i*n + (n-1)];\n        if (c2 != 0) adj0Count[c2]++; // right\n    }\n    // Internal 0 adjacencies (none initially, but keep generic)\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j+1 < n; ++j) {\n            int a = grid[i*n + j], b = grid[i*n + j + 1];\n            if (a == 0 && b != 0) adj0Count[b]++;\n            if (a != 0 && b == 0) adj0Count[a]++;\n        }\n    }\n    for (int i = 0; i+1 < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int a = grid[i*n + j], b = grid[(i+1)*n + j];\n            if (a == 0 && b != 0) adj0Count[b]++;\n            if (a != 0 && b == 0) adj0Count[a]++;\n        }\n    }\n\n    auto hasZeroNeighbor = [&](int id)->bool {\n        int i = id / n, j = id % n;\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            if (grid[ni*n + nj] == 0) return true;\n        }\n        return false;\n    };\n\n    auto borderSides = [&](int id)->int {\n        int i = id / n, j = id % n;\n        return (i == 0) + (i == n-1) + (j == 0) + (j == n-1);\n    };\n\n    // BFS helper for connectivity of neighbors (avoid deleting articulation points)\n    vector<int> seen(N, 0);\n    int stamp = 1;\n    auto neighbors_connected_after_remove = [&](int id, int color)->bool {\n        // Collect same-color neighbors\n        int i = id / n, j = id % n;\n        int sameNei[4], sn = 0;\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int nid = ni*n + nj;\n            if (grid[nid] == color) sameNei[sn++] = nid;\n        }\n        if (sn <= 1) return true;\n        // BFS from sameNei[0] avoiding 'id'\n        int targetsLeft = sn - 1;\n        stamp++;\n        deque<int> dq;\n        dq.push_back(sameNei[0]);\n        seen[sameNei[0]] = stamp;\n        while (!dq.empty()) {\n            int u = dq.front(); dq.pop_front();\n            int ui = u / n, uj = u % n;\n            for (int k = 0; k < 4; ++k) {\n                int vi = ui + dr[k], vj = uj + dc[k];\n                if (!inb(vi, vj)) continue;\n                int v = vi*n + vj;\n                if (v == id) continue;\n                if (grid[v] != color) continue;\n                if (seen[v] == stamp) continue;\n                seen[v] = stamp;\n                // Check if this v matches one of the target neighbors\n                for (int t = 1; t < sn; ++t) {\n                    if (v == sameNei[t]) {\n                        targetsLeft--;\n                        break;\n                    }\n                }\n                if (targetsLeft == 0) return true;\n                dq.push_back(v);\n            }\n        }\n        return false;\n    };\n\n    // Check if id is removable with all constraints\n    auto can_remove = [&](int id)->bool {\n        int c = grid[id];\n        if (c == 0) return false;\n        if (!isBC[c]) return false; // never remove interior color cells\n        // 0 must stay connected: only carve from boundary or existing 0\n        if (!(isBoundaryPos[id] || hasZeroNeighbor(id))) return false;\n        if (sizeCount[c] <= 1) return false;\n\n        // Do not create adjacency between 0 and interior colors\n        int i = id / n, j = id % n;\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int d = grid[ni*n + nj];\n            if (d != 0 && isIC[d]) return false;\n        }\n\n        // Preserve non-zero adjacencies: don't remove last c-d contact for any neighbor color d\n        // Count contacts with each neighbor color d\n        int cnt_col[128]; // m <= 100\n        int col_list[4]; int col_cnt = 0;\n        int cnt_map[4] = {0,0,0,0};\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int d = grid[ni*n + nj];\n            if (d == 0 || d == c) continue;\n            bool found = false;\n            for (int t = 0; t < col_cnt; ++t) {\n                if (col_list[t] == d) {\n                    cnt_map[t]++;\n                    found = true; break;\n                }\n            }\n            if (!found) {\n                col_list[col_cnt] = d;\n                cnt_map[col_cnt] = 1;\n                col_cnt++;\n            }\n        }\n        for (int t = 0; t < col_cnt; ++t) {\n            int d = col_list[t];\n            int cc = cnt_map[t];\n            int a = c, b = d;\n            if (a > b) swap(a, b);\n            // origAdj[a][b] must be true if they are neighbors at all\n            int pc = pairCount[a][b];\n            if (pc <= cc) return false;\n        }\n\n        // Preserve adjacency to 0 for boundary colors: adj0Count[c] must stay >= 1\n        int sameN = 0, zeroN = 0;\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int d = grid[ni*n + nj];\n            if (d == c) sameN++;\n            else if (d == 0) zeroN++;\n        }\n        int bSides = borderSides(id);\n        int delta0 = sameN - zeroN - bSides;\n        if (adj0Count[c] + delta0 <= 0) return false;\n\n        // Connectivity of color c: avoid articulation points\n        if (degSame[id] > 1) {\n            if (!neighbors_connected_after_remove(id, c)) return false;\n        }\n        return true;\n    };\n\n    auto remove_cell = [&](int id) {\n        int c = grid[id];\n        int i = id / n, j = id % n;\n\n        // For pair counts: decrement for every non-zero different-color neighbor\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int d = grid[ni*n + nj];\n            if (d != 0 && d != c) {\n                int a = c, b = d;\n                if (a > b) swap(a, b);\n                if (a >= 1 && b >= 1) {\n                    pairCount[a][b] = max(0, pairCount[a][b] - 1);\n                }\n            }\n        }\n\n        // Update degSame for same-color neighbors\n        int sameN = 0, zeroN = 0;\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int nid = ni*n + nj;\n            int d = grid[nid];\n            if (d == c) {\n                degSame[nid]--;\n                sameN++;\n            } else if (d == 0) {\n                zeroN++;\n            }\n        }\n\n        // Update adjacency to 0 counts\n        int bSides = borderSides(id);\n        // c loses zero edges that were to 0 neighbors and border sides, but gains edges to sameN neighbors\n        adj0Count[c] += (sameN - zeroN - bSides);\n        // Neighbors of other colors gain one 0 adjacency each\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int d = grid[ni*n + nj];\n            if (d != 0 && d != c) {\n                adj0Count[d]++; // new 0 edge along this side\n            }\n        }\n\n        if (isBoundaryPos[id]) boundaryCount[c]--;\n        sizeCount[c]--;\n        grid[id] = 0;\n        degSame[id] = 0;\n    };\n\n    auto is_accessible = [&](int id)->bool {\n        return isBoundaryPos[id] || hasZeroNeighbor(id);\n    };\n\n    Timer timer;\n    const double TIME_LIMIT = 1.95;\n\n    // Work queue: prioritize low-degree frontier cells\n    deque<int> Q;\n    vector<char> inQ(N, 0);\n\n    auto push_cand = [&](int id) {\n        if (inQ[id]) return;\n        if (grid[id] == 0) return;\n        int c = grid[id];\n        if (!isBC[c]) return;\n        if (!is_accessible(id)) return;\n        if (degSame[id] <= 2) Q.push_front(id);\n        else Q.push_back(id);\n        inQ[id] = 1;\n    };\n\n    // Seed with boundary cells of boundary colors\n    for (int id = 0; id < N; ++id) {\n        if (!isBoundaryPos[id]) continue;\n        if (grid[id] == 0) continue;\n        int c = grid[id];\n        if (!isBC[c]) continue;\n        push_cand(id);\n    }\n\n    while (!Q.empty() && timer.elapsed() < TIME_LIMIT * 0.985) {\n        int id = Q.front(); Q.pop_front();\n        inQ[id] = 0;\n        if (grid[id] == 0) continue;\n        if (!is_accessible(id)) continue;\n        if (can_remove(id)) {\n            int i = id / n, j = id % n;\n            remove_cell(id);\n            // Push neighbors as potential new candidates\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int nid = ni*n + nj;\n                if (grid[nid] != 0) push_cand(nid);\n            }\n        } else {\n            // still may become removable later; requeue with lower priority if time allows\n            if (timer.elapsed() < TIME_LIMIT * 0.98) {\n                if (degSame[id] <= 2) Q.push_back(id); // postpone\n                else Q.push_back(id);\n                inQ[id] = 1;\n            }\n        }\n    }\n\n    // Output the final grid\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            if (j) cout << ' ';\n            cout << grid[i*n + j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nstatic inline double sigmoid(double x) {\n    if (x >= 0) {\n        double e = exp(-x);\n        return 1.0 / (1.0 + e);\n    } else {\n        double e = exp(x);\n        return e / (1.0 + e);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, D, Q;\n    if (!(cin >> N >> D >> Q)) return 0;\n\n    // RNG\n    uint64_t seed = 1469598103934665603ull;\n    auto mix = [&](uint64_t x){ seed ^= x + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2); };\n    mix((uint64_t)N); mix((uint64_t)D); mix((uint64_t)Q);\n    mt19937_64 rng(seed);\n    uniform_real_distribution<double> ur01(0.0, 1.0);\n\n    // For adaptive query building\n    vector<double> w_est(N, 1.0); // current estimate for adaptive partition\n    vector<int> count_pm(N, 0);   // #plus - #minus per item to balance usage\n    vector<int> a(N, 0);          // current query vector in {+1,-1}\n    vector<int> score(N, 0);      // correlator accumulator\n\n    // Store informative rows for post-phase logistic regression\n    vector<int8_t> Aflat; Aflat.reserve((size_t)Q * N);\n    vector<int8_t> Y;     Y.reserve(Q);\n\n    string resp;\n\n    auto build_balanced_query = [&](vector<int>& a_out){\n        // Greedy partition by predicted weights to balance sums\n        vector<int> perm(N);\n        iota(perm.begin(), perm.end(), 0);\n        shuffle(perm.begin(), perm.end(), rng);\n\n        vector<int> L, R;\n        L.reserve(N); R.reserve(N);\n        double sumL = 0.0, sumR = 0.0;\n\n        for (int idx : perm) {\n            // Tie-breaking: try to balance counts to avoid bias\n            if (sumL < sumR) {\n                L.push_back(idx);\n                sumL += w_est[idx];\n            } else if (sumR < sumL) {\n                R.push_back(idx);\n                sumR += w_est[idx];\n            } else {\n                // sums equal; choose the side that reduces |count_pm[idx]|\n                if (count_pm[idx] > 0) {\n                    R.push_back(idx);\n                    sumR += w_est[idx];\n                } else if (count_pm[idx] < 0) {\n                    L.push_back(idx);\n                    sumL += w_est[idx];\n                } else {\n                    if (ur01(rng) < 0.5) { L.push_back(idx); sumL += w_est[idx]; }\n                    else { R.push_back(idx); sumR += w_est[idx]; }\n                }\n            }\n        }\n        // Both sides should be non-empty; if not, move one item\n        if (L.empty()) { L.push_back(R.back()); sumL += w_est[R.back()]; sumR -= w_est[R.back()]; R.pop_back(); }\n        if (R.empty()) { R.push_back(L.back()); sumR += w_est[L.back()]; sumL -= w_est[L.back()]; L.pop_back(); }\n\n        // Occasionally random perturbation to diversify queries\n        if (ur01(rng) < 0.10) {\n            if (!L.empty() && !R.empty()) {\n                // swap a random element across sides\n                int il = uniform_int_distribution<int>(0, (int)L.size()-1)(rng);\n                int ir = uniform_int_distribution<int>(0, (int)R.size()-1)(rng);\n                int u = L[il], v = R[ir];\n                swap(L[il], R[ir]); // just swap positions, arrays reflect sides\n            }\n        }\n\n        // Randomly flip sides to avoid systematic bias\n        bool flip = (ur01(rng) < 0.5);\n\n        a_out.assign(N, -1);\n        if (!flip) {\n            for (int idx : L) a_out[idx] = +1;\n        } else {\n            for (int idx : R) a_out[idx] = +1;\n            for (int &idx : L) {} // no-op\n        }\n\n        // Update counts for balance\n        for (int i = 0; i < N; i++) count_pm[i] += (a_out[i] > 0 ? +1 : -1);\n\n        // Output\n        int nL = 0, nR = 0;\n        for (int i = 0; i < N; i++) {\n            if (a_out[i] == +1) nL++;\n            else nR++;\n        }\n        cout << nL << ' ' << nR << ' ';\n        int printed = 0;\n        for (int i = 0; i < N; i++) if (a_out[i] == +1) {\n            cout << i;\n            printed++;\n            cout << ' ';\n        }\n        printed = 0;\n        int cntR = 0;\n        for (int i = 0; i < N; i++) if (a_out[i] == -1) {\n            cout << i;\n            cntR++;\n            if (cntR < nR) cout << ' ';\n        }\n        cout << \"\\n\" << flush;\n    };\n\n    // Query loop\n    for (int q = 0; q < Q; q++) {\n        build_balanced_query(a);\n\n        if (!(cin >> resp)) return 0;\n        int y = 0;\n        if (resp[0] == '>') y = +1;\n        else if (resp[0] == '<') y = -1;\n        else if (resp[0] == '=') y = 0;\n\n        if (y != 0) {\n            // Accumulate correlator and store row\n            for (int i = 0; i < N; i++) {\n                score[i] += y * a[i];\n            }\n            for (int i = 0; i < N; i++) {\n                int8_t v = (a[i] > 0 ? 1 : -1);\n                Aflat.push_back(v);\n            }\n            Y.push_back((int8_t)y);\n        }\n\n        // Update w_est for next query from current correlator (positive)\n        int mn = INT_MAX, mx = INT_MIN;\n        for (int i = 0; i < N; i++) { mn = min(mn, score[i]); mx = max(mx, score[i]); }\n        double shift = - (double)mn + 1.0;\n        for (int i = 0; i < N; i++) {\n            double val = score[i] + shift;\n            // Mild smoothing to avoid over-commit early\n            w_est[i] = max(1e-3, val);\n        }\n    }\n\n    // Build initial weights from correlator\n    vector<double> w(N, 1.0);\n    {\n        int mn = INT_MAX, mx = INT_MIN;\n        for (int i = 0; i < N; i++) { mn = min(mn, score[i]); mx = max(mx, score[i]); }\n        double shift = - (double)mn + 1.0;\n        for (int i = 0; i < N; i++) w[i] = max(1e-6, (double)score[i] + shift);\n    }\n\n    // Post-phase: 1-bit logistic regression to refine weights, if we have any informative rows\n    int M = (int)Y.size();\n    if (M > 0) {\n        vector<double> x = w; // init\n        // Normalize x to mean ~1 for stability\n        double meanx = 0.0;\n        for (double v : x) meanx += v;\n        meanx = (meanx > 0 ? meanx / N : 1.0);\n        for (double &v : x) v /= meanx;\n\n        // Hyperparameters\n        double lambda = 1e-3; // L2 regularization\n        double Lg = 0.25 * (double)N * (double)M + 2.0 * lambda; // Lipschitz upper bound\n        double eta = 1.0 / Lg; // step size\n        int iters = min(250, max(80, M / 4)); // more rows -> a bit more iterations\n\n        vector<double> grad(N, 0.0);\n        // Gradient descent with projection x >= 0\n        for (int it = 0; it < iters; it++) {\n            fill(grad.begin(), grad.end(), 0.0);\n            // Full batch gradient\n            const int8_t* Adata = Aflat.data();\n            for (int r = 0; r < M; r++) {\n                const int8_t yr = Y[r];\n                // s = a_r \u00b7 x\n                double s = 0.0;\n                const int8_t* row = Adata + (size_t)r * N;\n                for (int i = 0; i < N; i++) s += (double)row[i] * x[i];\n                // residual factor = - y * sigma(-y s) = -(y / (1 + exp(y s)))\n                double ys = (double)yr * s;\n                double p;\n                if (ys >= 0) {\n                    double e = exp(-ys);\n                    p = - (double)yr * (e / (1.0 + e));\n                } else {\n                    double e = exp(ys);\n                    p = - (double)yr * (1.0 / (1.0 + e));\n                }\n                // accumulate grad += p * a_r\n                for (int i = 0; i < N; i++) grad[i] += p * (double)row[i];\n            }\n            // add L2 gradient and take step\n            for (int i = 0; i < N; i++) {\n                grad[i] += 2.0 * lambda * x[i];\n                x[i] -= eta * grad[i];\n                if (x[i] < 1e-9) x[i] = 1e-9; // projection to nonnegative\n            }\n        }\n        w.swap(x);\n    }\n\n    // LPT initialization using refined weights\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng); // random tie-break\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){ return w[i] > w[j]; });\n\n    vector<int> assign(N, -1);\n    vector<double> binSum(D, 0.0);\n    vector<vector<int>> bins(D);\n    for (int idx : ord) {\n        int best = 0;\n        double bestSum = binSum[0];\n        for (int b = 1; b < D; b++) {\n            if (binSum[b] < bestSum) {\n                bestSum = binSum[b];\n                best = b;\n            }\n        }\n        assign[idx] = best;\n        binSum[best] += w[idx];\n        bins[best].push_back(idx);\n    }\n\n    // Local search: single moves to the lightest bin from any bin, then pair swaps across all heavy-light bin pairs\n    Timer timer;\n    const double TIME_BUDGET = 0.35; // seconds for local search\n    auto recompute_light_heavy = [&](){\n        int l = 0, h = 0;\n        for (int b = 1; b < D; b++) {\n            if (binSum[b] < binSum[l]) l = b;\n            if (binSum[b] > binSum[h]) h = b;\n        }\n        return pair<int,int>(l,h);\n    };\n\n    int iter = 0;\n    while (true) {\n        if (timer.elapsed() > TIME_BUDGET) break;\n        iter++;\n\n        // Recompute lightest and heaviest\n        auto [lbin, hbin] = recompute_light_heavy();\n        double best_delta = 0.0;\n        int from_b = -1, item_pos = -1, item_id = -1;\n        // Try single moves from any bin b != lbin to lbin\n        for (int b = 0; b < D; b++) {\n            if (b == lbin) continue;\n            double gap = binSum[b] - binSum[lbin];\n            if (gap <= 1e-12) continue;\n            double target = 0.5 * gap;\n            for (int pos = 0; pos < (int)bins[b].size(); pos++) {\n                int i = bins[b][pos];\n                double wi = w[i];\n                if (wi < gap) {\n                    double delta = -2.0 * wi * gap + 2.0 * wi * wi;\n                    if (from_b == -1 || delta < best_delta - 1e-15 ||\n                        (fabs(delta - best_delta) <= 1e-15 && fabs(wi - target) < fabs(w[item_id] - target))) {\n                        best_delta = delta;\n                        from_b = b;\n                        item_pos = pos;\n                        item_id = i;\n                    }\n                }\n            }\n        }\n        if (from_b != -1 && best_delta < -1e-12) {\n            // Perform the best single move\n            bins[from_b].erase(bins[from_b].begin() + item_pos);\n            bins[lbin].push_back(item_id);\n            assign[item_id] = lbin;\n            binSum[from_b] -= w[item_id];\n            binSum[lbin] += w[item_id];\n            continue;\n        }\n\n        // If no improving single move, try best pair swap across all heavier-lighter bin pairs\n        double best_swap_delta = 0.0;\n        int b_h = -1, b_l = -1, pos_i = -1, pos_j = -1;\n        int id_i = -1, id_j = -1;\n        for (int bh = 0; bh < D; bh++) {\n            for (int bl = 0; bl < D; bl++) {\n                if (binSum[bh] <= binSum[bl] + 1e-12) continue;\n                double gap = binSum[bh] - binSum[bl];\n                double target = 0.5 * gap;\n                for (int pi = 0; pi < (int)bins[bh].size(); pi++) {\n                    int i = bins[bh][pi];\n                    double wi = w[i];\n                    for (int pj = 0; pj < (int)bins[bl].size(); pj++) {\n                        int j = bins[bl][pj];\n                        double wj = w[j];\n                        double d = wi - wj;\n                        if (d <= 1e-12 || d >= gap - 1e-12) continue;\n                        double delta = 2.0 * (d * d - d * gap);\n                        if (b_h == -1 || delta < best_swap_delta - 1e-15 ||\n                            (fabs(delta - best_swap_delta) <= 1e-15 && fabs(d - target) < fabs((w[id_i] - w[id_j]) - target))) {\n                            best_swap_delta = delta;\n                            b_h = bh; b_l = bl;\n                            pos_i = pi; pos_j = pj;\n                            id_i = i; id_j = j;\n                        }\n                    }\n                }\n            }\n        }\n        if (b_h != -1 && best_swap_delta < -1e-12) {\n            // Perform swap\n            // Remove i from heavy bin and j from light bin\n            // Be careful with indices when erasing\n            int i = id_i, j = id_j;\n            // erase using swap-pop to O(1) then maintain order not needed\n            // but we need positions; simpler: erase by position\n            bins[b_h].erase(bins[b_h].begin() + pos_i);\n            bins[b_l].erase(bins[b_l].begin() + pos_j);\n            // add swapped\n            bins[b_h].push_back(j);\n            bins[b_l].push_back(i);\n            assign[i] = b_l; assign[j] = b_h;\n            double wi = w[i], wj = w[j];\n            binSum[b_h] += (wj - wi);\n            binSum[b_l] += (wi - wj);\n            continue;\n        }\n\n        // No improving move/swap\n        break;\n    }\n\n    // Output final assignment\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << assign[i];\n    }\n    cout << '\\n' << flush;\n\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Heuristic solver with improved destination scoring and opportunistic splitting.\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    if (!(cin >> n >> m)) return 0;\n    vector<vector<int>> st(m); // stacks: bottom -> top\n    int per = n / m;\n    for (int i = 0; i < m; ++i) {\n        st[i].resize(per);\n        for (int j = 0; j < per; ++j) cin >> st[i][j];\n    }\n\n    vector<pair<int,int>> ops;\n    ops.reserve(2000);\n\n    const int INF_TOP = n + 1;\n\n    auto carry_chain = [&](int &t) {\n        // Repeatedly extract while next needed is on some top.\n        bool changed = true;\n        while (changed && t <= n) {\n            changed = false;\n            for (int i = 0; i < m && t <= n; ++i) {\n                if (!st[i].empty() && st[i].back() == t) {\n                    st[i].pop_back();\n                    ops.emplace_back(t, 0);\n                    ++t;\n                    changed = true;\n                }\n            }\n        }\n    };\n\n    auto move_suffix = [&](int src, int start_idx, int dest) {\n        // Move suffix st[src][start_idx..end] to top of st[dest], preserving order.\n        // Assumes src != dest and start_idx < st[src].size()\n        for (int k = start_idx; k < (int)st[src].size(); ++k) {\n            st[dest].push_back(st[src][k]);\n        }\n        st[src].resize(start_idx);\n    };\n\n    auto find_box = [&](int v, int &src, int &idx) {\n        src = -1; idx = -1;\n        for (int i = 0; i < m; ++i) {\n            for (int j = (int)st[i].size() - 1; j >= 0; --j) {\n                if (st[i][j] == v) {\n                    src = i; idx = j; return;\n                }\n            }\n        }\n    };\n\n    auto choose_dest_with_prefix = [&](int src, int jv) -> int {\n        // jv = bottom index of block to move (just above target)\n        // Build block top-down\n        int s = (int)st[src].size() - jv;\n        vector<int> topDown;\n        topDown.reserve(s);\n        for (int k = (int)st[src].size() - 1; k >= jv; --k) topDown.push_back(st[src][k]);\n        // Evaluate candidates\n        int bestDest = -1;\n        int bestPrefix = -1;\n        int bestTop = -1;\n        for (int d = 0; d < m; ++d) if (d != src) {\n            int T = st[d].empty() ? INF_TOP : st[d].back();\n            int prefix = 0;\n            while (prefix < s && topDown[prefix] <= T) ++prefix;\n            // Prefer larger prefix, then larger T\n            if (prefix > bestPrefix || (prefix == bestPrefix && T > bestTop)) {\n                bestPrefix = prefix;\n                bestTop = T;\n                bestDest = d;\n            }\n        }\n        if (bestDest == -1) {\n            // Fallback (shouldn't happen when m>=2)\n            bestDest = (src == 0 ? 1 : 0);\n        }\n        return bestDest;\n    };\n\n    auto attempt_split_then_move = [&](int t, int src, int idx) -> bool {\n        // Try to split the above-block into two moves when top of block is larger than all others' tops\n        int jv = idx + 1;\n        int s = (int)st[src].size() - jv;\n        if (s <= 1) return false; // splitting not useful\n\n        // Build block top-down\n        vector<int> topDown;\n        topDown.reserve(s);\n        for (int k = (int)st[src].size() - 1; k >= jv; --k) topDown.push_back(st[src][k]);\n\n        int topBlock = topDown[0];\n\n        // Find best destination by top only (max T)\n        int bestDest = -1;\n        int Tbest = -1;\n        for (int d = 0; d < m; ++d) if (d != src) {\n            int T = st[d].empty() ? INF_TOP : st[d].back();\n            if (T > Tbest) {\n                Tbest = T;\n                bestDest = d;\n            }\n        }\n        if (bestDest == -1) return false;\n\n        if (Tbest >= topBlock) return false; // normal move will already have prefix >= 1\n\n        if (Tbest == INF_TOP) return false; // empty stack exists but shouldn't be < topBlock\n\n        // Find first position r (counting from top) where value <= Tbest\n        int r = 0;\n        while (r < s && topDown[r] > Tbest) ++r;\n        if (r >= s) return false; // no such element\n\n        // Compute how many consecutive elements from this position are <= Tbest\n        int p = 0;\n        while (r + p < s && topDown[r + p] <= Tbest) ++p;\n\n        // We need at least 2 to offset the extra +1 operation and gain future savings\n        if (p < 2) return false;\n\n        // First move: top segment A of size r to bestDest\n        int start_idx_A = (int)st[src].size() - r;\n        int vA = st[src][start_idx_A];\n        move_suffix(src, start_idx_A, bestDest);\n        ops.emplace_back(vA, bestDest + 1);\n\n        // Second move: remaining block (now size s - r) above t to a good destination\n        // Recompute destination with prefix scoring\n        int new_jv = idx + 1;\n        int dest2 = choose_dest_with_prefix(src, new_jv);\n        int vB = st[src][new_jv];\n        move_suffix(src, new_jv, dest2);\n        ops.emplace_back(vB, dest2 + 1);\n\n        return true;\n    };\n\n    int t = 1;\n    carry_chain(t);\n\n    while (t <= n) {\n        int src, idx;\n        find_box(t, src, idx);\n        if (src == -1) break; // should not happen\n\n        if (idx == (int)st[src].size() - 1) {\n            // t is already on top\n            st[src].pop_back();\n            ops.emplace_back(t, 0);\n            ++t;\n            carry_chain(t);\n            continue;\n        }\n\n        // Try opportunistic split in hard case\n        if (attempt_split_then_move(t, src, idx)) {\n            carry_chain(t);\n            continue;\n        }\n\n        // Normal: move the whole above-block to the best destination by prefix scoring\n        int jv = idx + 1;\n        int dest = choose_dest_with_prefix(src, jv);\n        int v = st[src][jv];\n        move_suffix(src, jv, dest);\n        ops.emplace_back(v, dest + 1);\n\n        // Then extract chain\n        carry_chain(t);\n    }\n\n    // Output\n    if ((int)ops.size() > 5000) {\n        // Extremely unlikely with this strategy; truncate if needed (but should not happen).\n        ops.resize(5000);\n    }\n    for (auto &op : ops) {\n        cout << op.first << ' ' << op.second << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge {\n    int u, v;\n    char ch_uv, ch_vu;\n};\n\nstruct AdjPort {\n    int to;\n    int eid;\n    char ch;             // move char from current node to 'to'\n    long long target;    // target departures from this node along this edge\n    long long used;      // departures used so far from this node along this edge\n};\n\nstruct XorShift64 {\n    unsigned long long x;\n    XorShift64(unsigned long long seed=88172645463393265ULL){x=seed;}\n    unsigned long long next() { x ^= x<<7; x ^= x>>9; return x; }\n    double nextDouble() { return (next() >> 11) * (1.0/9007199254740992.0); } // [0,1)\n    unsigned int nextUInt() { return (unsigned int)(next() & 0xFFFFFFFFULL); }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n\n    vector<string> hWall(max(0, N-1));\n    for (int i = 0; i < N-1; i++) cin >> hWall[i];\n    vector<string> vWall(N);\n    for (int i = 0; i < N; i++) cin >> vWall[i];\n\n    vector<vector<int>> d(N, vector<int>(N));\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) cin >> d[i][j];\n\n    auto inb = [&](int i, int j) -> bool { return (0 <= i && i < N && 0 <= j && j < N); };\n    auto canMove = [&](int i, int j, int di, int dj) -> bool {\n        int ni = i + di, nj = j + dj;\n        if (!inb(ni, nj)) return false;\n        if (di == 0 && dj == 1) { // right\n            return vWall[i][j] == '0';\n        } else if (di == 0 && dj == -1) { // left\n            return vWall[i][j-1] == '0';\n        } else if (di == 1 && dj == 0) { // down\n            return hWall[i][j] == '0';\n        } else if (di == -1 && dj == 0) { // up\n            return hWall[i-1][j] == '0';\n        }\n        return false;\n    };\n\n    int V = N * N;\n    auto id = [&](int i, int j) { return i * N + j; };\n    auto coord = [&](int v) { return pair<int,int>(v / N, v % N); };\n\n    // Build grid adjacency (unweighted)\n    vector<vector<int>> adjGrid(V);\n    vector<vector<char>> adjDir(V);\n    int di4[4] = {0, 1, 0, -1};\n    int dj4[4] = {1, 0, -1, 0};\n    char dc4[4] = {'R','D','L','U'};\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int u = id(i,j);\n        for (int k = 0; k < 4; k++) {\n            int ni = i + di4[k], nj = j + dj4[k];\n            if (!inb(ni, nj)) continue;\n            if (canMove(i, j, di4[k], dj4[k])) {\n                int v = id(ni, nj);\n                adjGrid[u].push_back(v);\n                adjDir[u].push_back(dc4[k]);\n            }\n        }\n    }\n\n    // BFS for shortest distances and parent tree\n    vector<int> dist(V, -1), par(V, -1);\n    vector<char> stepFromPar(V, '?');\n    deque<int> dq;\n    int root = 0;\n    dist[root] = 0;\n    dq.push_back(root);\n    // For mild bias, process neighbors of higher d first (tie-breaking for parent selection)\n    while (!dq.empty()) {\n        int u = dq.front(); dq.pop_front();\n        // sort neighbors by their d (descending) to bias BFS parent choices when multiple shortest exist\n        vector<int> idx(adjGrid[u].size());\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b){\n            int va = adjGrid[u][a], vb = adjGrid[u][b];\n            auto [ai, aj] = coord(va);\n            auto [bi, bj] = coord(vb);\n            if (d[ai][aj] != d[bi][bj]) return d[ai][aj] > d[bi][bj];\n            return adjDir[u][a] < adjDir[u][b];\n        });\n        for (int tidx : idx) {\n            int v = adjGrid[u][tidx];\n            if (dist[v] >= 0) continue;\n            dist[v] = dist[u] + 1;\n            par[v] = u;\n            stepFromPar[v] = adjDir[u][tidx];\n            dq.push_back(v);\n        }\n    }\n\n    // Children list (tree)\n    vector<vector<int>> children(V);\n    for (int v = 0; v < V; v++) {\n        if (v == root) continue;\n        if (par[v] >= 0) children[par[v]].push_back(v);\n    }\n\n    // Edges (tree edges)\n    vector<Edge> edges;\n    edges.reserve(V-1);\n    vector<int> edgeIdToParent(V, -1);\n    for (int vtx = 0; vtx < V; vtx++) {\n        if (vtx == root) continue;\n        int p = par[vtx];\n        auto [pi, pj] = coord(p);\n        auto [vi, vj] = coord(vtx);\n        char ch_pv = '?', ch_vp = '?';\n        if (vi == pi && vj == pj + 1) ch_pv = 'R';\n        else if (vi == pi && vj == pj - 1) ch_pv = 'L';\n        else if (vi == pi + 1 && vj == pj) ch_pv = 'D';\n        else if (vi == pi - 1 && vj == pj) ch_pv = 'U';\n        if (ch_pv == 'R') ch_vp = 'L';\n        else if (ch_pv == 'L') ch_vp = 'R';\n        else if (ch_pv == 'U') ch_vp = 'D';\n        else if (ch_pv == 'D') ch_vp = 'U';\n        Edge e{p, vtx, ch_pv, ch_vp};\n        int eid = (int)edges.size();\n        edges.push_back(e);\n        edgeIdToParent[vtx] = eid;\n    }\n\n    // Weight per node: sqrt(d / max(1, depth))\n    vector<long double> w(V, 0.0L);\n    for (int v = 0; v < V; v++) {\n        auto [i, j] = coord(v);\n        int dep = max(1, dist[v]);\n        w[v] = sqrtl((long double)d[i][j] / (long double)dep);\n    }\n\n    auto compute_length = [&](long double alpha, vector<long long>* out_sminus1 = nullptr) -> long long {\n        long long base = 2LL * (V - 1);\n        long long extra = 0;\n        if (out_sminus1) out_sminus1->assign(V, 0);\n        for (int v = 0; v < V; v++) {\n            if (v == root) continue;\n            int dep = dist[v];\n            if (dep <= 0) continue;\n            long double x = alpha * w[v];\n            long long s1 = (long long)floorl(x + 1e-18L);\n            if (s1 < 0) s1 = 0;\n            if (out_sminus1) (*out_sminus1)[v] = s1;\n            extra += 2LL * dep * s1;\n        }\n        return base + extra;\n    };\n\n    const long long Lmax = 100000;\n\n    // Binary search alpha to approach Lmax\n    long double lo = 0.0L, hi = 1.0L;\n    while (true) {\n        long long Lh = compute_length(hi);\n        if (Lh > Lmax) break;\n        if (hi > 1e12L) break;\n        hi *= 2.0L;\n    }\n    for (int it = 0; it < 60; it++) {\n        long double mid = (lo + hi) * 0.5L;\n        long long Lm = compute_length(mid);\n        if (Lm <= Lmax) lo = mid; else hi = mid;\n    }\n\n    vector<long long> sminus1;\n    long long Lfinal = compute_length(lo, &sminus1);\n\n    // If overshoot due to numeric, reduce cheapest extras first (low w or large depth)\n    if (Lfinal > Lmax) {\n        vector<int> idx;\n        idx.reserve(V);\n        for (int v = 0; v < V; v++) if (v != root && sminus1[v] > 0) idx.push_back(v);\n        sort(idx.begin(), idx.end(), [&](int a, int b){\n            if (w[a] != w[b]) return w[a] < w[b]; // remove worst weight first\n            if (dist[a] != dist[b]) return dist[a] > dist[b]; // drop far ones first\n            return a < b;\n        });\n        for (int v : idx) {\n            while (sminus1[v] > 0 && Lfinal > Lmax) {\n                sminus1[v]--;\n                Lfinal -= 2LL * dist[v];\n            }\n            if (Lfinal <= Lmax) break;\n        }\n    }\n\n    // Greedy fill remaining budget by best weight w[v] / cost (cost per unit = 2*dist)\n    long long remLen = Lmax - Lfinal;\n    if (remLen >= 2) {\n        vector<int> order(V);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b){\n            if (a == root && b == root) return false;\n            if (a == root) return false;\n            if (b == root) return true;\n            long double ra = w[a] / (long double)max(1, dist[a]);\n            long double rb = w[b] / (long double)max(1, dist[b]);\n            if (ra != rb) return ra > rb;\n            if (dist[a] != dist[b]) return dist[a] < dist[b];\n            return a < b;\n        });\n        bool progress = true;\n        while (remLen >= 2 && progress) {\n            progress = false;\n            for (int v : order) {\n                if (v == root) continue;\n                int dep = dist[v];\n                if (dep <= 0) continue;\n                long long cost = 2LL * dep;\n                if (cost <= remLen) {\n                    sminus1[v]++;\n                    remLen -= cost;\n                    progress = true;\n                    if (remLen < 2) break;\n                }\n            }\n        }\n        Lfinal = Lmax - remLen;\n    }\n\n    // Compute subtree sums of extra counts for multiplicities\n    vector<long long> subExtra(V, 0);\n    vector<int> orderV(V);\n    iota(orderV.begin(), orderV.end(), 0);\n    sort(orderV.begin(), orderV.end(), [&](int a, int b){\n        if (dist[a] != dist[b]) return dist[a] > dist[b];\n        return a < b;\n    });\n    for (int v : orderV) {\n        long long sumc = 0;\n        for (int c : children[v]) sumc += subExtra[c];\n        if (v == root) subExtra[v] = sumc;\n        else subExtra[v] = sumc + sminus1[v];\n    }\n\n    // Edge multiplicities: m_e = 2 * (1 + subExtra[child])\n    int M = (int)edges.size();\n    vector<long long> rem(M, 0), initM(M, 0);\n    for (int v = 0; v < V; v++) {\n        if (v == root) continue;\n        int eid = edgeIdToParent[v];\n        long long m = 2LL * (1 + subExtra[v]);\n        rem[eid] = m;\n        initM[eid] = m;\n    }\n\n    // Build adjacency for Euler with ports\n    vector<vector<AdjPort>> ports(V);\n    ports.assign(V, {});\n    ports.reserve(V);\n    for (int eid = 0; eid < M; eid++) {\n        auto &e = edges[eid];\n        long long target_each = initM[eid] / 2; // half on each endpoint\n        ports[e.u].push_back(AdjPort{e.v, eid, e.ch_uv, target_each, 0});\n        ports[e.v].push_back(AdjPort{e.u, eid, e.ch_vu, target_each, 0});\n    }\n\n    // Hierholzer with local weighted round-robin on ports by used/target ratio\n    XorShift64 rng(123456789ULL);\n    vector<int> st;\n    st.reserve(Lfinal + 5);\n    vector<int> out;\n    out.reserve(Lfinal + 5);\n    st.push_back(root);\n\n    // We do a full adjacency scan per step (deg <= 4)\n    while (!st.empty()) {\n        int v = st.back();\n        int bestIdx = -1;\n        long double bestKey = 1e100L;\n        long long bestRem = -1;\n        // Select incident edge with rem > 0 and minimal used/target ratio\n        for (int idx = 0; idx < (int)ports[v].size(); idx++) {\n            int eid = ports[v][idx].eid;\n            if (rem[eid] <= 0) continue;\n            long double t = (long double)ports[v][idx].target;\n            long double u = (long double)ports[v][idx].used;\n            // Tiny deterministic noise for ties\n            long double noise = (long double)( (rng.nextUInt() % 1024) ) * 1e-6L;\n            long double key;\n            if (t > 0.0L) key = (u + noise) / t;\n            else key = 0.0L + noise; // target should never be 0 here\n            // prefer smaller key; tie-breaker by larger rem to avoid dead-ends\n            if (key < bestKey - 1e-15L || (fabsl(key - bestKey) <= 1e-15L && rem[eid] > bestRem)) {\n                bestKey = key;\n                bestIdx = idx;\n                bestRem = rem[eid];\n            }\n        }\n        if (bestIdx != -1) {\n            int eid = ports[v][bestIdx].eid;\n            int to = ports[v][bestIdx].to;\n            // consume one traversal\n            rem[eid]--;\n            ports[v][bestIdx].used++;\n            st.push_back(to);\n        } else {\n            out.push_back(v);\n            st.pop_back();\n        }\n    }\n\n    reverse(out.begin(), out.end());\n\n    // Build move string from consecutive vertices\n    string ans;\n    ans.reserve(out.size() ? out.size()-1 : 0);\n    for (size_t i = 0; i + 1 < out.size(); i++) {\n        int a = out[i], b = out[i+1];\n        auto [ai, aj] = coord(a);\n        auto [bi, bj] = coord(b);\n        char ch = '?';\n        if (bi == ai && bj == aj + 1) ch = 'R';\n        else if (bi == ai && bj == aj - 1) ch = 'L';\n        else if (bi == ai + 1 && bj == aj) ch = 'D';\n        else if (bi == ai - 1 && bj == aj) ch = 'U';\n        else {\n            // Should not happen; fall back search in ports\n            bool found = false;\n            for (auto &pp : ports[a]) if (pp.to == b) { ch = pp.ch; found = true; break; }\n            if (!found) ch = 'U';\n        }\n        ans.push_back(ch);\n    }\n\n    // Safety clamp (shouldn't be needed)\n    if ((int)ans.size() > (int)Lmax) ans.resize((size_t)Lmax);\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, r;\n    DSU(int n=0): n(n), p(n), r(n,0) { iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n    bool unite(int a, int b){\n        a = find(a); b = find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n    bool same(int a, int b){ return find(a)==find(b); }\n};\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed=88172645463393265ull){ x=seed; }\n    uint64_t next(){\n        x ^= x<<7;\n        x ^= x>>9;\n        return x;\n    }\n    int next_int(int l, int r){ // inclusive\n        return l + (int)(next() % (uint64_t)(r-l+1));\n    }\n    double next_double(){ return (next() >> 11) * (1.0 / (1ull<<53)); }\n};\n\nstruct Pos { short i, j; };\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, M;\n    if(!(cin >> N >> M)) return 0;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> A(N);\n    for(int i=0;i<N;i++) cin >> A[i];\n    vector<string> t(M);\n    for(int k=0;k<M;k++) cin >> t[k]; // M=200, each length 5\n\n    // Collect positions for each uppercase letter\n    vector<vector<Pos>> pos(26);\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            int c = A[i][j]-'A';\n            pos[c].push_back(Pos{(short)i,(short)j});\n        }\n    }\n\n    // Precompute overlap matrix f[i][j]: longest k in [0..4] suffix of t[i] length k equals prefix of t[j] length k\n    vector<array<short, 26>> dummy; // not used\n    vector<vector<int>> f(M, vector<int>(M, 0));\n    auto overlap = [&](const string& a, const string& b)->int{\n        // lengths are 5\n        // check k from 4 to 1\n        for(int k=4;k>=1;k--){\n            bool ok=true;\n            for(int x=0;x<k;x++){\n                if(a[5-k+x] != b[x]){ ok=false; break; }\n            }\n            if(ok) return k;\n        }\n        return 0;\n    };\n    for(int i=0;i<M;i++){\n        for(int j=0;j<M;j++){\n            if(i==j) continue;\n            f[i][j] = overlap(t[i], t[j]);\n        }\n    }\n\n    auto sum_overlaps = [&](const vector<int>& pi)->int{\n        int s=0;\n        for(int i=0;i+1<(int)pi.size();i++) s += f[pi[i]][pi[i+1]];\n        return s;\n    };\n\n    XorShift rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Initial candidate 1: Greedy arc packing to form chains\n    vector<int> best_pi;\n    int best_score = -1;\n\n    {\n        struct Arc { int u, v; int w; uint64_t r; };\n        vector<Arc> arcs;\n        arcs.reserve((size_t)M*(M-1));\n        for(int i=0;i<M;i++){\n            for(int j=0;j<M;j++){\n                if(i==j) continue;\n                Arc a{ i, j, f[i][j], rng.next() };\n                arcs.push_back(a);\n            }\n        }\n        sort(arcs.begin(), arcs.end(), [](const Arc& a, const Arc& b){\n            if(a.w != b.w) return a.w > b.w;\n            return a.r < b.r;\n        });\n        vector<int> succ(M, -1), pred(M, -1);\n        DSU uf(M);\n        for(const auto& e : arcs){\n            int u=e.u, v=e.v;\n            if(succ[u]!=-1) continue;\n            if(pred[v]!=-1) continue;\n            if(uf.same(u, v)) continue; // would create a cycle\n            succ[u]=v;\n            pred[v]=u;\n            uf.unite(u, v);\n        }\n        // Extract chains\n        vector<char> used(M, 0);\n        vector<vector<int>> chains;\n        for(int i=0;i<M;i++){\n            if(pred[i]==-1){ // head of chain\n                vector<int> chain;\n                int cur=i;\n                while(cur!=-1){\n                    chain.push_back(cur);\n                    used[cur]=1;\n                    cur = succ[cur];\n                }\n                chains.push_back(move(chain));\n            }\n        }\n        // Any remaining nodes (in case of anomalies) -> singletons\n        for(int i=0;i<M;i++){\n            if(!used[i]){\n                chains.push_back(vector<int>{i});\n                used[i]=1;\n            }\n        }\n        int C = (int)chains.size();\n        // Build chain order greedily\n        vector<int> head(C), tail(C);\n        for(int c=0;c<C;c++){\n            head[c] = chains[c].front();\n            tail[c] = chains[c].back();\n        }\n        // Compute inBest for chains\n        vector<int> inBest(C, 0);\n        for(int j=0;j<C;j++){\n            int best=0;\n            for(int i=0;i<C;i++){\n                if(i==j) continue;\n                best = max(best, f[tail[i]][head[j]]);\n            }\n            inBest[j]=best;\n        }\n        int start = 0;\n        int minIn = INT_MAX;\n        for(int j=0;j<C;j++){\n            if(inBest[j] < minIn){\n                minIn = inBest[j];\n                start = j;\n            }\n        }\n        vector<char> usedChain(C, 0);\n        vector<int> orderChains; orderChains.reserve(C);\n        int cur = start; usedChain[cur]=1; orderChains.push_back(cur);\n        for(int step=1; step<C; step++){\n            int bestW=-1, bestJ=-1;\n            for(int j=0;j<C;j++){\n                if(usedChain[j]) continue;\n                int w = f[tail[cur]][head[j]];\n                if(w>bestW){ bestW=w; bestJ=j; }\n            }\n            if(bestJ==-1){\n                // pick any remaining\n                for(int j=0;j<C;j++){ if(!usedChain[j]){ bestJ=j; break; } }\n            }\n            usedChain[bestJ]=1;\n            orderChains.push_back(bestJ);\n            cur = bestJ;\n        }\n        vector<int> pi;\n        pi.reserve(M);\n        for(int idx : orderChains){\n            for(int node : chains[idx]) pi.push_back(node);\n        }\n        int score = sum_overlaps(pi);\n        if(score > best_score){\n            best_score = score;\n            best_pi = pi;\n        }\n    }\n\n    // Initial candidate 2: nearest neighbor greedy from several starts\n    {\n        // Precompute best outgoing for tie breaks\n        vector<int> bestOut(M, 0), bestIn(M, 0);\n        for(int i=0;i<M;i++){\n            int bo=0, bi=0;\n            for(int j=0;j<M;j++){\n                if(i==j) continue;\n                bo = max(bo, f[i][j]);\n                bi = max(bi, f[j][i]);\n            }\n            bestOut[i]=bo; bestIn[i]=bi;\n        }\n        auto build_from_start = [&](int s)->vector<int>{\n            vector<char> used(M,0);\n            vector<int> pi; pi.reserve(M);\n            int cur = s; used[cur]=1; pi.push_back(cur);\n            for(int k=1;k<M;k++){\n                int bestW=-1, bestJ=-1;\n                int bestTie=-1;\n                for(int j=0;j<M;j++){\n                    if(used[j]) continue;\n                    int w = f[cur][j];\n                    int tie = bestOut[j]; // or bestIn, choose out\n                    if(w > bestW || (w==bestW && tie > bestTie)){\n                        bestW=w; bestJ=j; bestTie=tie;\n                    }\n                }\n                if(bestJ==-1){\n                    for(int j=0;j<M;j++){ if(!used[j]){ bestJ=j; break; } }\n                }\n                used[bestJ]=1;\n                pi.push_back(bestJ);\n                cur=bestJ;\n            }\n            return pi;\n        };\n        // Try multiple starts (all or subset)\n        int trials = min(M, 40); // try 40 starts to save time\n        vector<int> startList;\n        startList.reserve(trials);\n        // pick some deterministic plus random starts\n        for(int i=0;i<trials;i++){\n            startList.push_back(i);\n        }\n        // Some random additional\n        for(int i=trials;i<min(M, trials+10);i++){\n            startList.push_back(rng.next_int(0, M-1));\n        }\n        for(int s : startList){\n            vector<int> pi = build_from_start(s);\n            int score = sum_overlaps(pi);\n            if(score > best_score){\n                best_score = score;\n                best_pi = move(pi);\n            }\n        }\n    }\n\n    // Local search: insertion-based hill climbing to improve sum of overlaps\n    vector<int> pi = best_pi;\n    int curSum = sum_overlaps(pi);\n\n    auto getEdge = [&](int a, int b)->int{\n        if(a<0 || b<0) return 0;\n        return f[a][b];\n    };\n\n    auto compute_insert_delta = [&](const vector<int>& p, int i, int j2)->int{\n        // i in [0..M-1], j2 in [0..M-1] inclusive of end position (len = M-1)\n        int Mloc = (int)p.size();\n        int x = p[i];\n        int delta = 0;\n        // Removal\n        if(i > 0) delta -= getEdge(p[i-1], p[i]);\n        if(i < Mloc-1) delta -= getEdge(p[i], p[i+1]);\n        if(i > 0 && i < Mloc-1) delta += getEdge(p[i-1], p[i+1]);\n\n        int len = Mloc - 1;\n        if(j2 < 0 || j2 > len) return INT_MIN/4; // invalid\n        auto getAfter = [&](int k)->int{\n            // k in [0..len-1]\n            if(k < i) return p[k];\n            else return p[k+1];\n        };\n        int L = -1, R = -1;\n        if(j2 > 0) L = getAfter(j2-1);\n        if(j2 < len) R = getAfter(j2);\n        // Replace boundary edge L->R by L->x and x->R\n        if(L != -1 && R != -1){\n            delta -= getEdge(L, R);\n            delta += getEdge(L, x);\n            delta += getEdge(x, R);\n        }else if(L == -1 && R != -1){\n            delta += getEdge(x, R);\n        }else if(L != -1 && R == -1){\n            delta += getEdge(L, x);\n        }else{\n            // len==0, inserting single element into empty? won't happen here\n        }\n        return delta;\n    };\n\n    auto apply_insert = [&](vector<int>& p, int i, int j2){\n        int x = p[i];\n        p.erase(p.begin()+i);\n        p.insert(p.begin()+j2, x);\n    };\n\n    auto start_time = chrono::high_resolution_clock::now();\n    double TIME_LIMIT = 1.75; // seconds budget for local search to be safe\n    auto elapsed = [&](){\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - start_time).count();\n    };\n\n    // First-improvement loop\n    while(true){\n        if(elapsed() > TIME_LIMIT) break;\n        bool improved = false;\n        // To diversify, randomize iteration order sometimes\n        vector<int> idx(M);\n        iota(idx.begin(), idx.end(), 0);\n        if(rng.next_int(0, 1)) {\n            shuffle(idx.begin(), idx.end(), std::mt19937((uint32_t)rng.next()));\n        }\n        for(int ii=0; ii<M; ii++){\n            if(elapsed() > TIME_LIMIT) break;\n            int i = idx[ii];\n            int len = M-1;\n            // j2 in [0..len], but skip \"no-op\" position:\n            // After removing i, inserting back at position i is no-op. So skip j2==i.\n            for(int j2=0; j2<=len; j2++){\n                if(j2 == i) continue;\n                int delta = compute_insert_delta(pi, i, j2);\n                if(delta > 0){\n                    apply_insert(pi, i, j2);\n                    curSum += delta;\n                    improved = true;\n                    break;\n                }\n            }\n            if(improved) break;\n        }\n        if(!improved) break;\n    }\n\n    // Build the string S from the permutation pi\n    string S;\n    S.reserve(5 * M); // approximate\n    S += t[pi[0]];\n    for(int k=1;k<M;k++){\n        int a = pi[k-1], b = pi[k];\n        int ov = f[a][b];\n        for(int x=ov; x<5; x++) S.push_back(t[b][x]);\n    }\n\n    // Map S to grid positions minimizing total cost via DP\n    int L = (int)S.size();\n    vector<int> letters(L);\n    for(int i=0;i<L;i++) letters[i] = S[i]-'A';\n\n    // parent pointers: for each step, for each candidate pos index at that step, store selected prev index\n    vector<vector<int>> parent(L); // parent[l][qidx] = index in pos[letters[l-1]]\n    vector<int> prev_dp_idx; // not needed entire; keep dp arrays\n    vector<int> dp_prev, dp_curr;\n    vector<pair<int,int>> coords_prev, coords_curr; // not necessary, we can access pos arrays\n\n    // Initialize for step 0\n    int c0 = letters[0];\n    int P0 = pos[c0].size();\n    if(P0 == 0){\n        // In case letter does not exist (should not happen due to guarantee), fallback: pick any cell 0,0\n        // But problem guarantees presence.\n    }\n    dp_prev.assign(P0, INT_MAX/4);\n    parent[0].assign(P0, -1);\n    for(int q=0;q<P0;q++){\n        int ii = pos[c0][q].i, jj = pos[c0][q].j;\n        int dist = abs(ii - si) + abs(jj - sj);\n        dp_prev[q] = dist + 1;\n    }\n\n    for(int l=1;l<L;l++){\n        int c = letters[l];\n        int Pc = pos[c].size();\n        int cp = letters[l-1];\n        int Pp = pos[cp].size();\n        dp_curr.assign(Pc, INT_MAX/4);\n        parent[l].assign(Pc, -1);\n        // For each current candidate, find best previous\n        for(int q=0;q<Pc;q++){\n            int qi = pos[c][q].i, qj = pos[c][q].j;\n            int best = INT_MAX/4;\n            int bestp = -1;\n            // iterate previous candidates\n            for(int p=0;p<Pp;p++){\n                int pi_i = pos[cp][p].i, pi_j = pos[cp][p].j;\n                int dist = abs(qi - pi_i) + abs(qj - pi_j);\n                int cand = dp_prev[p] + dist + 1;\n                if(cand < best){\n                    best = cand;\n                    bestp = p;\n                }\n            }\n            dp_curr[q] = best;\n            parent[l][q] = bestp;\n        }\n        dp_prev.swap(dp_curr);\n    }\n\n    // Choose best last position\n    int last_letter = letters[L-1];\n    int P_last = pos[last_letter].size();\n    int best_last_idx = 0;\n    int best_cost = INT_MAX/4;\n    for(int q=0;q<P_last;q++){\n        if(dp_prev[q] < best_cost){\n            best_cost = dp_prev[q];\n            best_last_idx = q;\n        }\n    }\n\n    // Reconstruct path\n    vector<pair<int,int>> ops(L);\n    int idx = best_last_idx;\n    for(int l=L-1; l>=0; l--){\n        int c = letters[l];\n        int ii = pos[c][idx].i, jj = pos[c][idx].j;\n        ops[l] = {ii, jj};\n        if(l>0){\n            idx = parent[l][idx];\n            if(idx < 0) idx = 0; // safety\n        }\n    }\n\n    // Output\n    // L is number of operations (length of S), guaranteed < 5000\n    for(int l=0;l<L;l++){\n        cout << ops[l].first << \" \" << ops[l].second << \"\\n\";\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer for time management\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::steady_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\n// Utilities\nstatic inline int cell_id(int i, int j, int N) { return i * N + j; }\nstatic inline pair<int,int> cell_ij(int id, int N) { return {id / N, id % N}; }\n\nstruct Shape {\n    int id;\n    vector<pair<int,int>> offsets; // relative cells (di,dj)\n    int H=0, W=0;\n    vector<vector<int>> shiftsCells; // per shift index, list of covered global cell ids\n    // For each global cell id (0..N*N-1), list of shift indices that cover it\n    vector<vector<int>> coverShiftsByCell; // size N*N; sparse per shape\n};\n\nstruct Problem {\n    int N, M;\n    double eps;\n    vector<Shape> shapes;\n};\n\nstruct State {\n    int N, M;\n    const Problem* prob;\n\n    // Known v values per cell; -1 unknown, >=0 known\n    vector<int> known; // size N*N\n    vector<int> drilledCells; // list of cell ids drilled\n    vector<int> vDrilled; // same order as drilledCells\n    vector<int> drilledIndexOf; // size N*N, maps cell id -> index in drilledCells or -1\n\n    // Active candidate shifts per shape: active[k][p] bool\n    vector<vector<uint8_t>> active; // per shape k, size Pk\n    vector<int> activeCount; // per shape k: number of active candidates\n\n    // For computation on drilled cells\n    int D = 0;\n    vector<vector<int>> anyCoverKD;  // M x D : 0/1 whether shape k could cover drilled cell d\n    vector<vector<int>> mustCoverKD; // M x D : 0/1 whether shape k must cover drilled cell d (all candidates cover it)\n    vector<int> sumAnyD;  // size D\n    vector<int> sumMustD; // size D\n\n    // caches per enumeration run: for each shape k, for each shift p, list of drilled indices it covers\n    vector<vector<vector<int>>> coverDrilledCache; // M x Pk x (#drilled covered indices)\n\n    // Operation count\n    int opCount = 0;\n    int opLimit;\n\n    // Random\n    mt19937 rng;\n\n    // Time management\n    Timer timer;\n    double timeLimitSec = 2.7; // keep some margin\n\n    State(const Problem* pr) {\n        prob = pr;\n        N = pr->N;\n        M = pr->M;\n        known.assign(N*N, -1);\n        drilledIndexOf.assign(N*N, -1);\n        active.resize(M);\n        activeCount.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            active[k].assign(Pk, 1);\n            activeCount[k] = Pk;\n        }\n        rng.seed(chrono::high_resolution_clock::now().time_since_epoch().count());\n        opLimit = 2 * N * N; // per problem\n    }\n\n    void flush() { cout.flush(); }\n\n    int drill_cell(int ci) {\n        if (known[ci] != -1) return known[ci];\n        auto [i,j] = cell_ij(ci, N);\n        cout << \"q 1 \" << i << \" \" << j << \"\\n\";\n        flush();\n        string s;\n        if (!(cin >> s)) {\n            // Should not happen; safeguard\n            exit(0);\n        }\n        int val = stoi(s);\n        known[ci] = val;\n        drilledIndexOf[ci] = (int)drilledCells.size();\n        drilledCells.push_back(ci);\n        vDrilled.push_back(val);\n        ++opCount;\n        // zero elimination\n        if (val == 0) {\n            // Eliminate all active shifts covering this cell\n            for (int k = 0; k < M; ++k) {\n                if (activeCount[k] == 0) continue;\n                const vector<int>& listShifts = prob->shapes[k].coverShiftsByCell[ci];\n                for (int p : listShifts) {\n                    if (active[k][p]) {\n                        active[k][p] = 0;\n                        --activeCount[k];\n                    }\n                }\n            }\n        }\n        return val;\n    }\n\n    // recompute D and per-drilled coverage bounds from current active sets\n    void recomputeCoverageBounds() {\n        D = (int)drilledCells.size();\n        anyCoverKD.assign(M, vector<int>(D, 0));\n        mustCoverKD.assign(M, vector<int>(D, 0));\n        sumAnyD.assign(D, 0);\n        sumMustD.assign(D, 0);\n        // For each shape k, for each drilled cell d, compute how many active shifts cover it\n        for (int k = 0; k < M; ++k) {\n            if (activeCount[k] == 0) continue; // Infeasible but handle\n            for (int d = 0; d < D; ++d) {\n                int c = drilledCells[d];\n                int count = 0;\n                const vector<int>& listShifts = prob->shapes[k].coverShiftsByCell[c];\n                for (int p : listShifts) if (active[k][p]) ++count;\n                anyCoverKD[k][d] = (count > 0) ? 1 : 0;\n                mustCoverKD[k][d] = (count == activeCount[k]) ? 1 : 0;\n                sumAnyD[d] += anyCoverKD[k][d];\n                sumMustD[d] += mustCoverKD[k][d];\n            }\n        }\n    }\n\n    // Prepare coverDrilledCache for current drilled set\n    void buildCoverDrilledCache() {\n        D = (int)drilledCells.size();\n        coverDrilledCache.clear();\n        coverDrilledCache.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            coverDrilledCache[k].resize(Pk);\n        }\n        // Build mapping cell id -> drilled index is already drilledIndexOf\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            for (int p = 0; p < Pk; ++p) {\n                if (!active[k][p]) { coverDrilledCache[k][p].clear(); continue; }\n                const vector<int>& cells = prob->shapes[k].shiftsCells[p];\n                vector<int>& vect = coverDrilledCache[k][p];\n                vect.clear();\n                // For each covered cell, if it is drilled, add its drilled index\n                for (int c : cells) {\n                    int d = drilledIndexOf[c];\n                    if (d >= 0) vect.push_back(d);\n                }\n                sort(vect.begin(), vect.end()); // for membership scan\n                vect.erase(unique(vect.begin(), vect.end()), vect.end());\n            }\n        }\n    }\n\n    // Choose shapes order for DFS. Optional: for target cell constraint\n    vector<int> chooseOrder(int targetCell = -1, int requireCovered = -1) {\n        // requireCovered: -1 no special, 0 force uncovered, 1 force covered\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        // prefer shapes with smaller activeCount; if force covered on targetCell, prioritize shapes that can cover it\n        auto canCover = [&](int k)->int {\n            if (targetCell < 0) return 0;\n            const auto& list = prob->shapes[k].coverShiftsByCell[targetCell];\n            for (int p : list) if (active[k][p]) return 1;\n            return 0;\n        };\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b){\n            // For requireCovered==1, shapes that can cover target come first\n            int ca = canCover(a), cb = canCover(b);\n            if (requireCovered == 1) {\n                if (ca != cb) return ca > cb;\n            } else if (requireCovered == 0) {\n                // force uncovered doesn't need special ordering\n            }\n            if (activeCount[a] != activeCount[b]) return activeCount[a] < activeCount[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    // Check if any active candidate remains for every shape; if not, something went wrong\n    bool allShapesHaveCandidates() const {\n        for (int k = 0; k < M; ++k) if (activeCount[k] <= 0) return false;\n        return true;\n    }\n\n    struct DFSContext {\n        State* st;\n        vector<int> order; // shape order\n        vector<int> cur; // current sums at drilled cells, size D\n        vector<int> assign; // chosen shift index per shape (or -1)\n        int solutionsLimit;\n        int solutionsFound;\n        vector<int> lastAssignment;\n        vector<int> unionCounts; // size N*N; count of solutions covering each cell\n        bool respectTime;\n        int targetCell; // -1 no target\n        int requireCovered; // -1 none, 0 force uncovered, 1 force covered\n        bool coveredYet; // for target requireCovered=1\n        vector<int> canCoverRemain; // prefix: for pruning target coverage\n        // cache pointers for speed\n        vector<vector<vector<int>>> *coverDrilledCachePtr;\n        vector<vector<int>> *anyCoverKDPtr;\n        vector<vector<int>> *mustCoverKDPtr;\n        vector<int> *sumAnyDPtr;\n        vector<int> *sumMustDPtr;\n\n        DFSContext(State* st_, const vector<int>& order_, int solLim, bool respectTime_,\n                   int targetCell_ = -1, int requireCovered_ = -1)\n            : st(st_), order(order_), solutionsLimit(solLim), solutionsFound(0),\n              respectTime(respectTime_), targetCell(targetCell_), requireCovered(requireCovered_) {\n            int D = (int)st->drilledCells.size();\n            cur.assign(D, 0);\n            assign.assign(st->M, -1);\n            lastAssignment.assign(st->M, -1);\n            unionCounts.assign(st->N*st->N, 0);\n            coveredYet = false;\n            canCoverRemain.assign(st->M+1, 0); // we'll compute cumulative suffix later if needed\n            coverDrilledCachePtr = &st->coverDrilledCache;\n            anyCoverKDPtr = &st->anyCoverKD;\n            mustCoverKDPtr = &st->mustCoverKD;\n            sumAnyDPtr = &st->sumAnyD;\n            sumMustDPtr = &st->sumMustD;\n        }\n\n        bool canShapeCoverTarget(int k) const {\n            if (targetCell < 0) return false;\n            const auto& list = st->prob->shapes[k].coverShiftsByCell[targetCell];\n            for (int p : list) if (st->active[k][p]) return true;\n            return false;\n        }\n\n        // Prepare suffix counts of shapes that can potentially cover target cell\n        void prepareCoverRemain() {\n            if (requireCovered != 1 || targetCell < 0) return;\n            vector<int> seq = order;\n            int m = st->M;\n            canCoverRemain.assign(m+1, 0);\n            for (int pos = m-1; pos >= 0; --pos) {\n                int k = seq[pos];\n                int add = canShapeCoverTarget(k) ? 1 : 0;\n                canCoverRemain[pos] = canCoverRemain[pos+1] + add;\n            }\n        }\n\n        // Build union and record a solution\n        void recordSolution() {\n            // Build union from assignments\n            vector<uint8_t> covered(st->N*st->N, 0);\n            for (int pos = 0; pos < st->M; ++pos) {\n                int k = order[pos];\n                int p = assign[k];\n                if (p < 0) return; // shouldn't happen\n                const vector<int>& cells = st->prob->shapes[k].shiftsCells[p];\n                for (int c : cells) covered[c] = 1;\n            }\n            for (int c = 0; c < st->N*st->N; ++c) if (covered[c]) ++unionCounts[c];\n            lastAssignment = assign;\n            ++solutionsFound;\n        }\n\n        // Viability check for choosing shape k shift p\n        bool viableChoice(int k, int p) {\n            // For requireCovered=0 (force uncovered), disallow shifts that cover target cell\n            if (requireCovered == 0 && targetCell >= 0) {\n                // check if this shift covers target cell\n                const vector<int>& cells = st->prob->shapes[k].shiftsCells[p];\n                // quick: iterate cells\n                for (int c : cells) if (c == targetCell) return false;\n            }\n\n            // For requireCovered=1, we will prune later if impossible to cover target\n\n            const vector<vector<int>>& anyCoverKD = *anyCoverKDPtr;\n            const vector<vector<int>>& mustCoverKD = *mustCoverKDPtr;\n            const vector<int>& sumAnyD = *sumAnyDPtr;\n            const vector<int>& sumMustD = *sumMustDPtr;\n            const vector<int>& vDrilled = st->vDrilled;\n            const vector<int>& cur = this->cur;\n\n            const vector<int>& coverD = (*coverDrilledCachePtr)[k][p];\n            int D = (int)st->drilledCells.size();\n\n            // We'll scan d=0..D-1 and see if rem' within [lb_excl, ub_excl]\n            int ptr = 0;\n            for (int d = 0; d < D; ++d) {\n                int cover = 0;\n                if (ptr < (int)coverD.size() && coverD[ptr] == d) { cover = 1; ++ptr; }\n                int remp = vDrilled[d] - (cur[d] + cover);\n                if (remp < 0) return false;\n                int ub_excl = sumAnyD[d] - anyCoverKD[k][d];\n                int lb_excl = sumMustD[d] - mustCoverKD[k][d];\n                if (remp < lb_excl) return false;\n                if (remp > ub_excl) return false;\n            }\n            return true;\n        }\n\n        void dfs(int pos) {\n            if (solutionsFound >= solutionsLimit) return;\n            if (respectTime && st->timer.elapsed() > st->timeLimitSec) return;\n            if (pos == st->M) {\n                // Target constraint check for requireCovered=1\n                if (requireCovered == 1 && targetCell >= 0) {\n                    // ensure at least one chosen shift covers target\n                    bool cov = false;\n                    for (int k = 0; k < st->M && !cov; ++k) {\n                        int kk = order[k];\n                        int p = assign[kk];\n                        if (p < 0) continue;\n                        const vector<int>& cells = st->prob->shapes[kk].shiftsCells[p];\n                        for (int c : cells) { if (c == targetCell) { cov = true; break; } }\n                    }\n                    if (!cov) return;\n                }\n                // Valid solution\n                recordSolution();\n                return;\n            }\n            int k = order[pos];\n\n            // If requireCovered==1 and target not yet covered: prune if no remaining shapes can cover it\n            if (requireCovered == 1 && targetCell >= 0) {\n                bool coveredNow = false;\n                // check coveredYet quickly by partial assignment\n                for (int t = 0; t < pos; ++t) {\n                    int kk = order[t];\n                    int psel = assign[kk];\n                    if (psel < 0) continue;\n                    const vector<int>& cells = st->prob->shapes[kk].shiftsCells[psel];\n                    for (int c : cells) if (c == targetCell) { coveredNow = true; break; }\n                    if (coveredNow) break;\n                }\n                if (!coveredNow) {\n                    int remCoverable = 0;\n                    for (int t = pos; t < st->M; ++t) {\n                        int kk = order[t];\n                        const auto& list = st->prob->shapes[kk].coverShiftsByCell[targetCell];\n                        bool ok = false;\n                        for (int p : list) if (st->active[kk][p]) { ok = true; break; }\n                        if (ok) ++remCoverable;\n                    }\n                    if (remCoverable == 0) return;\n                }\n            }\n\n            // Enumerate candidate shifts for shape k with simple ordering:\n            // Prefer shifts that influence drilled cells tightly; but we keep natural order\n            const int Pk = (int)st->prob->shapes[k].shiftsCells.size();\n\n            // Heuristic: try shifts that do/don't cover target first to reach target satisfaction quickly\n            vector<int> candidates;\n            candidates.reserve(st->activeCount[k]);\n            if (requireCovered == 1 && targetCell >= 0) {\n                // try those that cover target first\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) {\n                    const vector<int>& cells = st->prob->shapes[k].shiftsCells[p];\n                    bool cov = false;\n                    for (int c : cells) { if (c == targetCell) { cov = true; break; } }\n                    if (cov) candidates.push_back(p);\n                }\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) {\n                    const vector<int>& cells = st->prob->shapes[k].shiftsCells[p];\n                    bool cov = false;\n                    for (int c : cells) { if (c == targetCell) { cov = true; break; } }\n                    if (!cov) candidates.push_back(p);\n                }\n            } else {\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) candidates.push_back(p);\n            }\n\n            for (int p : candidates) {\n                if (!viableChoice(k, p)) continue;\n                // Choose\n                assign[k] = p;\n                // Update cur\n                const vector<int>& coverD = (*coverDrilledCachePtr)[k][p];\n                for (int d : coverD) ++cur[d];\n                dfs(pos+1);\n                for (int d : coverD) --cur[d];\n                assign[k] = -1;\n                if (solutionsFound >= solutionsLimit) return;\n                if (respectTime && st->timer.elapsed() > st->timeLimitSec) return;\n            }\n        }\n    };\n\n    // Enumerate up to L solutions (time limited) to collect union counts and one assignment\n    void enumerateSolutionsLimited(int L, vector<int>& oneAssignOut, vector<int>& unionCountsOut, int& found) {\n        recomputeCoverageBounds();\n        buildCoverDrilledCache();\n        vector<int> order = chooseOrder();\n        DFSContext ctx(this, order, L, true);\n        ctx.prepareCoverRemain();\n        ctx.dfs(0);\n        found = ctx.solutionsFound;\n        oneAssignOut = ctx.lastAssignment;\n        unionCountsOut = ctx.unionCounts;\n    }\n\n    // Forced alternative existence for target cell c; wantStatus: 0 force uncovered, 1 force covered\n    bool existsAlternativeForCell(int c, int wantStatus) {\n        // Quick contradictions with drilled known:\n        if (known[c] == 0 && wantStatus == 1) return false;\n        if (known[c] > 0 && wantStatus == 0) return false;\n\n        recomputeCoverageBounds();\n        buildCoverDrilledCache();\n\n        // Quick pre-check: if wantStatus==1 and no shape can possibly cover c with active candidates, impossible\n        bool anyShapeCanCover = false;\n        for (int k = 0; k < M; ++k) {\n            const auto& list = prob->shapes[k].coverShiftsByCell[c];\n            bool ok = false;\n            for (int p : list) if (active[k][p]) { ok = true; break; }\n            if (ok) { anyShapeCanCover = true; break; }\n        }\n        if (wantStatus == 1 && !anyShapeCanCover) return false;\n\n        // For wantStatus==0, if there exists a shape for which all active candidates cover c (mustCover), then impossible\n        for (int k = 0; k < M; ++k) {\n            const auto& list = prob->shapes[k].coverShiftsByCell[c];\n            int coverCount = 0;\n            for (int p : list) if (active[k][p]) ++coverCount;\n            if (activeCount[k] > 0 && coverCount == activeCount[k]) { // must cover\n                if (wantStatus == 0) return false;\n            }\n        }\n\n        int L = 1; // only need to know if at least one alternative exists\n        int requireCovered = (wantStatus == 1) ? 1 : 0;\n        vector<int> order = chooseOrder(c, requireCovered);\n        DFSContext ctx(this, order, L, true, c, requireCovered);\n        ctx.prepareCoverRemain();\n        ctx.dfs(0);\n        return ctx.solutionsFound >= 1;\n    }\n\n    // Build union set from an assignment (shift indices per shape)\n    vector<uint8_t> buildUnionFromAssignment(const vector<int>& assign) {\n        vector<uint8_t> covered(N*N, 0);\n        for (int k = 0; k < M; ++k) {\n            int p = assign[k];\n            if (p < 0) continue;\n            const vector<int>& cells = prob->shapes[k].shiftsCells[p];\n            for (int c : cells) covered[c] = 1;\n        }\n        return covered;\n    }\n\n    // Attempt to resolve union and drill ambiguous cells until unique\n    vector<uint8_t> solveUnion() {\n        // Initial coarse drilling: grid sampling\n        int step = (N >= 18 ? 4 : (N >= 14 ? 3 : 3));\n        for (int i = 0; i < N; i += step) {\n            for (int j = 0; j < N; j += step) {\n                if (opCount >= opLimit) break;\n                int c = cell_id(i, j, N);\n                if (known[c] == -1) {\n                    drill_cell(c);\n                }\n            }\n        }\n\n        // Ensure feasibility\n        if (!allShapesHaveCandidates()) {\n            // Should not happen often; fallback: drill all\n            for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) {\n                int c = cell_id(i,j,N);\n                if (known[c] == -1) drill_cell(c);\n            }\n        }\n\n        vector<int> oneAssign, unionCounts;\n        int found = 0;\n\n        while (true) {\n            if (opCount >= opLimit - 1) break; // reserve for answer\n            if (timer.elapsed() > timeLimitSec) break;\n\n            // Enumerate a limited set of solutions\n            enumerateSolutionsLimited(100, oneAssign, unionCounts, found);\n\n            if (found == 0) {\n                // No feasible solutions found within limit/time; drill a random cell to get more info\n                // Choose a cell not drilled with small chance of being covered (heuristic: minimal sum of potential coverage)\n                vector<int> candidateCells;\n                for (int c = 0; c < N*N; ++c) if (known[c] == -1) candidateCells.push_back(c);\n                if (candidateCells.empty()) break;\n                int bestC = candidateCells[rng() % candidateCells.size()];\n                // Simple heuristic: choose random if time low\n                drill_cell(bestC);\n                continue;\n            }\n\n            // Build best union from oneAssign\n            vector<uint8_t> baseUnion = buildUnionFromAssignment(oneAssign);\n\n            // Fast acceptance check: if unionCounts show unanimity across found solutions\n            bool unanimous = true;\n            for (int c = 0; c < N*N; ++c) {\n                if (known[c] == 0 && baseUnion[c] != 0) { unanimous = false; break; }\n                if (known[c] > 0 && baseUnion[c] != 1) { unanimous = false; break; }\n                if (unionCounts[c] != 0 && unionCounts[c] != found) {\n                    unanimous = false;\n                    break;\n                }\n            }\n            // Even if unanimity among sampled solutions, we still need a rigorous uniqueness check.\n            // Try to find any cell whose union can be flipped by a full DFS with target constraint.\n            int ambiguousCell = -1;\n            // We'll prioritize cells with unknown and near 50-50 in unionCounts; else scan all\n            vector<pair<int,int>> candidates; // (priority score, cell)\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) {\n                int cnt = unionCounts[c];\n                int score = found ? abs(found - 2*cnt) : 0; // lower score -> more ambiguous\n                candidates.emplace_back(score, c);\n            }\n            sort(candidates.begin(), candidates.end(),\n                 [&](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            bool alternativeFound = false;\n            // First try top-K ambiguous cells by sample (speed), then fallback to all unknown cells if needed\n            int K = min<int>(50, (int)candidates.size());\n            for (int idx = 0; idx < K; ++idx) {\n                int c = candidates[idx].second;\n                int want = baseUnion[c] ? 0 : 1;\n                if (existsAlternativeForCell(c, want)) {\n                    ambiguousCell = c;\n                    alternativeFound = true;\n                    break;\n                }\n                if (timer.elapsed() > timeLimitSec) break;\n            }\n            if (!alternativeFound) {\n                // Rigorous sweep over all unknown cells if time allows\n                for (int c = 0; c < N*N && !alternativeFound; ++c) {\n                    if (known[c] != -1) continue;\n                    int want = baseUnion[c] ? 0 : 1;\n                    if (existsAlternativeForCell(c, want)) {\n                        ambiguousCell = c;\n                        alternativeFound = true;\n                        break;\n                    }\n                    if (timer.elapsed() > timeLimitSec) break;\n                }\n            }\n\n            if (!alternativeFound) {\n                // Union is unique under current constraints\n                return baseUnion;\n            } else {\n                // Drill the ambiguous cell to disambiguate\n                drill_cell(ambiguousCell);\n                // loop continues\n            }\n        }\n\n        // Fallback: if time or ops budget low, drill remaining cells to guarantee correctness\n        for (int c = 0; c < N*N; ++c) {\n            if (opCount >= opLimit - 1) break;\n            if (known[c] == -1) drill_cell(c);\n        }\n        // Now union is simply v>0\n        vector<uint8_t> unionFinal(N*N, 0);\n        for (int c = 0; c < N*N; ++c) {\n            unionFinal[c] = (known[c] > 0) ? 1 : 0;\n        }\n        return unionFinal;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem prob;\n    if (!(cin >> prob.N >> prob.M >> prob.eps)) {\n        return 0;\n    }\n    prob.shapes.resize(prob.M);\n    for (int k = 0; k < prob.M; ++k) {\n        prob.shapes[k].id = k;\n        int d; cin >> d;\n        vector<pair<int,int>> offs;\n        offs.reserve(d);\n        int minI = INT_MAX, minJ = INT_MAX, maxI = INT_MIN, maxJ = INT_MIN;\n        for (int t = 0; t < d; ++t) {\n            int ii, jj; cin >> ii >> jj;\n            offs.emplace_back(ii, jj);\n            minI = min(minI, ii);\n            minJ = min(minJ, jj);\n            maxI = max(maxI, ii);\n            maxJ = max(maxJ, jj);\n        }\n        // Normalize offsets to start at 0? Already specified that min is 0, but ensure\n        for (auto &p : offs) {\n            p.first -= minI;\n            p.second -= minJ;\n        }\n        prob.shapes[k].offsets = offs;\n        prob.shapes[k].H = maxI - minI + 1;\n        prob.shapes[k].W = maxJ - minJ + 1;\n    }\n\n    // Precompute shifts for each shape and which cells they cover\n    for (int k = 0; k < prob.M; ++k) {\n        auto &S = prob.shapes[k];\n        int maxDI = prob.N - S.H;\n        int maxDJ = prob.N - S.W;\n        for (int di = 0; di <= maxDI; ++di) {\n            for (int dj = 0; dj <= maxDJ; ++dj) {\n                vector<int> cells;\n                cells.reserve(S.offsets.size());\n                for (auto [oi, oj] : S.offsets) {\n                    int i = di + oi;\n                    int j = dj + oj;\n                    cells.push_back(cell_id(i,j, prob.N));\n                }\n                sort(cells.begin(), cells.end());\n                S.shiftsCells.push_back(move(cells));\n            }\n        }\n        // Build coverShiftsByCell mapping\n        S.coverShiftsByCell.assign(prob.N*prob.N, {});\n        for (int p = 0; p < (int)S.shiftsCells.size(); ++p) {\n            for (int c : S.shiftsCells[p]) {\n                S.coverShiftsByCell[c].push_back(p);\n            }\n        }\n    }\n\n    State st(&prob);\n\n    // Solve union using the strategy\n    vector<uint8_t> unionSet = st.solveUnion();\n\n    // Build answer: cells with unionSet[c] == 1\n    vector<int> ans;\n    ans.reserve(st.N*st.N);\n    for (int c = 0; c < st.N*st.N; ++c) {\n        if (unionSet[c]) ans.push_back(c);\n    }\n\n    // Ensure inclusion of all drilled with v>0\n    for (int idx = 0; idx < (int)st.drilledCells.size(); ++idx) {\n        int c = st.drilledCells[idx];\n        if (st.known[c] > 0 && !unionSet[c]) {\n            // Force include it\n            ans.push_back(c);\n            unionSet[c] = 1;\n        }\n    }\n    // Deduplicate ans (if forced adds duplicates)\n    sort(ans.begin(), ans.end());\n    ans.erase(unique(ans.begin(), ans.end()), ans.end());\n\n    // Output answer\n    cout << \"a \" << ans.size();\n    for (int c : ans) {\n        auto [i,j] = cell_ij(c, st.N);\n        cout << \" \" << i << \" \" << j;\n    }\n    cout << \"\\n\";\n    cout.flush();\n    string resp;\n    if (!(cin >> resp)) return 0;\n    // If incorrect, we could try again, but we trust the method; end here.\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct MaxItem {\n    int s; // current shortage in area units (not multiplied by 100)\n    int i; // index\n    bool operator<(const MaxItem& o) const {\n        return s < o.s; // max-heap behavior\n    }\n};\nstruct MinItem {\n    int h; // current height\n    int i;\n    bool operator<(const MinItem& o) const {\n        if (h != o.h) return h > o.h; // min-heap behavior\n        return i > o.i;\n    }\n};\n\n// Arrange a multiset of heights to align boundaries with previous day's boundary rows as much as possible.\nstatic vector<int> arrange_align(const vector<int>& heights, const vector<int>& prev_bounds, int W) {\n    // Build multiset of heights\n    multiset<int> ms;\n    for (int h : heights) ms.insert(h);\n\n    vector<int> seq; seq.reserve(heights.size());\n    int pos = 0;\n\n    for (int b : prev_bounds) {\n        if (ms.empty()) break;\n        if (b <= pos) continue; // already passed this boundary\n        while (true) {\n            if (ms.empty()) break;\n            int delta = b - pos;\n            auto it_exact = ms.find(delta);\n            if (it_exact != ms.end()) {\n                // Place a segment exactly matching the gap => boundary matched\n                seq.push_back(delta);\n                pos += delta;\n                ms.erase(it_exact);\n                break;\n            } else {\n                // Place the smallest segment to creep towards the boundary\n                auto it_small = ms.begin();\n                int h0 = *it_small;\n                seq.push_back(h0);\n                pos += h0;\n                ms.erase(it_small);\n                if (pos >= b) {\n                    // boundary passed or matched (matched would have been caught via exact match above)\n                    break;\n                }\n            }\n        }\n    }\n    // Append remaining segments in ascending order\n    for (int h : ms) seq.push_back(h);\n\n    // Safety: ensure sum == W\n    // (By construction it should, but guard against pathological bugs.)\n    int sum = 0;\n    for (int h : seq) sum += h;\n    if (sum != W) {\n        // Adjust the last segment minimally to fix sum if off by a tiny rounding issue (shouldn't happen).\n        if (!seq.empty()) seq.back() += (W - sum);\n    }\n    return seq;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int W, D, N;\n    if (!(cin >> W >> D >> N)) return 0;\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> prev_bounds; // boundary rows used in previous day (prefix sums excluding W)\n    prev_bounds.clear();\n\n    for (int d = 0; d < D; d++) {\n        // 1) Compute per-day optimal stripe heights (full width) via greedy water-filling.\n        vector<int> k(N, 1); // heights (sum must be W)\n        int R = W - N;       // remaining height units to distribute\n        priority_queue<MaxItem> pq;\n        for (int i = 0; i < N; i++) {\n            int s = a[d][i] - W; // shortage after base height=1 (area=W)\n            if (s < 0) s = 0;\n            pq.push(MaxItem{s, i});\n        }\n        while (R > 0 && !pq.empty()) {\n            MaxItem cur = pq.top(); pq.pop();\n            if (cur.s <= 0) break; // no more benefit\n            k[cur.i] += 1;\n            cur.s -= W;\n            if (cur.s < 0) cur.s = 0;\n            pq.push(cur);\n            R--;\n        }\n        // If leftover height units remain (all shortages eliminated), distribute evenly to smallest heights.\n        if (R > 0) {\n            priority_queue<MinItem> minpq;\n            for (int i = 0; i < N; i++) minpq.push(MinItem{k[i], i});\n            while (R > 0) {\n                auto cur = minpq.top(); minpq.pop();\n                cur.h += 1;\n                k[cur.i] = cur.h;\n                minpq.push(cur);\n                R--;\n            }\n        }\n\n        // 2) Reorder stripes to align with previous day's boundaries to reduce L_d.\n        // Build the multiset of heights and arrange to match as many previous boundaries as possible.\n        // prev_bounds are sorted in increasing order by construction.\n        vector<int> heights = k; // multiset as vector\n        vector<int> seq = arrange_align(heights, prev_bounds, W);\n\n        // 3) Build rectangles according to seq (stack top to bottom). Each is full width [0,W).\n        int cur_i = 0;\n        vector<array<int,4>> rect_by_seq; rect_by_seq.reserve(N);\n        for (int t = 0; t < N; t++) {\n            int h = seq[t];\n            int i0 = cur_i;\n            int i1 = cur_i + h;\n            rect_by_seq.push_back({i0, 0, i1, W});\n            cur_i = i1;\n        }\n        // Sanity\n        if (cur_i != W && !rect_by_seq.empty()) {\n            rect_by_seq.back()[2] += (W - cur_i);\n        }\n\n        // 4) Assign rectangles to reservations to minimize deficiency: pair sorted areas (heights) with sorted demands.\n        // Build indices of stripes sorted by height ascending.\n        vector<pair<int,int>> height_with_idx; height_with_idx.reserve(N);\n        {\n            int pos = 0;\n            for (int t = 0; t < N; t++) {\n                height_with_idx.emplace_back(seq[t], t);\n            }\n            sort(height_with_idx.begin(), height_with_idx.end()); // ascending by height\n        }\n        // Output rectangles in reservation order (a[d] already sorted ascending).\n        for (int kidx = 0; kidx < N; kidx++) {\n            int stripe_idx = height_with_idx[kidx].second;\n            auto &r = rect_by_seq[stripe_idx];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << '\\n';\n        }\n\n        // 5) Prepare prev_bounds for next day: prefix sums of seq excluding the last (W).\n        prev_bounds.clear();\n        {\n            int ps = 0;\n            for (int t = 0; t < N - 1; t++) {\n                ps += seq[t];\n                prev_bounds.push_back(ps);\n            }\n            // ensure sorted (they are increasing)\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic const ll MOD = 998244353LL;\n\n// Fast cell gain given current remainder rcur and addition sval\ninline ll cell_gain(ll rcur, int sval) {\n    // Wrap occurs iff rcur + sval >= MOD <=> sval >= MOD - rcur\n    return ((ll)sval >= (MOD - rcur)) ? ((ll)sval - MOD) : (ll)sval;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    if (!(cin >> N >> M >> K)) return 0;\n\n    const int SZ = N * N; // 81\n    vector<ll> r(SZ);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            ll x; cin >> x;\n            r[i * N + j] = x;\n        }\n    }\n\n    // Read M stamps, each 3x3\n    vector<array<int, 9>> stamp(M);\n    vector<ll> stampSum(M, 0);\n    for (int m = 0; m < M; ++m) {\n        ll ssum = 0;\n        for (int u = 0; u < 3; ++u) {\n            for (int v = 0; v < 3; ++v) {\n                int x; cin >> x;\n                stamp[m][u * 3 + v] = x;\n                ssum += x;\n            }\n        }\n        stampSum[m] = ssum;\n    }\n\n    const int P = N - 2;           // 7 positions per dimension\n    const int POS_CNT = P * P;     // 49\n    const int OPS = M * POS_CNT;   // 980\n\n    // Mapping pos index <-> (p,q)\n    vector<int> pos_p(POS_CNT), pos_q(POS_CNT);\n    for (int p = 0, idx = 0; p < P; ++p) {\n        for (int q = 0; q < P; ++q, ++idx) {\n            pos_p[idx] = p;\n            pos_q[idx] = q;\n        }\n    }\n\n    // Precompute operations: for each op, store cells (size 9) and s values (size 9)\n    vector<array<int, 9>> op_cells(OPS);\n    vector<array<int, 9>> op_svals(OPS);\n    vector<int> op_m(OPS), op_p(OPS), op_q(OPS);\n    for (int m = 0; m < M; ++m) {\n        for (int pos = 0; pos < POS_CNT; ++pos) {\n            int p = pos_p[pos], q = pos_q[pos];\n            int op = m * POS_CNT + pos;\n            op_m[op] = m;\n            op_p[op] = p;\n            op_q[op] = q;\n            for (int u = 0; u < 3; ++u) {\n                for (int v = 0; v < 3; ++v) {\n                    int k = u * 3 + v;\n                    int i = p + u, j = q + v;\n                    int cell = i * N + j; // 0..80\n                    op_cells[op][k] = cell;\n                    op_svals[op][k] = stamp[m][k];\n                }\n            }\n        }\n    }\n\n    // Precompute overlap operations list for each op:\n    // op1(m,p,q) overlaps any op2(m2, p2,q2) where |p2-p|<=2 and |q2-q|<=2 (since each op covers 3x3)\n    vector<vector<int>> overlOps(OPS);\n    overlOps.assign(OPS, {});\n    for (int op = 0; op < OPS; ++op) {\n        int p = op_p[op];\n        int q = op_q[op];\n        overlOps[op].reserve(25 * M);\n        for (int dp = -2; dp <= 2; ++dp) {\n            int p2 = p + dp;\n            if (p2 < 0 || p2 >= P) continue;\n            for (int dq = -2; dq <= 2; ++dq) {\n                int q2 = q + dq;\n                if (q2 < 0 || q2 >= P) continue;\n                int pos2 = p2 * P + q2;\n                for (int m2 = 0; m2 < M; ++m2) {\n                    int op2 = m2 * POS_CNT + pos2;\n                    overlOps[op].push_back(op2);\n                }\n            }\n        }\n    }\n\n    // Compute all op gains from scratch for current r\n    vector<ll> gain(OPS, 0);\n    auto recompute_all_gains = [&](){\n        for (int op = 0; op < OPS; ++op) {\n            ll sum = 0;\n            const auto &cells = op_cells[op];\n            const auto &svals = op_svals[op];\n            // Unroll small loop for speed\n            sum += cell_gain(r[cells[0]], svals[0]);\n            sum += cell_gain(r[cells[1]], svals[1]);\n            sum += cell_gain(r[cells[2]], svals[2]);\n            sum += cell_gain(r[cells[3]], svals[3]);\n            sum += cell_gain(r[cells[4]], svals[4]);\n            sum += cell_gain(r[cells[5]], svals[5]);\n            sum += cell_gain(r[cells[6]], svals[6]);\n            sum += cell_gain(r[cells[7]], svals[7]);\n            sum += cell_gain(r[cells[8]], svals[8]);\n            gain[op] = sum;\n        }\n    };\n\n    recompute_all_gains();\n\n    // Prepare helper arrays for hypothetical remainder updates\n    vector<ll> tmpR(SZ, 0);\n    vector<int> tmpRMark(SZ, 0);\n    int tmpRTag = 1;\n\n    vector<int> overlapMark(OPS, 0);\n    int overlapTag = 1;\n\n    vector<tuple<int,int,int>> answer; // (m,p,q)\n\n    // Main loop: up to K presses\n    for (int step = 0; step < K; ++step) {\n        // Build sorted order of ops by current gain, descending\n        vector<int> order(OPS);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b){\n            if (gain[a] != gain[b]) return gain[a] > gain[b];\n            return a < b;\n        });\n\n        // Candidate size: consider top T even if negative\n        int T = 128;\n        if (T > OPS) T = OPS;\n\n        ll bestCombined = LLONG_MIN;\n        ll bestG1 = LLONG_MIN;\n        int bestOp = -1;\n\n        for (int idx = 0; idx < T; ++idx) {\n            int op1 = order[idx];\n            ll g1 = gain[op1];\n\n            // Mark overlapped operations for op1\n            ++overlapTag;\n            for (int t : overlOps[op1]) overlapMark[t] = overlapTag;\n\n            // Best unaffected op2: scan sorted order to find first not overlapped\n            ll bestUn = 0;\n            for (int id2 = 0; id2 < OPS; ++id2) {\n                int cand = order[id2];\n                if (overlapMark[cand] != overlapTag) {\n                    ll g2 = gain[cand];\n                    if (g2 > bestUn) bestUn = g2;\n                    break; // first is best due to sorting\n                }\n            }\n\n            // Hypothetical remainders after applying op1\n            ++tmpRTag;\n            const auto &cells1 = op_cells[op1];\n            const auto &svals1 = op_svals[op1];\n            for (int k = 0; k < 9; ++k) {\n                int c = cells1[k];\n                ll nr = r[c] + (ll)svals1[k];\n                if (nr >= MOD) nr -= MOD;\n                tmpR[c] = nr;\n                tmpRMark[c] = tmpRTag;\n            }\n\n            // Best overlapped op2 under r'\n            ll bestOv = LLONG_MIN;\n            for (int t : overlOps[op1]) {\n                ll sum = 0;\n                const auto &cells = op_cells[t];\n                const auto &svals = op_svals[t];\n                // Compute with hypothetical remainders where needed\n                // Unrolled loop\n                {\n                    ll rr = (tmpRMark[cells[0]] == tmpRTag) ? tmpR[cells[0]] : r[cells[0]];\n                    sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                }\n                {\n                    ll rr = (tmpRMark[cells[1]] == tmpRTag) ? tmpR[cells[1]] : r[cells[1]];\n                    sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                }\n                {\n                    ll rr = (tmpRMark[cells[2]] == tmpRTag) ? tmpR[cells[2]] : r[cells[2]];\n                    sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                }\n                {\n                    ll rr = (tmpRMark[cells[3]] == tmpRTag) ? tmpR[cells[3]] : r[cells[3]];\n                    sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                }\n                {\n                    ll rr = (tmpRMark[cells[4]] == tmpRTag) ? tmpR[cells[4]] : r[cells[4]];\n                    sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                }\n                {\n                    ll rr = (tmpRMark[cells[5]] == tmpRTag) ? tmpR[cells[5]] : r[cells[5]];\n                    sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                }\n                {\n                    ll rr = (tmpRMark[cells[6]] == tmpRTag) ? tmpR[cells[6]] : r[cells[6]];\n                    sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                }\n                {\n                    ll rr = (tmpRMark[cells[7]] == tmpRTag) ? tmpR[cells[7]] : r[cells[7]];\n                    sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                }\n                {\n                    ll rr = (tmpRMark[cells[8]] == tmpRTag) ? tmpR[cells[8]] : r[cells[8]];\n                    sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n                }\n                if (sum > bestOv) bestOv = sum;\n            }\n\n            ll best2 = bestUn;\n            if (bestOv > best2) best2 = bestOv;\n            if (best2 < 0) best2 = 0;\n\n            ll combined = g1 + best2;\n\n            if (combined > bestCombined || (combined == bestCombined && g1 > bestG1)) {\n                bestCombined = combined;\n                bestG1 = g1;\n                bestOp = op1;\n            }\n        }\n\n        if (bestOp == -1) break;\n        if (bestCombined <= 0) break; // no beneficial move (even with 2-step estimate)\n\n        // Apply bestOp to the actual board\n        int msel = op_m[bestOp];\n        int psel = op_p[bestOp];\n        int qsel = op_q[bestOp];\n        answer.emplace_back(msel, psel, qsel);\n\n        const auto &cellsBest = op_cells[bestOp];\n        const auto &svalsBest = op_svals[bestOp];\n        for (int k = 0; k < 9; ++k) {\n            int c = cellsBest[k];\n            ll nr = r[c] + (ll)svalsBest[k];\n            if (nr >= MOD) nr -= MOD;\n            r[c] = nr;\n        }\n\n        // Recompute all gains from scratch (fast enough for 980 ops)\n        recompute_all_gains();\n    }\n\n    // Output\n    cout << (int)answer.size() << '\\n';\n    for (auto &t : answer) {\n        int m, p, q;\n        tie(m, p, q) = t;\n        cout << m << ' ' << p << ' ' << q << '\\n';\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 5;\n    static constexpr int TOT = N * N;\n\n    int A[N][N];\n\n    // Grid occupancy: -1 for empty, otherwise container id\n    int occ[N][N];\n\n    // Spawn pointers per receiving row (col = 0)\n    int spawnIdx[N];\n\n    // Large crane state\n    int br = 0, bc = 0; // position\n    int hold = -1;      // container id held or -1\n\n    // Output strings\n    vector<string> S;\n\n    // Delivered tracking (only to know when done)\n    bool delivered[TOT];\n    int deliveredCount = 0;\n\n    Solver() {\n        memset(occ, -1, sizeof(occ));\n        memset(spawnIdx, 0, sizeof(spawnIdx));\n        memset(delivered, 0, sizeof(delivered));\n        S.assign(N, \"\");\n    }\n\n    void readInput() {\n        int n;\n        if (!(cin >> n)) exit(0); // N is always 5\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) cin >> A[i][j];\n        }\n    }\n\n    // Step 1: Spawn if possible at receiving gates (col 0)\n    void step1_spawn() {\n        for (int i = 0; i < N; i++) {\n            if (spawnIdx[i] >= N) continue; // no more to spawn for this row\n            if (occ[i][0] == -1) {\n                // Spawn is blocked only if a crane holding a container is at that gate\n                if (!(br == i && bc == 0 && hold != -1)) {\n                    int id = A[i][spawnIdx[i]];\n                    occ[i][0] = id;\n                    spawnIdx[i]++;\n                }\n            }\n        }\n    }\n\n    // Step 3: Dispatch at gates (col 4)\n    void step3_dispatch() {\n        for (int i = 0; i < N; i++) {\n            if (occ[i][4] != -1) {\n                int id = occ[i][4];\n                occ[i][4] = -1;\n                if (!delivered[id]) {\n                    delivered[id] = true;\n                    deliveredCount++;\n                }\n            }\n        }\n    }\n\n    // Find nearest container cell from (br, bc)\n    bool findNearestContainer(int &tr, int &tc) {\n        int bestD = INT_MAX;\n        int br0 = br, bc0 = bc;\n        bool found = false;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                if (occ[r][c] != -1) {\n                    int d = abs(r - br0) + abs(c - bc0);\n                    if (d < bestD || (d == bestD && (r < tr || (r == tr && c < tc)))) {\n                        bestD = d;\n                        tr = r; tc = c;\n                        found = true;\n                    }\n                }\n            }\n        }\n        return found;\n    }\n\n    char stepToward(int tr, int tc) {\n        if (br < tr) return 'D';\n        if (br > tr) return 'U';\n        if (bc < tc) return 'R';\n        if (bc > tc) return 'L';\n        return '.'; // already there\n    }\n\n    // Decide the large crane's action\n    char decideAction() {\n        if (hold != -1) {\n            int dr = hold / N;\n            int dc = N - 1; // 4\n            if (br == dr && bc == dc) {\n                // Drop if empty\n                if (occ[br][bc] == -1) return 'Q';\n                // Should not happen since gates dispatch at end of previous turn,\n                // but if occupied, wait.\n                return '.';\n            } else {\n                return stepToward(dr, dc);\n            }\n        } else {\n            // Not holding\n            if (occ[br][bc] != -1) {\n                // Pick immediately\n                return 'P';\n            } else {\n                // Move towards nearest container\n                int tr = -1, tc = -1;\n                if (findNearestContainer(tr, tc)) {\n                    if (br == tr && bc == tc) {\n                        // Just in case: pick now\n                        return 'P';\n                    } else {\n                        return stepToward(tr, tc);\n                    }\n                } else {\n                    // No containers on grid (may still have pending spawns), wait\n                    return '.';\n                }\n            }\n        }\n    }\n\n    // Apply the big crane action to our simulation state\n    void applyBigAction(char act) {\n        if (act == 'U') br--;\n        else if (act == 'D') br++;\n        else if (act == 'L') bc--;\n        else if (act == 'R') bc++;\n        else if (act == 'P') {\n            // Pick: must be valid in our generation\n            if (hold == -1 && occ[br][bc] != -1) {\n                hold = occ[br][bc];\n                occ[br][bc] = -1;\n            }\n        } else if (act == 'Q') {\n            // Drop: must be valid in our generation\n            if (hold != -1 && occ[br][bc] == -1) {\n                occ[br][bc] = hold;\n                hold = -1;\n            }\n        }\n        // '.' and 'B' not used for big\n    }\n\n    void run() {\n        const int MAX_TURNS = 10000;\n        for (int t = 0; t < MAX_TURNS; t++) {\n            // Step 1: spawn\n            step1_spawn();\n\n            // Step 2: actions\n            char bigAct = decideAction();\n\n            // Record outputs\n            S[0].push_back(bigAct);\n            for (int i = 1; i < N; i++) {\n                // Bomb small cranes at t=0, then idle\n                if (t == 0) S[i].push_back('B');\n                else S[i].push_back('.');\n            }\n\n            // Apply big action to state\n            applyBigAction(bigAct);\n\n            // Step 3: dispatch\n            step3_dispatch();\n\n            if (deliveredCount >= TOT) break;\n        }\n\n        // Pad strings to equal length\n        size_t L = 0;\n        for (int i = 0; i < N; i++) L = max(L, S[i].size());\n        for (int i = 0; i < N; i++) {\n            if (S[i].size() < L) S[i].append(L - S[i].size(), '.');\n        }\n    }\n\n    void output() {\n        for (int i = 0; i < N; i++) cout << S[i] << \"\\n\";\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.run();\n    solver.output();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Utilities\nstatic inline int id(int N, int r, int c){ return r*N + c; }\nstatic inline pair<int,int> rc(int N, int v){ return {v / N, v % N}; }\n\n// Build a Hamiltonian cycle on an even N x N grid by merging 2x2 cycles.\nstatic vector<pair<int,int>> build_cycle_evenN(int N){\n    const int M = N * N;\n    // Each vertex has degree 2 in the final cycle. We'll store up to 2 neighbors.\n    vector<array<int,2>> nb(M, array<int,2>{-1,-1});\n    auto add_edge = [&](int u, int v){\n        // add v to u\n        if(nb[u][0] == -1) nb[u][0] = v;\n        else if(nb[u][1] == -1) nb[u][1] = v;\n        else {\n            // Should not happen\n            // cerr << \"deg overflow at \" << u << endl;\n        }\n        // add u to v\n        if(nb[v][0] == -1) nb[v][0] = u;\n        else if(nb[v][1] == -1) nb[v][1] = u;\n        else {\n            // Should not happen\n            // cerr << \"deg overflow at \" << v << endl;\n        }\n    };\n    auto remove_edge = [&](int u, int v){\n        if(nb[u][0] == v) nb[u][0] = -1;\n        else if(nb[u][1] == v) nb[u][1] = -1;\n        else {\n            // edge not found; shouldn't happen\n        }\n        if(nb[v][0] == u) nb[v][0] = -1;\n        else if(nb[v][1] == u) nb[v][1] = -1;\n        else {\n            // edge not found; shouldn't happen\n        }\n    };\n\n    int Br = N/2, Bc = N/2;\n    // Initial disjoint 2x2 cycles\n    for(int br=0; br<Br; ++br){\n        for(int bc=0; bc<Bc; ++bc){\n            int x = 2*br, y = 2*bc;\n            int a = id(N, x, y);\n            int b = id(N, x, y+1);\n            int c = id(N, x+1, y+1);\n            int d = id(N, x+1, y);\n            add_edge(a, b);\n            add_edge(b, c);\n            add_edge(c, d);\n            add_edge(d, a);\n        }\n    }\n    // Merge horizontally within each block row\n    for(int br=0; br<Br; ++br){\n        for(int bc=0; bc<Bc-1; ++bc){\n            int x0 = 2*br;\n            int y1 = 2*bc+1;\n            int y2 = 2*bc+2;\n            int a = id(N, x0,   y1);\n            int b = id(N, x0+1, y1);\n            int c = id(N, x0,   y2);\n            int d = id(N, x0+1, y2);\n            // Remove vertical edges inside the two 2x2s, add horizontal across their seam.\n            remove_edge(a, b);\n            remove_edge(c, d);\n            add_edge(a, c);\n            add_edge(b, d);\n        }\n    }\n    // Merge vertically between neighboring block rows\n    for(int br=0; br<Br-1; ++br){\n        int r1 = 2*br+1;\n        int r2 = 2*br+2;\n        int a = id(N, r1, 0);\n        int b = id(N, r1, 1);\n        int c = id(N, r2, 0);\n        int d = id(N, r2, 1);\n        // Remove horizontal edges on these rows between columns 0 and 1, add vertical cross edges.\n        remove_edge(a, b);\n        remove_edge(c, d);\n        add_edge(a, c);\n        add_edge(b, d);\n    }\n    // Traverse the unique cycle\n    vector<pair<int,int>> path;\n    path.reserve(M);\n    int start = id(N, 0, 0);\n    int cur = start;\n    int prev = -1;\n    for(int cnt=0; cnt<M; ++cnt){\n        auto [r, c] = rc(N, cur);\n        path.emplace_back(r, c);\n        int n0 = nb[cur][0], n1 = nb[cur][1];\n        int nxt = (n0 == prev ? n1 : n0);\n        prev = cur;\n        cur = nxt;\n    }\n    // It's a cycle; cur should return to start after M steps.\n    return path;\n}\n\n// Build standard row-snake path (not a cycle)\nstatic vector<pair<int,int>> build_row_snake(int N){\n    vector<pair<int,int>> path;\n    path.reserve(N*N);\n    for(int i=0;i<N;i++){\n        if(i%2==0) for(int j=0;j<N;j++) path.emplace_back(i,j);\n        else for(int j=N-1;j>=0;j--) path.emplace_back(i,j);\n    }\n    return path;\n}\n// Build standard column-snake path (not a cycle)\nstatic vector<pair<int,int>> build_col_snake(int N){\n    vector<pair<int,int>> path;\n    path.reserve(N*N);\n    for(int j=0;j<N;j++){\n        if(j%2==0) for(int i=0;i<N;i++) path.emplace_back(i,j);\n        else for(int i=N-1;i>=0;i--) path.emplace_back(i,j);\n    }\n    return path;\n}\n\n// Rotate path by rot = 0,1,2,3 (0: identity, 1: 90deg CW, 2: 180, 3: 270)\nstatic vector<pair<int,int>> rotate_path(const vector<pair<int,int>>& path, int N, int rot){\n    vector<pair<int,int>> res;\n    res.reserve(path.size());\n    for(auto [r,c] : path){\n        int nr=r, nc=c;\n        if(rot==1){ nr = c; nc = N-1 - r; }\n        else if(rot==2){ nr = N-1 - r; nc = N-1 - c; }\n        else if(rot==3){ nr = N-1 - c; nc = r; }\n        res.emplace_back(nr,nc);\n    }\n    return res;\n}\n\n// Evaluate a path and pick the best valid rotation start with exact wrap handling for non-cycles.\nstruct BestPick {\n    long long estCost = (1LL<<62);\n    int startIndex = 0;\n    int pathIdx = -1;\n};\n\nstatic BestPick evaluate_over_paths(const vector<vector<pair<int,int>>>& paths,\n                                    const vector<vector<int>>& h, long long base)\n{\n    int N = (int)h.size();\n    int M = N*N;\n    BestPick best;\n    for(int pid=0; pid<(int)paths.size(); ++pid){\n        const auto& pos = paths[pid];\n        // Extract arr along path\n        vector<long long> arr(M);\n        for(int k=0;k<M;k++){\n            auto [x,y] = pos[k];\n            arr[k] = h[x][y];\n        }\n        // Build pre2 over duplicated array length 2M+1\n        vector<long long> pre2(2*M+1, 0);\n        for(int i=0;i<2*M;i++){\n            pre2[i+1] = pre2[i] + arr[i%M];\n        }\n        // Prefix of pre2 for range sum of pre2\n        vector<long long> prefpre2(2*M+1, 0);\n        for(int i=1;i<=2*M;i++){\n            prefpre2[i] = prefpre2[i-1] + pre2[i-1];\n        }\n        // Valid start indices are those where pre2[s] is global minimum over s in [0..M-1]\n        long long minVal = LLONG_MAX;\n        for(int i=0;i<M;i++) minVal = min(minVal, pre2[i]);\n        vector<int> starts;\n        for(int s=0;s<M;s++){\n            if(pre2[s] == minVal) starts.push_back(s);\n        }\n        // Precompute wrap distance for this path (distance between last and first)\n        auto [xlast, ylast] = pos[M-1];\n        auto [xfirst, yfirst] = pos[0];\n        int wrapDist = abs(xlast - xfirst) + abs(ylast - yfirst);\n\n        // Evaluate each valid start\n        for(int s : starts){\n            // Sum of load along moves (without wrap penalty)\n            long long sumPre2Range = prefpre2[s+M] - prefpre2[s+1]; // pre2[s+1..s+M-1]\n            long long dsum = sumPre2Range - 1LL*(M-1)*pre2[s];\n\n            // Moves: along path edges (M-1), plus reposition from (0,0) to start,\n            // plus extra moves if wrapDist>1 and s!=0 (we will need to jump across the wrap once)\n            int sx = pos[s].first, sy = pos[s].second;\n            int repositionDist = abs(sx) + abs(sy);\n\n            long long extraWrapMoves = 0;\n            long long extraWrapLoad = 0;\n            if(s != 0 && wrapDist > 1){\n                // Load carried during wrap is L = -pre2[s] (>= 0)\n                long long L = -pre2[s];\n                extraWrapMoves = (wrapDist - 1);\n                extraWrapLoad = extraWrapMoves * L;\n            }\n            long long moveCost = 100LL * ((M-1) + repositionDist + extraWrapMoves);\n            long long est = base + moveCost + dsum + extraWrapLoad;\n\n            if(est < best.estCost){\n                best.estCost = est;\n                best.startIndex = s;\n                best.pathIdx = pid;\n            }\n        }\n    }\n    return best;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if(!(cin>>N)) return 0;\n    vector<vector<int>> h(N, vector<int>(N));\n    long long base = 0;\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            cin>>h[i][j];\n            base += llabs((long long)h[i][j]);\n        }\n    }\n\n    // Build candidate paths\n    vector<vector<pair<int,int>>> paths;\n    // Primary: robust Hamiltonian cycles (rotations and reverses)\n    auto cyc0 = build_cycle_evenN(N);\n    for(int rot=0; rot<4; ++rot){\n        auto p = rotate_path(cyc0, N, rot);\n        paths.push_back(p);                    // cycle variant\n        vector<pair<int,int>> pr = p;\n        reverse(pr.begin(), pr.end());        // reversed cycle\n        paths.push_back(pr);\n    }\n    // Optionally keep snakes as extra candidates (now correctly penalized if rotated)\n    auto row_snake = build_row_snake(N);\n    auto row_rev = row_snake; reverse(row_rev.begin(), row_rev.end());\n    auto col_snake = build_col_snake(N);\n    auto col_rev = col_snake; reverse(col_rev.begin(), col_rev.end());\n    paths.push_back(row_snake);\n    paths.push_back(row_rev);\n    paths.push_back(col_snake);\n    paths.push_back(col_rev);\n\n    // Pick best path and start index\n    BestPick pick = evaluate_over_paths(paths, h, base);\n    if(pick.pathIdx < 0){\n        // Fallback: trivial row snake start at 0\n        pick.pathIdx = 0;\n        pick.startIndex = 0;\n    }\n    const auto& path = paths[pick.pathIdx];\n    int M = N*N;\n    int s = pick.startIndex;\n\n    // Prepare operation output\n    vector<string> ops;\n    ops.reserve(M*3 + 100);\n\n    int cx = 0, cy = 0;\n    long long load = 0;\n\n    auto move_to = [&](int tx, int ty){\n        // Move horizontally then vertically (any Manhattan shortest path)\n        while(cy < ty){ ops.emplace_back(\"R\"); cy++; }\n        while(cy > ty){ ops.emplace_back(\"L\"); cy--; }\n        while(cx < tx){ ops.emplace_back(\"D\"); cx++; }\n        while(cx > tx){ ops.emplace_back(\"U\"); cx--; }\n    };\n\n    // Reposition to start\n    int sx = path[s].first, sy = path[s].second;\n    move_to(sx, sy);\n\n    // Traverse the path from s\n    for(int t=0; t<M; ++t){\n        int idx = (s + t) % M;\n        int x = path[idx].first, y = path[idx].second;\n        int val = h[x][y];\n        if(val > 0){\n            ops.emplace_back(\"+\" + to_string(val));\n            load += val;\n            h[x][y] = 0;\n        }else if(val < 0){\n            int need = -val;\n            // Should have enough load due to start choice; but keep safe.\n            int give = (int)min<long long>(need, load);\n            if(give > 0){\n                ops.emplace_back(\"-\" + to_string(give));\n                load -= give;\n                h[x][y] += give;\n            }\n            if(h[x][y] < 0){\n                // If any deficit remains (shouldn't), fix it later; but we'll avoid this via start selection.\n                int rem = -h[x][y];\n                // No-op here; ideally shouldn't happen.\n            }\n        }\n        // Move to next unless last\n        if(t != M-1){\n            int nx = path[(idx+1)%M].first, ny = path[(idx+1)%M].second;\n            // If adjacent, single step; else Manhattan (wrap jump for snake paths if s>0)\n            if(nx == x && (ny == y+1 || ny == y-1)){\n                if(ny == y+1){ ops.emplace_back(\"R\"); cy++; }\n                else { ops.emplace_back(\"L\"); cy--; }\n            }else if(ny == y && (nx == x+1 || nx == x-1)){\n                if(nx == x+1){ ops.emplace_back(\"D\"); cx++; }\n                else { ops.emplace_back(\"U\"); cx--; }\n            }else{\n                // Non-adjacent: Manhattan path\n                move_to(nx, ny);\n            }\n        }\n    }\n\n    // Output operations\n    for(const auto& s : ops) cout << s << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Heuristic for AHC035 \"Grain\" with hub-focused propagation and coverage-aware selection.\n\nstruct RNG {\n    uint64_t x;\n    RNG() {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        x = seed ^ (seed << 13);\n    }\n    inline uint32_t next_u32() {\n        uint64_t y = x;\n        y ^= (y << 7);\n        y ^= (y >> 9);\n        x = y;\n        return (uint32_t)(y & 0xffffffffu);\n    }\n    inline int randint(int lo, int hi) { // inclusive\n        uint32_t r = next_u32();\n        return lo + (int)(r % (uint32_t)(hi - lo + 1));\n    }\n    inline double rand01() {\n        return (next_u32() / 4294967296.0);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    if (!(cin >> N >> M >> T)) return 0;\n    const int SEED_COUNT = 2 * N * (N - 1); // 60 for N=6\n\n    vector<vector<int>> X(SEED_COUNT, vector<int>(M, 0));\n    for (int i = 0; i < SEED_COUNT; i++) {\n        for (int j = 0; j < M; j++) cin >> X[i][j];\n    }\n\n    // Initial per-dimension maxima (upper bound; cannot increase due to crossover definition)\n    vector<int> Xmax(M, 0);\n    for (int l = 0; l < M; l++) {\n        int mx = 0;\n        for (int k = 0; k < SEED_COUNT; k++) mx = max(mx, X[k][l]);\n        Xmax[l] = mx;\n    }\n\n    // Grid topology\n    auto pos_id = [&](int i, int j){ return i * N + j; };\n    vector<vector<int>> neighbors(N*N);\n    vector<int> deg(N*N, 0);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int u = pos_id(i,j);\n        if (i > 0)   neighbors[u].push_back(pos_id(i-1,j));\n        if (i+1 < N) neighbors[u].push_back(pos_id(i+1,j));\n        if (j > 0)   neighbors[u].push_back(pos_id(i,j-1));\n        if (j+1 < N) neighbors[u].push_back(pos_id(i,j+1));\n        deg[u] = (int)neighbors[u].size();\n    }\n    // Undirected edges list\n    vector<pair<int,int>> edges;\n    {\n        vector<char> vis(N*N, 0);\n        for (int u = 0; u < N*N; u++) {\n            for (int v: neighbors[u]) if (u < v) edges.emplace_back(u,v);\n        }\n    }\n\n    // Position order: higher degree first, then closer to center\n    vector<int> posOrder(N*N);\n    iota(posOrder.begin(), posOrder.end(), 0);\n    const double ci = (N-1)/2.0, cj = (N-1)/2.0;\n    sort(posOrder.begin(), posOrder.end(), [&](int a, int b){\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        int ai = a / N, aj = a % N;\n        int bi = b / N, bj = b % N;\n        double da = fabs(ai - ci) + fabs(aj - cj);\n        double db = fabs(bi - ci) + fabs(bj - cj);\n        if (da != db) return da < db;\n        return a < b;\n    });\n\n    // Center position (choose one of the four for even N; we use (N/2-1, N/2-1))\n    int centerPos = pos_id(N/2 - 1, N/2 - 1);\n\n    RNG rng;\n\n    struct NodePairParams {\n        double wV, wRare, wCnt;\n        double pairFactor;\n        double pairBoth, pairOne;\n        double hubOne;       // extra pair reward for champion incident edge and missing dims\n        double hubNodeBoost; // extra node reward for covering champion's missing dims\n    };\n    auto paramsForTurn = [&](int t)->NodePairParams{\n        if (t <= 3) {\n            return NodePairParams{\n                0.14, 100.0, 20.0,\n                240.0,\n                2.7, 1.35,\n                5.0,\n                4.0\n            };\n        } else if (t <= 6) {\n            return NodePairParams{\n                0.18, 85.0, 18.0,\n                220.0,\n                2.4, 1.1,\n                4.0,\n                3.5\n            };\n        } else {\n            return NodePairParams{\n                0.22, 75.0, 16.0,\n                200.0,\n                2.1, 1.0,\n                3.0,\n                3.0\n            };\n        }\n    };\n    struct GreedySelParams {\n        int targetBase;\n        double wVfill;\n        double wMissingPref;\n    };\n    auto greedyParamsForTurn = [&](int t)->GreedySelParams{\n        if (t <= 3) return GreedySelParams{3, 0.010, 120.0};\n        if (t <= 6) return GreedySelParams{2, 0.014, 100.0};\n        return GreedySelParams{2, 0.018, 80.0};\n    };\n\n    for (int t = 0; t < T; t++) {\n        // Compute V, carrier masks, counts\n        vector<int> V(SEED_COUNT, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            int s = 0;\n            for (int l = 0; l < M; l++) s += X[k][l];\n            V[k] = s;\n        }\n        vector<uint16_t> bits(SEED_COUNT, 0);\n        vector<int> cntAll(M, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            uint16_t m = 0;\n            for (int l = 0; l < M; l++) if (X[k][l] == Xmax[l]) {\n                m |= (1u << l);\n            }\n            bits[k] = m;\n            for (int l = 0; l < M; l++) if ((m >> l) & 1u) cntAll[l]++;\n        }\n        uint16_t dimsAvailMask = 0;\n        for (int l = 0; l < M; l++) if (cntAll[l] > 0) dimsAvailMask |= (1u << l);\n\n        // Per-dimension rarity weights\n        vector<double> wdim(M, 0.0);\n        for (int l = 0; l < M; l++) wdim[l] = (cntAll[l] ? (1.0 / (double)cntAll[l]) : 0.0);\n\n        // Precompute sumW over all masks\n        int MASKSZ = 1 << M;\n        vector<double> sumW(MASKSZ, 0.0);\n        for (int m = 1; m < MASKSZ; m++) {\n            int lb = __builtin_ctz(m);\n            int prev = m & (m - 1);\n            sumW[m] = sumW[prev] + wdim[lb];\n        }\n\n        // Rare sum and carrier count per seed\n        vector<double> rareSum(SEED_COUNT, 0.0);\n        vector<int> carrierCnt(SEED_COUNT, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            rareSum[k] = sumW[bits[k]];\n            carrierCnt[k] = __builtin_popcount((unsigned)bits[k]);\n        }\n\n        // Choose champion (hub): prioritize V and many rare max genes\n        int champion = 0;\n        double bestChampScore = -1e100;\n        for (int k = 0; k < SEED_COUNT; k++) {\n            double sc = V[k] + 180.0 * rareSum[k]; // weight for rare genes\n            if (sc > bestChampScore) {\n                bestChampScore = sc;\n                champion = k;\n            }\n        }\n        uint16_t champMask = bits[champion];\n        uint16_t missMask = (uint16_t)(dimsAvailMask & (~champMask)) & (uint16_t)((1u<<M)-1);\n\n        // Selection: ensure at least one carrier per dimension, include champion, then greedy fill\n        vector<int> selected;\n        vector<char> used(SEED_COUNT, 0);\n        selected.reserve(N*N);\n\n        auto include = [&](int k){\n            if (!used[k]) {\n                used[k] = 1;\n                selected.push_back(k);\n            }\n        };\n\n        // Force include one top carrier per dimension (by V)\n        for (int l = 0; l < M; l++) {\n            if (cntAll[l] == 0) continue;\n            int best = -1, bestV = -1;\n            for (int k = 0; k < SEED_COUNT; k++) if (((bits[k] >> l) & 1u) && !used[k]) {\n                if (V[k] > bestV) bestV = V[k], best = k;\n            }\n            if (best != -1) include(best);\n        }\n\n        // Include champion\n        include(champion);\n\n        // Greedy fill to reach target coverage\n        auto gp = greedyParamsForTurn(t);\n        vector<int> cov(M, 0);\n        for (int k: selected) for (int l = 0; l < M; l++) if ((bits[k] >> l) & 1u) cov[l]++;\n\n        auto needWeight = [&](int l)->double{\n            if (cntAll[l] == 0) return 0.0;\n            int need = max(0, gp.targetBase - cov[l]);\n            if (need <= 0) return 0.0;\n            // Emphasize rare and low coverage\n            return (double)need * (1.0 / (double)max(1, cov[l])) * (wdim[l] > 0 ? (1.0 + 3.0 * wdim[l]) : 1.0);\n        };\n\n        while ((int)selected.size() < N*N) {\n            int best = -1;\n            double bestScore = -1e100;\n            for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) {\n                double coverGain = 0.0;\n                for (int l = 0; l < M; l++) if ((bits[k] >> l) & 1u) coverGain += needWeight(l);\n                double missGain = sumW[bits[k] & missMask];\n                double sc = gp.wVfill * V[k] + coverGain + gp.wMissingPref * missGain;\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = k;\n                }\n            }\n            if (best == -1) break;\n            include(best);\n            for (int l = 0; l < M; l++) if ((bits[best] >> l) & 1u) cov[l]++;\n        }\n        // If still not enough (shouldn't happen), fill by V\n        if ((int)selected.size() < N*N) {\n            vector<int> rest;\n            for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) rest.push_back(k);\n            sort(rest.begin(), rest.end(), [&](int a, int b){\n                if (V[a] != V[b]) return V[a] > V[b];\n                return a < b;\n            });\n            for (int k: rest) {\n                if ((int)selected.size() >= N*N) break;\n                include(k);\n            }\n        }\n\n        // Arrangement: two restarts, keep the best\n        auto pp = paramsForTurn(t);\n\n        // Precompute nodeWeight (includes hub-specific node boost for missing dims coverage)\n        vector<double> nodeWeight(SEED_COUNT, 0.0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            nodeWeight[k] = pp.wV * V[k] + pp.wRare * rareSum[k] + pp.wCnt * carrierCnt[k]\n                            + pp.hubNodeBoost * sumW[bits[k] & missMask];\n        }\n\n        // Build an objective evaluator with hub-aware pair score\n        auto pairScoreEdge = [&](int posA, int posB, int seedA, int seedB)->double{\n            // Base reward: both-carry and one-carry (by rarity)\n            double base = pp.pairBoth * sumW[bits[seedA] & bits[seedB]]\n                        + pp.pairOne  * sumW[bits[seedA] ^ bits[seedB]];\n            // Hub-specific: if one end is center, reward the other for covering champion's missing dims\n            if (posA == centerPos) base += pp.hubOne * sumW[bits[seedB] & missMask];\n            if (posB == centerPos) base += pp.hubOne * sumW[bits[seedA] & missMask];\n            return base;\n        };\n\n        auto totalObjective = [&](const vector<int>& assignPos)->double{\n            double nodeTerm = 0.0;\n            for (int p = 0; p < N*N; p++) {\n                int k = assignPos[p];\n                nodeTerm += deg[p] * nodeWeight[k];\n            }\n            double pairTerm = 0.0;\n            for (auto &e : edges) {\n                int a = e.first, b = e.second;\n                pairTerm += pairScoreEdge(a, b, assignPos[a], assignPos[b]);\n            }\n            return nodeTerm + pp.pairFactor * pairTerm;\n        };\n\n        int restarts = 2;\n        int iterPerRestart;\n        if (t <= 3) iterPerRestart = 100000;\n        else if (t <= 6) iterPerRestart = 85000;\n        else iterPerRestart = 70000;\n\n        double bestObj = -1e100;\n        vector<int> bestAssign;\n        vector<int> bestAssignInv(SEED_COUNT, -1);\n\n        // Sorting seeds for initial placement\n        vector<double> arrScore(SEED_COUNT, 0.0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            arrScore[k] = nodeWeight[k];\n        }\n\n        for (int rr = 0; rr < restarts; rr++) {\n            // Initial assignment with hub-neighbor preference\n            vector<int> assignPos(N*N, -1);\n            vector<int> invPos(SEED_COUNT, -1);\n\n            // Place champion at center\n            assignPos[centerPos] = champion;\n            invPos[champion] = centerPos;\n\n            // Choose neighbor seeds to best cover missing dims (simple greedy)\n            vector<int> pool = selected;\n            pool.erase(remove(pool.begin(), pool.end(), champion), pool.end());\n\n            auto noise = [&](double amp){ return (rng.rand01() - 0.5) * amp; };\n\n            vector<pair<double,int>> neighCand;\n            neighCand.reserve(pool.size());\n            for (int k : pool) {\n                double sc = 300.0 * sumW[bits[k] & missMask] + 0.03 * V[k] + noise(0.01);\n                neighCand.emplace_back(sc, k);\n            }\n            sort(neighCand.begin(), neighCand.end(), greater<>());\n            vector<int> neighSeeds;\n            for (int i = 0; i < (int)neighbors[centerPos].size() && i < (int)neighCand.size(); i++) {\n                neighSeeds.push_back(neighCand[i].second);\n            }\n\n            // Prepare sorted toPlace list\n            vector<pair<double,int>> rankSeeds;\n            rankSeeds.reserve(pool.size());\n            for (int k : pool) {\n                double sc = arrScore[k] + noise(0.05);\n                rankSeeds.emplace_back(sc, k);\n            }\n            sort(rankSeeds.begin(), rankSeeds.end(), greater<>());\n\n            // Fill neighbor positions with chosen seeds\n            vector<char> usedSeed(SEED_COUNT, 0);\n            usedSeed[champion] = 1;\n            for (int k : neighSeeds) usedSeed[k] = 1;\n            // Assign neighbor seeds to center neighbors\n            int idx = 0;\n            for (int nb : neighbors[centerPos]) {\n                if (idx < (int)neighSeeds.size()) {\n                    int k = neighSeeds[idx++];\n                    assignPos[nb] = k;\n                    invPos[k] = nb;\n                }\n            }\n            // Fill remaining positions by rank order\n            int filled = 0;\n            for (auto &pr : rankSeeds) {\n                int k = pr.second;\n                if (usedSeed[k]) continue;\n                // find next free pos in posOrder excluding already filled\n                for (int pi = 0; pi < N*N; pi++) {\n                    int pos = posOrder[pi];\n                    if (assignPos[pos] == -1) {\n                        assignPos[pos] = k;\n                        invPos[k] = pos;\n                        usedSeed[k] = 1;\n                        filled++;\n                        break;\n                    }\n                }\n            }\n            // Just in case (should be full)\n            for (int pi = 0; pi < N*N; pi++) {\n                int pos = posOrder[pi];\n                if (assignPos[pos] == -1) {\n                    // find any remaining\n                    for (int k : selected) if (!usedSeed[k]) {\n                        assignPos[pos] = k;\n                        invPos[k] = pos;\n                        usedSeed[k] = 1;\n                        break;\n                    }\n                }\n            }\n\n            // Local improvement: greedy swap, lock champion at center\n            auto currentObj = totalObjective(assignPos);\n\n            for (int it = 0; it < iterPerRestart; it++) {\n                int a = rng.randint(0, N*N-1);\n                int b = rng.randint(0, N*N-1);\n                if (a == b) continue;\n                // Lock champion at center\n                if (a == centerPos || b == centerPos) continue;\n\n                int ka = assignPos[a];\n                int kb = assignPos[b];\n\n                // Node term delta\n                double delta = 0.0;\n                delta += deg[a] * (nodeWeight[kb] - nodeWeight[ka]);\n                delta += deg[b] * (nodeWeight[ka] - nodeWeight[kb]);\n\n                // Pair term delta for edges incident to a and b\n                double deltaPair = 0.0;\n                for (int pa : neighbors[a]) {\n                    if (pa == b) continue;\n                    int kp = assignPos[pa];\n                    // old: edge (a,pa) with (ka,kp), new: (kb,kp)\n                    deltaPair += pairScoreEdge(a, pa, kb, kp) - pairScoreEdge(a, pa, ka, kp);\n                }\n                for (int pb : neighbors[b]) {\n                    if (pb == a) continue;\n                    int kp = assignPos[pb];\n                    // old: edge (b,pb) with (kb,kp), new: (ka,kp)\n                    deltaPair += pairScoreEdge(b, pb, ka, kp) - pairScoreEdge(b, pb, kb, kp);\n                }\n                // Edge (a,b) itself: since neither is center (locked), pairScoreEdge symmetric -> no change.\n\n                delta += pp.pairFactor * deltaPair;\n\n                if (delta > 1e-12) {\n                    // Accept swap\n                    swap(assignPos[a], assignPos[b]);\n                    invPos[ka] = b;\n                    invPos[kb] = a;\n                    currentObj += delta;\n                }\n            }\n\n            if (currentObj > bestObj) {\n                bestObj = currentObj;\n                bestAssign = assignPos;\n                bestAssignInv = invPos;\n            }\n        }\n\n        // Output planting plan grid\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int pos = i * N + j;\n                int k = bestAssign[pos];\n                cout << k << (j + 1 == N ? '\\n' : ' ');\n            }\n        }\n        cout.flush();\n\n        // Read next generation\n        for (int i = 0; i < SEED_COUNT; i++) {\n            for (int j = 0; j < M; j++) cin >> X[i][j];\n        }\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int x, y; };\n\nstruct Hungarian {\n    // Solves assignment problem with square cost matrix (n x n).\n    // cost[i][j] (0-indexed) must be integer.\n    // Returns pair (min_cost, assignment), where assignment[i] = j matched to row i.\n    // Complexity: O(n^3)\n    static pair<long long, vector<int>> solve(const vector<vector<int>>& cost) {\n        int n = (int)cost.size();\n        const int INF = 1e9;\n        vector<int> u(n+1), v(n+1), p(n+1), way(n+1);\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            int j0 = 0;\n            vector<int> minv(n+1, INF);\n            vector<char> used(n+1, false);\n            do {\n                used[j0] = true;\n                int i0 = p[j0], delta = INF, j1 = 0;\n                for (int j = 1; j <= n; j++) if (!used[j]) {\n                    int cur = cost[i0-1][j-1] - u[i0] - v[j];\n                    if (cur < minv[j]) { minv[j] = cur; way[j] = j0; }\n                    if (minv[j] < delta) { delta = minv[j]; j1 = j; }\n                }\n                for (int j = 0; j <= n; j++) {\n                    if (used[j]) { u[p[j]] += delta; v[j] -= delta; }\n                    else minv[j] -= delta;\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n        vector<int> assignment(n, -1);\n        for (int j = 1; j <= n; j++) if (p[j] != 0) assignment[p[j]-1] = j-1;\n        long long value = -v[0];\n        return {value, assignment};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, V;\n    if (!(cin >> N >> M >> V)) return 0;\n    vector<string> ss(N), tt(N);\n    for (int i = 0; i < N; i++) cin >> ss[i];\n    for (int i = 0; i < N; i++) cin >> tt[i];\n\n    vector<vector<int>> occ(N, vector<int>(N, 0));\n    vector<Pos> sources, targets;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int s = ss[i][j] - '0';\n            int t = tt[i][j] - '0';\n            occ[i][j] = s;\n            if (s == 1 && t == 0) sources.push_back({i, j});\n            if (s == 0 && t == 1) targets.push_back({i, j});\n        }\n    }\n\n    int Dcnt = (int)sources.size();\n    if ((int)targets.size() != Dcnt) {\n        // Fallback (shouldn't happen given constraints)\n        cout << 2 << \"\\n\";\n        cout << 0 << \" \" << 1 << \"\\n\";\n        cout << 0 << \" \" << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Design tree: simplest, V' = 2, one fingertip of length 1\n    int Vp = 2;\n\n    // Direction: 0=E, 1=S, 2=W, 3=N\n    const int DX[4] = {0, 1, 0, -1};\n    const int DY[4] = {1, 0, -1, 0};\n    auto rotdist = [&](int cur, int req) {\n        int d = (req - cur + 4) % 4;\n        return min(d, 4 - d);\n    };\n\n    // Adjacent root positions to manipulate cell (bx,by)\n    // Returns list of (root_x, root_y, required_dir)\n    auto enumerate_adj = [&](int bx, int by) -> vector<tuple<int,int,int>> {\n        vector<tuple<int,int,int>> res;\n        if (by - 1 >= 0) res.emplace_back(bx, by - 1, 0); // left -> face E\n        if (by + 1 < N) res.emplace_back(bx, by + 1, 2);  // right -> face W\n        if (bx - 1 >= 0) res.emplace_back(bx - 1, by, 1); // above -> face S\n        if (bx + 1 < N) res.emplace_back(bx + 1, by, 3);  // below -> face N\n        return res;\n    };\n\n    // Build Hungarian cost matrix (Manhattan distances)\n    vector<vector<int>> cost(Dcnt, vector<int>(Dcnt, 0));\n    for (int i = 0; i < Dcnt; i++) {\n        for (int j = 0; j < Dcnt; j++) {\n            cost[i][j] = abs(sources[i].x - targets[j].x) + abs(sources[i].y - targets[j].y);\n        }\n    }\n    vector<int> pairTo(Dcnt, -1);\n    if (Dcnt > 0) {\n        auto res = Hungarian::solve(cost);\n        pairTo = res.second; // sources[i] -> targets[pairTo[i]]\n    }\n\n    vector<string> ops; ops.reserve(100000);\n\n    // Simulator state\n    int rx = 0, ry = 0; // root position\n    int dir = 0;        // fingertip orientation (0=E) initially east per problem\n    bool holding = false;\n\n    auto push_turn = [&](char moveCh, char rotCh, bool P) {\n        string s(2*Vp, '.'); // length 4\n        s[0] = moveCh;       // movement\n        s[1] = (rotCh == 'L' || rotCh == 'R') ? rotCh : '.';\n        s[2] = '.';          // root is not a leaf\n        s[3] = (P ? 'P' : '.'); // fingertip action\n\n        // Apply movement\n        if (moveCh == 'U') rx -= 1;\n        else if (moveCh == 'D') rx += 1;\n        else if (moveCh == 'L') ry -= 1;\n        else if (moveCh == 'R') ry += 1;\n        // root must stay in bounds; guard anyway\n        rx = max(0, min(N-1, rx));\n        ry = max(0, min(N-1, ry));\n\n        // Apply rotation\n        if (rotCh == 'L') dir = (dir + 3) % 4;\n        else if (rotCh == 'R') dir = (dir + 1) % 4;\n\n        // Apply P\n        if (P) {\n            int fx = rx + DX[dir];\n            int fy = ry + DY[dir];\n            if (0 <= fx && fx < N && 0 <= fy && fy < N) {\n                if (!holding) {\n                    if (occ[fx][fy] == 1) { occ[fx][fy] = 0; holding = true; }\n                    // else do nothing (shouldn't happen)\n                } else {\n                    if (occ[fx][fy] == 0) { occ[fx][fy] = 1; holding = false; }\n                    // else do nothing (shouldn't happen)\n                }\n            }\n        }\n\n        ops.push_back(s);\n    };\n\n    auto rotate_step_char = [&](int cur, int req) -> char {\n        int d = (req - cur + 4) % 4;\n        if (d == 0) return '.';\n        if (d == 1) return 'R';\n        if (d == 3) return 'L';\n        return 'R'; // d == 2 -> choose 'R' twice\n    };\n\n    // Move/rotate to (tx,ty,reqdir); optionally fuse P at the last step if any,\n    // otherwise, if already aligned and fuseP is true, perform a single '.' '.' 'P' step.\n    auto move_rotate_to = [&](int tx, int ty, int reqdir, bool fuseP) {\n        int dx = abs(rx - tx);\n        int dy = abs(ry - ty);\n        int rotNeed = rotdist(dir, reqdir);\n        int totMoves = dx + dy;\n        int rotTail = max(0, rotNeed - totMoves);\n        int totalSteps = totMoves + rotTail;\n\n        // Move along x-axis first, then y-axis\n        int stepIdx = 0;\n        while (rx != tx) {\n            char mv = (rx < tx ? 'D' : 'U');\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn(mv, rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000) return;\n        }\n        while (ry != ty) {\n            char mv = (ry < ty ? 'R' : 'L');\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn(mv, rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000) return;\n        }\n        // Rotations if needed\n        while (dir != reqdir) {\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn('.', rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000) return;\n        }\n        // If already aligned from the start and we want to P, we need one step to do it\n        if (fuseP && totalSteps == 0) {\n            push_turn('.', '.', true);\n        }\n    };\n\n    // Best adjacency for a target cell from a given state (rx,ry,dir)\n    auto choose_best_adj = [&](int rx0, int ry0, int dir0, int bx, int by) {\n        auto cand = enumerate_adj(bx, by);\n        int bestIdx = -1;\n        long long bestCost = LLONG_MAX, bestMove = LLONG_MAX, bestRot = LLONG_MAX;\n        for (int i = 0; i < (int)cand.size(); i++) {\n            auto [nx, ny, ndir] = cand[i];\n            long long d1 = llabs(rx0 - nx) + llabs(ry0 - ny);\n            long long rd = rotdist(dir0, ndir);\n            long long cost = max(d1, rd);\n            if (cost < bestCost ||\n               (cost == bestCost && (d1 < bestMove ||\n               (d1 == bestMove && rd < bestRot)))) {\n                bestCost = cost; bestMove = d1; bestRot = rd; bestIdx = i;\n            }\n        }\n        if (bestIdx == -1) return tuple<int,int,int>(rx0, ry0, dir0);\n        return cand[bestIdx];\n    };\n\n    // Compute the next best source to go from hypothetical state (rx0,ry0,dir0)\n    auto next_best_source_from_state = [&](int rx0, int ry0, int dir0, const vector<char>& done) -> pair<long long,int> {\n        long long bestCost = LLONG_MAX;\n        int bestIdx = -1;\n        for (int i = 0; i < Dcnt; i++) if (!done[i]) {\n            auto b = sources[i];\n            auto cand = enumerate_adj(b.x, b.y);\n            for (auto &t : cand) {\n                int nx, ny, ndir;\n                tie(nx, ny, ndir) = t;\n                long long d1 = llabs(rx0 - nx) + llabs(ry0 - ny);\n                long long rd = rotdist(dir0, ndir);\n                long long cost = max(d1, rd);\n                if (cost < bestCost) {\n                    bestCost = cost; bestIdx = i;\n                }\n            }\n        }\n        return {bestCost, bestIdx};\n    };\n\n    // Pick the first task and initial root position:\n    int firstIdx = 0;\n    int init_rx = 0, init_ry = 0; // initial root\n    if (Dcnt > 0) {\n        // Prefer a source that has a left adjacency (ndir=0) to allow instant pick without rotation\n        int besti = -1;\n        long long bestScore = LLONG_MAX;\n        for (int i = 0; i < Dcnt; i++) {\n            int bx = sources[i].x, by = sources[i].y;\n            // check left adjacency\n            if (by - 1 >= 0) {\n                int ax = bx, ay = by - 1;\n                // heuristic: closeness to center\n                long long score = llabs(ax - (N/2)) + llabs(ay - (N/2));\n                if (score < bestScore) {\n                    bestScore = score; besti = i;\n                    init_rx = ax; init_ry = ay;\n                }\n            }\n        }\n        if (besti == -1) {\n            // If no left adjacency (rare at border-only), fallback to center-near best adjacency of some source\n            long long bestScore2 = LLONG_MAX;\n            for (int i = 0; i < Dcnt; i++) {\n                int bx = sources[i].x, by = sources[i].y;\n                auto cand = enumerate_adj(bx, by);\n                for (auto &t : cand) {\n                    int ax, ay, adir; tie(ax, ay, adir) = t;\n                    long long score = llabs(ax - (N/2)) + llabs(ay - (N/2)) + (adir != 0); // prefer dir=0 if possible\n                    if (score < bestScore2) {\n                        bestScore2 = score; besti = i; init_rx = ax; init_ry = ay;\n                    }\n                }\n            }\n        }\n        firstIdx = besti;\n    }\n\n    // Initialize root and orientation (orientation is fixed to east initially)\n    rx = init_rx; ry = init_ry; dir = 0;\n\n    // Output the tree and initial root position\n    cout << Vp << \"\\n\";\n    cout << 0 << \" \" << 1 << \"\\n\"; // edge (0,1) length 1\n    cout << rx << \" \" << ry << \"\\n\";\n\n    if (Dcnt == 0) {\n        // Nothing to move\n        return 0;\n    }\n\n    vector<char> done(Dcnt, 0);\n\n    auto process_task = [&](int idx) {\n        if ((int)ops.size() >= 100000) return;\n        Pos b = sources[idx];\n        Pos c = targets[pairTo[idx]];\n\n        // Move to best adjacency of b and pick (fused if possible)\n        {\n            auto [tx, ty, reqdir] = choose_best_adj(rx, ry, dir, b.x, b.y);\n            // Attempt to fuse pick at the last step\n            move_rotate_to(tx, ty, reqdir, true);\n            if ((int)ops.size() >= 100000) return;\n        }\n\n        // Move to best adjacency of c with look-ahead to next source, and place (fused)\n        {\n            auto candC = enumerate_adj(c.x, c.y);\n            long long bestTotal = LLONG_MAX;\n            int bestIdx = 0;\n            // Evaluate each target adjacency with look-ahead to next best source\n            for (int i = 0; i < (int)candC.size(); i++) {\n                int tx, ty, reqdir; tie(tx, ty, reqdir) = candC[i];\n                long long d1 = llabs(rx - tx) + llabs(ry - ty);\n                long long rd = rotdist(dir, reqdir);\n                long long stepCost = max(d1, rd);\n                // If stepCost == 0, we still need 1 step to place ('.','.', 'P'); but for comparing target adjacencies,\n                // this constant doesn't change relative ordering unless some have 0 and others >0, so add small epsilon\n                long long adjPlaceCost = stepCost + (stepCost == 0 ? 0 : 0);\n                // Hypothetical state after placing at (tx,ty,reqdir)\n                // The next move starts from (tx,ty,reqdir)\n                auto bestNext = next_best_source_from_state(tx, ty, reqdir, done);\n                long long total = adjPlaceCost + (bestNext.first >= (long long)4e18 ? 0 : bestNext.first);\n                if (total < bestTotal) { bestTotal = total; bestIdx = i; }\n            }\n            int tx, ty, reqdir; tie(tx, ty, reqdir) = candC[bestIdx];\n            move_rotate_to(tx, ty, reqdir, true);\n            if ((int)ops.size() >= 100000) return;\n        }\n\n        done[idx] = 1;\n    };\n\n    // Process the first task\n    process_task(firstIdx);\n\n    // Process remaining tasks: greedy nearest-next from current state\n    for (int it = 1; it < Dcnt; it++) {\n        if ((int)ops.size() >= 100000) break;\n        // Find next source with minimal cost from current state\n        long long bestCost = LLONG_MAX;\n        int besti = -1;\n        for (int i = 0; i < Dcnt; i++) if (!done[i]) {\n            auto b = sources[i];\n            auto cand = enumerate_adj(b.x, b.y);\n            for (auto &t : cand) {\n                int nx, ny, ndir;\n                tie(nx, ny, ndir) = t;\n                long long d1 = llabs(rx - nx) + llabs(ry - ny);\n                long long rd = rotdist(dir, ndir);\n                long long cost = max(d1, rd);\n                if (cost < bestCost) { bestCost = cost; besti = i; }\n            }\n        }\n        if (besti == -1) break;\n        process_task(besti);\n    }\n\n    // Output operations\n    for (auto &s : ops) cout << s << \"\\n\";\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int LIM = 100000;\nstatic const int PERIM_LIMIT = 400000;\n\n// Point with weight (+1 mackerel, -1 sardine)\nstruct Pt { int x, y, w; };\n\n// Candidate polygon\nstruct Candidate {\n    vector<pair<int,int>> poly; // vertices in order\n    long long approxScore = LLONG_MIN;\n    long long exactScore = LLONG_MIN;\n};\n\n// Utility: compute time in seconds\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\n// Point-in-polygon (axis aligned), inclusive on edges\nstatic bool point_on_edge(const vector<pair<int,int>>& poly, int x, int y) {\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        int x1 = poly[i].first;\n        int y1 = poly[i].second;\n        int x2 = poly[(i+1)%m].first;\n        int y2 = poly[(i+1)%m].second;\n        if (x1 == x2) {\n            // vertical segment\n            if (x == x1) {\n                int lo = min(y1, y2), hi = max(y1, y2);\n                if (lo <= y && y <= hi) return true;\n            }\n        } else if (y1 == y2) {\n            if (y == y1) {\n                int lo = min(x1, x2), hi = max(x1, x2);\n                if (lo <= x && x <= hi) return true;\n            }\n        }\n    }\n    return false;\n}\nstatic bool point_in_polygon(const vector<pair<int,int>>& poly, int x, int y) {\n    if (point_on_edge(poly, x, y)) return true;\n    // ray casting to the right\n    bool inside = false;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        int x1 = poly[i].first, y1 = poly[i].second;\n        int x2 = poly[(i+1)%m].first, y2 = poly[(i+1)%m].second;\n        // consider edges where y in [ymin, ymax)\n        if (y1 == y2) continue; // horizontal edges don't contribute\n        int ymin = min(y1, y2), ymax = max(y1, y2);\n        if (y < ymin || y >= ymax) continue;\n        // Compute x coordinate of intersection; edge is vertical if x1==x2\n        // For axis-aligned, intersect if vertical edge to the right of point\n        double xint;\n        if (x1 == x2) {\n            xint = x1;\n        } else {\n            // Shouldn't happen as edges are axis-aligned, but keep generic\n            xint = x1 + (double)(x2 - x1) * (double)(y - y1) / (double)(y2 - y1);\n        }\n        if ((double)x < xint) inside = !inside;\n    }\n    return inside;\n}\n\n// Build coarse grid best rectangle (Kadane over grid)\nstruct Rect { int L, R, B, T; };\nstatic Rect coarse_best_rect_from_W(const vector<vector<int>>& W) {\n    int G = (int)W.size();\n    if (G == 0) return {0, 0, 0, 0};\n    int H = G; // square\n    long long bestSum = LLONG_MIN;\n    int bestL=0, bestR=0, bestB=0, bestT=0;\n\n    vector<long long> acc(G);\n    for (int top = 0; top < H; ++top) {\n        fill(acc.begin(), acc.end(), 0);\n        for (int bot = top; bot < H; ++bot) {\n            for (int j = 0; j < G; ++j) acc[j] += W[bot][j];\n            // 1D Kadane\n            long long s = 0, best1D = LLONG_MIN;\n            int start = 0, l = 0, r = -1;\n            for (int j = 0; j < G; ++j) {\n                if (s <= 0) { s = acc[j]; start = j; }\n                else s += acc[j];\n                if (best1D == LLONG_MIN || s > best1D) { best1D = s; l = start; r = j; }\n            }\n            if (best1D > bestSum) {\n                bestSum = best1D;\n                bestL = l; bestR = r; bestB = top; bestT = bot;\n            }\n        }\n    }\n    return {bestL, bestR, bestB, bestT};\n}\n\n// Build grid lines using ceil(i*100001/G) capped to 100000 for polygon output\nstatic void build_grid_lines(int G, vector<int>& xs, vector<int>& ys) {\n    xs.resize(G+1); ys.resize(G+1);\n    for (int i = 0; i <= G; ++i) {\n        long long t = (long long)i * 100001;\n        int xi = (int)((t + G - 1) / G);\n        int yi = (int)((t + G - 1) / G);\n        if (xi > LIM) xi = LIM;\n        if (yi > LIM) yi = LIM;\n        xs[i] = xi;\n        ys[i] = yi;\n    }\n}\n\n// Convert grid-rectangle indices to polygon\nstatic vector<pair<int,int>> rect_to_polygon(const Rect& r, const vector<int>& xs, const vector<int>& ys) {\n    int Lx = xs[r.L];\n    int Rx = xs[r.R+1] - 1; if (Rx < Lx) Rx = Lx;\n    int By = ys[r.B];\n    int Ty = ys[r.T+1] - 1; if (Ty < By) Ty = By;\n    vector<pair<int,int>> poly;\n    poly.emplace_back(Lx, By);\n    poly.emplace_back(Rx, By);\n    poly.emplace_back(Rx, Ty);\n    poly.emplace_back(Lx, Ty);\n    return poly;\n}\n\n// Compute exact score of a polygon by scanning all points\nstatic long long exact_score_polygon(const vector<pair<int,int>>& poly, const vector<Pt>& pts) {\n    long long s = 0;\n    for (const auto& p : pts) {\n        if (point_in_polygon(poly, p.x, p.y)) s += p.w;\n    }\n    return s;\n}\n\n// Region growth on grid and polygon extraction\nstruct RegionGrower {\n    int G;\n    vector<vector<int>> W;           // cell weights [j][i]\n    vector<int> xs, ys;              // grid lines (safe, capped at 100000)\n    vector<int> wx, hy;              // cell widths and heights\n    vector<vector<char>> inR;        // chosen set\n    vector<vector<unsigned char>> nmask; // neighbor mask for frontier (bits: 1 L, 2 R, 4 B, 8 T)\n\n    RegionGrower(int G_, const vector<vector<int>>& W_, const vector<int>& xs_, const vector<int>& ys_)\n        : G(G_), W(W_), xs(xs_), ys(ys_) {\n        wx.resize(G); hy.resize(G);\n        for (int i = 0; i < G; ++i) {\n            wx[i] = xs[i+1] - xs[i];\n            if (wx[i] < 1) wx[i] = 1;\n            hy[i] = ys[i+1] - ys[i];\n            if (hy[i] < 1) hy[i] = 1;\n        }\n        inR.assign(G, vector<char>(G, 0));\n        nmask.assign(G, vector<unsigned char>(G, 0));\n    }\n\n    inline int delta_perim_for_cell(int i, int j, unsigned char mask) const {\n        int left = (mask & 1) ? 1 : 0;\n        int right = (mask & 2) ? 1 : 0;\n        int bottom = (mask & 4) ? 1 : 0;\n        int top = (mask & 8) ? 1 : 0;\n        // neighbors inside contribute twice the shared edge (one existing boundary removed + no new on that side)\n        int res = 2 * (wx[i] + hy[j]) - 2 * ( hy[j]*(left + right) + wx[i]*(bottom + top) );\n        return res;\n    }\n\n    struct PQEntry {\n        double key;\n        int i, j;\n        int ver;\n        bool operator<(const PQEntry& other) const { return key < other.key; }\n    };\n\n    // Grow region from seed (si, sj) with mode 'ratio' or 'lambda', returns inside mask after fill and approx score\n    // mode = 0: ratio; lambda ignored\n    // mode = 1: lambda gain\n    void reset() {\n        for (int j = 0; j < G; ++j) {\n            fill(inR[j].begin(), inR[j].end(), 0);\n            fill(nmask[j].begin(), nmask[j].end(), 0);\n        }\n    }\n\n    struct GrowResult {\n        vector<vector<char>> inside; // filled region mask\n        long long approxScore = LLONG_MIN;\n        long long perim = 0;\n        bool valid = false;\n    };\n\n    GrowResult grow_from_seed(int si, int sj, int mode, double lambda, double time_limit_sec, Timer& tim) {\n        reset();\n        vector<vector<int>> ver(G, vector<int>(G, 0));\n        priority_queue<PQEntry> pq;\n\n        auto push_update = [&](int i, int j) {\n            if (inR[j][i]) return;\n            unsigned char mask = nmask[j][i];\n            if (mask == 0) return; // not frontier\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (sc <= 0) return;\n                double key = (double)sc / (double)(max(1, dper));\n                // tie-breaker by score slightly\n                key += 1e-9 * sc;\n                pq.push({key, i, j, ++ver[j][i]});\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) return;\n                pq.push({gain, i, j, ++ver[j][i]});\n            }\n        };\n\n        long long perim = 0;\n        long long sum = 0;\n\n        // If seed weight not positive in ratio mode, skip\n        if (mode == 0 && W[sj][si] <= 0) {\n            GrowResult gr; gr.valid = false;\n            return gr;\n        }\n\n        // Add seed\n        auto add_cell = [&](int ci, int cj) {\n            // compute dper using current mask for this cell\n            unsigned char mask = 0;\n            if (ci > 0 && inR[cj][ci-1]) mask |= 1;\n            if (ci+1 < G && inR[cj][ci+1]) mask |= 2;\n            if (cj > 0 && inR[cj-1][ci]) mask |= 4;\n            if (cj+1 < G && inR[cj+1][ci]) mask |= 8;\n            int dper = delta_perim_for_cell(ci, cj, mask);\n            perim += dper;\n            sum += W[cj][ci];\n            inR[cj][ci] = 1;\n            // update neighbors' masks and push\n            if (ci > 0 && !inR[cj][ci-1]) { nmask[cj][ci-1] |= 2; push_update(ci-1, cj); }\n            if (ci+1 < G && !inR[cj][ci+1]) { nmask[cj][ci+1] |= 1; push_update(ci+1, cj); }\n            if (cj > 0 && !inR[cj-1][ci]) { nmask[cj-1][ci] |= 8; push_update(ci, cj-1); }\n            if (cj+1 < G && !inR[cj+1][ci]) { nmask[cj+1][ci] |= 4; push_update(ci, cj+1); }\n        };\n\n        add_cell(si, sj);\n        // Early exit if perimeter exceeds budget (shouldn't)\n        if (perim > PERIM_LIMIT) {\n            GrowResult gr; gr.valid = false;\n            return gr;\n        }\n\n        // Initialize frontier around seed already done via add_cell\n        // Now expand\n        while (!pq.empty()) {\n            if (tim.elapsed() > time_limit_sec) break;\n            auto e = pq.top(); pq.pop();\n            int i = e.i, j = e.j;\n            if (inR[j][i]) continue;\n            if (e.ver != ver[j][i]) continue;\n            unsigned char mask = nmask[j][i];\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n\n            if (mode == 0) {\n                if (sc <= 0) continue;\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) continue;\n            }\n            if (perim + dper > PERIM_LIMIT) continue;\n            add_cell(i, j);\n        }\n\n        // Build filled region: include holes (cells not reachable from outside through unselected)\n        vector<vector<char>> visited(G, vector<char>(G, 0));\n        deque<pair<int,int>> dq;\n        // Enqueue border unselected cells\n        auto push_border = [&](int i, int j) {\n            if (i < 0 || i >= G || j < 0 || j >= G) return;\n            if (inR[j][i]) return;\n            if (visited[j][i]) return;\n            visited[j][i] = 1;\n            dq.emplace_back(i, j);\n        };\n        for (int i = 0; i < G; ++i) {\n            push_border(i, 0);\n            push_border(i, G-1);\n        }\n        for (int j = 0; j < G; ++j) {\n            push_border(0, j);\n            push_border(G-1, j);\n        }\n        while (!dq.empty()) {\n            auto [i, j] = dq.front(); dq.pop_front();\n            // expand 4-neighbors\n            auto try_push = [&](int ni, int nj) {\n                if (ni < 0 || ni >= G || nj < 0 || nj >= G) return;\n                if (inR[nj][ni]) return;\n                if (visited[nj][ni]) return;\n                visited[nj][ni] = 1;\n                dq.emplace_back(ni, nj);\n            };\n            try_push(i-1, j);\n            try_push(i+1, j);\n            try_push(i, j-1);\n            try_push(i, j+1);\n        }\n        vector<vector<char>> inside(G, vector<char>(G, 0));\n        long long approxScore = 0;\n        for (int j = 0; j < G; ++j) {\n            for (int i = 0; i < G; ++i) {\n                if (inR[j][i] || (!visited[j][i] && !inR[j][i])) {\n                    // If not visited and not chosen, it's a hole; include it\n                    if (!visited[j][i]) inside[j][i] = 1;\n                    else inside[j][i] = inR[j][i];\n                } else {\n                    inside[j][i] = 0;\n                }\n                if (inside[j][i]) approxScore += W[j][i];\n            }\n        }\n        GrowResult gr;\n        gr.inside = move(inside);\n        gr.approxScore = approxScore;\n        gr.perim = perim; // note: real polygon perimeter may be slightly smaller due to capping at 100000, but within limit\n        gr.valid = true;\n        return gr;\n    }\n\n    // Convert inside mask into boundary polygon\n    vector<pair<int,int>> inside_to_polygon(const vector<vector<char>>& inside) const {\n        // generate boundary segments between inside and outside\n        // adjacency map from vertex to 2 neighbors\n        struct KeyHash {\n            size_t operator()(const uint64_t& k) const noexcept { return std::hash<uint64_t>{}(k); }\n        };\n        auto keyOf = [&](int x, int y)->uint64_t {\n            return (uint64_t)((uint32_t)x) << 32 | (uint32_t)y;\n        };\n        unordered_map<uint64_t, int, KeyHash> id;\n        vector<pair<int,int>> verts;\n        vector<vector<int>> adj; // adjacency list\n\n        auto get_id = [&](int x, int y)->int {\n            uint64_t key = keyOf(x, y);\n            auto it = id.find(key);\n            if (it != id.end()) return it->second;\n            int idx = (int)verts.size();\n            verts.emplace_back(x, y);\n            adj.emplace_back();\n            id.emplace(key, idx);\n            return idx;\n        };\n        auto add_edge = [&](int x1, int y1, int x2, int y2){\n            int a = get_id(x1, y1);\n            int b = get_id(x2, y2);\n            adj[a].push_back(b);\n            adj[b].push_back(a);\n        };\n\n        for (int j = 0; j < G; ++j) {\n            for (int i = 0; i < G; ++i) {\n                if (!inside[j][i]) continue;\n                int x0 = xs[i], x1 = xs[i+1];\n                int y0 = ys[j], y1 = ys[j+1];\n                // Left\n                if (i == 0 || !inside[j][i-1]) add_edge(x0, y0, x0, y1);\n                // Right\n                if (i+1 == G || !inside[j][i+1]) add_edge(x1, y0, x1, y1);\n                // Bottom\n                if (j == 0 || !inside[j-1][i]) add_edge(x0, y0, x1, y0);\n                // Top\n                if (j+1 == G || !inside[j+1][i]) add_edge(x0, y1, x1, y1);\n            }\n        }\n        if (verts.empty()) return {}; // no region\n        // find start vertex: minimal (y, x)\n        int start = 0;\n        for (int i = 1; i < (int)verts.size(); ++i) {\n            if (verts[i].second < verts[start].second ||\n                (verts[i].second == verts[start].second && verts[i].first < verts[start].first)) {\n                start = i;\n            }\n        }\n        // Traverse one cycle\n        vector<int> path;\n        path.reserve(adj.size());\n        int cur = start, prev = -1;\n        for (int step = 0; step < 1000000; ++step) {\n            path.push_back(cur);\n            // pick next neighbor != prev\n            if (adj[cur].empty()) break;\n            int n0 = adj[cur][0];\n            int next = n0;\n            if ((int)adj[cur].size() >= 2) {\n                int n1 = adj[cur][1];\n                next = (n0 == prev ? n1 : (n1 == prev ? n0 : n0)); // if prev unknown, choose n0\n            }\n            prev = cur;\n            cur = next;\n            if (cur == start) break;\n        }\n        // Convert to vertex list\n        vector<pair<int,int>> poly;\n        for (int idx : path) poly.push_back(verts[idx]);\n        // Remove last if same as first (already closed by path end), ensure closure by repeating first? but output expects no repeated last\n        if (!poly.empty() && poly.front() == poly.back()) {\n            poly.pop_back();\n        }\n        // Simplify collinear vertices\n        if (poly.size() >= 3) {\n            vector<pair<int,int>> simp;\n            int m = (int)poly.size();\n            for (int i = 0; i < m; ++i) {\n                auto p0 = poly[(i + m - 1) % m];\n                auto p1 = poly[i];\n                auto p2 = poly[(i + 1) % m];\n                bool col = ( (p0.first == p1.first && p1.first == p2.first) ||\n                             (p0.second == p1.second && p1.second == p2.second) );\n                if (!col) simp.push_back(p1);\n            }\n            poly.swap(simp);\n        }\n        // Ensure at least 4 vertices (can add a tiny square if needed)\n        if (poly.size() < 4 && !poly.empty()) {\n            // Attempt to duplicate to form rectangle if possible\n            // But usually region boundary has at least 4 vertices; else fallback main will handle\n        }\n        return poly;\n    }\n};\n\n// Build coarse grid W from points\nstatic vector<vector<int>> build_grid_W(int G, const vector<Pt>& pts) {\n    vector<vector<int>> W(G, vector<int>(G, 0));\n    for (const auto& p : pts) {\n        int xi = (int)((long long)p.x * G / 100001); if (xi < 0) xi = 0; if (xi >= G) xi = G-1;\n        int yi = (int)((long long)p.y * G / 100001); if (yi < 0) yi = 0; if (yi >= G) yi = G-1;\n        W[yi][xi] += p.w;\n    }\n    return W;\n}\n\n// Perimeter of polygon\nstatic long long polygon_perimeter(const vector<pair<int,int>>& poly) {\n    long long peri = 0;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        auto a = poly[i];\n        auto b = poly[(i+1)%m];\n        peri += llabs((long long)a.first - b.first) + llabs((long long)a.second - b.second);\n    }\n    return peri;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<Pt> pts;\n    pts.reserve(2*N);\n    for (int i = 0; i < N; ++i) {\n        int x, y; cin >> x >> y;\n        pts.push_back({x, y, +1});\n    }\n    for (int i = 0; i < N; ++i) {\n        int x, y; cin >> x >> y;\n        pts.push_back({x, y, -1});\n    }\n\n    Timer tim;\n\n    // Build main grid for region growth\n    const int G = 80;\n    vector<vector<int>> W = build_grid_W(G, pts);\n    vector<int> xs, ys;\n    build_grid_lines(G, xs, ys);\n    RegionGrower grower(G, W, xs, ys);\n\n    // Prepare seeds: top cells by W\n    struct Cell { int w, i, j; };\n    vector<Cell> cells;\n    cells.reserve(G*G);\n    for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (W[j][i] > 0) cells.push_back({W[j][i], i, j});\n    sort(cells.begin(), cells.end(), [](const Cell& a, const Cell& b){\n        if (a.w != b.w) return a.w > b.w;\n        if (a.j != b.j) return a.j < b.j;\n        return a.i < b.i;\n    });\n\n    vector<pair<int,int>> seedList;\n    const int maxSeeds = 8;\n    const int minDist = 4;\n    for (const auto& c : cells) {\n        bool ok = true;\n        for (auto [si, sj] : seedList) {\n            if (abs(si - c.i) + abs(sj - c.j) < minDist) { ok = false; break; }\n        }\n        if (!ok) continue;\n        seedList.emplace_back(c.i, c.j);\n        if ((int)seedList.size() >= maxSeeds) break;\n    }\n    if (seedList.empty()) {\n        // fallback: pick the maximum weight cell even if non-positive for mode lambda\n        int bi = 0, bj = 0, bw = INT_MIN;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (W[j][i] > bw) { bw = W[j][i]; bi = i; bj = j;}\n        seedList.emplace_back(bi, bj);\n    }\n\n    // Generate candidates\n    vector<Candidate> candidates;\n\n    // Rectangle candidates from coarse grids\n    vector<int> Gs_rect = {64, 96, 128};\n    for (int Grect : Gs_rect) {\n        vector<vector<int>> Wrect = build_grid_W(Grect, pts);\n        Rect rr = coarse_best_rect_from_W(Wrect);\n        // Map to world coordinates using corresponding grid lines\n        vector<int> xsr, ysr;\n        build_grid_lines(Grect, xsr, ysr);\n        vector<pair<int,int>> poly = rect_to_polygon(rr, xsr, ysr);\n        // perimeter check\n        long long peri = polygon_perimeter(poly);\n        if (peri > PERIM_LIMIT) {\n            // shrink slightly if needed: move right/top inward by 1\n            if (poly.size() == 4) {\n                // try shrink sides a bit\n                if (poly[1].first - poly[0].first > 1) poly[1].first--, poly[2].first--;\n                if (poly[2].second - poly[1].second > 1) poly[2].second--, poly[3].second--;\n                peri = polygon_perimeter(poly);\n            }\n        }\n        if (peri <= PERIM_LIMIT) {\n            Candidate cand;\n            cand.poly = move(poly);\n            cand.exactScore = exact_score_polygon(cand.poly, pts);\n            candidates.push_back(move(cand));\n        }\n    }\n\n    // Full area rectangle as safe fallback\n    {\n        vector<pair<int,int>> poly;\n        poly.emplace_back(0, 0);\n        poly.emplace_back(LIM, 0);\n        poly.emplace_back(LIM, LIM);\n        poly.emplace_back(0, LIM);\n        Candidate cand;\n        cand.poly = move(poly);\n        cand.exactScore = exact_score_polygon(cand.poly, pts);\n        candidates.push_back(move(cand));\n    }\n\n    // Region growth candidates\n    vector<double> lambdas = {0.005, 0.01, 0.02};\n    const double time_limit_sec = 1.75; // leave time for scoring\n    vector<Candidate> region_cands;\n    for (auto [si, sj] : seedList) {\n        if (tim.elapsed() > time_limit_sec) break;\n        // ratio mode\n        {\n            auto gr = grower.grow_from_seed(si, sj, 0, 0.0, time_limit_sec, tim);\n            if (gr.valid) {\n                auto poly = grower.inside_to_polygon(gr.inside);\n                if (!poly.empty()) {\n                    // perimeter check/limit\n                    long long peri = polygon_perimeter(poly);\n                    if (peri <= PERIM_LIMIT && (int)poly.size() <= 1000) {\n                        Candidate cand;\n                        cand.poly = move(poly);\n                        cand.approxScore = gr.approxScore;\n                        region_cands.push_back(move(cand));\n                    }\n                }\n            }\n        }\n        for (double lam : lambdas) {\n            if (tim.elapsed() > time_limit_sec) break;\n            auto gr = grower.grow_from_seed(si, sj, 1, lam, time_limit_sec, tim);\n            if (gr.valid) {\n                auto poly = grower.inside_to_polygon(gr.inside);\n                if (!poly.empty()) {\n                    long long peri = polygon_perimeter(poly);\n                    if (peri <= PERIM_LIMIT && (int)poly.size() <= 1000) {\n                        Candidate cand;\n                        cand.poly = move(poly);\n                        cand.approxScore = gr.approxScore;\n                        region_cands.push_back(move(cand));\n                    }\n                }\n            }\n        }\n    }\n\n    // Keep top few region candidates by approx score\n    sort(region_cands.begin(), region_cands.end(), [](const Candidate& a, const Candidate& b){\n        return a.approxScore > b.approxScore;\n    });\n    int keepK = min(4, (int)region_cands.size());\n    for (int i = 0; i < keepK; ++i) {\n        Candidate cand = region_cands[i];\n        cand.exactScore = exact_score_polygon(cand.poly, pts);\n        candidates.push_back(move(cand));\n    }\n\n    // Choose best candidate by exact score\n    long long bestScore = LLONG_MIN;\n    int bestIdx = -1;\n    for (int i = 0; i < (int)candidates.size(); ++i) {\n        long long sc = candidates[i].exactScore;\n        if (sc == LLONG_MIN) {\n            sc = exact_score_polygon(candidates[i].poly, pts);\n            candidates[i].exactScore = sc;\n        }\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestIdx = i;\n        }\n    }\n    // Safety fallback\n    vector<pair<int,int>> bestPoly;\n    if (bestIdx >= 0) {\n        bestPoly = candidates[bestIdx].poly;\n    } else {\n        // Output minimal rectangle\n        bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n    }\n\n    // Ensure constraints\n    if ((int)bestPoly.size() < 4) {\n        bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n    }\n    long long finalPeri = polygon_perimeter(bestPoly);\n    if (finalPeri > PERIM_LIMIT) {\n        // shrink uniformly a bit if needed\n        // move right/top inward until fits\n        // Assumes rectangle-like shape; if not, just clip a little: scale towards center (but must stay integer grid)\n        // Simple hack: reduce any max x/y by 1 until fits (rare)\n        for (int iter = 0; iter < 1000 && finalPeri > PERIM_LIMIT; ++iter) {\n            int mx = 0, my = 0;\n            for (auto &p : bestPoly) { mx = max(mx, p.first); my = max(my, p.second); }\n            for (auto &p : bestPoly) {\n                if (p.first == mx && mx > 0) p.first--;\n                if (p.second == my && my > 0) p.second--;\n            }\n            finalPeri = polygon_perimeter(bestPoly);\n        }\n    }\n    // Output\n    cout << bestPoly.size() << \"\\n\";\n    for (auto &p : bestPoly) cout << p.first << \" \" << p.second << \"\\n\";\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Op {\n    int p;   // rectangle index\n    int r;   // rotation 0/1\n    char d;  // 'U' or 'L'\n    int b;   // base rectangle index or -1\n};\n\nstruct Column {\n    long long cw;   // column width (top rectangle width in its chosen rotation)\n    long long ch;   // accumulated height in this column\n    int top_id;     // top row rectangle id (first U in this column)\n    int last_id;    // last rectangle id placed in this column\n};\n\nstruct Param {\n    double lamW;            // weight for width increase\n    double lamH;            // weight for height increase (H overflow)\n    long long fudge;        // capacity reduction margin when checking fit\n    double newColBias;      // negative value makes new column more attractive\n    unsigned tieRand;       // random tie breaker seed\n};\n\nstruct PlanResult {\n    vector<Op> ops;\n    long long W_est;\n    long long H_est;\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\n// Build one plan using greedy column stacking\nPlanResult build_plan(\n    const vector<long long>& wp, const vector<long long>& hp,\n    const Param& P\n){\n    int N = (int)wp.size();\n    vector<Op> ops; ops.reserve(N);\n\n    vector<Column> cols;\n    cols.reserve(N);\n\n    long long W = 0;\n    long long H = 0;\n    int lastTopId = -1;\n\n    // rng for tie-breaking\n    uint64_t rng = splitmix64(P.tieRand + 0x123456789abcdefULL);\n\n    for (int i = 0; i < N; ++i) {\n        long long w0 = wp[i], h0 = hp[i];\n        long long w1 = h0, h1 = w0; // rotated\n\n        // Candidate stacking to existing columns\n        int bestCol = -1;\n        int bestRotStack = 0; // 0 or 1\n        long long bestNewColHeight = LLONG_MAX; // ch[j] + height\n        for (int j = 0; j < (int)cols.size(); ++j) {\n            long long cap = cols[j].cw - P.fudge;\n            if (cap < 0) cap = 0;\n            bool fit0 = (w0 <= cap);\n            bool fit1 = (w1 <= cap);\n            if (!fit0 && !fit1) continue;\n            int rot = -1;\n            long long hAdd = LLONG_MAX;\n            if (fit0 && fit1) {\n                // choose rotation that minimizes height\n                if (h0 < h1) { rot = 0; hAdd = h0; }\n                else if (h1 < h0) { rot = 1; hAdd = h1; }\n                else {\n                    // equal heights, break tie by smaller width to be safe\n                    if (w0 <= w1) { rot = 0; hAdd = h0; }\n                    else { rot = 1; hAdd = h1; }\n                }\n            } else if (fit0) { rot = 0; hAdd = h0; }\n            else { rot = 1; hAdd = h1; }\n            long long newColH = cols[j].ch + hAdd;\n            if (newColH < bestNewColHeight) {\n                bestNewColHeight = newColH;\n                bestCol = j;\n                bestRotStack = rot;\n            } else if (newColH == bestNewColHeight && bestCol != -1) {\n                // tie-break: prefer the column with smaller current height\n                // and tiny randomness\n                long long curBestH = cols[bestCol].ch;\n                long long curH = cols[j].ch;\n                if (curH < curBestH) {\n                    bestCol = j;\n                    bestRotStack = rot;\n                } else if (curH == curBestH) {\n                    rng = splitmix64(rng);\n                    if ((rng & 1ULL) == 0ULL) {\n                        bestCol = j;\n                        bestRotStack = rot;\n                    }\n                }\n            }\n        }\n\n        // Evaluate stacking delta\n        double stackDelta = 1e100;\n        int chosenStackRot = 0;\n        if (bestCol != -1) {\n            long long hAdd = (bestRotStack == 0 ? h0 : h1);\n            long long newH = max(H, bestNewColHeight);\n            long long dH = newH - H;\n            stackDelta = P.lamH * (double)dH; // W doesn't change\n            chosenStackRot = bestRotStack;\n        }\n\n        // Evaluate opening new column (both rotations)\n        double newColDelta = 1e100;\n        int chosenNewRot = 0;\n        long long chosenNewCW = 0, chosenNewCH = 0;\n        // rotation 0\n        {\n            long long addW = w0;\n            long long newCH = h0;\n            long long dH = max(0LL, newCH - H);\n            double s = P.lamW * (double)addW + P.lamH * (double)dH + P.newColBias;\n            newColDelta = s;\n            chosenNewRot = 0;\n            chosenNewCW = w0;\n            chosenNewCH = h0;\n        }\n        // rotation 1\n        {\n            long long addW = w1;\n            long long newCH = h1;\n            long long dH = max(0LL, newCH - H);\n            double s = P.lamW * (double)addW + P.lamH * (double)dH + P.newColBias;\n            if (s < newColDelta - 1e-12) {\n                newColDelta = s;\n                chosenNewRot = 1;\n                chosenNewCW = w1;\n                chosenNewCH = h1;\n            }\n        }\n\n        // Choose the better option\n        if (bestCol != -1 && stackDelta <= newColDelta) {\n            // Stack on bestCol\n            int rot = chosenStackRot;\n            Op op;\n            op.p = i;\n            op.r = rot;\n            op.d = 'L';\n            op.b = cols[bestCol].last_id;\n            ops.push_back(op);\n\n            long long hAdd = (rot == 0 ? h0 : h1);\n            cols[bestCol].ch += hAdd;\n            cols[bestCol].last_id = i;\n            H = max(H, cols[bestCol].ch);\n        } else {\n            // Open a new column with U\n            int rot = chosenNewRot;\n            Op op;\n            op.p = i;\n            op.r = rot;\n            op.d = 'U';\n            op.b = (lastTopId == -1 ? -1 : lastTopId);\n            ops.push_back(op);\n\n            Column c;\n            c.cw = chosenNewCW;\n            c.ch = chosenNewCH;\n            c.top_id = i;\n            c.last_id = i;\n            cols.push_back(c);\n\n            lastTopId = i;\n            W += chosenNewCW;\n            H = max(H, chosenNewCH);\n        }\n    }\n\n    return {ops, W, H};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    long long sigma;\n    if (!(cin >> N >> T >> sigma)) return 0;\n    vector<long long> wp(N), hp(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> wp[i] >> hp[i];\n    }\n\n    // Predefined parameter sets to diversify attempts\n    vector<Param> presets;\n    // Basic balanced\n    presets.push_back({1.0, 1.0, 0, 0.0, 1234567});\n    // Favor fewer columns slightly\n    presets.push_back({0.8, 1.2, 0, 0.0, 2345678});\n    // Favor more columns (reduce H) slightly\n    presets.push_back({1.2, 0.8, 0, 0.0, 3456789});\n    // Add margins proportional to sigma\n    presets.push_back({1.0, 1.0, (long long)(sigma / 4), 0.0, 4567890});\n    presets.push_back({1.0, 1.0, (long long)(sigma / 2), 0.0, 5678901});\n    // Encourage new columns with small bias\n    presets.push_back({1.0, 1.0, 0, - (double)(sigma) * 0.05, 6789012});\n    // Mixed: weight width more, and margin\n    presets.push_back({1.3, 0.9, (long long)(sigma / 3), 0.0, 7890123});\n    // Mixed: weight height more, and margin\n    presets.push_back({0.9, 1.3, (long long)(sigma / 3), 0.0, 8901234});\n    // Negative margin (optimistic fit)\n    presets.push_back({1.0, 1.0, - (long long)(sigma / 4), 0.0, 9012345});\n    // Heavier column bias\n    presets.push_back({1.1, 0.9, 0, - (double)(sigma) * 0.10, 9123456});\n\n    // Random jitter around presets if T is large\n    std::mt19937_64 rng(123456789);\n    std::uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    for (int t = 0; t < T; ++t) {\n        Param P;\n        if (t < (int)presets.size()) {\n            P = presets[t];\n        } else {\n            // randomize around a base\n            Param B = presets[t % presets.size()];\n            double j1 = (uni01(rng) - 0.5) * 0.4; // +-20%\n            double j2 = (uni01(rng) - 0.5) * 0.4;\n            P.lamW = max(0.2, B.lamW * (1.0 + j1));\n            P.lamH = max(0.2, B.lamH * (1.0 + j2));\n            long long fj = (long long)((uni01(rng) - 0.5) * sigma); // ~[-0.5sigma,0.5sigma]\n            P.fudge = B.fudge + fj / 4;\n            P.newColBias = B.newColBias + (uni01(rng) - 0.5) * (sigma * 0.05);\n            P.tieRand = (unsigned)rng();\n        }\n\n        PlanResult res = build_plan(wp, hp, P);\n\n        // Optional comment line for debugging\n        cout << \"# est_W \" << res.W_est << \" est_H \" << res.H_est\n             << \" params lW=\" << fixed << setprecision(2) << P.lamW\n             << \" lH=\" << P.lamH << \" fudge=\" << P.fudge\n             << \" bias=\" << P.newColBias << \"\\n\";\n\n        // Output operations\n        cout << res.ops.size() << \"\\n\";\n        for (auto &op : res.ops) {\n            cout << op.p << \" \" << op.r << \" \" << op.d << \" \" << op.b << \"\\n\";\n        }\n        cout.flush();\n\n        long long Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0; // read and ignore\n        // Optional: could adapt parameters using feedback, but we keep it simple.\n    }\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double ms() const {\n        return chrono::duration<double, milli>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nstatic const uint16_t INF16 = (uint16_t)30000;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    if (!(cin >> N >> M >> H)) return 0;\n    vector<int> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n    vector<vector<int>> g(N);\n    vector<pair<int,int>> edges(M);\n    for (int i = 0; i < M; i++) {\n        int u, v; cin >> u >> v;\n        edges[i] = {u, v};\n        g[u].push_back(v);\n        g[v].push_back(u);\n    }\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n    Timer timer;\n\n    // Precompute all-pairs shortest distances\n    vector<uint16_t> Dist((size_t)N * (size_t)N, INF16);\n    {\n        vector<int> q; q.reserve(N);\n        vector<int> dist(N);\n        for (int s = 0; s < N; s++) {\n            fill(dist.begin(), dist.end(), -1);\n            q.clear(); q.push_back(s); dist[s] = 0;\n            for (size_t qi = 0; qi < q.size(); qi++) {\n                int u = q[qi];\n                for (int v : g[u]) if (dist[v] == -1) {\n                    dist[v] = dist[u] + 1;\n                    q.push_back(v);\n                }\n            }\n            uint16_t* row = &Dist[(size_t)s * N];\n            for (int v = 0; v < N; v++) row[v] = dist[v] >= 0 ? (uint16_t)dist[v] : INF16;\n        }\n    }\n\n    // Precompute within-H lists\n    vector<vector<int>> withinH(N);\n    for (int u = 0; u < N; u++) {\n        const uint16_t* Du = &Dist[(size_t)u * N];\n        for (int v = 0; v < N; v++) if (Du[v] <= (uint16_t)H) withinH[u].push_back(v);\n    }\n\n    // Greedy roots selection\n    vector<int> roots;\n    vector<char> isRoot(N, 0);\n    vector<uint16_t> dR(N, INF16);\n\n    int s0 = min_element(A.begin(), A.end()) - A.begin();\n    roots.push_back(s0);\n    isRoot[s0] = 1;\n    {\n        const uint16_t* D0 = &Dist[(size_t)s0 * N];\n        for (int v = 0; v < N; v++) dR[v] = D0[v];\n    }\n    auto recompute_dR = [&]() {\n        fill(dR.begin(), dR.end(), INF16);\n        for (int r : roots) {\n            const uint16_t* Dr = &Dist[(size_t)r * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dr[v]);\n        }\n    };\n\n    while (true) {\n        uint16_t dmax = 0;\n        for (int v = 0; v < N; v++) if (dR[v] > dmax) dmax = dR[v];\n        if (dmax <= (uint16_t)H) break;\n\n        vector<int> far;\n        for (int v = 0; v < N; v++) if (dR[v] == dmax) far.push_back(v);\n\n        int bestCand = -1, bestCover = -1, bestA = INT_MAX;\n        for (int cand : far) {\n            int cover = 0;\n            for (int u : withinH[cand]) if (dR[u] > (uint16_t)H) cover++;\n            if (cover > bestCover || (cover == bestCover && A[cand] < bestA)) {\n                bestCover = cover; bestA = A[cand]; bestCand = cand;\n            }\n        }\n        if (bestCand == -1) bestCand = far[0];\n        if (!isRoot[bestCand]) {\n            roots.push_back(bestCand);\n            isRoot[bestCand] = 1;\n            const uint16_t* Dn = &Dist[(size_t)bestCand * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dn[v]);\n        } else {\n            int cand2 = -1;\n            for (int v = 0; v < N; v++) if (dR[v] > (uint16_t)H) { cand2 = v; break; }\n            if (cand2 == -1) break;\n            roots.push_back(cand2);\n            isRoot[cand2] = 1;\n            const uint16_t* Dn = &Dist[(size_t)cand2 * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dn[v]);\n        }\n    }\n\n    // Prune redundant roots\n    auto compute_min12 = [&](vector<uint16_t>& m1, vector<uint16_t>& m2, vector<int>& arg) {\n        m1.assign(N, INF16); m2.assign(N, INF16); arg.assign(N, -1);\n        for (int r : roots) {\n            const uint16_t* Dr = &Dist[(size_t)r * N];\n            for (int v = 0; v < N; v++) {\n                uint16_t d = Dr[v];\n                if (d < m1[v]) {\n                    m2[v] = m1[v]; m1[v] = d; arg[v] = r;\n                } else if (d < m2[v]) {\n                    m2[v] = d;\n                }\n            }\n        }\n    };\n    {\n        vector<uint16_t> m1, m2; vector<int> arg;\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            compute_min12(m1, m2, arg);\n            for (int i = 0; i < (int)roots.size(); i++) {\n                int r = roots[i];\n                bool safe = true;\n                for (int v = 0; v < N; v++) if (arg[v] == r && m2[v] > (uint16_t)H) { safe = false; break; }\n                if (safe) {\n                    isRoot[r] = 0;\n                    roots.erase(roots.begin() + i);\n                    changed = true;\n                    break;\n                }\n            }\n        }\n        recompute_dR();\n    }\n\n    // Very small local swap over roots to improve sum A*dR (time-capped)\n    auto score_of_mindist = [&](const vector<uint16_t>& m1) -> long long {\n        long long S = 0;\n        for (int v = 0; v < N; v++) {\n            uint16_t d = min<uint16_t>(m1[v], (uint16_t)H);\n            S += 1LL * A[v] * d;\n        }\n        return S;\n    };\n    vector<uint16_t> m1, m2; vector<int> arg;\n    compute_min12(m1, m2, arg);\n    long long Scur = score_of_mindist(m1);\n\n    int maxSwapIter = 1; // keep small to leave time for deepening\n    for (int iter = 0; iter < maxSwapIter; iter++) {\n        if (timer.ms() > 1200.0) break;\n        bool improved = false;\n        long long bestDelta = 0;\n        int bestRootIdx = -1, bestCand = -1;\n\n        for (int ir = 0; ir < (int)roots.size(); ir++) {\n            if (timer.ms() > 1200.0) break;\n            int r = roots[ir];\n            vector<int> Z;\n            for (int v = 0; v < N; v++) if (arg[v] == r && m2[v] > (uint16_t)H) Z.push_back(v);\n\n            vector<int> candList;\n            if (Z.empty()) {\n                candList = withinH[r];\n            } else {\n                static vector<int> mark, cnt, visited;\n                static int stamp = 1;\n                if ((int)mark.size() != N) { mark.assign(N, 0); cnt.assign(N, 0); }\n                visited.clear();\n                stamp++;\n                for (int v : Z) {\n                    for (int c : withinH[v]) {\n                        if (mark[c] != stamp) { mark[c] = stamp; cnt[c] = 1; visited.push_back(c); }\n                        else cnt[c]++;\n                    }\n                }\n                for (int c : visited) if (cnt[c] == (int)Z.size()) candList.push_back(c);\n            }\n            for (int c : candList) {\n                if (c == r) continue;\n                const uint16_t* Dc = &Dist[(size_t)c * N];\n                long long Snew = 0;\n                bool ok = true;\n                for (int v = 0; v < N; v++) {\n                    uint16_t d_without = (arg[v] == r ? m2[v] : m1[v]);\n                    uint16_t dprime = min<uint16_t>(d_without, Dc[v]);\n                    if (dprime > (uint16_t)H) { ok = false; break; }\n                    Snew += 1LL * A[v] * dprime;\n                }\n                if (!ok) continue;\n                long long delta = Snew - Scur;\n                if (delta > bestDelta) { bestDelta = delta; bestRootIdx = ir; bestCand = c; }\n            }\n        }\n        if (bestDelta > 0 && bestRootIdx != -1) {\n            int oldr = roots[bestRootIdx];\n            isRoot[oldr] = 0;\n            roots[bestRootIdx] = bestCand;\n            isRoot[bestCand] = 1;\n            compute_min12(m1, m2, arg);\n            Scur = score_of_mindist(m1);\n            improved = true;\n        }\n        if (!improved) break;\n    }\n\n    // Recompute coverage mindist dR (not strictly needed now)\n    recompute_dR();\n\n    // Build initial parents via multi-source BFS\n    vector<int> parent(N, -1);\n    vector<uint16_t> depth(N, INF16);\n    deque<int> dq;\n    for (int r : roots) {\n        depth[r] = 0; parent[r] = -1; dq.push_back(r);\n    }\n    while (!dq.empty()) {\n        int u = dq.front(); dq.pop_front();\n        if (depth[u] >= (uint16_t)H) continue;\n        uint16_t nd = depth[u] + 1;\n        for (int v : g[u]) if (depth[v] == INF16) {\n            depth[v] = nd; parent[v] = u; dq.push_back(v);\n        }\n    }\n    // Safety: if any node remains unvisited (shouldn't), make it a root.\n    for (int v = 0; v < N; v++) if (depth[v] == INF16) { depth[v] = 0; parent[v] = -1; }\n\n    // Prepare children structure\n    vector<vector<int>> children(N);\n    vector<int> posInParent(N, -1);\n    for (int v = 0; v < N; v++) if (parent[v] != -1) {\n        int p = parent[v];\n        posInParent[v] = (int)children[p].size();\n        children[p].push_back(v);\n    }\n\n    // DFS info: tin/tout, order, subtree sums and max depths\n    vector<int> tin(N, 0), tout(N, 0), order(N, -1), rootsNow;\n    vector<long long> subSum(N, 0);\n    vector<uint16_t> subMax(N, 0);\n    function<void(int,int&)> dfs = [&](int u, int &timerDfs) {\n        tin[u] = timerDfs;\n        order[timerDfs] = u;\n        timerDfs++;\n        long long s = A[u];\n        uint16_t mx = depth[u];\n        for (int w : children[u]) {\n            dfs(w, timerDfs);\n            s += subSum[w];\n            mx = max<uint16_t>(mx, subMax[w]);\n        }\n        subSum[u] = s;\n        subMax[u] = mx;\n        tout[u] = timerDfs;\n    };\n    auto recompute_tree_info = [&]() {\n        rootsNow.clear();\n        for (int v = 0; v < N; v++) if (parent[v] == -1) rootsNow.push_back(v);\n        int timerDfs = 0;\n        for (int r : rootsNow) dfs(r, timerDfs);\n    };\n    recompute_tree_info();\n\n    auto is_ancestor = [&](int u, int v) -> bool {\n        return tin[u] <= tin[v] && tout[v] <= tout[u];\n    };\n\n    auto remove_from_parent = [&](int u) {\n        int p = parent[u];\n        if (p == -1) return;\n        int idx = posInParent[u];\n        int last = children[p].back();\n        swap(children[p][idx], children[p].back());\n        children[p].pop_back();\n        posInParent[last] = idx;\n        posInParent[u] = -1;\n        parent[u] = -1;\n    };\n    auto add_to_parent = [&](int u, int p) {\n        parent[u] = p;\n        posInParent[u] = (int)children[p].size();\n        children[p].push_back(u);\n    };\n\n    // Depth-increasing local improvements\n    while (timer.ms() < 1950.0) {\n        long long bestGain = 0;\n        int bestU = -1, bestX = -1;\n        int bestDelta = 0;\n\n        for (int u = 0; u < N; u++) {\n            if (subMax[u] >= (uint16_t)H) continue; // cannot deepen\n            // Try all neighbors as new parent candidates\n            for (int x : g[u]) {\n                if (x == parent[u]) continue;\n                if (is_ancestor(u, x)) continue; // would create cycle\n                int du = depth[u];\n                int dx = depth[x];\n                int delta = dx + 1 - du;\n                if (delta <= 0) continue;\n                if ((int)subMax[u] + delta > H) continue; // height violation\n                long long gain = 1LL * delta * subSum[u];\n                if (gain > bestGain) {\n                    bestGain = gain; bestU = u; bestX = x; bestDelta = delta;\n                }\n            }\n        }\n\n        if (bestGain <= 0 || bestU == -1) break;\n\n        // Apply the best move\n        int u = bestU, x = bestX, delta = bestDelta;\n        // Update depths on the subtree of u using Euler order\n        int L = tin[u], R = tout[u];\n        for (int i = L; i < R; i++) {\n            int w = order[i];\n            depth[w] = (uint16_t)(depth[w] + delta);\n        }\n        // Reparent u under x\n        remove_from_parent(u);\n        add_to_parent(u, x);\n\n        // Recompute tin/tout, subSum/subMax, order\n        recompute_tree_info();\n\n        // If time is nearly up, stop\n        if (timer.ms() > 1990.0) break;\n    }\n\n    // Output final parents\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << parent[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Structure to represent a safe cycle action\nstruct Action {\n    char d;       // 'L','R','U','D'\n    int p;        // row/column index\n    int k;        // length (number of shifts each way)\n    int cost;     // 2*k\n    vector<int> cover; // Oni IDs this action removes\n};\n\nstruct Plan {\n    vector<int> indices; // indices into candidate action array\n    int cost = INT_MAX;  // total operations\n};\n\nstatic inline char opposite(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\n// Build candidate actions from initial board, including all k from 1..safe width/height for each side.\n// Each action stores the list of Oni IDs it would remove (i.e., in that edge segment).\nvector<Action> build_candidates(const vector<string>& grid, const vector<pair<int,int>>& oni_pos,\n                                const vector<vector<int>>& oni_id) {\n    int N = grid.size();\n    vector<Action> acts;\n\n    // Precompute safe widths for rows\n    vector<int> Lsafe(N, 0), Rsafe(N, 0);\n    for (int r = 0; r < N; ++r) {\n        int firstF = N, lastF = -1;\n        for (int j = 0; j < N; ++j) if (grid[r][j] == 'o') {\n            firstF = min(firstF, j);\n            lastF = max(lastF, j);\n        }\n        Lsafe[r] = (firstF == N ? N : firstF);\n        Rsafe[r] = (lastF == -1 ? N : (N - 1 - lastF));\n    }\n    // Precompute safe heights for columns\n    vector<int> Usafe(N, 0), Dsafe(N, 0);\n    for (int c = 0; c < N; ++c) {\n        int firstF = N, lastF = -1;\n        for (int i = 0; i < N; ++i) if (grid[i][c] == 'o') {\n            firstF = min(firstF, i);\n            lastF = max(lastF, i);\n        }\n        Usafe[c] = (firstF == N ? N : firstF);\n        Dsafe[c] = (lastF == -1 ? N : (N - 1 - lastF));\n    }\n\n    // Build actions for rows\n    for (int r = 0; r < N; ++r) {\n        // Left: k = 1..Lsafe[r], segment [0..k-1]\n        for (int k = 1; k <= Lsafe[r]; ++k) {\n            vector<int> cov;\n            cov.reserve(k);\n            for (int j = 0; j < k; ++j) {\n                int id = oni_id[r][j];\n                if (id != -1) cov.push_back(id);\n            }\n            if (!cov.empty()) {\n                Action a; a.d = 'L'; a.p = r; a.k = k; a.cost = 2*k; a.cover = move(cov);\n                acts.push_back(move(a));\n            }\n        }\n        // Right: k = 1..Rsafe[r], segment [N-k..N-1]\n        for (int k = 1; k <= Rsafe[r]; ++k) {\n            vector<int> cov;\n            cov.reserve(k);\n            for (int j = N - k; j < N; ++j) {\n                int id = oni_id[r][j];\n                if (id != -1) cov.push_back(id);\n            }\n            if (!cov.empty()) {\n                Action a; a.d = 'R'; a.p = r; a.k = k; a.cost = 2*k; a.cover = move(cov);\n                acts.push_back(move(a));\n            }\n        }\n    }\n    // Build actions for columns\n    for (int c = 0; c < N; ++c) {\n        // Up: k = 1..Usafe[c], segment [0..k-1]\n        for (int k = 1; k <= Usafe[c]; ++k) {\n            vector<int> cov;\n            cov.reserve(k);\n            for (int i = 0; i < k; ++i) {\n                int id = oni_id[i][c];\n                if (id != -1) cov.push_back(id);\n            }\n            if (!cov.empty()) {\n                Action a; a.d = 'U'; a.p = c; a.k = k; a.cost = 2*k; a.cover = move(cov);\n                acts.push_back(move(a));\n            }\n        }\n        // Down: k = 1..Dsafe[c], segment [N-k..N-1]\n        for (int k = 1; k <= Dsafe[c]; ++k) {\n            vector<int> cov;\n            cov.reserve(k);\n            for (int i = N - k; i < N; ++i) {\n                int id = oni_id[i][c];\n                if (id != -1) cov.push_back(id);\n            }\n            if (!cov.empty()) {\n                Action a; a.d = 'D'; a.p = c; a.k = k; a.cost = 2*k; a.cover = move(cov);\n                acts.push_back(move(a));\n            }\n        }\n    }\n    return acts;\n}\n\nint selection_cost(const vector<int>& sel, const vector<Action>& acts) {\n    long long s = 0;\n    for (int idx : sel) s += acts[idx].cost;\n    if (s > INT_MAX) return INT_MAX;\n    return (int)s;\n}\n\nvector<int> prune_selection(vector<int> sel, const vector<Action>& acts, int M) {\n    // Remove redundant actions iteratively\n    vector<int> cover_count(M, 0);\n    for (int idx : sel) {\n        for (int id : acts[idx].cover) cover_count[id]++;\n    }\n    // Sort indices by cost descending to try removing expensive ones first\n    vector<int> order = sel;\n    sort(order.begin(), order.end(), [&](int a, int b){\n        if (acts[a].cost != acts[b].cost) return acts[a].cost > acts[b].cost;\n        return a < b;\n    });\n    vector<char> alive(acts.size(), 0);\n    for (int idx : sel) alive[idx] = 1;\n\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        for (int idx : order) {\n            if (!alive[idx]) continue;\n            bool canRemove = true;\n            for (int id : acts[idx].cover) {\n                if (cover_count[id] <= 1) { canRemove = false; break; }\n            }\n            if (canRemove) {\n                for (int id : acts[idx].cover) cover_count[id]--;\n                alive[idx] = 0;\n                changed = true;\n            }\n        }\n    }\n    vector<int> res;\n    res.reserve(sel.size());\n    for (int idx : sel) if (alive[idx]) res.push_back(idx);\n    return res;\n}\n\nvector<int> greedy_select(const vector<Action>& acts, int M, std::mt19937& rng) {\n    int A = (int)acts.size();\n    vector<int> order(A);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n\n    vector<char> covered(M, 0);\n    int remaining = M;\n    vector<int> sel;\n    sel.reserve(M);\n\n    // Quick map from randomized order to tie-breaking index\n    vector<int> rank_in_order(A, 0);\n    for (int i = 0; i < A; ++i) rank_in_order[order[i]] = i;\n\n    while (remaining > 0) {\n        int best = -1;\n        long long best_cost = 1;\n        long long best_gain = 0; // store comparator by cost/gain\n        for (int a = 0; a < A; ++a) {\n            // compute gain\n            int gain = 0;\n            for (int id : acts[a].cover) if (!covered[id]) gain++;\n            if (gain <= 0) continue;\n            long long cost = acts[a].cost;\n            if (best == -1) {\n                best = a; best_cost = cost; best_gain = gain;\n            } else {\n                // Compare cost/gain\n                // cost/gain < best_cost/best_gain  <=> cost*best_gain < best_cost*gain\n                long long lhs = cost * best_gain;\n                long long rhs = best_cost * (long long)gain;\n                if (lhs < rhs) {\n                    best = a; best_cost = cost; best_gain = gain;\n                } else if (lhs == rhs) {\n                    if (cost < best_cost) {\n                        best = a; best_cost = cost; best_gain = gain;\n                    } else if (cost == best_cost) {\n                        // tie-break by randomized order (earlier is preferred)\n                        if (rank_in_order[a] < rank_in_order[best]) {\n                            best = a; best_cost = cost; best_gain = gain;\n                        }\n                    }\n                }\n            }\n        }\n        if (best == -1) {\n            // Shouldn't happen if coverage is complete; break to avoid infinite loop.\n            break;\n        }\n        // Select best\n        sel.push_back(best);\n        for (int id : acts[best].cover) if (!covered[id]) { covered[id] = 1; --remaining; }\n    }\n    // Prune redundant sets\n    sel = prune_selection(sel, acts, M);\n    return sel;\n}\n\nvector<int> local_improvement(vector<int> sel, const vector<Action>& acts, int M, std::mt19937& rng, int iters=200) {\n    int A = (int)acts.size();\n    vector<char> inSel(A, 0);\n    for (int idx : sel) inSel[idx] = 1;\n    int bestCost = selection_cost(sel, acts);\n\n    for (int it = 0; it < iters; ++it) {\n        // pick a random candidate not in selection\n        int tries = 0;\n        int b = -1;\n        while (tries < 10) {\n            int x = rng() % A;\n            if (!inSel[x]) { b = x; break; }\n            ++tries;\n        }\n        if (b == -1) continue;\n        // Try adding and prune\n        vector<int> trial = sel;\n        trial.push_back(b);\n        trial = prune_selection(move(trial), acts, M);\n        int cst = selection_cost(trial, acts);\n        if (cst < bestCost) {\n            // improved\n            sel.swap(trial);\n            fill(inSel.begin(), inSel.end(), 0);\n            for (int idx : sel) inSel[idx] = 1;\n            bestCost = cst;\n        }\n    }\n    return sel;\n}\n\n// Build baseline per-Oni plan (simple safe cycle per Oni with minimal k).\n// Always <= 840 operations for N=20.\nvector<Action> build_baseline_actions(const vector<string>& grid,\n                                      const vector<pair<int,int>>& oni_pos) {\n    int N = grid.size();\n    vector<Action> acts;\n    acts.reserve(oni_pos.size());\n\n    // Precompute Fukunokami presence for fast direction checks\n    vector<vector<int>> fuku_row_prefix(N, vector<int>(N+1, 0));\n    vector<vector<int>> fuku_col_prefix(N, vector<int>(N+1, 0));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            fuku_row_prefix[i][j+1] = fuku_row_prefix[i][j] + (grid[i][j] == 'o');\n            fuku_col_prefix[j][i+1] = fuku_col_prefix[j][i] + (grid[i][j] == 'o');\n        }\n    }\n    auto no_fuku_row = [&](int r, int l, int rgt) -> bool { // inclusive l..rgt\n        if (l > rgt) return true;\n        return (fuku_row_prefix[r][rgt+1] - fuku_row_prefix[r][l]) == 0;\n    };\n    auto no_fuku_col = [&](int c, int top, int bot) -> bool {\n        if (top > bot) return true;\n        return (fuku_col_prefix[c][bot+1] - fuku_col_prefix[c][top]) == 0;\n    };\n\n    for (auto [i, j] : oni_pos) {\n        vector<pair<int,pair<char,int>>> cand; // cost, (dir, k)\n        // Up\n        if (no_fuku_col(j, 0, i-1)) {\n            int k = i + 1;\n            cand.push_back({2*k, {'U', k}});\n        }\n        // Down\n        if (no_fuku_col(j, i+1, N-1)) {\n            int k = N - i;\n            cand.push_back({2*k, {'D', k}});\n        }\n        // Left\n        if (no_fuku_row(i, 0, j-1)) {\n            int k = j + 1;\n            cand.push_back({2*k, {'L', k}});\n        }\n        // Right\n        if (no_fuku_row(i, j+1, N-1)) {\n            int k = N - j;\n            cand.push_back({2*k, {'R', k}});\n        }\n        if (cand.empty()) continue; // should not happen due to guarantees\n        // choose minimal cost\n        auto best = min_element(cand.begin(), cand.end(),\n                                [](auto& a, auto& b){ return a.first < b.first; });\n        Action a; a.d = best->second.first; a.p = (a.d == 'L' || a.d == 'R') ? i : j; a.k = best->second.second; a.cost = best->first;\n        acts.push_back(move(a));\n    }\n    return acts;\n}\n\n// Convert action list (selected indices) to the list of primitive operations\nvector<pair<char,int>> actions_to_ops(const vector<int>& sel, const vector<Action>& acts) {\n    vector<pair<char,int>> ops;\n    long long total = 0;\n    for (int idx : sel) total += acts[idx].cost;\n    ops.reserve((size_t)total);\n    for (int idx : sel) {\n        const auto& a = acts[idx];\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(a.d, a.p);\n        char od = opposite(a.d);\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(od, a.p);\n    }\n    return ops;\n}\nvector<pair<char,int>> actions_to_ops_direct(const vector<Action>& acts) {\n    vector<pair<char,int>> ops;\n    long long total = 0;\n    for (auto& a : acts) total += a.cost;\n    ops.reserve((size_t)total);\n    for (auto& a : acts) {\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(a.d, a.p);\n        char od = opposite(a.d);\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(od, a.p);\n    }\n    return ops;\n}\n\n// Simulator for verification\npair<int,int> simulate(const vector<string>& init, const vector<pair<char,int>>& ops) {\n    int N = init.size();\n    vector<string> g = init;\n    int rem_oni = 0, rem_fuku = 0;\n    for (auto& row : g) {\n        for (char ch : row) {\n            if (ch == 'x') rem_oni++;\n            else if (ch == 'o') rem_fuku++;\n        }\n    }\n    int removed_oni = 0, removed_fuku = 0;\n    for (auto [d,p] : ops) {\n        if (d == 'L') {\n            char out = g[p][0];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int j = 0; j < N-1; ++j) g[p][j] = g[p][j+1];\n            g[p][N-1] = '.';\n        } else if (d == 'R') {\n            char out = g[p][N-1];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\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            char out = g[0][p];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int i = 0; i < N-1; ++i) g[i][p] = g[i+1][p];\n            g[N-1][p] = '.';\n        } else { // 'D'\n            char out = g[N-1][p];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int i = N-1; i >= 1; --i) g[i][p] = g[i-1][p];\n            g[0][p] = '.';\n        }\n    }\n    int X = rem_oni - removed_oni;\n    int Y = removed_fuku;\n    return {X, Y};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n\n    // Collect Oni positions and ID map\n    vector<pair<int,int>> oni_pos;\n    vector<vector<int>> oni_id(N, vector<int>(N, -1));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (grid[i][j] == 'x') {\n                int id = (int)oni_pos.size();\n                oni_pos.emplace_back(i, j);\n                oni_id[i][j] = id;\n            }\n        }\n    }\n    int M = (int)oni_pos.size();\n\n    // Build candidates and run greedy multi-start with pruning and local improvement\n    vector<Action> candidates = build_candidates(grid, oni_pos, oni_id);\n\n    std::mt19937 rng(712367 + (uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    Plan bestPlan;\n    bestPlan.cost = INT_MAX;\n\n    int trials = 20; // number of random greedy restarts\n    for (int t = 0; t < trials; ++t) {\n        vector<int> sel = greedy_select(candidates, M, rng);\n        sel = local_improvement(sel, candidates, M, rng, 150);\n        int cst = selection_cost(sel, candidates);\n        if (cst < bestPlan.cost) {\n            bestPlan.indices = sel;\n            bestPlan.cost = cst;\n        }\n    }\n\n    // Build baseline plan as a fallback and also to compare\n    vector<Action> baselineActs = build_baseline_actions(grid, oni_pos);\n    int baselineCost = 0; for (auto& a : baselineActs) baselineCost += a.cost;\n\n    // Choose the better of greedy and baseline\n    vector<pair<char,int>> opsGreedy = actions_to_ops(bestPlan.indices, candidates);\n    auto checkGreedy = simulate(grid, opsGreedy);\n    bool greedyValid = (checkGreedy.second == 0); // Y == 0\n    // baseline\n    vector<pair<char,int>> opsBase = actions_to_ops_direct(baselineActs);\n    auto checkBase = simulate(grid, opsBase);\n    bool baseValid = (checkBase.second == 0);\n\n    // Prefer valid plans; among valid, choose fewer operations\n    vector<pair<char,int>> ops;\n    if (greedyValid && baseValid) {\n        if ((int)opsGreedy.size() <= (int)opsBase.size()) ops = move(opsGreedy);\n        else ops = move(opsBase);\n    } else if (greedyValid) {\n        ops = move(opsGreedy);\n    } else if (baseValid) {\n        ops = move(opsBase);\n    } else {\n        // As a last resort (shouldn't happen), output no moves\n        ops.clear();\n    }\n\n    // Output operations, one per line: \"d p\"\n    // Ensure not exceeding 4N^2 = 1600\n    if ((int)ops.size() > 4*N*N) {\n        // Truncate (shouldn't happen). But truncation may be invalid; better output baseline if valid and smaller.\n        if (baseValid && (int)opsBase.size() <= 4*N*N) {\n            ops = move(opsBase);\n        } else if (greedyValid && (int)opsGreedy.size() <= 4*N*N) {\n            ops = move(opsGreedy);\n        } else {\n            // emergency: no output\n            ops.clear();\n        }\n    }\n    for (auto &op : ops) {\n        cout << op.first << ' ' << op.second << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed_ms() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double, std::milli>(now - st).count();\n    }\n};\n\nstruct Candidate {\n    vector<int> a, b;\n    long long E = (1LL<<62);\n    vector<int> t;\n};\n\n// Build ascending-T cycle for a-edges, with random tie-breaking within equal T.\n// Also compute D[j] = 2*T[j] - T[prev_of_j_in_cycle], guaranteed >= 0 by ascending order.\nstatic void build_cycle_and_residuals(const vector<int>& T, mt19937_64 &rng,\n                                      vector<int>& a, vector<long long>& D,\n                                      vector<int>& order, vector<int>& pos) {\n    int N = (int)T.size();\n    order.resize(N);\n    iota(order.begin(), order.end(), 0);\n    // Random tie-breaking: shuffle then stable-sort by T\n    shuffle(order.begin(), order.end(), rng);\n    stable_sort(order.begin(), order.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    pos.assign(N, -1);\n    for (int k = 0; k < N; ++k) pos[order[k]] = k;\n\n    a.assign(N, 0);\n    D.assign(N, 0);\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    }\n    for (int k = 0; k < N; ++k) {\n        int j = order[k];\n        int prev = order[(k-1+N)%N];\n        long long Dj = 2LL * T[j] - (long long)T[prev];\n        if (Dj < 0) Dj = 0; // should not happen with ascending order, but guard\n        D[j] = Dj;\n    }\n}\n\n// Greedy assignment of b-edges (one per node) to minimize sum of abs residuals.\n// r is residual capacity array initialized to D.\nstatic void greedy_assign_b(const vector<int>& T, vector<long long>& r,\n                            mt19937_64 &rng, vector<int>& b) {\n    int N = (int)T.size();\n    b.assign(N, 0);\n    vector<int> items(N);\n    iota(items.begin(), items.end(), 0);\n    // Sort items by descending weight; tie-break randomly via initial shuffle\n    shuffle(items.begin(), items.end(), rng);\n    stable_sort(items.begin(), items.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] > T[j];\n        return i < j;\n    });\n\n    for (int idx = 0; idx < N; ++idx) {\n        int i = items[idx];\n        long long w = T[i];\n        long long bestDelta = (1LL<<62);\n        vector<int> cands;\n        cands.reserve(8);\n        for (int j = 0; j < N; ++j) {\n            long long rj = r[j];\n            long long delta = llabs(rj - w) - llabs(rj);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                cands.clear();\n                cands.push_back(j);\n            } else if (delta == bestDelta) {\n                cands.push_back(j);\n            }\n        }\n        // choose randomly among candidates\n        int j = cands[rng() % cands.size()];\n        b[i] = j;\n        r[j] -= w;\n    }\n}\n\n// Local improvement: move single items from oversupplied bins to undersupplied bins if it reduces sum|r|.\nstatic void local_improve_moves(const vector<int>& T, vector<long long>& r,\n                                vector<int>& b, mt19937_64 &rng, int max_passes = 3) {\n    int N = (int)T.size();\n    vector<vector<int>> itemsOfBin(N);\n    itemsOfBin.assign(N, {});\n    for (int i = 0; i < N; ++i) {\n        itemsOfBin[b[i]].push_back(i);\n    }\n\n    for (int pass = 0; pass < max_passes; ++pass) {\n        bool changed_any = false;\n        // Build lists of deficit and oversupply bins\n        vector<int> deficits, overs;\n        deficits.reserve(N);\n        overs.reserve(N);\n        for (int j = 0; j < N; ++j) {\n            if (r[j] < 0) deficits.push_back(j);\n            else if (r[j] > 0) overs.push_back(j);\n        }\n        // Shuffle order to add randomness\n        shuffle(deficits.begin(), deficits.end(), rng);\n        shuffle(overs.begin(), overs.end(), rng);\n\n        for (int k : deficits) {\n            long long bestGain = 0; // we want negative delta (gain)\n            int bestFromBin = -1;\n            int bestItem = -1;\n            for (int j : overs) {\n                // skip empty bins\n                if (itemsOfBin[j].empty()) continue;\n                long long rj = r[j], rk = r[k];\n                for (int ii : itemsOfBin[j]) {\n                    long long w = T[ii];\n                    long long delta = llabs(rj - w) + llabs(rk + w) - (llabs(rj) + llabs(rk));\n                    if (delta < bestGain) {\n                        bestGain = delta;\n                        bestFromBin = j;\n                        bestItem = ii;\n                    }\n                }\n            }\n            if (bestItem != -1) {\n                // apply move: from bestFromBin to k\n                int j = bestFromBin;\n                int ii = bestItem;\n                long long w = T[ii];\n                // update bins\n                r[j] -= w;\n                r[k] += w;\n                // update items lists\n                auto &vecJ = itemsOfBin[j];\n                auto &vecK = itemsOfBin[k];\n                // remove ii from vecJ\n                for (int idx = 0; idx < (int)vecJ.size(); ++idx) {\n                    if (vecJ[idx] == ii) {\n                        vecJ[idx] = vecJ.back();\n                        vecJ.pop_back();\n                        break;\n                    }\n                }\n                vecK.push_back(ii);\n                b[ii] = k;\n                changed_any = true;\n            }\n        }\n        if (!changed_any) break;\n    }\n}\n\n// Simulate rotor-router for L steps and compute t_i and E = sum |t_i - T_i|\nstatic long long simulate_error(const vector<int>& a, const vector<int>& b,\n                                int L, const vector<int>& T, vector<int>& t_out) {\n    int N = (int)a.size();\n    vector<int> t(N, 0);\n    int cur = 0;\n    for (int step = 0; step < L; ++step) {\n        t[cur] += 1;\n        if (t[cur] & 1) cur = a[cur];\n        else cur = b[cur];\n    }\n    long long E = 0;\n    for (int i = 0; i < N; ++i) {\n        E += llabs((long long)t[i] - (long long)T[i]);\n    }\n    t_out = move(t);\n    return E;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, L;\n    if (!(cin >> N >> L)) return 0;\n    vector<int> T(N);\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    Timer timer;\n    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    Candidate best;\n    best.a.assign(N, 0);\n    best.b.assign(N, 0);\n    best.t.assign(N, 0);\n    best.E = (1LL<<62);\n\n    // Time budget (ms)\n    const double TIME_LIMIT_MS = 1950.0;\n\n    // Generate multiple randomized candidates within time\n    int iter = 0;\n    while (true) {\n        double elapsed = timer.elapsed_ms();\n        if (elapsed > TIME_LIMIT_MS) break;\n        ++iter;\n\n        vector<int> a, b;\n        vector<long long> D;\n        vector<int> order, pos;\n        build_cycle_and_residuals(T, rng, a, D, order, pos);\n\n        // Residuals for assigning b\n        vector<long long> r = D;\n        b.assign(N, 0);\n        greedy_assign_b(T, r, rng, b);\n\n        // Local improvement but keep it cheap\n        local_improve_moves(T, r, b, rng, 2);\n\n        // Simulate\n        vector<int> t;\n        long long E = simulate_error(a, b, L, T, t);\n\n        if (E < best.E) {\n            best.a = a;\n            best.b = b;\n            best.E = E;\n            best.t = t;\n        }\n\n        // Try variations: modest extra random restarts\n        if (timer.elapsed_ms() > TIME_LIMIT_MS) break;\n    }\n\n    // Output best found\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    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x ? x : p[x]=find(p[x]); }\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; sz[a]+=sz[b];\n        return true;\n    }\n};\n\nstatic inline uint64_t morton_code(uint32_t x, uint32_t y) {\n    // Interleave lower 15 bits of x and y: bit 0 of x in bit 0, bit 0 of y in bit 1, etc.\n    // Works for coordinates up to < 2^15 (32768), and our coords <= 10000.\n    uint64_t code = 0;\n    for (int i = 0; i < 15; ++i) {\n        code |= (uint64_t)((x >> i) & 1u) << (2*i);\n        code |= (uint64_t)((y >> i) & 1u) << (2*i + 1);\n    }\n    return code;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, Q, L, W;\n    if (!(cin >> N >> M >> Q >> L >> W)) return 0;\n    vector<int> G(M);\n    for(int i=0;i<M;i++) cin >> G[i];\n    vector<int> lx(N), rx(N), ly(N), ry(N);\n    for(int i=0;i<N;i++){\n        cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n    }\n\n    // Estimated coordinates: centers\n    vector<int> xc(N), yc(N);\n    for(int i=0;i<N;i++){\n        xc[i] = (lx[i] + rx[i]) / 2;\n        yc[i] = (ly[i] + ry[i]) / 2;\n    }\n\n    // Sort by Morton (Z-order)\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    vector<uint64_t> code(N);\n    for(int i=0;i<N;i++){\n        code[i] = morton_code((uint32_t)xc[i], (uint32_t)yc[i]);\n    }\n    sort(ord.begin(), ord.end(), [&](int a, int b){ return code[a] < code[b]; });\n\n    // Build groups as contiguous segments along ord\n    vector<vector<int>> groups(M);\n    int ptr = 0;\n    for(int k=0;k<M;k++){\n        groups[k].reserve(G[k]);\n        for(int t=0; t<G[k]; ++t){\n            groups[k].push_back(ord[ptr++]);\n        }\n    }\n\n    auto dist2_est = [&](int u, int v)->long long{\n        long long dx = xc[u] - xc[v];\n        long long dy = yc[u] - yc[v];\n        return dx*dx + dy*dy;\n    };\n\n    // Query function\n    auto do_query = [&](const vector<int>& subset)->vector<pair<int,int>>{\n        int l = (int)subset.size();\n        cout << \"? \" << l;\n        for(int i=0;i<l;i++) cout << \" \" << subset[i];\n        cout << \"\\n\" << flush;\n        vector<pair<int,int>> res;\n        res.reserve(max(0, l-1));\n        for(int i=0;i<l-1;i++){\n            int a,b;\n            cin >> a >> b;\n            res.emplace_back(a,b);\n        }\n        return res;\n    };\n\n    int queries_used = 0;\n\n    // Storage for oracle edges per group\n    vector<vector<pair<int,int>>> oracle_edges(M);\n\n    // Step 1: fully query small groups (G_i <= L), prioritize larger first\n    vector<int> small_groups;\n    small_groups.reserve(M);\n    for(int k=0;k<M;k++) if (G[k] <= L && G[k] >= 2) small_groups.push_back(k);\n    sort(small_groups.begin(), small_groups.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 k : small_groups) {\n        if (queries_used >= Q) break;\n        // Query entire group of size G[k]\n        vector<int> subset = groups[k];\n        auto res = do_query(subset);\n        ++queries_used;\n        oracle_edges[k].insert(oracle_edges[k].end(), res.begin(), res.end());\n    }\n\n    // Step 2: Use remaining queries to query L-sized windows inside large groups\n    if (queries_used < Q) {\n        struct Window { long long score; int k; int start; };\n        vector<Window> cand;\n        for (int k = 0; k < M; ++k) {\n            if (G[k] > L) {\n                // Precompute neighbor sums to evaluate contiguous windows quickly\n                int sz = G[k];\n                const auto &grp = groups[k];\n                vector<long long> neigh(sz-1);\n                for (int i = 0; i < sz-1; ++i) {\n                    neigh[i] = dist2_est(grp[i], grp[i+1]);\n                }\n                vector<long long> pref(sz);\n                pref[0] = 0;\n                for (int i = 0; i < sz-1; ++i) pref[i+1] = pref[i] + neigh[i];\n                // Consider non-overlapping starts s = 0, L, 2L, ..., plus ensure last block\n                for (int s = 0; s + L <= sz; s += L) {\n                    long long score = pref[s+L-1] - pref[s];\n                    cand.push_back({score, k, s});\n                }\n                int last_s = sz - L;\n                if (last_s >= 0) {\n                    long long score = pref[last_s+L-1] - pref[last_s];\n                    cand.push_back({score, k, last_s});\n                }\n            }\n        }\n        sort(cand.begin(), cand.end(), [](const Window& a, const Window& b){\n            if (a.score != b.score) return a.score < b.score;\n            if (a.k != b.k) return a.k < b.k;\n            return a.start < b.start;\n        });\n        // Avoid querying same window twice\n        unordered_set<long long> usedWin; usedWin.reserve(cand.size()*2+1);\n        auto encKey = [&](int k, int s)->long long { return ((long long)k<<32) ^ (long long)s; };\n        for (auto &w : cand) {\n            if (queries_used >= Q) break;\n            long long key = encKey(w.k, w.start);\n            if (usedWin.count(key)) continue;\n            usedWin.insert(key);\n            vector<int> subset;\n            subset.reserve(L);\n            for (int i = w.start; i < w.start + L; ++i) subset.push_back(groups[w.k][i]);\n            auto res = do_query(subset);\n            ++queries_used;\n            oracle_edges[w.k].insert(oracle_edges[w.k].end(), res.begin(), res.end());\n        }\n    }\n\n    // After queries, build final answer\n    cout << \"!\" << \"\\n\";\n\n    // Helper: approximate MST edges via Prim using estimated positions\n    auto approx_mst_edges = [&](const vector<int>& nodes)->vector<pair<int,int>>{\n        int n = (int)nodes.size();\n        vector<char> used(n, 0);\n        const long long INF = (1LL<<60);\n        vector<long long> best(n, INF);\n        vector<int> parent(n, -1);\n        best[0] = 0;\n        vector<pair<int,int>> edges;\n        edges.reserve(max(0, n-1));\n        for (int it = 0; it < n; ++it) {\n            int v = -1;\n            long long bv = INF;\n            for (int i = 0; i < n; ++i) if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n            if (v == -1) break; // should not happen\n            used[v] = 1;\n            if (parent[v] != -1) {\n                edges.emplace_back(nodes[parent[v]], nodes[v]);\n            }\n            for (int u = 0; u < n; ++u) if (!used[u]) {\n                long long d2 = dist2_est(nodes[v], nodes[u]);\n                if (d2 < best[u]) {\n                    best[u] = d2;\n                    parent[u] = v;\n                }\n            }\n        }\n        return edges;\n    };\n\n    // To map node id to local index for DSU quickly\n    vector<int> id2pos(N, -1);\n\n    for (int k = 0; k < M; ++k) {\n        const auto &grp = groups[k];\n        int sz = (int)grp.size();\n\n        // Print city IDs for this group\n        for (int i = 0; i < sz; ++i) {\n            if (i) cout << \" \";\n            cout << grp[i];\n        }\n        cout << \"\\n\";\n\n        if (sz <= 1) {\n            // No edges for single-city group\n            continue;\n        }\n\n        // Prepare local index mapping\n        for (int i = 0; i < sz; ++i) id2pos[grp[i]] = i;\n\n        // Deduplicate oracle edges and keep only those within this group\n        vector<pair<int,int>> forced;\n        forced.reserve(oracle_edges[k].size());\n        {\n            unordered_set<long long> seen;\n            seen.reserve(oracle_edges[k].size()*2+1);\n            auto encEdge = [&](int a, int b)->long long {\n                if (a > b) swap(a,b);\n                return ((long long)a<<32) ^ (long long)b;\n            };\n            for (auto &e : oracle_edges[k]) {\n                int a = e.first, b = e.second;\n                if (a == b) continue;\n                if (id2pos[a] == -1 || id2pos[b] == -1) continue; // paranoid check\n                long long key = encEdge(a,b);\n                if (!seen.count(key)) {\n                    seen.insert(key);\n                    forced.emplace_back(a,b);\n                }\n            }\n        }\n\n        // Build approximate MST edges\n        vector<pair<int,int>> approx = approx_mst_edges(grp);\n\n        // Merge: include forced edges first, then approx edges to connect all\n        DSU dsu(sz);\n        vector<pair<int,int>> final_edges;\n        final_edges.reserve(sz - 1);\n\n        auto try_add = [&](int u, int v){\n            int iu = id2pos[u], iv = id2pos[v];\n            if (iu == -1 || iv == -1) return;\n            if (dsu.unite(iu, iv)) {\n                final_edges.emplace_back(u, v);\n            }\n        };\n\n        for (auto &e : forced) {\n            if ((int)final_edges.size() == sz-1) break;\n            try_add(e.first, e.second);\n        }\n        for (auto &e : approx) {\n            if ((int)final_edges.size() == sz-1) break;\n            try_add(e.first, e.second);\n        }\n\n        // Fallback if still not connected (should be rare)\n        if ((int)final_edges.size() < sz - 1) {\n            int root_id = grp[0];\n            for (int i = 1; i < sz && (int)final_edges.size() < sz-1; ++i) {\n                try_add(root_id, grp[i]);\n            }\n        }\n\n        // Print edges\n        for (auto &e : final_edges) {\n            cout << e.first << \" \" << e.second << \"\\n\";\n        }\n\n        // Clean mapping\n        for (int i = 0; i < sz; ++i) id2pos[grp[i]] = -1;\n    }\n\n    cout.flush();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Step {\n    char a; // 'M' or 'S'\n    char d; // 'U','D','L','R'\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    vector<pair<int,int>> P(M);\n    for (int k = 0; k < M; ++k) {\n        cin >> P[k].first >> P[k].second;\n    }\n\n    // Directions: 0:U, 1:D, 2:L, 3: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 i, int j) -> bool {\n        return (0 <= i && i < N && 0 <= j && j < N);\n    };\n\n    auto id = [&](int i, int j) -> int {\n        return i * N + j;\n    };\n\n    auto coord = [&](int idx) -> pair<int,int> {\n        return {idx / N, idx % N};\n    };\n\n    // Since we never alter, slide destinations are always to the boundary.\n    auto slide_dest = [&](int i, int j, int d) -> pair<int,int> {\n        if (d == 0) return make_pair(0, j);        // Up to row 0\n        if (d == 1) return make_pair(N - 1, j);    // Down to row N-1\n        if (d == 2) return make_pair(i, 0);        // Left to col 0\n        return make_pair(i, N - 1);                // Right to col N-1\n    };\n\n    // BFS between two points with Move and Slide only\n    auto bfs = [&](pair<int,int> s, pair<int,int> t) -> vector<Step> {\n        int NN = N * N;\n        vector<int> par(NN, -1);\n        vector<char> how(NN, 0);   // 'M' or 'S'\n        vector<char> hdir(NN, 0);  // 'U','D','L','R'\n        vector<char> vis(NN, 0);\n        queue<int> q;\n\n        int sId = id(s.first, s.second);\n        int tId = id(t.first, t.second);\n        vis[sId] = 1;\n        q.push(sId);\n\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            if (u == tId) break;\n            auto [ui, uj] = coord(u);\n\n            // Try Moves\n            for (int d = 0; d < 4; ++d) {\n                int vi = ui + di[d];\n                int vj = uj + dj[d];\n                if (!inside(vi, vj)) continue;\n                int v = id(vi, vj);\n                if (!vis[v]) {\n                    vis[v] = 1;\n                    par[v] = u;\n                    how[v] = 'M';\n                    hdir[v] = dch[d];\n                    q.push(v);\n                    if (v == tId) goto bfs_end;\n                }\n            }\n            // Try Slides\n            for (int d = 0; d < 4; ++d) {\n                auto [vi, vj] = slide_dest(ui, uj, d);\n                if (vi == ui && vj == uj) continue; // sliding into same cell is pointless\n                int v = id(vi, vj);\n                if (!vis[v]) {\n                    vis[v] = 1;\n                    par[v] = u;\n                    how[v] = 'S';\n                    hdir[v] = dch[d];\n                    q.push(v);\n                    if (v == tId) goto bfs_end;\n                }\n            }\n        }\n    bfs_end:;\n\n        vector<Step> path;\n        if (!vis[tId]) {\n            // Should not happen in an empty grid; fallback to empty\n            return path;\n        }\n        int cur = tId;\n        while (cur != sId) {\n            Step st{how[cur], hdir[cur]};\n            path.push_back(st);\n            cur = par[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    };\n\n    vector<Step> ans;\n    long long maxActions = 2LL * N * M; // hard cap\n\n    pair<int,int> cur = P[0];\n    for (int k = 1; k < M; ++k) {\n        auto path = bfs(cur, P[k]);\n        // Ensure we don't exceed the cap\n        if ((long long)ans.size() + (long long)path.size() > maxActions) {\n            long long rem = maxActions - (long long)ans.size();\n            rem = max(0LL, rem);\n            for (long long i = 0; i < rem; ++i) ans.push_back(path[i]);\n            // Reached cap; stop emitting further actions\n            break;\n        } else {\n            for (auto &st : path) ans.push_back(st);\n            cur = P[k];\n        }\n    }\n\n    // Output actions\n    for (auto &st : ans) {\n        cout << st.a << ' ' << st.d << '\\n';\n    }\n    return 0;\n}"},"4":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Solver {\n    static constexpr int LIMIT_COORD = 10000;\n\n    int n;\n    vector<int> x, y;\n    vector<int> r;\n    vector<Rect> rects;\n\n    mt19937_64 rng;\n    Timer timer;\n    double time_limit;\n\n    Solver(int n_, vector<int> x_, vector<int> y_, vector<int> r_, double tl=4.85)\n        : n(n_), x(move(x_)), y(move(y_)), r(move(r_)), time_limit(tl) {\n        rects.resize(n);\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        seed ^= (uint64_t)(uintptr_t)this;\n        rng.seed(seed);\n    }\n\n    inline ll area_of(const Rect &rc) const {\n        return (ll)(rc.c - rc.a) * (ll)(rc.d - rc.b);\n    }\n\n    inline double score_si_ri(ll s, ll ri) const {\n        if (s <= 0) return 0.0;\n        ll mn = (s < ri ? s : ri);\n        ll mx = (s > ri ? s : ri);\n        double t = (double)mn / (double)mx;\n        double d = (1.0 - t);\n        return 1.0 - d * d;\n    }\n\n    inline double score_i(int i) const {\n        return score_si_ri(area_of(rects[i]), r[i]);\n    }\n\n    // Compute maximum expansions in each direction for rectangle i against others.\n    inline void compute_allowed_expansions(int i, int &leftMax, int &rightMax, int &downMax, int &upMax) const {\n        const Rect &ri = rects[i];\n        int LBound = 0, RBound = LIMIT_COORD, DBound = 0, UBound = LIMIT_COORD;\n\n        for (int j = 0; j < n; ++j) {\n            if (j == i) continue;\n            const Rect &rj = rects[j];\n            // Horizontal expansion blocked by rectangles overlapping vertically\n            if (!(ri.d <= rj.b || rj.d <= ri.b)) {\n                if (rj.a >= ri.c) RBound = min(RBound, rj.a);\n                if (rj.c <= ri.a) LBound = max(LBound, rj.c);\n            }\n            // Vertical expansion blocked by rectangles overlapping horizontally\n            if (!(ri.c <= rj.a || rj.c <= ri.a)) {\n                if (rj.b >= ri.d) UBound = min(UBound, rj.b);\n                if (rj.d <= ri.b) DBound = max(DBound, rj.d);\n            }\n        }\n        leftMax = max(0, ri.a - LBound);\n        rightMax = max(0, RBound - ri.c);\n        downMax = max(0, ri.b - DBound);\n        upMax = max(0, UBound - ri.d);\n    }\n\n    template <class T>\n    inline T clampv(T v, T lo, T hi) const {\n        if (v < lo) return lo;\n        if (v > hi) return hi;\n        return v;\n    }\n\n    inline ll expand_horiz(int i, int delta, int leftMax, int rightMax) {\n        if (delta <= 0 || (leftMax + rightMax) <= 0) return 0;\n        Rect &ri = rects[i];\n        int h = ri.d - ri.b;\n        int maxDelta = min(delta, leftMax + rightMax);\n        // Split to keep seed near center.\n        int leftDist = x[i] - ri.a;\n        int rightDist = ri.c - x[i] - 1;\n        int diff = rightDist - leftDist;\n        int l = clampv((maxDelta + diff) / 2, 0, maxDelta);\n        l = min(l, leftMax);\n        int rTake = maxDelta - l;\n        if (rTake > rightMax) {\n            rTake = rightMax;\n            l = maxDelta - rTake;\n            l = min(l, leftMax);\n        }\n        if (l > 0) ri.a -= l;\n        if (rTake > 0) ri.c += rTake;\n        return (ll)h * (ll)(l + rTake);\n    }\n\n    inline ll expand_vert(int i, int delta, int downMax, int upMax) {\n        if (delta <= 0 || (downMax + upMax) <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int maxDelta = min(delta, downMax + upMax);\n        int downDist = y[i] - ri.b;\n        int upDist = ri.d - y[i] - 1;\n        int d = clampv((maxDelta + (downDist - upDist)) / 2, 0, maxDelta);\n        d = min(d, downMax);\n        int uTake = maxDelta - d;\n        if (uTake > upMax) {\n            uTake = upMax;\n            d = maxDelta - uTake;\n            d = min(d, downMax);\n        }\n        if (d > 0) ri.b -= d;\n        if (uTake > 0) ri.d += uTake;\n        return (ll)w * (ll)(d + uTake);\n    }\n\n    inline ll shrink_horiz(int i, int delta) {\n        if (delta <= 0) return 0;\n        Rect &ri = rects[i];\n        int h = ri.d - ri.b;\n        int shrinkLeftMax = x[i] - ri.a;          // move 'a' right\n        int shrinkRightMax = ri.c - (x[i] + 1);   // move 'c' left\n        int cap = shrinkLeftMax + shrinkRightMax;\n        if (cap <= 0) return 0;\n\n        int maxDelta = min(delta, cap);\n        int leftDist = x[i] - ri.a;\n        int rightDist = ri.c - x[i] - 1;\n        int l = clampv((maxDelta + (leftDist - rightDist)) / 2, 0, maxDelta);\n        l = min(l, shrinkLeftMax);\n        int rTake = maxDelta - l;\n        if (rTake > shrinkRightMax) {\n            rTake = shrinkRightMax;\n            l = maxDelta - rTake;\n            l = min(l, shrinkLeftMax);\n        }\n        if (l > 0) ri.a += l;\n        if (rTake > 0) ri.c -= rTake;\n        return (ll)h * (ll)(l + rTake);\n    }\n\n    inline ll shrink_vert(int i, int delta) {\n        if (delta <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int shrinkDownMax = y[i] - ri.b;\n        int shrinkUpMax = ri.d - (y[i] + 1);\n        int cap = shrinkDownMax + shrinkUpMax;\n        if (cap <= 0) return 0;\n\n        int maxDelta = min(delta, cap);\n        int downDist = y[i] - ri.b;\n        int upDist = ri.d - y[i] - 1;\n        int d = clampv((maxDelta + (downDist - upDist)) / 2, 0, maxDelta);\n        d = min(d, shrinkDownMax);\n        int uTake = maxDelta - d;\n        if (uTake > shrinkUpMax) {\n            uTake = shrinkUpMax;\n            d = maxDelta - uTake;\n            d = min(d, shrinkDownMax);\n        }\n        if (d > 0) ri.b += d;\n        if (uTake > 0) ri.d -= uTake;\n        return (ll)w * (ll)(d + uTake);\n    }\n\n    // Adjust rectangle i towards its target area r[i]\n    bool adjust_one(int i) {\n        Rect &rc = rects[i];\n        bool changed = false;\n\n        for (int it = 0; it < 3; ++it) {\n            ll s = area_of(rc);\n            ll target = r[i];\n            int w = rc.c - rc.a;\n            int h = rc.d - rc.b;\n\n            int leftMax, rightMax, downMax, upMax;\n            compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n\n            if (s < target) {\n                bool tryH = (leftMax + rightMax) > 0;\n                bool tryV = (downMax + upMax) > 0;\n                bool horizFirst;\n                if (tryH && tryV) {\n                    if (w < h) horizFirst = true;\n                    else if (w > h) horizFirst = false;\n                    else horizFirst = true;\n                } else if (tryH) horizFirst = true;\n                else if (tryV) horizFirst = false;\n                else horizFirst = true;\n\n                if (horizFirst && tryH) {\n                    ll need = target - s;\n                    int delta = (int)min<ll>((ll)(leftMax + rightMax), need / max(1, h));\n                    if (delta > 0) {\n                        expand_horiz(i, delta, leftMax, rightMax);\n                        changed = true;\n                    }\n                }\n                s = area_of(rc);\n                if (s < target && tryV) {\n                    compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n                    w = rc.c - rc.a;\n                    ll need2 = target - s;\n                    int delta2 = (int)min<ll>((ll)(downMax + upMax), need2 / max(1, w));\n                    if (delta2 > 0) {\n                        expand_vert(i, delta2, downMax, upMax);\n                        changed = true;\n                    }\n                }\n                s = area_of(rc);\n                if (s < target) {\n                    compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n                    w = rc.c - rc.a; int h2 = rc.d - rc.b;\n                    ll bestImprove = 0;\n                    int bestMove = -1;\n                    auto clos = [&](ll si){ return llabs(si - target); };\n                    ll curClos = clos(s);\n                    if (leftMax > 0) {\n                        ll s2 = s + h2;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 0;\n                    }\n                    if (rightMax > 0) {\n                        ll s2 = s + h2;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 1;\n                    }\n                    if (downMax > 0) {\n                        ll s2 = s + w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 2;\n                    }\n                    if (upMax > 0) {\n                        ll s2 = s + w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 3;\n                    }\n                    if (bestImprove > 0) {\n                        if (bestMove == 0) rc.a -= 1;\n                        else if (bestMove == 1) rc.c += 1;\n                        else if (bestMove == 2) rc.b -= 1;\n                        else if (bestMove == 3) rc.d += 1;\n                        changed = true;\n                    }\n                }\n            } else if (s > target) {\n                ll over = s - target;\n                bool canH = ((x[i] - rc.a) + (rc.c - (x[i] + 1))) > 0;\n                bool canV = ((y[i] - rc.b) + (rc.d - (y[i] + 1))) > 0;\n                bool shrinkHFirst;\n                if (canH && canV) {\n                    if (w > h) shrinkHFirst = true;\n                    else if (w < h) shrinkHFirst = false;\n                    else shrinkHFirst = true;\n                } else if (canH) shrinkHFirst = true;\n                else if (canV) shrinkHFirst = false;\n                else shrinkHFirst = true;\n\n                if (shrinkHFirst && canH) {\n                    int delta = (int)(over / max(1, h));\n                    if (delta > 0) {\n                        ll dec = shrink_horiz(i, delta);\n                        if (dec > 0) changed = true;\n                    }\n                }\n                s = area_of(rc);\n                if (s > target && canV) {\n                    over = s - target;\n                    int delta2 = (int)(over / max(1, w));\n                    if (delta2 > 0) {\n                        ll dec2 = shrink_vert(i, delta2);\n                        if (dec2 > 0) changed = true;\n                    }\n                }\n                s = area_of(rc);\n                if (s > target) {\n                    int shrinkLeftMax = x[i] - rc.a;\n                    int shrinkRightMax = rc.c - (x[i] + 1);\n                    int shrinkDownMax = y[i] - rc.b;\n                    int shrinkUpMax = rc.d - (y[i] + 1);\n                    ll bestImprove = 0;\n                    int bestMove = -1;\n                    auto clos = [&](ll si){ return llabs(si - target); };\n                    ll curClos = clos(s);\n                    if (shrinkLeftMax > 0) {\n                        ll s2 = s - (ll)h;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 0;\n                    }\n                    if (shrinkRightMax > 0) {\n                        ll s2 = s - (ll)h;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 1;\n                    }\n                    if (shrinkDownMax > 0) {\n                        ll s2 = s - (ll)w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 2;\n                    }\n                    if (shrinkUpMax > 0) {\n                        ll s2 = s - (ll)w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 3;\n                    }\n                    if (bestImprove > 0) {\n                        if (bestMove == 0) rc.a += 1;\n                        else if (bestMove == 1) rc.c -= 1;\n                        else if (bestMove == 2) rc.b += 1;\n                        else if (bestMove == 3) rc.d -= 1;\n                        changed = true;\n                    }\n                }\n            } else {\n                break;\n            }\n\n            // Safety clamps\n            rc.a = clampv(rc.a, 0, LIMIT_COORD - 1);\n            rc.c = clampv(rc.c, rc.a + 1, LIMIT_COORD);\n            rc.b = clampv(rc.b, 0, LIMIT_COORD - 1);\n            rc.d = clampv(rc.d, rc.b + 1, LIMIT_COORD);\n            if (!(rc.a <= x[i] && x[i] < rc.c && rc.b <= y[i] && y[i] < rc.d)) {\n                rc.a = x[i]; rc.b = y[i]; rc.c = x[i] + 1; rc.d = y[i] + 1;\n                changed = true;\n            }\n        }\n        return changed;\n    }\n\n    void initial_setup() {\n        for (int i = 0; i < n; ++i) rects[i] = Rect{ x[i], y[i], x[i] + 1, y[i] + 1 };\n    }\n\n    static inline long long floordiv(long long a, long long b) {\n        if (b < 0) a = -a, b = -b;\n        if (a >= 0) return a / b;\n        else return - ((-a + b - 1) / b);\n    }\n    static inline long long ceildiv(long long a, long long b) {\n        return -floordiv(-a, b);\n    }\n\n    struct PairItem {\n        int i, j; // i left of j if vertical; i bottom of j if horizontal\n        bool vertical;\n    };\n\n    void build_fullside_pairs(vector<PairItem>& pairs) const {\n        pairs.clear();\n        for (int i = 0; i < n; ++i) {\n            const Rect &ri = rects[i];\n            for (int j = i+1; j < n; ++j) {\n                const Rect &rj = rects[j];\n                // Vertical adjacency full side\n                if (ri.c == rj.a && ri.b == rj.b && ri.d == rj.d) {\n                    pairs.push_back({i, j, true});\n                } else if (rj.c == ri.a && rj.b == ri.b && rj.d == ri.d) {\n                    pairs.push_back({j, i, true});\n                }\n                // Horizontal adjacency full side\n                if (ri.d == rj.b && ri.a == rj.a && ri.c == rj.c) {\n                    pairs.push_back({i, j, false});\n                } else if (rj.d == ri.b && rj.a == ri.a && rj.c == ri.c) {\n                    pairs.push_back({j, i, false});\n                }\n            }\n        }\n    }\n\n    double best_slide_for_pair_local(const Rect &L, const Rect &R, bool vertical, int idxL, int idxR, int &bestT) const {\n        ll sL0 = (ll)(L.c - L.a) * (ll)(L.d - L.b);\n        ll sR0 = (ll)(R.c - R.a) * (ll)(R.d - R.b);\n        double base = score_si_ri(sL0, r[idxL]) + score_si_ri(sR0, r[idxR]);\n\n        int tmin, tmax, unit;\n        if (vertical) {\n            tmin = (x[idxL] + 1) - L.c;\n            tmax = x[idxR] - R.a;\n            unit = L.d - L.b;\n        } else {\n            tmin = (y[idxL] + 1) - L.d;\n            tmax = y[idxR] - R.b;\n            unit = L.c - L.a;\n        }\n        if (unit <= 0) { bestT = 0; return base; }\n        if (tmin > tmax) { bestT = 0; return base; }\n\n        vector<int> cand;\n        auto push_cand = [&](long long t) {\n            if (t < tmin) t = tmin;\n            if (t > tmax) t = tmax;\n            int ti = (int)t;\n            for (int v : cand) if (v == ti) return;\n            cand.push_back(ti);\n        };\n        push_cand(0);\n        push_cand(tmin);\n        push_cand(tmax);\n\n        long long di = (long long)r[idxL] - sL0;\n        long long ti_floor = floordiv(di, unit);\n        long long ti_ceil = ceildiv(di, unit);\n        push_cand(ti_floor);\n        push_cand(ti_floor - 1);\n        push_cand(ti_floor + 1);\n        push_cand(ti_ceil);\n        push_cand(ti_ceil - 1);\n        push_cand(ti_ceil + 1);\n\n        long long dj = sR0 - (long long)r[idxR];\n        long long tj_floor = floordiv(dj, unit);\n        long long tj_ceil = ceildiv(dj, unit);\n        push_cand(tj_floor);\n        push_cand(tj_floor - 1);\n        push_cand(tj_floor + 1);\n        push_cand(tj_ceil);\n        push_cand(tj_ceil - 1);\n        push_cand(tj_ceil + 1);\n\n        double bestVal = base;\n        int best = 0;\n        for (int t : cand) {\n            ll sL = sL0 + (ll)unit * (ll)t;\n            ll sR = sR0 - (ll)unit * (ll)t;\n            double val = score_si_ri(sL, r[idxL]) + score_si_ri(sR, r[idxR]);\n            if (val > bestVal + 1e-15) {\n                bestVal = val;\n                best = t;\n            }\n        }\n        bestT = best;\n        return bestVal;\n    }\n\n    bool slide_pairs_pass() {\n        vector<PairItem> pairs;\n        build_fullside_pairs(pairs);\n        if (pairs.empty()) return false;\n\n        shuffle(pairs.begin(), pairs.end(), rng);\n\n        bool anyImproved = false;\n        for (const auto &pi : pairs) {\n            int i = pi.i, j = pi.j;\n            const Rect &ri = rects[i];\n            const Rect &rj = rects[j];\n\n            ll si0 = area_of(ri);\n            ll sj0 = area_of(rj);\n            double base = score_si_ri(si0, r[i]) + score_si_ri(sj0, r[j]);\n\n            int tmin = 0, tmax = 0, unit = 1;\n            if (pi.vertical) {\n                tmin = (x[i] + 1) - ri.c;\n                tmax = x[j] - rj.a;\n                unit = ri.d - ri.b;\n            } else {\n                tmin = (y[i] + 1) - ri.d;\n                tmax = y[j] - rj.b;\n                unit = ri.c - ri.a;\n            }\n            if (unit <= 0 || tmin > tmax) continue;\n\n            vector<int> cand;\n            auto push_cand = [&](long long t) {\n                if (t < tmin) t = tmin;\n                if (t > tmax) t = tmax;\n                int ti = (int)t;\n                for (int v : cand) if (v == ti) return;\n                cand.push_back(ti);\n            };\n            push_cand(0);\n            push_cand(tmin);\n            push_cand(tmax);\n\n            long long di = (long long)r[i] - si0;\n            long long ti_floor = floordiv(di, unit);\n            long long ti_ceil = ceildiv(di, unit);\n            push_cand(ti_floor);\n            push_cand(ti_floor - 1);\n            push_cand(ti_floor + 1);\n            push_cand(ti_ceil);\n            push_cand(ti_ceil - 1);\n            push_cand(ti_ceil + 1);\n\n            long long dj = sj0 - (long long)r[j];\n            long long tj_floor = floordiv(dj, unit);\n            long long tj_ceil = ceildiv(dj, unit);\n            push_cand(tj_floor);\n            push_cand(tj_floor - 1);\n            push_cand(tj_floor + 1);\n            push_cand(tj_ceil);\n            push_cand(tj_ceil - 1);\n            push_cand(tj_ceil + 1);\n\n            double bestVal = base;\n            int bestT = 0;\n            for (int t : cand) {\n                ll si = si0 + (ll)unit * (ll)t;\n                ll sj = sj0 - (ll)unit * (ll)t;\n                double val = score_si_ri(si, r[i]) + score_si_ri(sj, r[j]);\n                if (val > bestVal + 1e-15) {\n                    bestVal = val;\n                    bestT = t;\n                }\n            }\n\n            if (bestT != 0) {\n                if (pi.vertical) {\n                    rects[i].c += bestT;\n                    rects[j].a += bestT;\n                } else {\n                    rects[i].d += bestT;\n                    rects[j].b += bestT;\n                }\n                anyImproved = true;\n            }\n\n            if (timer.elapsed() > time_limit * 0.95) break;\n        }\n        return anyImproved;\n    }\n\n    // Try to align partially adjacent pairs into full-side neighbors using free space, then slide.\n    bool align_pairs_pass() {\n        bool anyImproved = false;\n\n        // Vertical adjacency alignment\n        for (int i = 0; i < n; ++i) {\n            if (timer.elapsed() > time_limit * 0.92) break;\n            for (int j = i + 1; j < n; ++j) {\n                Rect Li, Rj;\n                int idxL = -1, idxR = -1;\n                // Check vertical adjacency (touching boundary)\n                if (rects[i].c == rects[j].a) {\n                    idxL = i; idxR = j; Li = rects[i]; Rj = rects[j];\n                } else if (rects[j].c == rects[i].a) {\n                    idxL = j; idxR = i; Li = rects[j]; Rj = rects[i];\n                } else {\n                    continue;\n                }\n                // Already full side?\n                if (Li.b == Rj.b && Li.d == Rj.d) continue;\n\n                // union Y range\n                int minb = min(Li.b, Rj.b);\n                int maxd = max(Li.d, Rj.d);\n\n                int needDownL = Li.b - minb;\n                int needUpL = maxd - Li.d;\n                int needDownR = Rj.b - minb;\n                int needUpR = maxd - Rj.d;\n\n                int lL, rL, dL, uL, lR, rR, dR, uR;\n                compute_allowed_expansions(idxL, lL, rL, dL, uL);\n                compute_allowed_expansions(idxR, lR, rR, dR, uR);\n\n                if (needDownL <= dL && needUpL <= uL && needDownR <= dR && needUpR <= uR) {\n                    // Hypothetical rectangles after alignment\n                    Rect L2 = Li, R2 = Rj;\n                    L2.b -= needDownL; L2.d += needUpL;\n                    R2.b -= needDownR; R2.d += needUpR;\n\n                    int bestT = 0;\n                    double base = score_si_ri(area_of(rects[idxL]), r[idxL]) + score_si_ri(area_of(rects[idxR]), r[idxR]);\n                    double bestVal = best_slide_for_pair_local(L2, R2, true, idxL, idxR, bestT);\n                    if (bestVal > base + 1e-12) {\n                        // Commit alignment and slide\n                        rects[idxL] = L2;\n                        rects[idxR] = R2;\n                        rects[idxL].c += bestT;\n                        rects[idxR].a += bestT;\n                        anyImproved = true;\n                    }\n                }\n            }\n        }\n\n        // Horizontal adjacency alignment\n        for (int i = 0; i < n; ++i) {\n            if (timer.elapsed() > time_limit * 0.94) break;\n            for (int j = i + 1; j < n; ++j) {\n                Rect Bi, Tj;\n                int idxB = -1, idxT = -1;\n                // Check horizontal adjacency\n                if (rects[i].d == rects[j].b) {\n                    idxB = i; idxT = j; Bi = rects[i]; Tj = rects[j];\n                } else if (rects[j].d == rects[i].b) {\n                    idxB = j; idxT = i; Bi = rects[j]; Tj = rects[i];\n                } else {\n                    continue;\n                }\n                // Already full side?\n                if (Bi.a == Tj.a && Bi.c == Tj.c) continue;\n\n                // union X range\n                int mina = min(Bi.a, Tj.a);\n                int maxc = max(Bi.c, Tj.c);\n\n                int needLeftB = Bi.a - mina;\n                int needRightB = maxc - Bi.c;\n                int needLeftT = Tj.a - mina;\n                int needRightT = maxc - Tj.c;\n\n                int lB, rB, dB, uB, lT, rT, dT, uT;\n                compute_allowed_expansions(idxB, lB, rB, dB, uB);\n                compute_allowed_expansions(idxT, lT, rT, dT, uT);\n\n                if (needLeftB <= lB && needRightB <= rB && needLeftT <= lT && needRightT <= rT) {\n                    Rect B2 = Bi, T2 = Tj;\n                    B2.a -= needLeftB; B2.c += needRightB;\n                    T2.a -= needLeftT; T2.c += needRightT;\n\n                    int bestT = 0;\n                    double base = score_si_ri(area_of(rects[idxB]), r[idxB]) + score_si_ri(area_of(rects[idxT]), r[idxT]);\n                    double bestVal = best_slide_for_pair_local(B2, T2, false, idxB, idxT, bestT);\n                    if (bestVal > base + 1e-12) {\n                        rects[idxB] = B2;\n                        rects[idxT] = T2;\n                        rects[idxB].d += bestT;\n                        rects[idxT].b += bestT;\n                        anyImproved = true;\n                    }\n                }\n            }\n        }\n\n        return anyImproved;\n    }\n\n    void expand_pass_random() {\n        vector<int> idx(n);\n        iota(idx.begin(), idx.end(), 0);\n        shuffle(idx.begin(), idx.end(), rng);\n        for (int k = 0; k < n; ++k) {\n            if ((k & 31) == 0 && timer.elapsed() > time_limit) return;\n            adjust_one(idx[k]);\n        }\n    }\n\n    void expand_pass_descR(const vector<int>& order) {\n        for (int id : order) {\n            if (timer.elapsed() > time_limit) return;\n            adjust_one(id);\n        }\n    }\n\n    void expand_pass_by_gap() {\n        vector<pair<ll,int>> arr;\n        arr.reserve(n);\n        for (int i = 0; i < n; ++i) {\n            ll s = area_of(rects[i]);\n            arr.emplace_back(llabs(s - (ll)r[i]), i);\n        }\n        sort(arr.begin(), arr.end(), [&](const auto& A, const auto& B){ return A.first > B.first; });\n        for (int k = 0; k < n; ++k) {\n            if ((k & 31) == 0 && timer.elapsed() > time_limit) return;\n            adjust_one(arr[k].second);\n        }\n    }\n\n    void solve() {\n        initial_setup();\n\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        stable_sort(order.begin(), order.end(), [&](int a, int b){ return r[a] > r[b]; });\n\n        // Phase 1: expansion/shrink passes (large first, random, gap-based)\n        double t1 = time_limit * 0.30;\n        while (timer.elapsed() < t1) {\n            expand_pass_descR(order);\n            expand_pass_random();\n        }\n        expand_pass_by_gap();\n\n        // Phase 1.5: alignment to create more full-side pairs\n        double t_align1 = time_limit * 0.55;\n        while (timer.elapsed() < t_align1) {\n            bool imp = align_pairs_pass();\n            if (!imp) break;\n        }\n\n        // Phase 2: pairwise slides on full sides\n        double t2 = time_limit * 0.85;\n        while (timer.elapsed() < t2) {\n            bool improved = slide_pairs_pass();\n            if (!improved) break;\n        }\n\n        // Phase 2.5: try alignment again (after some slides, more opportunities may appear)\n        double t_align2 = time_limit * 0.93;\n        while (timer.elapsed() < t_align2) {\n            bool imp = align_pairs_pass();\n            if (!imp) break;\n        }\n\n        // Phase 3: final smoothing\n        while (timer.elapsed() < time_limit) {\n            expand_pass_by_gap();\n            if (timer.elapsed() > time_limit) break;\n            bool improved = slide_pairs_pass();\n            if (!improved) break;\n        }\n    }\n\n    void output() const {\n        for (int i = 0; i < n; ++i) {\n            const Rect &rc = rects[i];\n            cout << rc.a << ' ' << rc.b << ' ' << rc.c << ' ' << rc.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    if (!(cin >> n)) return 0;\n    vector<int> x(n), y(n), r(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> x[i] >> y[i] >> r[i];\n    }\n\n    Solver solver(n, x, y, r, 4.85);\n    solver.solve();\n    solver.output();\n\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Fast RNG (xorshift)\nstruct XorShift64 {\n    uint64_t x;\n    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    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int randint(int l, int r) { // inclusive l..r\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Params {\n    double wP;        // weight for immediate p\n    double wDeg;      // weight for degree of next cell\n    double wPot;      // weight for precomputed potential\n    double wTwinPot;  // penalty weight for twin potential\n    double wTwinDeg;  // penalty weight for twin degree\n    double wLook;     // weight for 2-ply lookahead\n    double noise;     // random noise amplitude\n    int avoidDeadMinLen; // avoid moving into dead-end (deg==0) before this many steps, if alternatives exist\n};\n\nstruct PathResult {\n    long long score;\n    string moves;\n    int lengthTiles; // number of tiles visited\n};\n\n// Global constants\nstatic const int H = 50, W = 50, N = H * W;\n\n// Utility to get id from (i,j)\ninline int id_of(int i, int j) { return i * W + j; }\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto time_start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.95; // seconds (precompute+runs)\n\n    int si, sj;\n    if (!(cin >> si >> sj)) {\n        // No input\n        cout << \"\\n\";\n        return 0;\n    }\n\n    vector<int> tile(N), pval(N);\n    int maxTile = -1;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int t; cin >> t;\n            tile[id_of(i, j)] = t;\n            if (t > maxTile) maxTile = t;\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            int pv; cin >> pv;\n            pval[id_of(i, j)] = pv;\n        }\n    }\n\n    // Build tileCells and twin mapping\n    vector<vector<int>> tileCells(M);\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int id = id_of(i, j);\n            tileCells[tile[id]].push_back(id);\n        }\n    }\n    vector<int> twin(N, -1);\n    for (int t = 0; t < M; t++) {\n        if (tileCells[t].size() == 2) {\n            int a = tileCells[t][0];\n            int b = tileCells[t][1];\n            twin[a] = b;\n            twin[b] = a;\n        }\n    }\n\n    // Build allowed neighbor list: edges only across different tiles\n    vector<array<int, 4>> coord(N);\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) coord[id_of(i,j)] = {i,j,0,0}; // only i,j used\n    vector<vector<int>> NB(N);\n    vector<char> UD(N), LR(N); // not used; we will compute moves by coord difference\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = id_of(i, j);\n            // up\n            if (i-1 >= 0) {\n                int v = id_of(i-1, j);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n            // down\n            if (i+1 < H) {\n                int v = id_of(i+1, j);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n            // left\n            if (j-1 >= 0) {\n                int v = id_of(i, j-1);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n            // right\n            if (j+1 < W) {\n                int v = id_of(i, j+1);\n                if (tile[u] != tile[v]) NB[u].push_back(v);\n            }\n        }\n    }\n\n    // Precompute static potentials: BFS to depth 3 on allowed graph, with decays for p\n    vector<double> pot(N, 0.0);\n    {\n        static const double w1 = 1.0, w2 = 0.6, w3 = 0.3;\n        vector<char> seen(N, 0);\n        vector<int> frontier, nextf;\n        frontier.reserve(64);\n        nextf.reserve(128);\n\n        for (int s = 0; s < N; s++) {\n            fill(seen.begin(), seen.end(), 0);\n            seen[s] = 1;\n            double sum = 0.0;\n\n            frontier.clear();\n            for (int v : NB[s]) if (!seen[v]) { seen[v] = 1; frontier.push_back(v); sum += w1 * pval[v]; }\n\n            // depth 2\n            nextf.clear();\n            for (int v : frontier) {\n                for (int u : NB[v]) if (!seen[u]) { seen[u] = 1; nextf.push_back(u); sum += w2 * pval[u]; }\n            }\n            // depth 3\n            frontier.swap(nextf);\n            nextf.clear();\n            for (int v : frontier) {\n                for (int u : NB[v]) if (!seen[u]) { seen[u] = 1; nextf.push_back(u); sum += w3 * pval[u]; }\n            }\n\n            pot[s] = sum;\n        }\n    }\n\n    // Precompute deg0 for convenience\n    vector<int> deg0(N);\n    for (int i = 0; i < N; i++) deg0[i] = (int)NB[i].size();\n\n    // RNG seed from input to diversify per test\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)si + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    seed ^= (uint64_t)sj + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    XorShift64 rng(seed);\n\n    // helper lambdas\n    auto dynamicDeg = [&](int cell, const vector<char>& tileUsed, int extraTile1 = -1, int extraTile2 = -1) -> int {\n        int cnt = 0;\n        for (int w : NB[cell]) {\n            int tt = tile[w];\n            if (tileUsed[tt]) continue;\n            if (tt == extraTile1 || tt == extraTile2) continue;\n            cnt++;\n        }\n        return cnt;\n    };\n\n    auto direction_char = [&](int u, int v) -> char {\n        int ui = u / W, uj = u % W;\n        int vi = v / W, vj = v % W;\n        if (vi == ui - 1 && vj == uj) return 'U';\n        if (vi == ui + 1 && vj == uj) return 'D';\n        if (vi == ui && vj == uj - 1) return 'L';\n        if (vi == ui && vj == uj + 1) return 'R';\n        // Should not happen if v is neighbor\n        return 'U';\n    };\n\n    // Parameter presets (will also randomize slightly)\n    vector<Params> presets;\n    presets.push_back(Params{1.00, 1.50, 0.050, 0.040, 0.30, 0.40, 1.5, 500});\n    presets.push_back(Params{1.20, 0.80, 0.080, 0.050, 0.20, 0.50, 1.2, 300});\n    presets.push_back(Params{1.00, 1.00, 0.060, 0.040, 0.25, 0.35, 1.5, 700});\n    presets.push_back(Params{1.00, 0.80, 0.030, 0.020, 0.20, 0.60, 1.0, 400});\n    presets.push_back(Params{1.00, 0.50, 0.100, 0.070, 0.15, 0.60, 1.2, 800});\n    presets.push_back(Params{1.40, 0.60, 0.040, 0.030, 0.20, 0.30, 1.5, 200});\n    presets.push_back(Params{1.00, 1.20, 0.070, 0.060, 0.25, 0.45, 1.0, 600});\n\n    auto build_path = [&](const Params& baseParam) -> PathResult {\n        // Slight random variation per run\n        Params P = baseParam;\n        auto jitter = [&](double v, double f=0.15) {\n            // multiply by 1 +/- up to f\n            double m = 1.0 + (rng.next_double() * 2.0 - 1.0) * f;\n            return v * m;\n        };\n        P.wP       = jitter(P.wP,       0.10);\n        P.wDeg     = jitter(P.wDeg,     0.20);\n        P.wPot     = jitter(P.wPot,     0.25);\n        P.wTwinPot = jitter(P.wTwinPot, 0.25);\n        P.wTwinDeg = jitter(P.wTwinDeg, 0.20);\n        P.wLook    = jitter(P.wLook,    0.25);\n        P.noise    = jitter(P.noise,    0.40);\n        int avoidLimit = P.avoidDeadMinLen;\n\n        vector<char> tileUsed(M, 0);\n        int start = id_of(si, sj);\n        tileUsed[tile[start]] = 1;\n\n        long long score = pval[start];\n        int pos = start;\n        string moves;\n        moves.reserve(2000);\n\n        // We'll build until stuck\n        for (int step = 0; ; step++) {\n            // List candidate neighbors whose tile not yet visited\n            vector<int> cand;\n            cand.reserve(4);\n            for (int v : NB[pos]) {\n                int t = tile[v];\n                if (!tileUsed[t]) cand.push_back(v);\n            }\n            if (cand.empty()) break;\n\n            // Precompute degAfter for candidates and check for any non-dead options\n            vector<int> degAfter(cand.size(), 0);\n            bool hasNonDead = false;\n            for (size_t i = 0; i < cand.size(); i++) {\n                degAfter[i] = dynamicDeg(cand[i], tileUsed);\n                if (degAfter[i] > 0) hasNonDead = true;\n            }\n\n            double bestVal = -1e100;\n            int bestV = -1;\n\n            for (size_t idx = 0; idx < cand.size(); idx++) {\n                int v = cand[idx];\n                if (step < avoidLimit && hasNonDead && degAfter[idx] == 0) {\n                    // avoid entering a dead end early if alternatives exist\n                    continue;\n                }\n                double val = 0.0;\n\n                // immediate gain and local features\n                val += P.wP * pval[v];\n                val += P.wPot * pot[v];\n\n                // degree after stepping into v (available next moves)\n                val += P.wDeg * degAfter[idx];\n\n                // penalty for blocking via twin\n                int tv = twin[v];\n                if (tv != -1) {\n                    // twin degree and potential (approximate loss)\n                    int dTwin = dynamicDeg(tv, tileUsed);\n                    val -= P.wTwinDeg * dTwin;\n                    val -= P.wTwinPot * pot[tv];\n                }\n\n                // 2-ply lookahead: best child of v\n                if (degAfter[idx] > 0 && P.wLook > 1e-9) {\n                    double best2 = -1e100;\n                    for (int w : NB[v]) {\n                        int tw = tile[w];\n                        if (tileUsed[tw]) continue;\n                        // deg after moving to w, with v's tile considered newly visited\n                        int deg2 = dynamicDeg(w, tileUsed, tile[v]);\n                        double val2 = 0.0;\n                        val2 += P.wP * pval[w];\n                        val2 += P.wPot * pot[w];\n                        val2 += P.wDeg * deg2;\n                        int t2 = twin[w];\n                        if (t2 != -1) {\n                            int dtwin2 = dynamicDeg(t2, tileUsed, tile[v]);\n                            val2 -= P.wTwinDeg * dtwin2;\n                            val2 -= P.wTwinPot * pot[t2];\n                        }\n                        if (val2 > best2) best2 = val2;\n                    }\n                    if (best2 > -1e90) val += P.wLook * best2;\n                }\n\n                // noise\n                val += (rng.next_double() * 2.0 - 1.0) * P.noise;\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestV = v;\n                }\n            }\n\n            if (bestV == -1) {\n                // If all candidates were dead-ends and we avoided them, but we must choose one; pick the best ignoring avoid\n                bestVal = -1e100;\n                for (int v : cand) {\n                    double val = P.wP * pval[v] + P.wPot * pot[v] + (rng.next_double() * 2.0 - 1.0) * P.noise;\n                    if (val > bestVal) bestVal = val, bestV = v;\n                }\n                if (bestV == -1) break;\n            }\n\n            // Take the move\n            tileUsed[tile[bestV]] = 1;\n            score += pval[bestV];\n            moves.push_back(direction_char(pos, bestV));\n            pos = bestV;\n        }\n\n        PathResult res;\n        res.score = score;\n        res.moves = moves;\n        res.lengthTiles = (int)moves.size() + 1;\n        return res;\n    };\n\n    // Run multiple randomized attempts within time limit\n    long long bestScore = -1;\n    string bestMoves;\n    int runs = 0;\n\n    // Ensure at least one run with default\n    {\n        Params P = presets[0];\n        PathResult r = build_path(P);\n        bestScore = r.score;\n        bestMoves = r.moves;\n        runs++;\n    }\n\n    while (true) {\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - time_start).count();\n        if (elapsed > TIME_LIMIT) break;\n\n        // Pick a preset randomly\n        Params baseP = presets[rng.randint(0, (int)presets.size()-1)];\n\n        // Mildly adapt avoidDeadMinLen with elapsed (later runs may allow more dead-ends to grab value)\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        if (progress > 0.6) {\n            baseP.avoidDeadMinLen = max(0, baseP.avoidDeadMinLen - (int)((progress - 0.6) * 800));\n        }\n\n        PathResult r = build_path(baseP);\n        if (r.score > bestScore) {\n            bestScore = r.score;\n            bestMoves = r.moves;\n        }\n        runs++;\n    }\n\n    // Output best path\n    cout << bestMoves << '\\n';\n\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int H = 30;\n    static constexpr int W = 30;\n    static constexpr int N = H * W;\n    // true generation range\n    static constexpr double WMIN = 1000.0;\n    static constexpr double WMAX = 9000.0;\n    // per-edge deviation clamp\n    static constexpr double DEV_CLAMP = 3000.0;\n\n    // base parameters: row-segment for horizontals, col-segment for verticals\n    // Hseg[i][s] for s=0..2: j in [0..9], [10..19], [20..28]\n    // Vseg[j][s] for s=0..2: i in [0..9], [10..19], [20..28]\n    array<array<double, 3>, H> Hseg;\n    array<array<double, 3>, W> Vseg;\n\n    // per-edge deviations\n    double dev_h[H][W-1];\n    double dev_v[H-1][W];\n\n    // query counter\n    int qid;\n\n    Solver() {\n        // initialize bases to center of allowed range\n        double init = 5000.0;\n        for (int i = 0; i < H; i++) Hseg[i] = {init, init, init};\n        for (int j = 0; j < W; j++) Vseg[j] = {init, init, init};\n        for (int i = 0; i < H; i++) for (int j = 0; j < W-1; j++) dev_h[i][j] = 0.0;\n        for (int i = 0; i < H-1; i++) for (int j = 0; j < W; j++) dev_v[i][j] = 0.0;\n        qid = 0;\n    }\n\n    static inline int segH_from_j(int j) {\n        if (j < 10) return 0;\n        if (j < 20) return 1;\n        return 2; // 20..28\n    }\n    static inline int segV_from_i(int i) {\n        if (i < 10) return 0;\n        if (i < 20) return 1;\n        return 2; // 20..28\n    }\n\n    inline double wh(int i, int j) const { // horizontal edge (i,j)-(i,j+1), j in [0..28]\n        int s = segH_from_j(j);\n        double x = Hseg[i][s] + dev_h[i][j];\n        if (x < WMIN) x = WMIN;\n        if (x > WMAX) x = WMAX;\n        return x;\n    }\n    inline double wv(int i, int j) const { // vertical edge (i,j)-(i+1,j), i in [0..28]\n        int s = segV_from_i(i);\n        double x = Vseg[j][s] + dev_v[i][j];\n        if (x < WMIN) x = WMIN;\n        if (x > WMAX) x = WMAX;\n        return x;\n    }\n\n    struct Node {\n        double d;\n        int i, j;\n        bool operator<(const Node& other) const {\n            return d > other.d; // for min-heap\n        }\n    };\n\n    // compute shortest path under current estimates using Dijkstra\n    string compute_path(int si, int sj, int ti, int tj, double &pred_len) {\n        static double dist[H][W];\n        static int pi[H][W], pj[H][W];\n        static char pdir[H][W];\n\n        for (int i = 0; i < H; i++) {\n            for (int j = 0; j < W; j++) {\n                dist[i][j] = numeric_limits<double>::infinity();\n                pi[i][j] = pj[i][j] = -1;\n                pdir[i][j] = 0;\n            }\n        }\n\n        priority_queue<Node> pq;\n        dist[si][sj] = 0.0;\n        pq.push({0.0, si, sj});\n\n        while (!pq.empty()) {\n            Node cur = pq.top(); pq.pop();\n            int i = cur.i, j = cur.j;\n            if (cur.d != dist[i][j]) continue;\n            if (i == ti && j == tj) break;\n\n            // neighbors: U,D,L,R\n            if (i > 0) {\n                double w = wv(i-1, j);\n                double nd = cur.d + w;\n                if (nd < dist[i-1][j]) {\n                    dist[i-1][j] = nd;\n                    pi[i-1][j] = i; pj[i-1][j] = j; pdir[i-1][j] = 'U';\n                    pq.push({nd, i-1, j});\n                }\n            }\n            if (i+1 < H) {\n                double w = wv(i, j);\n                double nd = cur.d + w;\n                if (nd < dist[i+1][j]) {\n                    dist[i+1][j] = nd;\n                    pi[i+1][j] = i; pj[i+1][j] = j; pdir[i+1][j] = 'D';\n                    pq.push({nd, i+1, j});\n                }\n            }\n            if (j > 0) {\n                double w = wh(i, j-1);\n                double nd = cur.d + w;\n                if (nd < dist[i][j-1]) {\n                    dist[i][j-1] = nd;\n                    pi[i][j-1] = i; pj[i][j-1] = j; pdir[i][j-1] = 'L';\n                    pq.push({nd, i, j-1});\n                }\n            }\n            if (j+1 < W) {\n                double w = wh(i, j);\n                double nd = cur.d + w;\n                if (nd < dist[i][j+1]) {\n                    dist[i][j+1] = nd;\n                    pi[i][j+1] = i; pj[i][j+1] = j; pdir[i][j+1] = 'R';\n                    pq.push({nd, i, j+1});\n                }\n            }\n        }\n\n        // reconstruct path\n        string rev;\n        int ci = ti, cj = tj;\n        while (!(ci == si && cj == sj)) {\n            char c = pdir[ci][cj];\n            rev.push_back(c);\n            int ni = pi[ci][cj], nj = pj[ci][cj];\n            ci = ni; cj = nj;\n        }\n        reverse(rev.begin(), rev.end());\n        pred_len = dist[ti][tj];\n        return rev;\n    }\n\n    struct EdgeUse {\n        bool isH; // true: horizontal; false: vertical\n        int i, j; // for horizontal: edge (i,j)-(i,j+1), j in [0..28]; for vertical: (i,j)-(i+1,j), i in [0..28]\n    };\n\n    // parse path into edges, compute predicted length and feature counts\n    void parse_path_and_features(int si, int sj, const string &path,\n                                 vector<EdgeUse> &edges,\n                                 vector<array<int,3>> &countHseg, // size H: counts per segment\n                                 vector<array<int,3>> &countVseg, // size W: counts per segment\n                                 double &S_pred) {\n        edges.clear();\n        countHseg.assign(H, {0,0,0});\n        countVseg.assign(W, {0,0,0});\n        int i = si, j = sj;\n        S_pred = 0.0;\n\n        for (char c : path) {\n            if (c == 'U') {\n                // use vertical edge (i-1,j)\n                int ei = i - 1, ej = j;\n                edges.push_back({false, ei, ej});\n                int s = segV_from_i(ei);\n                countVseg[ej][s] += 1;\n                double w = wv(ei, ej);\n                S_pred += w;\n                i -= 1;\n            } else if (c == 'D') {\n                int ei = i, ej = j;\n                edges.push_back({false, ei, ej});\n                int s = segV_from_i(ei);\n                countVseg[ej][s] += 1;\n                double w = wv(ei, ej);\n                S_pred += w;\n                i += 1;\n            } else if (c == 'L') {\n                int ei = i, ej = j - 1;\n                edges.push_back({true, ei, ej});\n                int s = segH_from_j(ej);\n                countHseg[ei][s] += 1;\n                double w = wh(ei, ej);\n                S_pred += w;\n                j -= 1;\n            } else if (c == 'R') {\n                int ei = i, ej = j;\n                edges.push_back({true, ei, ej});\n                int s = segH_from_j(ej);\n                countHseg[ei][s] += 1;\n                double w = wh(ei, ej);\n                S_pred += w;\n                j += 1;\n            }\n        }\n    }\n\n    // Update parameters using normalized LMS; devs receive larger share\n    void update_from_observation(int si, int sj, const string &path, long long y) {\n        vector<EdgeUse> edges;\n        vector<array<int,3>> countH; // per row segments\n        vector<array<int,3>> countV; // per col segments\n        double S_pred = 0.0;\n        parse_path_and_features(si, sj, path, edges, countH, countV, S_pred);\n\n        // Error\n        double delta = (double)y - S_pred;\n        int L = (int)edges.size();\n\n        // Compute norms for base features\n        double n_base = 0.0;\n        for (int i = 0; i < H; i++) {\n            for (int s = 0; s < 3; s++) {\n                int c = countH[i][s];\n                if (c) n_base += (double)c * (double)c;\n            }\n        }\n        for (int j = 0; j < W; j++) {\n            for (int s = 0; s < 3; s++) {\n                int c = countV[j][s];\n                if (c) n_base += (double)c * (double)c;\n            }\n        }\n        if (n_base < 1e-9) n_base = 0.0;\n\n        // Learning rates schedule\n        double t = (double)qid / 1000.0; // 0 ... ~1\n        // linearly decrease learning rates over time\n        double eta_dev = (1.0 - t) * 0.75 + t * 0.35;   // from 0.75 to 0.35\n        double eta_base = (1.0 - t) * 0.24 + t * 0.10;  // from 0.24 to 0.10\n        double lambda = 1.0;\n\n        // compute step sizes\n        double alpha_dev = 0.0;\n        if (L > 0) alpha_dev = eta_dev * delta / ( (double)L + lambda );\n\n        double alpha_base = 0.0;\n        if (n_base > 0.0) alpha_base = eta_base * delta / ( n_base + lambda );\n\n        // Update base parameters\n        if (alpha_base != 0.0) {\n            for (int i = 0; i < H; i++) {\n                for (int s = 0; s < 3; s++) {\n                    int c = countH[i][s];\n                    if (c) {\n                        Hseg[i][s] += alpha_base * c;\n                        if (Hseg[i][s] < WMIN) Hseg[i][s] = WMIN;\n                        else if (Hseg[i][s] > WMAX) Hseg[i][s] = WMAX;\n                    }\n                }\n            }\n            for (int j = 0; j < W; j++) {\n                for (int s = 0; s < 3; s++) {\n                    int c = countV[j][s];\n                    if (c) {\n                        Vseg[j][s] += alpha_base * c;\n                        if (Vseg[j][s] < WMIN) Vseg[j][s] = WMIN;\n                        else if (Vseg[j][s] > WMAX) Vseg[j][s] = WMAX;\n                    }\n                }\n            }\n        }\n\n        // Update per-edge deviations\n        if (alpha_dev != 0.0) {\n            for (const auto &e : edges) {\n                if (e.isH) {\n                    dev_h[e.i][e.j] += alpha_dev;\n                    if (dev_h[e.i][e.j] < -DEV_CLAMP) dev_h[e.i][e.j] = -DEV_CLAMP;\n                    else if (dev_h[e.i][e.j] > DEV_CLAMP) dev_h[e.i][e.j] = DEV_CLAMP;\n                } else {\n                    dev_v[e.i][e.j] += alpha_dev;\n                    if (dev_v[e.i][e.j] < -DEV_CLAMP) dev_v[e.i][e.j] = -DEV_CLAMP;\n                    else if (dev_v[e.i][e.j] > DEV_CLAMP) dev_v[e.i][e.j] = DEV_CLAMP;\n                }\n            }\n        }\n\n        // Small deviation decay towards 0 to regularize\n        double decay = (1.0 - t) * 0.0007 + t * 0.0018; // from ~7e-4 to ~1.8e-3\n        if (decay > 0.0) {\n            double mul = 1.0 - decay;\n            for (int i = 0; i < H; i++) {\n                for (int j = 0; j < W-1; j++) {\n                    dev_h[i][j] *= mul;\n                }\n            }\n            for (int i = 0; i < H-1; i++) {\n                for (int j = 0; j < W; j++) {\n                    dev_v[i][j] *= mul;\n                }\n            }\n        }\n\n        qid++;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int k = 0; k < 1000; k++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) {\n            return 0; // input ended unexpectedly\n        }\n\n        double pred_len = 0.0;\n        string path = solver.compute_path(si, sj, ti, tj, pred_len);\n\n        // Output path and flush\n        cout << path << '\\n' << flush;\n\n        long long observed_len;\n        if (!(cin >> observed_len)) {\n            return 0; // interactive judge ended\n        }\n\n        // Update model\n        solver.update_from_observation(si, sj, path, observed_len);\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\nusing namespace std;\n\n// Timer\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\n// Xorshift RNG\nstruct XorShift64 {\n    uint64_t x;\n    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    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n    inline double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n};\n\n// Problem constants\nstatic const int N_FIX = 20;\nstatic const int LMIN = 2;\nstatic const int LMAX = 12;\nstatic const int LCOUNT = LMAX - LMIN + 1;\n\nusing u64 = uint64_t;\nusing FlatMap = boost::unordered_flat_map<u64,int>;\n\nstatic inline u64 pack_key_str(const string& s) {\n    u64 k = 0;\n    for (char ch : s) k = (k << 3) | (u64)(ch - 'A');\n    return k;\n}\n\n// AC automaton for alphabet size 8\nstruct ACNode {\n    int next[8];\n    int fail;\n    vector<int> out; // list of uids ending at this state (with suffix outputs merged after build)\n    ACNode() {\n        memset(next, -1, sizeof(next));\n        fail = 0;\n    }\n};\nstruct AhoCorasick {\n    vector<ACNode> nodes;\n    AhoCorasick() { nodes.reserve(4096); nodes.push_back(ACNode()); }\n\n    void add(const vector<uint8_t>& s, int uid) {\n        int v = 0;\n        for (uint8_t c : s) {\n            if (nodes[v].next[c] == -1) {\n                nodes[v].next[c] = (int)nodes.size();\n                nodes.push_back(ACNode());\n            }\n            v = nodes[v].next[c];\n        }\n        nodes[v].out.push_back(uid);\n    }\n\n    void build() {\n        queue<int> q;\n        for (int c = 0; c < 8; ++c) {\n            int u = nodes[0].next[c];\n            if (u != -1) {\n                nodes[u].fail = 0;\n                q.push(u);\n            } else {\n                nodes[0].next[c] = 0;\n            }\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int f = nodes[v].fail;\n            // merge outputs from fail link\n            if (!nodes[f].out.empty()) {\n                auto &ov = nodes[v].out;\n                const auto &of = nodes[f].out;\n                ov.insert(ov.end(), of.begin(), of.end());\n            }\n            for (int c = 0; c < 8; ++c) {\n                int u = nodes[v].next[c];\n                if (u != -1) {\n                    nodes[u].fail = nodes[f].next[c];\n                    q.push(u);\n                } else {\n                    nodes[v].next[c] = nodes[f].next[c];\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    vector<string> inputS(M);\n    for (int i = 0; i < M; ++i) cin >> inputS[i];\n\n    Timer timer;\n    const double TIME_LIMIT = 2.95;\n\n    // Build unique strings (lenIdx, key) -> uid\n    struct UKeyHasher {\n        size_t operator()(const pair<int,u64>& p) const {\n            return std::hash<u64>()((p.second << 4) ^ (u64)p.first);\n        }\n    };\n    struct UKeyEq {\n        bool operator()(const pair<int,u64>& a, const pair<int,u64>& b) const {\n            return a.first == b.first && a.second == b.second;\n        }\n    };\n    boost::unordered_flat_map<pair<int,u64>, int, UKeyHasher, UKeyEq> uniqMap;\n    uniqMap.reserve(M*2);\n\n    struct Unique {\n        int len;\n        u64 key;\n        int weight;\n        vector<uint8_t> codes;\n    };\n    vector<Unique> uniqs; uniqs.reserve(M);\n\n    for (int i = 0; i < M; ++i) {\n        const string &s = inputS[i];\n        int L = (int)s.size();\n        int li = L - LMIN;\n        u64 key = pack_key_str(s);\n        auto pr = make_pair(li, key);\n        auto it = uniqMap.find(pr);\n        if (it == uniqMap.end()) {\n            int uid = (int)uniqs.size();\n            uniqMap.emplace(pr, uid);\n            Unique u;\n            u.len = L;\n            u.key = key;\n            u.weight = 1;\n            u.codes.resize(L);\n            for (int j = 0; j < L; ++j) u.codes[j] = (uint8_t)(s[j] - 'A');\n            uniqs.push_back(std::move(u));\n        } else {\n            uniqs[it->second].weight += 1;\n        }\n    }\n    int K = (int)uniqs.size();\n\n    // Per-length key->uid maps\n    array<FlatMap, LCOUNT> key2uid;\n    for (int li = 0; li < LCOUNT; ++li) key2uid[li].reserve(max(8, K / LCOUNT * 2));\n    for (int uid = 0; uid < K; ++uid) {\n        int li = uniqs[uid].len - LMIN;\n        key2uid[li].emplace(uniqs[uid].key, uid);\n    }\n\n    // Precompute bit shifts\n    int shiftAmt[LCOUNT][LMAX];\n    for (int li = 0; li < LCOUNT; ++li) {\n        int L = LMIN + li;\n        for (int t = 0; t < L; ++t) shiftAmt[li][t] = 3 * (L - 1 - t);\n    }\n\n    // Grid initialization: random\n    XorShift64 rng(123456789);\n    uint8_t g[N_FIX][N_FIX];\n    for (int i = 0; i < N_FIX; ++i) for (int j = 0; j < N_FIX; ++j) g[i][j] = (uint8_t)rng.next_int(0,7);\n\n    // windowsKey/Uid for lines: [li][line 0..39][start 0..19]\n    u64 windowsKey[LCOUNT][2*N_FIX][N_FIX];\n    int  windowsUid[LCOUNT][2*N_FIX][N_FIX];\n    for (int li = 0; li < LCOUNT; ++li)\n        for (int ln = 0; ln < 2*N_FIX; ++ln)\n            for (int s = 0; s < N_FIX; ++s) {\n                windowsKey[li][ln][s] = 0;\n                windowsUid[li][ln][s] = -1;\n            }\n\n    vector<int> occCount(K, 0);\n    vector<char> present(K, 0);\n    long long scoreC = 0;\n\n    // Initialize windows and occCount\n    for (int li = 0; li < LCOUNT; ++li) {\n        int L = LMIN + li;\n        for (int ln = 0; ln < 2*N_FIX; ++ln) {\n            for (int s = 0; s < N_FIX; ++s) {\n                u64 key = 0;\n                if (ln < N_FIX) {\n                    int i = ln;\n                    for (int r = 0; r < L; ++r) {\n                        int idx = s + r;\n                        if (idx >= N_FIX) idx -= N_FIX;\n                        key = (key << 3) | (u64)g[i][idx];\n                    }\n                } else {\n                    int j = ln - N_FIX;\n                    for (int r = 0; r < L; ++r) {\n                        int idx = s + r;\n                        if (idx >= N_FIX) idx -= N_FIX;\n                        key = (key << 3) | (u64)g[idx][j];\n                    }\n                }\n                windowsKey[li][ln][s] = key;\n                auto it = key2uid[li].find(key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    windowsUid[li][ln][s] = uid;\n                    if (occCount[uid] == 0) {\n                        scoreC += uniqs[uid].weight;\n                        present[uid] = 1;\n                    }\n                    occCount[uid] += 1;\n                } else {\n                    windowsUid[li][ln][s] = -1;\n                }\n            }\n        }\n    }\n\n    // Stamping structures for evaluating deltas\n    vector<int> deltaOcc(K, 0);\n    vector<int> lastStamp(K, -1);\n    vector<int> touched; touched.reserve(4096);\n    int stamp = 0;\n\n    // Aggregate masks for block paste row/col evaluation\n    static u64 aggMask[LCOUNT][N_FIX];\n    static int maskStamp[LCOUNT][N_FIX];\n    int aggStamp = 1; // start from 1 so 0 means \"never\"\n\n    // Common accumulator for a single change on given line at pos, with ocxor\n    auto accumulate_single_change = [&](int line, int pos, int ocxor_) {\n        for (int li = 0; li < LCOUNT; ++li) {\n            int Lw = LMIN + li;\n            for (int t = 0; t < Lw; ++t) {\n                int s = pos - t;\n                if (s < 0) s += N_FIX;\n                int old_uid = windowsUid[li][line][s];\n                if (old_uid >= 0) {\n                    if (lastStamp[old_uid] != stamp) {\n                        lastStamp[old_uid] = stamp;\n                        deltaOcc[old_uid] = 0;\n                        touched.push_back(old_uid);\n                    }\n                    deltaOcc[old_uid] -= 1;\n                }\n                u64 old_key = windowsKey[li][line][s];\n                u64 new_key = old_key ^ ((u64)ocxor_ << shiftAmt[li][t]);\n                auto it = key2uid[li].find(new_key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    if (lastStamp[uid] != stamp) {\n                        lastStamp[uid] = stamp;\n                        deltaOcc[uid] = 0;\n                        touched.push_back(uid);\n                    }\n                    deltaOcc[uid] += 1;\n                }\n            }\n        }\n    };\n\n    // Update windows and counts for a single change\n    auto update_line_single = [&](int line, int pos, int ocxor_) {\n        for (int li = 0; li < LCOUNT; ++li) {\n            int Lw = LMIN + li;\n            for (int t = 0; t < Lw; ++t) {\n                int s = pos - t;\n                if (s < 0) s += N_FIX;\n                int old_uid = windowsUid[li][line][s];\n                u64 old_key = windowsKey[li][line][s];\n                u64 new_key = old_key ^ ((u64)ocxor_ << shiftAmt[li][t]);\n                auto it = key2uid[li].find(new_key);\n                int new_uid = (it == key2uid[li].end() ? -1 : it->second);\n\n                if (old_uid >= 0) {\n                    occCount[old_uid] -= 1;\n                    if (occCount[old_uid] == 0) {\n                        scoreC -= uniqs[old_uid].weight;\n                        present[old_uid] = 0;\n                    }\n                }\n                if (new_uid >= 0) {\n                    if (occCount[new_uid] == 0) {\n                        scoreC += uniqs[new_uid].weight;\n                        present[new_uid] = 1;\n                    }\n                    occCount[new_uid] += 1;\n                }\n\n                windowsKey[li][line][s] = new_key;\n                windowsUid[li][line][s] = new_uid;\n            }\n        }\n    };\n\n    auto eval_delta_for_letter = [&](int i, int j, uint8_t newCode) -> long long {\n        uint8_t oldCode = g[i][j];\n        if (newCode == oldCode) return 0;\n        int ocxor = (int)(oldCode ^ newCode);\n\n        ++stamp;\n        touched.clear();\n\n        // row\n        accumulate_single_change(i, j, ocxor);\n        // column\n        accumulate_single_change(N_FIX + j, i, ocxor);\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto apply_letter = [&](int i, int j, uint8_t newCode) {\n        uint8_t oldCode = g[i][j];\n        if (newCode == oldCode) return;\n        int ocxor = (int)(oldCode ^ newCode);\n\n        // update row windows\n        update_line_single(i, j, ocxor);\n        // update column windows\n        update_line_single(N_FIX + j, i, ocxor);\n\n        // update grid\n        g[i][j] = newCode;\n    };\n\n    // Aggregate evaluation for multiple changes on the same line\n    auto eval_delta_paste_line_aggregate = [&](int line, const vector<pair<int,int>>& posXor) {\n        ++aggStamp;\n        for (auto &px : posXor) {\n            int pos = px.first;\n            int ocxor = px.second;\n            if (ocxor == 0) continue;\n            for (int li = 0; li < LCOUNT; ++li) {\n                int Lw = LMIN + li;\n                for (int t = 0; t < Lw; ++t) {\n                    int s = pos - t;\n                    if (s < 0) s += N_FIX;\n                    if (maskStamp[li][s] != aggStamp) {\n                        maskStamp[li][s] = aggStamp;\n                        aggMask[li][s] = 0;\n                    }\n                    aggMask[li][s] ^= ((u64)ocxor << shiftAmt[li][t]);\n                }\n            }\n        }\n        for (int li = 0; li < LCOUNT; ++li) {\n            for (int s = 0; s < N_FIX; ++s) {\n                if (maskStamp[li][s] != aggStamp) continue;\n                u64 m = aggMask[li][s];\n                if (m == 0) continue;\n                int old_uid = windowsUid[li][line][s];\n                if (old_uid >= 0) {\n                    if (lastStamp[old_uid] != stamp) {\n                        lastStamp[old_uid] = stamp;\n                        deltaOcc[old_uid] = 0;\n                        touched.push_back(old_uid);\n                    }\n                    deltaOcc[old_uid] -= 1;\n                }\n                u64 old_key = windowsKey[li][line][s];\n                u64 new_key = old_key ^ m;\n                auto it = key2uid[li].find(new_key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    if (lastStamp[uid] != stamp) {\n                        lastStamp[uid] = stamp;\n                        deltaOcc[uid] = 0;\n                        touched.push_back(uid);\n                    }\n                    deltaOcc[uid] += 1;\n                }\n            }\n        }\n    };\n\n    auto eval_delta_paste_row = [&](int i, int start, const vector<uint8_t>& codes) -> long long {\n        vector<pair<int,int>> rowPosXor; rowPosXor.reserve((int)codes.size());\n        vector<tuple<int,int,int>> colTriples; colTriples.reserve((int)codes.size());\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int j = start + p; if (j >= N_FIX) j -= N_FIX;\n            int ocxor = g[i][j] ^ codes[p];\n            if (ocxor == 0) continue;\n            rowPosXor.emplace_back(j, ocxor);\n            colTriples.emplace_back(N_FIX + j, i, ocxor);\n        }\n        if (rowPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        // row aggregate\n        eval_delta_paste_line_aggregate(i, rowPosXor);\n\n        // columns single\n        for (auto &tp : colTriples) {\n            int line = get<0>(tp), pos = get<1>(tp), ocxor = get<2>(tp);\n            accumulate_single_change(line, pos, ocxor);\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto eval_delta_paste_col = [&](int j, int start, const vector<uint8_t>& codes) -> long long {\n        vector<pair<int,int>> colPosXor; colPosXor.reserve((int)codes.size());\n        vector<tuple<int,int,int>> rowTriples; rowTriples.reserve((int)codes.size());\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int i = start + p; if (i >= N_FIX) i -= N_FIX;\n            int ocxor = g[i][j] ^ codes[p];\n            if (ocxor == 0) continue;\n            colPosXor.emplace_back(i, ocxor);\n            rowTriples.emplace_back(i, j, ocxor);\n        }\n        if (colPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        // column aggregate\n        eval_delta_paste_line_aggregate(N_FIX + j, colPosXor);\n\n        // rows single\n        for (auto &tp : rowTriples) {\n            int line = get<0>(tp), pos = get<1>(tp), ocxor = get<2>(tp);\n            accumulate_single_change(line, pos, ocxor);\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto apply_paste_row = [&](int i, int start, const vector<uint8_t>& codes) {\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int j = start + p; if (j >= N_FIX) j -= N_FIX;\n            if (g[i][j] != codes[p]) apply_letter(i, j, codes[p]);\n        }\n    };\n    auto apply_paste_col = [&](int j, int start, const vector<uint8_t>& codes) {\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int i = start + p; if (i >= N_FIX) i -= N_FIX;\n            if (g[i][j] != codes[p]) apply_letter(i, j, codes[p]);\n        }\n    };\n\n    // Rotation evaluation and application\n    auto eval_delta_rotate_row = [&](int i, int sft) -> long long {\n        if (sft % N_FIX == 0) return 0;\n        ++stamp;\n        touched.clear();\n        for (int j = 0; j < N_FIX; ++j) {\n            int j2 = j - sft; if (j2 < 0) j2 += N_FIX;\n            int ocxor = g[i][j] ^ g[i][j2];\n            if (ocxor) {\n                // only column line affected at pos i\n                accumulate_single_change(N_FIX + j, i, ocxor);\n            }\n        }\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n    auto apply_rotate_row = [&](int i, int sft) {\n        if (sft % N_FIX == 0) return;\n        uint8_t newRow[N_FIX];\n        for (int j = 0; j < N_FIX; ++j) {\n            int j2 = j - sft; if (j2 < 0) j2 += N_FIX;\n            newRow[j] = g[i][j2];\n        }\n        for (int j = 0; j < N_FIX; ++j) {\n            uint8_t oldC = g[i][j];\n            uint8_t newC = newRow[j];\n            if (oldC != newC) {\n                int ocxor = (int)(oldC ^ newC);\n                update_line_single(N_FIX + j, i, ocxor);\n                g[i][j] = newC;\n            }\n        }\n        // rotate row windows arrays without changing occCount\n        for (int li = 0; li < LCOUNT; ++li) {\n            u64 tmpK[N_FIX];\n            int tmpU[N_FIX];\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                int from = s0 - sft; if (from < 0) from += N_FIX;\n                tmpK[s0] = windowsKey[li][i][from];\n                tmpU[s0] = windowsUid[li][i][from];\n            }\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                windowsKey[li][i][s0] = tmpK[s0];\n                windowsUid[li][i][s0] = tmpU[s0];\n            }\n        }\n    };\n\n    auto eval_delta_rotate_col = [&](int j, int sft) -> long long {\n        if (sft % N_FIX == 0) return 0;\n        ++stamp;\n        touched.clear();\n        for (int i = 0; i < N_FIX; ++i) {\n            int i2 = i - sft; if (i2 < 0) i2 += N_FIX;\n            int ocxor = g[i][j] ^ g[i2][j];\n            if (ocxor) {\n                // only row line affected at pos j\n                accumulate_single_change(i, j, ocxor);\n            }\n        }\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n    auto apply_rotate_col = [&](int j, int sft) {\n        if (sft % N_FIX == 0) return;\n        uint8_t newCol[N_FIX];\n        for (int i = 0; i < N_FIX; ++i) {\n            int i2 = i - sft; if (i2 < 0) i2 += N_FIX;\n            newCol[i] = g[i2][j];\n        }\n        for (int i = 0; i < N_FIX; ++i) {\n            uint8_t oldC = g[i][j];\n            uint8_t newC = newCol[i];\n            if (oldC != newC) {\n                int ocxor = (int)(oldC ^ newC);\n                update_line_single(i, j, ocxor);\n                g[i][j] = newC;\n            }\n        }\n        // rotate column windows arrays without changing occCount\n        for (int li = 0; li < LCOUNT; ++li) {\n            u64 tmpK[N_FIX];\n            int tmpU[N_FIX];\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                int from = s0 - sft; if (from < 0) from += N_FIX;\n                tmpK[s0] = windowsKey[li][N_FIX + j][from];\n                tmpU[s0] = windowsUid[li][N_FIX + j][from];\n            }\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                windowsKey[li][N_FIX + j][s0] = tmpK[s0];\n                windowsUid[li][N_FIX + j][s0] = tmpU[s0];\n            }\n        }\n    };\n\n    long long bestScore = scoreC;\n    uint8_t bestGrid[N_FIX][N_FIX];\n    memcpy(bestGrid, g, sizeof(g));\n\n    // Build AC automaton with all unique strings\n    AhoCorasick ac;\n    for (int uid = 0; uid < K; ++uid) ac.add(uniqs[uid].codes, uid);\n    ac.build();\n    int S = (int)ac.nodes.size();\n\n    // Buffers for DP per line\n    vector<int> outW(S, 0), dp(S, 0), ndp(S, 0);\n    vector<uint8_t> choice((size_t)N_FIX * S);\n\n    auto ac_build_best_line = [&](vector<uint8_t>& out) {\n        for (int v = 0; v < S; ++v) {\n            int sum = 0;\n            const auto &ov = ac.nodes[v].out;\n            for (int uid : ov) if (!present[uid]) sum += uniqs[uid].weight;\n            outW[v] = sum;\n        }\n        fill(dp.begin(), dp.end(), 0);\n        for (int pos = N_FIX - 1; pos >= 0; --pos) {\n            for (int v = 0; v < S; ++v) {\n                int bestVal = INT_MIN;\n                uint8_t bestC = 0;\n                for (int c = 0; c < 8; ++c) {\n                    int u = ac.nodes[v].next[c];\n                    int val = outW[u] + dp[u];\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestC = (uint8_t)c;\n                    }\n                }\n                ndp[v] = bestVal;\n                choice[(size_t)pos * S + v] = bestC;\n            }\n            dp.swap(ndp);\n        }\n        out.resize(N_FIX);\n        int v = 0;\n        for (int pos = 0; pos < N_FIX; ++pos) {\n            uint8_t c = choice[(size_t)pos * S + v];\n            out[pos] = c;\n            v = ac.nodes[v].next[c];\n        }\n    };\n\n    // Stage 0: AC-guided line synthesis (approx greedy)\n    double T_AC = min(0.80, TIME_LIMIT * 0.25);\n    vector<int> lines(2*N_FIX);\n    iota(lines.begin(), lines.end(), 0);\n    while (timer.elapsed() < T_AC) {\n        shuffle(lines.begin(), lines.end(), std::mt19937(1234567 ^ (unsigned)rng.next_u32()));\n        bool anyApplied = false;\n        for (int idx = 0; idx < (int)lines.size(); ++idx) {\n            if (timer.elapsed() >= T_AC) break;\n            int ln = lines[idx];\n            vector<uint8_t> bestLine;\n            ac_build_best_line(bestLine);\n            long long delta = (ln < N_FIX) ? eval_delta_paste_row(ln, 0, bestLine)\n                                           : eval_delta_paste_col(ln - N_FIX, 0, bestLine);\n            if (delta > 0) {\n                if (ln < N_FIX) apply_paste_row(ln, 0, bestLine);\n                else apply_paste_col(ln - N_FIX, 0, bestLine);\n                anyApplied = true;\n                if (scoreC > bestScore) {\n                    bestScore = scoreC;\n                    memcpy(bestGrid, g, sizeof(g));\n                }\n            }\n        }\n        if (!anyApplied) break;\n    }\n\n    // Stage 0.5: Rotation pass (rows then columns)\n    auto rotation_pass = [&]() {\n        // Rows\n        for (int i = 0; i < N_FIX; ++i) {\n            long long bestD = 0;\n            int bestSft = 0;\n            for (int sft = 1; sft < N_FIX; ++sft) {\n                long long d = eval_delta_rotate_row(i, sft);\n                if (d > bestD) { bestD = d; bestSft = sft; }\n            }\n            if (bestD > 0) {\n                apply_rotate_row(i, bestSft);\n                if (scoreC > bestScore) {\n                    bestScore = scoreC;\n                    memcpy(bestGrid, g, sizeof(g));\n                }\n            }\n        }\n        // Columns\n        for (int j = 0; j < N_FIX; ++j) {\n            long long bestD = 0;\n            int bestSft = 0;\n            for (int sft = 1; sft < N_FIX; ++sft) {\n                long long d = eval_delta_rotate_col(j, sft);\n                if (d > bestD) { bestD = d; bestSft = sft; }\n            }\n            if (bestD > 0) {\n                apply_rotate_col(j, bestSft);\n                if (scoreC > bestScore) {\n                    bestScore = scoreC;\n                    memcpy(bestGrid, g, sizeof(g));\n                }\n            }\n        }\n    };\n    rotation_pass();\n\n    // Stage 1: Block paste hill-climbing\n    double T_BLOCK = TIME_LIMIT * 0.82;\n    while (timer.elapsed() < T_BLOCK) {\n        // pick uid: biased toward absent and heavier weight\n        int uid = -1;\n        int bestW = -1;\n        bool wantAbsent = (rng.next_double() < 0.75);\n        for (int t = 0; t < 10; ++t) {\n            int cand = rng.next_int(0, K-1);\n            if (wantAbsent && present[cand]) continue;\n            int w = uniqs[cand].weight;\n            if (w > bestW) { bestW = w; uid = cand; }\n        }\n        if (uid < 0) uid = rng.next_int(0, K-1);\n        const auto &codes = uniqs[uid].codes;\n\n        long long bestDelta = LLONG_MIN;\n        bool bestIsRow = true;\n        int bestLine = 0, bestStart = 0;\n\n        int tries = 14;\n        for (int t = 0; t < tries; ++t) {\n            bool isRow = (rng.next_u32() & 1) == 0;\n            int line = rng.next_int(0, N_FIX-1);\n            int start = rng.next_int(0, N_FIX-1);\n            long long delta = isRow ? eval_delta_paste_row(line, start, codes)\n                                    : eval_delta_paste_col(line, start, codes);\n            if (delta > bestDelta) {\n                bestDelta = delta;\n                bestIsRow = isRow;\n                bestLine = line;\n                bestStart = start;\n            }\n        }\n\n        if (bestDelta > 0) {\n            if (bestIsRow) apply_paste_row(bestLine, bestStart, codes);\n            else apply_paste_col(bestLine, bestStart, codes);\n            if (scoreC > bestScore) {\n                bestScore = scoreC;\n                memcpy(bestGrid, g, sizeof(g));\n            }\n        }\n    }\n\n    // Optional quick second rotation pass if time allows\n    if (timer.elapsed() < TIME_LIMIT * 0.9) rotation_pass();\n\n    // Stage 2: SA fine-tuning with single-letter moves\n    double T0 = 1.0, T1 = 0.01;\n    while (timer.elapsed() < TIME_LIMIT) {\n        int i = rng.next_int(0, N_FIX-1);\n        int j = rng.next_int(0, N_FIX-1);\n        uint8_t oldCode = g[i][j];\n\n        long long bestDelta = LLONG_MIN;\n        uint8_t bestCode = oldCode;\n        for (uint8_t nc = 0; nc < 8; ++nc) {\n            if (nc == oldCode) continue;\n            long long delta = eval_delta_for_letter(i, j, nc);\n            if (delta > bestDelta) {\n                bestDelta = delta;\n                bestCode = nc;\n            }\n        }\n\n        double t = timer.elapsed() / TIME_LIMIT;\n        if (t > 1.0) break;\n        double T = T0 + (T1 - T0) * t;\n\n        bool accept = false;\n        if (bestDelta >= 0) accept = true;\n        else {\n            double prob = exp((double)bestDelta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n        if (accept && bestCode != oldCode) {\n            apply_letter(i, j, bestCode);\n            if (scoreC > bestScore) {\n                bestScore = scoreC;\n                memcpy(bestGrid, g, sizeof(g));\n            }\n        }\n    }\n\n    // Output best grid\n    for (int i = 0; i < N_FIX; ++i) {\n        string out; out.resize(N_FIX);\n        for (int j = 0; j < N_FIX; ++j) out[j] = char('A' + bestGrid[i][j]);\n        cout << out << '\\n';\n    }\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist;\n    vector<int> matchL, matchR;\n\n    HopcroftKarp(int nL_, int nR_) : nL(nL_), nR(nR_), g(nL_), dist(nL_), matchL(nL_, -1), matchR(nR_, -1) {}\n\n    void add_edge(int u, int v) { g[u].push_back(v); }\n\n    bool bfs() {\n        queue<int> q;\n        for (int i = 0; i < nL; ++i) {\n            if (matchL[i] == -1) {\n                dist[i] = 0;\n                q.push(i);\n            } else dist[i] = -1;\n        }\n        bool found = false;\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    bool dfs(int u) {\n        for (int v : g[u]) {\n            int u2 = matchR[v];\n            if (u2 == -1 || (dist[u2] == dist[u] + 1 && dfs(u2))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int max_matching() {\n        int res = 0;\n        while (bfs()) {\n            for (int i = 0; i < nL; ++i) {\n                if (matchL[i] == -1) if (dfs(i)) ++res;\n            }\n        }\n        return res;\n    }\n\n    pair<vector<char>, vector<char>> min_vertex_cover() {\n        // Compute Z: vertices reachable from unmatched left vertices via alternating paths\n        vector<char> visL(nL, 0), visR(nR, 0);\n        queue<int> q;\n        for (int u = 0; u < nL; ++u) if (matchL[u] == -1) {\n            visL[u] = 1;\n            q.push(u);\n        }\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                if (matchL[u] != v) { // unmatched edge\n                    if (!visR[v]) {\n                        visR[v] = 1;\n                        int u2 = matchR[v];\n                        if (u2 != -1 && !visL[u2]) {\n                            visL[u2] = 1;\n                            q.push(u2);\n                        }\n                    }\n                }\n            }\n        }\n        vector<char> coverL(nL, 0), coverR(nR, 0);\n        for (int u = 0; u < nL; ++u) if (!visL[u]) coverL[u] = 1;\n        for (int v = 0; v < nR; ++v) if (visR[v]) coverR[v] = 1;\n        return {coverL, coverR};\n    }\n};\n\nstruct NodePQ {\n    int d, u;\n    bool operator<(const NodePQ& o) const { return d > o.d; }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, si, sj;\n    if (!(cin >> N >> si >> sj)) return 0;\n    vector<string> c(N);\n    for (int i = 0; i < N; ++i) cin >> c[i];\n\n    const int H = N, W = N;\n    auto id = [&](int i, int j){ return i*W + j; };\n    const int M = H*W;\n\n    vector<char> isRoad(M, 0);\n    vector<int> w(M, -1);\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        if (c[i][j] != '#') {\n            int u = id(i,j);\n            isRoad[u] = 1;\n            w[u] = c[i][j] - '0';\n        }\n    }\n\n    // Build row segments\n    vector<int> rowSegId(M, -1), colSegId(M, -1);\n    vector<int> rowPos(M, -1), colPos(M, -1);\n    vector<vector<int>> rowSegCells;\n    for (int i = 0; i < H; ++i) {\n        int j = 0;\n        while (j < W) {\n            if (isRoad[id(i,j)] && (j == 0 || !isRoad[id(i, j-1)])) {\n                int j2 = j;\n                int segId = (int)rowSegCells.size();\n                rowSegCells.emplace_back();\n                while (j2 < W && isRoad[id(i,j2)]) {\n                    int u = id(i,j2);\n                    rowSegId[u] = segId;\n                    rowPos[u] = (int)rowSegCells.back().size();\n                    rowSegCells.back().push_back(u);\n                    ++j2;\n                }\n                j = j2;\n            } else ++j;\n        }\n    }\n    // Build column segments\n    vector<vector<int>> colSegCells;\n    for (int j = 0; j < W; ++j) {\n        int i = 0;\n        while (i < H) {\n            if (isRoad[id(i,j)] && (i == 0 || !isRoad[id(i-1, j)])) {\n                int i2 = i;\n                int segId = (int)colSegCells.size();\n                colSegCells.emplace_back();\n                while (i2 < H && isRoad[id(i2,j)]) {\n                    int u = id(i2,j);\n                    colSegId[u] = segId;\n                    colPos[u] = (int)colSegCells.back().size();\n                    colSegCells.back().push_back(u);\n                    ++i2;\n                }\n                i = i2;\n            } else ++i;\n        }\n    }\n    int nR = (int)rowSegCells.size();\n    int nC = (int)colSegCells.size();\n\n    // Build bipartite graph: row segs -> col segs via edges for each road cell\n    HopcroftKarp hk(nR, nC);\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        int u = id(i,j);\n        if (!isRoad[u]) continue;\n        int r = rowSegId[u], cc = colSegId[u];\n        if (r >= 0 && cc >= 0) hk.add_edge(r, cc);\n    }\n    hk.max_matching();\n    auto [chooseRow_char, chooseCol_char] = hk.min_vertex_cover();\n    vector<char> chooseRow = chooseRow_char, chooseCol = chooseCol_char;\n\n    // Coverage states for chosen segments only\n    vector<char> coveredRow(nR, 0), coveredCol(nC, 0);\n    long long remain = 0;\n    for (int r = 0; r < nR; ++r) if (chooseRow[r]) ++remain;\n    for (int cc = 0; cc < nC; ++cc) if (chooseCol[cc]) ++remain;\n\n    // Prefix sums for along-segment costs\n    vector<vector<int>> rowPref(nR), colPref(nC);\n    for (int r = 0; r < nR; ++r) {\n        int L = (int)rowSegCells[r].size();\n        rowPref[r].resize(L);\n        for (int k = 0; k < L; ++k) {\n            int u = rowSegCells[r][k];\n            rowPref[r][k] = w[u] + (k ? rowPref[r][k-1] : 0);\n        }\n    }\n    for (int cc = 0; cc < nC; ++cc) {\n        int L = (int)colSegCells[cc].size();\n        colPref[cc].resize(L);\n        for (int k = 0; k < L; ++k) {\n            int u = colSegCells[cc][k];\n            colPref[cc][k] = w[u] + (k ? colPref[cc][k-1] : 0);\n        }\n    }\n    auto rowCost = [&](int seg, int p, int q)->int {\n        if (q >= p) return rowPref[seg][q] - rowPref[seg][p];\n        else return rowPref[seg][p-1] - (q > 0 ? rowPref[seg][q-1] : 0);\n    };\n    auto colCost = [&](int seg, int p, int q)->int {\n        if (q >= p) return colPref[seg][q] - colPref[seg][p];\n        else return colPref[seg][p-1] - (q > 0 ? colPref[seg][q-1] : 0);\n    };\n\n    int start = id(si, sj);\n    int cur = start;\n    string ans;\n\n    auto mark_covered_at_cell = [&](int u)->int {\n        int added = 0;\n        int r = rowSegId[u], cc = colSegId[u];\n        if (r >= 0 && chooseRow[r] && !coveredRow[r]) { coveredRow[r] = 1; --remain; ++added; }\n        if (cc >= 0 && chooseCol[cc] && !coveredCol[cc]) { coveredCol[cc] = 1; --remain; ++added; }\n        return added;\n    };\n    mark_covered_at_cell(cur);\n\n    const int INF = 1e9;\n    vector<int> dist(M, INF), prv(M, -1);\n    vector<char> prvDir(M, 0);\n\n    auto reconstruct_and_apply = [&](int s, int t){\n        if (s == t) return;\n        vector<char> moves;\n        int x = t;\n        while (x != s && x != -1) {\n            moves.push_back(prvDir[x]);\n            x = prv[x];\n        }\n        if (x != s) return;\n        reverse(moves.begin(), moves.end());\n        int ci = cur / W, cj = cur % W;\n        for (char mv : moves) {\n            if (mv == 'U') --ci;\n            else if (mv == 'D') ++ci;\n            else if (mv == 'L') --cj;\n            else if (mv == 'R') ++cj;\n            int nid = id(ci, cj);\n            mark_covered_at_cell(nid);\n            ans.push_back(mv);\n        }\n        cur = id(ci, cj);\n    };\n\n    auto dijkstra_to_single = [&](int target){\n        fill(dist.begin(), dist.end(), INF);\n        fill(prv.begin(), prv.end(), -1);\n        fill(prvDir.begin(), prvDir.end(), 0);\n        priority_queue<NodePQ> pq;\n        dist[cur] = 0;\n        pq.push({0, cur});\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (u == target) break;\n            int ui = u / W, uj = u % W;\n            if (ui-1 >= 0) {\n                int v = id(ui-1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'U'; pq.push({nd, v});\n                    }\n                }\n            }\n            if (ui+1 < H) {\n                int v = id(ui+1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'D'; pq.push({nd, v});\n                    }\n                }\n            }\n            if (uj-1 >= 0) {\n                int v = id(ui, uj-1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'L'; pq.push({nd, v});\n                    }\n                }\n            }\n            if (uj+1 < W) {\n                int v = id(ui, uj+1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'R'; pq.push({nd, v});\n                    }\n                }\n            }\n        }\n    };\n\n    auto dijkstra_next_target = [&]()->int {\n        const int LOOKAHEAD_MARGIN = 30;\n        fill(dist.begin(), dist.end(), INF);\n        fill(prv.begin(), prv.end(), -1);\n        fill(prvDir.begin(), prvDir.end(), 0);\n        priority_queue<NodePQ> pq;\n        dist[cur] = 0;\n        pq.push({0, cur});\n\n        auto is_union_target = [&](int u)->bool {\n            int r = rowSegId[u], cc = colSegId[u];\n            if (r >= 0 && chooseRow[r] && !coveredRow[r]) return true;\n            if (cc >= 0 && chooseCol[cc] && !coveredCol[cc]) return true;\n            return false;\n        };\n        auto is_inter_target = [&](int u)->bool {\n            int r = rowSegId[u], cc = colSegId[u];\n            bool t1 = (r >= 0 && chooseRow[r] && !coveredRow[r]);\n            bool t2 = (cc >= 0 && chooseCol[cc] && !coveredCol[cc]);\n            return t1 && t2;\n        };\n\n        int bestUnion = -1, bestUnionDist = INF;\n        int bestInter = -1, bestInterDist = INF;\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (bestInter != -1 && d >= bestInterDist) break;\n            if (bestUnion != -1 && d > bestUnionDist + LOOKAHEAD_MARGIN) break;\n\n            if (is_union_target(u)) {\n                if (d < bestUnionDist) {\n                    bestUnionDist = d;\n                    bestUnion = u;\n                }\n                if (is_inter_target(u)) {\n                    if (d < bestInterDist) {\n                        bestInterDist = d;\n                        bestInter = u;\n                    }\n                }\n            }\n\n            int ui = u / W, uj = u % W;\n            if (ui-1 >= 0) {\n                int v = id(ui-1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'U'; pq.push({nd, v}); }\n                }\n            }\n            if (ui+1 < H) {\n                int v = id(ui+1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'D'; pq.push({nd, v}); }\n                }\n            }\n            if (uj-1 >= 0) {\n                int v = id(ui, uj-1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'L'; pq.push({nd, v}); }\n                }\n            }\n            if (uj+1 < W) {\n                int v = id(ui, uj+1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'R'; pq.push({nd, v}); }\n                }\n            }\n        }\n        if (bestInter != -1) return bestInter;\n        if (bestUnion != -1) return bestUnion;\n        return cur; // fallback\n    };\n\n    auto local_sweep = [&](){\n        // Conservative sweeping to catch nearby MVC intersections\n        const int STEP_LIMIT = 40;   // max cost per single extension\n        const int TOTAL_LIMIT = 120; // total budget per call\n        int spent = 0;\n\n        while (remain > 0 && spent < TOTAL_LIMIT) {\n            int u = cur;\n            int r = rowSegId[u], cc = colSegId[u];\n            int rp = (r >= 0 ? rowPos[u] : -1);\n            int cp = (cc >= 0 ? colPos[u] : -1);\n\n            int bestRowPos = -1, bestRowCost = INT_MAX;\n            if (r >= 0) {\n                // search left for nearest uncovered chosen col segment\n                for (int q = rp - 1; q >= 0; --q) {\n                    int v = rowSegCells[r][q];\n                    int c2 = colSegId[v];\n                    if (c2 >= 0 && chooseCol[c2] && !coveredCol[c2]) {\n                        bestRowPos = q;\n                        bestRowCost = rowCost(r, rp, q);\n                        break;\n                    }\n                }\n                // search right\n                int L = (int)rowSegCells[r].size();\n                for (int q = rp + 1; q < L; ++q) {\n                    int v = rowSegCells[r][q];\n                    int c2 = colSegId[v];\n                    if (c2 >= 0 && chooseCol[c2] && !coveredCol[c2]) {\n                        int cost = rowCost(r, rp, q);\n                        if (cost < bestRowCost) { bestRowCost = cost; bestRowPos = q; }\n                        break;\n                    }\n                }\n            }\n\n            int bestColPos = -1, bestColCost = INT_MAX;\n            if (cc >= 0) {\n                // up\n                for (int q = cp - 1; q >= 0; --q) {\n                    int v = colSegCells[cc][q];\n                    int r2 = rowSegId[v];\n                    if (r2 >= 0 && chooseRow[r2] && !coveredRow[r2]) {\n                        bestColPos = q;\n                        bestColCost = colCost(cc, cp, q);\n                        break;\n                    }\n                }\n                // down\n                int L = (int)colSegCells[cc].size();\n                for (int q = cp + 1; q < L; ++q) {\n                    int v = colSegCells[cc][q];\n                    int r2 = rowSegId[v];\n                    if (r2 >= 0 && chooseRow[r2] && !coveredRow[r2]) {\n                        int cost = colCost(cc, cp, q);\n                        if (cost < bestColCost) { bestColCost = cost; bestColPos = q; }\n                        break;\n                    }\n                }\n            }\n\n            bool doRow = false, doCol = false;\n            int extCost = INT_MAX;\n            if (bestRowPos != -1) { doRow = true; extCost = bestRowCost; }\n            if (bestColPos != -1 && bestColCost < extCost) { doRow = false; doCol = true; extCost = bestColCost; }\n\n            if (extCost == INT_MAX || extCost > STEP_LIMIT || spent + extCost > TOTAL_LIMIT) break;\n\n            if (doRow) {\n                int targetPos = bestRowPos;\n                int ci = cur / W, cj = cur % W;\n                int diff = targetPos - rp;\n                char mv = (diff > 0 ? 'R' : 'L');\n                int steps = abs(diff);\n                for (int t = 0; t < steps; ++t) {\n                    if (mv == 'R') ++cj; else --cj;\n                    int nid = id(ci, cj);\n                    mark_covered_at_cell(nid);\n                    ans.push_back(mv);\n                }\n                cur = id(ci, cj);\n                spent += extCost;\n            } else if (doCol) {\n                int targetPos = bestColPos;\n                int ci = cur / W, cj = cur % W;\n                int diff = targetPos - cp;\n                char mv = (diff > 0 ? 'D' : 'U');\n                int steps = abs(diff);\n                for (int t = 0; t < steps; ++t) {\n                    if (mv == 'D') ++ci; else --ci;\n                    int nid = id(ci, cj);\n                    mark_covered_at_cell(nid);\n                    ans.push_back(mv);\n                }\n                cur = id(ci, cj);\n                spent += extCost;\n            } else {\n                break;\n            }\n        }\n    };\n\n    // Main loop\n    while (remain > 0) {\n        int dest = dijkstra_next_target();\n        if (dest == cur) {\n            // fallback: pick any target explicitly by full dijkstra\n            dijkstra_to_single(cur); // init dist/prv from current\n            int bestD = INF; dest = -1;\n            for (int u = 0; u < M; ++u) if (isRoad[u]) {\n                int r = rowSegId[u], cc = colSegId[u];\n                bool need = (r >= 0 && chooseRow[r] && !coveredRow[r]) || (cc >= 0 && chooseCol[cc] && !coveredCol[cc]);\n                if (need && dist[u] < bestD) { bestD = dist[u]; dest = u; }\n            }\n            if (dest == -1) break;\n        } else {\n            // Already have dist/prv/prvDir from the multi-target search\n        }\n        reconstruct_and_apply(cur, dest);\n        // local sweep to grab nearby MVC segments at low extra cost\n        local_sweep();\n    }\n\n    // Return to start\n    if (cur != start) {\n        dijkstra_to_single(start);\n        reconstruct_and_apply(cur, start);\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Fast RNG (used for small init noise)\nstruct FastRNG {\n    uint64_t x;\n    FastRNG(uint64_t seed=88172645463393265ull) : x(seed) {}\n    uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    double drand() { return (next() >> 11) * (1.0/9007199254740992.0); } // [0,1)\n    double uni(double a, double b){ return a + (b-a)*drand(); }\n};\n\n// Hungarian algorithm (min-cost assignment) on an n x n matrix\nstruct Hungarian {\n    static pair<double, vector<int>> solve(const vector<vector<double>>& a) {\n        int n = (int)a.size();\n        const double INF = 1e100;\n        vector<double> u(n+1, 0), v(n+1, 0);\n        vector<int> p(n+1, 0), way(n+1, 0);\n        for (int i = 1; i <= n; ++i) {\n            p[0] = i;\n            int j0 = 0;\n            vector<double> minv(n+1, INF);\n            vector<char> used(n+1, false);\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                double delta = INF;\n                for (int j = 1; j <= n; ++j) if (!used[j]) {\n                    double cur = a[i0-1][j-1] - u[i0] - v[j];\n                    if (cur < minv[j]) { minv[j] = cur; way[j] = j0; }\n                    if (minv[j] < delta) { delta = minv[j]; j1 = j; }\n                }\n                for (int j = 0; j <= n; ++j) {\n                    if (used[j]) { u[p[j]] += delta; v[j] -= delta; }\n                    else { minv[j] -= delta; }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n        vector<int> assignment(n, -1);\n        for (int j = 1; j <= n; ++j) if (p[j]) assignment[p[j]-1] = j-1;\n        double value = -v[0];\n        return {value, assignment};\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K, R;\n    if(!(cin >> N >> M >> K >> R)) return 0;\n\n    vector<vector<int>> D(N, vector<int>(K));\n    vector<double> sumD(N, 0.0), meanD(K, 0.0);\n    for(int i=0;i<N;i++){\n        double s=0.0;\n        for(int k=0;k<K;k++){\n            cin >> D[i][k];\n            s += D[i][k];\n            meanD[k] += D[i][k];\n        }\n        sumD[i] = s;\n    }\n    for(int k=0;k<K;k++) meanD[k] /= N;\n\n    vector<vector<int>> G(N);\n    vector<int> indeg(N, 0);\n    for(int e=0;e<R;e++){\n        int u,v; cin >> u >> v; --u; --v;\n        G[u].push_back(v);\n        indeg[v]++;\n    }\n\n    // Longest path depth (DAG with u<v)\n    vector<int> dp(N, 1), outdeg(N);\n    for(int i=N-1;i>=0;--i){\n        int best=0;\n        for(int v: G[i]) best = max(best, dp[v]);\n        dp[i] = 1 + best;\n        outdeg[i] = (int)G[i].size();\n    }\n    int dpMax = *max_element(dp.begin(), dp.end()); if(dpMax<=0) dpMax=1;\n    double sumDmax = *max_element(sumD.begin(), sumD.end()); if(sumDmax<=0) sumDmax=1.0;\n    int outMax = *max_element(outdeg.begin(), outdeg.end()); if(outMax<=0) outMax=1;\n\n    // Base priority (normalized)\n    vector<double> basePri(N);\n    const double wDepth = 1.0;\n    const double wOut = 0.3;\n    const double wDiff = 0.2;\n    for(int i=0;i<N;i++){\n        double nd = (double)dp[i] / dpMax;\n        double no = (double)outdeg[i] / outMax;\n        double nf = sumD[i] / sumDmax;\n        basePri[i] = wDepth*nd + wOut*no + wDiff*nf; // ~[0, ~1.5]\n    }\n\n    // Ready tracking (dynamic)\n    vector<char> in_ready(N, 0), started(N, 0), done(N, 0);\n    vector<int> readySince(N, 0);\n    vector<int> readyList; readyList.reserve(N);\n\n    // Initialize ready set\n    for(int i=0;i<N;i++){\n        if(indeg[i] == 0){\n            in_ready[i] = 1;\n            readySince[i] = 0; // available from day 1\n            readyList.push_back(i);\n        }\n    }\n\n    // Worker state\n    vector<int> workerTask(M, -1);\n    vector<int> workerStart(M, 0);\n\n    // Skill estimates and hard lower bounds\n    FastRNG rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    vector<vector<double>> S(M, vector<double>(K, 0.0));\n    vector<vector<double>> sLB(M, vector<double>(K, 0.0));\n    for(int j=0;j<M;j++){\n        for(int k=0;k<K;k++){\n            double val = meanD[k] * 1.6 + rng.uni(-0.5, 0.5);\n            if(val < 0) val = 0;\n            S[j][k] = val;\n            sLB[j][k] = 0.0;\n        }\n    }\n    vector<int> obsCnt(M, 0);\n\n    // Time model helpers\n    auto expected_time_from_w = [&](double w)->double{\n        if (w <= 1e-12) return 1.0;\n        double sum = 0.0;\n        for(int r=-3;r<=3;r++){\n            double val = w + r;\n            if(val < 1.0) val = 1.0;\n            sum += val;\n        }\n        return sum / 7.0;\n    };\n    auto dEt_dw = [&](double w)->double{\n        int cnt=0;\n        for(int r=-3;r<=3;r++){\n            if (w + r > 1.0) cnt++;\n        }\n        return cnt / 7.0;\n    };\n\n    // Softplus smoothing for SGD\n    const double beta = 0.35;\n    const double invbeta = 1.0 / beta;\n    auto softplus_sum = [&](const vector<int>& dvec, const vector<double>& svec)->double{\n        double res=0.0;\n        for(int k=0;k<K;k++){\n            double x = dvec[k] - svec[k];\n            double bx = beta * x;\n            if (bx > 30.0) res += x;\n            else if (bx < -30.0) { /* ~0 */ }\n            else res += log1p(exp(bx)) * invbeta;\n        }\n        return res;\n    };\n    auto sigmoid_beta = [&](double x)->double{\n        double bx = beta * x;\n        if (bx >= 0) {\n            double e = exp(-bx);\n            return 1.0 / (1.0 + e);\n        } else {\n            double e = exp(bx);\n            return e / (1.0 + e);\n        }\n    };\n\n    // Predict expected time using clamped skills with lower bounds\n    const double Smax = 120.0;\n    auto predict_time = [&](int i, int j)->double{\n        double w=0.0;\n        for(int k=0;k<K;k++){\n            double sj = S[j][k];\n            if (sj < sLB[j][k]) sj = sLB[j][k];\n            double z = (double)D[i][k] - sj;\n            if (z > 0) w += z;\n        }\n        return expected_time_from_w(w);\n    };\n\n    // SGD update\n    const double baseLR = 0.5;\n    auto update_skill = [&](int j, int i, int t){\n        vector<double> Sc(S[j]);\n        for(int k=0;k<K;k++) if(Sc[k] < sLB[j][k]) Sc[k] = sLB[j][k];\n        double wsoft = softplus_sum(D[i], Sc);\n        double pred = (wsoft < 0.05 ? 1.0 : expected_time_from_w(wsoft));\n        double target = max(1, t);\n        double err = pred - target;\n        double gE = dEt_dw(wsoft); // in [0,1]\n\n        double lr = baseLR / sqrt((double)obsCnt[j] + 1.0);\n        if (t <= 1) lr *= 0.2;\n        else if (t >= 5) lr *= 1.1;\n\n        if (err > 8) err = 8;\n        if (err < -8) err = -8;\n\n        double scale = lr * gE;\n        if (scale <= 0) { obsCnt[j]++; return; }\n\n        for(int k=0;k<K;k++){\n            double s_curr = S[j][k];\n            if (s_curr < sLB[j][k]) s_curr = sLB[j][k];\n            double g = sigmoid_beta((double)D[i][k] - s_curr); // d wsoft / d s_k = -g\n            double ns = s_curr + scale * err * g;\n            if (ns < sLB[j][k]) ns = sLB[j][k];\n            if (ns < 0) ns = 0;\n            if (ns > Smax) ns = Smax;\n            S[j][k] = ns;\n        }\n        obsCnt[j]++;\n    };\n\n    // Parameters for dynamic pool and matching\n    const double ageCoef = 0.25;   // bonus added to basePri\n    const int ageCap = 7;          // days to saturate age bonus\n    const double priWeight = 0.40; // weight in cost: t_pred - priWeight * score\n    const double riskCoef = 0.45;  // uncertainty penalty coefficient\n\n    int day = 0;\n    vector<double> scoreBuf(N, -1.0); // reused each day for ready tasks' scores\n    vector<char> inPool(N, 0);\n\n    while(true){\n        day++;\n\n        // Collect free workers\n        vector<int> freeWorkers;\n        freeWorkers.reserve(M);\n        for(int j=0;j<M;j++) if(workerTask[j] == -1) freeWorkers.push_back(j);\n\n        vector<pair<int,int>> assignments; // (worker, task)\n\n        if(!freeWorkers.empty()){\n            // Build full candidate list with dynamic scores\n            vector<pair<double,int>> cand; cand.reserve(readyList.size());\n            for(int idx=0; idx<(int)readyList.size(); ++idx){\n                int i = readyList[idx];\n                if(i < 0) continue;\n                if(!in_ready[i]) continue;\n                if(started[i] || done[i]) continue;\n                int age = max(0, day - max(1, readySince[i]));\n                double ageBoost = ageCoef * (double)(min(age, ageCap)) / (double)ageCap;\n                double score = basePri[i] + ageBoost;\n                cand.emplace_back(score, i);\n                scoreBuf[i] = score;\n            }\n\n            int readyCnt = (int)cand.size();\n            if(readyCnt > 0){\n                // Base pool by score\n                int F = (int)freeWorkers.size();\n                int baseTarget = min(readyCnt, max(F * 10, 20)); // base pool\n                baseTarget = min(baseTarget, 70);                // cap base pool to keep fast\n                if (baseTarget < readyCnt){\n                    nth_element(cand.begin(), cand.begin() + baseTarget, cand.end(),\n                                [](const pair<double,int>& a, const pair<double,int>& b){\n                                    return a.first > b.first; // descending\n                                });\n                } else {\n                    baseTarget = readyCnt;\n                }\n\n                // Reset inPool marks\n                for(int ii=0; ii<(int)readyList.size(); ++ii){\n                    int id = readyList[ii];\n                    if (id>=0) inPool[id] = 0;\n                }\n\n                vector<int> pool; pool.reserve(100);\n                vector<double> poolScore; poolScore.reserve(100);\n                for(int i=0;i<baseTarget;i++){\n                    int id = cand[i].second;\n                    pool.push_back(id);\n                    poolScore.push_back(cand[i].first);\n                    inPool[id] = 1;\n                }\n\n                // Augment pool with worker-centric picks from rest\n                int unionCap = 90; // final pool cap\n                int addPerWorker = 3;\n                if ((int)pool.size() < unionCap){\n                    // Build list of rest candidates (unsorted)\n                    vector<pair<double,int>> rest;\n                    rest.reserve(readyCnt - baseTarget);\n                    for(int i=baseTarget;i<readyCnt;i++) rest.push_back(cand[i]);\n\n                    // Collect candidates from workers\n                    struct Cand { int task; double metric; }; // metric = min tpred - priWeight*score\n                    unordered_map<int, double> bestMetric; bestMetric.reserve(256);\n                    for(int fi=0; fi<F; ++fi){\n                        int j = freeWorkers[fi];\n                        // select top-k by predicted time among rest\n                        vector<pair<double,int>> topk; topk.reserve(addPerWorker+2);\n                        for(auto &rp : rest){\n                            int ti = rp.second;\n                            double tpred = predict_time(ti, j);\n                            if ((int)topk.size() < addPerWorker){\n                                topk.emplace_back(tpred, ti);\n                                if ((int)topk.size() == addPerWorker){\n                                    sort(topk.begin(), topk.end(),\n                                         [](const auto& A, const auto& B){ return A.first < B.first; });\n                                }\n                            } else if (tpred < topk.back().first){\n                                topk.back() = {tpred, ti};\n                                // keep sorted small vector\n                                for (int x = (int)topk.size()-1; x>0 && topk[x].first < topk[x-1].first; --x)\n                                    swap(topk[x], topk[x-1]);\n                            }\n                        }\n                        for(auto &p : topk){\n                            int ti = p.second;\n                            if (inPool[ti]) continue;\n                            double metric = p.first - priWeight * scoreBuf[ti];\n                            auto it = bestMetric.find(ti);\n                            if (it == bestMetric.end()) bestMetric.emplace(ti, metric);\n                            else if (metric < it->second) it->second = metric;\n                        }\n                    }\n                    // Convert to vector and sort by metric\n                    vector<pair<double,int>> addList;\n                    addList.reserve(bestMetric.size());\n                    for(auto &kv : bestMetric){\n                        addList.emplace_back(kv.second, kv.first);\n                    }\n                    sort(addList.begin(), addList.end(),\n                         [](const auto& A, const auto& B){ return A.first < B.first; });\n                    for(auto &pp : addList){\n                        int ti = pp.second;\n                        if ((int)pool.size() >= unionCap) break;\n                        if (!inPool[ti]){\n                            pool.push_back(ti);\n                            poolScore.push_back(scoreBuf[ti]);\n                            inPool[ti] = 1;\n                        }\n                    }\n                }\n\n                int P = (int)pool.size();\n                if (P > 0){\n                    // Build cost matrix for Hungarian\n                    int n = max(F, P);\n                    const double BIG = 1e6;\n                    vector<vector<double>> cost(n, vector<double>(n, BIG));\n\n                    for(int fi=0; fi<F; ++fi){\n                        int j = freeWorkers[fi];\n                        double uncert = 1.0 / sqrt((double)obsCnt[j] + 1.0);\n                        for(int pi=0; pi<P; ++pi){\n                            int ti = pool[pi];\n                            double tpred = predict_time(ti, j);\n                            // Uncertainty penalty: scaled by difficulty and depth\n                            double nf = sumD[ti] / sumDmax;\n                            double nd = (double)dp[ti] / dpMax;\n                            double risk = riskCoef * uncert * (0.6*nf + 0.4*nd);\n                            double c = tpred + risk - priWeight * poolScore[pi];\n                            cost[fi][pi] = c;\n                        }\n                        for(int ccol=P; ccol<n; ++ccol) cost[fi][ccol] = 100.0; // dummy task\n                    }\n                    for(int r=F; r<n; ++r){\n                        for(int c=0;c<n;c++) cost[r][c] = 0.0; // dummy workers\n                    }\n\n                    auto res = Hungarian::solve(cost);\n                    vector<int> assignCols = res.second;\n\n                    vector<char> taskTaken(P, 0), workerTaken(F, 0);\n                    for(int fi=0; fi<F; ++fi){\n                        int col = assignCols[fi];\n                        if(col >= 0 && col < P){\n                            int j = freeWorkers[fi];\n                            int ti = pool[col];\n                            assignments.emplace_back(j, ti);\n                            workerTaken[fi] = 1;\n                            taskTaken[col] = 1;\n                        }\n                    }\n                    // Mark assigned tasks as no longer ready\n                    for(int pi=0; pi<P; ++pi){\n                        if(taskTaken[pi]){\n                            int ti = pool[pi];\n                            in_ready[ti] = 0;\n                        }\n                    }\n                }\n\n                // cleanup score buffer for next day (only clear used indices)\n                for(auto &p : cand) scoreBuf[p.second] = -1.0;\n            }\n        }\n\n        // Emit output\n        cout << assignments.size();\n        for(auto &p: assignments){\n            int j = p.first;\n            int i = p.second;\n            cout << \" \" << (j+1) << \" \" << (i+1);\n            workerTask[j] = i;\n            workerStart[j] = day;\n            started[i] = 1;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        // Read feedback\n        int ncomp;\n        if(!(cin >> ncomp)) return 0;\n        if(ncomp == -1){\n            // Completed or day limit\n            return 0;\n        }\n        vector<int> fins(ncomp);\n        for(int idx=0; idx<ncomp; ++idx){\n            int fj; cin >> fj; --fj;\n            fins[idx] = fj;\n        }\n        sort(fins.begin(), fins.end());\n        fins.erase(unique(fins.begin(), fins.end()), fins.end());\n\n        // Process completions\n        for(int fj : fins){\n            int i = workerTask[fj];\n            if(i < 0) continue; // safety\n            int t = day - workerStart[fj] + 1;\n\n            // Skill update\n            update_skill(fj, i, t);\n            // If task finished in 1 day, enforce per-dimension lower bound s >= d\n            if (t <= 1){\n                for(int k=0;k<K;k++){\n                    if (sLB[fj][k] < D[i][k]) sLB[fj][k] = D[i][k];\n                    if (S[fj][k] < sLB[fj][k]) S[fj][k] = sLB[fj][k];\n                }\n            }\n\n            workerTask[fj] = -1;\n            done[i] = 1;\n\n            // Unlock children for next day\n            for(int v: G[i]){\n                indeg[v]--;\n                if(indeg[v] == 0 && !started[v] && !done[v] && !in_ready[v]){\n                    in_ready[v] = 1;\n                    readySince[v] = day; // ready for next day\n                    readyList.push_back(v);\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 88172645463393265ull) { x = seed; }\n    inline uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int randint(int l, int r) { // inclusive\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    inline double drand() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstatic inline int manhattan(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\nstruct Order {\n    int id; // 0-based original index\n    int ax, ay, cx, cy; // pickup (a,b), drop (c,d)\n};\n\nstruct Event {\n    int oid; // 0..M-1 (index in selected array)\n    bool is_pick; // true: pickup, false: drop\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 1000;\n    const int M = 50;\n    const int OFFICE_X = 400;\n    const int OFFICE_Y = 400;\n\n    vector<Order> all(N);\n    for (int i = 0; i < N; ++i) {\n        int a,b,c,d;\n        if (!(cin >> a >> b >> c >> d)) return 0;\n        all[i] = {i, a, b, c, d};\n    }\n\n    auto s_cost = [&](const Order& o)->long long {\n        long long s = 0;\n        s += manhattan(OFFICE_X, OFFICE_Y, o.ax, o.ay);\n        s += manhattan(o.ax, o.ay, o.cx, o.cy);\n        s += manhattan(o.cx, o.cy, OFFICE_X, OFFICE_Y);\n        return s;\n    };\n\n    // Rank orders by surrogate cost\n    vector<pair<long long,int>> score_idx;\n    score_idx.reserve(N);\n    for (int i = 0; i < N; ++i) score_idx.emplace_back(s_cost(all[i]), i);\n    sort(score_idx.begin(), score_idx.end());\n\n    // Choose top M initially\n    vector<int> selected_orig_ids(M);\n    for (int i = 0; i < M; ++i) selected_orig_ids[i] = score_idx[i].second;\n\n    // Build selected arrays and coords\n    vector<Order> sel(M);\n    for (int i = 0; i < M; ++i) sel[i] = all[selected_orig_ids[i]];\n    vector<int> px(M), py(M), dx(M), dy(M);\n    for (int i = 0; i < M; ++i) {\n        px[i] = sel[i].ax; py[i] = sel[i].ay;\n        dx[i] = sel[i].cx; dy[i] = sel[i].cy;\n    }\n\n    auto coord_pick = [&](int oid)->pair<int,int>{ return {px[oid], py[oid]}; };\n    auto coord_drop = [&](int oid)->pair<int,int>{ return {dx[oid], dy[oid]}; };\n\n    auto coord_of_event = [&](const Event &e) -> pair<int,int> {\n        return e.is_pick ? coord_pick(e.oid) : coord_drop(e.oid);\n    };\n\n    auto route_cost = [&](const vector<Event> &s)->long long {\n        long long t = 0;\n        int lx = OFFICE_X, ly = OFFICE_Y;\n        for (auto &e : s) {\n            auto [nx, ny] = e.is_pick ? coord_pick(e.oid) : coord_drop(e.oid);\n            t += manhattan(lx, ly, nx, ny);\n            lx = nx; ly = ny;\n        }\n        t += manhattan(lx, ly, OFFICE_X, OFFICE_Y);\n        return t;\n    };\n\n    // Initial route builders\n    auto build_route_greedy = [&]()->vector<Event> {\n        vector<Event> seq;\n        seq.reserve(2*M);\n        vector<char> picked(M, 0), delivered(M, 0);\n        int curx = OFFICE_X, cury = OFFICE_Y;\n        int delivered_cnt = 0;\n        const double alpha_pick_penalty = 0.2;\n        while (delivered_cnt < M) {\n            int best_oid = -1;\n            bool best_is_pick = true;\n            double best_score = 1e100;\n\n            for (int i = 0; i < M; ++i) if (!picked[i]) {\n                int nx = px[i], ny = py[i];\n                int base = manhattan(curx, cury, nx, ny);\n                int pd = manhattan(px[i], py[i], dx[i], dy[i]);\n                double sc = base + alpha_pick_penalty * pd;\n                if (sc < best_score) {\n                    best_score = sc;\n                    best_oid = i;\n                    best_is_pick = true;\n                }\n            }\n            for (int i = 0; i < M; ++i) if (picked[i] && !delivered[i]) {\n                int nx = dx[i], ny = dy[i];\n                int base = manhattan(curx, cury, nx, ny);\n                double sc = base;\n                if (sc < best_score) {\n                    best_score = sc;\n                    best_oid = i;\n                    best_is_pick = false;\n                }\n            }\n            if (best_oid == -1) {\n                int bestd = INT_MAX, bi = -1;\n                for (int i = 0; i < M; ++i) if (!picked[i]) {\n                    int d = manhattan(curx, cury, px[i], py[i]);\n                    if (d < bestd) { bestd = d; bi = i; }\n                }\n                best_oid = bi;\n                best_is_pick = true;\n            }\n            if (best_is_pick) {\n                picked[best_oid] = 1;\n                seq.push_back({best_oid, true});\n                curx = px[best_oid]; cury = py[best_oid];\n            } else {\n                delivered[best_oid] = 1;\n                seq.push_back({best_oid, false});\n                curx = dx[best_oid]; cury = dy[best_oid];\n                delivered_cnt++;\n            }\n        }\n        return seq;\n    };\n    auto build_route_pick_then_drop = [&]()->vector<Event> {\n        vector<Event> seq;\n        seq.reserve(2*M);\n        vector<char> visP(M, 0), visD(M, 0);\n        int curx = OFFICE_X, cury = OFFICE_Y;\n        // pickups\n        for (int k = 0; k < M; ++k) {\n            int best = -1, bestd = INT_MAX;\n            for (int i = 0; i < M; ++i) if (!visP[i]) {\n                int d = manhattan(curx, cury, px[i], py[i]);\n                if (d < bestd) { bestd = d; best = i; }\n            }\n            visP[best] = 1;\n            seq.push_back({best, true});\n            curx = px[best]; cury = py[best];\n        }\n        // deliveries\n        for (int k = 0; k < M; ++k) {\n            int best = -1, bestd = INT_MAX;\n            for (int i = 0; i < M; ++i) if (!visD[i]) {\n                int d = manhattan(curx, cury, dx[i], dy[i]);\n                if (d < bestd) { bestd = d; best = i; }\n            }\n            visD[best] = 1;\n            seq.push_back({best, false});\n            curx = dx[best]; cury = dy[best];\n        }\n        return seq;\n    };\n\n    vector<Event> seqA = build_route_greedy();\n    vector<Event> seqB = build_route_pick_then_drop();\n    long long costA = route_cost(seqA);\n    long long costB = route_cost(seqB);\n    vector<Event> seq = (costA <= costB) ? seqA : seqB;\n\n    int L = (int)seq.size(); // should be 2*M\n\n    // pos arrays\n    vector<int> posPick(M, -1), posDel(M, -1);\n    auto recompute_positions = [&](){\n        fill(posPick.begin(), posPick.end(), -1);\n        fill(posDel.begin(), posDel.end(), -1);\n        for (int i = 0; i < (int)seq.size(); ++i) {\n            if (seq[i].is_pick) posPick[seq[i].oid] = i;\n            else posDel[seq[i].oid] = i;\n        }\n        L = (int)seq.size();\n    };\n    recompute_positions();\n\n    RNG rng(chrono::high_resolution_clock::now().time_since_epoch().count()*11995408973635179863ull);\n\n    // Helpers for coords at index\n    auto get_coord_by_index = [&](int idx)->pair<int,int>{\n        const Event &e = seq[idx];\n        return e.is_pick ? coord_pick(e.oid) : coord_drop(e.oid);\n    };\n\n    // Delta for single-event relocation\n    auto delta_move_single = [&](int p, int q)->long long {\n        const Event &ev = seq[p];\n        int oid = ev.oid;\n        if (ev.is_pick) {\n            int pos_del_prime = posDel[oid] - 1; // after removal\n            if (q > pos_del_prime) return (long long)4e18; // invalid\n        } else {\n            int pos_pick_prime = posPick[oid];\n            if (q <= pos_pick_prime) return (long long)4e18; // invalid\n        }\n        auto curr = get_coord_by_index(p);\n        pair<int,int> prevc, nextc;\n        if (p == 0) prevc = {OFFICE_X, OFFICE_Y};\n        else prevc = get_coord_by_index(p-1);\n        if (p == L-1) nextc = {OFFICE_X, OFFICE_Y};\n        else nextc = get_coord_by_index(p+1);\n        long long old_edges = (long long)manhattan(prevc.first, prevc.second, curr.first, curr.second)\n                            + (long long)manhattan(curr.first, curr.second, nextc.first, nextc.second);\n        long long new_edges = (long long)manhattan(prevc.first, prevc.second, nextc.first, nextc.second);\n        long long delta = new_edges - old_edges;\n\n        pair<int,int> prev2, next2;\n        if (q == 0) prev2 = {OFFICE_X, OFFICE_Y};\n        else {\n            int j1 = q - 1;\n            int orig1 = (j1 < p ? j1 : j1 + 1);\n            prev2 = get_coord_by_index(orig1);\n        }\n        if (q == L-1) {\n            next2 = {OFFICE_X, OFFICE_Y};\n        } else {\n            int orig2 = (q < p ? q : q + 1);\n            next2 = get_coord_by_index(orig2);\n        }\n        long long add_edges = (long long)manhattan(prev2.first, prev2.second, curr.first, curr.second)\n                            + (long long)manhattan(curr.first, curr.second, next2.first, next2.second);\n        long long rem_edge = (long long)manhattan(prev2.first, prev2.second, next2.first, next2.second);\n        delta += add_edges - rem_edge;\n\n        return delta;\n    };\n\n    auto apply_move_single = [&](int p, int q) {\n        Event ev = seq[p];\n        seq.erase(seq.begin() + p);\n        seq.insert(seq.begin() + q, ev);\n        recompute_positions();\n    };\n\n    // Mapping helpers for pair removal (p1<p2)\n    auto get_after_removals_coord = [&](int p1, int p2, int k)->pair<int,int>{\n        int orig;\n        if (k < p1) orig = k;\n        else if (k < p2 - 1) orig = k + 1;\n        else orig = k + 2;\n        return get_coord_by_index(orig);\n    };\n    auto get_after_removals_and_pick_coord = [&](int p1, int p2, int i, const pair<int,int>& pickCoord, int k)->pair<int,int>{\n        if (k == i) return pickCoord;\n        if (k < i) return get_after_removals_coord(p1, p2, k);\n        return get_after_removals_coord(p1, p2, k - 1);\n    };\n\n    // Delta for pair relocation of the same order (remove both, insert at i<j)\n    auto delta_move_pair = [&](int oid, int i, int j)->long long {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        if (!(0 <= p1 && p1 < p2 && p2 < L)) return (long long)4e18;\n        // Removal delta for p1\n        auto curr1 = get_coord_by_index(p1);\n        pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n        long long delta = 0;\n        delta += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n               - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n               - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n        // Removal delta for p2 after removing p1\n        auto curr2 = get_coord_by_index(p2);\n        pair<int,int> prev2prime, next2prime;\n        if (p2 == p1 + 1) {\n            prev2prime = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        } else {\n            prev2prime = get_coord_by_index(p2 - 1);\n        }\n        next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n        delta += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n               - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n               - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n\n        // Insertion\n        int L2 = L - 2;\n        if (i < 0 || i > L2) return (long long)4e18;\n        if (j <= i || j > L2 + 1) return (long long)4e18;\n        auto pC = coord_pick(oid);\n        auto dC = coord_drop(oid);\n        pair<int,int> prevI = (i == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i - 1);\n        pair<int,int> nextI = (i == L2) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i);\n        long long delta_ins = 0;\n        delta_ins += (long long)manhattan(prevI.first, prevI.second, pC.first, pC.second)\n                   + (long long)manhattan(pC.first, pC.second, nextI.first, nextI.second)\n                   - (long long)manhattan(prevI.first, prevI.second, nextI.first, nextI.second);\n\n        pair<int,int> prevJ = (j == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j - 1);\n        pair<int,int> nextJ = (j == L2 + 1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j);\n        delta_ins += (long long)manhattan(prevJ.first, prevJ.second, dC.first, dC.second)\n                   + (long long)manhattan(dC.first, dC.second, nextJ.first, nextJ.second)\n                   - (long long)manhattan(prevJ.first, prevJ.second, nextJ.first, nextJ.second);\n\n        return delta + delta_ins;\n    };\n\n    auto apply_move_pair = [&](int oid, int i, int j) {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        // remove delivery first then pickup to keep indices valid\n        seq.erase(seq.begin() + p2);\n        seq.erase(seq.begin() + p1);\n        // insert pickup at i (in the sequence after both removals)\n        Event ep{oid, true};\n        if (i < 0) i = 0;\n        if (i > (int)seq.size()) i = (int)seq.size();\n        seq.insert(seq.begin() + i, ep);\n        // insert drop at j (in the sequence after inserting pickup)\n        Event ed{oid, false};\n        if (j < 0) j = 0;\n        if (j > (int)seq.size()) j = (int)seq.size();\n        seq.insert(seq.begin() + j, ed);\n        recompute_positions();\n    };\n\n    // Best insertion positions for a given pair after removing two positions (p1,p2)\n    auto best_insertion_after_removal = [&](int p1, int p2, const pair<int,int>& pC, const pair<int,int>& dC, long long &bestDelta, int &bestI, int &bestJ){\n        int L2 = L - 2;\n        bestDelta = (long long)4e18;\n        bestI = 0; bestJ = 1;\n        for (int i = 0; i <= L2; ++i) {\n            pair<int,int> prevI = (i == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i - 1);\n            pair<int,int> nextI = (i == L2) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i);\n            long long delta_pick = (long long)manhattan(prevI.first, prevI.second, pC.first, pC.second)\n                                 + (long long)manhattan(pC.first, pC.second, nextI.first, nextI.second)\n                                 - (long long)manhattan(prevI.first, prevI.second, nextI.first, nextI.second);\n            for (int j = i + 1; j <= L2 + 1; ++j) {\n                pair<int,int> prevJ = (j == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j - 1);\n                pair<int,int> nextJ = (j == L2 + 1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j);\n                long long delta_drop = (long long)manhattan(prevJ.first, prevJ.second, dC.first, dC.second)\n                                     + (long long)manhattan(dC.first, dC.second, nextJ.first, nextJ.second)\n                                     - (long long)manhattan(prevJ.first, prevJ.second, nextJ.first, nextJ.second);\n                long long tot = delta_pick + delta_drop;\n                if (tot < bestDelta) {\n                    bestDelta = tot;\n                    bestI = i; bestJ = j;\n                }\n            }\n        }\n    };\n\n    // Lightweight order exchange stage: try replacing a selected order with an outside candidate\n    vector<char> in_selected(N, 0);\n    for (int i = 0; i < M; ++i) in_selected[selected_orig_ids[i]] = 1;\n    vector<int> cand_pool;\n    int Kcand = min(200, N); // candidate pool size\n    for (int i = 0; i < Kcand; ++i) {\n        int id = score_idx[i].second;\n        if (!in_selected[id]) cand_pool.push_back(id);\n    }\n\n    auto total_cost = route_cost(seq);\n    auto start_time = chrono::high_resolution_clock::now();\n    const double TIME_LIMIT = 1.95;\n    const double REPLACE_LIMIT = 0.35;\n\n    auto elapsed_sec = [&](){\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - start_time).count();\n    };\n\n    // Try a few replacements within time budget\n    if (!cand_pool.empty()) {\n        while (elapsed_sec() < REPLACE_LIMIT) {\n            int rem_oid = rng.randint(0, M-1);\n            if (cand_pool.empty()) break;\n            int idx = rng.randint(0, (int)cand_pool.size()-1);\n            int add_orig = cand_pool[idx];\n            // Compute removal delta for rem_oid\n            int p1 = posPick[rem_oid];\n            int p2 = posDel[rem_oid];\n            if (p1 < 0 || p2 < 0) { recompute_positions(); continue; }\n            auto curr1 = get_coord_by_index(p1);\n            pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n            pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n            long long delta_rem = 0;\n            delta_rem += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n                       - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n                       - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n            auto curr2 = get_coord_by_index(p2);\n            pair<int,int> prev2prime, next2prime;\n            if (p2 == p1 + 1) {\n                prev2prime = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n            } else {\n                prev2prime = get_coord_by_index(p2 - 1);\n            }\n            next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n            delta_rem += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n                       - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n                       - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n\n            // Insertion best delta for add_orig after removing p1,p2\n            pair<int,int> newP = {all[add_orig].ax, all[add_orig].ay};\n            pair<int,int> newD = {all[add_orig].cx, all[add_orig].cy};\n            long long bestIns; int bi, bj;\n            best_insertion_after_removal(p1, p2, newP, newD, bestIns, bi, bj);\n            long long delta_tot = delta_rem + bestIns;\n\n            if (delta_tot < 0) {\n                // Apply replacement: remove rem_oid events and insert new ones at bi,bj, update selected arrays\n                // remove indices p2 then p1\n                seq.erase(seq.begin() + p2);\n                seq.erase(seq.begin() + p1);\n                // update sel coord arrays for rem_oid to new order\n                selected_orig_ids[rem_oid] = add_orig;\n                sel[rem_oid] = all[add_orig];\n                px[rem_oid] = newP.first; py[rem_oid] = newP.second;\n                dx[rem_oid] = newD.first; dy[rem_oid] = newD.second;\n                // insert\n                Event ep{rem_oid, true}, ed{rem_oid, false};\n                seq.insert(seq.begin() + bi, ep);\n                seq.insert(seq.begin() + bj, ed);\n                recompute_positions();\n                total_cost += delta_tot;\n                // Move membership marks\n                in_selected[add_orig] = 1;\n                // Find which was removed (we removed rem_oid mapping to old orig id, which is unknown now)\n                // We need to mark previously selected original id as not selected:\n                // Actually we already overwrote selected_orig_ids[rem_oid], but we need old id:\n                // To handle this, we can set after capturing old id above:\n                // Let's fix by keeping old id before overwrite.\n            } else {\n                // try another candidate\n            }\n\n            // Fix membership bookkeeping:\n            // The above missed old id; Let's correct with a small change:\n            // We'll store old id before overwrite.\n            // But we cannot change past code inside this loop; So adapt: do membership toggling properly in next iterations.\n\n            // To keep correctness, rebuild in_selected and cand_pool every few attempts could be simpler but cost is small.\n            // We'll rebuild now for safety:\n            fill(in_selected.begin(), in_selected.end(), 0);\n            for (int i = 0; i < M; ++i) in_selected[selected_orig_ids[i]] = 1;\n            cand_pool.clear();\n            for (int i = 0; i < Kcand; ++i) {\n                int id = score_idx[i].second;\n                if (!in_selected[id]) cand_pool.push_back(id);\n            }\n            if (cand_pool.empty()) break;\n        }\n    }\n\n    // SA preparation\n    long long cur_cost = route_cost(seq);\n    long long best_cost = cur_cost;\n    vector<Event> best_seq = seq;\n\n    const double T0 = 200.0;\n    const double T1 = 1.0;\n\n    auto delta_pair_best_wrapper = [&](int oid, long long &bestDelta, int &bi, int &bj)->long long {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        // removal delta\n        auto curr1 = get_coord_by_index(p1);\n        pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n        long long delta_rem = 0;\n        delta_rem += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n                   - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n                   - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n        auto curr2 = get_coord_by_index(p2);\n        pair<int,int> prev2prime, next2prime;\n        if (p2 == p1 + 1) {\n            prev2prime = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        } else {\n            prev2prime = get_coord_by_index(p2 - 1);\n        }\n        next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n        delta_rem += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n                   - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n                   - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n\n        long long bestIns; int iBest, jBest;\n        best_insertion_after_removal(p1, p2, coord_pick(oid), coord_drop(oid), bestIns, iBest, jBest);\n        bestDelta = delta_rem + bestIns;\n        bi = iBest; bj = jBest;\n        return bestDelta;\n    };\n\n    auto time_left = [&](){ return TIME_LIMIT - elapsed_sec(); };\n\n    // SA loop\n    while (elapsed_sec() < TIME_LIMIT) {\n        double tfrac = min(1.0, elapsed_sec() / TIME_LIMIT);\n        double temp = T0 + (T1 - T0) * tfrac;\n\n        int moveType = rng.randint(0, 99);\n        bool accepted = false;\n        long long d = 0;\n\n        if (moveType < 60) {\n            // Single-event relocation\n            int p = rng.randint(0, L - 1);\n            int Lp = L - 1;\n            if (Lp <= 0) continue;\n            int q = rng.randint(0, Lp);\n            if (q == p) continue;\n            d = delta_move_single(p, q);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_single(p, q);\n                cur_cost += d;\n                accepted = true;\n            }\n        } else if (moveType < 90) {\n            // Random pair relocation\n            int oid = rng.randint(0, M - 1);\n            int i = rng.randint(0, L - 2);\n            int j = rng.randint(i + 1, L - 1);\n            d = delta_move_pair(oid, i, j);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_pair(oid, i, j);\n                cur_cost += d;\n                accepted = true;\n            }\n        } else {\n            // Best pair relocation for a random order (O(L^2))\n            int oid = rng.randint(0, M - 1);\n            long long bestDelta; int bi, bj;\n            d = delta_pair_best_wrapper(oid, bestDelta, bi, bj);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_pair(oid, bi, bj);\n                cur_cost += d;\n                accepted = true;\n            }\n        }\n\n        if (accepted && cur_cost < best_cost) {\n            best_cost = cur_cost;\n            best_seq = seq;\n        }\n    }\n\n    // Use best sequence\n    seq = best_seq;\n    L = (int)seq.size();\n\n    // Output\n    cout << M;\n    for (int i = 0; i < M; ++i) cout << ' ' << (selected_orig_ids[i] + 1);\n    cout << '\\n';\n\n    int n = 2*M + 2;\n    cout << n << ' ' << OFFICE_X << ' ' << OFFICE_Y;\n    for (int i = 0; i < L; ++i) {\n        auto [x, y] = coord_of_event(seq[i]);\n        cout << ' ' << x << ' ' << y;\n    }\n    cout << ' ' << OFFICE_X << ' ' << OFFICE_Y << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\n#include <boost/dynamic_bitset.hpp>\nusing namespace std;\n\n// Problem-fixed sizes\nstatic constexpr int N = 400;\nstatic constexpr int M = 5 * (N - 1);\n\nstruct Edge {\n    int u, v;\n    int d;             // rounded Euclidean distance\n    int level = 6;     // 1..5 if in k-th spanning tree (by d on E), else 6\n    bool is_nn = false; // among top-K nearest by d from an endpoint\n};\n\n// DSU with cut-edge bitsets per component: inc[C] is XOR of incident-edge bitsets of vertices in C\nstruct DSU {\n    vector<int> parent, sz;\n    vector<boost::dynamic_bitset<unsigned long long>> inc; // cut edges per component\n    DSU(int n, int m_bits) : parent(n), sz(n,1), inc(n, boost::dynamic_bitset<unsigned long long>(m_bits)) {\n        iota(parent.begin(), parent.end(), 0);\n    }\n    int find(int x){\n        while(parent[x]!=x){\n            parent[x]=parent[parent[x]];\n            x=parent[x];\n        }\n        return x;\n    }\n    int unite(int a, int b){\n        a=find(a); b=find(b);\n        if(a==b) return a;\n        if(sz[a] < sz[b]) swap(a,b);\n        inc[a] ^= inc[b]; // exact update for cut edges\n        parent[b] = a;\n        sz[a] += sz[b];\n        return a;\n    }\n};\n\n// Count up to cap set bits strictly after pos\nstatic inline int count_suffix_capped(const boost::dynamic_bitset<unsigned long long>& bs, int pos, int cap) {\n    int c = 0;\n    auto idx = bs.find_next(pos);\n    while (idx != boost::dynamic_bitset<unsigned long long>::npos) {\n        ++c;\n        if (c >= cap) break;\n        idx = bs.find_next(idx);\n    }\n    return c;\n}\n\n// Quick check if there exists a set bit strictly after pos\nstatic inline bool has_future(const boost::dynamic_bitset<unsigned long long>& bs, int pos) {\n    auto idx = bs.find_next(pos);\n    return idx != boost::dynamic_bitset<unsigned long long>::npos;\n}\n\nstatic inline int round_int(double x) {\n    return (int)llround(x);\n}\n\n// Assign levels 1..K by extracting K spanning trees on E (weights = d)\nstatic void assign_mst_levels(vector<Edge>& edges, int K) {\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    stable_sort(idx.begin(), idx.end(), [&](int a, int b){\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n\n    vector<char> available(M, 1);\n    for (int lev = 1; lev <= K; lev++) {\n        vector<int> par(N), rnk(N,0);\n        iota(par.begin(), par.end(), 0);\n        function<int(int)> fnd = [&](int x){ return par[x]==x ? x : par[x]=fnd(par[x]); };\n        auto uni = [&](int a, int b)->bool {\n            a=fnd(a); b=fnd(b);\n            if(a==b) return false;\n            if(rnk[a]<rnk[b]) swap(a,b);\n            par[b]=a;\n            if(rnk[a]==rnk[b]) rnk[a]++;\n            return true;\n        };\n\n        int picked = 0;\n        for (int id : idx) {\n            if (!available[id]) continue;\n            int u = edges[id].u, v = edges[id].v;\n            if (uni(u, v)) {\n                edges[id].level = lev;\n                available[id] = 0;\n                picked++;\n                if (picked == N-1) break;\n            }\n        }\n        // If not enough available edges to complete a tree, remaining edges keep higher levels (6).\n    }\n}\n\n// Temporary DSU for connectivity checks among current components using only future edges\nstruct TempDSU {\n    vector<int> par;\n    int comps;\n    explicit TempDSU(int n=0) { init(n); }\n    void init(int n) {\n        par.resize(n);\n        iota(par.begin(), par.end(), 0);\n        comps = n;\n    }\n    int find(int a){\n        while(par[a]!=a){ par[a]=par[par[a]]; a=par[a]; }\n        return a;\n    }\n    bool unite(int a, int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        par[b]=a;\n        --comps;\n        return true;\n    }\n};\n\n// Check if rejecting current edge keeps the \"future graph\" connected:\n// Nodes = current DSU components; Edges = edges with index > i connecting different components.\nstatic bool future_connected_after_reject(int i, DSU& dsu, const vector<Edge>& edges) {\n    static vector<int> root_idx;\n    root_idx.assign(N, -1);\n    int K = 0;\n    for (int v = 0; v < N; v++) {\n        if (dsu.parent[v] == v) { // v is a root\n            root_idx[v] = K++;\n        }\n    }\n    if (K <= 1) return true;\n\n    TempDSU tmp(K);\n\n    for (int j = i + 1; j < M; j++) {\n        int ru = dsu.find(edges[j].u);\n        int rv = dsu.find(edges[j].v);\n        if (ru == rv) continue;\n        int iu = root_idx[ru];\n        int iv = root_idx[rv];\n        if (iu < 0 || iv < 0) continue; // safety\n        if (tmp.unite(iu, iv) && tmp.comps == 1) {\n            return true; // connected\n        }\n    }\n    return tmp.comps == 1;\n}\n\n// Deterministic PRNG (xorshift)\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed=88172645463393265ULL): x(seed) {}\n    uint64_t next() {\n        uint64_t y = x;\n        y ^= y << 7;\n        y ^= y >> 9;\n        return x = y;\n    }\n    // uniform in [0,1)\n    double next_double() {\n        return (next() >> 11) * (1.0 / (1ULL << 53));\n    }\n    // uniform in [a,b)\n    double uniform(double a, double b) {\n        return a + (b - a) * next_double();\n    }\n};\n\n// Build multiple perturbed MSTs on E to compute frequency of edges in MSTs\nstatic vector<int> mst_frequency(const vector<Edge>& edges, int rounds, double sigma) {\n    vector<int> freq(M, 0);\n    vector<int> idx(M);\n    vector<double> w(M);\n    XorShift64 rng(20250821ULL); // deterministic\n\n    for (int r = 0; r < rounds; r++) {\n        for (int i = 0; i < M; i++) {\n            double noise = rng.uniform(-sigma, sigma);\n            w[i] = edges[i].d * (1.0 + noise);\n            idx[i] = i;\n        }\n        sort(idx.begin(), idx.end(), [&](int a, int b){\n            if (w[a] != w[b]) return w[a] < w[b];\n            return a < b;\n        });\n        // DSU\n        vector<int> par(N), rnk(N,0);\n        iota(par.begin(), par.end(), 0);\n        function<int(int)> fnd = [&](int x){ return par[x]==x ? x : par[x]=fnd(par[x]); };\n        auto uni = [&](int a, int b)->bool {\n            a=fnd(a); b=fnd(b);\n            if(a==b) return false;\n            if(rnk[a]<rnk[b]) swap(a,b);\n            par[b]=a;\n            if(rnk[a]==rnk[b]) rnk[a]++;\n            return true;\n        };\n        int picked = 0;\n        for (int id : idx) {\n            if (uni(edges[id].u, edges[id].v)) {\n                freq[id]++;\n                picked++;\n                if (picked == N-1) break;\n            }\n        }\n    }\n    return freq;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Read coordinates\n    vector<int> x(N), y(N);\n    for (int i = 0; i < N; i++) {\n        if (!(cin >> x[i] >> y[i])) {\n            return 0;\n        }\n    }\n\n    // Read edges and compute rounded geometric distances\n    vector<Edge> edges(M);\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        edges[i].u = u;\n        edges[i].v = v;\n        long long dx = x[u] - x[v];\n        long long dy = y[u] - y[v];\n        double dist = sqrt((double)dx * dx + (double)dy * dy);\n        int d = round_int(dist);\n        if (d <= 0) d = 1;\n        edges[i].d = d;\n    }\n\n    // Offline guidance: nearest neighbor edges per vertex by d\n    const int KNN = 4;\n    vector<vector<pair<int,int>>> adj(N); // (d, edge_index)\n    for (int i = 0; i < M; i++) {\n        adj[edges[i].u].push_back({edges[i].d, i});\n        adj[edges[i].v].push_back({edges[i].d, i});\n    }\n    for (int v = 0; v < N; v++) {\n        auto &lst = adj[v];\n        sort(lst.begin(), lst.end(), [](const auto& a, const auto& b){ return a.first < b.first; });\n        int limit = min<int>(KNN, lst.size());\n        for (int j = 0; j < limit; j++) {\n            edges[lst[j].second].is_nn = true;\n        }\n    }\n\n    // Assign MST levels 1..5 using weights d\n    assign_mst_levels(edges, 5);\n\n    // MST frequency over perturbed weights (robustness)\n    const int FREQ_ROUNDS = 16;\n    const double FREQ_SIGMA = 0.03;\n    vector<int> freq = mst_frequency(edges, FREQ_ROUNDS, FREQ_SIGMA);\n\n    // Distance quantiles for small/large d adjustments\n    vector<int> all_d; all_d.reserve(M);\n    for (auto &e : edges) all_d.push_back(e.d);\n    vector<int> tmp = all_d;\n    nth_element(tmp.begin(), tmp.begin() + M/4, tmp.end());\n    int q25 = tmp[M/4];\n    tmp = all_d;\n    nth_element(tmp.begin(), tmp.begin() + (3*M)/4, tmp.end());\n    int q75 = tmp[(3*M)/4];\n\n    // DSU with cut-bitsets\n    DSU dsu(N, M);\n    for (int i = 0; i < M; i++) {\n        dsu.inc[edges[i].u].set(i);\n        dsu.inc[edges[i].v].set(i);\n    }\n\n    // Heuristic parameters (tuned moderately)\n    static const double levelAdd[7] = {0.0, 0.26, 0.18, 0.12, 0.07, 0.03, 0.0}; // index 1..5 used\n    const double nnAdd        = 0.05;\n    const double smallDAdd    = 0.04;\n    const double largeDPen    = 0.05;\n    const double tRelaxCoeff  = 0.07;  // slight time-based relaxation\n    const int    kCapCount    = 256;\n    const double freqScale    = 0.010; // per-round contribution (max ~0.16)\n\n    auto k_small_bonus = [](int kmin)->double{\n        if (kmin <= 1) return 0.18;\n        if (kmin == 2) return 0.15;\n        if (kmin == 3) return 0.08;\n        if (kmin == 4) return 0.04;\n        return 0.0;\n    };\n\n    // Temp bitset for pairwise computation to reduce reallocations\n    boost::dynamic_bitset<unsigned long long> pairBS(M);\n\n    // Interactive processing\n    for (int i = 0; i < M; i++) {\n        int l;\n        if (!(cin >> l)) return 0;\n\n        const Edge &e = edges[i];\n        int ru = dsu.find(e.u);\n        int rv = dsu.find(e.v);\n\n        int decision = 0;\n\n        if (ru == rv) {\n            // Reject cycle edges\n            decision = 0;\n        } else {\n            // Strong connectivity guarantee:\n            // If rejecting this edge would make the remaining graph (contracted by accepted edges) disconnected, accept it.\n            bool must_accept = false;\n\n            // Fast necessary check: if either endpoint's component has no future cross edges after i\n            if (!has_future(dsu.inc[ru], i) || !has_future(dsu.inc[rv], i)) {\n                must_accept = true;\n            } else {\n                // Full check: is the future component graph connected without this edge?\n                if (!future_connected_after_reject(i, dsu, edges)) must_accept = true;\n            }\n\n            if (must_accept) {\n                decision = 1;\n                dsu.unite(ru, rv);\n            } else {\n                // Scarcity-aware heuristic\n                int k1 = count_suffix_capped(dsu.inc[ru], i, kCapCount);\n                int k2 = count_suffix_capped(dsu.inc[rv], i, kCapCount);\n                int kmin = min(k1, k2);\n\n                // Pair-specific future edges between ru and rv\n                pairBS = dsu.inc[ru];\n                pairBS &= dsu.inc[rv];\n                int kpair = 0;\n                int dminpair = INT_MAX;\n                auto idxb = pairBS.find_next(i);\n                while (idxb != boost::dynamic_bitset<unsigned long long>::npos) {\n                    ++kpair;\n                    int eid = (int)idxb;\n                    dminpair = min(dminpair, edges[eid].d);\n                    idxb = pairBS.find_next(idxb);\n                }\n\n                double r = (double)l / (double)e.d;\n                double thr = 1.0 + 2.0 / (double)(kmin + 1);\n\n                // Pair-quality factor: adjust by relative best future d between ru and rv\n                double pairFactor = 1.0;\n                if (kpair > 0) {\n                    pairFactor = (double)dminpair / (double)e.d;\n                    // clamp to avoid overly aggressive cut\n                    if (pairFactor < 0.75) pairFactor = 0.75;\n                    if (pairFactor > 1.20) pairFactor = 1.20;\n                }\n                thr *= pairFactor;\n\n                // Offline/geometry adjustments\n                if (e.level >= 1 && e.level <= 5) thr += levelAdd[e.level];\n                if (e.is_nn) thr += nnAdd;\n                if (e.d <= q25) thr += smallDAdd;\n                else if (e.d >= q75) thr -= largeDPen;\n\n                // MST frequency bonus\n                thr += freq[e.u == edges[i].u && e.v == edges[i].v ? i : i] * freqScale; // i (edge index) maps directly\n\n                // Small extra help for small k\n                thr += k_small_bonus(kmin);\n\n                // Mild relaxation as stream progresses\n                double t = (double)i / (double)M;\n                thr += tRelaxCoeff * t;\n\n                // Cap thr in [1,3] (since r \u2208 [1,3])\n                if (thr < 1.0) thr = 1.0;\n                if (thr > 3.0) thr = 3.0;\n\n                if (r <= thr) {\n                    decision = 1;\n                    dsu.unite(ru, rv);\n                } else {\n                    decision = 0;\n                }\n            }\n        }\n\n        cout << decision << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pet { int x, y, t; };\n\nstruct TwoCellPlan {\n    bool active = false;     // trying to build a 2-cell chamber\n    bool sealed = false;     // all boundary blocked/out-of-bounds\n    int ax = -1, ay = -1;    // cell A\n    int bx = -1, by = -1;    // cell B\n    int pos = 0;             // 0 if currently at A, 1 if at B\n    vector<pair<int,int>> boundary; // target boundary cells\n    vector<int> side;        // which interior cell they are adjacent to (0:A, 1:B)\n    vector<char> done;       // boundary squares already blocked/OOB\n    int idle_turns = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int H = 30, W = 30;\n    auto inb = [&](int x, int y)->bool { return 0 <= x && x < H && 0 <= y && y < W; };\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<Pet> pets(N);\n    for (int i = 0; i < N; i++) {\n        int px, py, pt; cin >> px >> py >> pt;\n        pets[i] = {px-1, py-1, pt};\n    }\n    int M; cin >> M;\n    vector<int> hx(M), hy(M);\n    for (int i = 0; i < M; i++) {\n        int x, y; cin >> x >> y;\n        hx[i] = x-1; hy[i] = y-1;\n    }\n\n    vector<vector<char>> blocked(H, vector<char>(W, 0));\n    vector<vector<int>> pet_here(H, vector<int>(W, 0));\n    vector<vector<int>> human_here(H, vector<int>(W, 0));\n\n    auto rebuild_human_here = [&]() {\n        for (int i = 0; i < H; i++) fill(human_here[i].begin(), human_here[i].end(), 0);\n        for (int i = 0; i < M; i++) human_here[hx[i]][hy[i]]++;\n    };\n    auto rebuild_pet_here = [&]() {\n        for (int i = 0; i < H; i++) fill(pet_here[i].begin(), pet_here[i].end(), 0);\n        for (int i = 0; i < N; i++) pet_here[pets[i].x][pets[i].y]++;\n    };\n\n    rebuild_human_here();\n    rebuild_pet_here();\n\n    const int dx4[4] = {-1, 0, 1, 0};\n    const int dy4[4] = {0, 1, 0, -1};\n    const char blockChar[4] = {'u','r','d','l'};\n    const char moveChar[4]  = {'U','R','D','L'};\n\n    // Preferred direction order for fallback 1-cell closure\n    vector<array<int,4>> prefDir(M);\n    for (int i = 0; i < M; i++) {\n        int topDist = hx[i];\n        int bottomDist = (H-1) - hx[i];\n        int leftDist = hy[i];\n        int rightDist = (W-1) - hy[i];\n        int firstV = (topDist <= bottomDist ? 0 : 2);   // up or down\n        int firstH = (leftDist <= rightDist ? 3 : 1);   // left or right\n        int otherV = firstV ^ 2;\n        int otherH = firstH ^ 2;\n        prefDir[i] = { firstV, firstH, otherV, otherH };\n    }\n\n    vector<char> fully_closed(M, 0); // closed with either 1-cell or 2-cell chamber\n    vector<TwoCellPlan> plan(M);\n\n    auto count_open_neighbors = [&](int x, int y)->int {\n        int c = 0;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (!blocked[nx][ny]) c++;\n        }\n        return c;\n    };\n\n    auto can_block = [&](int tx, int ty)->bool {\n        if (!inb(tx, ty)) return false;\n        if (blocked[tx][ty]) return false;\n        if (human_here[tx][ty] > 0) return false;\n        if (pet_here[tx][ty] > 0) return false;\n        for (int k = 0; k < 4; k++) {\n            int ax = tx + dx4[k], ay = ty + dy4[k];\n            if (!inb(ax, ay)) continue;\n            if (pet_here[ax][ay] > 0) return false;\n        }\n        return true;\n    };\n\n    auto build_two_cell_plan = [&](int i) {\n        int ax = hx[i], ay = hy[i];\n        int best_dir = -1;\n        int best_score = -1;\n\n        vector<pair<int,int>> tmp_boundary;\n        vector<int> tmp_side;\n        auto eval_dir = [&](int dir)->pair<int,int> {\n            tmp_boundary.clear();\n            tmp_side.clear();\n            int bx = ax + dx4[dir], by = ay + dy4[dir];\n            if (!inb(bx, by)) return make_pair(-1, -1);\n            if (blocked[bx][by]) return make_pair(-1, -1);\n            auto add_unique = [&](int tx, int ty, int s) {\n                for (size_t k = 0; k < tmp_boundary.size(); k++) {\n                    if (tmp_boundary[k].first == tx && tmp_boundary[k].second == ty) return;\n                }\n                tmp_boundary.emplace_back(tx, ty);\n                tmp_side.push_back(s);\n            };\n            for (int d = 0; d < 4; d++) {\n                int nx = ax + dx4[d], ny = ay + dy4[d];\n                if (nx == bx && ny == by) continue;\n                add_unique(nx, ny, 0);\n            }\n            for (int d = 0; d < 4; d++) {\n                int nx = bx + dx4[d], ny = by + dy4[d];\n                if (nx == ax && ny == ay) continue;\n                add_unique(nx, ny, 1);\n            }\n            int score = 0;\n            for (auto &p : tmp_boundary) {\n                int tx = p.first, ty = p.second;\n                if (!inb(tx, ty)) score++;\n                else if (blocked[tx][ty]) score++;\n            }\n            return make_pair(score, dir);\n        };\n\n        for (int d = 0; d < 4; d++) {\n            auto pr = eval_dir(d);\n            int score = pr.first;\n            if (score < 0) continue;\n            if (score > best_score) {\n                best_score = score;\n                best_dir = pr.second;\n            }\n        }\n\n        if (best_dir == -1) {\n            plan[i].active = false;\n            plan[i].sealed = false;\n            plan[i].boundary.clear();\n            plan[i].side.clear();\n            plan[i].done.clear();\n            plan[i].idle_turns = 0;\n            return;\n        }\n\n        int bx = ax + dx4[best_dir], by = ay + dy4[best_dir];\n        vector<pair<int,int>> boundary;\n        vector<int> side;\n        auto add_unique = [&](int tx, int ty, int s) {\n            for (size_t k = 0; k < boundary.size(); k++) {\n                if (boundary[k].first == tx && boundary[k].second == ty) return;\n            }\n            boundary.emplace_back(tx, ty);\n            side.push_back(s);\n        };\n        for (int d = 0; d < 4; d++) {\n            int nx = ax + dx4[d], ny = ay + dy4[d];\n            if (nx == bx && ny == by) continue;\n            add_unique(nx, ny, 0);\n        }\n        for (int d = 0; d < 4; d++) {\n            int nx = bx + dx4[d], ny = by + dy4[d];\n            if (nx == ax && ny == ay) continue;\n            add_unique(nx, ny, 1);\n        }\n\n        plan[i].active = true;\n        plan[i].sealed = false;\n        plan[i].ax = ax; plan[i].ay = ay;\n        plan[i].bx = bx; plan[i].by = by;\n        plan[i].pos = 0;\n        plan[i].boundary = boundary;\n        plan[i].side = side;\n        plan[i].done.assign(boundary.size(), 0);\n        plan[i].idle_turns = 0;\n        for (size_t k = 0; k < boundary.size(); k++) {\n            int tx = boundary[k].first, ty = boundary[k].second;\n            if (!inb(tx, ty) || blocked[tx][ty]) plan[i].done[k] = 1;\n        }\n    };\n\n    auto fallback_one_cell_action = [&](int i)->char {\n        if (fully_closed[i]) return '.';\n        int x = hx[i], y = hy[i];\n        int openN = 0;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (!blocked[nx][ny]) openN++;\n        }\n        if (openN == 0) {\n            fully_closed[i] = 1;\n            return '.';\n        }\n        bool petOnMyCell = (pet_here[x][y] > 0);\n        if (openN == 1 && petOnMyCell) {\n            return '.';\n        }\n        for (int order = 0; order < 4; order++) {\n            int d = prefDir[i][order];\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (blocked[nx][ny]) continue;\n            if (can_block(nx, ny)) {\n                return blockChar[d];\n            }\n        }\n        return '.';\n    };\n\n    for (int turn = 0; turn < 300; turn++) {\n        // Sync plan pos with current human positions\n        for (int i = 0; i < M; i++) {\n            if (plan[i].active) {\n                if (hx[i] == plan[i].ax && hy[i] == plan[i].ay) plan[i].pos = 0;\n                else if (hx[i] == plan[i].bx && hy[i] == plan[i].by) plan[i].pos = 1;\n                else plan[i].active = false;\n            }\n            if (!plan[i].active && !fully_closed[i]) {\n                build_two_cell_plan(i);\n            }\n        }\n\n        // First decide tentative actions\n        string actions(M, '.');\n\n        for (int i = 0; i < M; i++) {\n            if (fully_closed[i]) {\n                actions[i] = '.';\n                continue;\n            }\n\n            if (!plan[i].active) {\n                actions[i] = fallback_one_cell_action(i);\n                continue;\n            }\n\n            // Update boundary done flags\n            for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                if (!inb(tx, ty) || blocked[tx][ty]) plan[i].done[k] = 1;\n            }\n            int remain = 0;\n            for (char d : plan[i].done) if (!d) remain++;\n\n            // If B is blocked already, abort plan\n            if (blocked[plan[i].bx][plan[i].by]) {\n                plan[i].active = false;\n                actions[i] = fallback_one_cell_action(i);\n                continue;\n            }\n\n            if (remain == 0) {\n                plan[i].sealed = true;\n                fully_closed[i] = 1;\n                actions[i] = '.';\n                continue;\n            }\n\n            bool petInside = (pet_here[plan[i].ax][plan[i].ay] > 0) || (pet_here[plan[i].bx][plan[i].by] > 0);\n            int cx = (plan[i].pos == 0 ? plan[i].ax : plan[i].bx);\n            int cy = (plan[i].pos == 0 ? plan[i].ay : plan[i].by);\n\n            int chosen_k = -1;\n            int chosen_dir = -1;\n            for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                if (plan[i].done[k]) continue;\n                if (plan[i].side[k] != plan[i].pos) continue;\n                int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                if (!inb(tx, ty)) continue;\n                if (remain == 1 && petInside) continue;\n                if (!can_block(tx, ty)) continue;\n                int dd = -1;\n                for (int d = 0; d < 4; d++) {\n                    if (cx + dx4[d] == tx && cy + dy4[d] == ty) { dd = d; break; }\n                }\n                if (dd == -1) continue;\n                chosen_k = (int)k;\n                chosen_dir = dd;\n                break;\n            }\n\n            if (chosen_k != -1) {\n                actions[i] = blockChar[chosen_dir];\n            } else {\n                // Consider moving to other interior cell to block from there\n                int nx = (plan[i].pos == 0 ? plan[i].bx : plan[i].ax);\n                int ny = (plan[i].pos == 0 ? plan[i].by : plan[i].ay);\n                bool canMove = inb(nx, ny) && !blocked[nx][ny];\n\n                bool otherHasCandidate = false;\n                for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                    if (plan[i].done[k]) continue;\n                    if (plan[i].side[k] != 1 - plan[i].pos) continue;\n                    int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                    if (!inb(tx, ty)) continue;\n                    if (remain == 1 && petInside) continue;\n                    if (can_block(tx, ty)) { otherHasCandidate = true; break; }\n                }\n                if (canMove && otherHasCandidate) {\n                    int dd = -1;\n                    for (int d = 0; d < 4; d++) {\n                        if (hx[i] + dx4[d] == nx && hy[i] + dy4[d] == ny) { dd = d; break; }\n                    }\n                    if (dd != -1) actions[i] = moveChar[dd];\n                    else actions[i] = '.';\n                } else {\n                    actions[i] = '.';\n                }\n            }\n        }\n\n        // Phase-2: prevent moving into a cell that becomes blocked by anyone this turn\n        vector<vector<char>> blocked_this_turn(H, vector<char>(W, 0));\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'u' || c == 'r' || c == 'd' || c == 'l') {\n                int d = (c=='u'?0:(c=='r'?1:(c=='d'?2:3)));\n                int tx = hx[i] + dx4[d], ty = hy[i] + dy4[d];\n                if (inb(tx, ty)) blocked_this_turn[tx][ty] = 1;\n            }\n        }\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'U' || c == 'R' || c == 'D' || c == 'L') {\n                int d = (c=='U'?0:(c=='R'?1:(c=='D'?2:3)));\n                int nx = hx[i] + dx4[d], ny = hy[i] + dy4[d];\n                if (inb(nx, ny) && blocked_this_turn[nx][ny]) {\n                    // cancel the move to avoid illegal action\n                    actions[i] = '.';\n                }\n            }\n        }\n\n        // Adjust idle_turns based on final actions\n        for (int i = 0; i < M; i++) {\n            if (!plan[i].active || fully_closed[i]) continue;\n            if (actions[i] == '.') plan[i].idle_turns++;\n            else plan[i].idle_turns = 0;\n            if (plan[i].idle_turns >= 40) {\n                plan[i].active = false;\n            }\n        }\n\n        // Output final actions and flush\n        cout << actions << '\\n' << flush;\n\n        // Apply blocks and moves locally\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'u' || c == 'r' || c == 'd' || c == 'l') {\n                int d = (c=='u'?0:(c=='r'?1:(c=='d'?2:3)));\n                int tx = hx[i] + dx4[d], ty = hy[i] + dy4[d];\n                if (inb(tx, ty)) blocked[tx][ty] = 1;\n            } else if (c == 'U' || c == 'R' || c == 'D' || c == 'L') {\n                int d = (c=='U'?0:(c=='R'?1:(c=='D'?2:3)));\n                int nx = hx[i] + dx4[d], ny = hy[i] + dy4[d];\n                if (inb(nx, ny) && !blocked[nx][ny]) {\n                    hx[i] = nx; hy[i] = ny;\n                }\n            }\n        }\n\n        // Read pet moves\n        for (int i = 0; i < N; i++) {\n            string s; cin >> s;\n            if (s == \".\") continue;\n            for (char mv : s) {\n                if (mv == 'U') pets[i].x -= 1;\n                else if (mv == 'D') pets[i].x += 1;\n                else if (mv == 'L') pets[i].y -= 1;\n                else if (mv == 'R') pets[i].y += 1;\n            }\n        }\n\n        // Rebuild occupancy for next turn\n        rebuild_pet_here();\n        rebuild_human_here();\n\n        // Update closure status\n        for (int i = 0; i < M; i++) {\n            if (fully_closed[i]) continue;\n            if (plan[i].active) {\n                int remain = 0;\n                for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                    int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                    if (!inb(tx, ty) || blocked[tx][ty]) plan[i].done[k] = 1;\n                    if (!plan[i].done[k]) remain++;\n                }\n                if (remain == 0) {\n                    plan[i].sealed = true;\n                    fully_closed[i] = 1;\n                }\n            } else {\n                if (count_open_neighbors(hx[i], hy[i]) == 0) {\n                    fully_closed[i] = 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static auto st = steady_clock::now();\n    auto cur = steady_clock::now();\n    return duration<double>(cur - st).count();\n}\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int randint(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    int si, sj, ti, tj;\n    double p;\n    if (!(cin >> si >> sj >> ti >> tj >> p)) return 0;\n    vector<string> h(20);\n    for (int i = 0; i < 20; i++) cin >> h[i];\n    vector<string> v(19);\n    for (int i = 0; i < 19; i++) cin >> v[i];\n\n    const int H = 20, W = 20, N = H * W;\n    auto id = [&](int r, int c) { return r * W + c; };\n    int s_id = id(si, sj);\n    int t_id = id(ti, tj);\n\n    if (s_id == t_id) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    // Directions: 0=U,1=D,2=L,3=R\n    const char DIRC[4] = {'U','D','L','R'};\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n\n    const double q = 1.0 - p;\n\n    // Precompute dest for each state and direction\n    static int dest[400][4];\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = id(i, j);\n            // U\n            if (i > 0 && v[i-1][j] == '0') dest[u][0] = id(i-1, j);\n            else dest[u][0] = -1;\n            // D\n            if (i < H-1 && v[i][j] == '0') dest[u][1] = id(i+1, j);\n            else dest[u][1] = -1;\n            // L\n            if (j > 0 && h[i][j-1] == '0') dest[u][2] = id(i, j-1);\n            else dest[u][2] = -1;\n            // R\n            if (j < W-1 && h[i][j] == '0') dest[u][3] = id(i, j+1);\n            else dest[u][3] = -1;\n        }\n    }\n\n    // Precompute right-transition weights:\n    // out[u] += self_w_right[dir][u] * in[u];\n    // and if other exists: out[other_idx_right[dir][u]] += other_w_right[dir][u] * in[u]\n    static double self_w_right[4][400], other_w_right[4][400];\n    static int other_idx_right[4][400];\n    for (int d = 0; d < 4; d++) {\n        for (int u = 0; u < N; u++) {\n            if (u == t_id) {\n                self_w_right[d][u] = 1.0;\n                other_w_right[d][u] = 0.0;\n                other_idx_right[d][u] = u;\n            } else {\n                int y = dest[u][d];\n                if (y >= 0) {\n                    self_w_right[d][u] = p;     // forget => stay\n                    other_w_right[d][u] = q;    // remember and move\n                    other_idx_right[d][u] = y;\n                } else {\n                    self_w_right[d][u] = 1.0;  // blocked => stay\n                    other_w_right[d][u] = 0.0;\n                    other_idx_right[d][u] = u;\n                }\n            }\n        }\n    }\n\n    // BFS path (with order parameter)\n    auto bfs_path = [&](array<int,4> order) -> vector<int> {\n        vector<int> par(N, -1), pdir(N, -1);\n        deque<int> dq;\n        dq.push_back(s_id);\n        par[s_id] = s_id;\n        while (!dq.empty() && par[t_id] == -1) {\n            int u = dq.front(); dq.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int d = order[k];\n                int vtx = dest[u][d];\n                if (vtx == -1) continue;\n                if (par[vtx] != -1) continue;\n                par[vtx] = u;\n                pdir[vtx] = d;\n                dq.push_back(vtx);\n            }\n        }\n        vector<int> dirs;\n        if (par[t_id] != -1) {\n            int cur = t_id;\n            while (cur != s_id) {\n                dirs.push_back(pdir[cur]);\n                cur = par[cur];\n            }\n            reverse(dirs.begin(), dirs.end());\n        }\n        return dirs;\n    };\n\n    // Build a sequence by repeating a path to length L\n    auto build_seq_from_path = [&](const vector<int>& path, int L) -> vector<int> {\n        vector<int> seq;\n        seq.reserve(L);\n        if (path.empty()) {\n            // Fallback greedy toward target\n            int cr = si, cc = sj;\n            vector<int> tmp;\n            for (int steps = 0; steps < 400 && !(cr == ti && cc == tj); steps++) {\n                int bestd = 0, bestdist = INT_MAX;\n                for (int d = 0; d < 4; d++) {\n                    int nr = cr + dr[d], nc = cc + dc[d];\n                    if (nr < 0 || nr >= H || nc < 0 || nc >= W) continue;\n                    if (dest[id(cr,cc)][d] == -1) continue;\n                    int md = abs(nr - ti) + abs(nc - tj);\n                    if (md < bestdist) { bestdist = md; bestd = d; }\n                }\n                tmp.push_back(bestd);\n                cr += dr[bestd]; cc += dc[bestd];\n            }\n            while ((int)seq.size() < L) {\n                for (int d: tmp) {\n                    seq.push_back(d);\n                    if ((int)seq.size() >= L) break;\n                }\n            }\n        } else {\n            while ((int)seq.size() < L) {\n                for (int d: path) {\n                    seq.push_back(d);\n                    if ((int)seq.size() >= L) break;\n                }\n            }\n        }\n        return seq;\n    };\n\n    const int L = 200;\n\n    // Buffers\n    vector<array<double, 400>> g(L);\n    array<double, 400> gtmp;\n    array<double, 400> vcur, vtmp, vbest;\n\n    auto apply_right = [&](int dir, const double* vin, double* vout) {\n        for (int i = 0; i < N; i++) vout[i] = 0.0;\n        const double* selfw = self_w_right[dir];\n        const double* otherw = other_w_right[dir];\n        const int* otheri = other_idx_right[dir];\n        for (int u = 0; u < N; u++) {\n            double val = vin[u];\n            if (val == 0.0) continue;\n            vout[u] += selfw[u] * val;\n            double ow = otherw[u];\n            if (ow != 0.0) {\n                int oi = otheri[u];\n                vout[oi] += ow * val;\n            }\n        }\n    };\n\n    auto apply_right_and_dot = [&](int dir, const double* vin, double* vout, const double* gvec) -> double {\n        double sum = 0.0;\n        for (int i = 0; i < N; i++) vout[i] = 0.0;\n        const double* selfw = self_w_right[dir];\n        const double* otherw = other_w_right[dir];\n        const int* otheri = other_idx_right[dir];\n        for (int u = 0; u < N; u++) {\n            double val = vin[u];\n            if (val == 0.0) continue;\n            double self_add = selfw[u] * val;\n            vout[u] += self_add;\n            sum += gvec[u] * self_add;\n            double ow = otherw[u];\n            if (ow != 0.0) {\n                int oi = otheri[u];\n                double add = ow * val;\n                vout[oi] += add;\n                sum += gvec[oi] * add;\n            }\n        }\n        return sum;\n    };\n\n    auto apply_left = [&](int dir, const double* gcur, double* gprev) {\n        // gprev[u] = sum_y P(u->y) * gcur[y]\n        const double* selfw = self_w_right[dir];\n        const double* otherw = other_w_right[dir];\n        const int* otheri = other_idx_right[dir];\n        for (int u = 0; u < N; u++) {\n            double s = selfw[u] * gcur[u];\n            double ow = otherw[u];\n            if (ow != 0.0) {\n                int oi = otheri[u];\n                s += ow * gcur[oi];\n            }\n            gprev[u] = s;\n        }\n    };\n\n    auto compute_backward_g = [&](const vector<int>& seq) {\n        for (int i = 0; i < N; i++) g[L-1][i] = 0.0;\n        g[L-1][t_id] = double(401 - L);\n        for (int t = L - 2; t >= 0; t--) {\n            // g[t] = e_target + (P^{a_{t+1}})^T g[t+1]\n            for (int i = 0; i < N; i++) g[t][i] = 0.0;\n            g[t][t_id] = 1.0;\n            int dir_next = seq[t+1];\n            apply_left(dir_next, g[t+1].data(), gtmp.data());\n            for (int i = 0; i < N; i++) g[t][i] += gtmp[i];\n        }\n    };\n\n    auto evaluate_seq = [&](const vector<int>& seq)->double {\n        for (int i = 0; i < N; i++) vcur[i] = 0.0;\n        vcur[s_id] = 1.0;\n        double score = 0.0;\n        for (int t = 0; t < L; t++) {\n            apply_right(seq[t], vcur.data(), vtmp.data());\n            for (int i = 0; i < N; i++) vcur[i] = vtmp[i];\n            double Ft = vcur[t_id];\n            if (t < L - 1) score += Ft;\n            else score += double(401 - L) * Ft;\n        }\n        return score;\n    };\n\n    auto forward_single_pass = [&](vector<int>& seq, double& score_out, bool& changed_out) {\n        compute_backward_g(seq); // ensure g up-to-date\n        for (int i = 0; i < N; i++) vcur[i] = 0.0;\n        vcur[s_id] = 1.0;\n        double score = 0.0;\n        bool changed = false;\n        for (int t = 0; t < L; t++) {\n            int old_dir = seq[t];\n            double best_val = -1e300;\n            int best_dir = old_dir;\n            for (int d = 0; d < 4; d++) {\n                double val = apply_right_and_dot(d, vcur.data(), vtmp.data(), g[t].data());\n                if (val > best_val + 1e-12 || (fabs(val - best_val) <= 1e-12 && d == old_dir)) {\n                    best_val = val;\n                    best_dir = d;\n                    for (int i = 0; i < N; i++) vbest[i] = vtmp[i];\n                }\n            }\n            if (best_dir != old_dir) {\n                changed = true;\n                seq[t] = best_dir;\n            }\n            // advance vcur\n            for (int i = 0; i < N; i++) vcur[i] = vbest[i];\n            // accumulate score\n            double Ft = vcur[t_id];\n            if (t < L - 1) score += Ft;\n            else score += double(401 - L) * Ft;\n        }\n        score_out = score;\n        changed_out = changed;\n    };\n\n    // Two-step block forward pass\n    auto forward_pair_pass = [&](vector<int>& seq, double& score_out, bool& changed_out) {\n        compute_backward_g(seq); // compute g for current future actions\n        for (int i = 0; i < N; i++) vcur[i] = 0.0;\n        vcur[s_id] = 1.0;\n        bool changed = false;\n        double score = 0.0;\n\n        // Buffers for 4 candidates each\n        array<array<double,400>,4> X;      // x_a = P^a vcur\n        array<array<double,400>,4> GB;     // gb_b = e_target + (P^b)^T g[t+1]\n\n        for (int t = 0; t < L; ) {\n            if (t == L - 1) {\n                // Last step single update\n                int old_dir = seq[t];\n                int best_dir = old_dir;\n                double best_val = -1e300;\n                for (int d = 0; d < 4; d++) {\n                    double val = apply_right_and_dot(d, vcur.data(), vtmp.data(), g[t].data());\n                    if (val > best_val + 1e-12 || (fabs(val - best_val) <= 1e-12 && d == old_dir)) {\n                        best_val = val;\n                        best_dir = d;\n                        for (int i = 0; i < N; i++) vbest[i] = vtmp[i];\n                    }\n                }\n                if (best_dir != old_dir) { changed = true; seq[t] = best_dir; }\n                for (int i = 0; i < N; i++) vcur[i] = vbest[i];\n                double Ft = vcur[t_id];\n                score += double(401 - L) * Ft;\n                t++;\n                continue;\n            }\n\n            // Precompute X for 4 actions from current vcur\n            for (int a = 0; a < 4; a++) {\n                apply_right(a, vcur.data(), X[a].data());\n            }\n            // Precompute GB for 4 actions based on g[t+1]\n            for (int b = 0; b < 4; b++) {\n                apply_left(b, g[t+1].data(), GB[b].data());\n                GB[b][t_id] += 1.0; // add e_target\n            }\n\n            int old_a = seq[t];\n            int old_b = seq[t+1];\n            int best_a = old_a, best_b = old_b;\n            double best_val = -1e300;\n\n            // Evaluate all 16 pairs: val = dot(GB[b], X[a])\n            for (int a = 0; a < 4; a++) {\n                // Compute dot with 4 GBs\n                for (int b = 0; b < 4; b++) {\n                    double val = 0.0;\n                    const double* xa = X[a].data();\n                    const double* gb = GB[b].data();\n                    for (int i = 0; i < N; i++) val += xa[i] * gb[i];\n                    bool tie_keep = (a == old_a && b == old_b);\n                    if (val > best_val + 1e-12 || (fabs(val - best_val) <= 1e-12 && tie_keep)) {\n                        best_val = val;\n                        best_a = a;\n                        best_b = b;\n                    }\n                }\n            }\n\n            if (best_a != old_a || best_b != old_b) changed = true;\n            seq[t] = best_a;\n            seq[t+1] = best_b;\n\n            // Update vcur to after two steps; also accumulate score for t and t+1\n            // After first step: v1 = X[best_a]\n            // After second step: v2 = P^{best_b} v1\n            const double* v1 = X[best_a].data();\n            apply_right(best_b, v1, vtmp.data());\n            // accumulate score\n            double F1 = v1[t_id];\n            double F2 = vtmp[t_id];\n            score += F1;\n            if (t + 1 < L - 1) score += F2;\n            else score += double(401 - L) * F2;\n            // advance\n            for (int i = 0; i < N; i++) vcur[i] = vtmp[i];\n            t += 2;\n        }\n\n        score_out = score;\n        changed_out = changed;\n    };\n\n    // Prepare multiple randomized BFS initial paths\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift rng(seed);\n\n    vector<array<int,4>> orders;\n    array<int,4> base = {0,1,2,3};\n    // Include some fixed orders and random permutations\n    orders.push_back({0,1,2,3});\n    orders.push_back({1,0,3,2});\n    orders.push_back({2,3,0,1});\n    orders.push_back({3,2,1,0});\n    for (int k = 0; k < 12; k++) {\n        array<int,4> ord = base;\n        for (int i = 3; i > 0; --i) {\n            int j = rng.randint(0, i);\n            swap(ord[i], ord[j]);\n        }\n        orders.push_back(ord);\n    }\n\n    const double TL = 1.95;\n    double t0 = now_sec();\n\n    double global_best_score = -1e300;\n    vector<int> global_best_seq;\n\n    int restart_idx = 0;\n    while (now_sec() - t0 < TL && restart_idx < (int)orders.size()) {\n        array<int,4> ord = orders[restart_idx++];\n        vector<int> path = bfs_path(ord);\n        vector<int> seq = build_seq_from_path(path, L);\n\n        double best_score_here = evaluate_seq(seq);\n        bool any_improve = true;\n        int iter = 0;\n        while (any_improve && now_sec() - t0 < TL) {\n            any_improve = false;\n\n            double sc_pair; bool ch_pair;\n            forward_pair_pass(seq, sc_pair, ch_pair);\n            if (sc_pair > best_score_here + 1e-9) {\n                best_score_here = sc_pair;\n                any_improve = true;\n            }\n\n            double sc_single; bool ch_single;\n            forward_single_pass(seq, sc_single, ch_single);\n            if (sc_single > best_score_here + 1e-9) {\n                best_score_here = sc_single;\n                any_improve = true;\n            }\n\n            iter++;\n            if (iter >= 20) break; // Avoid too many iterations per restart\n        }\n\n        if (best_score_here > global_best_score + 1e-9) {\n            global_best_score = best_score_here;\n            global_best_seq = seq;\n        }\n    }\n\n    // A few random perturbation restarts near the best found\n    int perturb_trials = 0;\n    while (now_sec() - t0 < TL && perturb_trials < 12 && !global_best_seq.empty()) {\n        perturb_trials++;\n        vector<int> seq = global_best_seq;\n        int K = 6 + rng.randint(0, 8);\n        for (int k = 0; k < K; k++) {\n            int tpos = rng.randint(0, L - 1);\n            int ndir = rng.randint(0, 3);\n            seq[tpos] = ndir;\n        }\n        double sc0 = evaluate_seq(seq);\n        bool any_improve = true;\n        int iter = 0;\n        while (any_improve && now_sec() - t0 < TL) {\n            any_improve = false;\n\n            double sc_pair; bool ch_pair;\n            forward_pair_pass(seq, sc_pair, ch_pair);\n            if (sc_pair > sc0 + 1e-9) {\n                sc0 = sc_pair;\n                any_improve = true;\n            }\n\n            double sc_single; bool ch_single;\n            forward_single_pass(seq, sc_single, ch_single);\n            if (sc_single > sc0 + 1e-9) {\n                sc0 = sc_single;\n                any_improve = true;\n            }\n\n            iter++;\n            if (iter >= 12) break;\n        }\n        if (sc0 > global_best_score + 1e-9) {\n            global_best_score = sc0;\n            global_best_seq = seq;\n        }\n    }\n\n    if (global_best_seq.empty()) {\n        // Fallback in very rare case\n        vector<int> path = bfs_path({0,1,2,3});\n        global_best_seq = build_seq_from_path(path, L);\n    }\n\n    string out;\n    out.reserve(L);\n    for (int d: global_best_seq) out.push_back(DIRC[d]);\n    cout << out << \"\\n\";\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\n// RNG\nstruct XorShift {\n    uint64_t x;\n    XorShift() {\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        x = seed ^ (seed << 13) ^ (seed >> 7) ^ (seed << 17);\n        if (x == 0) x = 88172645463393265ull;\n    }\n    inline uint64_t next() { x ^= x << 7; x ^= x << 13; x ^= x >> 9; return x; }\n    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline int randint(int l, int r) { return l + (int)(next_u32() % (uint32_t)(r - l + 1)); }\n    inline double rand01() { return (next_u32() & 0xFFFFFF) / double(0x1000000); }\n} rng;\n\n// Directions: 0=left,1=up,2=right,3=down\nstatic const int di[4] = {0,-1,0,1};\nstatic const int dj[4] = {-1,0,1,0};\n\n// to[t][d] as in statement\nstatic const int TO[8][4] = {\n    {1, 0, -1, -1},\n    {3, -1, -1, 0},\n    {-1, -1, 3, 2},\n    {-1, 2, 1, -1},\n    {1, 0, 3, 2},\n    {3, 2, 1, 0},\n    {2, -1, 0, -1},\n    {-1, 3, -1, 1},\n};\n\n// Presence\nstatic bool PRES[8][4];\nstatic int OUT_COUNT_TO[8][4];\n\n// rotate mapping\ninline int rotate_t(int t, int r) {\n    if (t < 4) return (t + r) & 3;\n    if (t < 6) return (r & 1) ? 9 - t : t; // 4<->5 on odd\n    return (r & 1) ? 13 - t : t;           // 6<->7 on odd\n}\n\nstatic inline int state_id(int i, int j, int d) {\n    return ((i * 30 + j) << 2) | d;\n}\n\nstruct LoopEval {\n    long long L1=0, L2=0;\n    long long product() const { return (L2==0 ? 0LL : L1*L2); }\n};\n\n// Efficient loop evaluator\nLoopEval evaluate_loops(const array<array<int,30>,30>& eff) {\n    const int N=30, M=30, TOT=N*M*4;\n    static int next_state[30*30*4];\n    static unsigned char allowed[30*30*4];\n    // Build next mapping\n    for (int i=0;i<N;i++){\n        for (int j=0;j<M;j++){\n            int t = eff[i][j];\n            for (int d=0; d<4; d++){\n                int idx = state_id(i,j,d);\n                int d2 = TO[t][d];\n                if (d2 == -1) {\n                    allowed[idx] = 0;\n                    next_state[idx] = -1;\n                    continue;\n                }\n                allowed[idx] = 1;\n                int i2 = i + di[d2], j2 = j + dj[d2];\n                if (i2 < 0 || i2 >= N || j2 < 0 || j2 >= M) {\n                    next_state[idx] = -1;\n                } else {\n                    int t2 = eff[i2][j2];\n                    int d_rev = (d2 + 2) & 3;\n                    if (TO[t2][d_rev] == -1) next_state[idx] = -1;\n                    else next_state[idx] = state_id(i2,j2,d_rev);\n                }\n            }\n        }\n    }\n\n    // Detect cycles using path-walk with per-pass marks (no heap)\n    static unsigned char visited[30*30*4];\n    static int seen_pass[30*30*4];\n    static int seen_pos[30*30*4];\n    memset(visited, 0, sizeof(visited));\n    int pass_id = 1;\n    long long best1=0, best2=0;\n    int stack_arr[30*30*4];\n\n    const int TOT_ST = TOT;\n    for (int v0=0; v0<TOT_ST; v0++){\n        if (!allowed[v0] || visited[v0]) continue;\n        int v = v0;\n        int top = 0;\n        ++pass_id;\n        while (true) {\n            if (v < 0 || !allowed[v] || next_state[v] == -1) {\n                // Mark visited\n                while (top) visited[stack_arr[--top]] = 1;\n                break;\n            }\n            if (visited[v]) {\n                while (top) visited[stack_arr[--top]] = 1;\n                break;\n            }\n            if (seen_pass[v] == pass_id) {\n                int cycle_len = top - seen_pos[v];\n                long long L = cycle_len;\n                if (L > best1) { best2 = best1; best1 = L; }\n                else if (L > best2) { best2 = L; }\n                while (top) visited[stack_arr[--top]] = 1;\n                break;\n            }\n            seen_pass[v] = pass_id;\n            seen_pos[v] = top;\n            stack_arr[top++] = v;\n            v = next_state[v];\n        }\n    }\n    LoopEval le; le.L1=best1; le.L2=best2;\n    return le;\n}\n\n// Score2: number of valid next transitions (i,j,d) that lead to in-bounds neighbor accepting entry.\nstruct Score2 {\n    int N=30, M=30;\n    inline int count_outgoing(const array<array<int,30>,30>& eff, int i, int j, int t) const {\n        int s=0;\n        for (int d=0; d<4; d++){\n            int d2 = TO[t][d];\n            if (d2 == -1) continue;\n            int i2 = i + di[d2], j2 = j + dj[d2];\n            if (i2 < 0 || i2 >= N || j2 < 0 || j2 >= M) continue;\n            int t2 = eff[i2][j2];\n            int d_rev = (d2 + 2) & 3;\n            if (TO[t2][d_rev] != -1) s++;\n        }\n        return s;\n    }\n    long long compute_all(const array<array<int,30>,30>& eff) const {\n        long long s=0;\n        for (int i=0;i<N;i++) for (int j=0;j<M;j++) s += count_outgoing(eff, i, j, eff[i][j]);\n        return s;\n    }\n    long long delta_change(const array<array<int,30>,30>& eff, int i, int j, int curT, int newT) const {\n        long long delta = 0;\n        delta += count_outgoing(eff, i, j, newT) - count_outgoing(eff, i, j, curT);\n        if (j-1 >= 0) {\n            int tL = eff[i][j-1];\n            int c = OUT_COUNT_TO[tL][2];\n            delta += c * ( (PRES[newT][0] ? 1:0) - (PRES[curT][0] ? 1:0) );\n        }\n        if (j+1 < M) {\n            int tR = eff[i][j+1];\n            int c = OUT_COUNT_TO[tR][0];\n            delta += c * ( (PRES[newT][2] ? 1:0) - (PRES[curT][2] ? 1:0) );\n        }\n        if (i-1 >= 0) {\n            int tU = eff[i-1][j];\n            int c = OUT_COUNT_TO[tU][3];\n            delta += c * ( (PRES[newT][1] ? 1:0) - (PRES[curT][1] ? 1:0) );\n        }\n        if (i+1 < N) {\n            int tD = eff[i+1][j];\n            int c = OUT_COUNT_TO[tD][1];\n            delta += c * ( (PRES[newT][3] ? 1:0) - (PRES[curT][3] ? 1:0) );\n        }\n        return delta;\n    }\n};\n\n// Boundary-friendly suggested rotation\nstatic int boundary_friendly_rotation(int base_t, int i, int j) {\n    const int N=30, M=30;\n    int bestR = 0, bestBad = 1e9;\n    for (int r=0; r<4; r++){\n        int tt = rotate_t(base_t, r);\n        int bad = 0;\n        if (i==0 && PRES[tt][1]) bad++;\n        if (i==N-1 && PRES[tt][3]) bad++;\n        if (j==0 && PRES[tt][0]) bad++;\n        if (j==M-1 && PRES[tt][2]) bad++;\n        if (bad < bestBad) { bestBad = bad; bestR = r; }\n    }\n    return bestR;\n}\n\n// Count invalid exits for tile (focus metric for SA)\ninline int count_invalid_exits(const array<array<int,30>,30>& eff, int i, int j) {\n    const int N=30, M=30;\n    int t = eff[i][j];\n    int bad = 0;\n    for (int d=0; d<4; d++){\n        int d2 = TO[t][d];\n        if (d2 == -1) continue;\n        int i2 = i + di[d2], j2 = j + dj[d2];\n        if (i2 < 0 || i2 >= N || j2 < 0 || j2 >= M) { bad++; continue; }\n        int t2 = eff[i2][j2];\n        int d_rev = (d2 + 2) & 3;\n        if (TO[t2][d_rev] == -1) bad++;\n    }\n    return bad;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Precompute PRES and OUT_COUNT_TO\n    for (int t=0;t<8;t++){\n        for (int d=0; d<4; d++){\n            PRES[t][d] = (TO[t][d] != -1);\n        }\n        for (int dir=0; dir<4; dir++){\n            int c=0;\n            for (int d=0; d<4; d++) if (TO[t][d] == dir) c++;\n            OUT_COUNT_TO[t][dir] = c;\n        }\n    }\n\n    const int N=30, M=30;\n    array<array<int,30>,30> base{};\n    for (int i=0;i<N;i++){\n        string s; if(!(cin>>s)) return 0;\n        for (int j=0;j<M;j++){\n            base[i][j] = s[j]-'0';\n        }\n    }\n\n    Timer timer;\n    const double TIME_LIMIT = 1.98;\n\n    array<array<int,30>,30> rot{};\n    array<array<int,30>,30> eff{};\n\n    // Initialize rotations: boundary-friendly with mild randomness\n    for (int i=0;i<N;i++){\n        for (int j=0;j<M;j++){\n            int t0 = base[i][j];\n            int rr = boundary_friendly_rotation(t0, i, j);\n            // mild random tweak\n            if (rng.rand01() < 0.5) rr = (rr + rng.randint(0,3)) & 3;\n            rot[i][j] = rr;\n            eff[i][j] = rotate_t(t0, rr);\n        }\n    }\n\n    // Phase 1: Coordinate ascent on S2 (~0.6s)\n    Score2 scorer2;\n    long long S2 = scorer2.compute_all(eff);\n    {\n        vector<pair<int,int>> order;\n        order.reserve(N*M);\n        for (int i=0;i<N;i++) for (int j=0;j<M;j++) order.emplace_back(i,j);\n        double t_end = min(0.62, TIME_LIMIT * 0.58);\n        while (timer.elapsed() < t_end) {\n            shuffle(order.begin(), order.end(), std::mt19937(rng.next_u32()));\n            bool improved_any = false;\n            for (auto &p : order) {\n                int i = p.first, j = p.second;\n                int base_t = base[i][j];\n                int curR = rot[i][j];\n                int curT = eff[i][j];\n                long long bestDelta = 0;\n                int bestR = curR;\n                for (int r=0;r<4;r++){\n                    if (r == curR) continue;\n                    int newT = rotate_t(base_t, r);\n                    long long delta = scorer2.delta_change(eff, i, j, curT, newT);\n                    if (delta > bestDelta || (delta == bestDelta && rng.rand01() < 0.1)) {\n                        bestDelta = delta;\n                        bestR = r;\n                    }\n                }\n                if (bestR != curR) {\n                    int newT = rotate_t(base_t, bestR);\n                    S2 += scorer2.delta_change(eff, i, j, curT, newT);\n                    rot[i][j] = bestR;\n                    eff[i][j] = newT;\n                    improved_any = true;\n                }\n                if (timer.elapsed() >= t_end) break;\n            }\n            if (!improved_any) break;\n        }\n    }\n\n    // Evaluate initial loops\n    LoopEval initEval = evaluate_loops(eff);\n    long long currScore = initEval.product();\n\n    // Keep best\n    auto bestRot = rot;\n    auto bestEff = eff;\n    long long bestScore = currScore;\n\n    // Helper lambda: SA run with time budget\n    auto run_SA = [&](array<array<int,30>,30>& rotSA,\n                      array<array<int,30>,30>& effSA,\n                      long long& currScoreSA,\n                      double time_budget) {\n        // Current and best within this run\n        auto currRot = rotSA;\n        auto currEff = effSA;\n        long long currScoreLocal = currScoreSA;\n        auto runBestRot = currRot;\n        auto runBestEff = currEff;\n        long long runBestScore = currScoreLocal;\n\n        double startT = 4.0, endT = 0.02;\n        double t0 = timer.elapsed();\n        int iter = 0;\n\n        while (true) {\n            double e = timer.elapsed() - t0;\n            if (e >= time_budget) break;\n            iter++;\n            double progress = e / time_budget;\n            double T = startT + (endT - startT) * progress;\n\n            // Tournament selection among K candidates using invalid exit count\n            const int K = 5;\n            int bi=-1, bj=-1, bbad=-1;\n            for (int k=0;k<K;k++){\n                int ci = rng.randint(0,N-1);\n                int cj = rng.randint(0,M-1);\n                int bad = count_invalid_exits(currEff, ci, cj);\n                if (bad > bbad || (bad == bbad && rng.rand01() < 0.5)) {\n                    bbad = bad; bi = ci; bj = cj;\n                }\n            }\n            if (bi < 0) { bi = rng.randint(0,N-1); bj = rng.randint(0,M-1); }\n\n            bool two_move = (rng.rand01() < 0.2); // 20% try two-tile move\n            if (two_move) {\n                int i1 = bi, j1 = bj;\n                int dir = rng.randint(0,3);\n                int i2 = i1 + di[dir], j2 = j1 + dj[dir];\n                if (i2<0||i2>=N||j2<0||j2>=M) two_move = false;\n                if (two_move) {\n                    int t1 = base[i1][j1];\n                    int t2 = base[i2][j2];\n                    int oldR1 = currRot[i1][j1], oldR2 = currRot[i2][j2];\n                    int newR1 = (oldR1 + rng.randint(1,3)) & 3;\n                    int newR2 = (oldR2 + rng.randint(1,3)) & 3;\n                    if (newR1 == oldR1) newR1 = (newR1 + 1) & 3;\n                    if (newR2 == oldR2) newR2 = (newR2 + 1) & 3;\n                    int oldT1 = currEff[i1][j1], oldT2 = currEff[i2][j2];\n                    int newT1 = rotate_t(t1, newR1), newT2 = rotate_t(t2, newR2);\n\n                    currRot[i1][j1] = newR1; currEff[i1][j1] = newT1;\n                    currRot[i2][j2] = newR2; currEff[i2][j2] = newT2;\n\n                    LoopEval le = evaluate_loops(currEff);\n                    long long newScore = le.product();\n                    long long diff = newScore - currScoreLocal;\n                    bool accept = false;\n                    if (diff >= 0) accept = true;\n                    else {\n                        double prob = exp((double)diff / max(1.0, T));\n                        if (rng.rand01() < prob) accept = true;\n                    }\n                    if (accept) {\n                        currScoreLocal = newScore;\n                        if (newScore > runBestScore) {\n                            runBestScore = newScore;\n                            runBestRot = currRot;\n                            runBestEff = currEff;\n                        }\n                    } else {\n                        currRot[i1][j1] = oldR1; currEff[i1][j1] = oldT1;\n                        currRot[i2][j2] = oldR2; currEff[i2][j2] = oldT2;\n                    }\n                    continue;\n                }\n            }\n\n            // Single-tile move\n            int i = bi, j = bj;\n            int tbase = base[i][j];\n            int oldR = currRot[i][j];\n            int newR = (oldR + rng.randint(1,3)) & 3;\n            if (newR == oldR) newR = (newR + 1) & 3;\n            int oldT = currEff[i][j];\n            int newT = rotate_t(tbase, newR);\n            currRot[i][j] = newR;\n            currEff[i][j] = newT;\n\n            LoopEval le = evaluate_loops(currEff);\n            long long newScore = le.product();\n            long long diff = newScore - currScoreLocal;\n\n            bool accept = false;\n            if (diff >= 0) accept = true;\n            else {\n                double prob = exp((double)diff / max(1.0, T));\n                if (rng.rand01() < prob) accept = true;\n            }\n            if (accept) {\n                currScoreLocal = newScore;\n                if (newScore > runBestScore) {\n                    runBestScore = newScore;\n                    runBestRot = currRot;\n                    runBestEff = currEff;\n                }\n            } else {\n                currRot[i][j] = oldR;\n                currEff[i][j] = oldT;\n            }\n        }\n\n        // Update global best if better\n        if (runBestScore > bestScore) {\n            bestScore = runBestScore;\n            bestRot = runBestRot;\n            bestEff = runBestEff;\n        }\n        // Return the end-of-run state back to caller\n        rotSA = runBestRot;\n        effSA = runBestEff;\n        currScoreSA = runBestScore;\n    };\n\n    // SA total time budget\n    double used = timer.elapsed();\n    double SA_TOTAL = max(0.9, TIME_LIMIT - used - 0.03); // leave a small margin\n    if (SA_TOTAL > 0.01) {\n        // Split into 2 restarts\n        int restarts = 2;\n        double per = SA_TOTAL / restarts;\n        // First run from current\n        {\n            auto rotSA = rot;\n            auto effSA = eff;\n            long long scSA = currScore;\n            run_SA(rotSA, effSA, scSA, per);\n        }\n        // Second run: shake and re-run\n        if (timer.elapsed() < TIME_LIMIT - 0.04) {\n            auto rotSA = bestRot;\n            auto effSA = bestEff;\n            // Shake: flip ~200 random tiles slightly\n            int Kshake = 200;\n            for (int k=0;k<Kshake;k++){\n                int i = rng.randint(0,N-1), j = rng.randint(0,M-1);\n                int oldR = rotSA[i][j];\n                int newR = (oldR + rng.randint(1,3)) & 3;\n                rotSA[i][j] = newR;\n                effSA[i][j] = rotate_t(base[i][j], newR);\n            }\n            long long scSA = evaluate_loops(effSA).product();\n            run_SA(rotSA, effSA, scSA, per);\n        }\n    }\n\n    // Optional greedy tail if time remains: try a few improving flips\n    if (timer.elapsed() < TIME_LIMIT - 0.01) {\n        auto currRot = bestRot;\n        auto currEff = bestEff;\n        long long currSc = bestScore;\n        int trials = 1500;\n        for (int t=0; t<trials; ++t) {\n            if (timer.elapsed() >= TIME_LIMIT - 0.01) break;\n            // Use tournament selection\n            int bi=-1, bj=-1, bbad=-1;\n            const int K=4;\n            for (int k=0;k<K;k++){\n                int ci = rng.randint(0,N-1), cj = rng.randint(0,M-1);\n                int bad = count_invalid_exits(currEff, ci, cj);\n                if (bad > bbad || (bad == bbad && rng.rand01() < 0.5)) {\n                    bbad = bad; bi = ci; bj = cj;\n                }\n            }\n            if (bi<0) { bi=rng.randint(0,N-1); bj=rng.randint(0,M-1); }\n            int i=bi,j=bj;\n            int base_t = base[i][j];\n            int curR = currRot[i][j];\n            long long bestLocalSc = currSc;\n            int bestR = curR;\n            int bestT = currEff[i][j];\n            for (int r=0;r<4;r++){\n                if (r == curR) continue;\n                int newT = rotate_t(base_t, r);\n                auto saveT = currEff[i][j];\n                currEff[i][j] = newT;\n                LoopEval le = evaluate_loops(currEff);\n                long long sc = le.product();\n                if (sc > bestLocalSc) {\n                    bestLocalSc = sc; bestR = r; bestT = newT;\n                }\n                currEff[i][j] = saveT;\n            }\n            if (bestLocalSc > currSc) {\n                currSc = bestLocalSc;\n                currRot[i][j] = bestR;\n                currEff[i][j] = bestT;\n            }\n        }\n        if (currSc > bestScore) {\n            bestScore = currSc;\n            bestRot = currRot;\n            bestEff = currEff;\n        }\n    }\n\n    // Output best rotations\n    {\n        string out;\n        out.reserve(N*M);\n        for (int i=0;i<N;i++){\n            for (int j=0;j<M;j++){\n                out.push_back(char('0' + bestRot[i][j]));\n            }\n        }\n        cout << out << \"\\n\";\n    }\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\n// High resolution timer\nstatic inline double now_sec() {\n    using clk = chrono::high_resolution_clock;\n    return chrono::duration<double>(clk::now().time_since_epoch()).count();\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n_) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        p.resize(n);\n        sz.assign(n, 0);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Eval {\n    int largestTree = 0;\n    int largestCC = 0;\n    int cyclesInLargestCC = 0;\n    int totalEdges = 0;\n    int loops2x2 = 0;\n    int cyclesTotal = 0;\n};\n\nstruct ScoreKey {\n    // Larger is better.\n    int largestTree;\n    int negCyclesTotal;\n    int largestCC;\n    int negCyclesInLargestCC;\n    int totalEdges;\n    int negLoops2x2;\n    uint32_t tieRand;\n};\n\nstatic inline bool better_key(const ScoreKey& a, const ScoreKey& b) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.negCyclesTotal != b.negCyclesTotal) return a.negCyclesTotal > b.negCyclesTotal;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.negCyclesInLargestCC != b.negCyclesInLargestCC) return a.negCyclesInLargestCC > b.negCyclesInLargestCC;\n    if (a.totalEdges != b.totalEdges) return a.totalEdges > b.totalEdges;\n    if (a.negLoops2x2 != b.negLoops2x2) return a.negLoops2x2 > b.negLoops2x2;\n    return a.tieRand < b.tieRand; // final tie-break\n}\n\nstatic inline int hexchar_to_int(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    if ('a' <= c && c <= 'f') return 10 + (c - 'a');\n    if ('A' <= c && c <= 'F') return 10 + (c - 'A');\n    return 0;\n}\n\nstruct Board {\n    int N;\n    vector<int> a; // size N*N, 0 is empty\n    int zr, zc;\n\n    inline bool in_bounds(int r, int c) const {\n        return (0 <= r && r < N && 0 <= c && c < N);\n    }\n\n    // dir: 0=U,1=D,2=L,3=R (empty moves in that direction)\n    inline bool applyMove(int dir) {\n        static const int dr[4] = {-1, +1, 0, 0};\n        static const int dc[4] = {0, 0, -1, +1};\n        int nr = zr + dr[dir], nc = zc + dc[dir];\n        if (!in_bounds(nr, nc)) return false;\n        int zidx = zr * N + zc;\n        int nidx = nr * N + nc;\n        swap(a[zidx], a[nidx]);\n        zr = nr; zc = nc;\n        return true;\n    }\n};\n\nstruct Evaluator {\n    int N, n2;\n    DSU dsu;\n    vector<char> occ;\n    vector<int> deg;         // degree per vertex in matched graph\n    vector<int> compDegSum;  // sum of deg per component\n\n    Evaluator() {}\n    Evaluator(int N_) { init(N_); }\n    void init(int N_) {\n        N = N_; n2 = N*N;\n        dsu.init(n2);\n        occ.assign(n2, 0);\n        deg.assign(n2, 0);\n        compDegSum.assign(n2, 0);\n    }\n\n    Eval evaluate(const Board& B) {\n        const int L = 1, U = 2, R = 4, D = 8;\n        // reset\n        fill(occ.begin(), occ.end(), 0);\n        fill(deg.begin(), deg.end(), 0);\n        iota(dsu.p.begin(), dsu.p.end(), 0);\n        fill(dsu.sz.begin(), dsu.sz.end(), 0);\n\n        // mark occupied and init DSU sizes\n        for (int i = 0; i < N; ++i) {\n            int base = i * N;\n            for (int j = 0; j < N; ++j) {\n                int id = base + j;\n                if (B.a[id] != 0) {\n                    occ[id] = 1;\n                    dsu.sz[id] = 1;\n                }\n            }\n        }\n\n        int totalEdges = 0;\n        // Unite along matched edges and accumulate degrees\n        // Vertical\n        for (int i = 0; i < N-1; ++i) {\n            int base = i * N;\n            int base2 = (i+1) * N;\n            for (int j = 0; j < N; ++j) {\n                int id1 = base + j;\n                int id2 = base2 + j;\n                int m1 = B.a[id1], m2 = B.a[id2];\n                if ((m1 & D) && (m2 & U)) {\n                    totalEdges++;\n                    deg[id1]++; deg[id2]++;\n                    if (occ[id1] && occ[id2]) dsu.unite(id1, id2);\n                }\n            }\n        }\n        // Horizontal\n        for (int i = 0; i < N; ++i) {\n            int base = i * N;\n            for (int j = 0; j < N-1; ++j) {\n                int id1 = base + j;\n                int id2 = base + (j+1);\n                int m1 = B.a[id1], m2 = B.a[id2];\n                if ((m1 & R) && (m2 & L)) {\n                    totalEdges++;\n                    deg[id1]++; deg[id2]++;\n                    if (occ[id1] && occ[id2]) dsu.unite(id1, id2);\n                }\n            }\n        }\n\n        // Count 2x2 loops\n        int loops2x2 = 0;\n        for (int i = 0; i < N-1; ++i) {\n            int base = i * N;\n            int base2 = (i+1) * N;\n            for (int j = 0; j < N-1; ++j) {\n                int id00 = base + j;\n                int id01 = base + (j+1);\n                int id10 = base2 + j;\n                int id11 = base2 + (j+1);\n                int m00 = B.a[id00], m01 = B.a[id01], m10 = B.a[id10], m11 = B.a[id11];\n                bool v1 = (m00 & 8) && (m10 & 2);\n                bool v2 = (m01 & 8) && (m11 & 2);\n                bool h1 = (m00 & 4) && (m01 & 1);\n                bool h2 = (m10 & 4) && (m11 & 1);\n                if (v1 && v2 && h1 && h2) loops2x2++;\n            }\n        }\n\n        // Sum degrees per component\n        fill(compDegSum.begin(), compDegSum.end(), 0);\n        for (int id = 0; id < n2; ++id) {\n            if (!occ[id]) continue;\n            int r = dsu.find(id);\n            compDegSum[r] += deg[id];\n        }\n\n        int largestCC = 0;\n        int largestTree = 0;\n        int cyclesInLargestCC = 0;\n        int cyclesTotal = 0;\n\n        vector<char> seen(n2, 0);\n        for (int id = 0; id < n2; ++id) {\n            if (!occ[id]) continue;\n            int r = dsu.find(id);\n            if (seen[r]) continue;\n            seen[r] = 1;\n            int V = dsu.sz[r];\n            int E = compDegSum[r] / 2; // each edge counted twice in sums\n            int cyc = E - (V - 1);\n            if (V > largestCC) {\n                largestCC = V;\n                cyclesInLargestCC = max(0, cyc);\n            } else if (V == largestCC) {\n                cyclesInLargestCC = min(cyclesInLargestCC, max(0, cyc));\n            }\n            if (E == V - 1) {\n                if (V > largestTree) largestTree = V;\n            }\n            if (cyc > 0) cyclesTotal += cyc;\n        }\n\n        Eval ev;\n        ev.largestTree = largestTree;\n        ev.largestCC = largestCC;\n        ev.cyclesInLargestCC = cyclesInLargestCC;\n        ev.totalEdges = totalEdges;\n        ev.loops2x2 = loops2x2;\n        ev.cyclesTotal = cyclesTotal;\n        return ev;\n    }\n};\n\nstatic inline ScoreKey make_key(const Eval& ev, std::mt19937& rng) {\n    ScoreKey k;\n    k.largestTree = ev.largestTree;\n    k.negCyclesTotal = -ev.cyclesTotal;\n    k.largestCC = ev.largestCC;\n    k.negCyclesInLargestCC = -ev.cyclesInLargestCC;\n    k.totalEdges = ev.totalEdges;\n    k.negLoops2x2 = -ev.loops2x2;\n    k.tieRand = rng();\n    return k;\n}\n\n// Local heuristic for ordering: delta matched edges and delta 2x2 loops around swapped cells\nstruct LocalHeu {\n    int deltaEdges;  // more is better\n    int deltaLoops;  // fewer is better (negative preferred)\n};\n\nstruct Searcher {\n    int N;\n    Evaluator &evaluator;\n    Board &B;\n    std::mt19937 &rng;\n\n    // Directions: 0=U,1=D,2=L,3=R and opposites\n    static constexpr int dr[4] = {-1, +1, 0, 0};\n    static constexpr int dc[4] = {0, 0, -1, +1};\n    static constexpr int opp[4] = {1, 0, 3, 2};\n    static constexpr char mvch[4] = {'U','D','L','R'};\n\n    vector<int> curPath, bestPath;\n\n    Searcher(int N_, Evaluator &ev, Board &b, std::mt19937 &r)\n        : N(N_), evaluator(ev), B(b), rng(r) {\n        curPath.reserve(16);\n        bestPath.reserve(16);\n    }\n\n    inline bool in_bounds(int r, int c) const {\n        return (0 <= r && r < N && 0 <= c && c < N);\n    }\n\n    // Count matched edges incident to (r,c)\n    int incidentEdgesAt(const Board& BB, int r, int c) const {\n        int id = r * N + c;\n        int m = BB.a[id];\n        if (m == 0) return 0;\n        int cnt = 0;\n        // up\n        if (r-1 >= 0) {\n            int m2 = BB.a[(r-1)*N + c];\n            if ((m & 2) && (m2 & 8)) cnt++;\n        }\n        // down\n        if (r+1 < N) {\n            int m2 = BB.a[(r+1)*N + c];\n            if ((m & 8) && (m2 & 2)) cnt++;\n        }\n        // left\n        if (c-1 >= 0) {\n            int m2 = BB.a[r*N + (c-1)];\n            if ((m & 1) && (m2 & 4)) cnt++;\n        }\n        // right\n        if (c+1 < N) {\n            int m2 = BB.a[r*N + (c+1)];\n            if ((m & 4) && (m2 & 1)) cnt++;\n        }\n        return cnt;\n    }\n\n    // Does 2x2 square with top-left (i,j) form a cycle?\n    bool isLoop2x2At(const Board& BB, int i, int j) const {\n        if (i < 0 || j < 0 || i+1 >= N || j+1 >= N) return false;\n        int id00 = i*N + j;\n        int id01 = i*N + (j+1);\n        int id10 = (i+1)*N + j;\n        int id11 = (i+1)*N + (j+1);\n        int m00 = BB.a[id00], m01 = BB.a[id01], m10 = BB.a[id10], m11 = BB.a[id11];\n        bool v1 = (m00 & 8) && (m10 & 2);\n        bool v2 = (m01 & 8) && (m11 & 2);\n        bool h1 = (m00 & 4) && (m01 & 1);\n        bool h2 = (m10 & 4) && (m11 & 1);\n        return v1 && v2 && h1 && h2;\n    }\n\n    // Local heuristic: deltaEdges and deltaLoops caused by move dir\n    LocalHeu local_delta_for_dir(int dir) {\n        LocalHeu h{0, 0};\n        int zr = B.zr, zc = B.zc;\n        int nr = zr + dr[dir], nc = zc + dc[dir];\n        if (!in_bounds(nr, nc)) return h;\n\n        // Cells affected: (zr,zc) and (nr,nc)\n        // Pre counts\n        int preEdges = incidentEdgesAt(B, zr, zc) + incidentEdgesAt(B, nr, nc);\n\n        // Loops: check up to 8 top-left corners that include either cell\n        static int dpos[4][2] = {{0,0},{-1,0},{0,-1},{-1,-1}};\n        vector<pair<int,int>> tllist;\n        tllist.reserve(8);\n        auto add_tl = [&](int r, int c) {\n            for (int k = 0; k < 4; ++k) {\n                int tr = r + dpos[k][0];\n                int tc = c + dpos[k][1];\n                if (tr < 0 || tc < 0 || tr+1 >= N || tc+1 >= N) continue;\n                tllist.emplace_back(tr, tc);\n            }\n        };\n        add_tl(zr, zc);\n        add_tl(nr, nc);\n        // Deduplicate\n        sort(tllist.begin(), tllist.end());\n        tllist.erase(unique(tllist.begin(), tllist.end()), tllist.end());\n\n        int preLoops = 0;\n        for (auto &p : tllist) {\n            if (isLoop2x2At(B, p.first, p.second)) preLoops++;\n        }\n\n        // Apply move\n        B.applyMove(dir);\n\n        int postEdges = incidentEdgesAt(B, zr, zc) + incidentEdgesAt(B, nr, nc);\n        int postLoops = 0;\n        for (auto &p : tllist) {\n            if (isLoop2x2At(B, p.first, p.second)) postLoops++;\n        }\n\n        // Undo\n        B.applyMove(opp[dir]);\n\n        h.deltaEdges = postEdges - preEdges;\n        h.deltaLoops = postLoops - preLoops;\n        return h;\n    }\n\n    // DFS with time budget and local move ordering\n    void dfs(int depth, int maxD, int lastDir, ScoreKey& bestKey, double endTime, bool& timeUp) {\n        // Check time occasionally\n        if (depth > 0 && ((depth & 1) == 0)) {\n            if (now_sec() > endTime) {\n                timeUp = true;\n                return;\n            }\n        }\n\n        if (depth == maxD) {\n            Eval ev = evaluator.evaluate(B);\n            ScoreKey key = make_key(ev, rng);\n            if (better_key(key, bestKey)) {\n                bestKey = key;\n                bestPath = curPath;\n            }\n            return;\n        }\n\n        // Generate candidate moves\n        array<int,4> cand;\n        int cn = 0;\n        for (int dir = 0; dir < 4; ++dir) {\n            if (lastDir != -1 && dir == opp[lastDir]) continue;\n            int nr = B.zr + dr[dir];\n            int nc = B.zc + dc[dir];\n            if (!in_bounds(nr, nc)) continue;\n            cand[cn++] = dir;\n        }\n        if (cn == 0) return;\n\n        // Order candidates by local heuristic\n        vector<pair<pair<int,int>,int>> ord; // ((deltaEdges, -deltaLoops), dir)\n        ord.reserve(cn);\n        for (int i = 0; i < cn; ++i) {\n            int dir = cand[i];\n            LocalHeu h = local_delta_for_dir(dir);\n            ord.push_back({{h.deltaEdges, -h.deltaLoops}, dir});\n        }\n        sort(ord.begin(), ord.end(), [&](const auto& A, const auto& B){\n            if (A.first.first != B.first.first) return A.first.first > B.first.first;\n            if (A.first.second != B.first.second) return A.first.second > B.first.second;\n            return A.second < B.second;\n        });\n\n        for (int i = 0; i < cn; ++i) {\n            int dir = ord[i].second;\n\n            bool ok = B.applyMove(dir);\n            if (!ok) continue;\n            curPath.push_back(dir);\n\n            dfs(depth+1, maxD, dir, bestKey, endTime, timeUp);\n\n            curPath.pop_back();\n            B.applyMove(opp[dir]);\n            if (timeUp) return;\n        }\n    }\n\n    // Choose best move with time budget and desired depth\n    int choose_move_with_budget(int maxDepth, double budget_sec, ScoreKey& outKey) {\n        curPath.clear();\n        bestPath.clear();\n        ScoreKey bestKey = {-1, INT_MIN, -1, INT_MIN, -1, INT_MIN, 0};\n        bool timeUp = false;\n        double endTime = now_sec() + budget_sec;\n        dfs(0, maxDepth, -1, bestKey, endTime, timeUp);\n        outKey = bestKey;\n        if (!bestPath.empty()) return bestPath[0];\n        return -1;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    if (!(cin >> N >> T)) return 0;\n    vector<string> ts(N);\n    for (int i = 0; i < N; ++i) cin >> ts[i];\n\n    Board B;\n    B.N = N;\n    B.a.assign(N*N, 0);\n    B.zr = -1; B.zc = -1;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int v = hexchar_to_int(ts[i][j]);\n            B.a[i*N + j] = v;\n            if (v == 0) { B.zr = i; B.zc = j; }\n        }\n    }\n\n    Evaluator evaluator(N);\n\n    string ans;\n    ans.reserve(T);\n\n    // RNG\n    std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Directions helpers\n    static const int dr[4] = {-1, +1, 0, 0};\n    static const int dc[4] = {0, 0, -1, +1};\n    static const char mvch[4] = {'U', 'D', 'L', 'R'};\n    static const int opp[4] = {1, 0, 3, 2};\n\n    // Timer\n    double t_start = now_sec();\n    const double TIME_LIMIT = 2.95; // seconds\n    const double SAFETY_MARGIN = 0.05; // keep some margin\n\n    // Early perfect check\n    Eval ev0 = evaluator.evaluate(B);\n    if (ev0.largestTree == N*N - 1) {\n        cout << \"\" << '\\n';\n        return 0;\n    }\n\n    Searcher searcher(N, evaluator, B, rng);\n\n    auto fallback_one_ply = [&]() -> int {\n        // Choose best of legal 1-step moves by full evaluation\n        ScoreKey bestKey = {-1, INT_MIN, -1, INT_MIN, -1, INT_MIN, 0};\n        int bestDir = -1;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nr = B.zr + dr[dir];\n            int nc = B.zc + dc[dir];\n            if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) continue;\n            B.applyMove(dir);\n            Eval ev = evaluator.evaluate(B);\n            ScoreKey key = make_key(ev, rng);\n            if (better_key(key, bestKey)) {\n                bestKey = key;\n                bestDir = dir;\n            }\n            B.applyMove(opp[dir]);\n        }\n        if (bestDir == -1) {\n            // Any legal move\n            for (int dir = 0; dir < 4; ++dir) {\n                int nr = B.zr + dr[dir];\n                int nc = B.zc + dc[dir];\n                if ((0 <= nr && nr < N && 0 <= nc && nc < N)) return dir;\n            }\n        }\n        return bestDir;\n    };\n\n    for (int step = 0; step < T; ++step) {\n        double elapsed = now_sec() - t_start;\n        double timeLeft = TIME_LIMIT - elapsed - SAFETY_MARGIN;\n        if (timeLeft < 0.0) timeLeft = 0.0;\n\n        // Per-step budget: target to use most time but finish all steps\n        double remainSteps = double(T - step);\n        double budget = (remainSteps > 0 ? timeLeft / remainSteps : 0.0);\n        // Clamp budget to reasonable range\n        double minBudget = 0.00025; // 0.25 ms\n        double maxBudget = 0.0035;  // 3.5 ms per step typical upper bound\n        if (budget < minBudget) budget = minBudget;\n        if (budget > maxBudget) budget = maxBudget;\n\n        // Dynamic depth selection\n        int maxDepth;\n        if (N <= 7) {\n            if (budget > 0.0028) maxDepth = 5;\n            else if (budget > 0.0015) maxDepth = 4;\n            else maxDepth = 3;\n        } else {\n            if (budget > 0.0022) maxDepth = 4;\n            else maxDepth = 3;\n        }\n\n        // Search within budget\n        ScoreKey outKey;\n        int chosenDir = searcher.choose_move_with_budget(maxDepth, budget, outKey);\n\n        if (chosenDir == -1) {\n            // Fallback 1-ply greedy (fast)\n            chosenDir = fallback_one_ply();\n            if (chosenDir == -1) break; // no legal move (should not happen)\n        }\n\n        // Execute\n        B.applyMove(chosenDir);\n        ans.push_back(mvch[chosenDir]);\n\n        // Optional early stop if perfect\n        Eval ev = evaluator.evaluate(B);\n        if (ev.largestTree == N*N - 1) {\n            // Done; stopping early improves K if perfect\n            break;\n        }\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\nstruct Normal { long long nx, ny; };\n\nstruct WeightSpec {\n    int mode;      // 0: uniform; 1: symmetric center-heavy (r<1); 2: monotonic (r<1)\n    long double r; // ratio parameter (unused for uniform)\n};\n\nstatic inline long long now_us() {\n    using namespace std::chrono;\n    return duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();\n}\n\n// Build weights\nstatic vector<long double> make_weights(int m, const WeightSpec& ws) {\n    vector<long double> w(max(m, 1), 1.0L);\n    if (m <= 0) return w;\n    if (ws.mode == 0) {\n        for (int i = 0; i < m; ++i) w[i] = 1.0L;\n    } else if (ws.mode == 1) {\n        long double mid = (m - 1) * 0.5L;\n        for (int i = 0; i < m; ++i) {\n            long double d = fabsl((long double)i - mid);\n            w[i] = pow(ws.r, d);\n        }\n    } else if (ws.mode == 2) {\n        long double v = 1.0L;\n        for (int i = 0; i < m; ++i) {\n            w[i] = v;\n            v *= ws.r;\n        }\n    } else {\n        for (int i = 0; i < m; ++i) w[i] = 1.0L;\n    }\n    long double s = 0;\n    for (auto &x : w) s += x;\n    if (s > 0) for (auto &x : w) x /= s;\n    return w;\n}\n\n// Largest Remainder Method\nstatic vector<int> targets_from_weights(const vector<long double>& w, int N) {\n    int m = (int)w.size();\n    vector<int> tgt(m, 0);\n    vector<pair<long double,int>> frac; frac.reserve(m);\n    long double sum_floor = 0;\n    for (int i = 0; i < m; ++i) {\n        long double val = (long double)N * w[i];\n        int f = (int)floor(val);\n        tgt[i] = f;\n        sum_floor += f;\n        frac.emplace_back(val - f, i);\n    }\n    int rem = N - (int)sum_floor;\n    if (rem > 0) {\n        sort(frac.begin(), frac.end(), [](const auto& a, const auto& b){ return a.first > b.first; });\n        for (int k = 0; k < rem && k < m; ++k) {\n            tgt[frac[k].second]++;\n        }\n    }\n    return tgt;\n}\n\n// Safe j positions where integer cut is possible between arr[j] and arr[j+1], with sentinels -1 and N-1\nstatic vector<int> build_safe_indices(const vector<long long>& arr) {\n    int N = (int)arr.size();\n    vector<int> safe;\n    safe.reserve(N + 2);\n    safe.push_back(-1);\n    for (int j = 0; j + 1 < N; ++j) {\n        if (arr[j+1] - arr[j] >= 2) {\n            safe.push_back(j);\n        }\n    }\n    safe.push_back(N - 1);\n    return safe;\n}\n\nstatic int choose_nearest_safe(const vector<int>& safe, int t, int min_j) {\n    int lo = 0, hi = (int)safe.size();\n    while (lo < hi) {\n        int mid = (lo + hi) >> 1;\n        if (safe[mid] < t) lo = mid + 1;\n        else hi = mid;\n    }\n    long long bestDist = (1LL<<60);\n    int best = -1;\n    for (int k = lo - 1; k <= lo; ++k) {\n        if (k < 0 || k >= (int)safe.size()) continue;\n        int cand = safe[k];\n        if (cand < min_j) continue;\n        long long dist = llabs((long long)cand - (long long)t);\n        if (dist < bestDist) {\n            bestDist = dist;\n            best = cand;\n        }\n    }\n    if (best == -1) {\n        int idx = lower_bound(safe.begin(), safe.end(), min_j) - safe.begin();\n        if (idx >= (int)safe.size()) idx = (int)safe.size() - 1;\n        best = safe[idx];\n    }\n    return best;\n}\n\n// Plan boundary j-values (in terms of index into arr_sorted: cut between j and j+1) given per-segment counts\nstatic vector<int> plan_boundaries_from_targets(const vector<long long>& arr_sorted, const vector<int>& inc) {\n    int N = (int)arr_sorted.size();\n    int L = (int)inc.size();\n    vector<int> safe = build_safe_indices(arr_sorted);\n    vector<int> js; js.reserve(L);\n    int pos = 0;\n    for (int i = 0; i < L; ++i) {\n        int c = inc[i];\n        if (pos >= N) {\n            js.push_back(N - 1); // far right\n            continue;\n        }\n        if (c <= 0) {\n            js.push_back(-1); // far left\n            continue;\n        }\n        int desired = pos + c - 1;\n        desired = max(desired, pos - 1);\n        desired = min(desired, N - 1);\n        int j = choose_nearest_safe(safe, desired, pos - 1);\n        js.push_back(j);\n        if (j >= pos - 1) pos = max(pos, j + 1);\n    }\n    sort(js.begin(), js.end()); // monotone sequence\n    return js;\n}\n\nstruct Projected {\n    vector<long long> u, v;         // raw projections\n    vector<pair<long long,int>> up, vp; // value,id sorted\n    vector<long long> uSorted, vSorted;\n    vector<int> ru, rv;             // ranks in sorted arrays\n    vector<int> safeU, safeV;       // safe j lists\n};\n\nstatic void build_projection(const vector<Point>& pts, const Normal& nx, const Normal& ny, Projected& P) {\n    int N = (int)pts.size();\n    P.u.resize(N); P.v.resize(N);\n    for (int i = 0; i < N; ++i) {\n        P.u[i] = nx.nx * (long long)pts[i].x + nx.ny * (long long)pts[i].y;\n        P.v[i] = ny.nx * (long long)pts[i].x + ny.ny * (long long)pts[i].y;\n    }\n    P.up.resize(N); P.vp.resize(N);\n    for (int i = 0; i < N; ++i) {\n        P.up[i] = {P.u[i], i};\n        P.vp[i] = {P.v[i], i};\n    }\n    stable_sort(P.up.begin(), P.up.end());\n    stable_sort(P.vp.begin(), P.vp.end());\n    P.uSorted.resize(N);\n    P.vSorted.resize(N);\n    P.ru.assign(N, 0);\n    P.rv.assign(N, 0);\n    for (int i = 0; i < N; ++i) {\n        P.uSorted[i] = P.up[i].first;\n        P.vSorted[i] = P.vp[i].first;\n        P.ru[P.up[i].second] = i;\n        P.rv[P.vp[i].second] = i;\n    }\n    // Build safe indices\n    P.safeU = build_safe_indices(P.uSorted);\n    P.safeV = build_safe_indices(P.vSorted);\n}\n\nstatic long long evaluate_score_from_boundaries(const vector<int>& jx, const vector<int>& jy,\n                                                const Projected& P,\n                                                const array<int,11>& a) {\n    int V = (int)jx.size();\n    int H = (int)jy.size();\n    int C = V + 1;\n    int R = H + 1;\n    vector<int> counts(C * R, 0);\n    // For each point, get ci = # {j in jx | j <= ru-1} and ri similar\n    for (size_t i = 0; i < P.u.size(); ++i) {\n        int ru = P.ru[i];\n        int rv = P.rv[i];\n        int ci = int(upper_bound(jx.begin(), jx.end(), ru - 1) - jx.begin());\n        int ri = int(upper_bound(jy.begin(), jy.end(), rv - 1) - jy.begin());\n        counts[ri * C + ci] += 1;\n    }\n    array<int,11> b{}; // b[1..10]\n    for (int val : counts) {\n        if (val >= 1 && val <= 10) b[val]++;\n    }\n    long long s = 0;\n    for (int d = 1; d <= 10; ++d) s += min(a[d], b[d]);\n    return s;\n}\n\nstatic long long extgcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) { x = (a >= 0 ? 1 : -1); y = 0; return llabs(a); }\n    long long x1, y1;\n    long long g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\n// Convert boundary j list to integer constants T for the line equation nx*x + ny*y = T\nstatic vector<long long> constants_from_boundaries(const vector<int>& jlist, const vector<long long>& arrSorted) {\n    int N = (int)arrSorted.size();\n    long long minV = arrSorted.front();\n    long long maxV = arrSorted.back();\n    vector<int> js = jlist;\n    sort(js.begin(), js.end());\n    vector<long long> T; T.reserve(js.size());\n    int leftExtra = 0, rightExtra = 0;\n    for (int j : js) {\n        if (j <= -1) {\n            T.push_back(minV - 1 - leftExtra);\n            leftExtra++;\n        } else if (j >= N - 1) {\n            T.push_back(maxV + 1 + rightExtra);\n            rightExtra++;\n        } else {\n            T.push_back(arrSorted[j] + 1);\n        }\n    }\n    return T;\n}\n\nstatic pair<pair<long long,long long>, pair<long long,long long>> line_endpoints(const Normal& n, long long T) {\n    long long nx = n.nx, ny = n.ny;\n    long long x0, y0;\n    long long g = extgcd(nx, ny, x0, y0);\n    if (g < 0) { g = -g; x0 = -x0; y0 = -y0; }\n    long long mul = T / g;\n    long long px = x0 * mul;\n    long long py = y0 * mul;\n    long long dx = -ny;\n    long long dy = nx;\n    long long px2 = px + dx, py2 = py + dy;\n    return {{px, py}, {px2, py2}};\n}\n\nstruct Candidate {\n    Normal nx, ny;\n    vector<int> jx, jy; // boundary j-values\n    long long score;\n};\n\n// Generate orientation pairs (coprime small normals)\nstatic vector<pair<Normal,Normal>> generate_orientations() {\n    vector<pair<Normal,Normal>> O;\n    auto add = [&](long long ax, long long ay, long long bx, long long by) {\n        if (std::gcd(llabs(ax), llabs(ay)) != 1) return;\n        if (std::gcd(llabs(bx), llabs(by)) != 1) return;\n        // Non-collinear\n        if (ax * by - ay * bx == 0) return;\n        O.push_back({{ax, ay}, {bx, by}});\n    };\n    add(1,0,  0,1);\n    add(1,1,  1,-1);\n    add(2,1,  1,2);\n    add(3,1,  1,3);\n    add(3,2,  2,3);\n    add(4,1,  1,4);\n    add(2,1,  1,-2);\n    add(5,2,  2,5);\n    return O;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    long long start_us = now_us();\n    const long long TIME_LIMIT_US = 2900000; // 2.9s\n    const long long SEARCH_BUDGET_US = 1700000; // ~1.7s for global search\n    const long long LOCAL_BUDGET_US = 1000000;  // ~1.0s for local search (rest is slack)\n\n    int N, K;\n    if (!(cin >> N >> K)) return 0;\n    array<int,11> a{}; for (int d = 1; d <= 10; ++d) cin >> a[d];\n    vector<Point> pts(N); for (int i = 0; i < N; ++i) cin >> pts[i].x >> pts[i].y;\n\n    // Orientation candidates\n    vector<pair<Normal,Normal>> orientations = generate_orientations();\n\n    // Budgeted k values and V/H ratios\n    vector<int> kList;\n    for (int x : {50, 70, 90, 100}) if (x <= K) kList.push_back(x);\n    if (kList.empty()) kList.push_back(min(K, 50));\n    vector<long double> alphaList = {0.35L, 0.45L, 0.55L, 0.65L};\n\n    // Weight options\n    vector<WeightSpec> weightOptions = {\n        {0, 1.0L},   // uniform\n        {1, 0.95L},  // symmetric mild\n        {1, 0.90L},  // symmetric medium\n        {1, 0.85L},  // symmetric strong\n        {2, 0.95L},  // monotonic mild\n        {2, 0.90L},  // monotonic medium\n        {2, 0.80L},  // monotonic strong\n    };\n\n    mt19937_64 rng(123456789); // deterministic for stability\n\n    Candidate best; best.score = -1;\n\n    // Global search\n    for (auto &orn : orientations) {\n        if (now_us() - start_us > SEARCH_BUDGET_US) break;\n\n        Projected P;\n        build_projection(pts, orn.first, orn.second, P);\n\n        for (int kUse : kList) {\n            if (now_us() - start_us > SEARCH_BUDGET_US) break;\n\n            for (long double alpha : alphaList) {\n                if (now_us() - start_us > SEARCH_BUDGET_US) break;\n\n                int V = (int)llround(alpha * kUse);\n                V = max(1, min(V, kUse - 1));\n                int H = kUse - V;\n                int C = V + 1, R = H + 1;\n\n                for (const auto &wc : weightOptions) {\n                    if (now_us() - start_us > SEARCH_BUDGET_US) break;\n                    vector<long double> wcol = make_weights(C, wc);\n                    vector<int> colCounts = targets_from_weights(wcol, N);\n                    vector<int> colInc(colCounts.begin(), colCounts.end() - 1);\n\n                    for (const auto &wr : weightOptions) {\n                        if (now_us() - start_us > SEARCH_BUDGET_US) break;\n                        vector<long double> wrow = make_weights(R, wr);\n                        vector<int> rowCounts = targets_from_weights(wrow, N);\n                        vector<int> rowInc(rowCounts.begin(), rowCounts.end() - 1);\n\n                        vector<int> jx = plan_boundaries_from_targets(P.uSorted, colInc);\n                        vector<int> jy = plan_boundaries_from_targets(P.vSorted, rowInc);\n\n                        long long sc = evaluate_score_from_boundaries(jx, jy, P, a);\n                        if (sc > best.score) {\n                            best.score = sc;\n                            best.nx = orn.first;\n                            best.ny = orn.second;\n                            best.jx = move(jx);\n                            best.jy = move(jy);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Local improvement (hill-climbing) on the best grid\n    if (best.score < 0) {\n        // Fallback: no cuts\n        cout << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Prepare projection for best orientation\n    Projected Pbest;\n    build_projection(pts, best.nx, best.ny, Pbest);\n\n    // Convert j-values to indices in safe arrays for quick move steps\n    auto to_safe_indices = [&](const vector<int>& jlist, const vector<int>& safe) {\n        vector<int> sidx(jlist.size());\n        for (size_t i = 0; i < jlist.size(); ++i) {\n            int j = jlist[i];\n            int idx = int(lower_bound(safe.begin(), safe.end(), j) - safe.begin());\n            if (idx == (int)safe.size() || safe[idx] != j) {\n                // due to sorting, j should be in safe; handle extremes anyway\n                // adjust to nearest\n                if (idx > 0) --idx;\n            }\n            // ensure exact match\n            if (safe[idx] != j) {\n                // fallback search small window\n                int k1 = idx;\n                if (k1+1 < (int)safe.size() && safe[k1+1] == j) idx = k1+1;\n                else if (k1 > 0 && safe[k1-1] == j) idx = k1-1;\n            }\n            sidx[i] = idx;\n        }\n        sort(sidx.begin(), sidx.end());\n        return sidx;\n    };\n\n    auto sx = to_safe_indices(best.jx, Pbest.safeU);\n    auto sy = to_safe_indices(best.jy, Pbest.safeV);\n\n    auto rebuild_j_from_s = [&](const vector<int>& sidx, const vector<int>& safe) {\n        vector<int> jv; jv.reserve(sidx.size());\n        for (int si : sidx) jv.push_back(safe[si]);\n        // jv must be nondecreasing if sidx is nondecreasing\n        return jv;\n    };\n\n    auto evaluate_s = [&](const vector<int>& sx, const vector<int>& sy) {\n        vector<int> jx = rebuild_j_from_s(sx, Pbest.safeU);\n        vector<int> jy = rebuild_j_from_s(sy, Pbest.safeV);\n        return evaluate_score_from_boundaries(jx, jy, Pbest, a);\n    };\n\n    long long currentScore = evaluate_s(sx, sy);\n    if (currentScore != best.score) {\n        // in rare cases due to rounding differences; sync\n        best.score = currentScore;\n    }\n\n    uniform_int_distribution<int> coin(0, 1);\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    auto try_move_line = [&](bool vertical, int idx, int dir, int step)->bool{\n        if (vertical) {\n            if (sx.empty()) return false;\n            int V = (int)sx.size();\n            if (idx < 0 || idx >= V) return false;\n            int new_val = sx[idx] + dir * step;\n            int lo = (idx == 0 ? sx[idx] : sx[idx-1]);\n            int hi = (idx == V-1 ? sx[idx] : sx[idx+1]);\n            if (dir < 0) {\n                new_val = max(new_val, lo);\n            } else {\n                new_val = min(new_val, hi);\n            }\n            if (new_val == sx[idx]) return false;\n\n            int old = sx[idx];\n            sx[idx] = new_val;\n            long long sc = evaluate_s(sx, sy);\n            if (sc > currentScore) {\n                currentScore = sc;\n                return true;\n            } else {\n                sx[idx] = old;\n                return false;\n            }\n        } else {\n            if (sy.empty()) return false;\n            int H = (int)sy.size();\n            if (idx < 0 || idx >= H) return false;\n            int new_val = sy[idx] + dir * step;\n            int lo = (idx == 0 ? sy[idx] : sy[idx-1]);\n            int hi = (idx == H-1 ? sy[idx] : sy[idx+1]);\n            if (dir < 0) new_val = max(new_val, lo);\n            else new_val = min(new_val, hi);\n            if (new_val == sy[idx]) return false;\n\n            int old = sy[idx];\n            sy[idx] = new_val;\n            long long sc = evaluate_s(sx, sy);\n            if (sc > currentScore) {\n                currentScore = sc;\n                return true;\n            } else {\n                sy[idx] = old;\n                return false;\n            }\n        }\n    };\n\n    // Hill-climb loop within time budget\n    while (now_us() - start_us < SEARCH_BUDGET_US + LOCAL_BUDGET_US) {\n        bool vertical = coin(rng);\n        if ((vertical && sx.empty()) || (!vertical && sy.empty())) vertical = !vertical;\n        int idx = 0;\n        int step = 1;\n        if (vertical) {\n            if (sx.empty()) break;\n            uniform_int_distribution<int> pick(0, (int)sx.size() - 1);\n            idx = pick(rng);\n        } else {\n            if (sy.empty()) break;\n            uniform_int_distribution<int> pick(0, (int)sy.size() - 1);\n            idx = pick(rng);\n        }\n        double r = uni01(rng);\n        if (r < 0.15) step = 2;\n        else if (r < 0.20) step = 3;\n        int dir = (coin(rng) ? 1 : -1);\n        try_move_line(vertical, idx, dir, step);\n    }\n\n    // Rebuild final j lists and compute T constants for output\n    vector<int> finalJx = rebuild_j_from_s(sx, Pbest.safeU);\n    vector<int> finalJy = rebuild_j_from_s(sy, Pbest.safeV);\n    vector<long long> Tx = constants_from_boundaries(finalJx, Pbest.uSorted);\n    vector<long long> Ty = constants_from_boundaries(finalJy, Pbest.vSorted);\n\n    // Output lines\n    int V = (int)Tx.size();\n    int H = (int)Ty.size();\n    cout << (V + H) << \"\\n\";\n    // Family X\n    for (int i = 0; i < V; ++i) {\n        auto ep = line_endpoints(best.nx, Tx[i]);\n        auto [p, q] = ep;\n        cout << p.first << \" \" << p.second << \" \" << q.first << \" \" << q.second << \"\\n\";\n    }\n    // Family Y\n    for (int j = 0; j < H; ++j) {\n        auto ep = line_endpoints(best.ny, Ty[j]);\n        auto [p, q] = ep;\n        cout << p.first << \" \" << p.second << \" \" << q.first << \" \" << q.second << \"\\n\";\n    }\n\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Operation {\n    int x1,y1,x2,y2,x3,y3,x4,y4;\n};\n\nstruct Solver {\n    int N, M;\n    int c; // center coordinate (N-1)/2\n    vector<uint8_t> occ; // occupancy grid N*N\n\n    // used unit segments\n    vector<uint8_t> usedH;  // horizontal: size N*(N-1), seg (x,y)-(x+1,y)\n    vector<uint8_t> usedV;  // vertical:   size (N-1)*N, seg (x,y)-(x,y+1)\n    vector<uint8_t> usedD1; // diag +1:    size (N-1)*(N-1), (x,y)-(x+1,y+1)\n    vector<uint8_t> usedD2; // diag -1:    size (N-1)*(N-1), (x,y)-(x+1,y-1) mapped by y-1\n\n    vector<pair<int,int>> points; // all dots (initial + added)\n    vector<Operation> ops;\n\n    // line indices for fast 45\u00b0 generation\n    // diagPlus id: d = x - y, in [-(N-1), +(N-1)] -> index d + (N-1)\n    // diagMinus id: s = x + y, in [0, 2(N-1)] -> index s\n    vector<vector<pair<int,int>>> diagPlus;  // size 2N-1\n    vector<vector<pair<int,int>>> diagMinus; // size 2N-1\n\n    inline int idx(int x, int y) const { return y*N + x; }\n    inline bool isInside(int x, int y) const { return (0 <= x && x < N && 0 <= y && y < N); }\n\n    inline int idxH(int x, int y) const { return y*(N-1) + x; } // x in [0..N-2], y in [0..N-1]\n    inline int idxV(int x, int y) const { return y*N + x; }     // x in [0..N-1], y in [0..N-2]\n    inline int idxD1_fromPoints(int x0, int y0, int x1, int y1) const {\n        // slope +1 segment normalized to (min x, min y)\n        int x = min(x0, x1);\n        int y = min(y0, y1);\n        return y*(N-1) + x; // y in [0..N-2], x in [0..N-2]\n    }\n    inline int idxD2_fromPoints(int x0, int y0, int x1, int y1) const {\n        // slope -1 segment normalized to (min x, max y), index (y-1)*(N-1) + x\n        int x = min(x0, x1);\n        int y = max(y0, y1); // y in [1..N-1]\n        return (y-1)*(N-1) + x;\n    }\n\n    inline int weight(int x, int y) const {\n        int dx = x - c;\n        int dy = y - c;\n        return dx*dx + dy*dy + 1;\n    }\n\n    struct Candidate {\n        // type 0: axis-aligned rectangle\n        // type 1: rotated 45\u00b0 rectangle (sides parallel to y=x and y=-x)\n        int type;\n        int p1x, p1y; // new dot\n        // scoring\n        int w;           // weight(p1)\n        int perim;       // perimeter measured in unit segments\n        long long score; // priority key: higher is better\n\n        // axis fields\n        int xL, xR, yB, yT;\n\n        // rot45 fields: store three existing corners A,B,C (D=p1)\n        int ax, ay, bx, by, cx, cy;\n    };\n\n    struct CandCmp {\n        bool operator()(const Candidate& a, const Candidate& b) const {\n            if (a.score != b.score) return a.score < b.score; // max-heap by score\n            if (a.w != b.w) return a.w < b.w; // then by raw weight\n            // tie-breaker: prefer larger span\n            int aa;\n            if (a.type==0) aa = (a.xR - a.xL) + (a.yT - a.yB);\n            else {\n                int d1 = abs(a.bx - a.ax);\n                int d2 = abs(a.cx - a.ax);\n                aa = d1 + d2;\n            }\n            int bb;\n            if (b.type==0) bb = (b.xR - b.xL) + (b.yT - b.yB);\n            else {\n                int d1 = abs(b.bx - b.ax);\n                int d2 = abs(b.cx - b.ax);\n                bb = d1 + d2;\n            }\n            if (aa != bb) return aa < bb;\n            if (a.p1x != b.p1x) return a.p1x < b.p1x;\n            return a.p1y < b.p1y;\n        }\n    };\n\n    priority_queue<Candidate, vector<Candidate>, CandCmp> pq;\n\n    Solver(int N_, int M_) : N(N_), M(M_) {\n        c = (N - 1) / 2;\n        occ.assign(N*N, 0);\n        usedH.assign(N*(N-1), 0);\n        usedV.assign((N-1)*N, 0);\n        usedD1.assign((N-1)*(N-1), 0);\n        usedD2.assign((N-1)*(N-1), 0);\n        diagPlus.assign(2*N-1, {});\n        diagMinus.assign(2*N-1, {});\n    }\n\n    inline int diagPlusId(int x, int y) const { return (x - y) + (N - 1); }\n    inline int diagMinusId(int x, int y) const { return (x + y); }\n\n    // Compute priority key\n    inline long long priorityScore(int w, int perim) const {\n        // favor weight per unit perimeter; add small bias\n        return (long long)w * 100000LL / (perim + 4);\n    }\n\n    // -------- Validation --------\n    bool validateAxis(const Candidate& cd) const {\n        if (!isInside(cd.p1x, cd.p1y)) return false;\n        if (occ[idx(cd.p1x, cd.p1y)]) return false;\n\n        // other three corners must be occupied\n        int cx[4] = {cd.xL, cd.xR, cd.xR, cd.xL};\n        int cy[4] = {cd.yB, cd.yB, cd.yT, cd.yT};\n        int cntExist = 0;\n        for (int i=0;i<4;i++) {\n            int x = cx[i], y = cy[i];\n            if (x==cd.p1x && y==cd.p1y) continue;\n            if (!isInside(x,y)) return false;\n            if (!occ[idx(x,y)]) return false;\n            cntExist++;\n        }\n        if (cntExist != 3) return false;\n\n        // Perimeter must have no other dots (interior points along sides)\n        for (int x = cd.xL+1; x <= cd.xR-1; ++x) {\n            if (occ[idx(x, cd.yB)]) return false;\n            if (occ[idx(x, cd.yT)]) return false;\n        }\n        for (int y = cd.yB+1; y <= cd.yT-1; ++y) {\n            if (occ[idx(cd.xL, y)]) return false;\n            if (occ[idx(cd.xR, y)]) return false;\n        }\n\n        // No used unit segments on perimeter\n        for (int x = cd.xL; x <= cd.xR-1; ++x) {\n            if (usedH[idxH(x, cd.yB)]) return false;\n            if (usedH[idxH(x, cd.yT)]) return false;\n        }\n        for (int y = cd.yB; y <= cd.yT-1; ++y) {\n            if (usedV[idxV(cd.xL, y)]) return false;\n            if (usedV[idxV(cd.xR, y)]) return false;\n        }\n        return true;\n    }\n\n    bool validateRot45(const Candidate& cd) const {\n        // A(ax,ay), B(bx,by) on +1 diag, C(cx,cy) on -1 diag, D=p1=B+C-A\n        int ax=cd.ax, ay=cd.ay, bx=cd.bx, by=cd.by, cx=cd.cx, cy=cd.cy;\n        int dx=cd.p1x, dy=cd.p1y;\n\n        // basic checks\n        if (!isInside(dx,dy) || occ[idx(dx,dy)]) return false;\n        if (!isInside(ax,ay) || !isInside(bx,by) || !isInside(cx,cy)) return false;\n        if (!occ[idx(ax,ay)] || !occ[idx(bx,by)] || !occ[idx(cx,cy)]) return false;\n\n        // Check geometry: AB slope +1, AC slope -1\n        if (abs(bx - ax) != abs(by - ay)) return false;\n        if (abs(cx - ax) != abs(cy - ay)) return false;\n        int d1 = abs(bx - ax);\n        int d2 = abs(cx - ax);\n        if (d1 == 0 || d2 == 0) return false;\n\n        // D must equal B + C - A\n        if (!(dx == bx + cx - ax && dy == by + cy - ay)) return false;\n\n        int s1x = (bx > ax) ? 1 : -1;\n        int s1y = (by > ay) ? 1 : -1;\n        int s2x = (cx > ax) ? 1 : -1;\n        int s2y = (cy > ay) ? 1 : -1;\n\n        // Perimeter interior points empty\n        // AB interior (+1)\n        for (int t=1; t<=d1-1; ++t) {\n            if (occ[idx(ax + s1x*t, ay + s1y*t)]) return false;\n        }\n        // AC interior (-1)\n        for (int t=1; t<=d2-1; ++t) {\n            if (occ[idx(ax + s2x*t, ay + s2y*t)]) return false;\n        }\n        // BD interior (-1)\n        for (int t=1; t<=d2-1; ++t) {\n            if (occ[idx(bx + s2x*t, by + s2y*t)]) return false;\n        }\n        // DC interior (+1), direction is from D to C which is -s1\n        int ns1x = -s1x, ns1y = -s1y;\n        for (int t=1; t<=d1-1; ++t) {\n            if (occ[idx(dx + ns1x*t, dy + ns1y*t)]) return false;\n        }\n\n        // No used segments: AB and DC are diag +1; BD and CA are diag -1\n        // AB (+1)\n        for (int t=0; t<=d1-1; ++t) {\n            int x0 = ax + s1x*t, y0 = ay + s1y*t;\n            int x1 = ax + s1x*(t+1), y1 = ay + s1y*(t+1);\n            if (usedD1[idxD1_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n        // BD (-1)\n        for (int t=0; t<=d2-1; ++t) {\n            int x0 = bx + s2x*t, y0 = by + s2y*t;\n            int x1 = bx + s2x*(t+1), y1 = by + s2y*(t+1);\n            if (usedD2[idxD2_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n        // DC (+1) from D towards C with -s1\n        for (int t=0; t<=d1-1; ++t) {\n            int x0 = dx + ns1x*t, y0 = dy + ns1y*t;\n            int x1 = dx + ns1x*(t+1), y1 = dy + ns1y*(t+1);\n            if (usedD1[idxD1_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n        // CA (-1) from C towards A with -s2\n        for (int t=0; t<=d2-1; ++t) {\n            int x0 = cx - s2x*t, y0 = cy - s2y*t;\n            int x1 = cx - s2x*(t+1), y1 = cy - s2y*(t+1);\n            if (usedD2[idxD2_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n\n        return true;\n    }\n\n    bool validate(const Candidate& cd) const {\n        if (cd.type == 0) return validateAxis(cd);\n        else return validateRot45(cd);\n    }\n\n    // -------- Mark used segments after committing --------\n    void markUsedSegments(const Candidate& cd) {\n        if (cd.type == 0) {\n            for (int x = cd.xL; x <= cd.xR-1; ++x) {\n                usedH[idxH(x, cd.yB)] = 1;\n                usedH[idxH(x, cd.yT)] = 1;\n            }\n            for (int y = cd.yB; y <= cd.yT-1; ++y) {\n                usedV[idxV(cd.xL, y)] = 1;\n                usedV[idxV(cd.xR, y)] = 1;\n            }\n        } else {\n            int ax=cd.ax, ay=cd.ay, bx=cd.bx, by=cd.by, cx=cd.cx, cy=cd.cy;\n            int dx=cd.p1x, dy=cd.p1y;\n            int s1x = (bx > ax) ? 1 : -1;\n            int s1y = (by > ay) ? 1 : -1;\n            int s2x = (cx > ax) ? 1 : -1;\n            int s2y = (cy > ay) ? 1 : -1;\n            int ns1x = -s1x, ns1y = -s1y;\n            int d1 = abs(bx - ax);\n            int d2 = abs(cx - ax);\n\n            // AB (+1)\n            for (int t=0; t<=d1-1; ++t) {\n                int x0 = ax + s1x*t, y0 = ay + s1y*t;\n                int x1 = ax + s1x*(t+1), y1 = ay + s1y*(t+1);\n                usedD1[idxD1_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n            // BD (-1)\n            for (int t=0; t<=d2-1; ++t) {\n                int x0 = bx + s2x*t, y0 = by + s2y*t;\n                int x1 = bx + s2x*(t+1), y1 = by + s2y*(t+1);\n                usedD2[idxD2_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n            // DC (+1)\n            for (int t=0; t<=d1-1; ++t) {\n                int x0 = dx + ns1x*t, y0 = dy + ns1y*t;\n                int x1 = dx + ns1x*(t+1), y1 = dy + ns1y*(t+1);\n                usedD1[idxD1_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n            // CA (-1)\n            for (int t=0; t<=d2-1; ++t) {\n                int x0 = cx - s2x*t, y0 = cy - s2y*t;\n                int x1 = cx - s2x*(t+1), y1 = cy - s2y*(t+1);\n                usedD2[idxD2_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n        }\n    }\n\n    void emitOperation(const Candidate& cd) {\n        Operation op;\n        if (cd.type == 0) {\n            // order cycle LL -> LR -> UR -> UL; rotate so p1 is first\n            int LLx = cd.xL, LLy = cd.yB;\n            int LRx = cd.xR, LRy = cd.yB;\n            int URx = cd.xR, URy = cd.yT;\n            int ULx = cd.xL, ULy = cd.yT;\n            array<pair<int,int>,4> seq = {{{LLx,LLy},{LRx,LRy},{URx,URy},{ULx,ULy}}};\n            int pos = 0;\n            for (int i=0;i<4;i++) if (seq[i].first==cd.p1x && seq[i].second==cd.p1y) { pos=i; break; }\n            auto get = [&](int k)->pair<int,int> { return seq[(pos + k) % 4]; };\n            auto p1 = get(0);\n            auto p2 = get(1);\n            auto p3 = get(2);\n            auto p4 = get(3);\n            op = {p1.first,p1.second,p2.first,p2.second,p3.first,p3.second,p4.first,p4.second};\n        } else {\n            // cycle is A -> B -> D -> C -> A; start with D\n            int ax=cd.ax, ay=cd.ay, bx=cd.bx, by=cd.by, cx=cd.cx, cy=cd.cy;\n            int dx=cd.p1x, dy=cd.p1y;\n            op = {dx,dy, cx,cy, ax,ay, bx,by};\n        }\n        ops.push_back(op);\n    }\n\n    // -------- Candidate generation helpers --------\n\n    void pushAxisCandidateFromPair(int x1, int y1, int x2, int y2) {\n        if (x1 == x2 || y1 == y2) return; // need diagonal pair\n        int xL = min(x1, x2), xR = max(x1, x2);\n        int yB = min(y1, y2), yT = max(y1, y2);\n        int c1x = x1, c1y = y2; // (x1,y2)\n        int c2x = x2, c2y = y1; // (x2,y1)\n        bool occ1 = occ[idx(c1x, c1y)];\n        bool occ2 = occ[idx(c2x, c2y)];\n        if (occ1 == occ2) return; // need exactly one occupied\n        Candidate cd;\n        cd.type = 0;\n        if (!occ1) { cd.p1x = c1x; cd.p1y = c1y; }\n        else       { cd.p1x = c2x; cd.p1y = c2y; }\n        cd.xL = xL; cd.xR = xR; cd.yB = yB; cd.yT = yT;\n        cd.w = weight(cd.p1x, cd.p1y);\n        cd.perim = 2 * ((xR - xL) + (yT - yB));\n        cd.score = priorityScore(cd.w, cd.perim);\n        if (validate(cd)) pq.push(cd);\n    }\n\n    void pushRot45CandidateFromPivotABC(int ax, int ay, int bx, int by, int cx, int cy) {\n        // D = B + C - A\n        int dx = bx + cx - ax;\n        int dy = by + cy - ay;\n        if (!isInside(dx,dy)) return;\n        if (occ[idx(dx,dy)]) return; // must be empty\n\n        Candidate cd;\n        cd.type = 1;\n        cd.ax = ax; cd.ay = ay; cd.bx = bx; cd.by = by; cd.cx = cx; cd.cy = cy;\n        cd.p1x = dx; cd.p1y = dy;\n        cd.w = weight(dx,dy);\n\n        int d1 = abs(bx - ax);\n        int d2 = abs(cx - ax);\n        if (d1 == 0 || d2 == 0) return;\n        cd.perim = 2*(d1 + d2);\n        cd.score = priorityScore(cd.w, cd.perim);\n\n        if (validate(cd)) pq.push(cd);\n    }\n\n    void generateRot45FromPivot(int ax, int ay) {\n        int idp = diagPlusId(ax, ay);\n        int idm = diagMinusId(ax, ay);\n        auto &Blist = diagPlus[idp];\n        auto &Clist = diagMinus[idm];\n        if (Blist.size() <= 1 || Clist.size() <= 1) return;\n\n        for (auto &B : Blist) {\n            int bx = B.first, by = B.second;\n            if (bx == ax && by == ay) continue;\n            for (auto &C : Clist) {\n                int cx = C.first, cy = C.second;\n                if (cx == ax && cy == ay) continue;\n                pushRot45CandidateFromPivotABC(ax, ay, bx, by, cx, cy);\n            }\n        }\n    }\n\n    // New: incremental 45\u00b0 generation using the new point as B (same +1 diagonal as A)\n    void generateRot45WithNewAsB(int nx, int ny) {\n        int idp = diagPlusId(nx, ny);\n        auto &AList = diagPlus[idp];\n        for (auto &A : AList) {\n            int ax = A.first, ay = A.second;\n            if (ax == nx && ay == ny) continue; // skip itself\n            auto &Clist = diagMinus[diagMinusId(ax, ay)];\n            if (Clist.empty()) continue;\n            for (auto &C : Clist) {\n                int cx = C.first, cy = C.second;\n                if (cx == ax && cy == ay) continue; // avoid zero length\n                pushRot45CandidateFromPivotABC(ax, ay, nx, ny, cx, cy);\n            }\n        }\n    }\n\n    // New: incremental 45\u00b0 generation using the new point as C (same -1 diagonal as A)\n    void generateRot45WithNewAsC(int nx, int ny) {\n        int idm = diagMinusId(nx, ny);\n        auto &AList = diagMinus[idm];\n        for (auto &A : AList) {\n            int ax = A.first, ay = A.second;\n            if (ax == nx && ay == ny) continue; // skip itself\n            auto &Blist = diagPlus[diagPlusId(ax, ay)];\n            if (Blist.empty()) continue;\n            for (auto &B : Blist) {\n                int bx = B.first, by = B.second;\n                if (bx == ax && by == ay) continue; // avoid zero length\n                pushRot45CandidateFromPivotABC(ax, ay, bx, by, nx, ny);\n            }\n        }\n    }\n\n    void initialCandidates() {\n        // fill line indices\n        for (auto &p : points) {\n            int x = p.first, y = p.second;\n            diagPlus[diagPlusId(x,y)].emplace_back(x,y);\n            diagMinus[diagMinusId(x,y)].emplace_back(x,y);\n        }\n\n        int P = (int)points.size();\n        // Axis-aligned candidates from diagonal pairs\n        for (int i=0;i<P;i++) {\n            auto [x1,y1] = points[i];\n            for (int j=i+1;j<P;j++) {\n                auto [x2,y2] = points[j];\n                pushAxisCandidateFromPair(x1,y1,x2,y2);\n            }\n        }\n\n        // Rotated 45\u00b0 rectangles: generate from every pivot\n        for (auto &p : points) {\n            generateRot45FromPivot(p.first, p.second);\n        }\n    }\n\n    void generateFromNewPointAxis(int nx, int ny) {\n        int P = (int)points.size() - 1; // points[0..P-1] are old points\n        for (int i=0;i<P;i++) {\n            int x2 = points[i].first;\n            int y2 = points[i].second;\n            if (nx != x2 && ny != y2) {\n                pushAxisCandidateFromPair(nx,ny,x2,y2);\n            }\n        }\n    }\n\n    void addPointToLines(int x, int y) {\n        diagPlus[diagPlusId(x,y)].emplace_back(x,y);\n        diagMinus[diagMinusId(x,y)].emplace_back(x,y);\n    }\n\n    void solve() {\n        auto start = chrono::steady_clock::now();\n        const double TIME_LIMIT = 4.95; // seconds\n\n        // initial candidates\n        initialCandidates();\n\n        while (!pq.empty()) {\n            // time check\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - start).count();\n            if (elapsed > TIME_LIMIT) break;\n\n            Candidate cd = pq.top(); pq.pop();\n            if (!validate(cd)) continue;\n\n            // Commit this operation\n            occ[idx(cd.p1x, cd.p1y)] = 1;\n            points.emplace_back(cd.p1x, cd.p1y);\n            addPointToLines(cd.p1x, cd.p1y);\n            markUsedSegments(cd);\n            emitOperation(cd);\n\n            // Generate new candidates involving the new point\n            // Axis-aligned: with all existing points\n            generateFromNewPointAxis(cd.p1x, cd.p1y);\n            // Rotated 45\u00b0:\n            // 1) new point as pivot (opposite corner missing)\n            generateRot45FromPivot(cd.p1x, cd.p1y);\n            // 2) new point as B and as C relative to existing pivots\n            generateRot45WithNewAsB(cd.p1x, cd.p1y);\n            generateRot45WithNewAsC(cd.p1x, cd.p1y);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    Solver solver(N, M);\n    solver.points.reserve(N*N);\n    for (int i=0;i<M;i++) {\n        int x,y; cin >> x >> y;\n        solver.points.emplace_back(x,y);\n        solver.occ[solver.idx(x,y)] = 1;\n    }\n\n    solver.solve();\n\n    cout << solver.ops.size() << '\\n';\n    for (auto &op : solver.ops) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << ' '\n             << op.x3 << ' ' << op.y3 << ' ' << op.x4 << ' ' << op.y4 << '\\n';\n    }\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    void reset(int m){ n=m; p.resize(n); sz.assign(n,1); iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\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; sz[a]+=sz[b];\n        return true;\n    }\n    int size(int x){ return sz[find(x)]; }\n};\n\nstruct Simulator {\n    static const int H = 10;\n    static const int W = 10;\n    array<array<int,W>,H> board;\n\n    Simulator() { for (int r=0;r<H;r++) for (int c=0;c<W;c++) board[r][c]=0; }\n\n    pair<int,int> emptyIndexToRC(int p) const {\n        int cnt=0;\n        for(int r=0;r<H;r++){\n            for(int c=0;c<W;c++){\n                if(board[r][c]==0){\n                    ++cnt;\n                    if(cnt==p) return {r,c};\n                }\n            }\n        }\n        return {-1,-1};\n    }\n\n    struct SimResult {\n        array<array<int,W>,H> b;\n        int new_r, new_c;\n    };\n\n    // dir: 0=F,1=B,2=L,3=R\n    SimResult simulateTilt(const array<array<int,W>,H>& inputBoard, int dir, int src_r, int src_c) const {\n        SimResult res;\n        for (int r=0;r<H;r++) for (int c=0;c<W;c++) res.b[r][c]=0;\n\n        if (dir == 0) { // F\n            int cnt = 0;\n            for (int r=0; r<=src_r; ++r) if (inputBoard[r][src_c]!=0) ++cnt;\n            res.new_r = cnt-1; res.new_c = src_c;\n            for (int c=0;c<W;c++){\n                int to=0;\n                for (int r=0;r<H;r++){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[to++][c] = v;\n                }\n            }\n        } else if (dir == 1) { // B\n            int cnt = 0;\n            for (int r=src_r; r<H; ++r) if (inputBoard[r][src_c]!=0) ++cnt;\n            res.new_r = H-1-(cnt-1); res.new_c = src_c;\n            for (int c=0;c<W;c++){\n                int to=H-1;\n                for (int r=H-1;r>=0;r--){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[to--][c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            int cnt = 0;\n            for (int c=0; c<=src_c; ++c) if (inputBoard[src_r][c]!=0) ++cnt;\n            res.new_r = src_r; res.new_c = cnt-1;\n            for (int r=0;r<H;r++){\n                int to=0;\n                for (int c=0;c<W;c++){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[r][to++] = v;\n                }\n            }\n        } else { // R\n            int cnt = 0;\n            for (int c=src_c; c<W; ++c) if (inputBoard[src_r][c]!=0) ++cnt;\n            res.new_r = src_r; res.new_c = W-1-(cnt-1);\n            for (int r=0;r<H;r++){\n                int to=W-1;\n                for (int c=W-1;c>=0;c--){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[r][to--] = v;\n                }\n            }\n        }\n        return res;\n    }\n};\n\nstatic const int H = Simulator::H;\nstatic const int W = Simulator::W;\n\n// Compute sum of squared component sizes for same-color connectivity\nlong long sumSqComponents(const array<array<int,W>,H>& b) {\n    DSU dsu(H*W);\n    auto id = [](int r,int c){ return r*W + c; };\n    for (int r=0;r<H;r++){\n        for (int c=0;c<W;c++){\n            int v = b[r][c];\n            if (!v) continue;\n            if (r+1<H && b[r+1][c]==v) dsu.unite(id(r,c), id(r+1,c));\n            if (c+1<W && b[r][c+1]==v) dsu.unite(id(r,c), id(r,c+1));\n        }\n    }\n    vector<int> cnt(H*W,0);\n    for (int r=0;r<H;r++) for (int c=0;c<W;c++) if (b[r][c]!=0) cnt[dsu.find(id(r,c))]++;\n    long long ans=0;\n    for (int i=0;i<H*W;i++) if (cnt[i]>0) ans += 1LL*cnt[i]*cnt[i];\n    return ans;\n}\n\n// Count number of undirected equal-color adjacent pairs\nlong long adjacencyPairs(const array<array<int,W>,H>& b) {\n    long long cnt=0;\n    for (int r=0;r<H;r++){\n        for (int c=0;c<W;c++){\n            int v = b[r][c];\n            if (!v) continue;\n            if (r+1<H && b[r+1][c]==v) cnt++;\n            if (c+1<W && b[r][c+1]==v) cnt++;\n        }\n    }\n    return cnt;\n}\n\n// Movement distance for a tilt from board0 (before tilt)\nlong long totalMovementDistance(const array<array<int,W>,H>& b0, int dir) {\n    long long mv=0;\n    if (dir==0){ // F\n        for (int c=0;c<W;c++){\n            vector<int> rows;\n            rows.reserve(H);\n            for (int r=0;r<H;r++) if (b0[r][c]!=0) rows.push_back(r);\n            for (int i=0;i<(int)rows.size();i++){\n                mv += rows[i] - i;\n            }\n        }\n    } else if (dir==1){ // B\n        for (int c=0;c<W;c++){\n            vector<int> rows;\n            rows.reserve(H);\n            for (int r=0;r<H;r++) if (b0[r][c]!=0) rows.push_back(r);\n            int k = (int)rows.size();\n            for (int i=0;i<k;i++){\n                int newr = H - k + i;\n                mv += newr - rows[i];\n            }\n        }\n    } else if (dir==2){ // L\n        for (int r=0;r<H;r++){\n            vector<int> cols;\n            cols.reserve(W);\n            for (int c=0;c<W;c++) if (b0[r][c]!=0) cols.push_back(c);\n            for (int j=0;j<(int)cols.size();j++){\n                mv += cols[j] - j;\n            }\n        }\n    } else { // R\n        for (int r=0;r<H;r++){\n            vector<int> cols;\n            cols.reserve(W);\n            for (int c=0;c<W;c++) if (b0[r][c]!=0) cols.push_back(c);\n            int k = (int)cols.size();\n            for (int j=0;j<k;j++){\n                int newc = W - k + j;\n                mv += newc - cols[j];\n            }\n        }\n    }\n    return mv;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> f(100);\n    for (int i=0;i<100;i++){\n        if(!(cin>>f[i])) return 0;\n    }\n\n    Simulator sim;\n\n    // Precompute manhattan distances from all cells to 4 corners\n    array<pair<int,int>,4> corners = { pair<int,int>{0,0}, {0,9}, {9,0}, {9,9} };\n    int distToCorner[4][H][W];\n    for (int k=0;k<4;k++){\n        auto [tr,tc] = corners[k];\n        for (int r=0;r<H;r++) for (int c=0;c<W;c++) distToCorner[k][r][c] = abs(r-tr)+abs(c-tc);\n    }\n\n    // Prepare all 4P3=24 mappings: map[1]=corner for color1, map[2]=..., map[3]=...\n    vector<array<int,4>> mappings;\n    array<int,4> perm = {0,1,2,3};\n    sort(perm.begin(), perm.end());\n    do{\n        array<int,4> m = {0, perm[0], perm[1], perm[2]};\n        mappings.push_back(m);\n    }while(next_permutation(perm.begin(), perm.end()));\n    // current mapping (for potential future use / tie-breaks), start with some default\n    array<int,4> currentMap = mappings[0];\n\n    for (int t=0;t<100;t++){\n        int p; if(!(cin>>p)) return 0;\n\n        // Place the new candy at p-th empty\n        auto [r,c] = sim.emptyIndexToRC(p);\n        auto board0 = sim.board;\n        int color = f[t];\n        board0[r][c] = color;\n\n        // Progress-based weights\n        double progress = (t<=99 ? (double)t/99.0 : 1.0);\n\n        double w_comp       = 6.0 + 24.0*progress;            // emphasize components more later\n        double w_compDelta  = 2.0 + 6.0*progress;             // reward immediate merges\n        double w_adjDelta   = 4.0 + 12.0*progress;            // reward new adjacencies\n        double w_sumDist    = 0.30 - 0.15*progress;           // small pull to corners; decrease over time\n        double w_newAbs     = 1.5*(1.0-progress) + 0.2;       // absolute new dist (bigger early)\n        double w_newDelta   = 2.4*(1.0 - 0.3*progress);       // encourage immediate reduction\n        double w_adjNewSame = 1.5 + 2.5*progress;             // local merging for the new candy\n        double w_adjNewDiff = 0.4 + 0.2*progress;             // avoid bad neighbors\n        double w_move       = 0.03 + 0.25*progress;           // stability penalty (small early, bigger late)\n\n        // Precompute mapping-independent quantities per direction\n        long long sumSq0 = sumSqComponents(board0);\n        long long adjBefore = adjacencyPairs(board0);\n\n        array<Simulator::SimResult,4> ress;\n        array<long long,4> sumSqAfter;\n        array<long long,4> adjAfter;\n        array<long long,4> moveDist;\n        array<int,4> adjNewSame;\n        array<int,4> adjNewDiff;\n\n        static const int dr4[4] = {-1,1,0,0};\n        static const int dc4[4] = {0,0,-1,1};\n\n        for (int d=0; d<4; d++){\n            ress[d] = sim.simulateTilt(board0, d, r, c);\n            sumSqAfter[d] = sumSqComponents(ress[d].b);\n            adjAfter[d]   = adjacencyPairs(ress[d].b);\n            moveDist[d]   = totalMovementDistance(board0, d);\n\n            // new candy neighborhood\n            int nr = ress[d].new_r, nc = ress[d].new_c;\n            int same=0, diff=0;\n            if (0<=nr && nr<H && 0<=nc && nc<W) {\n                for (int k=0;k<4;k++){\n                    int rr = nr + dr4[k], cc = nc + dc4[k];\n                    if (0<=rr && rr<H && 0<=cc && cc<W) {\n                        int v = ress[d].b[rr][cc];\n                        if (!v) continue;\n                        if (v == color) same++;\n                        else diff++;\n                    }\n                }\n            }\n            adjNewSame[d] = same;\n            adjNewDiff[d] = diff;\n        }\n\n        // Evaluate all mappings and directions\n        double bestScore = -1e100;\n        int bestDir = 0;\n        array<int,4> bestMap = currentMap;\n\n        // Precompute newDistBefore for each mapping (depends only on (r,c) and mapping)\n        for (const auto& cmap : mappings) {\n            int cornerIdx = cmap[color];\n            int newDistBefore = distToCorner[cornerIdx][r][c];\n\n            for (int d=0; d<4; d++){\n                // mapping-dependent sums\n                long long sumDistAfter = 0;\n                const auto& B = ress[d].b;\n                for (int rr=0; rr<H; rr++){\n                    for (int cc=0; cc<W; cc++){\n                        int v = B[rr][cc];\n                        if (!v) continue;\n                        int idx = cmap[v];\n                        sumDistAfter += distToCorner[idx][rr][cc];\n                    }\n                }\n                int nr = ress[d].new_r, nc = ress[d].new_c;\n                int newDistAfter = (0<=nr && nr<H && 0<=nc && nc<W) ? distToCorner[cornerIdx][nr][nc] : 0;\n\n                double score = 0.0;\n                score += w_comp * (double)sumSqAfter[d];\n                score += w_compDelta * (double)(sumSqAfter[d] - sumSq0);\n                score += w_adjDelta * (double)(adjAfter[d] - adjBefore);\n                score -= w_sumDist * (double)sumDistAfter;\n                // new-candy terms\n                score -= w_newAbs * (double)newDistAfter;\n                score += w_newDelta * (double)(newDistBefore - newDistAfter);\n                score += w_adjNewSame * (double)adjNewSame[d];\n                score -= w_adjNewDiff * (double)adjNewDiff[d];\n                // movement penalty\n                score -= w_move * (double)moveDist[d];\n\n                // slight tie-breaker: prefer keeping current mapping (consistency)\n                if (cmap == currentMap) score += 0.1;\n\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestDir = d;\n                    bestMap = cmap;\n                }\n            }\n        }\n\n        // Output for first 99 steps\n        if (t < 99) {\n            static const char dirs[4] = {'F','B','L','R'};\n            cout << dirs[bestDir] << '\\n' << flush;\n        }\n\n        // Update board and adopt the mapping that justified the choice\n        sim.board = ress[bestDir].b;\n        currentMap = bestMap;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Utilities\nstatic inline int ceil_log2_int(int x) {\n    int l = 0; int v = 1;\n    while (v < x) { v <<= 1; l++; }\n    return l;\n}\n\n// Build an R x A binary matrix alpha with column sums t[a],\n// keeping row sums balanced and pairwise distances large.\nstatic vector<vector<int>> build_alpha(int R, int A, const vector<int>& t, mt19937_64 &rng) {\n    vector<vector<int>> alpha(R, vector<int>(A, 0));\n    vector<int> rowSum(R, 0);\n\n    // Greedy column fill by balancing row sums\n    for (int a = 0; a < A; ++a) {\n        int need = t[a];\n        vector<int> idx(R);\n        iota(idx.begin(), idx.end(), 0);\n        stable_sort(idx.begin(), idx.end(), [&](int r1, int r2){\n            if (rowSum[r1] != rowSum[r2]) return rowSum[r1] < rowSum[r2];\n            return r1 < r2;\n        });\n        for (int k = 0; k < need && k < R; ++k) {\n            int r = idx[k];\n            alpha[r][a] = 1;\n            rowSum[r]++;\n        }\n    }\n\n    // Small local improvement\n    auto min_pairwise_dist = [&]() {\n        if (R <= 1) return A;\n        int mind = INT_MAX;\n        for (int i = 0; i < R; ++i) {\n            for (int j = i+1; j < R; ++j) {\n                int d = 0;\n                for (int a = 0; a < A; ++a) if (alpha[i][a] != alpha[j][a]) d++;\n                mind = min(mind, d);\n            }\n        }\n        if (mind == INT_MAX) mind = 0;\n        return mind;\n    };\n    int currentMinD = min_pairwise_dist();\n\n    auto penalty = [&](const vector<int>& rs) {\n        int p = 0;\n        int target = A/2;\n        for (int r = 0; r < R; ++r) {\n            int d = abs(rs[r] - target);\n            p += d*d;\n        }\n        return p;\n    };\n    int oldPen = penalty(rowSum);\n\n    uniform_int_distribution<int> distA(0, max(0, A-1));\n    uniform_int_distribution<int> distR(0, max(0, R-1));\n    for (int iter = 0; iter < 2000; ++iter) {\n        if (A <= 0 || R <= 1) break;\n        int a = distA(rng);\n        int r1 = distR(rng), r2 = distR(rng);\n        if (r1 == r2) continue;\n        if (alpha[r1][a] == alpha[r2][a]) continue;\n\n        alpha[r1][a] ^= 1;\n        alpha[r2][a] ^= 1;\n\n        int newMinD = min_pairwise_dist();\n        vector<int> rowSumNew = rowSum;\n        rowSumNew[r1] += (alpha[r1][a] ? 1 : -1);\n        rowSumNew[r2] += (alpha[r2][a] ? 1 : -1);\n        int newPen = penalty(rowSumNew);\n\n        bool accept = false;\n        if (newMinD > currentMinD) accept = true;\n        else if (newMinD == currentMinD && newPen <= oldPen) accept = true;\n\n        if (accept) {\n            currentMinD = newMinD;\n            rowSum = rowSumNew;\n            oldPen = newPen;\n        } else {\n            alpha[r1][a] ^= 1;\n            alpha[r2][a] ^= 1;\n        }\n    }\n    return alpha;\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    mt19937_64 rng(123456789);\n\n    // Bits required (for reference)\n    int Lbits = max(1, ceil_log2_int(M));\n\n    // Choose cluster size g more aggressively small for tiny eps to reduce N.\n    int g;\n    if (eps <= 0.02) g = 6;\n    else if (eps <= 0.06) g = 7;\n    else if (eps <= 0.12) g = 8;\n    else if (eps <= 0.20) g = 9;\n    else g = 10;\n\n    // Number of cluster rows R (redundancy). Keep R=Lbits; extra redundancy hurts N.\n    int R = Lbits;\n\n    // Anchors: A = min(R + 1, cap). We use full A=R+1 for maximal separation if fits.\n    int A = R + 1;\n\n    // Column sums t[a] = a in 0..R (strictly increasing)\n    vector<int> t(A);\n    for (int a = 0; a < A; ++a) t[a] = a;\n\n    // Build alpha\n    auto alpha = build_alpha(R, A, t, rng);\n\n    // Row sums\n    vector<int> rowSum(R, 0);\n    for (int i = 0; i < R; ++i) for (int a = 0; a < A; ++a) rowSum[i] += alpha[i][a];\n    int rowSumMax = 0;\n    for (int i = 0; i < R; ++i) rowSumMax = max(rowSumMax, rowSum[i]);\n\n    // Pads U with eps-dependent margin\n    int margin;\n    if (eps <= 0.04) margin = 1;\n    else if (eps <= 0.10) margin = 2;\n    else if (eps <= 0.20) margin = 3;\n    else margin = 3;\n\n    int U = 0;\n    while (true) {\n        int clusterMaxDeg = rowSumMax + (g - 1);\n        int Utarget = max(0, clusterMaxDeg + margin - (A - 1));\n        int N0 = A + R * g;\n        if (N0 > 100) {\n            if (g > 4) { g--; continue; }\n            // reduce A if necessary (choose distinct t[a] spread)\n            if (A > 6) { A--; t.resize(A); for (int a=0;a<A;++a) t[a] = (int)llround( (double)a * R / (double)(A-1) ); alpha = build_alpha(R, A, t, rng);\n                // recompute rowSumMax\n                rowSum.assign(R,0); for(int i=0;i<R;++i) for(int a=0;a<A;++a) rowSum[i]+=alpha[i][a];\n                rowSumMax = 0; for(int i=0;i<R;++i) rowSumMax = max(rowSumMax, rowSum[i]);\n                continue;\n            }\n            // If still too big, reduce R (last resort)\n            if (R > Lbits) { R--; g = max(g, 4); A = min(A, R+1); t.resize(A); for (int a=0;a<A;++a) t[a] = (int)llround( (double)a * R / (double)(A-1) ); alpha = build_alpha(R, A, t, rng);\n                rowSum.assign(R,0); for(int i=0;i<R;++i) for(int a=0;a<A;++a) rowSum[i]+=alpha[i][a];\n                rowSumMax = 0; for(int i=0;i<R;++i) rowSumMax = max(rowSumMax, rowSum[i]);\n                continue;\n            }\n            // fallback\n            break;\n        }\n        if (N0 + Utarget <= 100) {\n            U = Utarget;\n            break;\n        } else {\n            if (g > 4) { g--; continue; }\n            if (A > 6) { A--; t.resize(A); for (int a=0;a<A;++a) t[a] = (int)llround( (double)a * R / (double)(A-1) ); alpha = build_alpha(R, A, t, rng);\n                rowSum.assign(R,0); for(int i=0;i<R;++i) for(int a=0;a<A;++a) rowSum[i]+=alpha[i][a];\n                rowSumMax = 0; for(int i=0;i<R;++i) rowSumMax = max(rowSumMax, rowSum[i]);\n                continue;\n            }\n            // Reduce U to fit\n            U = max(0, 100 - (A + R * g));\n            break;\n        }\n    }\n\n    int N = A + U + R * g;\n    int T = N * (N - 1) / 2;\n\n    // Index mapping (i<j) -> position in string\n    vector<int> offset(N+1, 0);\n    for (int i = 1; i <= N; ++i) offset[i] = offset[i-1] + (N - i);\n    auto idx = [&](int i, int j) -> int {\n        if (i > j) swap(i, j);\n        return offset[i] + (j - i - 1);\n    };\n\n    // Cluster ranges\n    auto cluster_start = [&](int r) { return A + U + r * g; };\n    auto cluster_end = [&](int r) { return A + U + (r + 1) * g - 1; };\n\n    // Build base adjacency string\n    string base(T, '0');\n\n    // Anchors clique\n    for (int i = 0; i < A; ++i)\n        for (int j = i + 1; j < A; ++j)\n            base[idx(i,j)] = '1';\n\n    // Pads connect to all anchors\n    for (int a = 0; a < A; ++a)\n        for (int p = A; p < A + U; ++p)\n            base[idx(a,p)] = '1';\n\n    // Anchor-to-cluster edges via alpha\n    for (int r = 0; r < R; ++r) {\n        int s = cluster_start(r), e = cluster_end(r);\n        for (int a = 0; a < A; ++a) if (alpha[r][a]) {\n            for (int v = s; v <= e; ++v) base[idx(a,v)] = '1';\n        }\n    }\n\n    // Precompute internal edge positions for clusters\n    vector<vector<int>> clusterEdgePos(R);\n    for (int r = 0; r < R; ++r) {\n        int s = cluster_start(r), e = cluster_end(r);\n        for (int u = s; u <= e; ++u)\n            for (int v = u + 1; v <= e; ++v)\n                clusterEdgePos[r].push_back(idx(u,v));\n    }\n\n    // Simple codebook: use identity mapping on R clusters (same as before).\n    // For robustness w.r.t. ML we could design custom codewords, but keeping the simple\n    // mapping retains previous strong performance and benefits from improved assignment.\n    // codebit[r] = bit r of s.\n    // Output N and M graphs\n    cout << N << \"\\n\";\n    cout.flush();\n    for (int k = 0; k < M; ++k) {\n        string out = base;\n        for (int r = 0; r < R; ++r) {\n            int bit = (k >> r) & 1;\n            if (bit) {\n                for (int pos : clusterEdgePos[r]) out[pos] = '1';\n            } else {\n                for (int pos : clusterEdgePos[r]) out[pos] = '0';\n            }\n        }\n        cout << out << \"\\n\";\n    }\n    cout.flush();\n\n    // ML constants\n    double log_p1 = log(max(1e-12, 1.0 - eps));\n    double log_q1 = log(max(1e-12, eps));\n    double log_p0 = log(max(1e-12, eps));\n    double log_q0 = log(max(1e-12, 1.0 - eps));\n\n    // Decoding helper: assign clusters with improved greedy + refinement\n    auto assign_clusters = [&](const vector<vector<char>>& adj, const vector<int>& anchors_ordered){\n        int n = (int)adj.size();\n        vector<int> isAnchorIndex(n, -1);\n        for (int a = 0; a < A; ++a) isAnchorIndex[anchors_ordered[a]] = a;\n\n        vector<int> nonAnchors;\n        nonAnchors.reserve(n - A);\n        for (int v = 0; v < n; ++v) if (isAnchorIndex[v] < 0) nonAnchors.push_back(v);\n\n        // Distances to rows and best rows\n        vector<array<int, 32>> distToRow(n); // R <= 16 in this setup\n        vector<int> bestRow(n, -1), bestD(n, 0), secondD(n, 0);\n        for (int v : nonAnchors) {\n            int d1 = INT_MAX, d2 = INT_MAX, r1 = -1;\n            for (int r = 0; r < R; ++r) {\n                int d = 0;\n                for (int a = 0; a < A; ++a) {\n                    int av = anchors_ordered[a];\n                    int bit = alpha[r][a];\n                    if ((int)adj[v][av] != bit) d++;\n                }\n                distToRow[v][r] = d;\n                if (d < d1) { d2 = d1; d1 = d; r1 = r; }\n                else if (d < d2) d2 = d;\n            }\n            bestRow[v] = r1; bestD[v] = d1; secondD[v] = d2;\n        }\n\n        // Primary candidate lists: for each row, vertices that prefer this row\n        vector<vector<pair<int,int>>> primary(R); // (dist, v)\n        vector<vector<tuple<int,int,int>>> secondary(R); // (gap, dist, v)\n        for (int v : nonAnchors) {\n            int r1 = bestRow[v];\n            primary[r1].push_back({bestD[v], v});\n        }\n        // Prepare secondary lists for fallback: vertices that don't prefer row r\n        for (int r = 0; r < R; ++r) {\n            secondary[r].reserve(nonAnchors.size());\n        }\n        for (int v : nonAnchors) {\n            int r1 = bestRow[v];\n            for (int r = 0; r < R; ++r) if (r != r1) {\n                int gap = distToRow[v][r] - bestD[v]; // >= 0\n                secondary[r].emplace_back(gap, distToRow[v][r], v);\n            }\n        }\n        for (int r = 0; r < R; ++r) {\n            sort(primary[r].begin(), primary[r].end()); // by dist asc\n            sort(secondary[r].begin(), secondary[r].end()); // by gap asc, then dist asc\n        }\n\n        vector<vector<int>> clusterVerts(R);\n        vector<char> used(n, 0);\n        // First pass: take from primary lists\n        for (int r = 0; r < R; ++r) {\n            for (auto &pr : primary[r]) {\n                if ((int)clusterVerts[r].size() >= g) break;\n                int v = pr.second;\n                if (!used[v]) {\n                    clusterVerts[r].push_back(v);\n                    used[v] = 1;\n                }\n            }\n        }\n        // Second pass: fill from secondary lists\n        for (int r = 0; r < R; ++r) {\n            if ((int)clusterVerts[r].size() < g) {\n                for (auto &tp : secondary[r]) {\n                    if ((int)clusterVerts[r].size() >= g) break;\n                    int v = get<2>(tp);\n                    if (!used[v]) {\n                        clusterVerts[r].push_back(v);\n                        used[v] = 1;\n                    }\n                }\n            }\n        }\n        // Last resort: fill any gaps with remaining non-anchors\n        if (true) {\n            for (int r = 0; r < R; ++r) {\n                if ((int)clusterVerts[r].size() < g) {\n                    for (int v : nonAnchors) if (!used[v]) {\n                        clusterVerts[r].push_back(v);\n                        used[v] = 1;\n                        if ((int)clusterVerts[r].size() >= g) break;\n                    }\n                }\n            }\n        }\n        for (int r = 0; r < R; ++r) if ((int)clusterVerts[r].size() > g) clusterVerts[r].resize(g);\n\n        // Local refinement: try beneficial swaps to reduce total distance to rows\n        // Limit iterations for speed\n        for (int it = 0; it < 2; ++it) { // a couple of passes\n            bool improved = false;\n            for (int r1 = 0; r1 < R; ++r1) {\n                for (int r2 = r1+1; r2 < R; ++r2) {\n                    for (int i1 = 0; i1 < (int)clusterVerts[r1].size(); ++i1) {\n                        int v1 = clusterVerts[r1][i1];\n                        int d11 = distToRow[v1][r1];\n                        int d12 = distToRow[v1][r2];\n                        for (int i2 = 0; i2 < (int)clusterVerts[r2].size(); ++i2) {\n                            int v2 = clusterVerts[r2][i2];\n                            int d22 = distToRow[v2][r2];\n                            int d21 = distToRow[v2][r1];\n                            int delta = (d11 + d22) - (d12 + d21);\n                            if (delta > 0) {\n                                // swap\n                                swap(clusterVerts[r1][i1], clusterVerts[r2][i2]);\n                                d11 = distToRow[clusterVerts[r1][i1]][r1]; // update for next\n                                improved = true;\n                            }\n                        }\n                    }\n                }\n            }\n            if (!improved) break;\n        }\n        return clusterVerts;\n    };\n\n    // Decode for a given anchor ordering: returns {bestS, bestLL}\n    auto decode_with_order = [&](const vector<vector<char>>& adj, const vector<int>& deg, const vector<int>& anchors_ordered)->pair<int,double>{\n        // Build assignment\n        auto clusterVerts = assign_clusters(adj, anchors_ordered);\n\n        // Count intra-cluster edges\n        vector<int> x(R, 0), pairCount(R, 0);\n        for (int r = 0; r < R; ++r) {\n            auto &vec = clusterVerts[r];\n            int gi = (int)vec.size();\n            pairCount[r] = gi * (gi - 1) / 2;\n            int cnt = 0;\n            for (int i = 0; i < gi; ++i)\n                for (int j = i + 1; j < gi; ++j)\n                    if (adj[vec[i]][vec[j]]) cnt++;\n            x[r] = cnt;\n        }\n\n        // ML over s in [0..M-1] using codebit[r] = ((s>>r)&1)\n        int bestS = 0;\n        double bestLL = -1e300;\n        for (int s = 0; s < M; ++s) {\n            double ll = 0.0;\n            for (int r = 0; r < R; ++r) {\n                int bit = (s >> r) & 1;\n                int xi = x[r];\n                int ni = pairCount[r];\n                if (bit) ll += xi * log_p1 + (ni - xi) * log_q1;\n                else ll += xi * log_p0 + (ni - xi) * log_q0;\n            }\n            if (ll > bestLL) { bestLL = ll; bestS = s; }\n        }\n        return {bestS, bestLL};\n    };\n\n    // Prepare adj/deg buffers\n    vector<vector<char>> adj(N, vector<char>(N, 0));\n    vector<int> deg(N, 0);\n\n    for (int q = 0; q < 100; ++q) {\n        string H; cin >> H;\n\n        // Build adjacency and degrees\n        int pos = 0;\n        for (int i = 0; i < N; ++i) {\n            deg[i] = 0;\n            for (int j = 0; j < N; ++j) adj[i][j] = 0;\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = i+1; j < N; ++j) {\n                char c = H[pos++];\n                if (c == '1') {\n                    adj[i][j] = adj[j][i] = 1;\n                    deg[i]++; deg[j]++;\n                }\n            }\n        }\n\n        // Identify anchors: top A by degree\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        nth_element(ord.begin(), ord.begin() + A, ord.end(), [&](int x, int y){\n            return deg[x] > deg[y];\n        });\n        vector<int> anchors(ord.begin(), ord.begin() + A);\n\n        // Build 4 candidate orderings\n        vector<vector<int>> orderings;\n\n        // 1) ascending by degree\n        {\n            vector<int> o = anchors;\n            sort(o.begin(), o.end(), [&](int x, int y){\n                if (deg[x] != deg[y]) return deg[x] < deg[y];\n                return x < y;\n            });\n            orderings.push_back(o);\n            reverse(o.begin(), o.end());\n            orderings.push_back(o);\n        }\n        // 2) ascending by degree to non-anchors\n        vector<char> inA(N, 0);\n        for (int v : anchors) inA[v] = 1;\n        {\n            vector<pair<int,int>> tmp;\n            tmp.reserve(A);\n            for (int v : anchors) {\n                int ext = 0;\n                for (int u = 0; u < N; ++u) if (!inA[u] && adj[v][u]) ext++;\n                tmp.emplace_back(ext, v);\n            }\n            sort(tmp.begin(), tmp.end());\n            vector<int> o; o.reserve(A);\n            for (auto &p : tmp) o.push_back(p.second);\n            orderings.push_back(o);\n            reverse(o.begin(), o.end());\n            orderings.push_back(o);\n        }\n\n        // Try all candidate orderings\n        int finalS = 0;\n        double finalLL = -1e300;\n        for (auto &ordA : orderings) {\n            auto res = decode_with_order(adj, deg, ordA);\n            if (res.second > finalLL) {\n                finalLL = res.second;\n                finalS = res.first;\n            }\n        }\n\n        cout << finalS << \"\\n\";\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Edge {\n    int u, v;\n    ll w;\n};\nstruct AdjEdge {\n    int to;\n    int id;\n    ll w;\n};\n\nconst ll INFLL = (ll)4e18;\n\nint N, M, D, K;\nvector<Edge> edges;\nvector<vector<AdjEdge>> adj;\nvector<int> Xcoord, Ycoord;\n\n// Morton (Z-order) interleaving for tie-breaking by spatial key\nstatic inline uint64_t part1by1(uint32_t x) {\n    uint64_t v = x & 0x0000ffffu;\n    v = (v | (v << 8)) & 0x00FF00FFu;\n    v = (v | (v << 4)) & 0x0F0F0F0Fu;\n    v = (v | (v << 2)) & 0x33333333u;\n    v = (v | (v << 1)) & 0x55555555u;\n    return v;\n}\nstatic inline uint64_t morton2D_32(uint32_t x, uint32_t y) {\n    return (part1by1(y) << 1) | part1by1(x);\n}\n\n// Dijkstra from s to t while ignoring one banned edge (early exit on t)\nll dijkstra_exclude_target(int s, int t, int banned_edge_id) {\n    static vector<ll> dist;\n    static vector<char> vis;\n    dist.assign(N, INFLL);\n    vis.assign(N, 0);\n    struct Node { ll d; int v; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n    dist[s] = 0;\n    pq.push({0, s});\n    while (!pq.empty()) {\n        auto [dcur, u] = pq.top(); pq.pop();\n        if (vis[u]) continue;\n        vis[u] = 1;\n        if (u == t) return dcur;\n        for (const auto &ae : adj[u]) {\n            if (ae.id == banned_edge_id) continue;\n            int v = ae.to;\n            ll nd = dcur + ae.w;\n            if (dist[v] > nd) {\n                dist[v] = nd;\n                pq.push({nd, v});\n            }\n        }\n    }\n    return dist[t];\n}\n\n// Dijkstra SPT from src on full graph; returns dist and parent edge id for each vertex\nvoid dijkstra_tree(int src, vector<ll>& dist, vector<int>& parentEdge) {\n    dist.assign(N, INFLL);\n    parentEdge.assign(N, -1);\n    vector<char> vis(N, 0);\n    struct Node { ll d; int v; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n    dist[src] = 0;\n    pq.push({0, src});\n    while (!pq.empty()) {\n        auto [dcur, u] = pq.top(); pq.pop();\n        if (vis[u]) continue;\n        vis[u] = 1;\n        for (const auto& ae : adj[u]) {\n            int v = ae.to;\n            ll nd = dcur + ae.w;\n            if (dist[v] > nd) {\n                dist[v] = nd;\n                parentEdge[v] = ae.id;\n                pq.push({nd, v});\n            }\n        }\n    }\n}\n\n// Connected components of complement graph for a day (exclude edges scheduled on that day)\nvoid compute_components_for_day(int day, const vector<int>& assign, vector<int>& compId, int& compCount) {\n    compId.assign(N, -1);\n    compCount = 0;\n    deque<int> dq;\n    for (int i = 0; i < N; i++) {\n        if (compId[i] != -1) continue;\n        compId[i] = compCount;\n        dq.push_back(i);\n        while (!dq.empty()) {\n            int u = dq.front(); dq.pop_front();\n            for (const auto& ae : adj[u]) {\n                if (assign[ae.id] == day) continue; // removed that day\n                int v = ae.to;\n                if (compId[v] == -1) {\n                    compId[v] = compCount;\n                    dq.push_back(v);\n                }\n            }\n        }\n        compCount++;\n    }\n}\n\n// Tarjan bridges for day 'day' on the complement graph (edges with assign != day).\n// Returns isBridge[edge_id] (true if edge is a bridge in the complement for this day)\nvoid compute_bridges_for_day(int day, const vector<int>& assign, vector<char>& isBridge) {\n    isBridge.assign(M, false);\n    vector<int> tin(N, -1), low(N, -1);\n    int timer = 0;\n    function<void(int,int)> dfs = [&](int u, int peid) {\n        tin[u] = low[u] = timer++;\n        for (const auto& ae : adj[u]) {\n            int id = ae.id;\n            if (assign[id] == day) continue; // absent that day\n            if (id == peid) continue;\n            int v = ae.to;\n            if (tin[v] == -1) {\n                dfs(v, id);\n                low[u] = min(low[u], low[v]);\n                if (low[v] > tin[u]) {\n                    isBridge[id] = true;\n                }\n            } else {\n                low[u] = min(low[u], tin[v]);\n            }\n        }\n    };\n    for (int i = 0; i < N; i++) {\n        if (tin[i] == -1) dfs(i, -1);\n    }\n}\n\n// Compute isBridge for all days\nvoid precompute_bridges_all_days(const vector<int>& assign, vector<vector<char>>& isBridgeDays) {\n    isBridgeDays.assign(D, vector<char>(M, false));\n    for (int d = 0; d < D; d++) {\n        compute_bridges_for_day(d, assign, isBridgeDays[d]);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> D >> K;\n    edges.resize(M);\n    for (int i = 0; i < M; i++) {\n        int u, v; ll w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[i] = {u, v, w};\n    }\n    Xcoord.resize(N);\n    Ycoord.resize(N);\n    for (int i = 0; i < N; i++) cin >> Xcoord[i] >> Ycoord[i];\n\n    adj.assign(N, {});\n    for (int i = 0; i < M; i++) {\n        auto &e = edges[i];\n        adj[e.u].push_back({e.v, i, e.w});\n        adj[e.v].push_back({e.u, i, e.w});\n    }\n\n    auto time_start = chrono::steady_clock::now();\n    const double T_budget = 5.80; // conservative\n\n    // 1) Per-edge importance via bypass length (dist_no_e(u,v) - w)\n    vector<ll> importance(M, 0);\n    for (int i = 0; i < M; i++) {\n        const auto &e = edges[i];\n        ll alt = dijkstra_exclude_target(e.u, e.v, i);\n        if (alt >= INFLL/2) {\n            importance[i] = (ll)1e9; // should not happen (2-edge-connected), but be safe\n        } else {\n            ll imp = alt - e.w;\n            if (imp < 0) imp = 0;\n            importance[i] = imp;\n        }\n    }\n\n    // 2) Edge usage via S shortest path trees with subtree sizes\n    vector<int> usage(M, 0);\n    vector<int> deg(N, 0);\n    for (int u = 0; u < N; u++) deg[u] = (int)adj[u].size();\n    vector<int> vid(N);\n    iota(vid.begin(), vid.end(), 0);\n    sort(vid.begin(), vid.end(), [&](int a, int b){\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        return a < b;\n    });\n    int SCount = min(48, max(24, N / 20)); // 24..48 depending on N\n    vector<int> sources;\n    int n1 = min((int)vid.size(), SCount / 2);\n    for (int i = 0; i < n1; i++) sources.push_back(vid[i]);\n    for (int i = 0; (int)sources.size() < SCount && i < SCount * 3; i++) {\n        int id = (int)((1LL * i * N) / SCount);\n        if (id >= N) id = N - 1;\n        sources.push_back(id);\n        sort(sources.begin(), sources.end());\n        sources.erase(unique(sources.begin(), sources.end()), sources.end());\n    }\n    for (int i = 0; (int)sources.size() < SCount && i < N; i++) {\n        sources.push_back(i);\n        sort(sources.begin(), sources.end());\n        sources.erase(unique(sources.begin(), sources.end()), sources.end());\n    }\n    if ((int)sources.size() > SCount) sources.resize(SCount);\n\n    vector<ll> distTmp;\n    vector<int> parentEdge;\n    vector<int> orderNodes(N);\n    vector<int> parentVertex(N, -1);\n    vector<int> subtree(N, 0);\n    for (int s : sources) {\n        dijkstra_tree(s, distTmp, parentEdge);\n        // Build parent vertex\n        for (int v = 0; v < N; v++) {\n            int pe = parentEdge[v];\n            if (pe < 0) { parentVertex[v] = -1; continue; }\n            int a = edges[pe].u, b = edges[pe].v;\n            parentVertex[v] = (a == v ? b : a);\n        }\n        // Order nodes by distance descending for subtree accumulation\n        iota(orderNodes.begin(), orderNodes.end(), 0);\n        sort(orderNodes.begin(), orderNodes.end(), [&](int a, int b){\n            return distTmp[a] > distTmp[b];\n        });\n        // init subtree sizes\n        for (int v = 0; v < N; v++) subtree[v] = 1;\n        // accumulate\n        for (int v : orderNodes) {\n            int p = parentVertex[v];\n            if (p >= 0) {\n                int pe = parentEdge[v];\n                // add subtree size to usage of that edge\n                usage[pe] += subtree[v];\n                subtree[p] += subtree[v];\n            }\n        }\n    }\n    int maxUsage = 0;\n    for (int i = 0; i < M; i++) maxUsage = max(maxUsage, usage[i]);\n\n    // 3) Heavy metric combining importance and usage\n    const double alphaUsage = 2.0; // weight of usage in heavy\n    vector<double> heavy(M, 0.0);\n    for (int i = 0; i < M; i++) {\n        double uNorm = (maxUsage > 0 ? (double)usage[i] / (double)maxUsage : 0.0);\n        heavy[i] = (double)importance[i] * (1.0 + alphaUsage * uNorm);\n    }\n\n    // Spatial key for ordering tie-breaks\n    vector<uint64_t> zkey(M);\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        int mx = (Xcoord[u] + Xcoord[v]) >> 1;\n        int my = (Ycoord[u] + Ycoord[v]) >> 1;\n        zkey[i] = morton2D_32((uint32_t)mx, (uint32_t)my);\n    }\n\n    // 4) Grid partition for spatial penalty\n    const int GW = 20, GH = 20;\n    const int strideX = (1001 + GW - 1) / GW; // ceil(1001/GW)\n    const int strideY = (1001 + GH - 1) / GH;\n    auto cell_of_point = [&](int x, int y) -> int {\n        int cx = x / strideX; if (cx >= GW) cx = GW - 1;\n        int cy = y / strideY; if (cy >= GH) cy = GH - 1;\n        return cy * GW + cx;\n    };\n    vector<int> edgeCell(M, 0);\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        int mx = (Xcoord[u] + Xcoord[v]) >> 1;\n        int my = (Ycoord[u] + Ycoord[v]) >> 1;\n        edgeCell[i] = cell_of_point(mx, my);\n    }\n    const int nCells = GW * GH;\n\n    // 5) Sort edges to assign: heavy desc then spatial key asc\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    stable_sort(order.begin(), order.end(), [&](int a, int b){\n        if (heavy[a] != heavy[b]) return heavy[a] > heavy[b];\n        if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n        return a < b;\n    });\n\n    // 6) Greedy assignment with capacity K only (no lower bounds)\n    vector<int> assign(M, -1);\n    vector<vector<int>> dayEdges(D);\n    vector<int> daySize(D, 0);\n\n    // Objective components\n    vector<vector<double>> PV(N, vector<double>(D, 0.0)); // per-vertex/day\n    vector<vector<double>> PC(nCells, vector<double>(D, 0.0)); // per-cell/day\n    vector<double> daySum(D, 0.0); // per-day sum\n    // Endpoint conflict counts (soft preference)\n    vector<vector<int>> cnt(N, vector<int>(D, 0));\n\n    // Objective weights\n    const long double lamV = 1.0L;\n    const long double lamC = 0.30L;\n    const long double lamD = 0.02L;\n\n    auto sqDelta = [&](double s, double dw) -> long double {\n        long double ss = (long double)s;\n        long double ddw = (long double)dw;\n        return (ss + ddw) * (ss + ddw) - ss * ss;\n    };\n\n    auto add_delta = [&](int e, int d) -> long double {\n        int u = edges[e].u, v = edges[e].v;\n        int c = edgeCell[e];\n        double w = heavy[e];\n        long double delta = 0.0L;\n        delta += lamV * ( sqDelta(PV[u][d], w) + sqDelta(PV[v][d], w) );\n        delta += lamC * ( sqDelta(PC[c][d], w) );\n        delta += lamD * ( sqDelta(daySum[d], w) );\n        return delta;\n    };\n    auto remove_delta = [&](int e, int d) -> long double {\n        int u = edges[e].u, v = edges[e].v;\n        int c = edgeCell[e];\n        double w = heavy[e];\n        long double delta = 0.0L;\n        delta += lamV * ( sqDelta(PV[u][d], -w) + sqDelta(PV[v][d], -w) );\n        delta += lamC * ( sqDelta(PC[c][d], -w) );\n        delta += lamD * ( sqDelta(daySum[d], -w) );\n        return delta;\n    };\n\n    for (int idx = 0; idx < M; idx++) {\n        int e = order[idx];\n        int u = edges[e].u, v = edges[e].v;\n\n        int best_d = -1;\n        int best_conf = INT_MAX;\n        long double best_incr = 1e300L;\n        int best_size = INT_MAX;\n\n        for (int d = 0; d < D; d++) {\n            if (daySize[d] >= K) continue;\n            int conf = cnt[u][d] + cnt[v][d];\n            long double incr = add_delta(e, d);\n\n            if (conf < best_conf ||\n                (conf == best_conf && (incr < best_incr - 1e-12L ||\n                                       (fabsl(incr - best_incr) <= 1e-12L && daySize[d] < best_size)))) {\n                best_conf = conf;\n                best_incr = incr;\n                best_size = daySize[d];\n                best_d = d;\n            }\n        }\n        if (best_d == -1) best_d = 0;\n\n        assign[e] = best_d;\n        dayEdges[best_d].push_back(e);\n        daySize[best_d]++;\n        cnt[u][best_d]++; cnt[v][best_d]++;\n        int c = edgeCell[e];\n        double w = heavy[e];\n        PV[u][best_d] += w; PV[v][best_d] += w;\n        PC[c][best_d] += w;\n        daySum[best_d] += w;\n    }\n\n    // posInDay map\n    vector<int> posInDay(M, -1);\n    for (int d = 0; d < D; d++) {\n        for (int i = 0; i < (int)dayEdges[d].size(); i++) posInDay[dayEdges[d][i]] = i;\n    }\n\n    // 7) Connectivity enforcement: fix disconnected days by moving heaviest cross-edges out\n    vector<vector<char>> isBridgeDays;\n    precompute_bridges_all_days(assign, isBridgeDays);\n\n    auto moveEdge = [&](int e, int from, int to) {\n        if (from == to) return;\n        int u = edges[e].u, v = edges[e].v;\n        int c = edgeCell[e];\n        double w = heavy[e];\n        // remove from 'from'\n        {\n            int p = posInDay[e];\n            int last = dayEdges[from].back();\n            dayEdges[from][p] = last;\n            posInDay[last] = p;\n            dayEdges[from].pop_back();\n            daySize[from]--;\n        }\n        // add to 'to'\n        posInDay[e] = (int)dayEdges[to].size();\n        dayEdges[to].push_back(e);\n        daySize[to]++;\n\n        // update stats\n        cnt[u][from]--; cnt[v][from]--;\n        cnt[u][to]++; cnt[v][to]++;\n        PV[u][from] -= w; PV[v][from] -= w;\n        PV[u][to] += w; PV[v][to] += w;\n        PC[c][from] -= w; PC[c][to] += w;\n        daySum[from] -= w; daySum[to] += w;\n        assign[e] = to;\n\n        // update bridges for affected days\n        compute_bridges_for_day(from, assign, isBridgeDays[from]);\n        compute_bridges_for_day(to, assign, isBridgeDays[to]);\n    };\n\n    struct DSU {\n        vector<int> p, r; int comps;\n        DSU() {}\n        DSU(int n) { init(n); }\n        void init(int n) { p.resize(n); r.assign(n,0); iota(p.begin(), p.end(), 0); comps = n; }\n        int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n        bool unite(int a, int b){\n            a = find(a); b = find(b);\n            if (a == b) return false;\n            if (r[a] < r[b]) swap(a, b);\n            p[b] = a;\n            if (r[a] == r[b]) r[a]++;\n            comps--;\n            return true;\n        }\n    };\n\n    int maxPass = 4;\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool changedAny = false;\n        for (int d = 0; d < D; d++) {\n            vector<int> compId;\n            int compCount = 0;\n            compute_components_for_day(d, assign, compId, compCount);\n            if (compCount <= 1) continue;\n\n            // edges removed on day d connecting different components\n            vector<int> crossEdges;\n            for (int e : dayEdges[d]) {\n                int u = edges[e].u, v = edges[e].v;\n                if (compId[u] != compId[v]) crossEdges.push_back(e);\n            }\n            if (crossEdges.empty()) continue;\n\n            // Move heaviest cross edges first\n            sort(crossEdges.begin(), crossEdges.end(), [&](int a, int b){\n                if (heavy[a] != heavy[b]) return heavy[a] > heavy[b];\n                return a < b;\n            });\n\n            DSU dsu(compCount);\n            for (int e : crossEdges) {\n                int cu = dsu.find(compId[edges[e].u]);\n                int cv = dsu.find(compId[edges[e].v]);\n                if (cu == cv) continue;\n\n                // choose target day with capacity and preferably safe (no new disconnect)\n                int bestSafe = -1, bestAny = -1;\n                long double bestSafeDelta = 1e300L, bestAnyDelta = 1e300L;\n                for (int tday = 0; tday < D; tday++) {\n                    if (tday == d) continue;\n                    if (daySize[tday] >= K) continue;\n                    bool safe = !isBridgeDays[tday][e];\n                    long double delta = add_delta(e, tday); // removal from d only helps, ignore here\n                    if (safe) {\n                        if (delta < bestSafeDelta) { bestSafeDelta = delta; bestSafe = tday; }\n                    } else {\n                        if (delta < bestAnyDelta) { bestAnyDelta = delta; bestAny = tday; }\n                    }\n                }\n                int tday = (bestSafe != -1 ? bestSafe : bestAny);\n                if (tday == -1) continue; // no capacity; rare\n                moveEdge(e, d, tday);\n                dsu.unite(cu, cv);\n                changedAny = true;\n                if (dsu.comps == 1) break;\n            }\n        }\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - time_start).count();\n        if (elapsed > T_budget) break;\n        if (!changedAny) break;\n    }\n\n    // 8) Local search with connectivity-safe 1-move and swaps\n    auto computeObj = [&]() -> long double {\n        long double obj = 0;\n        for (int v = 0; v < N; v++) for (int d = 0; d < D; d++) {\n            long double s = (long double)PV[v][d];\n            obj += lamV * s * s;\n        }\n        for (int c = 0; c < nCells; c++) for (int d = 0; d < D; d++) {\n            long double s = (long double)PC[c][d];\n            obj += lamC * s * s;\n        }\n        for (int d = 0; d < D; d++) {\n            long double s = (long double)daySum[d];\n            obj += lamD * s * s;\n        }\n        return obj;\n    };\n    long double obj = computeObj();\n\n    auto applyMove = [&](int e, int dFrom, int dTo) {\n        int u = edges[e].u, v = edges[e].v;\n        int c = edgeCell[e];\n        double w = heavy[e];\n\n        // remove from dFrom\n        {\n            int p = posInDay[e];\n            int last = dayEdges[dFrom].back();\n            dayEdges[dFrom][p] = last;\n            posInDay[last] = p;\n            dayEdges[dFrom].pop_back();\n            daySize[dFrom]--;\n        }\n        // add to dTo\n        posInDay[e] = (int)dayEdges[dTo].size();\n        dayEdges[dTo].push_back(e);\n        daySize[dTo]++;\n\n        // update stats\n        cnt[u][dFrom]--; cnt[v][dFrom]--;\n        cnt[u][dTo]++; cnt[v][dTo]++;\n        PV[u][dFrom] -= w; PV[v][dFrom] -= w;\n        PV[u][dTo] += w; PV[v][dTo] += w;\n        PC[c][dFrom] -= w; PC[c][dTo] += w;\n        daySum[dFrom] -= w; daySum[dTo] += w;\n        assign[e] = dTo;\n\n        // update bridges for affected days\n        compute_bridges_for_day(dFrom, assign, isBridgeDays[dFrom]);\n        compute_bridges_for_day(dTo, assign, isBridgeDays[dTo]);\n    };\n\n    auto now = chrono::steady_clock::now();\n    double elapsed = chrono::duration<double>(now - time_start).count();\n    double time_left = T_budget - elapsed;\n    if (time_left > 0.10) {\n        mt19937 rng(1234567);\n        uniform_int_distribution<int> dayDist(0, D-1);\n        uniform_int_distribution<int> edgeDist(0, M-1);\n\n        int attemptsMove = 90000;\n        int attemptsSwap = 60000;\n\n        // 1-move attempts\n        for (int it = 0; it < attemptsMove; it++) {\n            if ((it & 1023) == 0) {\n                now = chrono::steady_clock::now();\n                elapsed = chrono::duration<double>(now - time_start).count();\n                if (elapsed > T_budget) break;\n            }\n            int e = edgeDist(rng);\n            int dFrom = assign[e];\n            if (dFrom < 0) continue;\n            // try a few candidate days\n            int bestTo = -1;\n            long double bestDelta = -1e-12L;\n            const int trials = min(D, 6);\n            for (int t = 0; t < trials; t++) {\n                int dTo = dayDist(rng);\n                if (dTo == dFrom) continue;\n                if (daySize[dTo] >= K) continue;\n                if (isBridgeDays[dTo][e]) continue; // would disconnect day dTo\n                long double delta = remove_delta(e, dFrom) + add_delta(e, dTo);\n                if (delta < bestDelta) {\n                    bestDelta = delta; bestTo = dTo;\n                }\n            }\n            if (bestTo != -1) {\n                applyMove(e, dFrom, bestTo);\n                obj += bestDelta;\n            }\n        }\n\n        // Swap attempts\n        for (int it = 0; it < attemptsSwap; it++) {\n            if ((it & 1023) == 0) {\n                now = chrono::steady_clock::now();\n                elapsed = chrono::duration<double>(now - time_start).count();\n                if (elapsed > T_budget) break;\n            }\n            int d1 = dayDist(rng), d2 = dayDist(rng);\n            if (d1 == d2) continue;\n            if (dayEdges[d1].empty() || dayEdges[d2].empty()) continue;\n\n            int e1 = dayEdges[d1][ (int)(rng() % dayEdges[d1].size()) ];\n            int e2 = dayEdges[d2][ (int)(rng() % dayEdges[d2].size()) ];\n            if (e1 == e2) continue;\n\n            // Connectivity-safe: ensure adding e1 to d2 and e2 to d1 won't disconnect those days\n            if (isBridgeDays[d2][e1]) continue;\n            if (isBridgeDays[d1][e2]) continue;\n\n            long double delta = remove_delta(e1, d1) + add_delta(e1, d2)\n                              + remove_delta(e2, d2) + add_delta(e2, d1);\n            if (delta < -1e-12L) {\n                // Apply as two moves for code reuse\n                applyMove(e1, d1, d2);\n                applyMove(e2, d2, d1);\n                obj += delta;\n            }\n        }\n    }\n\n    // Output (1-indexed days)\n    for (int i = 0; i < M; i++) {\n        if (i) cout << ' ';\n        cout << (assign[i] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Hopcroft-Karp for bipartite matching (left: 0..nL-1, right: 0..nR-1)\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> adj; // adj[u] -> list of right vertices\n    vector<int> dist, matchL, matchR;\n\n    HopcroftKarp(int nL=0, int nR=0): nL(nL), nR(nR), adj(nL) {}\n\n    void init(int _nL, int _nR) {\n        nL = _nL; nR = _nR;\n        adj.assign(nL, {});\n    }\n\n    void addEdge(int u, int v) {\n        adj[u].push_back(v);\n    }\n\n    bool bfs() {\n        dist.assign(nL, -1);\n        queue<int> q;\n        for (int u = 0; u < nL; ++u) {\n            if (matchL[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        bool found = false;\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : adj[u]) {\n                int w = matchR[v];\n                if (w >= 0) {\n                    if (dist[w] < 0) {\n                        dist[w] = dist[u] + 1;\n                        q.push(w);\n                    }\n                } else {\n                    found = true;\n                }\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for (int v : adj[u]) {\n            int w = matchR[v];\n            if (w < 0 || (dist[w] == dist[u] + 1 && dfs(w))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int maxMatching(vector<int>* outMatchL = nullptr, vector<int>* outMatchR = nullptr) {\n        matchL.assign(nL, -1);\n        matchR.assign(nR, -1);\n        int matching = 0;\n        while (bfs()) {\n            for (int u = 0; u < nL; ++u) {\n                if (matchL[u] == -1) {\n                    if (dfs(u)) matching++;\n                }\n            }\n        }\n        if (outMatchL) *outMatchL = matchL;\n        if (outMatchR) *outMatchR = matchR;\n        return matching;\n    }\n};\n\nstatic inline int idx3(int D, int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\nstruct Arrangement {\n    int D;\n    vector<char> present; // size D^3\n    long long volume = 0;\n};\n\nstruct Run {\n    int x, y, z0, len;\n    int off; // how many voxels consumed from the start\n};\n\n// Build arrangement with vertical preservation using matching,\n// minimal per-layer occupancy and some randomness to diversify.\nArrangement build_arrangement(const vector<string>& fz, const vector<string>& rz, int D, uint32_t seed) {\n    Arrangement arr;\n    arr.D = D;\n    int N = D * D * D;\n    arr.present.assign(N, 0);\n\n    // Precompute per-layer A (xs) and B (ys)\n    vector<vector<int>> Ax(D), By(D);\n    for (int z = 0; z < D; ++z) {\n        for (int x = 0; x < D; ++x) if (fz[z][x] == '1') Ax[z].push_back(x);\n        for (int y = 0; y < D; ++y) if (rz[z][y] == '1') By[z].push_back(y);\n    }\n\n    // RNG\n    uint32_t rng_state = seed ? seed : 123456789u;\n    auto rng = [&]() -> uint32_t {\n        rng_state ^= rng_state << 13;\n        rng_state ^= rng_state >> 17;\n        rng_state ^= rng_state << 5;\n        return rng_state;\n    };\n\n    vector<vector<char>> prevOcc(D, vector<char>(D, 0));\n    for (int z = 0; z < D; ++z) {\n        auto& A = Ax[z];\n        auto& B = By[z];\n        int Nx = (int)A.size();\n        int Ny = (int)B.size();\n        // xId/yId if needed\n        if (Nx >= Ny) {\n            // x-dominant: assign y to each x, cover all y\n            // Stage 1: preserve prev columns using matching y->x\n            HopcroftKarp hk(Ny, Nx);\n            for (int j = 0; j < Ny; ++j) {\n                int y = B[j];\n                for (int i = 0; i < Nx; ++i) {\n                    int x = A[i];\n                    if (prevOcc[x][y]) hk.addEdge(j, i);\n                }\n            }\n            vector<int> matchY, matchX;\n            hk.maxMatching(&matchY, &matchX);\n\n            vector<int> xToY(Nx, -1);\n            vector<int> loadY(Ny, 0);\n            vector<char> usedX(Nx, 0), yCovered(Ny, 0);\n            for (int j = 0; j < Ny; ++j) if (matchY[j] != -1) {\n                xToY[matchY[j]] = j;\n                usedX[matchY[j]] = 1;\n                yCovered[j] = 1;\n                loadY[j]++;\n            }\n            // Pref counts for x\n            vector<int> prefCountX(Nx, 0);\n            for (int i = 0; i < Nx; ++i) {\n                int x = A[i];\n                int cnt = 0;\n                for (int j = 0; j < Ny; ++j) if (prevOcc[x][B[j]]) cnt++;\n                prefCountX[i] = cnt;\n            }\n            // Cover remaining y\n            for (int j = 0; j < Ny; ++j) if (!yCovered[j]) {\n                int pick_i = -1;\n                int bestScore = INT_MAX;\n                for (int i = 0; i < Nx; ++i) if (!usedX[i]) {\n                    int score = prefCountX[i] * 10 + (int)(rng() & 7u);\n                    if (score < bestScore) { bestScore = score; pick_i = i; }\n                }\n                if (pick_i == -1) {\n                    for (int i = 0; i < Nx; ++i) if (xToY[i] != -1) { pick_i = i; break; }\n                }\n                if (pick_i == -1) pick_i = 0;\n                xToY[pick_i] = j;\n                usedX[pick_i] = 1;\n                yCovered[j] = 1;\n                loadY[j]++;\n            }\n            // Stage 2: assign remaining x\n            vector<vector<int>> xsPerY(Ny);\n            for (int i = 0; i < Nx; ++i) if (xToY[i] != -1) xsPerY[xToY[i]].push_back(i);\n            for (int i = 0; i < Nx; ++i) if (!usedX[i]) {\n                int x = A[i];\n                int bestY = 0;\n                int bestScore = -1e9;\n                for (int j = 0; j < Ny; ++j) {\n                    int y = B[j];\n                    int sc = 0;\n                    if (prevOcc[x][y]) sc += 100;\n                    for (int xi : xsPerY[j]) {\n                        if (abs(A[xi] - x) == 1) { sc += 10; break; }\n                    }\n                    sc -= loadY[j];\n                    sc += (int)(rng() & 3u);\n                    if (sc > bestScore) { bestScore = sc; bestY = j; }\n                }\n                xToY[i] = bestY;\n                loadY[bestY]++;\n                xsPerY[bestY].push_back(i);\n            }\n            // Emit cells\n            for (int i = 0; i < Nx; ++i) {\n                int x = A[i];\n                int y = B[xToY[i]];\n                arr.present[idx3(D, x, y, z)] = 1;\n                arr.volume++;\n            }\n        } else {\n            // y-dominant: assign x to each y, cover all x\n            HopcroftKarp hk(Nx, Ny); // left X, right Y\n            for (int i = 0; i < Nx; ++i) {\n                int x = A[i];\n                for (int j = 0; j < Ny; ++j) {\n                    int y = B[j];\n                    if (prevOcc[x][y]) hk.addEdge(i, j);\n                }\n            }\n            vector<int> matchX, matchY;\n            hk.maxMatching(&matchX, &matchY);\n\n            vector<int> yToX(Ny, -1);\n            vector<char> usedY(Ny, 0);\n            vector<int> loadX(Nx, 0);\n            vector<vector<int>> ysPerX(Nx);\n\n            for (int i = 0; i < Nx; ++i) if (matchX[i] != -1) {\n                int j = matchX[i];\n                yToX[j] = i;\n                usedY[j] = 1;\n                loadX[i]++;\n                ysPerX[i].push_back(j);\n            }\n            vector<int> prefCountY(Ny, 0);\n            for (int j = 0; j < Ny; ++j) {\n                int y = B[j];\n                int cnt = 0;\n                for (int i = 0; i < Nx; ++i) if (prevOcc[A[i]][y]) cnt++;\n                prefCountY[j] = cnt;\n            }\n            // Cover unmatched x\n            for (int i = 0; i < Nx; ++i) if (matchX[i] == -1) {\n                int pick_j = -1;\n                int bestScore = INT_MAX;\n                for (int j = 0; j < Ny; ++j) if (!usedY[j]) {\n                    int score = prefCountY[j] * 10 + (int)(rng() & 7u);\n                    if (score < bestScore) { bestScore = score; pick_j = j; }\n                }\n                if (pick_j == -1) {\n                    for (int j = 0; j < Ny; ++j) if (!usedY[j]) { pick_j = j; break; }\n                    if (pick_j == -1) pick_j = 0;\n                }\n                yToX[pick_j] = i;\n                usedY[pick_j] = 1;\n                loadX[i]++;\n                ysPerX[i].push_back(pick_j);\n            }\n            // Assign remaining y\n            for (int j = 0; j < Ny; ++j) if (!usedY[j]) {\n                int y = B[j];\n                int bestX = 0;\n                int bestScore = -1e9;\n                for (int i = 0; i < Nx; ++i) {\n                    int x = A[i];\n                    int sc = 0;\n                    if (prevOcc[x][y]) sc += 100;\n                    for (int yj : ysPerX[i]) {\n                        if (abs(B[yj] - y) == 1) { sc += 10; break; }\n                    }\n                    sc -= loadX[i];\n                    sc += (int)(rng() & 3u);\n                    if (sc > bestScore) { bestScore = sc; bestX = i; }\n                }\n                yToX[j] = bestX;\n                usedY[j] = 1;\n                loadX[bestX]++;\n                ysPerX[bestX].push_back(j);\n            }\n            // Emit cells\n            for (int j = 0; j < Ny; ++j) {\n                int i = yToX[j];\n                int x = A[i], y = B[j];\n                arr.present[idx3(D, x, y, z)] = 1;\n                arr.volume++;\n            }\n        }\n\n        // Update prevOcc for next layer\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) prevOcc[x][y] = 0;\n        for (int x = 0; x < D; ++x) {\n            for (int y = 0; y < D; ++y) {\n                int p = idx3(D, x, y, z);\n                if (arr.present[p]) prevOcc[x][y] = 1;\n            }\n        }\n    }\n    return arr;\n}\n\nstatic vector<Run> extract_runs(const Arrangement& arr) {\n    int D = arr.D;\n    vector<Run> runs;\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            int z = 0;\n            while (z < D) {\n                while (z < D) {\n                    int p = idx3(D, x, y, z);\n                    if (arr.present[p]) break;\n                    ++z;\n                }\n                if (z >= D) break;\n                int z0 = z;\n                while (z < D) {\n                    int p = idx3(D, x, y, z);\n                    if (!arr.present[p]) break;\n                    ++z;\n                }\n                int len = z - z0;\n                if (len > 0) runs.push_back({x, y, z0, len, 0});\n            }\n        }\n    }\n    return runs;\n}\n\nstruct PairingScore {\n    double penalty;\n    long long sharedVolume;\n};\n\n// Compute greedy pairing score only (no assignment), pairing longest runs first\nstatic PairingScore evaluate_pairing(const vector<Run>& r1, const vector<Run>& r2) {\n    struct Node { int len; int id; };\n    struct Cmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.len != b.len) return a.len < b.len; // max-heap\n            return a.id > b.id;\n        }\n    };\n    priority_queue<Node, vector<Node>, Cmp> pq1, pq2;\n    int n1 = (int)r1.size(), n2 = (int)r2.size();\n    vector<int> rem1(n1), rem2(n2);\n    long long V1 = 0, V2 = 0;\n    for (int i = 0; i < n1; ++i) { rem1[i] = r1[i].len; V1 += r1[i].len; if (rem1[i] > 0) pq1.push({rem1[i], i}); }\n    for (int i = 0; i < n2; ++i) { rem2[i] = r2[i].len; V2 += r2[i].len; if (rem2[i] > 0) pq2.push({rem2[i], i}); }\n    double penalty = 0;\n    long long shared = 0;\n    while (!pq1.empty() && !pq2.empty()) {\n        auto a = pq1.top(); pq1.pop();\n        auto b = pq2.top(); pq2.pop();\n        int L = min(a.len, b.len);\n        penalty += 1.0 / (double)L;\n        shared += L;\n        a.len -= L;\n        b.len -= L;\n        if (a.len > 0) pq1.push(a);\n        if (b.len > 0) pq2.push(b);\n    }\n    // In principle, shared should equal min(V1, V2)\n    return {penalty, shared};\n}\n\n// Assign shared and arrangement-only sticks using the same greedy pairing\nstatic void assign_blocks_from_runs(\n    const vector<Run>& r1, const vector<Run>& r2,\n    int D, vector<int>& b1, vector<int>& b2, int& nblocks\n) {\n    struct Node { int len; int id; };\n    struct Cmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.len != b.len) return a.len < b.len; // max-heap\n            return a.id > b.id;\n        }\n    };\n    priority_queue<Node, vector<Node>, Cmp> pq1, pq2;\n    int n1 = (int)r1.size(), n2 = (int)r2.size();\n    vector<int> rem1(n1), rem2(n2);\n    vector<int> off1(n1), off2(n2);\n    for (int i = 0; i < n1; ++i) { rem1[i] = r1[i].len; off1[i] = 0; if (rem1[i] > 0) pq1.push({rem1[i], i}); }\n    for (int i = 0; i < n2; ++i) { rem2[i] = r2[i].len; off2[i] = 0; if (rem2[i] > 0) pq2.push({rem2[i], i}); }\n\n    // Shared sticks first\n    while (!pq1.empty() && !pq2.empty()) {\n        auto a = pq1.top(); pq1.pop();\n        auto b = pq2.top(); pq2.pop();\n        int i = a.id, j = b.id;\n        int L = min(rem1[i], rem2[j]);\n        int id = ++nblocks;\n        // assign in b1\n        for (int t = 0; t < L; ++t) {\n            int z = r1[i].z0 + off1[i] + t;\n            int p = idx3(D, r1[i].x, r1[i].y, z);\n            b1[p] = id;\n        }\n        // assign in b2\n        for (int t = 0; t < L; ++t) {\n            int z = r2[j].z0 + off2[j] + t;\n            int p = idx3(D, r2[j].x, r2[j].y, z);\n            b2[p] = id;\n        }\n        rem1[i] -= L; off1[i] += L;\n        rem2[j] -= L; off2[j] += L;\n        if (rem1[i] > 0) pq1.push({rem1[i], i});\n        if (rem2[j] > 0) pq2.push({rem2[j], j});\n    }\n\n    // Remaining arrangement-only sticks in A1\n    for (int i = 0; i < n1; ++i) if (rem1[i] > 0) {\n        int id = ++nblocks;\n        for (int t = 0; t < rem1[i]; ++t) {\n            int z = r1[i].z0 + off1[i] + t;\n            int p = idx3(D, r1[i].x, r1[i].y, z);\n            b1[p] = id;\n        }\n    }\n    // Remaining arrangement-only sticks in A2\n    for (int j = 0; j < n2; ++j) if (rem2[j] > 0) {\n        int id = ++nblocks;\n        for (int t = 0; t < rem2[j]; ++t) {\n            int z = r2[j].z0 + off2[j] + t;\n            int p = idx3(D, r2[j].x, r2[j].y, z);\n            b2[p] = id;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    if (!(cin >> D)) return 0;\n    vector<string> f[2], r[2];\n    for (int t = 0; t < 2; ++t) {\n        f[t].resize(D);\n        for (int i = 0; i < D; ++i) cin >> f[t][i];\n        r[t].resize(D);\n        for (int i = 0; i < D; ++i) cin >> r[t][i];\n    }\n\n    // Iterative improvement with small time budget\n    auto start = chrono::steady_clock::now();\n    const double timeLimit = 1.6; // seconds, keep margin\n    double elapsed = 0.0;\n\n    Arrangement bestA1, bestA2;\n    vector<Run> bestRuns1, bestRuns2;\n    double bestScore = 1e100;\n\n    uint32_t baseSeed = 146527u;\n\n    int iter = 0;\n    while (true) {\n        uint32_t seed1 = baseSeed + 10007u * (iter + 1);\n        uint32_t seed2 = baseSeed ^ (0x9E3779B9u * (iter + 137));\n        Arrangement A1 = build_arrangement(f[0], r[0], D, seed1);\n        Arrangement A2 = build_arrangement(f[1], r[1], D, seed2);\n        auto runs1 = extract_runs(A1);\n        auto runs2 = extract_runs(A2);\n        auto ps = evaluate_pairing(runs1, runs2);\n        // Total absolute-ish score proxy: |V1 - V2| + penalty\n        double score = (double)llabs(A1.volume - A2.volume) + ps.penalty;\n\n        if (score < bestScore) {\n            bestScore = score;\n            bestA1 = move(A1);\n            bestA2 = move(A2);\n            bestRuns1 = move(runs1);\n            bestRuns2 = move(runs2);\n        }\n\n        ++iter;\n        if ((iter & 7) == 0) {\n            auto now = chrono::steady_clock::now();\n            elapsed = chrono::duration<double>(now - start).count();\n            if (elapsed > timeLimit) break;\n        }\n        // Limit iterations to avoid too many on small inputs\n        if (iter > 4000) break;\n    }\n\n    // Final assignment\n    int N = D * D * D;\n    vector<int> b1(N, 0), b2(N, 0);\n    int nblocks = 0;\n    assign_blocks_from_runs(bestRuns1, bestRuns2, D, b1, b2, nblocks);\n\n    // Safety: ensure every occupied cell is assigned\n    // (not strictly necessary, but good to be safe)\n    // If any present cell remains zero, assign as unit block.\n    for (int p = 0; p < N; ++p) {\n        if (bestA1.present[p] && b1[p] == 0) {\n            int id = ++nblocks;\n            b1[p] = id;\n        }\n    }\n    for (int p = 0; p < N; ++p) {\n        if (bestA2.present[p] && b2[p] == 0) {\n            int id = ++nblocks;\n            b2[p] = id;\n        }\n    }\n\n    cout << nblocks << \"\\n\";\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            for (int z = 0; z < D; ++z) {\n                int p = idx3(D, x, y, z);\n                cout << b1[p] << ( (x==D-1 && y==D-1 && z==D-1) ? '\\n' : ' ' );\n            }\n        }\n    }\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            for (int z = 0; z < D; ++z) {\n                int p = idx3(D, x, y, z);\n                cout << b2[p] << ( (x==D-1 && y==D-1 && z==D-1) ? '\\n' : ' ' );\n            }\n        }\n    }\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge { int u, v; long long w; };\n\nstruct Solution {\n    vector<int> P;           // size N\n    vector<char> edgeOn;     // size M\n    long long edgeSum = 0;\n    long long pSum = 0;\n    long long S = (1LL<<62);\n};\n\nstatic inline int sqrt_ceil_ll(long long x) {\n    if (x <= 0) return 0;\n    long double dx = (long double)x;\n    long long r = (long long)floor(sqrt(dx) + 1e-12L);\n    while ((r+1) * (r+1) <= x) ++r;\n    while (r * r > x) --r;\n    if (r * r == x) return (int)r;\n    return (int)(r + 1);\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, r;\n    DSU(int n=0):n(n),p(n),r(n,0){ iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n    bool unite(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, M, K;\n    if(!(cin>>N>>M>>K)) return 0;\n    vector<long long> xs(N), ys(N);\n    for(int i=0;i<N;i++){ cin>>xs[i]>>ys[i]; }\n    vector<Edge> edges(M);\n    for(int j=0;j<M;j++){\n        int u,v; long long w;\n        cin>>u>>v>>w; --u; --v;\n        edges[j] = {u,v,w};\n    }\n    vector<long long> ax(K), ay(K);\n    for(int k=0;k<K;k++){ cin>>ax[k]>>ay[k]; }\n\n    // build adjacency\n    vector<vector<pair<int,int>>> adj(N);\n    for(int e=0;e<M;e++){\n        int u=edges[e].u, v=edges[e].v;\n        adj[u].push_back({v,e});\n        adj[v].push_back({u,e});\n    }\n\n    // Precompute squared distances station-resident and coverage sets\n    const long long R2 = 5000LL*5000LL;\n    vector<vector<int>> covList(N);\n    vector<vector<uint64_t>> covBits(N);\n    int B = (K + 63) >> 6;\n    uint64_t lastMask = (K%64 == 0) ? ~0ULL : ((1ULL << (K%64)) - 1ULL);\n    vector<vector<int>> d2sr(N, vector<int>(K, 0));\n    // reverse mapping: for each resident, list of stations within 5000\n    vector<vector<int>> nearStationsForResid(K);\n    for(int i=0;i<N;i++){\n        covBits[i].assign(B, 0ULL);\n        for(int k=0;k<K;k++){\n            long long dx = xs[i] - ax[k];\n            long long dy = ys[i] - ay[k];\n            long long d2 = dx*dx + dy*dy;\n            if (d2 > INT_MAX) d2 = INT_MAX; // clamp to int\n            d2sr[i][k] = (int)d2;\n            if(d2 <= R2){\n                covList[i].push_back(k);\n                nearStationsForResid[k].push_back(i);\n                int blk = k >> 6, off = k & 63;\n                covBits[i][blk] |= (1ULL << off);\n            }\n        }\n    }\n\n    // All-pairs shortest paths (weight) with parents to reconstruct paths\n    const long long INF = (1LL<<60);\n    vector<vector<long long>> distW(N, vector<long long>(N, INF));\n    vector<vector<int>> prevV(N, vector<int>(N, -1));\n    vector<vector<int>> prevE(N, vector<int>(N, -1));\n    auto dijkstra_from = [&](int s){\n        auto &d = distW[s];\n        auto &pv = prevV[s];\n        auto &pe = prevE[s];\n        fill(d.begin(), d.end(), INF);\n        fill(pv.begin(), pv.end(), -1);\n        fill(pe.begin(), pe.end(), -1);\n        d[s] = 0;\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        pq.push({0, s});\n        while(!pq.empty()){\n            auto [cd,u] = pq.top(); pq.pop();\n            if(cd != d[u]) continue;\n            for(auto [v,eid] : adj[u]){\n                long long nd = cd + edges[eid].w;\n                if(nd < d[v]){\n                    d[v] = nd;\n                    pv[v] = u;\n                    pe[v] = eid;\n                    pq.push({nd, v});\n                }\n            }\n        }\n    };\n    for(int i=0;i<N;i++) dijkstra_from(i);\n\n    // SPT from root 0\n    vector<int> parentSPT(N, -1);\n    vector<int> parentEdgeSPT(N, -1);\n    for(int v=0; v<N; v++){\n        parentSPT[v] = prevV[0][v];\n        parentEdgeSPT[v] = prevE[0][v];\n    }\n\n    auto build_inV = [&](const vector<char>& edgeOn)->vector<char>{\n        vector<char> inV(N, 0);\n        queue<int> q;\n        inV[0] = 1; q.push(0);\n        while(!q.empty()){\n            int u=q.front(); q.pop();\n            for(auto [v,eid]: adj[u]){\n                if(edgeOn[eid] && !inV[v]){\n                    inV[v]=1; q.push(v);\n                }\n            }\n        }\n        return inV;\n    };\n\n    auto count_covered_bits = [&](const vector<char>& inV)->int{\n        vector<uint64_t> uni(B, 0ULL);\n        for(int i=0;i<N;i++){\n            if(!inV[i]) continue;\n            for(int b=0;b<B;b++) uni[b] |= covBits[i][b];\n        }\n        long long cnt = 0;\n        for(int b=0;b<B;b++){\n            uint64_t mask = (b==B-1 ? lastMask : ~0ULL);\n            cnt += __builtin_popcountll(uni[b] & mask);\n        }\n        return (int)cnt;\n    };\n\n    auto prune_unused_leaves = [&](vector<char>& edgeOn, const vector<int>& P){\n        vector<vector<int>> inc(N);\n        for(int e=0;e<M;e++){\n            if(edgeOn[e]){\n                int u=edges[e].u, v=edges[e].v;\n                inc[u].push_back(e);\n                inc[v].push_back(e);\n            }\n        }\n        vector<int> deg(N,0);\n        for(int i=0;i<N;i++){\n            for(int e: inc[i]) if(edgeOn[e]) deg[i]++;\n        }\n        deque<int> dq;\n        for(int i=0;i<N;i++){\n            if(i==0) continue;\n            if(deg[i]==1 && P[i]==0) dq.push_back(i);\n        }\n        vector<char> rm(N,0);\n        while(!dq.empty()){\n            int v = dq.front(); dq.pop_front();\n            if(rm[v]) continue;\n            if(deg[v]!=1 || P[v]!=0) continue;\n            int euniq=-1, u=-1;\n            for(int eid: inc[v]){\n                if(edgeOn[eid]){\n                    euniq=eid;\n                    u = (edges[eid].u==v? edges[eid].v : edges[eid].u);\n                    break;\n                }\n            }\n            if(euniq==-1) continue;\n            edgeOn[euniq]=0;\n            deg[v]--; deg[u]--;\n            rm[v]=1;\n            if(u!=0 && deg[u]==1 && P[u]==0) dq.push_back(u);\n        }\n    };\n\n    struct FastEval {\n        vector<char> inV;\n        vector<int> bestTo;   // size K\n        vector<int> bestD2;   // size K\n        vector<int> P;\n        long long pSum=0, edgeSum=0, S=0;\n        bool allCovered=false;\n    };\n\n    auto fast_evaluate = [&](const vector<char>& edgeOn){\n        FastEval fe;\n        fe.edgeSum = 0;\n        for(int e=0;e<M;e++) if(edgeOn[e]) fe.edgeSum += edges[e].w;\n        fe.inV = build_inV(edgeOn);\n        int covered = count_covered_bits(fe.inV);\n        fe.allCovered = (covered == K);\n        // Assign nearest reachable station\n        fe.bestTo.assign(K, -1);\n        fe.bestD2.assign(K, INT_MAX);\n        for(int k=0;k<K;k++){\n            int besti=-1, bestd2 = INT_MAX;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                int d2 = d2sr[i][k];\n                if(d2 < bestd2){\n                    bestd2 = d2; besti = i;\n                }\n            }\n            fe.bestTo[k] = besti;\n            fe.bestD2[k] = bestd2;\n        }\n        vector<long long> maxD2(N, 0);\n        for(int k=0;k<K;k++){\n            int i = fe.bestTo[k];\n            if(i<0) continue;\n            long long d2 = fe.bestD2[k];\n            if(d2 > maxD2[i]) maxD2[i] = d2;\n        }\n        fe.P.assign(N, 0);\n        fe.pSum = 0;\n        for(int i=0;i<N;i++){\n            if(!fe.inV[i]) { fe.P[i]=0; continue; }\n            int rad = sqrt_ceil_ll(maxD2[i]);\n            if(rad>5000) rad=5000; // clamp\n            fe.P[i]=rad;\n            fe.pSum += 1LL*rad*rad;\n        }\n        fe.S = fe.edgeSum + fe.pSum;\n        return fe;\n    };\n\n    struct FullEval {\n        Solution sol;\n        vector<char> inV;\n        vector<int> assignTo; // K -> i\n    };\n\n    auto optimize_assignment = [&](const vector<char>& edgeOn){\n        FullEval fe;\n        fe.inV = build_inV(edgeOn);\n        // nearest assignment\n        fe.assignTo.assign(K, -1);\n        vector<vector<int>> assigned(N);\n        vector<multiset<int>> dsets(N);\n        vector<long long> maxD2(N, 0);\n        for(int k=0;k<K;k++){\n            int besti=-1, bestd2=INT_MAX;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                int d2 = d2sr[i][k];\n                if(d2 < bestd2){ bestd2=d2; besti=i; }\n            }\n            fe.assignTo[k]=besti;\n            if(besti>=0){\n                assigned[besti].push_back(k);\n                dsets[besti].insert(bestd2);\n                if(bestd2 > maxD2[besti]) maxD2[besti] = bestd2;\n            }\n        }\n        vector<int> P(N,0);\n        vector<int> rad2(N,0);\n        for(int i=0;i<N;i++){\n            if(!fe.inV[i]) { P[i]=0; rad2[i]=0; continue; }\n            int rad = sqrt_ceil_ll(maxD2[i]);\n            if(rad>5000) rad=5000;\n            P[i]=rad;\n            rad2[i]=rad*rad;\n        }\n\n        auto recompute_max_after_removal = [&](int i, int d2val)->long long{\n            if(dsets[i].empty()) return 0;\n            auto it = dsets[i].find(d2val);\n            if(it == dsets[i].end()){\n                return (long long)(*dsets[i].rbegin());\n            }\n            dsets[i].erase(it);\n            long long res = dsets[i].empty() ? 0 : (long long)(*dsets[i].rbegin());\n            dsets[i].insert(d2val);\n            return res;\n        };\n\n        // Step A: move unique farthest to a station that already covers it\n        bool changedA = true;\n        int guardA = 0;\n        while(changedA && guardA < 2*N){\n            changedA = false; guardA++;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                if(dsets[i].empty()) continue;\n                int dmax = *prev(dsets[i].end());\n                int cntMax = (int)dsets[i].count(dmax);\n                if(cntMax != 1) continue;\n                // find a resident r having d2 == dmax\n                int r = -1;\n                for(int idx : assigned[i]){\n                    if(d2sr[i][idx] == dmax){ r = idx; break; }\n                }\n                if(r==-1) continue;\n                // find j in near stations that already covers r\n                int jbest = -1;\n                for(int j : nearStationsForResid[r]){\n                    if(!fe.inV[j] || j==i) continue;\n                    if(rad2[j] >= d2sr[j][r]){ jbest = j; break; }\n                }\n                if(jbest==-1) continue;\n                // move r i -> jbest\n                dsets[i].erase(dsets[i].find(dmax));\n                auto itv = find(assigned[i].begin(), assigned[i].end(), r);\n                if(itv != assigned[i].end()) assigned[i].erase(itv);\n                assigned[jbest].push_back(r);\n                dsets[jbest].insert(d2sr[jbest][r]);\n                fe.assignTo[r] = jbest;\n                // update i's P\n                long long newMaxI = dsets[i].empty() ? 0 : (long long)(*dsets[i].rbegin());\n                int newPi = sqrt_ceil_ll(newMaxI); if(newPi>5000) newPi=5000;\n                P[i] = newPi; rad2[i] = newPi*newPi;\n                changedA = true;\n            }\n        }\n\n        // Step B: move an outlier to reduce total pSum (within 5000 only)\n        bool improved = true;\n        int iter = 0;\n        while(improved && iter < 300){\n            improved = false; iter++;\n            long long bestDelta = 0;\n            int bi=-1, bj=-1, br=-1;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                if(dsets[i].empty()) continue;\n                int dmax = *prev(dsets[i].end());\n                // find one r with dmax\n                int r = -1;\n                for(int idx : assigned[i]){\n                    if(d2sr[i][idx] == dmax){ r = idx; break; }\n                }\n                if(r==-1) continue;\n                // compute new rad2 for i after removing r\n                long long newMaxI_d2 = recompute_max_after_removal(i, dmax);\n                int newPi = sqrt_ceil_ll(newMaxI_d2); if(newPi>5000) newPi=5000;\n                int newPi_sq = newPi*newPi;\n                int curPi_sq = rad2[i];\n                // try all j within 5000 for resident r\n                for(int j : nearStationsForResid[r]){\n                    if(!fe.inV[j] || j==i) continue;\n                    long long curMaxJ_d2 = dsets[j].empty() ? 0 : (long long)(*dsets[j].rbegin());\n                    long long newMaxJ_d2 = max(curMaxJ_d2, (long long)d2sr[j][r]);\n                    int newPj = sqrt_ceil_ll(newMaxJ_d2);\n                    if(newPj>5000) newPj=5000;\n                    int newPj_sq = newPj*newPj;\n                    long long curPj_sq = rad2[j];\n                    long long delta = (long long)newPi_sq + newPj_sq - curPi_sq - curPj_sq;\n                    if(delta < bestDelta){\n                        bestDelta = delta;\n                        bi = i; bj = j; br = r;\n                    }\n                }\n            }\n            if(bestDelta < 0 && bi>=0){\n                // apply move\n                int i = bi, j = bj, r = br;\n                int dmax = d2sr[i][r];\n                // remove from i\n                auto itf = dsets[i].find(dmax);\n                if(itf != dsets[i].end()) dsets[i].erase(itf);\n                auto itv = find(assigned[i].begin(), assigned[i].end(), r);\n                if(itv != assigned[i].end()) assigned[i].erase(itv);\n                // add to j\n                dsets[j].insert(d2sr[j][r]);\n                assigned[j].push_back(r);\n                fe.assignTo[r] = j;\n                // update rad2 both\n                long long newMaxI_d2 = dsets[i].empty() ? 0 : (long long)(*dsets[i].rbegin());\n                int newPi2 = sqrt_ceil_ll(newMaxI_d2); if(newPi2>5000) newPi2=5000;\n                P[i] = newPi2; rad2[i] = newPi2*newPi2;\n\n                long long newMaxJ_d2 = (long long)(*dsets[j].rbegin());\n                int newPj2 = sqrt_ceil_ll(newMaxJ_d2); if(newPj2>5000) newPj2=5000;\n                P[j] = newPj2; rad2[j] = newPj2*newPj2;\n\n                improved = true;\n            }\n        }\n\n        // finalize costs\n        long long pSum = 0;\n        for(int i=0;i<N;i++) pSum += 1LL*P[i]*P[i];\n        long long edgeSum = 0;\n        for(int e=0;e<M;e++) if(edgeOn[e]) edgeSum += edges[e].w;\n        fe.sol.P = P;\n        fe.sol.edgeOn = edgeOn;\n        fe.sol.pSum = pSum;\n        fe.sol.edgeSum = edgeSum;\n        fe.sol.S = pSum + edgeSum;\n        return fe;\n    };\n\n    auto start = chrono::steady_clock::now();\n    auto time_ms = [&](){\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count();\n    };\n\n    // Steinerization: build metric MST connecting terminals and re-optimize P\n    auto build_tree_for_terminals = [&](const vector<int>& T)->vector<char>{\n        int TS = (int)T.size();\n        if(TS <= 1){\n            return vector<char>(M, 0);\n        }\n        // Prim on metric closure\n        vector<char> used(TS,0);\n        vector<long long> low(TS, INF);\n        vector<int> par(TS,-1);\n        used[0]=1;\n        for(int i=1;i<TS;i++){ low[i]=distW[T[0]][T[i]]; par[i]=0; }\n        vector<pair<int,int>> mstPairs; mstPairs.reserve(TS-1);\n        for(int it=0; it<TS-1; it++){\n            int v=-1; long long best=INF;\n            for(int j=0;j<TS;j++){\n                if(!used[j] && low[j] < best){\n                    best=low[j]; v=j;\n                }\n            }\n            if(v==-1) break;\n            used[v]=1;\n            mstPairs.emplace_back(T[par[v]], T[v]);\n            for(int j=0;j<TS;j++){\n                if(!used[j]){\n                    long long nd = distW[T[v]][T[j]];\n                    if(nd < low[j]){ low[j]=nd; par[j]=v; }\n                }\n            }\n        }\n        // Union of shortest paths for pairs\n        vector<char> edgeOn(M, 0);\n        for(auto [u,v] : mstPairs){\n            int cur = v;\n            while(cur != u){\n                int eid = prevE[u][cur];\n                if(eid<0) break;\n                edgeOn[eid]=1;\n                cur = prevV[u][cur];\n                if(cur<0) break;\n            }\n        }\n        // Reduce within union by Kruskal\n        vector<int> unionEdges;\n        for(int e=0;e<M;e++) if(edgeOn[e]) unionEdges.push_back(e);\n        sort(unionEdges.begin(), unionEdges.end(), [&](int a,int b){ return edges[a].w < edges[b].w; });\n        DSU dsu(N);\n        vector<char> edgeOn2(M,0);\n        for(int e: unionEdges){\n            int u=edges[e].u, v=edges[e].v;\n            if(dsu.unite(u,v)) edgeOn2[e]=1;\n        }\n        // prune non-terminal leaves\n        vector<char> isTerm(N,0);\n        for(int v: T) isTerm[v]=1;\n        vector<vector<int>> inc(N);\n        for(int e=0;e<M;e++){\n            if(!edgeOn2[e]) continue;\n            int u=edges[e].u, v=edges[e].v;\n            inc[u].push_back(e);\n            inc[v].push_back(e);\n        }\n        vector<int> deg(N,0);\n        for(int i=0;i<N;i++){\n            for(int e: inc[i]) if(edgeOn2[e]) deg[i]++;\n        }\n        deque<int> dq;\n        for(int i=0;i<N;i++) if(deg[i]==1 && !isTerm[i]) dq.push_back(i);\n        vector<char> rm(N,0);\n        while(!dq.empty()){\n            int v=dq.front(); dq.pop_front();\n            if(rm[v]) continue;\n            if(deg[v]!=1 || isTerm[v]) continue;\n            int euniq=-1, u=-1;\n            for(int eid: inc[v]) if(edgeOn2[eid]){ euniq=eid; u=(edges[eid].u==v? edges[eid].v : edges[eid].u); break; }\n            if(euniq==-1) continue;\n            edgeOn2[euniq]=0; deg[v]--; deg[u]--; rm[v]=1;\n            if(deg[u]==1 && !isTerm[u]) dq.push_back(u);\n        }\n        return edgeOn2;\n    };\n\n    auto steinerize_from_P = [&](const Solution& sol)->Solution{\n        vector<int> T;\n        T.push_back(0);\n        for(int i=0;i<N;i++) if(sol.P[i] > 0 && i!=0) T.push_back(i);\n        vector<char> edgeOn = build_tree_for_terminals(T);\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    // Build solution 1: Set cover + metric MST\n    auto build_solution_setcover = [&](){\n        vector<char> selected(N, 0);\n        vector<char> uncovered(K, 1);\n        int remaining = K;\n        vector<long long> dRoot(N);\n        for(int i=0;i<N;i++) dRoot[i] = distW[0][i];\n\n        while(remaining > 0){\n            int besti = -1, bestc = -1;\n            long long tieRoot = (1LL<<60);\n            for(int i=0;i<N;i++){\n                if(selected[i]) continue;\n                int cnt = 0;\n                for(int k: covList[i]) if(uncovered[k]) cnt++;\n                if(cnt > bestc || (cnt==bestc && dRoot[i] < tieRoot)){\n                    bestc = cnt; tieRoot = dRoot[i]; besti = i;\n                }\n            }\n            if(besti==-1 || bestc<=0){\n                // fallback\n                for(int i=0;i<N && besti==-1;i++){\n                    if(selected[i]) continue;\n                    for(int k : covList[i]) if(uncovered[k]){ besti=i; break; }\n                }\n                if(besti==-1) break;\n            }\n            selected[besti]=1;\n            for(int k : covList[besti]) if(uncovered[k]){ uncovered[k]=0; remaining--; }\n        }\n\n        // Remove redundant greedily\n        vector<int> coverCnt(K, 0);\n        for(int i=0;i<N;i++){\n            if(!selected[i]) continue;\n            for(int k: covList[i]) coverCnt[k]++;\n        }\n        bool ch = true;\n        while(ch){\n            ch=false;\n            for(int i=0;i<N;i++){\n                if(!selected[i]) continue;\n                bool canRem = true;\n                for(int k: covList[i]) if(coverCnt[k] <= 1){ canRem=false; break; }\n                if(canRem){\n                    selected[i]=0;\n                    for(int k: covList[i]) coverCnt[k]--;\n                    ch=true;\n                }\n            }\n        }\n\n        // Terminals T\n        vector<int> T;\n        T.push_back(0);\n        for(int i=0;i<N;i++) if(selected[i] && i!=0) T.push_back(i);\n        vector<char> edgeOn = build_tree_for_terminals(T);\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    // Build solution 2: SPT greedy coverage\n    auto build_solution_spt = [&](){\n        vector<char> inV(N, 0);\n        vector<char> edgeOn(M, 0);\n        inV[0]=1;\n        vector<uint64_t> covered(B, 0ULL);\n        for(int b=0;b<B;b++) covered[b] |= covBits[0][b];\n        auto allCovered = [&](){\n            for(int b=0;b<B;b++){\n                uint64_t mask = (b==B-1? lastMask : ~0ULL);\n                if( (covered[b] & mask) != mask) return false;\n            }\n            return true;\n        };\n        vector<uint64_t> tmp(B);\n        while(!allCovered()){\n            int bestV = -1;\n            long long bestGain = -1;\n            long long bestIncW = (1LL<<60);\n            for(int v=0; v<N; v++){\n                if(inV[v]) continue;\n                for(int b=0;b<B;b++) tmp[b]=0ULL;\n                long long incW=0;\n                int cur=v; bool any=false;\n                while(cur!=-1 && !inV[cur]){\n                    for(int b=0;b<B;b++) tmp[b] |= covBits[cur][b];\n                    int pe = parentEdgeSPT[cur];\n                    if(pe>=0) incW += edges[pe].w;\n                    cur = parentSPT[cur];\n                    any=true;\n                }\n                if(!any) continue;\n                long long gain=0;\n                for(int b=0;b<B;b++){\n                    uint64_t mask = (b==B-1? lastMask : ~0ULL);\n                    uint64_t nc = (~covered[b]) & mask;\n                    uint64_t add = tmp[b] & nc;\n                    gain += __builtin_popcountll(add);\n                }\n                if(gain > bestGain || (gain==bestGain && incW < bestIncW)){\n                    bestGain=gain; bestIncW=incW; bestV=v;\n                }\n            }\n            if(bestV==-1) break;\n            for(int b=0;b<B;b++) tmp[b]=0ULL;\n            int cur=bestV;\n            while(cur!=-1 && !inV[cur]){\n                for(int b=0;b<B;b++) tmp[b] |= covBits[cur][b];\n                int pe = parentEdgeSPT[cur];\n                if(pe>=0) edgeOn[pe]=1;\n                inV[cur]=1;\n                cur = parentSPT[cur];\n            }\n            for(int b=0;b<B;b++) covered[b] |= tmp[b];\n        }\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    Solution sol1 = build_solution_setcover();\n    Solution sol2 = build_solution_spt();\n\n    // Steinerize both initial solutions based on P>0 terminals to reduce edge costs\n    auto maybe_steinerize_iters = [&](Solution s)->Solution{\n        if (s.P.empty()) return s;\n        for(int it=0; it<2; ++it){\n            if (time_ms() > 1600) break;\n            Solution s2 = steinerize_from_P(s);\n            if(s2.S < s.S) s = s2;\n            else break;\n        }\n        return s;\n    };\n    sol1 = maybe_steinerize_iters(sol1);\n    sol2 = maybe_steinerize_iters(sol2);\n\n    Solution best = (sol1.S <= sol2.S ? sol1 : sol2);\n\n    // Local search: edge removals with fast evaluation\n    auto removal_pass = [&](Solution cur)->Solution{\n        vector<char> edgeOn = cur.edgeOn;\n        auto fe = fast_evaluate(edgeOn);\n        long long curS = fe.S;\n        // Sort ON edges by descending weight\n        vector<int> onEdges;\n        for(int e=0;e<M;e++) if(edgeOn[e]) onEdges.push_back(e);\n        sort(onEdges.begin(), onEdges.end(), [&](int a,int b){ return edges[a].w > edges[b].w; });\n        bool improved=true;\n        int rounds=0;\n        while(improved && rounds<2 && time_ms() < 1800){\n            improved=false; rounds++;\n            for(int e : onEdges){\n                if(!edgeOn[e]) continue;\n                edgeOn[e]=0;\n                // check coverage possibility (5000 reachability)\n                vector<char> inV = build_inV(edgeOn);\n                int covered = count_covered_bits(inV);\n                if(covered < K){\n                    edgeOn[e]=1;\n                    continue;\n                }\n                auto fe2 = fast_evaluate(edgeOn);\n                if(fe2.S <= curS){\n                    fe = fe2;\n                    curS = fe2.S;\n                    improved=true;\n                }else{\n                    edgeOn[e]=1;\n                }\n                if(time_ms() >= 1850) break;\n            }\n        }\n        // finalize with full optimization + pruning\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    auto addition_pass = [&](Solution cur)->Solution{\n        // perform a few greedy additions\n        vector<char> edgeOn = cur.edgeOn;\n        auto fe = fast_evaluate(edgeOn);\n        long long curS = fe.S;\n        int tries = 0;\n        while(tries < 12 && time_ms() < 1900){\n            vector<char> inV = fe.inV;\n            vector<int>& bestD2 = fe.bestD2;\n            vector<pair<long long,int>> cand; // (score, edge)\n            cand.reserve(M);\n            for(int e=0;e<M;e++){\n                if(edgeOn[e]) continue;\n                int u=edges[e].u, v=edges[e].v;\n                int a = inV[u], b = inV[v];\n                if(a ^ b){\n                    int t = a? v : u;\n                    long long better = 0;\n                    for(int k=0;k<K;k++){\n                        int d2 = d2sr[t][k];\n                        if(d2 < bestD2[k]) better++;\n                    }\n                    if(better>0){\n                        long long score = better*1000000LL - (edges[e].w / 1000LL);\n                        cand.emplace_back(score, e);\n                    }\n                }\n            }\n            if(cand.empty()) break;\n            sort(cand.begin(), cand.end(), greater<>());\n            bool added=false;\n            int upto = min((int)cand.size(), 10);\n            for(int idx=0; idx<upto && time_ms()<1950; idx++){\n                int e = cand[idx].second;\n                edgeOn[e]=1;\n                auto fe2 = fast_evaluate(edgeOn);\n                if(fe2.allCovered && fe2.S < curS){\n                    fe = fe2;\n                    curS = fe2.S;\n                    added=true;\n                    break;\n                }else{\n                    edgeOn[e]=0;\n                }\n            }\n            if(!added) break;\n            tries++;\n        }\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    // Apply local search passes if time allows\n    if(time_ms() < 1600){\n        Solution afterRem = removal_pass(best);\n        if(afterRem.S < best.S) best = afterRem;\n    }\n    if(time_ms() < 1850){\n        Solution afterAdd = addition_pass(best);\n        if(afterAdd.S < best.S) best = afterAdd;\n    }\n    if(time_ms() < 1950){\n        Solution afterRem2 = removal_pass(best);\n        if(afterRem2.S < best.S) best = afterRem2;\n    }\n\n    // Ensure final coverage by adjusting P and possibly adding edges\n    auto ensure_full_coverage = [&](Solution& sol){\n        vector<char> inV = build_inV(sol.edgeOn);\n\n        auto isCoveredByP = [&](int k)->bool{\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                long long d2 = d2sr[i][k];\n                if(1LL*sol.P[i]*sol.P[i] >= d2) return true;\n            }\n            return false;\n        };\n\n        vector<int> uncovered;\n        uncovered.reserve(K);\n        for(int k=0;k<K;k++){\n            if(!isCoveredByP(k)) uncovered.push_back(k);\n        }\n\n        // First try to cover by increasing P on existing reachable stations\n        vector<int> needConnectResidents;\n        for(int k : uncovered){\n            int bestI = -1;\n            long long bestInc = (1LL<<62);\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                int needR = sqrt_ceil_ll(d2sr[i][k]);\n                if(needR > 5000) continue;\n                long long inc = 1LL*needR*needR - 1LL*sol.P[i]*sol.P[i];\n                if(inc < 0) inc = 0;\n                if(inc < bestInc){\n                    bestInc = inc; bestI = i;\n                }\n            }\n            if(bestI == -1){\n                // no reachable station within 5000: need to connect\n                needConnectResidents.push_back(k);\n            }else{\n                int needR = sqrt_ceil_ll(d2sr[bestI][k]);\n                if(needR > sol.P[bestI]) sol.P[bestI] = needR;\n            }\n        }\n\n        // Connect necessary stations: choose nearest in terms of root path\n        vector<char> toAddEdge(M, 0);\n        for(int k : needConnectResidents){\n            long long bestDist = (1LL<<60);\n            int bestI = -1;\n            for(int i : nearStationsForResid[k]){\n                if(distW[0][i] < bestDist){\n                    bestDist = distW[0][i];\n                    bestI = i;\n                }\n            }\n            if(bestI == -1) continue; // should not happen per input guarantee\n            int cur = bestI;\n            while(cur != 0){\n                int eid = prevE[0][cur];\n                if(eid < 0) break;\n                toAddEdge[eid] = 1;\n                cur = prevV[0][cur];\n                if(cur < 0) break;\n            }\n        }\n        bool anyAdd = false;\n        if(!needConnectResidents.empty()){\n            for(int e=0;e<M;e++){\n                if(toAddEdge[e] && !sol.edgeOn[e]){\n                    sol.edgeOn[e] = 1; anyAdd = true;\n                    sol.edgeSum += edges[e].w;\n                }\n            }\n            if(anyAdd){\n                inV = build_inV(sol.edgeOn);\n            }\n        }\n\n        // After connecting, cover remaining uncovered by increasing P\n        vector<int> uncovered2;\n        for(int k=0;k<K;k++){\n            bool ok = false;\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                if(1LL*sol.P[i]*sol.P[i] >= (long long)d2sr[i][k]){ ok = true; break; }\n            }\n            if(!ok) uncovered2.push_back(k);\n        }\n        for(int k : uncovered2){\n            int bestI = -1;\n            long long bestInc = (1LL<<62);\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                int needR = sqrt_ceil_ll(d2sr[i][k]);\n                if(needR > 5000) continue;\n                long long inc = 1LL*needR*needR - 1LL*sol.P[i]*sol.P[i];\n                if(inc < 0) inc = 0;\n                if(inc < bestInc){\n                    bestInc = inc; bestI = i;\n                }\n            }\n            if(bestI != -1){\n                int needR = sqrt_ceil_ll(d2sr[bestI][k]);\n                if(needR > sol.P[bestI]) sol.P[bestI] = needR;\n            }\n        }\n\n        // Recompute pSum and S\n        sol.pSum = 0;\n        for(int i=0;i<N;i++){\n            if(sol.P[i] > 5000) sol.P[i] = 5000;\n            sol.pSum += 1LL*sol.P[i]*sol.P[i];\n        }\n        sol.edgeSum = 0;\n        for(int e=0;e<M;e++) if(sol.edgeOn[e]) sol.edgeSum += edges[e].w;\n        sol.S = sol.pSum + sol.edgeSum;\n    };\n\n    // Ensure coverage, then Steinerize again if time allows\n    auto finalize_solution = [&](Solution s)->Solution{\n        ensure_full_coverage(s);\n        if(time_ms() < 1950){\n            Solution s2 = steinerize_from_P(s);\n            if(s2.S < s.S) s = s2;\n        }\n        return s;\n    };\n\n    best = finalize_solution(best);\n\n    // Output final solution\n    for(int i=0;i<N;i++){\n        if(i) cout << ' ';\n        cout << best.P[i];\n    }\n    cout << '\\n';\n    for(int j=0;j<M;j++){\n        if(j) cout << ' ';\n        cout << (best.edgeOn[j] ? 1 : 0);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Move {\n    int x1, y1, x2, y2;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 30;\n    vector<vector<int>> A(N);\n    for (int x = 0; x < N; ++x) {\n        A[x].resize(x + 1);\n        for (int y = 0; y <= x; ++y) cin >> A[x][y];\n    }\n\n    const int LIMIT = 10000;\n    vector<Move> ops;\n    ops.reserve(LIMIT);\n\n    auto inRange = [&](int x, int y) -> bool {\n        return 0 <= x && x < N && 0 <= y && y <= x;\n    };\n\n    auto isViolation = [&](int x, int y) -> bool {\n        if (x >= N - 1) return false;\n        int v = A[x][y];\n        int c1 = A[x + 1][y];\n        int c2 = A[x + 1][y + 1];\n        return v > (c1 < c2 ? c1 : c2);\n    };\n\n    // Buckets by depth (x). Process deeper x first.\n    vector<deque<pair<int,int>>> buckets(N);\n    vector<vector<char>> inQ(N);\n    for (int x = 0; x < N; ++x) inQ[x].assign(x + 1, 0);\n\n    auto pushBucket = [&](int x, int y) {\n        if (!inRange(x, y) || x >= N - 1) return;\n        if (inQ[x][y]) return;\n        if (!isViolation(x, y)) return;\n        inQ[x][y] = 1;\n        buckets[x].emplace_back(x, y);\n    };\n\n    // Initialize with all current violations (bottom-first not needed at init, buckets handle order)\n    for (int x = 0; x <= N - 2; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            if (isViolation(x, y)) pushBucket(x, y);\n        }\n    }\n\n    auto recordSwap = [&](int x1, int y1, int x2, int y2) {\n        ops.push_back({x1, y1, x2, y2});\n    };\n\n    auto pushParents = [&](int x, int y) {\n        if (x <= 0) return;\n        if (y - 1 >= 0) pushBucket(x - 1, y - 1);\n        if (y <= x - 1) pushBucket(x - 1, y);\n    };\n\n    auto chooseChild = [&](int x, int y) -> pair<int,int> {\n        // Assumes x < N-1 and violation exists or being considered\n        int v1 = A[x + 1][y];\n        int v2 = A[x + 1][y + 1];\n        if (v1 < v2) return {x + 1, y};\n        if (v2 < v1) return {x + 1, y + 1};\n        // Tie-breaker using grandchildren minima if available\n        if (x + 1 >= N - 1) return {x + 1, y}; // children are leaves\n        int g1a = A[x + 2][y];\n        int g1b = A[x + 2][y + 1];\n        int g2a = A[x + 2][y + 1];\n        int g2b = A[x + 2][y + 2];\n        int m1 = (g1a < g1b ? g1a : g1b);\n        int m2 = (g2a < g2b ? g2a : g2b);\n        if (m1 <= m2) return {x + 1, y};\n        else return {x + 1, y + 1};\n    };\n\n    // Main processing loop: always pick deepest violating node\n    while ((int)ops.size() < LIMIT) {\n        int selX = -1;\n        for (int x = N - 2; x >= 0; --x) {\n            if (!buckets[x].empty()) { selX = x; break; }\n        }\n        if (selX == -1) break;\n\n        auto [sx, sy] = buckets[selX].front();\n        buckets[selX].pop_front();\n        inQ[sx][sy] = 0;\n\n        int x = sx, y = sy;\n        // Sift down step-by-step\n        while (x < N - 1) {\n            int v = A[x][y];\n            int c1 = A[x + 1][y];\n            int c2 = A[x + 1][y + 1];\n            int mn = (c1 < c2 ? c1 : c2);\n            if (v <= mn) break;\n\n            auto [tx, ty] = chooseChild(x, y);\n\n            if ((int)ops.size() >= LIMIT) break;\n\n            swap(A[x][y], A[tx][ty]);\n            recordSwap(x, y, tx, ty);\n\n            // The node (x,y) decreased; its parents may now violate.\n            pushParents(x, y);\n\n            x = tx; y = ty;\n        }\n\n        // If still violating (e.g., we hit limit), requeue\n        if ((int)ops.size() < LIMIT && x < N - 1 && isViolation(x, y)) {\n            pushBucket(x, y);\n        }\n    }\n\n    int K = min<int>(ops.size(), LIMIT);\n    cout << K << '\\n';\n    for (int i = 0; i < K; ++i) {\n        cout << ops[i].x1 << ' ' << ops[i].y1 << ' ' << ops[i].x2 << ' ' << ops[i].y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int i, j; };\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    const int H = D, W = D;\n    const int ei = 0, ej = (D - 1) / 2; // entrance coordinates\n    const int INF = 1e9;\n\n    // Obstacles\n    vector<vector<char>> obs(H, vector<char>(W, 0));\n    for (int k = 0; k < N; ++k) {\n        int r, c;\n        cin >> r >> c;\n        obs[r][c] = 1;\n    }\n\n    auto inside = [&](int i, int j){ return 0 <= i && i < H && 0 <= j && j < W; };\n    int di[4] = {-1, 0, 1, 0};\n    int dj[4] = {0, 1, 0, -1};\n\n    // Precompute BFS distances from entrance (ignoring containers)\n    vector<vector<int>> dist(H, vector<int>(W, INF));\n    deque<Pos> dq;\n    dist[ei][ej] = 0;\n    dq.push_back({ei, ej});\n    while (!dq.empty()) {\n        auto p = dq.front(); dq.pop_front();\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = p.i + di[dir], nj = p.j + dj[dir];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (dist[ni][nj] > dist[p.i][p.j] + 1) {\n                dist[ni][nj] = dist[p.i][p.j] + 1;\n                dq.push_back({ni, nj});\n            }\n        }\n    }\n\n    // Build target order: increasing distance from entrance, tie by (i,j)\n    vector<Pos> order;\n    order.reserve(H*W);\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            if (obs[i][j]) continue;\n            if (i == ei && j == ej) continue;\n            order.push_back({i, j});\n        }\n    }\n    sort(order.begin(), order.end(), [&](const Pos &a, const Pos &b){\n        if (dist[a.i][a.j] != dist[b.i][b.j]) return dist[a.i][a.j] < dist[b.i][b.j];\n        if (a.i != b.i) return a.i < b.i;\n        return a.j < b.j;\n    });\n    int M = (int)order.size();\n\n    // rank index of each cell in the order\n    vector<vector<int>> rankIndex(H, vector<int>(W, -1));\n    for (int idx = 0; idx < (int)order.size(); ++idx) {\n        rankIndex[order[idx].i][order[idx].j] = idx;\n    }\n\n    // State during placement\n    vector<vector<char>> empty(H, vector<char>(W, 0)); // currently empty and not obstacle (entrance included)\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) empty[i][j] = !obs[i][j];\n    vector<vector<int>> labelAt(H, vector<int>(W, -1)); // label placed at cell (if any), -1 if none\n\n    // Tarjan articulation points on current empty graph (including entrance)\n    auto compute_articulation = [&](const vector<vector<char>>& curEmpty)->vector<vector<char>> {\n        vector<vector<int>> id(H, vector<int>(W, -1));\n        vector<Pos> nodes; nodes.reserve(H*W);\n        int vid = 0;\n        for (int i = 0; i < H; ++i)\n            for (int j = 0; j < W; ++j)\n                if (curEmpty[i][j]) { id[i][j] = vid++; nodes.push_back({i,j}); }\n\n        int n = vid;\n        vector<vector<int>> g(n);\n        for (auto &p : nodes) {\n            int u = id[p.i][p.j];\n            for (int d = 0; d < 4; ++d) {\n                int ni = p.i + di[d], nj = p.j + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (!curEmpty[ni][nj]) continue;\n                int v = id[ni][nj];\n                g[u].push_back(v);\n            }\n        }\n        vector<int> tin(n, -1), low(n, -1), parent(n, -1);\n        vector<char> isArtV(n, 0);\n        int timer = 0;\n        function<void(int)> dfs = [&](int u){\n            tin[u] = low[u] = timer++;\n            int child = 0;\n            for (int v : g[u]) {\n                if (tin[v] == -1) {\n                    parent[v] = u;\n                    ++child;\n                    dfs(v);\n                    low[u] = min(low[u], low[v]);\n                    if (parent[u] != -1 && low[v] >= tin[u]) isArtV[u] = 1;\n                } else if (v != parent[u]) {\n                    low[u] = min(low[u], tin[v]);\n                }\n            }\n            if (parent[u] == -1 && child > 1) isArtV[u] = 1;\n        };\n        for (int u = 0; u < n; ++u) if (tin[u] == -1) dfs(u);\n\n        vector<vector<char>> isArt(H, vector<char>(W, 0));\n        for (auto &p : nodes) {\n            int u = id[p.i][p.j];\n            isArt[p.i][p.j] = isArtV[u];\n        }\n        return isArt;\n    };\n\n    auto count_safe_prefix = [&](const vector<vector<char>> &isArt, const vector<vector<char>> &curEmpty, int prefixLen)->int {\n        int cnt = 0;\n        for (int k = 0; k < (int)order.size() && k < prefixLen; ++k) {\n            int i = order[k].i, j = order[k].j;\n            if (!curEmpty[i][j]) continue;\n            if (!isArt[i][j]) cnt++;\n        }\n        return cnt;\n    };\n\n    int step = 0;\n\n    auto choose_position = [&](int label)->Pos {\n        vector<vector<char>> baseArt = compute_articulation(empty);\n\n        struct Cand { int i, j, idx, baseCost, deg; };\n        vector<Cand> cands;\n        cands.reserve(order.size());\n        for (int k = 0; k < (int)order.size(); ++k) {\n            int i = order[k].i, j = order[k].j;\n            if (!empty[i][j]) continue;     // already occupied\n            if (baseArt[i][j]) continue;    // avoid articulation to keep connectivity\n            int deg = 0;\n            for (int d = 0; d < 4; ++d) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (empty[ni][nj]) deg++;\n            }\n            int cost = abs(k - label);\n            cands.push_back({i, j, k, cost, deg});\n        }\n\n        if (cands.empty()) {\n            // Fallback: any empty non-entrance cell\n            for (int k = 0; k < (int)order.size(); ++k) {\n                int i = order[k].i, j = order[k].j;\n                if (!empty[i][j]) continue;\n                return {i, j};\n            }\n        }\n\n        // Prefer candidates within a window around the target index (keeps labels near their ideal spot)\n        int Wrange = max(8, M / 6); // ~12 for M~80\n        vector<Cand> windowCands;\n        windowCands.reserve(cands.size());\n        for (auto &c : cands) if (abs(c.idx - label) <= Wrange) windowCands.push_back(c);\n        vector<Cand> &useCands = windowCands.empty() ? cands : windowCands;\n\n        sort(useCands.begin(), useCands.end(), [&](const Cand& a, const Cand& b){\n            if (a.baseCost != b.baseCost) return a.baseCost < b.baseCost;\n            if (a.deg != b.deg) return a.deg < b.deg;\n            if (dist[a.i][a.j] != dist[b.i][b.j]) return dist[a.i][a.j] < dist[b.i][b.j];\n            if (a.i != b.i) return a.i < b.i;\n            return a.j < b.j;\n        });\n\n        int K = min<int>(25, useCands.size());      // evaluate top-K\n        int P = min<int>(20, (int)order.size());    // protect early prefix\n        int baseSafePrefix = count_safe_prefix(baseArt, empty, P);\n        int wUnlock = 2; // mild bonus\n\n        long long bestScoreLL = LLONG_MIN;\n        Pos best{-1, -1};\n        int bestBaseCost = INT_MAX;\n        int bestDist = INT_MAX;\n\n        for (int z = 0; z < K; ++z) {\n            auto c = useCands[z];\n            // Tentative placement\n            empty[c.i][c.j] = 0;\n            vector<vector<char>> art2 = compute_articulation(empty);\n            int afterSafe = count_safe_prefix(art2, empty, P);\n            int benefit = afterSafe - baseSafePrefix;\n\n            long long score = -(long long)c.baseCost + (long long)wUnlock * benefit;\n            // tiny tie-breaker\n            score -= (c.deg >= 3 ? 1 : 0);\n\n            empty[c.i][c.j] = 1;\n\n            if (score > bestScoreLL) {\n                bestScoreLL = score;\n                best = {c.i, c.j};\n                bestBaseCost = c.baseCost;\n                bestDist = dist[c.i][c.j];\n            } else if (score == bestScoreLL) {\n                if (c.baseCost < bestBaseCost) {\n                    best = {c.i, c.j};\n                    bestBaseCost = c.baseCost;\n                    bestDist = dist[c.i][c.j];\n                } else if (c.baseCost == bestBaseCost) {\n                    if (dist[c.i][c.j] < bestDist) {\n                        best = {c.i, c.j};\n                        bestDist = dist[c.i][c.j];\n                    }\n                }\n            }\n        }\n\n        if (best.i == -1) {\n            auto c = useCands[0];\n            best = {c.i, c.j};\n        }\n        return best;\n    };\n\n    // Interactive placement\n    for (step = 0; step < M; ++step) {\n        int t;\n        cin >> t;\n        Pos p = choose_position(t);\n        empty[p.i][p.j] = 0;\n        labelAt[p.i][p.j] = t;\n        cout << p.i << ' ' << p.j << '\\n' << flush;\n    }\n\n    // Retrieval strategies: simulate and choose the one with fewer inversions\n    auto inversion_count = [&](const vector<int>& a)->long long {\n        int n = (int)a.size();\n        int MX = n + 2;\n        vector<int> bit(MX, 0);\n        auto add = [&](int i){\n            for (++i; i < MX; i += i & -i) bit[i] += 1;\n        };\n        auto sum = [&](int i){\n            int s = 0;\n            for (++i; i > 0; i -= i & -i) s += bit[i];\n            return s;\n        };\n        long long inv = 0;\n        for (int i = 0; i < n; ++i) {\n            inv += i - sum(a[i]);\n            add(a[i]);\n        }\n        return inv;\n    };\n\n    // Base occupancy\n    vector<vector<char>> occ0(H, vector<char>(W, 0));\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        if (obs[i][j]) continue;\n        if (i == ei && j == ej) continue;\n        if (labelAt[i][j] >= 0) occ0[i][j] = 1;\n    }\n\n    // Strategy B: greedy smallest-label frontier\n    vector<pair<int,int>> seqB;\n    {\n        auto occ = occ0;\n        struct Node { int label, i, j; bool operator<(const Node& o) const { return label > o.label; } };\n        priority_queue<Node> pq;\n        vector<vector<char>> inFrontier(H, vector<char>(W, 0));\n        auto try_push = [&](int i, int j){\n            if (!inside(i,j)) return;\n            if (obs[i][j]) return;\n            if (!occ[i][j]) return;\n            if (inFrontier[i][j]) return;\n            inFrontier[i][j] = 1;\n            pq.push({labelAt[i][j], i, j});\n        };\n        for (int d = 0; d < 4; ++d) {\n            int ni = ei + di[d], nj = ej + dj[d];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (occ[ni][nj]) try_push(ni, nj);\n        }\n        for (int step2 = 0; step2 < M; ++step2) {\n            while (!pq.empty() && !occ[pq.top().i][pq.top().j]) pq.pop();\n            if (pq.empty()) {\n                // Shouldn't happen; robustness: find any frontier cell\n                bool pushed = false;\n                for (int i = 0; i < H && !pushed; ++i) for (int j = 0; j < W && !pushed; ++j) {\n                    if (!occ[i][j]) continue;\n                    for (int d = 0; d < 4; ++d) {\n                        int ni = i + di[d], nj = j + dj[d];\n                        if (!inside(ni, nj)) continue;\n                        if (obs[ni][nj]) continue;\n                        if (!occ[ni][nj]) { try_push(i, j); pushed = true; break; }\n                    }\n                }\n                if (pq.empty()) break;\n            }\n            auto cur = pq.top(); pq.pop();\n            int ci = cur.i, cj = cur.j;\n            occ[ci][cj] = 0;\n            seqB.emplace_back(ci, cj);\n            for (int d = 0; d < 4; ++d) {\n                int ni = ci + di[d], nj = cj + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (obs[ni][nj]) continue;\n                if (occ[ni][nj]) try_push(ni, nj);\n            }\n        }\n    }\n    vector<int> labelsB; labelsB.reserve(M);\n    for (auto &p : seqB) labelsB.push_back(labelAt[p.first][p.second]);\n    long long invB = inversion_count(labelsB);\n\n    // Strategy C: greedy closest to BFS-rank head\n    vector<pair<int,int>> seqC;\n    {\n        auto occ = occ0;\n        struct NodeC {\n            int key, idx, label, i, j;\n            bool operator<(const NodeC& o) const {\n                if (key != o.key) return key > o.key;\n                if (label != o.label) return label > o.label;\n                return idx > o.idx;\n            }\n        };\n        priority_queue<NodeC> pq;\n        vector<vector<char>> inFrontier(H, vector<char>(W, 0));\n        int headIdx = 0;\n        auto try_push = [&](int i, int j){\n            if (!inside(i,j)) return;\n            if (obs[i][j]) return;\n            if (!occ[i][j]) return;\n            if (inFrontier[i][j]) return;\n            inFrontier[i][j] = 1;\n            int idx = rankIndex[i][j];\n            int key = abs(idx - headIdx);\n            pq.push(NodeC{key, idx, labelAt[i][j], i, j});\n        };\n        for (int d = 0; d < 4; ++d) {\n            int ni = ei + di[d], nj = ej + dj[d];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (occ[ni][nj]) try_push(ni, nj);\n        }\n        for (int step2 = 0; step2 < M; ++step2) {\n            while (!pq.empty() && !occ[pq.top().i][pq.top().j]) pq.pop();\n            if (pq.empty()) {\n                bool pushed = false;\n                for (int i = 0; i < H && !pushed; ++i) for (int j = 0; j < W && !pushed; ++j) {\n                    if (!occ[i][j]) continue;\n                    for (int d = 0; d < 4; ++d) {\n                        int ni = i + di[d], nj = j + dj[d];\n                        if (!inside(ni, nj)) continue;\n                        if (obs[ni][nj]) continue;\n                        if (!occ[ni][nj]) { try_push(i, j); pushed = true; break; }\n                    }\n                }\n                if (pq.empty()) break;\n            }\n            auto cur = pq.top(); pq.pop();\n            int ci = cur.i, cj = cur.j;\n            occ[ci][cj] = 0;\n            seqC.emplace_back(ci, cj);\n            // advance headIdx to next unremoved index\n            while (headIdx < M) {\n                auto p = order[headIdx];\n                if (occ[p.i][p.j]) break;\n                headIdx++;\n            }\n            for (int d = 0; d < 4; ++d) {\n                int ni = ci + di[d], nj = cj + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (obs[ni][nj]) continue;\n                if (occ[ni][nj]) try_push(ni, nj);\n            }\n        }\n    }\n    vector<int> labelsC; labelsC.reserve(M);\n    for (auto &p : seqC) labelsC.push_back(labelAt[p.first][p.second]);\n    long long invC = inversion_count(labelsC);\n\n    // Choose the better legal sequence\n    vector<pair<int,int>>* bestSeq = &seqB;\n    long long bestInv = invB;\n    if ((int)seqC.size() == M && invC < bestInv) { bestInv = invC; bestSeq = &seqC; }\n    // ensure we output exactly M lines; if a sequence is short due to unforeseen issue, fallback to the other\n    if ((int)bestSeq->size() != M) {\n        if ((int)seqB.size() == M) bestSeq = &seqB;\n        else bestSeq = &seqC; // one of them should be full; as a last resort\n    }\n\n    for (auto &p : *bestSeq) {\n        cout << p.first << ' ' << p.second << '\\n';\n    }\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    if (!(cin >> n >> m)) return 0;\n    const int N = n * n;\n\n    vector<int> origGrid(N);\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j < n; ++j)\n            cin >> origGrid[i*n + j];\n\n    auto inb = [&](int r, int c)->bool { return 0 <= r && r < n && 0 <= c && c < n; };\n    const int dr[4] = {1, -1, 0, 0};\n    const int dc[4] = {0, 0, 1, -1};\n\n    // Precompute boundary flags, BC/IC, degSame0, adjToIC on original\n    vector<char> isBoundaryPos(N, 0);\n    vector<int> boundaryCount0(m+1, 0);\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j;\n            if (i == 0 || j == 0 || i == n-1 || j == n-1) {\n                isBoundaryPos[id] = 1;\n                int c = origGrid[id];\n                boundaryCount0[c]++;\n            }\n        }\n    }\n    vector<char> isBC(m+1, 0), isIC(m+1, 0);\n    for (int c = 1; c <= m; ++c) isBC[c] = (boundaryCount0[c] > 0);\n    for (int c = 1; c <= m; ++c) isIC[c] = !isBC[c];\n\n    vector<int> degSame0(N, 0);\n    for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) {\n        int id = i*n + j, c = origGrid[id], d = 0;\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            if (origGrid[ni*n + nj] == c) d++;\n        }\n        degSame0[id] = d;\n    }\n    vector<char> adjToIC(N, 0);\n    for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) {\n        int id = i*n + j;\n        bool flag = false;\n        for (int k = 0; k < 4; ++k) {\n            int ni = i + dr[k], nj = j + dc[k];\n            if (!inb(ni, nj)) continue;\n            int d = origGrid[ni*n + nj];\n            if (d != 0 && isIC[d]) { flag = true; break; }\n        }\n        adjToIC[id] = flag ? 1 : 0;\n    }\n\n    // Build list of adjacency edges for each non-zero pair (u<v): vector of pairs (cell_u, cell_v)\n    // Key as u*(m+1)+v\n    unordered_map<int, vector<pair<int,int>>> pairEdges;\n    pairEdges.reserve(4000);\n    auto add_pair_edge = [&](int a, int b, int idA, int idB){\n        if (a == 0 || b == 0 || a == b) return;\n        int u = a, v = b, idU = idA, idV = idB;\n        if (u > v) { swap(u, v); swap(idU, idV); }\n        int key = u*(m+1) + v;\n        pairEdges[key].emplace_back(idU, idV);\n    };\n    for (int i = 0; i < n; ++i) for (int j = 0; j+1 < n; ++j) {\n        int idA = i*n + j, idB = i*n + j + 1;\n        int a = origGrid[idA], b = origGrid[idB];\n        if (a != b) add_pair_edge(a, b, idA, idB);\n    }\n    for (int i = 0; i+1 < n; ++i) for (int j = 0; j < n; ++j) {\n        int idA = i*n + j, idB = (i+1)*n + j;\n        int a = origGrid[idA], b = origGrid[idB];\n        if (a != b) add_pair_edge(a, b, idA, idB);\n    }\n\n    auto borderSides = [&](int id)->int {\n        int i = id / n, j = id % n;\n        return (i == 0) + (i == n-1) + (j == 0) + (j == n-1);\n    };\n\n    Timer timer;\n    const double TIME_LIMIT = 1.95;\n\n    std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    auto run_once = [&](int runType, double time_budget)->pair<int, vector<int>> {\n        vector<int> grid = origGrid;\n\n        // size per color\n        vector<int> sizeCount(m+1, 0);\n        for (int id = 0; id < N; ++id) sizeCount[grid[id]]++;\n\n        // degSame dynamic\n        vector<int> degSame = degSame0;\n\n        // pairCount[u][v]\n        vector<vector<int>> pairCount(m+1, vector<int>(m+1, 0));\n        auto add_pair_cnt = [&](int a, int b, int delta){\n            if (a == 0 || b == 0 || a == b) return;\n            if (a > b) swap(a, b);\n            pairCount[a][b] += delta;\n        };\n        for (int i = 0; i < n; ++i) for (int j = 0; j+1 < n; ++j) {\n            int a = grid[i*n + j], b = grid[i*n + j + 1];\n            if (a != b) add_pair_cnt(a, b, +1);\n        }\n        for (int i = 0; i+1 < n; ++i) for (int j = 0; j < n; ++j) {\n            int a = grid[i*n + j], b = grid[(i+1)*n + j];\n            if (a != b) add_pair_cnt(a, b, +1);\n        }\n\n        // adjacency to 0 counts\n        vector<int> adj0Count(m+1, 0);\n        // border edges\n        for (int j = 0; j < n; ++j) {\n            int t = grid[0*n + j]; if (t) adj0Count[t]++;\n            int b = grid[(n-1)*n + j]; if (b) adj0Count[b]++;\n        }\n        for (int i = 0; i < n; ++i) {\n            int l = grid[i*n + 0]; if (l) adj0Count[l]++;\n            int r = grid[i*n + (n-1)]; if (r) adj0Count[r]++;\n        }\n        // internal 0 edges (none initially but keep generic)\n        for (int i = 0; i < n; ++i) for (int j = 0; j+1 < n; ++j) {\n            int a = grid[i*n + j], b = grid[i*n + j + 1];\n            if (a == 0 && b != 0) adj0Count[b]++;\n            if (a != 0 && b == 0) adj0Count[a]++;\n        }\n        for (int i = 0; i+1 < n; ++i) for (int j = 0; j < n; ++j) {\n            int a = grid[i*n + j], b = grid[(i+1)*n + j];\n            if (a == 0 && b != 0) adj0Count[b]++;\n            if (a != 0 && b == 0) adj0Count[a]++;\n        }\n\n        // Optional: choose and protect one anchor edge per pair (u,v)\n        vector<char> protectAnchor(N, 0);\n        if (runType >= 1) {\n            for (auto &kv : pairEdges) {\n                auto &vec = kv.second;\n                if (vec.empty()) continue;\n                int u = kv.first / (m+1), v = kv.first % (m+1);\n                // Heuristic cost\n                int bestIdx = 0;\n                int bestCost = INT_MAX;\n                for (int idx = 0; idx < (int)vec.size(); ++idx) {\n                    int idU = vec[idx].first;\n                    int idV = vec[idx].second;\n                    int cost = 0;\n                    // Prefer endpoints adjacent to interior (we won't touch those anyway)\n                    if (!(adjToIC[idU] || adjToIC[idV])) cost += 5;\n                    // Prefer lower degree borders\n                    cost += (degSame0[idU] > 2) + (degSame0[idV] > 2);\n                    // Slight preference to border contacts\n                    if (!(isBoundaryPos[idU] || isBoundaryPos[idV])) cost += 1;\n                    // Random jitter\n                    cost = cost * 8 + (int)(rng() & 7);\n                    if (cost < bestCost) { bestCost = cost; bestIdx = idx; }\n                }\n                int idU = vec[bestIdx].first;\n                int idV = vec[bestIdx].second;\n                protectAnchor[idU] = 1;\n                protectAnchor[idV] = 1;\n            }\n        }\n\n        auto hasZeroNeighbor = [&](int id)->bool {\n            int i = id / n, j = id % n;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                if (grid[ni*n + nj] == 0) return true;\n            }\n            return false;\n        };\n        auto is_accessible = [&](int id)->bool {\n            return isBoundaryPos[id] || hasZeroNeighbor(id);\n        };\n\n        // Articulation check: neighbors of same color remain connected after removing id\n        vector<int> seen(N, 0);\n        int stamp = 1;\n        auto neighbors_connected_after_remove = [&](int id, int color)->bool {\n            int i = id / n, j = id % n;\n            int sameNei[4]; int sn = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int nid = ni*n + nj;\n                if (grid[nid] == color) sameNei[sn++] = nid;\n            }\n            if (sn <= 1) return true;\n            stamp++;\n            deque<int> dq;\n            dq.push_back(sameNei[0]);\n            seen[sameNei[0]] = stamp;\n            int targetsLeft = sn - 1;\n            while (!dq.empty()) {\n                int u = dq.front(); dq.pop_front();\n                int ui = u / n, uj = u % n;\n                for (int k = 0; k < 4; ++k) {\n                    int vi = ui + dr[k], vj = uj + dc[k];\n                    if (!inb(vi, vj)) continue;\n                    int v = vi*n + vj;\n                    if (v == id) continue;\n                    if (grid[v] != color) continue;\n                    if (seen[v] == stamp) continue;\n                    seen[v] = stamp;\n                    // Check if v is one of the neighbor targets\n                    for (int t = 1; t < sn; ++t) {\n                        if (v == sameNei[t]) {\n                            targetsLeft--;\n                            break;\n                        }\n                    }\n                    if (targetsLeft == 0) return true;\n                    dq.push_back(v);\n                }\n            }\n            return false;\n        };\n\n        auto can_remove = [&](int id)->bool {\n            int c = grid[id];\n            if (c == 0) return false;\n            if (!isBC[c]) return false;          // never touch interior colors\n            if (protectAnchor[id]) return false; // keep selected anchor endpoints\n            if (!is_accessible(id)) return false;// keep 0 connected\n            if (sizeCount[c] <= 1) return false; // keep at least one cell\n\n            // Do not create adjacency between 0 and interior colors\n            int i = id / n, j = id % n;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d != 0 && isIC[d]) return false;\n            }\n\n            // Preserve non-zero adjacencies: don't remove last c-d contact for any neighbor d\n            int neighCols[4]; int counts[4]; int cnt = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d == 0 || d == c) continue;\n                bool found = false;\n                for (int t = 0; t < cnt; ++t) {\n                    if (neighCols[t] == d) { counts[t]++; found = true; break; }\n                }\n                if (!found) { neighCols[cnt] = d; counts[cnt] = 1; cnt++; }\n            }\n            for (int t = 0; t < cnt; ++t) {\n                int d = neighCols[t];\n                int a = c, b = d;\n                if (a > b) swap(a, b);\n                if (pairCount[a][b] <= counts[t]) return false;\n            }\n\n            // Preserve adjacency to 0 for boundary colors\n            int sameN = 0, zeroN = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d == c) sameN++;\n                else if (d == 0) zeroN++;\n            }\n            int bSides = borderSides(id);\n            int delta0 = sameN - zeroN - bSides;\n            if (adj0Count[c] + delta0 <= 0) return false;\n\n            // Connectivity: avoid articulation points\n            if (degSame[id] > 1) {\n                if (!neighbors_connected_after_remove(id, c)) return false;\n            }\n            return true;\n        };\n\n        auto remove_cell = [&](int id) {\n            int c = grid[id];\n            int i = id / n, j = id % n;\n            // Update pair counts for non-zero neighbors\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d != 0 && d != c) {\n                    int a = c, b = d; if (a > b) swap(a, b);\n                    if (pairCount[a][b] > 0) pairCount[a][b]--;\n                }\n            }\n            // Update degSame for same-color neighbors\n            int sameN = 0, zeroN = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int nid = ni*n + nj;\n                int d = grid[nid];\n                if (d == c) { degSame[nid]--; sameN++; }\n                else if (d == 0) zeroN++;\n            }\n            // Update adjacency to 0 counts\n            int bSides = borderSides(id);\n            adj0Count[c] += (sameN - zeroN - bSides);\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d != 0 && d != c) adj0Count[d]++;\n            }\n\n            sizeCount[c]--;\n            grid[id] = 0;\n            degSame[id] = 0;\n        };\n\n        // Carving queue\n        deque<int> Q;\n        vector<char> inQ(N, 0);\n        auto push_cand = [&](int id) {\n            if (inQ[id]) return;\n            if (grid[id] == 0) return;\n            int c = grid[id];\n            if (!isBC[c]) return;\n            if (!isBoundaryPos[id] && !hasZeroNeighbor(id)) return;\n            if (protectAnchor[id]) return;\n            if (degSame[id] <= 2) Q.push_front(id);\n            else Q.push_back(id);\n            inQ[id] = 1;\n        };\n        // Seed: boundary cells of boundary colors\n        for (int id = 0; id < N; ++id) {\n            if (!isBoundaryPos[id]) continue;\n            int c = grid[id];\n            if (c == 0 || !isBC[c]) continue;\n            push_cand(id);\n        }\n\n        double start_t = timer.elapsed();\n        while (!Q.empty() && timer.elapsed() - start_t < time_budget) {\n            int id = Q.front(); Q.pop_front();\n            inQ[id] = 0;\n            if (grid[id] == 0) continue;\n            if (!is_accessible(id)) continue;\n            if (can_remove(id)) {\n                int i = id / n, j = id % n;\n                remove_cell(id);\n                // push neighbors\n                for (int k = 0; k < 4; ++k) {\n                    int ni = i + dr[k], nj = j + dc[k];\n                    if (!inb(ni, nj)) continue;\n                    int nid = ni*n + nj;\n                    if (grid[nid] != 0) push_cand(nid);\n                }\n            }\n        }\n\n        int zeros = 0;\n        for (int id = 0; id < N; ++id) if (grid[id] == 0) zeros++;\n        return {zeros, grid};\n    };\n\n    vector<int> bestGrid = origGrid;\n    int bestZeros = 0;\n\n    // Plan runs: always do baseline (no anchors), then one or two anchor-guided runs if time permits\n    double remain = TIME_LIMIT - timer.elapsed();\n    double base_budget = min(0.9, max(0.4, remain * 0.45));\n    {\n        auto [zeros, grid] = run_once(0, base_budget);\n        if (zeros > bestZeros) { bestZeros = zeros; bestGrid = move(grid); }\n    }\n\n    int extraRuns = 2;\n    for (int r = 1; r <= extraRuns; ++r) {\n        remain = TIME_LIMIT - timer.elapsed();\n        if (remain < 0.2) break;\n        double budget = min(remain - 0.05, 0.8);\n        if (budget <= 0) break;\n        auto [zeros, grid] = run_once(1 + (rng() & 1), budget);\n        if (zeros > bestZeros) { bestZeros = zeros; bestGrid = move(grid); }\n    }\n\n    // Output best\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            if (j) cout << ' ';\n            cout << bestGrid[i*n + j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, D, Q;\n    if (!(cin >> N >> D >> Q)) return 0;\n\n    // RNG\n    uint64_t seed = 1469598103934665603ull;\n    auto mix = [&](uint64_t x){ seed ^= x + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2); };\n    mix((uint64_t)N); mix((uint64_t)D); mix((uint64_t)Q);\n    mt19937_64 rng(seed);\n    uniform_real_distribution<double> ur01(0.0, 1.0);\n\n    // Correlator estimate\n    vector<int> score(N, 0);\n    // Adaptive estimate for building queries (positive)\n    vector<double> w_est(N, 1.0);\n    // Track side usage to reduce bias\n    vector<int> count_pm(N, 0);\n\n    // Store rows for post-phase logistic regression\n    vector<int8_t> Aflat; Aflat.reserve((size_t)Q * N);\n    vector<int8_t> Y;     Y.reserve(Q);\n\n    vector<int> a(N, 0);\n    string resp;\n\n    auto build_balanced_query = [&](const vector<double>& w_est, vector<int>& a_out){\n        vector<int> perm(N);\n        iota(perm.begin(), perm.end(), 0);\n        shuffle(perm.begin(), perm.end(), rng);\n\n        vector<int> L; L.reserve(N);\n        vector<int> R; R.reserve(N);\n        double sumL = 0.0, sumR = 0.0;\n\n        // Greedy assign to balance predicted sums; no cardinality constraint\n        for (int idx : perm) {\n            double wi = w_est[idx];\n            if (sumL < sumR) {\n                L.push_back(idx);\n                sumL += wi;\n            } else if (sumR < sumL) {\n                R.push_back(idx);\n                sumR += wi;\n            } else {\n                // sums equal; use side-usage balance then random\n                if (count_pm[idx] > 0) { // used +1 more; prefer -1 side\n                    R.push_back(idx); sumR += wi;\n                } else if (count_pm[idx] < 0) {\n                    L.push_back(idx); sumL += wi;\n                } else {\n                    if (ur01(rng) < 0.5) { L.push_back(idx); sumL += wi; }\n                    else { R.push_back(idx); sumR += wi; }\n                }\n            }\n        }\n\n        // Ensure both sides non-empty\n        if (L.empty()) { L.push_back(R.back()); sumL += w_est[R.back()]; sumR -= w_est[R.back()]; R.pop_back(); }\n        if (R.empty()) { R.push_back(L.back()); sumR += w_est[L.back()]; sumL -= w_est[L.back()]; L.pop_back(); }\n\n        // Small random perturbation (swap one random element) to diversify queries\n        if (ur01(rng) < 0.10 && !L.empty() && !R.empty()) {\n            int il = uniform_int_distribution<int>(0, (int)L.size()-1)(rng);\n            int ir = uniform_int_distribution<int>(0, (int)R.size()-1)(rng);\n            swap(L[il], R[ir]);\n        }\n\n        // Randomly choose which side becomes \"left\"/+1\n        bool flip = (ur01(rng) < 0.5);\n\n        a_out.assign(N, -1);\n        if (!flip) {\n            for (int idx : L) a_out[idx] = +1;\n        } else {\n            for (int idx : R) a_out[idx] = +1;\n        }\n\n        // Update side-usage counts\n        for (int i = 0; i < N; i++) count_pm[i] += (a_out[i] > 0 ? +1 : -1);\n\n        // Output query\n        int nL = 0, nR = 0;\n        for (int i = 0; i < N; i++) {\n            if (a_out[i] == +1) nL++; else nR++;\n        }\n        cout << nL << ' ' << nR;\n        for (int i = 0; i < N; i++) if (a_out[i] == +1) cout << ' ' << i;\n        for (int i = 0; i < N; i++) if (a_out[i] == -1) cout << ' ' << i;\n        cout << \"\\n\" << flush;\n    };\n\n    // Query loop\n    for (int q = 0; q < Q; q++) {\n        build_balanced_query(w_est, a);\n\n        if (!(cin >> resp)) return 0;\n        int y = 0;\n        if (resp[0] == '>') y = +1;\n        else if (resp[0] == '<') y = -1;\n        else if (resp[0] == '=') y = 0;\n\n        if (y != 0) {\n            for (int i = 0; i < N; i++) {\n                score[i] += y * a[i];\n            }\n            for (int i = 0; i < N; i++) {\n                Aflat.push_back((int8_t)(a[i] > 0 ? 1 : -1));\n            }\n            Y.push_back((int8_t)y);\n        }\n\n        // Refresh w_est from correlator (shift to positive)\n        int mn = INT_MAX;\n        for (int i = 0; i < N; i++) mn = min(mn, score[i]);\n        double shift = - (double)mn + 1.0;\n        for (int i = 0; i < N; i++) w_est[i] = max(1e-3, (double)score[i] + shift);\n    }\n\n    // Initial weights from correlator\n    vector<double> w(N, 1.0);\n    {\n        int mn = INT_MAX;\n        for (int i = 0; i < N; i++) mn = min(mn, score[i]);\n        double shift = - (double)mn + 1.0;\n        for (int i = 0; i < N; i++) w[i] = max(1e-6, (double)score[i] + shift);\n    }\n\n    // Post-phase 1-bit logistic regression without intercept\n    int M = (int)Y.size();\n    if (M > 0) {\n        vector<double> x = w; // init from correlator\n        // Normalize to mean ~1 for stability\n        double meanx = 0.0;\n        for (double v : x) meanx += v;\n        meanx = (meanx > 0 ? meanx / N : 1.0);\n        for (double &v : x) v /= meanx;\n\n        double lambda = 1e-3; // L2\n        double Lg = 0.25 * (double)N * (double)M + 2.0 * lambda; // rough Lipschitz\n        double eta = 1.0 / Lg;\n        int iters = min(250, max(80, M / 4));\n\n        vector<double> grad(N, 0.0);\n        const int8_t* Adata = Aflat.data();\n\n        for (int it = 0; it < iters; it++) {\n            fill(grad.begin(), grad.end(), 0.0);\n            for (int r = 0; r < M; r++) {\n                const int8_t* row = Adata + (size_t)r * N;\n                int8_t yr = Y[r];\n                double s = 0.0;\n                for (int i = 0; i < N; i++) s += (double)row[i] * x[i];\n                // p = - y * sigma(-y s)\n                double ys = (double)yr * s;\n                double p;\n                if (ys >= 0) {\n                    double e = exp(-ys);\n                    p = -(double)yr * (e / (1.0 + e));\n                } else {\n                    double e = exp(ys);\n                    p = -(double)yr * (1.0 / (1.0 + e));\n                }\n                for (int i = 0; i < N; i++) grad[i] += p * (double)row[i];\n            }\n            for (int i = 0; i < N; i++) {\n                grad[i] += 2.0 * lambda * x[i];\n                x[i] -= eta * grad[i];\n                if (x[i] < 1e-12) x[i] = 1e-12; // nonnegativity\n            }\n        }\n        w.swap(x);\n    }\n\n    // LPT initialization\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng); // random tie-break\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){ return w[i] > w[j]; });\n\n    vector<int> assign(N, -1);\n    vector<double> binSum(D, 0.0);\n    vector<vector<int>> bins(D);\n    for (int idx : ord) {\n        int best = 0;\n        double bestSum = binSum[0];\n        for (int b = 1; b < D; b++) {\n            if (binSum[b] < bestSum) {\n                bestSum = binSum[b];\n                best = b;\n            }\n        }\n        assign[idx] = best;\n        binSum[best] += w[idx];\n        bins[best].push_back(idx);\n    }\n\n    // Local search: single moves to lightest bin and pair swaps across all heavy-light bin pairs\n    Timer timer;\n    const double TIME_BUDGET = 0.35; // seconds\n\n    auto recompute_light_heavy = [&](){\n        int l = 0, h = 0;\n        for (int b = 1; b < D; b++) {\n            if (binSum[b] < binSum[l]) l = b;\n            if (binSum[b] > binSum[h]) h = b;\n        }\n        return pair<int,int>(l,h);\n    };\n\n    while (true) {\n        if (timer.elapsed() > TIME_BUDGET) break;\n\n        auto [lbin, hbin] = recompute_light_heavy();\n        double best_delta = 0.0;\n        int from_b = -1, item_pos = -1, item_id = -1;\n\n        // Single moves from any bin to the current lightest bin\n        for (int b = 0; b < D; b++) {\n            if (b == lbin) continue;\n            double gap = binSum[b] - binSum[lbin];\n            if (gap <= 1e-12) continue;\n            double target = 0.5 * gap;\n            for (int pos = 0; pos < (int)bins[b].size(); pos++) {\n                int i = bins[b][pos];\n                double wi = w[i];\n                if (wi < gap) {\n                    double delta = -2.0 * wi * gap + 2.0 * wi * wi; // change in s_b^2 + s_l^2\n                    if (from_b == -1 || delta < best_delta - 1e-15 ||\n                        (fabs(delta - best_delta) <= 1e-15 && fabs(wi - target) < fabs(w[item_id] - target))) {\n                        best_delta = delta;\n                        from_b = b;\n                        item_pos = pos;\n                        item_id = i;\n                    }\n                }\n            }\n        }\n        if (from_b != -1 && best_delta < -1e-12) {\n            // Perform best single move\n            bins[from_b].erase(bins[from_b].begin() + item_pos);\n            bins[lbin].push_back(item_id);\n            assign[item_id] = lbin;\n            binSum[from_b] -= w[item_id];\n            binSum[lbin] += w[item_id];\n            continue;\n        }\n\n        // Pair swaps across heavier-lighter pairs\n        double best_swap_delta = 0.0;\n        int b_h = -1, b_l = -1, pos_i = -1, pos_j = -1;\n        int id_i = -1, id_j = -1;\n        for (int bh = 0; bh < D; bh++) {\n            for (int bl = 0; bl < D; bl++) {\n                if (binSum[bh] <= binSum[bl] + 1e-12) continue;\n                double gap = binSum[bh] - binSum[bl];\n                double target = 0.5 * gap;\n                for (int pi = 0; pi < (int)bins[bh].size(); pi++) {\n                    int i = bins[bh][pi];\n                    double wi = w[i];\n                    for (int pj = 0; pj < (int)bins[bl].size(); pj++) {\n                        int j = bins[bl][pj];\n                        double wj = w[j];\n                        double d = wi - wj;\n                        if (d <= 1e-12 || d >= gap - 1e-12) continue;\n                        double delta = 2.0 * (d * d - d * gap); // change in s_h^2 + s_l^2\n                        if (b_h == -1 || delta < best_swap_delta - 1e-15 ||\n                            (fabs(delta - best_swap_delta) <= 1e-15 && fabs(d - target) < fabs((w[id_i] - w[id_j]) - target))) {\n                            best_swap_delta = delta;\n                            b_h = bh; b_l = bl;\n                            pos_i = pi; pos_j = pj;\n                            id_i = i; id_j = j;\n                        }\n                    }\n                }\n            }\n        }\n        if (b_h != -1 && best_swap_delta < -1e-12) {\n            // Perform swap\n            bins[b_h].erase(bins[b_h].begin() + pos_i);\n            bins[b_l].erase(bins[b_l].begin() + pos_j);\n            bins[b_h].push_back(id_j);\n            bins[b_l].push_back(id_i);\n            assign[id_i] = b_l; assign[id_j] = b_h;\n            double wi = w[id_i], wj = w[id_j];\n            binSum[b_h] += (wj - wi);\n            binSum[b_l] += (wi - wj);\n            continue;\n        }\n\n        // No improving move/swap\n        break;\n    }\n\n    // Output final assignment\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << assign[i];\n    }\n    cout << '\\n' << flush;\n\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Heuristic solver with destination scoring by min-below and improved, safe splitting.\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    if (!(cin >> n >> m)) return 0;\n    vector<vector<int>> st(m); // bottom -> top\n    int per = n / m;\n    for (int i = 0; i < m; ++i) {\n        st[i].resize(per);\n        for (int j = 0; j < per; ++j) cin >> st[i][j];\n    }\n\n    const int INF = n + 1;\n    vector<pair<int,int>> ops;\n    ops.reserve(3000);\n\n    auto get_min_stack = [&](int idx)->int{\n        if (st[idx].empty()) return INF;\n        int mn = st[idx][0];\n        for (int v : st[idx]) if (v < mn) mn = v;\n        return mn;\n    };\n\n    auto carry_chain = [&](int &t) {\n        bool changed = true;\n        while (changed && t <= n) {\n            changed = false;\n            for (int i = 0; i < m && t <= n; ++i) {\n                if (!st[i].empty() && st[i].back() == t) {\n                    st[i].pop_back();\n                    ops.emplace_back(t, 0);\n                    ++t;\n                    changed = true;\n                }\n            }\n        }\n    };\n\n    auto move_suffix = [&](int src, int start_idx, int dest) {\n        // Move st[src][start_idx..end] to top of st[dest]\n        int S = (int)st[src].size();\n        if (!(0 <= start_idx && start_idx < S)) return; // safety\n        for (int k = start_idx; k < S; ++k) {\n            st[dest].push_back(st[src][k]);\n        }\n        st[src].resize(start_idx);\n    };\n\n    auto find_box = [&](int v, int &src, int &idx) {\n        src = -1; idx = -1;\n        for (int i = 0; i < m; ++i) {\n            for (int j = (int)st[i].size() - 1; j >= 0; --j) {\n                if (st[i][j] == v) { src = i; idx = j; return; }\n            }\n        }\n    };\n\n    auto choose_dest_minPrefix = [&](int src, int jv, int exclude1=-1, int exclude2=-1) -> int {\n        // Score candidates by how many from the block top are < min(old dest content).\n        int s = (int)st[src].size() - jv;\n        vector<int> topDown;\n        topDown.reserve(s);\n        for (int k = (int)st[src].size() - 1; k >= jv; --k) topDown.push_back(st[src][k]);\n\n        int bestD = -1;\n        int bestPrefix = -1;\n        int bestM = -1;\n        int bestTop = -1;\n        int bestNegSize = 0; // prefer smaller size\n        for (int d = 0; d < m; ++d) {\n            if (d == src || d == exclude1 || d == exclude2) continue;\n            int M = get_min_stack(d);\n            int prefix = 0;\n            while (prefix < s && topDown[prefix] < M) ++prefix; // strictly less than M\n\n            int topVal = st[d].empty() ? INF : st[d].back();\n            int negSize = - (int)st[d].size();\n\n            // tie-breakers: larger prefix, then larger M, then larger topVal, then smaller size\n            if (prefix > bestPrefix ||\n                (prefix == bestPrefix && (M > bestM ||\n                 (M == bestM && (topVal > bestTop ||\n                  (topVal == bestTop && negSize > bestNegSize)))))) {\n                bestPrefix = prefix;\n                bestM = M;\n                bestTop = topVal;\n                bestNegSize = negSize;\n                bestD = d;\n            }\n        }\n        if (bestD == -1) {\n            // fallback respecting excludes\n            for (int d = 0; d < m; ++d) {\n                if (d != src && d != exclude1 && d != exclude2) { bestD = d; break; }\n            }\n        }\n        return bestD;\n    };\n\n    auto choose_heavy_dest = [&](int src, int avoid)->int{\n        // For the heavy segment, prefer destination with large min (M) and large top.\n        int bestD = -1;\n        int bestM = -1;\n        int bestTop = -1;\n        int bestNegSize = 0;\n        for (int d = 0; d < m; ++d) {\n            if (d == src || d == avoid) continue;\n            int M = get_min_stack(d);\n            int topVal = st[d].empty() ? INF : st[d].back();\n            int negSize = - (int)st[d].size();\n            if (M > bestM || (M == bestM && (topVal > bestTop ||\n                 (topVal == bestTop && negSize > bestNegSize)))) {\n                bestM = M;\n                bestTop = topVal;\n                bestNegSize = negSize;\n                bestD = d;\n            }\n        }\n        if (bestD == -1) {\n            for (int d = 0; d < m; ++d) {\n                if (d != src && d != avoid) { bestD = d; break; }\n            }\n        }\n        return bestD;\n    };\n\n    auto attempt_split_then_move = [&](int src, int idx) -> bool {\n        // Try to split the above-block to create a good prefix >= 2 for the remainder on a good destination.\n        int jv = idx + 1;\n        int s = (int)st[src].size() - jv;\n        if (s <= 1) return false;\n\n        // Block top-down\n        vector<int> topDown;\n        topDown.reserve(s);\n        for (int k = (int)st[src].size() - 1; k >= jv; --k) topDown.push_back(st[src][k]);\n\n        // Choose best destination for the remainder\n        int destBest = choose_dest_minPrefix(src, jv);\n        if (destBest == -1) return false;\n        int Mbest = get_min_stack(destBest);\n\n        // Compute overall best-prefix for this dest; if already good (>=2), no need to split\n        int bestPrefix = 0;\n        while (bestPrefix < s && topDown[bestPrefix] < Mbest) ++bestPrefix;\n        if (bestPrefix >= 2) return false;\n\n        // Compute split point r: number of top elements >= Mbest\n        int r = 0;\n        while (r < s && topDown[r] >= Mbest) ++r;\n        if (r >= s) return false; // no \"good\" part\n        // Count consecutive \"good\" elements after r\n        int p = 0;\n        while (r + p < s && topDown[r + p] < Mbest) ++p;\n\n        // Require at least 2 good elements to justify an extra move AND r > 0 to move a non-empty heavy segment\n        if (p < 2 || r == 0) return false;\n\n        // Choose destination for the heavy top segment\n        int heavyDest = choose_heavy_dest(src, destBest);\n        if (heavyDest == -1) return false;\n\n        // First move: heavy top segment of size r to heavyDest\n        int startA = (int)st[src].size() - r; // start index of top r segment\n        if (!(0 <= startA && startA < (int)st[src].size())) return false; // safety\n        int vA = st[src][startA];\n        move_suffix(src, startA, heavyDest);\n        ops.emplace_back(vA, heavyDest + 1);\n\n        // Second move: remainder above t to a good destination (avoid heavyDest)\n        int new_jv = idx + 1;\n        if (!(0 <= new_jv && new_jv < (int)st[src].size())) {\n            // If nothing remains above t, no second move is needed\n            return true;\n        }\n        int dest2 = choose_dest_minPrefix(src, new_jv, heavyDest, -1);\n        if (dest2 == -1) {\n            // As a last resort, put it back onto best dest\n            dest2 = destBest;\n        }\n        int vB = st[src][new_jv];\n        move_suffix(src, new_jv, dest2);\n        ops.emplace_back(vB, dest2 + 1);\n\n        return true;\n    };\n\n    int t = 1;\n    carry_chain(t);\n\n    while (t <= n) {\n        int src, idx;\n        find_box(t, src, idx);\n        if (src == -1) break; // shouldn't happen\n\n        if (idx == (int)st[src].size() - 1) {\n            // Already top\n            st[src].pop_back();\n            ops.emplace_back(t, 0);\n            ++t;\n            carry_chain(t);\n            continue;\n        }\n\n        // Try improved, safe split\n        if (attempt_split_then_move(src, idx)) {\n            carry_chain(t);\n            continue;\n        }\n\n        // Normal: move whole suffix with destination chosen by min-prefix\n        int jv = idx + 1;\n        int dest = choose_dest_minPrefix(src, jv);\n        if (dest == -1) {\n            // Fallback: choose any stack != src\n            for (int d = 0; d < m; ++d) if (d != src) { dest = d; break; }\n        }\n        int v = st[src][jv];\n        move_suffix(src, jv, dest);\n        ops.emplace_back(v, dest + 1);\n\n        carry_chain(t);\n    }\n\n    if ((int)ops.size() > 5000) {\n        // Should not happen\n        ops.resize(5000);\n    }\n    for (auto &op : ops) {\n        cout << op.first << ' ' << op.second << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    unsigned long long x;\n    XorShift64(unsigned long long seed=88172645463393265ULL){x=seed;}\n    unsigned long long next() { x ^= x<<7; x ^= x>>9; return x; }\n    unsigned int nextUInt() { return (unsigned int)(next() & 0xFFFFFFFFULL); }\n};\n\nstruct UEdge {\n    int u, v;\n    char ch_uv, ch_vu;\n};\n\nstruct AdjPort {\n    int to;\n    int eid;\n    char ch;\n    long long target; // departures from this node along this edge\n    long long used;   // used departures\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<string> hWall(max(0, N-1));\n    for (int i = 0; i < N-1; i++) cin >> hWall[i];\n    vector<string> vWall(N);\n    for (int i = 0; i < N; i++) cin >> vWall[i];\n    vector<vector<int>> d(N, vector<int>(N));\n    long long Dsum_ll = 0;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) { cin >> d[i][j]; Dsum_ll += d[i][j]; }\n    long double Dsum = (long double)Dsum_ll;\n\n    auto inb = [&](int i, int j) -> bool { return (0 <= i && i < N && 0 <= j && j < N); };\n    auto canMove = [&](int i, int j, int di, int dj) -> bool {\n        int ni = i + di, nj = j + dj;\n        if (!inb(ni, nj)) return false;\n        if (di == 0 && dj == 1) { // right\n            return vWall[i][j] == '0';\n        } else if (di == 0 && dj == -1) { // left\n            return vWall[i][j-1] == '0';\n        } else if (di == 1 && dj == 0) { // down\n            return hWall[i][j] == '0';\n        } else if (di == -1 && dj == 0) { // up\n            return hWall[i-1][j] == '0';\n        }\n        return false;\n    };\n    auto id = [&](int i, int j) { return i * N + j; };\n    auto coord = [&](int v) { return pair<int,int>(v / N, v % N); };\n\n    int V = N * N;\n    int root = 0;\n\n    // Build undirected grid edges (unique)\n    vector<UEdge> edges; edges.reserve(2*N*(N-1));\n    vector<vector<pair<int,int>>> nodeNbrEid(V); // (neighbor, eid)\n    auto add_edge = [&](int u, int v, char ch_uv, char ch_vu){\n        UEdge e{u,v,ch_uv,ch_vu};\n        int eid = (int)edges.size();\n        edges.push_back(e);\n        nodeNbrEid[u].push_back({v, eid});\n        nodeNbrEid[v].push_back({u, eid});\n    };\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int u = id(i,j);\n        if (j+1 < N && canMove(i,j,0,1)) {\n            int v = id(i, j+1);\n            add_edge(u, v, 'R', 'L');\n        }\n        if (i+1 < N && canMove(i,j,1,0)) {\n            int v = id(i+1, j);\n            add_edge(u, v, 'D', 'U');\n        }\n    }\n    int M = (int)edges.size();\n\n    // Build full directed adjacency (for BFS distance and candidate parents)\n    vector<vector<int>> adjGrid(V);\n    for (int i = 0; i < V; i++) {\n        for (auto [to, eid] : nodeNbrEid[i]) adjGrid[i].push_back(to);\n    }\n\n    // BFS distances\n    vector<int> dist(V, -1);\n    deque<int> dq;\n    dist[root] = 0; dq.push_back(root);\n    while (!dq.empty()) {\n        int u = dq.front(); dq.pop_front();\n        for (int v : adjGrid[u]) if (dist[v] == -1) { dist[v] = dist[u] + 1; dq.push_back(v); }\n    }\n    int maxDist = 0;\n    for (int v = 0; v < V; v++) if (dist[v] > maxDist) maxDist = dist[v];\n\n    // Candidate parents: neighbors at dist-1\n    vector<vector<int>> candPar(V);\n    for (int v = 0; v < V; v++) {\n        if (v == root) continue;\n        for (int u : adjGrid[v]) if (dist[u] == dist[v] - 1) candPar[v].push_back(u);\n    }\n    vector<vector<int>> layers(maxDist+1);\n    for (int v = 0; v < V; v++) layers[dist[v]].push_back(v);\n\n    // Balanced shortest-path tree builder for given weights\n    auto build_par_balanced = [&](const vector<long double>& w) -> vector<int> {\n        vector<int> par(V, -1);\n        vector<int> rootBranch(V, -1);\n        vector<long double> load(V, 0.0L);      // cumulative subtree weight\n        vector<long double> branchLoad(V, 0.0L); // total weight per root child branch\n        vector<int> childCnt(V, 0);\n\n        // layer 1\n        for (int v : layers[1]) {\n            par[v] = root;\n            rootBranch[v] = v;\n            load[root] += w[v];\n            branchLoad[v] += w[v];\n            childCnt[root]++;\n        }\n        // layers >= 2\n        for (int L = 2; L <= maxDist; L++) {\n            for (int v : layers[L]) {\n                long double best1 = 1e300L, best2 = 1e300L;\n                int best3 = INT_MAX, bestP = candPar[v][0];\n                for (int p : candPar[v]) {\n                    int b = rootBranch[p];\n                    long double key1 = branchLoad[b];\n                    long double key2 = load[p];\n                    int key3 = childCnt[p];\n                    if (key1 < best1 - 1e-18L ||\n                       (fabsl(key1 - best1) <= 1e-18L && (key2 < best2 - 1e-18L ||\n                        (fabsl(key2 - best2) <= 1e-18L && (key3 < best3 ||\n                         (key3 == best3 && p < bestP)))))) {\n                        best1 = key1; best2 = key2; best3 = key3; bestP = p;\n                    }\n                }\n                int p = bestP;\n                par[v] = p;\n                int b = rootBranch[p];\n                rootBranch[v] = b;\n                // update loads along path p -> root\n                int u = p;\n                while (u != -1) {\n                    load[u] += w[v];\n                    u = par[u];\n                }\n                branchLoad[b] += w[v];\n                childCnt[p]++;\n            }\n        }\n        return par;\n    };\n\n    const long long Lmax = 100000;\n\n    // Parameter candidates for weights: w_i = sqrt(d_i) / (dist_i + gamma)^beta\n    struct Param { long double beta, gamma; };\n    vector<Param> params = {\n        {0.5L, 0.0L},\n        {0.3L, 0.0L},\n        {0.5L, 0.5L}\n    };\n\n    // Select base tree by proxy score on base multiplicity (tree edges doubled)\n    vector<int> best_par;\n    long double best_score = numeric_limits<long double>::infinity();\n    for (auto prm : params) {\n        vector<long double> w(V, 0.0L);\n        for (int v = 0; v < V; v++) {\n            auto [i,j] = coord(v);\n            long double dd = (long double)d[i][j];\n            long double base = sqrtl(max(0.0L, dd));\n            long double dep = (long double)dist[v] + prm.gamma;\n            if (v == root) dep = 1.0L + prm.gamma;\n            if (prm.beta > 0.0L) w[v] = base / powl(max(1e-12L, dep), prm.beta);\n            else w[v] = base;\n        }\n        vector<int> par = build_par_balanced(w);\n\n        // Evaluate base proxy\n        vector<long long> deg(V, 0);\n        long long L0 = 0;\n        for (int v = 0; v < V; v++) if (v != root) {\n            deg[v] += 2;\n            deg[par[v]] += 2;\n            L0 += 2;\n        }\n        vector<long long> k(V, 1);\n        long double Ad0 = 0.0L;\n        for (int v = 0; v < V; v++) {\n            long long kv = max(1LL, deg[v] / 2);\n            k[v] = kv;\n            auto [i,j] = coord(v);\n            Ad0 += (long double)d[i][j] / (long double)kv;\n        }\n        long double score = 0.5L * ((long double)L0 * Ad0 - Dsum);\n        if (score < best_score) {\n            best_score = score;\n            best_par = move(par);\n        }\n    }\n    vector<int> par = best_par;\n\n    // Build base multiplicities: tree edges doubled (m_e += 2)\n    vector<long long> m(M, 0);\n    vector<long long> deg(V, 0);\n    long long L = 0;\n    auto find_eid = [&](int a, int b)->int{\n        for (auto [to, eid] : nodeNbrEid[a]) if (to == b) return eid;\n        return -1;\n    };\n    for (int v = 0; v < V; v++) if (v != root) {\n        int p = par[v];\n        int eid = find_eid(v, p);\n        if (eid < 0) {\n            // shouldn't happen in a valid grid input\n            continue;\n        }\n        m[eid] += 2;\n        deg[v] += 2;\n        deg[p] += 2;\n        L += 2;\n    }\n\n    // Initial k and Ad\n    vector<long long> k(V, 1);\n    long double Ad = 0.0L;\n    for (int v = 0; v < V; v++) {\n        long long kv = max(1LL, deg[v] / 2);\n        k[v] = kv;\n        auto [i,j] = coord(v);\n        Ad += (long double)d[i][j] / (long double)kv;\n    }\n\n    // Priority queue for edge-based greedy fill\n    struct Item {\n        long double val; // d[u]/(ku(ku+1)) + d[v]/(kv(kv+1))\n        int eid;\n        int ku, kv;\n        bool operator<(Item const& other) const {\n            return val < other.val;\n        }\n    };\n    vector<int> eu(M), ev(M);\n    vector<char> ch_uv(M), ch_vu(M);\n    for (int eid = 0; eid < M; eid++) {\n        eu[eid] = edges[eid].u; ev[eid] = edges[eid].v;\n        ch_uv[eid] = edges[eid].ch_uv; ch_vu[eid] = edges[eid].ch_vu;\n    }\n\n    auto val_for_edge = [&](int eid)->long double{\n        int u = eu[eid], v = ev[eid];\n        auto [ui, uj] = coord(u);\n        auto [vi, vj] = coord(v);\n        long double du = (long double)d[ui][uj];\n        long double dv = (long double)d[vi][vj];\n        long double ku0 = (long double)k[u];\n        long double kv0 = (long double)k[v];\n        // if ku0 or kv0 is zero (should not happen), guard\n        if (ku0 <= 0.5L) ku0 = 1.0L;\n        if (kv0 <= 0.5L) kv0 = 1.0L;\n        return du / (ku0 * (ku0 + 1.0L)) + dv / (kv0 * (kv0 + 1.0L));\n    };\n\n    priority_queue<Item> pq;\n    for (int eid = 0; eid < M; eid++) {\n        int u = eu[eid], v = ev[eid];\n        Item it;\n        it.eid = eid;\n        it.ku = (int)k[u];\n        it.kv = (int)k[v];\n        it.val = val_for_edge(eid);\n        pq.push(it);\n    }\n\n    long long remLen = Lmax - L;\n    const long double eps = 1e-18L;\n\n    // Precompute incident edge lists for quick updates\n    vector<vector<int>> incEdges(V);\n    for (int eid = 0; eid < M; eid++) {\n        incEdges[eu[eid]].push_back(eid);\n        incEdges[ev[eid]].push_back(eid);\n    }\n\n    while (remLen >= 2 && !pq.empty()) {\n        Item it = pq.top(); pq.pop();\n        int eid = it.eid;\n        int u = eu[eid], v = ev[eid];\n        // lazy validation\n        if (it.ku != (int)k[u] || it.kv != (int)k[v]) {\n            Item nit;\n            nit.eid = eid;\n            nit.ku = (int)k[u];\n            nit.kv = (int)k[v];\n            nit.val = val_for_edge(eid);\n            pq.push(nit);\n            continue;\n        }\n        long double theta = 2.0L * Ad / ((long double)L + 2.0L);\n        if (it.val <= theta + eps) break; // no beneficial addition remains\n        if (remLen < 2) break;\n\n        // Apply: add 2 to edge eid\n        long long ku_old = k[u], kv_old = k[v];\n        m[eid] += 2;\n        deg[u] += 2; deg[v] += 2;\n        k[u] += 1; k[v] += 1;\n        L += 2;\n        remLen -= 2;\n\n        // Update Ad\n        auto [ui, uj] = coord(u);\n        auto [vi, vj] = coord(v);\n        long double du = (long double)d[ui][uj];\n        long double dv = (long double)d[vi][vj];\n        Ad += du * (1.0L / (long double)k[u] - 1.0L / (long double)ku_old);\n        Ad += dv * (1.0L / (long double)k[v] - 1.0L / (long double)kv_old);\n\n        // Update incident edges around u and v\n        for (int e2 : incEdges[u]) {\n            Item nit;\n            nit.eid = e2;\n            int a = eu[e2], b = ev[e2];\n            nit.ku = (int)k[a];\n            nit.kv = (int)k[b];\n            nit.val = val_for_edge(e2);\n            pq.push(nit);\n        }\n        for (int e2 : incEdges[v]) {\n            Item nit;\n            nit.eid = e2;\n            int a = eu[e2], b = ev[e2];\n            nit.ku = (int)k[a];\n            nit.kv = (int)k[b];\n            nit.val = val_for_edge(e2);\n            pq.push(nit);\n        }\n    }\n\n    // Build adjacency ports for Euler traversal (only edges with m[eid] > 0)\n    vector<vector<AdjPort>> ports(V);\n    ports.assign(V, {});\n    vector<long long> rem(m); // remaining multiplicities\n    for (int eid = 0; eid < M; eid++) if (m[eid] > 0) {\n        int u = eu[eid], v = ev[eid];\n        long long tgt = m[eid] / 2;\n        ports[u].push_back(AdjPort{v, eid, ch_uv[eid], tgt, 0});\n        ports[v].push_back(AdjPort{u, eid, ch_vu[eid], tgt, 0});\n    }\n\n    // Weighted round-robin Euler traversal\n    XorShift64 rng(123456789ULL);\n    vector<int> st; st.reserve(L+5);\n    vector<int> out; out.reserve(L+5);\n    st.push_back(root);\n    while (!st.empty()) {\n        int v = st.back();\n        int bestIdx = -1;\n        long double bestKey = 1e100L;\n        long long bestRem = -1;\n        for (int idx = 0; idx < (int)ports[v].size(); idx++) {\n            int eid = ports[v][idx].eid;\n            if (rem[eid] <= 0) continue;\n            long double t = (long double)ports[v][idx].target;\n            long double uused = (long double)ports[v][idx].used;\n            long double noise = (long double)( (rng.nextUInt() & 1023U) ) * 1e-6L;\n            long double key = (t > 0.0L) ? ( (uused + noise) / t ) : noise;\n            if (key < bestKey - 1e-15L || (fabsl(key - bestKey) <= 1e-15L && rem[eid] > bestRem)) {\n                bestKey = key;\n                bestIdx = idx;\n                bestRem = rem[eid];\n            }\n        }\n        if (bestIdx != -1) {\n            int eid = ports[v][bestIdx].eid;\n            int to = ports[v][bestIdx].to;\n            rem[eid]--;\n            ports[v][bestIdx].used++;\n            st.push_back(to);\n        } else {\n            out.push_back(v);\n            st.pop_back();\n        }\n    }\n    reverse(out.begin(), out.end());\n\n    // Build move string\n    string ans;\n    ans.reserve(out.size() ? out.size()-1 : 0);\n    for (size_t i = 0; i + 1 < out.size(); i++) {\n        int a = out[i], b = out[i+1];\n        // find edge to get char\n        char ch = '?';\n        for (auto &pp : ports[a]) if (pp.to == b) { ch = pp.ch; break; }\n        if (ch == '?') {\n            // fallback by coords\n            auto [ai, aj] = coord(a);\n            auto [bi, bj] = coord(b);\n            if (bi == ai && bj == aj + 1) ch = 'R';\n            else if (bi == ai && bj == aj - 1) ch = 'L';\n            else if (bi == ai + 1 && bj == aj) ch = 'D';\n            else if (bi == ai - 1 && bj == aj) ch = 'U';\n            else ch = 'U';\n        }\n        ans.push_back(ch);\n    }\n\n    if ((int)ans.size() > (int)Lmax) ans.resize((size_t)Lmax);\n    cout << ans << '\\n';\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, r;\n    DSU(int n=0): n(n), p(n), r(n,0) { iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n    bool same(int a, int b){ return find(a)==find(b); }\n    bool unite(int a, int b){\n        a = find(a); b = find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n};\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed=88172645463393265ull){ x=seed; }\n    uint64_t next(){\n        x ^= x<<7;\n        x ^= x>>9;\n        return x;\n    }\n    int next_int(int l, int r){ // inclusive\n        return l + (int)(next() % (uint64_t)(r-l+1));\n    }\n    double next_double(){ return (next() >> 11) * (1.0 / (1ull<<53)); }\n};\n\nstruct Pos { short i, j; };\n\nstatic inline int manhattan(const Pos& a, const Pos& b){\n    return abs(a.i - b.i) + abs(a.j - b.j);\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if(!(cin >> N >> M)) return 0; // N=15, M=200\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> A(N);\n    for(int i=0;i<N;i++) cin >> A[i];\n    vector<string> t(M);\n    for(int k=0;k<M;k++) cin >> t[k];\n\n    auto time_start = chrono::high_resolution_clock::now();\n    auto elapsed = [&](){\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - time_start).count();\n    };\n    const double TIME_LIMIT = 1.95;\n\n    XorShift rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Positions per letter\n    vector<vector<Pos>> pos(26);\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            int c = A[i][j]-'A';\n            pos[c].push_back(Pos{(short)i,(short)j});\n        }\n    }\n\n    // Start distance per letter\n    vector<int> startDist(26, INT_MAX/4);\n    for(int c=0;c<26;c++){\n        for(auto &p : pos[c]){\n            startDist[c] = min(startDist[c], abs(p.i - si) + abs(p.j - sj));\n        }\n        if(startDist[c] == INT_MAX/4) startDist[c] = 20; // safety\n    }\n\n    // Letter-to-letter proxy distance: average of K smallest distances\n    const int K_MIN = 3;\n    vector<vector<double>> dLL(26, vector<double>(26, 0.0));\n    for(int a=0;a<26;a++){\n        for(int b=0;b<26;b++){\n            vector<int> ds;\n            ds.reserve(pos[a].size() * pos[b].size());\n            for(auto &pa : pos[a]){\n                for(auto &pb : pos[b]){\n                    ds.push_back(abs(pa.i - pb.i) + abs(pa.j - pb.j));\n                }\n            }\n            if(ds.empty()){\n                dLL[a][b] = 8.0; // fallback\n            }else{\n                int cnt = min((int)ds.size(), K_MIN);\n                nth_element(ds.begin(), ds.begin()+cnt-1, ds.end());\n                sort(ds.begin(), ds.begin()+cnt);\n                double s=0;\n                for(int i=0;i<cnt;i++) s += ds[i];\n                dLL[a][b] = s / cnt;\n            }\n        }\n    }\n\n    // Overlap matrix f[i][j] in [0..4]\n    auto overlap = [&](const string& a, const string& b)->int{\n        for(int k=4;k>=1;k--){\n            bool ok = true;\n            for(int x=0;x<k;x++){\n                if(a[5-k+x] != b[x]){ ok=false; break; }\n            }\n            if(ok) return k;\n        }\n        return 0;\n    };\n    vector<vector<int>> f(M, vector<int>(M, 0));\n    for(int i=0;i<M;i++){\n        for(int j=0;j<M;j++){\n            if(i==j) continue;\n            f[i][j] = overlap(t[i], t[j]);\n        }\n    }\n\n    // Word letters\n    vector<array<int,5>> wlett(M);\n    for(int i=0;i<M;i++){\n        for(int k=0;k<5;k++) wlett[i][k] = t[i][k] - 'A';\n    }\n\n    // Intra-word suffix proxy movement costs for each possible overlap ov (0..4)\n    vector<array<double,5>> intraSuf(M);\n    for(int j=0;j<M;j++){\n        double pref[6]={0};\n        pref[0]=0;\n        for(int k=0;k<4;k++){\n            int a = wlett[j][k], b = wlett[j][k+1];\n            pref[k+1] = pref[k] + dLL[a][b];\n        }\n        for(int ov=0; ov<=4; ov++){\n            intraSuf[j][ov] = pref[4] - pref[ov];\n        }\n    }\n\n    // Estimated edge weights (maximize) and start weights\n    vector<vector<double>> W_est(M, vector<double>(M, -1e100));\n    vector<double> Wstart(M, 0.0);\n    for(int i=0;i<M;i++){\n        for(int j=0;j<M;j++){\n            if(i==j){ W_est[i][j] = -1e100; continue; }\n            int ov = f[i][j];\n            int lastc = wlett[i][4];\n            int firstNew = wlett[j][ov];\n            double boundary = dLL[lastc][firstNew];\n            double c = (5 - ov) + boundary + intraSuf[j][ov];\n            W_est[i][j] = -c;\n        }\n    }\n    for(int i=0;i<M;i++){\n        double c = 5.0 + startDist[wlett[i][0]] + intraSuf[i][0];\n        Wstart[i] = -c;\n    }\n\n    // Overlap sum for sequence\n    auto sum_overlaps = [&](const vector<int>& pi)->int{\n        int s=0;\n        for(int i=0;i+1<(int)pi.size();i++) s += f[pi[i]][pi[i+1]];\n        return s;\n    };\n\n    // Initial construction: arc packing using overlaps\n    auto build_by_arc_packing = [&]()->vector<int>{\n        struct Arc { int u, v; int w; uint64_t r; };\n        vector<Arc> arcs;\n        arcs.reserve((size_t)M*(M-1));\n        for(int i=0;i<M;i++){\n            for(int j=0;j<M;j++){\n                if(i==j) continue;\n                arcs.push_back({ i, j, f[i][j], (uint64_t)rng.next() });\n            }\n        }\n        sort(arcs.begin(), arcs.end(), [](const Arc& a, const Arc& b){\n            if(a.w != b.w) return a.w > b.w;\n            return a.r < b.r;\n        });\n        vector<int> succ(M, -1), pred(M, -1);\n        DSU uf(M);\n        for(const auto& e : arcs){\n            int u=e.u, v=e.v;\n            if(succ[u]!=-1) continue;\n            if(pred[v]!=-1) continue;\n            if(uf.same(u, v)) continue; // avoid cycle\n            succ[u]=v;\n            pred[v]=u;\n            uf.unite(u, v);\n        }\n        // Extract chains\n        vector<char> used(M, 0);\n        vector<vector<int>> chains;\n        for(int i=0;i<M;i++){\n            if(pred[i]==-1){ // head\n                vector<int> chain;\n                int cur=i;\n                while(cur!=-1){\n                    chain.push_back(cur);\n                    used[cur]=1;\n                    cur = succ[cur];\n                }\n                chains.push_back(move(chain));\n            }\n        }\n        for(int i=0;i<M;i++){\n            if(!used[i]){\n                chains.push_back(vector<int>{i});\n                used[i]=1;\n            }\n        }\n        int Cn = (int)chains.size();\n        vector<int> head(Cn), tail(Cn);\n        for(int c=0;c<Cn;c++){\n            head[c] = chains[c].front();\n            tail[c] = chains[c].back();\n        }\n        // Choose start chain with worst incoming overlap\n        vector<int> inBest(Cn, 0);\n        for(int j=0;j<Cn;j++){\n            int best=0;\n            for(int i=0;i<Cn;i++){\n                if(i==j) continue;\n                best = max(best, f[tail[i]][head[j]]);\n            }\n            inBest[j]=best;\n        }\n        int start = 0;\n        int minIn = INT_MAX;\n        for(int j=0;j<Cn;j++){\n            if(inBest[j] < minIn){\n                minIn = inBest[j];\n                start = j;\n            }\n        }\n        vector<char> usedC(Cn,0);\n        vector<int> order; order.reserve(Cn);\n        int cur = start; usedC[cur]=1; order.push_back(cur);\n        for(int step=1; step<Cn; step++){\n            int bestW=-1, bestJ=-1;\n            for(int j=0;j<Cn;j++){\n                if(usedC[j]) continue;\n                int w = f[tail[cur]][head[j]];\n                if(w>bestW){ bestW=w; bestJ=j; }\n            }\n            if(bestJ==-1){\n                for(int j=0;j<Cn;j++){ if(!usedC[j]){ bestJ=j; break; } }\n            }\n            usedC[bestJ]=1;\n            order.push_back(bestJ);\n            cur = bestJ;\n        }\n        vector<int> pi;\n        pi.reserve(M);\n        for(int idx : order){\n            for(int node : chains[idx]) pi.push_back(node);\n        }\n        return pi;\n    };\n\n    // Nearest-neighbor on overlaps\n    auto build_by_nn = [&](int s)->vector<int>{\n        vector<char> used(M,0);\n        vector<int> pi; pi.reserve(M);\n        int cur = s; used[cur]=1; pi.push_back(cur);\n        for(int k=1;k<M;k++){\n            int bestW=-1, bestJ=-1;\n            for(int j=0;j<M;j++){\n                if(used[j]) continue;\n                int w = f[cur][j];\n                if(w>bestW){ bestW=w; bestJ=j; }\n            }\n            if(bestJ==-1){\n                for(int j=0;j<M;j++){ if(!used[j]){ bestJ=j; break; } }\n            }\n            used[bestJ]=1;\n            pi.push_back(bestJ);\n            cur = bestJ;\n        }\n        return pi;\n    };\n\n    // Overlap insertion LS (simple)\n    auto insertion_ls_overlap = [&](vector<int>& p, double time_budget_sec){\n        int n = p.size();\n        auto getEdge = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        auto compute_insert_delta = [&](int i, int j2)->int{\n            int N = n;\n            int x = p[i];\n            int delta = 0;\n            if(i == 0){\n                if(N >= 2){\n                    delta -= getEdge(p[0], p[1]);\n                }\n            }else{\n                delta -= getEdge(p[i-1], p[i]);\n                if(i < N-1){\n                    delta -= getEdge(p[i], p[i+1]);\n                    delta += getEdge(p[i-1], p[i+1]);\n                }\n            }\n            int len = N - 1;\n            auto getAfter = [&](int k)->int{\n                if(k < i) return p[k];\n                else return p[k+1];\n            };\n            if(len == 0){\n                return delta;\n            }\n            if(j2 == 0){\n                int R = getAfter(0);\n                delta += getEdge(x, R);\n            }else if(j2 == len){\n                int L = getAfter(len-1);\n                delta += getEdge(L, x);\n            }else{\n                int L = getAfter(j2-1);\n                int R = getAfter(j2);\n                delta -= getEdge(L, R);\n                delta += getEdge(L, x);\n                delta += getEdge(x, R);\n            }\n            return delta;\n        };\n        auto apply_insert = [&](int i, int j2){\n            int x = p[i];\n            p.erase(p.begin()+i);\n            p.insert(p.begin()+j2, x);\n        };\n        double t0 = elapsed();\n        while(elapsed() - t0 < time_budget_sec){\n            bool improved = false;\n            for(int i=0;i<n;i++){\n                int best_j=-1, best_d=0;\n                for(int j2=0;j2<=n-1;j2++){\n                    if(j2==i) continue;\n                    int d = compute_insert_delta(i,j2);\n                    if(d > best_d){ best_d=d; best_j=j2; }\n                }\n                if(best_d > 0){\n                    apply_insert(i,best_j);\n                    improved = true;\n                    break;\n                }\n            }\n            if(!improved) break;\n        }\n    };\n\n    // Build initial candidates\n    vector<vector<int>> candidates;\n    vector<int> pi1 = build_by_arc_packing();\n    insertion_ls_overlap(pi1, 0.05);\n    candidates.push_back(pi1);\n    // NN starts\n    int nn_trials = 10;\n    for(int s=0;s<nn_trials;s++){\n        int start = rng.next_int(0, M-1);\n        vector<int> pi = build_by_nn(start);\n        insertion_ls_overlap(pi, 0.03);\n        candidates.push_back(move(pi));\n    }\n\n    // Select top few by overlap sum\n    struct Cand { vector<int> pi; int ov; };\n    vector<Cand> cands;\n    cands.reserve(candidates.size());\n    for(auto &pi : candidates){\n        cands.push_back({pi, sum_overlaps(pi)});\n    }\n    sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){\n        return a.ov > b.ov;\n    });\n    int keep = min<int>(cands.size(), 4);\n\n    // Utilities to build letter sequence and DP\n    auto build_letters_from_pi = [&](const vector<int>& pi)->vector<int>{\n        vector<int> letters;\n        letters.reserve(5*M);\n        // Add first word fully\n        for(int k=0;k<5;k++) letters.push_back(t[pi[0]][k]-'A');\n        for(int i=1;i<M;i++){\n            int a = pi[i-1], b = pi[i];\n            int ov = f[a][b];\n            for(int k=ov;k<5;k++) letters.push_back(t[b][k]-'A');\n        }\n        return letters;\n    };\n\n    auto dp_cost = [&](const vector<int>& letters)->long long{\n        int L = (int)letters.size();\n        int c0 = letters[0];\n        int P0 = (int)pos[c0].size();\n        if(P0==0) return (long long)1e18;\n        vector<int> dp_prev(P0);\n        for(int q=0;q<P0;q++){\n            int ii=pos[c0][q].i, jj=pos[c0][q].j;\n            dp_prev[q] = abs(ii-si) + abs(jj-sj) + 1;\n        }\n        for(int l=1;l<L;l++){\n            int c = letters[l];\n            int Pc = (int)pos[c].size();\n            int cp = letters[l-1];\n            int Pp = (int)pos[cp].size();\n            vector<int> dp_curr(Pc, INT_MAX/4);\n            for(int q=0;q<Pc;q++){\n                int qi=pos[c][q].i, qj=pos[c][q].j;\n                int best = INT_MAX/4;\n                for(int pidx=0;pidx<Pp;pidx++){\n                    int pi_i=pos[cp][pidx].i, pi_j=pos[cp][pidx].j;\n                    int cand = dp_prev[pidx] + abs(qi-pi_i) + abs(qj-pi_j) + 1;\n                    if(cand < best) best = cand;\n                }\n                dp_curr[q] = best;\n            }\n            dp_prev.swap(dp_curr);\n        }\n        int lastc = letters.back();\n        int Pl = (int)pos[lastc].size();\n        int bestv = INT_MAX/4;\n        for(int q=0;q<Pl;q++) bestv = min(bestv, dp_prev[q]);\n        return bestv;\n    };\n\n    auto dp_solve = [&](const vector<int>& letters)->pair<long long, vector<pair<int,int>>>{\n        int L = (int)letters.size();\n        vector<vector<int>> parent(L);\n        vector<int> dp_prev, dp_curr;\n        // init\n        int c0 = letters[0];\n        int P0 = (int)pos[c0].size();\n        dp_prev.assign(P0, INT_MAX/4);\n        parent[0].assign(P0, -1);\n        for(int q=0;q<P0;q++){\n            int ii = pos[c0][q].i, jj = pos[c0][q].j;\n            int dist = abs(ii - si) + abs(jj - sj);\n            dp_prev[q] = dist + 1;\n        }\n        for(int l=1;l<L;l++){\n            int c = letters[l];\n            int Pc = (int)pos[c].size();\n            int cp = letters[l-1];\n            int Pp = (int)pos[cp].size();\n            dp_curr.assign(Pc, INT_MAX/4);\n            parent[l].assign(Pc, -1);\n            for(int q=0;q<Pc;q++){\n                int qi = pos[c][q].i, qj = pos[c][q].j;\n                int best = INT_MAX/4, bestp=-1;\n                for(int pidx=0;pidx<Pp;pidx++){\n                    int pi_i = pos[cp][pidx].i, pi_j = pos[cp][pidx].j;\n                    int cand = dp_prev[pidx] + abs(qi - pi_i) + abs(qj - pi_j) + 1;\n                    if(cand < best){\n                        best = cand;\n                        bestp = pidx;\n                    }\n                }\n                dp_curr[q] = best;\n                parent[l][q] = bestp;\n            }\n            dp_prev.swap(dp_curr);\n        }\n        int lastc = letters.back();\n        int Pl = (int)pos[lastc].size();\n        int bestq=0, bestv=INT_MAX/4;\n        for(int q=0;q<Pl;q++){\n            if(dp_prev[q] < bestv){ bestv = dp_prev[q]; bestq=q; }\n        }\n        vector<pair<int,int>> ops(letters.size());\n        int idx = bestq;\n        for(int l=L-1;l>=0;l--){\n            int c = letters[l];\n            ops[l] = {pos[c][idx].i, pos[c][idx].j};\n            if(l>0){\n                idx = parent[l][idx];\n                if(idx < 0) idx = 0;\n            }\n        }\n        return { (long long)bestv, ops };\n    };\n\n    // Pick best baseline by DP cost; also consider reversed\n    long long best_T = (1LL<<60);\n    vector<int> best_pi;\n    vector<int> best_letters;\n    for(int i=0;i<keep;i++){\n        if(elapsed() > TIME_LIMIT) break;\n        auto &pi = cands[i].pi;\n        vector<int> letters = build_letters_from_pi(pi);\n        long long Tcost = dp_cost(letters);\n        if(Tcost < best_T){\n            best_T = Tcost;\n            best_pi = pi;\n            best_letters = letters;\n        }\n        // reversed candidate\n        vector<int> pir = pi;\n        reverse(pir.begin(), pir.end());\n        vector<int> letters_r = build_letters_from_pi(pir);\n        long long Tr = dp_cost(letters_r);\n        if(Tr < best_T){\n            best_T = Tr;\n            best_pi.swap(pir);\n            best_letters.swap(letters_r);\n        }\n    }\n    if(best_pi.empty()){\n        best_pi = build_by_arc_packing();\n        best_letters = build_letters_from_pi(best_pi);\n        best_T = dp_cost(best_letters);\n    }\n    int curOv = sum_overlaps(best_pi);\n\n    // Helpers: overlap deltas\n    auto overlap_insert_delta = [&](const vector<int>& p, int i, int j2)->int{\n        int N = p.size();\n        int x = p[i];\n        auto e = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        int delta = 0;\n        if(i == 0){\n            if(N >= 2){\n                delta -= e(p[0], p[1]);\n            }\n        }else{\n            delta -= e(p[i-1], p[i]);\n            if(i < N-1){\n                delta -= e(p[i], p[i+1]);\n                delta += e(p[i-1], p[i+1]);\n            }\n        }\n        int len = N - 1;\n        auto getAfter = [&](int k)->int{\n            if(k < i) return p[k];\n            else return p[k+1];\n        };\n        if(len == 0){\n            return delta;\n        }\n        if(j2 == 0){\n            int R = getAfter(0);\n            delta += e(x, R);\n        }else if(j2 == len){\n            int L = getAfter(len-1);\n            delta += e(L, x);\n        }else{\n            int L = getAfter(j2-1);\n            int R = getAfter(j2);\n            delta -= e(L, R);\n            delta += e(L, x);\n            delta += e(x, R);\n        }\n        return delta;\n    };\n\n    auto overlap_swap_delta = [&](const vector<int>& p, int i, int j)->int{\n        if(i==j) return 0;\n        if(i>j) swap(i,j);\n        int n = p.size();\n        auto e = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        int a = p[i], b = p[j];\n        int before = 0, after = 0;\n        if(i+1 == j){\n            if(i-1>=0){ before += e(p[i-1], a); after += e(p[i-1], b); }\n            before += e(a, b);\n            after += e(b, a);\n            if(j+1<n){ before += e(b, p[j+1]); after += e(a, p[j+1]); }\n        }else{\n            if(i-1>=0){ before += e(p[i-1], a); after += e(p[i-1], b); }\n            if(i+1<n){ before += e(a, p[i+1]); after += e(b, p[i+1]); }\n            if(j-1>=0){ before += e(p[j-1], b); after += e(p[j-1], a); }\n            if(j+1<n){ before += e(b, p[j+1]); after += e(a, p[j+1]); }\n        }\n        return after - before;\n    };\n\n    auto overlap_block_delta = [&](const vector<int>& p, int L, int R, int K)->int{\n        int N = p.size();\n        int B = R-L+1;\n        auto e = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        int delta = 0;\n        // Before edges to remove\n        if(L>0) delta -= e(p[L-1], p[L]);\n        if(R<N-1) delta -= e(p[R], p[R+1]);\n        // The pair at insertion site in original sequence (left->right) to remove:\n        if(!(K==0 || K==N-B)){\n            if(K <= L){\n                // pair (p[K-1], p[K])\n                delta -= e(p[K-1], p[K]);\n            }else{\n                // pair (p[K-1+B], p[K+B])\n                if(K-1+B >= 0 && K+B < N){\n                    delta -= e(p[K-1+B], p[K+B]);\n                }\n            }\n        }\n        // After edges to add\n        if(L>0 && R<N-1) delta += e(p[L-1], p[R+1]);\n        auto getAfter = [&](int k)->int{\n            if(k < L) return p[k];\n            else return p[k+B];\n        };\n        if(K>0){\n            int left = getAfter(K-1);\n            delta += e(left, p[L]);\n        }\n        if(K < N-B){\n            int right = getAfter(K);\n            delta += e(p[R], right);\n        }\n        return delta;\n    };\n\n    // Estimated deltas (W_est with start)\n    auto est_insert_delta = [&](const vector<int>& p, int i, int j2)->double{\n        int n = p.size();\n        int x = p[i];\n        double delta = 0.0;\n        // start changes?\n        if(i == 0){\n            delta -= Wstart[p[0]];\n            if(n >= 2){\n                delta -= W_est[p[0]][p[1]];\n                delta += Wstart[p[1]];\n            }\n        }else{\n            delta -= W_est[p[i-1]][p[i]];\n            if(i < n-1){\n                delta -= W_est[p[i]][p[i+1]];\n                delta += W_est[p[i-1]][p[i+1]];\n            }\n        }\n        int len = n - 1;\n        auto getAfter = [&](int k)->int{\n            if(k < i) return p[k];\n            else return p[k+1];\n        };\n        if(len == 0){\n            delta += Wstart[x];\n            return delta;\n        }\n        if(j2 == 0){\n            int R = getAfter(0);\n            delta -= Wstart[R];\n            delta += Wstart[x];\n            delta += W_est[x][R];\n        }else if(j2 == len){\n            int L = getAfter(len-1);\n            delta += W_est[L][x];\n        }else{\n            int L = getAfter(j2-1);\n            int R = getAfter(j2);\n            delta -= W_est[L][R];\n            delta += W_est[L][x];\n            delta += W_est[x][R];\n        }\n        return delta;\n    };\n\n    auto est_swap_delta = [&](const vector<int>& p, int i, int j)->double{\n        if(i==j) return 0.0;\n        if(i>j) swap(i,j);\n        int n = p.size();\n        auto edge_sum_partial = [&](const vector<int>& arr, int i, int j)->double{\n            double s = 0.0;\n            // start changes if i==0 or j==0\n            if(i==0 || j==0){\n                s += Wstart[arr[0]];\n            }\n            // edges around i-1,i and j-1,j and adjacent\n            int a=i, b=j;\n            vector<int> idxs;\n            for(int k=a-1;k<=a;k++) if(k>=0 && k<n-1) idxs.push_back(k);\n            for(int k=b-1;k<=b;k++) if(k>=0 && k<n-1) idxs.push_back(k);\n            sort(idxs.begin(), idxs.end());\n            idxs.erase(unique(idxs.begin(), idxs.end()), idxs.end());\n            for(int k: idxs){\n                s += W_est[arr[k]][arr[k+1]];\n            }\n            return s;\n        };\n        double before = edge_sum_partial(p, i, j);\n        vector<int> q = p;\n        swap(q[i], q[j]);\n        double after  = edge_sum_partial(q, i, j);\n        return after - before;\n    };\n\n    auto est_block_delta = [&](const vector<int>& p, int L, int R, int K)->double{\n        int N = p.size();\n        int B = R-L+1;\n        double delta = 0.0;\n        // Start contribution\n        double beforeStart = Wstart[p[0]];\n        double afterStart = beforeStart;\n        if(K==0){\n            afterStart = Wstart[p[L]];\n        }else if(L==0 && K>0){\n            // new head is q[0] = p[R+1]\n            if(R+1 < N) afterStart = Wstart[p[R+1]];\n        }else{\n            // unchanged\n            afterStart = beforeStart;\n        }\n        delta += (afterStart - beforeStart);\n\n        auto E = [&](int a, int b)->double{ if(a<0||b<0) return 0.0; return W_est[a][b]; };\n        // Before edges to remove\n        if(L>0) delta -= E(p[L-1], p[L]);\n        if(R<N-1) delta -= E(p[R], p[R+1]);\n        // The pair at insertion site in original sequence to remove:\n        if(!(K==0 || K==N-B)){\n            if(K <= L){\n                // pair (p[K-1], p[K])\n                delta -= E(p[K-1], p[K]);\n            }else{\n                if(K-1+B >= 0 && K+B < N){\n                    delta -= E(p[K-1+B], p[K+B]);\n                }\n            }\n        }\n        // After edges to add\n        if(L>0 && R<N-1) delta += E(p[L-1], p[R+1]);\n        auto getAfter = [&](int k)->int{\n            if(k < L) return p[k];\n            else return p[k+B];\n        };\n        if(K>0){\n            int left = getAfter(K-1);\n            delta += E(left, p[L]);\n        }\n        if(K < N-B){\n            int right = getAfter(K);\n            delta += E(p[R], right);\n        }\n        return delta;\n    };\n\n    auto apply_insert = [&](vector<int>& p, int i, int j2){\n        int x = p[i];\n        p.erase(p.begin()+i);\n        p.insert(p.begin()+j2, x);\n    };\n    auto apply_block = [&](vector<int>& p, int L, int R, int K){\n        vector<int> block;\n        block.reserve(R-L+1);\n        for(int i=L;i<=R;i++) block.push_back(p[i]);\n        p.erase(p.begin()+L, p.begin()+R+1);\n        p.insert(p.begin()+K, block.begin(), block.end());\n    };\n\n    // DP-based local improvements with movement-aware gating\n    double t_ls_start = elapsed();\n    while(elapsed() < TIME_LIMIT - 0.08){\n        int moveTypeSel = rng.next_int(0, 99);\n        if(moveTypeSel < 50){\n            // insertion\n            int i = rng.next_int(0, M-1);\n            int j2 = rng.next_int(0, M-1);\n            if(j2==i) continue;\n            int dOv = overlap_insert_delta(best_pi, i, j2);\n            if(dOv < -1) continue;\n            double dEst = est_insert_delta(best_pi, i, j2);\n            // gate: prefer dEst>0 or non-negative overlap change\n            if(!(dEst > 1e-9 || dOv >= 0 || rng.next_int(0,99)<5)) continue;\n            vector<int> cand_pi = best_pi;\n            apply_insert(cand_pi, i, j2);\n            vector<int> letters = build_letters_from_pi(cand_pi);\n            long long Tcost = dp_cost(letters);\n            if(Tcost < best_T){\n                best_T = Tcost;\n                best_pi.swap(cand_pi);\n                best_letters.swap(letters);\n                curOv += dOv;\n            }\n        }else if(moveTypeSel < 80){\n            // swap\n            int i = rng.next_int(0, M-1);\n            int j = rng.next_int(0, M-1);\n            if(i==j) continue;\n            if(i>j) swap(i,j);\n            int dOv = overlap_swap_delta(best_pi, i, j);\n            if(dOv < -1) continue;\n            double dEst = est_swap_delta(best_pi, i, j);\n            if(!(dEst > 1e-9 || dOv >= 0 || rng.next_int(0,99)<3)) continue;\n            vector<int> cand_pi = best_pi;\n            swap(cand_pi[i], cand_pi[j]);\n            vector<int> letters = build_letters_from_pi(cand_pi);\n            long long Tcost = dp_cost(letters);\n            if(Tcost < best_T){\n                best_T = Tcost;\n                best_pi.swap(cand_pi);\n                best_letters.swap(letters);\n                curOv += dOv;\n            }\n        }else{\n            // block insertion\n            int L = rng.next_int(0, M-2);\n            int maxlen = min(8, M - L); // limit block size\n            int len = rng.next_int(2, maxlen);\n            int R = L + len - 1;\n            int K = rng.next_int(0, M - len);\n            // Avoid no-op where K equals original position of block\n            if(K >= L && K <= R+1) continue;\n            int dOv = overlap_block_delta(best_pi, L, R, K);\n            if(dOv < -1) continue;\n            double dEst = est_block_delta(best_pi, L, R, K);\n            if(!(dEst > 1e-9 || dOv >= 0 || rng.next_int(0,99)<3)) continue;\n            vector<int> cand_pi = best_pi;\n            apply_block(cand_pi, L, R, K);\n            vector<int> letters = build_letters_from_pi(cand_pi);\n            long long Tcost = dp_cost(letters);\n            if(Tcost < best_T){\n                best_T = Tcost;\n                best_pi.swap(cand_pi);\n                best_letters.swap(letters);\n                curOv += dOv;\n            }\n        }\n    }\n\n    // Final DP with path reconstruction\n    auto [finalT, ops] = dp_solve(best_letters);\n\n    for(auto &p : ops){\n        cout << p.first << \" \" << p.second << \"\\n\";\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer for internal time management\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::steady_clock::now(); }\n    double elapsed() const { return chrono::duration<double>(chrono::steady_clock::now() - st).count(); }\n};\n\nstatic inline int cell_id(int i, int j, int N) { return i * N + j; }\nstatic inline pair<int,int> cell_ij(int id, int N) { return {id / N, id % N}; }\n\nstruct Shape {\n    int id;\n    vector<pair<int,int>> offsets; // relative coordinates within shape\n    int H=0, W=0;\n    vector<vector<int>> shiftsCells; // per shift: global cell ids covered\n    vector<vector<int>> coverShiftsByCell; // for each global cell, list of shifts that cover it\n};\n\nstruct Problem {\n    int N, M;\n    double eps;\n    vector<Shape> shapes;\n};\n\nstruct State {\n    int N, M;\n    const Problem* prob;\n\n    // Known v(i,j) via drilling, -1 unknown\n    vector<int> known; // size N*N\n    vector<int> drilledCells;\n    vector<int> vDrilled;\n    vector<int> drilledIndexOf; // map cell -> drilled index\n\n    // Candidate shifts per shape\n    vector<vector<uint8_t>> active;\n    vector<int> activeCount;\n\n    // Coverage bounds for drilled cells\n    int D = 0;\n    vector<vector<int>> anyCoverKD;  // [k][d] could cover\n    vector<vector<int>> mustCoverKD; // [k][d] must cover\n    vector<int> sumAnyD, sumMustD;\n\n    // Cache: for each (shape, shift), drilled indices covered\n    vector<vector<vector<int>>> coverDrilledCache;\n\n    int opCount = 0;\n    int opLimit;\n\n    mt19937 rng;\n    Timer timer;\n    double timeLimitSec = 2.25; // strict internal limit\n\n    State(const Problem* pr) : prob(pr) {\n        N = pr->N; M = pr->M;\n        known.assign(N*N, -1);\n        drilledIndexOf.assign(N*N, -1);\n        active.resize(M);\n        activeCount.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            active[k].assign(Pk, 1);\n            activeCount[k] = Pk;\n        }\n        rng.seed(chrono::high_resolution_clock::now().time_since_epoch().count());\n        opLimit = 2 * N * N;\n    }\n\n    inline void flush() { cout.flush(); }\n\n    inline bool removeShift(int k, int p) {\n        if (active[k][p]) {\n            active[k][p] = 0;\n            --activeCount[k];\n            return true;\n        }\n        return false;\n    }\n\n    inline int drill_cell(int c) {\n        if (known[c] != -1) return known[c];\n        auto [i,j] = cell_ij(c, N);\n        cout << \"q 1 \" << i << \" \" << j << \"\\n\";\n        flush();\n        string s;\n        if (!(cin >> s)) exit(0);\n        int val = stoi(s);\n        known[c] = val;\n        drilledIndexOf[c] = (int)drilledCells.size();\n        drilledCells.push_back(c);\n        vDrilled.push_back(val);\n        ++opCount;\n        if (val == 0) {\n            // eliminate shifts covering this cell\n            for (int k = 0; k < M; ++k) {\n                if (activeCount[k] == 0) continue;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) {\n                    removeShift(k, p);\n                }\n            }\n        }\n        return val;\n    }\n\n    bool allShapesHaveCandidates() const {\n        for (int k = 0; k < M; ++k) if (activeCount[k] <= 0) return false;\n        return true;\n    }\n\n    void recomputeCoverageBounds() {\n        D = (int)drilledCells.size();\n        anyCoverKD.assign(M, vector<int>(D, 0));\n        mustCoverKD.assign(M, vector<int>(D, 0));\n        sumAnyD.assign(D, 0);\n        sumMustD.assign(D, 0);\n        for (int k = 0; k < M; ++k) {\n            if (activeCount[k] <= 0) continue;\n            for (int d = 0; d < D; ++d) {\n                int c = drilledCells[d];\n                int cnt = 0;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) ++cnt;\n                anyCoverKD[k][d] = (cnt > 0) ? 1 : 0;\n                mustCoverKD[k][d] = (cnt == activeCount[k]) ? 1 : 0;\n                sumAnyD[d] += anyCoverKD[k][d];\n                sumMustD[d] += mustCoverKD[k][d];\n            }\n        }\n    }\n\n    void buildCoverDrilledCache() {\n        D = (int)drilledCells.size();\n        coverDrilledCache.clear();\n        coverDrilledCache.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            coverDrilledCache[k].resize(Pk);\n            for (int p = 0; p < Pk; ++p) {\n                if (!active[k][p]) { coverDrilledCache[k][p].clear(); continue; }\n                const auto& cells = prob->shapes[k].shiftsCells[p];\n                auto& v = coverDrilledCache[k][p];\n                v.clear();\n                for (int c : cells) {\n                    int d = drilledIndexOf[c];\n                    if (d >= 0) v.push_back(d);\n                }\n                sort(v.begin(), v.end());\n                v.erase(unique(v.begin(), v.end()), v.end());\n            }\n        }\n    }\n\n    // Constraint propagation using drilled cells info\n    bool propagateConstraints(int maxIter = 200) {\n        for (int iter = 0; iter < maxIter; ++iter) {\n            bool changed = false;\n            recomputeCoverageBounds();\n            // quick contradiction check\n            for (int d = 0; d < D; ++d) {\n                int v = vDrilled[d];\n                if (sumAnyD[d] < v || sumMustD[d] > v) {\n                    // Contradiction; return false to trigger fallback\n                    return false;\n                }\n            }\n            for (int d = 0; d < D; ++d) {\n                int c = drilledCells[d];\n                int v = vDrilled[d];\n                // v == 0: ensure elimination\n                if (v == 0) {\n                    for (int k = 0; k < M; ++k) {\n                        if (activeCount[k] <= 0) continue;\n                        if (anyCoverKD[k][d]) {\n                            for (int p : prob->shapes[k].coverShiftsByCell[c]) {\n                                if (removeShift(k, p)) changed = true;\n                            }\n                        }\n                    }\n                    continue;\n                }\n                // sumAny == v: all potential shapes must cover c\n                if (sumAnyD[d] == v) {\n                    for (int k = 0; k < M; ++k) {\n                        if (activeCount[k] <= 0) continue;\n                        if (anyCoverKD[k][d]) {\n                            // remove shifts NOT covering c\n                            int Pk = (int)prob->shapes[k].shiftsCells.size();\n                            // Mark covering shifts for quick test\n                            static vector<uint8_t> mark;\n                            mark.assign(Pk, 0);\n                            for (int p : prob->shapes[k].coverShiftsByCell[c]) mark[p] = 1;\n                            for (int p = 0; p < Pk; ++p) if (active[k][p] && !mark[p]) {\n                                if (removeShift(k, p)) changed = true;\n                            }\n                        }\n                    }\n                }\n                // sumMust == v: all other shapes must NOT cover c\n                if (sumMustD[d] == v) {\n                    for (int k = 0; k < M; ++k) {\n                        if (activeCount[k] <= 0) continue;\n                        if (anyCoverKD[k][d] && mustCoverKD[k][d] == 0) {\n                            for (int p : prob->shapes[k].coverShiftsByCell[c]) {\n                                if (removeShift(k, p)) changed = true;\n                            }\n                        }\n                    }\n                }\n            }\n            if (!changed) break;\n            // continue to next iteration until fixpoint\n        }\n        return allShapesHaveCandidates();\n    }\n\n    vector<int> chooseOrder(int targetCell = -1, int requireCovered = -1) {\n        vector<int> ord(M); iota(ord.begin(), ord.end(), 0);\n        auto canCover = [&](int k)->int {\n            if (targetCell < 0) return 0;\n            for (int p : prob->shapes[k].coverShiftsByCell[targetCell]) if (active[k][p]) return 1;\n            return 0;\n        };\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b){\n            if (requireCovered == 1) {\n                int ca = canCover(a), cb = canCover(b);\n                if (ca != cb) return ca > cb;\n            }\n            if (activeCount[a] != activeCount[b]) return activeCount[a] < activeCount[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    struct DFSContext {\n        State* st;\n        vector<int> order;\n        vector<int> cur; // current contributions at drilled cells\n        vector<int> assign; // chosen shift per shape id\n        int solutionsLimit;\n        int solutionsFound;\n        vector<int> lastAssignment;\n        vector<int> unionCounts;\n        bool respectTime;\n        int targetCell;     // -1 none\n        int requireCovered; // -1 none, 0 force uncovered, 1 force covered\n        vector<vector<int>> sufAny;\n        vector<vector<int>> sufMust;\n        vector<vector<vector<int>>> *coverDrilledCachePtr;\n        vector<vector<int>> *anyCoverKDPtr;\n        vector<vector<int>> *mustCoverKDPtr;\n\n        DFSContext(State* st_, const vector<int>& order_, int solLim, bool respectTime_,\n                   int targetCell_ = -1, int requireCovered_ = -1)\n            : st(st_), order(order_), solutionsLimit(solLim), solutionsFound(0),\n              respectTime(respectTime_), targetCell(targetCell_), requireCovered(requireCovered_) {\n            int D = (int)st->drilledCells.size();\n            int M = st->M;\n            cur.assign(D, 0);\n            assign.assign(st->M, -1);\n            lastAssignment.assign(st->M, -1);\n            unionCounts.assign(st->N * st->N, 0);\n            coverDrilledCachePtr = &st->coverDrilledCache;\n            anyCoverKDPtr = &st->anyCoverKD;\n            mustCoverKDPtr = &st->mustCoverKD;\n            sufAny.assign(M + 1, vector<int>(D, 0));\n            sufMust.assign(M + 1, vector<int>(D, 0));\n            for (int pos = M - 1; pos >= 0; --pos) {\n                int k = order[pos];\n                for (int d = 0; d < D; ++d) {\n                    sufAny[pos][d] = sufAny[pos + 1][d] + (*anyCoverKDPtr)[k][d];\n                    sufMust[pos][d] = sufMust[pos + 1][d] + (*mustCoverKDPtr)[k][d];\n                }\n            }\n        }\n\n        void recordSolution() {\n            vector<uint8_t> covered(st->N * st->N, 0);\n            for (int pos = 0; pos < st->M; ++pos) {\n                int k = order[pos];\n                int p = assign[k];\n                if (p < 0) return;\n                for (int c : st->prob->shapes[k].shiftsCells[p]) covered[c] = 1;\n            }\n            for (int c = 0; c < st->N * st->N; ++c) if (covered[c]) ++unionCounts[c];\n            lastAssignment = assign;\n            ++solutionsFound;\n        }\n\n        bool viableChoice(int pos, int k, int p) {\n            if (requireCovered == 0 && targetCell >= 0) {\n                for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) return false;\n            }\n            const vector<int>& vDrilled = st->vDrilled;\n            const vector<int>& coverD = (*coverDrilledCachePtr)[k][p];\n            int D = (int)st->drilledCells.size();\n            int ptr = 0;\n            for (int d = 0; d < D; ++d) {\n                int cover = 0;\n                if (ptr < (int)coverD.size() && coverD[ptr] == d) { cover = 1; ++ptr; }\n                int remp = vDrilled[d] - (cur[d] + cover);\n                if (remp < 0) return false;\n                int ub_rem = sufAny[pos + 1][d];\n                int lb_rem = sufMust[pos + 1][d];\n                if (remp < lb_rem) return false;\n                if (remp > ub_rem) return false;\n            }\n            return true;\n        }\n\n        void dfs(int pos) {\n            if (solutionsFound >= solutionsLimit) return;\n            if (respectTime && st->timer.elapsed() > st->timeLimitSec) return;\n            if (pos == st->M) {\n                if (requireCovered == 1 && targetCell >= 0) {\n                    bool cov = false;\n                    for (int t = 0; t < st->M && !cov; ++t) {\n                        int k = order[t];\n                        int p = assign[k];\n                        if (p < 0) continue;\n                        for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) { cov = true; break; }\n                    }\n                    if (!cov) return;\n                }\n                recordSolution();\n                return;\n            }\n            int k = order[pos];\n\n            if (requireCovered == 1 && targetCell >= 0) {\n                bool coveredNow = false;\n                for (int t = 0; t < pos && !coveredNow; ++t) {\n                    int kk = order[t];\n                    int psel = assign[kk];\n                    if (psel < 0) continue;\n                    for (int c : st->prob->shapes[kk].shiftsCells[psel]) if (c == targetCell) { coveredNow = true; break; }\n                }\n                if (!coveredNow) {\n                    bool exists = false;\n                    for (int t = pos; t < st->M && !exists; ++t) {\n                        int kk = order[t];\n                        for (int p2 : st->prob->shapes[kk].coverShiftsByCell[targetCell]) if (st->active[kk][p2]) { exists = true; break; }\n                    }\n                    if (!exists) return;\n                }\n            }\n\n            const int Pk = (int)st->prob->shapes[k].shiftsCells.size();\n            vector<int> candidates;\n            candidates.reserve(st->activeCount[k]);\n            if (requireCovered == 1 && targetCell >= 0) {\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) {\n                    bool cov = false;\n                    for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) { cov = true; break; }\n                    if (cov) candidates.push_back(p);\n                }\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) {\n                    bool cov = false;\n                    for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) { cov = true; break; }\n                    if (!cov) candidates.push_back(p);\n                }\n            } else {\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) candidates.push_back(p);\n            }\n\n            for (int p : candidates) {\n                if (!viableChoice(pos, k, p)) continue;\n                assign[k] = p;\n                const auto& coverD = (*coverDrilledCachePtr)[k][p];\n                for (int d : coverD) ++cur[d];\n                dfs(pos + 1);\n                for (int d : coverD) --cur[d];\n                assign[k] = -1;\n                if (solutionsFound >= solutionsLimit) return;\n                if (respectTime && st->timer.elapsed() > st->timeLimitSec) return;\n            }\n        }\n    };\n\n    void enumerateSolutionsLimited(int L, vector<int>& oneAssignOut, vector<int>& unionCountsOut, int& found) {\n        recomputeCoverageBounds();\n        buildCoverDrilledCache();\n        vector<int> order = chooseOrder();\n        DFSContext ctx(this, order, L, true);\n        ctx.dfs(0);\n        found = ctx.solutionsFound;\n        oneAssignOut = ctx.lastAssignment;\n        unionCountsOut = ctx.unionCounts;\n    }\n\n    // Alternative existence using prepared caches\n    bool existsAlternativeForCellPrepared(int c, int wantStatus) {\n        if (known[c] == 0 && wantStatus == 1) return false;\n        if (known[c] > 0 && wantStatus == 0) return false;\n\n        if (wantStatus == 1) {\n            bool anyCan = false;\n            for (int k = 0; k < M && !anyCan; ++k) {\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) { anyCan = true; break; }\n            }\n            if (!anyCan) return false;\n        }\n        if (wantStatus == 0) {\n            for (int k = 0; k < M; ++k) {\n                int coverCnt = 0;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) ++coverCnt;\n                if (activeCount[k] > 0 && coverCnt == activeCount[k]) return false;\n            }\n        }\n\n        int requireCovered = (wantStatus == 1) ? 1 : 0;\n        vector<int> order = chooseOrder(c, requireCovered);\n        DFSContext ctx(this, order, 1, true, c, requireCovered);\n        ctx.dfs(0);\n        return ctx.solutionsFound >= 1;\n    }\n\n    vector<uint8_t> buildUnionFromAssignment(const vector<int>& assign) {\n        vector<uint8_t> covered(N*N, 0);\n        for (int k = 0; k < M; ++k) {\n            int p = assign[k];\n            if (p < 0) continue;\n            for (int c : prob->shapes[k].shiftsCells[p]) covered[c] = 1;\n        }\n        return covered;\n    }\n\n    // Compute min/max cover per cell given current active sets\n    void computeMinMaxCover(vector<int>& minCover, vector<int>& maxCover) {\n        minCover.assign(N*N, 0);\n        maxCover.assign(N*N, 0);\n        for (int k = 0; k < M; ++k) {\n            if (activeCount[k] <= 0) continue;\n            // For each cell c that is covered by some shift, count coverActive\n            // Approach: iterate all cells 0..N*N and count active covering shifts\n            for (int c = 0; c < N*N; ++c) {\n                int coverCnt = 0;\n                const auto& vec = prob->shapes[k].coverShiftsByCell[c];\n                if (vec.empty()) continue;\n                for (int p : vec) if (active[k][p]) ++coverCnt;\n                if (coverCnt > 0) ++maxCover[c];\n                if (coverCnt == activeCount[k]) ++minCover[c];\n            }\n        }\n    }\n\n    // Choose a cell with maximum elimination potential (sum of active covering shifts)\n    int bestCoverageDrillCandidate() {\n        int bestC = -1;\n        int bestScore = -1;\n        for (int c = 0; c < N*N; ++c) {\n            if (known[c] != -1) continue;\n            int score = 0;\n            for (int k = 0; k < M; ++k) {\n                if (activeCount[k] <= 0) continue;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) ++score;\n            }\n            if (score > bestScore) { bestScore = score; bestC = c; }\n        }\n        if (bestC == -1) {\n            // fallback: random unknown\n            vector<int> unknown;\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) unknown.push_back(c);\n            if (!unknown.empty()) bestC = unknown[rng() % unknown.size()];\n        }\n        return bestC;\n    }\n\n    // Drill all remaining cells and return exact union\n    vector<uint8_t> drillAllAndBuildUnion() {\n        for (int c = 0; c < N*N; ++c) {\n            if (opCount >= opLimit - 1) break;\n            if (known[c] == -1) drill_cell(c);\n        }\n        vector<uint8_t> res(N*N, 0);\n        for (int c = 0; c < N*N; ++c) res[c] = (known[c] > 0) ? 1 : 0;\n        return res;\n    }\n\n    pair<vector<uint8_t>, bool> solveUnion() {\n        // Initial coarse drilling grid step based on M\n        int s = max(2, min(4, (int)floor(sqrt((double)N * (double)N / (double)(max(1,M) * 2.0)))));\n        for (int i = 0; i < N; i += s) {\n            for (int j = 0; j < N; j += s) {\n                if (opCount >= opLimit) break;\n                int c = cell_id(i, j, N);\n                if (known[c] == -1) drill_cell(c);\n            }\n        }\n        // Propagate\n        if (!propagateConstraints()) {\n            vector<uint8_t> res = drillAllAndBuildUnion();\n            return {res, true};\n        }\n\n        vector<int> oneAssign, unionCounts;\n        int found = 0;\n\n        while (true) {\n            if (opCount >= opLimit - 1) break;\n            if (timer.elapsed() > timeLimitSec) break;\n\n            // Deterministic classification via min/max cover\n            vector<int> minCover, maxCover;\n            computeMinMaxCover(minCover, maxCover);\n            bool allClassified = true;\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) {\n                if (!(maxCover[c] == 0 || minCover[c] > 0)) { allClassified = false; break; }\n            }\n            if (allClassified) {\n                vector<uint8_t> res(N*N, 0);\n                for (int c = 0; c < N*N; ++c) {\n                    if (known[c] != -1) res[c] = (known[c] > 0);\n                    else res[c] = (minCover[c] > 0) ? 1 : 0;\n                }\n                return {res, true};\n            }\n\n            // Enumerate some solutions for ambiguity guidance\n            enumerateSolutionsLimited(60, oneAssign, unionCounts, found);\n            if (found == 0) {\n                if (!allShapesHaveCandidates()) {\n                    vector<uint8_t> res = drillAllAndBuildUnion();\n                    return {res, true};\n                }\n                // Drill high-potential cell\n                int cPick = bestCoverageDrillCandidate();\n                if (cPick == -1) break;\n                drill_cell(cPick);\n                if (!propagateConstraints()) {\n                    vector<uint8_t> res = drillAllAndBuildUnion();\n                    return {res, true};\n                }\n                continue;\n            }\n\n            // Build base union and ambiguous list limited by min/max cover classification\n            vector<uint8_t> baseUnion = buildUnionFromAssignment(oneAssign);\n            vector<pair<int,int>> cells; // (score, cell)\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) {\n                if (maxCover[c] == 0 || minCover[c] > 0) continue; // already decided\n                int cnt = unionCounts[c];\n                int score = abs(found - 2*cnt);\n                cells.emplace_back(score, c);\n            }\n            sort(cells.begin(), cells.end(), [&](const auto& a, const auto& b){\n                if (a.first != b.first) return a.first < b.first;\n                return a.second < b.second;\n            });\n\n            // Prepare caches once\n            recomputeCoverageBounds();\n            buildCoverDrilledCache();\n\n            bool alternativeFound = false;\n            bool completeScan = true;\n            int ambiguousCell = -1;\n\n            for (auto &pr : cells) {\n                if (timer.elapsed() > timeLimitSec) { completeScan = false; break; }\n                int c = pr.second;\n                int want = baseUnion[c] ? 0 : 1;\n                if (existsAlternativeForCellPrepared(c, want)) {\n                    ambiguousCell = c;\n                    alternativeFound = true;\n                    break;\n                }\n            }\n\n            if (!completeScan) {\n                // Time low: drill a high-potential cell\n                int cPick = bestCoverageDrillCandidate();\n                if (cPick == -1) break;\n                drill_cell(cPick);\n                if (!propagateConstraints()) {\n                    vector<uint8_t> res = drillAllAndBuildUnion();\n                    return {res, true};\n                }\n                continue;\n            }\n\n            if (!alternativeFound) {\n                // Proven unique\n                return {baseUnion, true};\n            } else {\n                drill_cell(ambiguousCell);\n                if (!propagateConstraints()) {\n                    vector<uint8_t> res = drillAllAndBuildUnion();\n                    return {res, true};\n                }\n            }\n        }\n\n        // Fallback: drill remaining cells for correctness\n        vector<uint8_t> res = drillAllAndBuildUnion();\n        return {res, true};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem prob;\n    if (!(cin >> prob.N >> prob.M >> prob.eps)) return 0;\n    prob.shapes.resize(prob.M);\n    for (int k = 0; k < prob.M; ++k) {\n        prob.shapes[k].id = k;\n        int d; cin >> d;\n        vector<pair<int,int>> offs;\n        offs.reserve(d);\n        int minI = INT_MAX, minJ = INT_MAX, maxI = INT_MIN, maxJ = INT_MIN;\n        for (int t = 0; t < d; ++t) {\n            int ii, jj; cin >> ii >> jj;\n            offs.emplace_back(ii, jj);\n            minI = min(minI, ii);\n            minJ = min(minJ, jj);\n            maxI = max(maxI, ii);\n            maxJ = max(maxJ, jj);\n        }\n        for (auto &p : offs) { p.first -= minI; p.second -= minJ; }\n        prob.shapes[k].offsets = offs;\n        prob.shapes[k].H = maxI - minI + 1;\n        prob.shapes[k].W = maxJ - minJ + 1;\n    }\n\n    // Precompute all shifts and mapping\n    for (int k = 0; k < prob.M; ++k) {\n        auto &S = prob.shapes[k];\n        int maxDI = prob.N - S.H;\n        int maxDJ = prob.N - S.W;\n        for (int di = 0; di <= maxDI; ++di) {\n            for (int dj = 0; dj <= maxDJ; ++dj) {\n                vector<int> cells;\n                cells.reserve(S.offsets.size());\n                for (auto [oi, oj] : S.offsets) {\n                    int i = di + oi;\n                    int j = dj + oj;\n                    cells.push_back(cell_id(i, j, prob.N));\n                }\n                sort(cells.begin(), cells.end());\n                S.shiftsCells.push_back(move(cells));\n            }\n        }\n        S.coverShiftsByCell.assign(prob.N * prob.N, {});\n        for (int p = 0; p < (int)S.shiftsCells.size(); ++p) {\n            for (int c : S.shiftsCells[p]) S.coverShiftsByCell[c].push_back(p);\n        }\n    }\n\n    State st(&prob);\n\n    auto resPair = st.solveUnion();\n    vector<uint8_t> unionSet = resPair.first;\n\n    // Build answer vector; ensure inclusion of drilled positives\n    vector<int> ans;\n    ans.reserve(st.N * st.N);\n    for (int c = 0; c < st.N * st.N; ++c) if (unionSet[c]) ans.push_back(c);\n    for (int idx = 0; idx < (int)st.drilledCells.size(); ++idx) {\n        int c = st.drilledCells[idx];\n        if (st.known[c] > 0 && !unionSet[c]) { ans.push_back(c); unionSet[c] = 1; }\n    }\n    sort(ans.begin(), ans.end());\n    ans.erase(unique(ans.begin(), ans.end()), ans.end());\n\n    auto print_answer = [&](const vector<int>& cells){\n        cout << \"a \" << cells.size();\n        for (int c : cells) {\n            auto [i,j] = cell_ij(c, st.N);\n            cout << \" \" << i << \" \" << j;\n        }\n        cout << \"\\n\";\n        cout.flush();\n    };\n\n    print_answer(ans);\n    string resp;\n    if (!(cin >> resp)) return 0;\n\n    if (resp == \"0\") {\n        // Recovery: drill all remaining cells and re-answer exactly\n        vector<uint8_t> exactUnion = st.drillAllAndBuildUnion();\n        vector<int> ans2;\n        for (int c = 0; c < st.N * st.N; ++c) if (exactUnion[c]) ans2.push_back(c);\n        print_answer(ans2);\n        if (!(cin >> resp)) return 0;\n    }\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct MaxItem {\n    int s; // current shortage (area units), not multiplied by 100\n    int i; // index\n    bool operator<(const MaxItem& o) const {\n        return s < o.s; // max-heap\n    }\n};\nstruct MinItem {\n    int h; // current height\n    int i;\n    bool operator<(const MinItem& o) const {\n        if (h != o.h) return h > o.h; // min-heap\n        return i > o.i;\n    }\n};\n\n// Greedy water-filling for one day: full-width stripes, minimize deficiency\nstatic vector<int> compute_heights_one_day(int W, const vector<int>& a_sorted) {\n    int N = (int)a_sorted.size();\n    vector<int> k(N, 1);            // base height 1 for each rectangle (positive area constraint)\n    int R = W - N;                  // remaining height units to distribute\n    priority_queue<MaxItem> pq;\n    for (int i = 0; i < N; i++) {\n        int s = a_sorted[i] - W;    // shortage after base height=1\n        if (s < 0) s = 0;\n        pq.push(MaxItem{s, i});\n    }\n    while (R > 0 && !pq.empty()) {\n        MaxItem cur = pq.top(); pq.pop();\n        if (cur.s <= 0) break; // no more benefit\n        k[cur.i] += 1;\n        cur.s -= W;\n        if (cur.s < 0) cur.s = 0;\n        pq.push(cur);\n        R--;\n    }\n    // If leftover height units remain (all shortages eliminated), distribute evenly to smallest heights\n    if (R > 0) {\n        priority_queue<MinItem> minpq;\n        for (int i = 0; i < N; i++) minpq.push(MinItem{k[i], i});\n        while (R > 0) {\n            auto cur = minpq.top(); minpq.pop();\n            cur.h += 1;\n            k[cur.i] = cur.h;\n            minpq.push(cur);\n            R--;\n        }\n    }\n    // Safety\n    int sumh = 0;\n    for (int h : k) sumh += h;\n    if (sumh != W && N > 0) {\n        // Adjust last to ensure sum matches W (should not happen)\n        k.back() += (W - sumh);\n    }\n    return k;\n}\n\n// Arrange heights to align with prev boundaries as much as possible using subset-sum per boundary (greedy).\n// heights: multiset of heights (sum = W), prev_bounds: sorted list of previous boundary rows (values in (0..W-1)).\nstatic vector<int> arrange_align_subset(const vector<int>& heights, const vector<int>& prev_bounds, int W) {\n    // Remaining heights multiset\n    vector<int> rem = heights;\n    sort(rem.begin(), rem.end()); // stable, deterministic order\n    vector<int> seq; seq.reserve(rem.size());\n    int pos = 0;\n\n    // For each target boundary b, try to find a subset of rem summing to (b - pos)\n    for (int b : prev_bounds) {\n        if (b <= pos) continue;\n        int gap = b - pos;\n        // Quick fail if gap > remaining sum (shouldn't happen)\n        int sumRem = 0;\n        for (int h : rem) sumRem += h;\n        if (gap > sumRem) continue;\n\n        // 0/1 knapsack subset sum to target gap on rem\n        int m = (int)rem.size();\n        vector<int> parent(gap + 1, -2);   // -2 unreachable, -1 for start\n        vector<int> takeIdx(gap + 1, -1);  // which rem index used to reach this sum\n        parent[0] = -1;\n\n        for (int t = 0; t < m; t++) {\n            int h = rem[t];\n            if (h > gap) continue;\n            for (int s = gap - h; s >= 0; s--) {\n                if (parent[s] != -2 && parent[s + h] == -2) {\n                    parent[s + h] = s;\n                    takeIdx[s + h] = t;\n                }\n            }\n            if (parent[gap] != -2) break; // early exit if we hit exact gap\n        }\n\n        if (parent[gap] == -2) {\n            // Cannot match this boundary; skip it\n            continue;\n        }\n\n        // Reconstruct subset\n        vector<char> mark(m, 0);\n        int s = gap;\n        while (s > 0) {\n            int t = takeIdx[s];\n            mark[t] = 1;\n            s = parent[s];\n        }\n\n        // Append selected items to seq in ascending height (stable: increasing t)\n        for (int t = 0; t < m; t++) if (mark[t]) seq.push_back(rem[t]);\n\n        // Remove selected items from rem\n        vector<int> rem2; rem2.reserve(m);\n        for (int t = 0; t < m; t++) if (!mark[t]) rem2.push_back(rem[t]);\n        rem.swap(rem2);\n\n        pos = b; // matched this boundary\n        if (rem.empty()) break;\n    }\n\n    // Append remaining segments in ascending order\n    for (int h : rem) seq.push_back(h);\n\n    // Safety: ensure sum == W\n    int sum = 0;\n    for (int h : seq) sum += h;\n    if (sum != W && !seq.empty()) {\n        seq.back() += (W - sum);\n    }\n    return seq;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int W, D, N;\n    if (!(cin >> W >> D >> N)) return 0;\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    // Heights per day via water-filling (deficiency-minimizing under full-width stripes, base height 1)\n    vector<vector<int>> heightsByDay(D);\n    for (int d = 0; d < D; d++) {\n        // a[d] already sorted ascending per statement\n        heightsByDay[d] = compute_heights_one_day(W, a[d]);\n    }\n\n    vector<int> prev_bounds; // boundary rows from previous day (prefix sums excluding W)\n\n    // For day 0, we can try to anticipate day 1 boundaries to reduce L1.\n    vector<int> target_bounds_day0;\n    if (D >= 2) {\n        vector<int> h1 = heightsByDay[1];\n        sort(h1.begin(), h1.end()); // naive ordering for day 1\n        int ps = 0;\n        for (int i = 0; i < N - 1; i++) {\n            ps += h1[i];\n            target_bounds_day0.push_back(ps);\n        }\n    }\n\n    for (int d = 0; d < D; d++) {\n        // Arrange heights to align with prev_bounds (or target for day 0)\n        vector<int> heights = heightsByDay[d];\n        vector<int> seq;\n        if (d == 0 && !target_bounds_day0.empty()) {\n            seq = arrange_align_subset(heights, target_bounds_day0, W);\n        } else {\n            seq = arrange_align_subset(heights, prev_bounds, W);\n        }\n\n        // Build rectangles: full-width horizontal stripes in this order\n        int cur_i = 0;\n        vector<array<int,4>> rect_by_seq; rect_by_seq.reserve(N);\n        for (int t = 0; t < N; t++) {\n            int h = seq[t];\n            int i0 = cur_i;\n            int i1 = cur_i + h;\n            rect_by_seq.push_back({i0, 0, i1, W});\n            cur_i = i1;\n        }\n        if (cur_i != W && !rect_by_seq.empty()) {\n            rect_by_seq.back()[2] += (W - cur_i);\n        }\n\n        // Assign rectangles to reservations: pair sorted by height ascending to sorted demands (already ascending).\n        vector<pair<int,int>> height_with_idx; height_with_idx.reserve(N);\n        for (int t = 0; t < N; t++) height_with_idx.emplace_back(seq[t], t);\n        sort(height_with_idx.begin(), height_with_idx.end()); // ascending by height\n\n        for (int kidx = 0; kidx < N; kidx++) {\n            int stripe_idx = height_with_idx[kidx].second;\n            auto &r = rect_by_seq[stripe_idx];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << '\\n';\n        }\n\n        // Prepare prev_bounds for next day: prefix sums of seq excluding W\n        prev_bounds.clear();\n        int ps = 0;\n        for (int t = 0; t < N - 1; t++) {\n            ps += seq[t];\n            prev_bounds.push_back(ps);\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic const ll MOD = 998244353LL;\n\ninline ll cell_gain(ll rcur, int sval) {\n    return ((ll)sval >= (MOD - rcur)) ? ((ll)sval - MOD) : (ll)sval;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto T0 = chrono::steady_clock::now();\n    auto elapsed_ms = [&](){\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - T0).count();\n    };\n    const long long TIME_LIMIT_MS = 1950;\n\n    int N, M, K;\n    if (!(cin >> N >> M >> K)) return 0;\n\n    const int SZ = N * N; // 81\n    vector<ll> r0(SZ), r(SZ);\n    for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) { ll x; cin >> x; r0[i*N+j] = x % MOD; }\n    r = r0;\n\n    vector<array<int, 9>> stamp(M);\n    for (int m = 0; m < M; ++m) {\n        for (int u = 0; u < 3; ++u) for (int v = 0; v < 3; ++v) {\n            int x; cin >> x;\n            stamp[m][u*3+v] = x;\n        }\n    }\n\n    const int P = N - 2;        // 7\n    const int POS_CNT = P * P;  // 49\n    const int OPS = M * POS_CNT;// 980\n\n    vector<int> pos_p(POS_CNT), pos_q(POS_CNT);\n    for (int p = 0, idx = 0; p < P; ++p) for (int q = 0; q < P; ++q, ++idx) pos_p[idx]=p, pos_q[idx]=q;\n\n    vector<array<int, 9>> op_cells(OPS);\n    vector<array<int, 9>> op_svals(OPS);\n    vector<int> op_m(OPS), op_p(OPS), op_q(OPS), op_pos(OPS);\n    for (int m = 0; m < M; ++m) {\n        for (int pos = 0; pos < POS_CNT; ++pos) {\n            int p = pos_p[pos], q = pos_q[pos];\n            int op = m * POS_CNT + pos;\n            op_m[op] = m; op_p[op] = p; op_q[op] = q; op_pos[op] = pos;\n            for (int u = 0; u < 3; ++u) for (int v = 0; v < 3; ++v) {\n                int k = u*3+v;\n                int i = p + u, j = q + v;\n                op_cells[op][k] = i * N + j;\n                op_svals[op][k] = stamp[m][k];\n            }\n        }\n    }\n\n    // Precompute overlap operations list for each op:\n    vector<vector<int>> overlOps(OPS);\n    overlOps.assign(OPS, {});\n    for (int op = 0; op < OPS; ++op) {\n        int p = op_p[op], q = op_q[op];\n        overlOps[op].reserve(25 * M);\n        for (int dp = -2; dp <= 2; ++dp) {\n            int p2 = p + dp; if (p2 < 0 || p2 >= P) continue;\n            for (int dq = -2; dq <= 2; ++dq) {\n                int q2 = q + dq; if (q2 < 0 || q2 >= P) continue;\n                int pos2 = p2 * P + q2;\n                for (int m2 = 0; m2 < M; ++m2) {\n                    int op2 = m2 * POS_CNT + pos2;\n                    overlOps[op].push_back(op2);\n                }\n            }\n        }\n    }\n\n    auto apply_op = [&](vector<ll>& board, int op){\n        const auto &cells = op_cells[op];\n        const auto &svals = op_svals[op];\n        ll nr;\n        nr = board[cells[0]] + (ll)svals[0]; if (nr >= MOD) nr -= MOD; board[cells[0]] = nr;\n        nr = board[cells[1]] + (ll)svals[1]; if (nr >= MOD) nr -= MOD; board[cells[1]] = nr;\n        nr = board[cells[2]] + (ll)svals[2]; if (nr >= MOD) nr -= MOD; board[cells[2]] = nr;\n        nr = board[cells[3]] + (ll)svals[3]; if (nr >= MOD) nr -= MOD; board[cells[3]] = nr;\n        nr = board[cells[4]] + (ll)svals[4]; if (nr >= MOD) nr -= MOD; board[cells[4]] = nr;\n        nr = board[cells[5]] + (ll)svals[5]; if (nr >= MOD) nr -= MOD; board[cells[5]] = nr;\n        nr = board[cells[6]] + (ll)svals[6]; if (nr >= MOD) nr -= MOD; board[cells[6]] = nr;\n        nr = board[cells[7]] + (ll)svals[7]; if (nr >= MOD) nr -= MOD; board[cells[7]] = nr;\n        nr = board[cells[8]] + (ll)svals[8]; if (nr >= MOD) nr -= MOD; board[cells[8]] = nr;\n    };\n\n    auto compute_gain_for_op = [&](const vector<ll>& board, int op)->ll{\n        const auto &cells = op_cells[op];\n        const auto &svals = op_svals[op];\n        ll sum = 0;\n        sum += cell_gain(board[cells[0]], svals[0]);\n        sum += cell_gain(board[cells[1]], svals[1]);\n        sum += cell_gain(board[cells[2]], svals[2]);\n        sum += cell_gain(board[cells[3]], svals[3]);\n        sum += cell_gain(board[cells[4]], svals[4]);\n        sum += cell_gain(board[cells[5]], svals[5]);\n        sum += cell_gain(board[cells[6]], svals[6]);\n        sum += cell_gain(board[cells[7]], svals[7]);\n        sum += cell_gain(board[cells[8]], svals[8]);\n        return sum;\n    };\n\n    auto compute_gain_all = [&](const vector<ll>& board, vector<ll>& gain){\n        for (int op = 0; op < OPS; ++op) gain[op] = compute_gain_for_op(board, op);\n    };\n\n    vector<ll> gain(OPS, 0);\n    vector<int> overlapMark(OPS, 0);\n    int overlapTag = 1;\n\n    // Temporary remainder buffers for hypothetical updates\n    vector<ll> tmpR(SZ, 0), tmpR2(SZ, 0);\n    vector<int> tmpRMark(SZ, 0), tmpR2Mark(SZ, 0);\n    int tmpRTag = 1, tmpR2Tag = 1;\n\n    // Mark array for dedup in union scanning\n    vector<int> seen(OPS, 0);\n    int seenTag = 1;\n\n    vector<int> selectedOps; selectedOps.reserve(K);\n\n    // Evaluate and apply presses greedily with 3-step lookahead (select op1 only)\n    auto global_refill = [&](){\n        compute_gain_all(r, gain);\n        while ((int)selectedOps.size() < K) {\n            if (elapsed_ms() > TIME_LIMIT_MS) return;\n\n            // Build sorted order by current gain\n            static vector<int> order;\n            order.resize(OPS);\n            iota(order.begin(), order.end(), 0);\n            sort(order.begin(), order.end(), [&](int a, int b){\n                if (gain[a] != gain[b]) return gain[a] > gain[b];\n                return a < b;\n            });\n\n            // Dynamic candidate count and whether to use triple lookahead\n            bool useTriple = (elapsed_ms() < TIME_LIMIT_MS * 0.65);\n            int T = useTriple ? 96 : 196;\n            if (T > OPS) T = OPS;\n\n            ll bestCombined = LLONG_MIN;\n            ll bestG1 = LLONG_MIN;\n            int bestOp = -1;\n\n            for (int idx = 0; idx < T; ++idx) {\n                int op1 = order[idx];\n                ll g1 = gain[op1];\n\n                // Mark overlapped ops for op1\n                ++overlapTag;\n                for (int t : overlOps[op1]) overlapMark[t] = overlapTag;\n\n                // Candidate op2: best unaffected base gain\n                int op2_un = -1; ll g2_un = LLONG_MIN;\n                for (int j = 0; j < OPS; ++j) {\n                    int cand = order[j];\n                    if (overlapMark[cand] != overlapTag) {\n                        op2_un = cand; g2_un = gain[cand];\n                        break;\n                    }\n                }\n\n                // Hypothetical apply op1: compute r' for its 9 cells\n                ++tmpRTag;\n                const auto &cells1 = op_cells[op1];\n                const auto &svals1 = op_svals[op1];\n                for (int k = 0; k < 9; ++k) {\n                    int c = cells1[k];\n                    ll nr = r[c] + (ll)svals1[k];\n                    if (nr >= MOD) nr -= MOD;\n                    tmpR[c] = nr;\n                    tmpRMark[c] = tmpRTag;\n                }\n\n                // Top overlapped op2 candidates (evaluate under r'): keep top 2\n                ll topG2a = LLONG_MIN, topG2b = LLONG_MIN;\n                int topOp2a = -1, topOp2b = -1;\n                for (int t : overlOps[op1]) {\n                    ll sum = 0;\n                    const auto &cells = op_cells[t];\n                    const auto &svals = op_svals[t];\n                    // compute under r'\n                    ll rr;\n                    rr = (tmpRMark[cells[0]] == tmpRTag) ? tmpR[cells[0]] : r[cells[0]];\n                    sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                    rr = (tmpRMark[cells[1]] == tmpRTag) ? tmpR[cells[1]] : r[cells[1]];\n                    sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                    rr = (tmpRMark[cells[2]] == tmpRTag) ? tmpR[cells[2]] : r[cells[2]];\n                    sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                    rr = (tmpRMark[cells[3]] == tmpRTag) ? tmpR[cells[3]] : r[cells[3]];\n                    sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                    rr = (tmpRMark[cells[4]] == tmpRTag) ? tmpR[cells[4]] : r[cells[4]];\n                    sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                    rr = (tmpRMark[cells[5]] == tmpRTag) ? tmpR[cells[5]] : r[cells[5]];\n                    sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                    rr = (tmpRMark[cells[6]] == tmpRTag) ? tmpR[cells[6]] : r[cells[6]];\n                    sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                    rr = (tmpRMark[cells[7]] == tmpRTag) ? tmpR[cells[7]] : r[cells[7]];\n                    sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                    rr = (tmpRMark[cells[8]] == tmpRTag) ? tmpR[cells[8]] : r[cells[8]];\n                    sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n\n                    if (sum > topG2a) { topG2b = topG2a; topOp2b = topOp2a; topG2a = sum; topOp2a = t; }\n                    else if (sum > topG2b && t != topOp2a) { topG2b = sum; topOp2b = t; }\n                }\n\n                // Evaluate combined score\n                ll combined = LLONG_MIN;\n\n                if (useTriple) {\n                    // Build candidate list for op2: up to 3 items\n                    array<int, 3> cand2 = {topOp2a, topOp2b, op2_un};\n                    array<ll, 3> cand2g = {topG2a, topG2b, g2_un};\n\n                    ll best2plus3 = 0;\n                    for (int ci = 0; ci < 3; ++ci) {\n                        int op2 = cand2[ci];\n                        if (op2 < 0) continue;\n                        ll g2 = cand2g[ci];\n\n                        // Mark union of overlapped ops of op1 and op2\n                        ++overlapTag;\n                        for (int t : overlOps[op1]) overlapMark[t] = overlapTag;\n                        for (int t : overlOps[op2]) overlapMark[t] = overlapTag;\n\n                        // Prepare r'' after applying op2 on top of r'\n                        ++tmpR2Tag;\n                        const auto &cells2 = op_cells[op2];\n                        const auto &svals2 = op_svals[op2];\n                        for (int k = 0; k < 9; ++k) {\n                            int c = cells2[k];\n                            ll rr1 = (tmpRMark[c] == tmpRTag) ? tmpR[c] : r[c];\n                            ll nr = rr1 + (ll)svals2[k]; if (nr >= MOD) nr -= MOD;\n                            tmpR2[c] = nr;\n                            tmpR2Mark[c] = tmpR2Tag;\n                        }\n\n                        // Best overlapped third op under r''\n                        ll bestOv3 = LLONG_MIN;\n                        ++seenTag;\n                        for (int t : overlOps[op1]) seen[t] = seenTag;\n                        for (int t : overlOps[op2]) {\n                            if (seen[t] == seenTag) continue; // skip duplicates\n                            seen[t] = seenTag;\n                        }\n                        // Scan union via two loops, computing gain under r''\n                        // First loop: overlOps[op1]\n                        for (int t : overlOps[op1]) {\n                            ll sum = 0;\n                            const auto &cells = op_cells[t];\n                            const auto &svals = op_svals[t];\n                            // pick the correct remainder: tmpR2 > tmpR > r\n                            ll rr;\n                            rr = (tmpR2Mark[cells[0]] == tmpR2Tag) ? tmpR2[cells[0]] :\n                                 (tmpRMark[cells[0]] == tmpRTag ? tmpR[cells[0]] : r[cells[0]]);\n                            sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                            rr = (tmpR2Mark[cells[1]] == tmpR2Tag) ? tmpR2[cells[1]] :\n                                 (tmpRMark[cells[1]] == tmpRTag ? tmpR[cells[1]] : r[cells[1]]);\n                            sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                            rr = (tmpR2Mark[cells[2]] == tmpR2Tag) ? tmpR2[cells[2]] :\n                                 (tmpRMark[cells[2]] == tmpRTag ? tmpR[cells[2]] : r[cells[2]]);\n                            sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                            rr = (tmpR2Mark[cells[3]] == tmpR2Tag) ? tmpR2[cells[3]] :\n                                 (tmpRMark[cells[3]] == tmpRTag ? tmpR[cells[3]] : r[cells[3]]);\n                            sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                            rr = (tmpR2Mark[cells[4]] == tmpR2Tag) ? tmpR2[cells[4]] :\n                                 (tmpRMark[cells[4]] == tmpRTag ? tmpR[cells[4]] : r[cells[4]]);\n                            sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                            rr = (tmpR2Mark[cells[5]] == tmpR2Tag) ? tmpR2[cells[5]] :\n                                 (tmpRMark[cells[5]] == tmpRTag ? tmpR[cells[5]] : r[cells[5]]);\n                            sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                            rr = (tmpR2Mark[cells[6]] == tmpR2Tag) ? tmpR2[cells[6]] :\n                                 (tmpRMark[cells[6]] == tmpRTag ? tmpR[cells[6]] : r[cells[6]]);\n                            sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                            rr = (tmpR2Mark[cells[7]] == tmpR2Tag) ? tmpR2[cells[7]] :\n                                 (tmpRMark[cells[7]] == tmpRTag ? tmpR[cells[7]] : r[cells[7]]);\n                            sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                            rr = (tmpR2Mark[cells[8]] == tmpR2Tag) ? tmpR2[cells[8]] :\n                                 (tmpRMark[cells[8]] == tmpRTag ? tmpR[cells[8]] : r[cells[8]]);\n                            sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n                            if (sum > bestOv3) bestOv3 = sum;\n                        }\n                        // Second loop: overlOps[op2] excluding those already seen\n                        for (int t : overlOps[op2]) {\n                            if (seen[t] != seenTag) continue; // ensure in union\n                            // Actually we marked all in union into seen; We need to recompute for those unique to op2 only\n                            // To avoid recomputing those from op1 again, we can skip if overlapMark==overlapTag in previous step,\n                            // but seenTag used as union marker; Let's compute for all unique in op2 not in op1:\n                            // Keep a different guard:\n                        }\n                        // The above way is cumbersome; instead do a simple dedup: use another marker to compute union properly.\n                        // Simpler approach: recompute second loop only for those not in op1:\n                        ++overlapTag;\n                        for (int t2 : overlOps[op1]) overlapMark[t2] = overlapTag;\n                        for (int t : overlOps[op2]) {\n                            if (overlapMark[t] == overlapTag) continue; // already done in first loop\n                            ll sum = 0;\n                            const auto &cells = op_cells[t];\n                            const auto &svals = op_svals[t];\n                            ll rr;\n                            rr = (tmpR2Mark[cells[0]] == tmpR2Tag) ? tmpR2[cells[0]] :\n                                 (tmpRMark[cells[0]] == tmpRTag ? tmpR[cells[0]] : r[cells[0]]);\n                            sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                            rr = (tmpR2Mark[cells[1]] == tmpR2Tag) ? tmpR2[cells[1]] :\n                                 (tmpRMark[cells[1]] == tmpRTag ? tmpR[cells[1]] : r[cells[1]]);\n                            sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                            rr = (tmpR2Mark[cells[2]] == tmpR2Tag) ? tmpR2[cells[2]] :\n                                 (tmpRMark[cells[2]] == tmpRTag ? tmpR[cells[2]] : r[cells[2]]);\n                            sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                            rr = (tmpR2Mark[cells[3]] == tmpR2Tag) ? tmpR2[cells[3]] :\n                                 (tmpRMark[cells[3]] == tmpRTag ? tmpR[cells[3]] : r[cells[3]]);\n                            sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                            rr = (tmpR2Mark[cells[4]] == tmpR2Tag) ? tmpR2[cells[4]] :\n                                 (tmpRMark[cells[4]] == tmpRTag ? tmpR[cells[4]] : r[cells[4]]);\n                            sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                            rr = (tmpR2Mark[cells[5]] == tmpR2Tag) ? tmpR2[cells[5]] :\n                                 (tmpRMark[cells[5]] == tmpRTag ? tmpR[cells[5]] : r[cells[5]]);\n                            sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                            rr = (tmpR2Mark[cells[6]] == tmpR2Tag) ? tmpR2[cells[6]] :\n                                 (tmpRMark[cells[6]] == tmpRTag ? tmpR[cells[6]] : r[cells[6]]);\n                            sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                            rr = (tmpR2Mark[cells[7]] == tmpR2Tag) ? tmpR2[cells[7]] :\n                                 (tmpRMark[cells[7]] == tmpRTag ? tmpR[cells[7]] : r[cells[7]]);\n                            sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                            rr = (tmpR2Mark[cells[8]] == tmpR2Tag) ? tmpR2[cells[8]] :\n                                 (tmpRMark[cells[8]] == tmpRTag ? tmpR[cells[8]] : r[cells[8]]);\n                            sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n                            if (sum > bestOv3) bestOv3 = sum;\n                        }\n\n                        // Best unaffected third op (base gains) outside union\n                        ll bestUn3 = 0;\n                        for (int j = 0; j < OPS; ++j) {\n                            int cand = order[j];\n                            if (overlapMark[cand] != overlapTag) { // not in union\n                                bestUn3 = max(bestUn3, gain[cand]);\n                                break;\n                            }\n                        }\n\n                        ll best3 = max(bestOv3, bestUn3);\n                        if (best3 < 0) best3 = 0;\n                        ll twoPlusThree = g2 + best3;\n                        if (twoPlusThree < 0) twoPlusThree = 0;\n                        if (twoPlusThree > best2plus3) best2plus3 = twoPlusThree;\n                    }\n\n                    combined = g1 + best2plus3;\n                } else {\n                    // 2-step: best of unaffected vs overlapped under r'\n                    ll bestUn = 0; if (op2_un >= 0 && g2_un > bestUn) bestUn = g2_un;\n                    ll bestOv = LLONG_MIN;\n                    for (int t : overlOps[op1]) {\n                        ll sum = 0;\n                        const auto &cells = op_cells[t];\n                        const auto &svals = op_svals[t];\n                        ll rr;\n                        rr = (tmpRMark[cells[0]] == tmpRTag) ? tmpR[cells[0]] : r[cells[0]];\n                        sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                        rr = (tmpRMark[cells[1]] == tmpRTag) ? tmpR[cells[1]] : r[cells[1]];\n                        sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                        rr = (tmpRMark[cells[2]] == tmpRTag) ? tmpR[cells[2]] : r[cells[2]];\n                        sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                        rr = (tmpRMark[cells[3]] == tmpRTag) ? tmpR[cells[3]] : r[cells[3]];\n                        sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                        rr = (tmpRMark[cells[4]] == tmpRTag) ? tmpR[cells[4]] : r[cells[4]];\n                        sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                        rr = (tmpRMark[cells[5]] == tmpRTag) ? tmpR[cells[5]] : r[cells[5]];\n                        sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                        rr = (tmpRMark[cells[6]] == tmpRTag) ? tmpR[cells[6]] : r[cells[6]];\n                        sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                        rr = (tmpRMark[cells[7]] == tmpRTag) ? tmpR[cells[7]] : r[cells[7]];\n                        sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                        rr = (tmpRMark[cells[8]] == tmpRTag) ? tmpR[cells[8]] : r[cells[8]];\n                        sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n                        if (sum > bestOv) bestOv = sum;\n                    }\n                    ll best2 = max(bestUn, bestOv);\n                    if (best2 < 0) best2 = 0;\n                    combined = g1 + best2;\n                }\n\n                if (combined > bestCombined || (combined == bestCombined && g1 > bestG1)) {\n                    bestCombined = combined;\n                    bestG1 = g1;\n                    bestOp = op1;\n                }\n            }\n\n            if (bestOp == -1) break;\n            if (bestCombined <= 0) break;\n\n            // Apply bestOp and update r and gains incrementally\n            selectedOps.push_back(bestOp);\n            apply_op(r, bestOp);\n\n            // Incrementally recompute gains for overlapping ops only\n            for (int t : overlOps[bestOp]) {\n                gain[t] = compute_gain_for_op(r, t);\n            }\n        }\n    };\n\n    // Initial global search\n    global_refill();\n\n    // Deterministic RNG seeded from input dimensions\n    uint64_t seed = 0x9e3779b97f4a7c15ULL ^ (uint64_t)N * 0xBF58476D1CE4E5B9ULL ^ (uint64_t)M * 0x94D049BB133111EBULL ^ (uint64_t)K;\n    auto rng64 = [&]()->uint64_t {\n        seed ^= seed << 7; seed ^= seed >> 9; seed *= 0xD6E8FEB86659FD93ULL; return seed;\n    };\n    auto rnd_int = [&](int L, int R)->int { return L + (int)(rng64() % (uint64_t)(R - L + 1)); };\n\n    // Local Neighborhood Search (LNS): restricted to anchors in a small rectangle\n    vector<char> allowedMark(OPS, 0);\n    vector<int> keptOpsBuf; keptOpsBuf.reserve(K);\n    vector<int> removedOpsBuf; removedOpsBuf.reserve(K);\n    vector<ll> r_work(SZ);\n    vector<ll> lgain(OPS, LLONG_MIN);\n    vector<int> allowedOps; allowedOps.reserve(OPS);\n\n    vector<ll> tmpR_local(SZ, 0);\n    vector<int> tmpRMark_local(SZ, 0);\n    int tmpRTag_local = 1;\n\n    auto recompute_local_gain_for_op = [&](int op)->ll{\n        const auto &cells = op_cells[op];\n        const auto &svals = op_svals[op];\n        ll sum = 0;\n        sum += cell_gain(r_work[cells[0]], svals[0]);\n        sum += cell_gain(r_work[cells[1]], svals[1]);\n        sum += cell_gain(r_work[cells[2]], svals[2]);\n        sum += cell_gain(r_work[cells[3]], svals[3]);\n        sum += cell_gain(r_work[cells[4]], svals[4]);\n        sum += cell_gain(r_work[cells[5]], svals[5]);\n        sum += cell_gain(r_work[cells[6]], svals[6]);\n        sum += cell_gain(r_work[cells[7]], svals[7]);\n        sum += cell_gain(r_work[cells[8]], svals[8]);\n        return sum;\n    };\n\n    auto sum_region_cells = [&](const vector<ll>& board, int sp, int sq, int RA)->ll {\n        int i0 = sp, i1 = sp + RA + 1;\n        int j0 = sq, j1 = sq + RA + 1;\n        ll sum = 0;\n        for (int i = i0; i <= i1; ++i) for (int j = j0; j <= j1; ++j) sum += board[i*N + j];\n        return sum;\n    };\n\n    vector<int> newOps; newOps.reserve(K);\n\n    // Local refill using 2-step lookahead restricted to allowedMark, with incremental gain updates\n    auto local_refill = [&](int cap, vector<int>& outOps){\n        outOps.clear();\n        allowedOps.clear();\n        for (int op = 0; op < OPS; ++op) if (allowedMark[op]) allowedOps.push_back(op);\n        if (allowedOps.empty() || cap <= 0) return;\n\n        // Initialize local gains\n        for (int op : allowedOps) lgain[op] = recompute_local_gain_for_op(op);\n\n        vector<int> order;\n        order.reserve(allowedOps.size());\n\n        int steps = 0;\n        while (steps < cap) {\n            if (elapsed_ms() > TIME_LIMIT_MS) return;\n\n            order = allowedOps;\n            sort(order.begin(), order.end(), [&](int a, int b){\n                if (lgain[a] != lgain[b]) return lgain[a] > lgain[b];\n                return a < b;\n            });\n\n            int T = min(64, (int)order.size());\n\n            ll bestCombined = LLONG_MIN, bestG1 = LLONG_MIN;\n            int bestOp = -1;\n\n            for (int idx = 0; idx < T; ++idx) {\n                int op1 = order[idx];\n                ll g1 = lgain[op1];\n\n                // Mark overlapped within allowed\n                ++overlapTag;\n                for (int t : overlOps[op1]) if (allowedMark[t]) overlapMark[t] = overlapTag;\n\n                // Best unaffected second\n                ll bestUn = 0;\n                for (int j = 0; j < (int)order.size(); ++j) {\n                    int cand = order[j];\n                    if (overlapMark[cand] != overlapTag) { bestUn = max(bestUn, lgain[cand]); break; }\n                }\n\n                // Hypothetical apply op1 on r_work\n                ++tmpRTag_local;\n                const auto &cells1 = op_cells[op1];\n                const auto &svals1 = op_svals[op1];\n                for (int k = 0; k < 9; ++k) {\n                    int c = cells1[k];\n                    ll nr = r_work[c] + (ll)svals1[k];\n                    if (nr >= MOD) nr -= MOD;\n                    tmpR_local[c] = nr;\n                    tmpRMark_local[c] = tmpRTag_local;\n                }\n\n                // Best overlapped under r'\n                ll bestOv = LLONG_MIN;\n                for (int t : overlOps[op1]) {\n                    if (!allowedMark[t]) continue;\n                    ll sum = 0;\n                    const auto &cells = op_cells[t];\n                    const auto &svals = op_svals[t];\n                    ll rr;\n                    rr = (tmpRMark_local[cells[0]] == tmpRTag_local) ? tmpR_local[cells[0]] : r_work[cells[0]];\n                    sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                    rr = (tmpRMark_local[cells[1]] == tmpRTag_local) ? tmpR_local[cells[1]] : r_work[cells[1]];\n                    sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                    rr = (tmpRMark_local[cells[2]] == tmpRTag_local) ? tmpR_local[cells[2]] : r_work[cells[2]];\n                    sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                    rr = (tmpRMark_local[cells[3]] == tmpRTag_local) ? tmpR_local[cells[3]] : r_work[cells[3]];\n                    sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                    rr = (tmpRMark_local[cells[4]] == tmpRTag_local) ? tmpR_local[cells[4]] : r_work[cells[4]];\n                    sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                    rr = (tmpRMark_local[cells[5]] == tmpRTag_local) ? tmpR_local[cells[5]] : r_work[cells[5]];\n                    sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                    rr = (tmpRMark_local[cells[6]] == tmpRTag_local) ? tmpR_local[cells[6]] : r_work[cells[6]];\n                    sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                    rr = (tmpRMark_local[cells[7]] == tmpRTag_local) ? tmpR_local[cells[7]] : r_work[cells[7]];\n                    sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                    rr = (tmpRMark_local[cells[8]] == tmpRTag_local) ? tmpR_local[cells[8]] : r_work[cells[8]];\n                    sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n                    if (sum > bestOv) bestOv = sum;\n                }\n\n                ll best2 = max(bestUn, bestOv);\n                if (best2 < 0) best2 = 0;\n                ll combined = g1 + best2;\n\n                if (combined > bestCombined || (combined == bestCombined && g1 > bestG1)) {\n                    bestCombined = combined;\n                    bestG1 = g1;\n                    bestOp = op1;\n                }\n            }\n\n            if (bestOp == -1) break;\n            if (bestCombined <= 0) break;\n\n            outOps.push_back(bestOp);\n            apply_op(r_work, bestOp);\n\n            // Incrementally update lgain for allowed overlapping ops\n            for (int t : overlOps[bestOp]) if (allowedMark[t]) lgain[t] = recompute_local_gain_for_op(t);\n\n            ++steps;\n        }\n    };\n\n    // LNS loop (time-bounded)\n    for (;;) {\n        if (elapsed_ms() > TIME_LIMIT_MS) break;\n        if (selectedOps.empty()) break;\n\n        // Region size: favor 3 and 4; occasionally 5 if time permits\n        int roll = (int)(rng64() % 100);\n        int RA = (roll < 55 ? 3 : (roll < 95 ? 4 : 5));\n        if (RA > P) RA = P;\n        int sp = rnd_int(0, P - RA);\n        int sq = rnd_int(0, P - RA);\n\n        // Mark allowed ops (anchors in [sp..sp+RA-1] x [sq..sq+RA-1])\n        fill(allowedMark.begin(), allowedMark.end(), 0);\n        for (int p = sp; p < sp + RA; ++p) {\n            for (int q = sq; q < sq + RA; ++q) {\n                int pos = p * P + q;\n                for (int m = 0; m < M; ++m) allowedMark[m * POS_CNT + pos] = 1;\n            }\n        }\n\n        // Split selected ops into kept and removed\n        keptOpsBuf.clear(); removedOpsBuf.clear();\n        for (int op : selectedOps) {\n            if (allowedMark[op]) removedOpsBuf.push_back(op);\n            else keptOpsBuf.push_back(op);\n        }\n        if (removedOpsBuf.empty()) continue;\n\n        // Build r_work: apply kept ops to r0\n        r_work = r0;\n        for (int op : keptOpsBuf) apply_op(r_work, op);\n\n        // Region cell sum before change (on current global r)\n        ll sumBefore = sum_region_cells(r, sp, sq, RA);\n\n        // Capacity for local rebuild\n        int cap = K - (int)keptOpsBuf.size();\n        int capMin = (int)removedOpsBuf.size();\n        int capBound = 2 * RA * RA;\n        cap = max(min(cap, capBound), min(cap, capMin));\n        if (cap <= 0) continue;\n\n        // Local refill\n        local_refill(cap, newOps);\n\n        // Evaluate after local change\n        ll sumAfter = sum_region_cells(r_work, sp, sq, RA);\n        if (sumAfter > sumBefore) {\n            // Accept\n            selectedOps = keptOpsBuf;\n            selectedOps.insert(selectedOps.end(), newOps.begin(), newOps.end());\n            r = r_work;\n\n            // Quick global refill with remaining capacity\n            global_refill();\n        }\n    }\n\n    // Output\n    cout << (int)selectedOps.size() << '\\n';\n    for (int op : selectedOps) {\n        cout << op_m[op] << ' ' << op_p[op] << ' ' << op_q[op] << '\\n';\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 5;\n    static constexpr int TOT = N * N;\n\n    int A[N][N];\n\n    // Grid occupancy: -1 for empty, otherwise container id\n    int occ[N][N];\n\n    // Spawn pointers per receiving row (col = 0)\n    int spawnIdx[N];\n\n    // Large crane state\n    int br = 0, bc = 0; // position\n    int hold = -1;      // container id held or -1\n\n    // Output strings\n    vector<string> S;\n\n    // Delivered tracking\n    bool delivered[TOT];\n    int deliveredCount = 0;\n\n    // Next expected id per dispatch row (row i expects i*N .. i*N+N-1 in order)\n    int nextExpected[N];\n\n    Solver() {\n        memset(occ, -1, sizeof(occ));\n        memset(spawnIdx, 0, sizeof(spawnIdx));\n        memset(delivered, 0, sizeof(delivered));\n        S.assign(N, \"\");\n        for (int i = 0; i < N; i++) nextExpected[i] = i * N;\n    }\n\n    void readInput() {\n        int n;\n        if (!(cin >> n)) exit(0); // N is always 5\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) cin >> A[i][j];\n        }\n    }\n\n    // Step 1: Spawn if possible at receiving gates (col 0)\n    void step1_spawn() {\n        for (int i = 0; i < N; i++) {\n            if (spawnIdx[i] >= N) continue; // no more to spawn for this row\n            if (occ[i][0] == -1) {\n                // Spawn is blocked only if a crane holding a container is at that gate\n                if (!(br == i && bc == 0 && hold != -1)) {\n                    int id = A[i][spawnIdx[i]];\n                    occ[i][0] = id;\n                    spawnIdx[i]++;\n                }\n            }\n        }\n    }\n\n    // Step 3: Dispatch at gates (col 4)\n    void step3_dispatch() {\n        for (int i = 0; i < N; i++) {\n            if (occ[i][4] != -1) {\n                int id = occ[i][4];\n                occ[i][4] = -1;\n                if (!delivered[id]) {\n                    delivered[id] = true;\n                    deliveredCount++;\n                }\n            }\n        }\n        // Update nextExpected per row according to delivered flags\n        for (int r = 0; r < N; r++) {\n            int lo = r * N;\n            int hi = lo + N;\n            while (nextExpected[r] < hi && delivered[nextExpected[r]]) nextExpected[r]++;\n        }\n    }\n\n    inline int manhattan(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    // Decide the large crane's action\n    char decideAction() {\n        if (hold != -1) {\n            int dr = hold / N;\n            int dc = N - 1; // 4\n            if (br == dr && bc == dc) {\n                // Drop if empty\n                if (occ[br][bc] == -1) return 'Q';\n                // If occupied (very unlikely), wait\n                return '.';\n            } else {\n                // Move towards its dispatch gate\n                if (br < dr) return 'D';\n                if (br > dr) return 'U';\n                if (bc < dc) return 'R';\n                if (bc > dc) return 'L';\n                return '.';\n            }\n        } else {\n            // Not holding: choose the best container to pick considering inversion penalty\n            // cost = dist(current -> pos) + dist(pos -> gate) + 100 * m\n            // where m = id - nextExpected[row], the number of smaller undelivered in that row\n            long long bestCost = (1LL << 60);\n            int targetR = -1, targetC = -1, targetID = -1;\n\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    int id = occ[r][c];\n                    if (id == -1) continue;\n                    if (c == N - 1) continue; // ignore containers already at dispatch gates; they'll be dispatched automatically\n                    int dr = id / N;\n                    int expected = nextExpected[dr];\n                    // All ids in [expected .. id-1] in this row are undelivered\n                    int m = (id >= expected ? (id - expected) : 0);\n                    int travel = manhattan(br, bc, r, c) + manhattan(r, c, dr, N - 1);\n                    long long cost = (long long)travel + 100LL * m;\n\n                    if (cost < bestCost || (cost == bestCost && id < targetID)) {\n                        bestCost = cost;\n                        targetR = r; targetC = c; targetID = id;\n                    }\n                }\n            }\n\n            if (targetID == -1) {\n                // No candidates (only dispatch-gate containers may remain); wait\n                return '.';\n            } else {\n                if (br == targetR && bc == targetC) {\n                    // Pick it\n                    return 'P';\n                } else {\n                    if (br < targetR) return 'D';\n                    if (br > targetR) return 'U';\n                    if (bc < targetC) return 'R';\n                    if (bc > targetC) return 'L';\n                    return '.'; // shouldn't happen\n                }\n            }\n        }\n    }\n\n    // Apply the big crane action to our simulation state\n    void applyBigAction(char act) {\n        if (act == 'U') br--;\n        else if (act == 'D') br++;\n        else if (act == 'L') bc--;\n        else if (act == 'R') bc++;\n        else if (act == 'P') {\n            // Pick: valid if not holding and cell has container\n            if (hold == -1 && occ[br][bc] != -1) {\n                hold = occ[br][bc];\n                occ[br][bc] = -1;\n            }\n        } else if (act == 'Q') {\n            // Drop: valid if holding and cell empty\n            if (hold != -1 && occ[br][bc] == -1) {\n                occ[br][bc] = hold;\n                hold = -1;\n            }\n        }\n        // '.' and 'B' not used for big\n    }\n\n    void run() {\n        const int MAX_TURNS = 10000;\n        for (int t = 0; t < MAX_TURNS; t++) {\n            // Step 1: spawn\n            step1_spawn();\n\n            // Step 2: actions\n            char bigAct = decideAction();\n\n            // Record outputs\n            S[0].push_back(bigAct);\n            for (int i = 1; i < N; i++) {\n                // Bomb small cranes at t=0, then idle\n                if (t == 0) S[i].push_back('B');\n                else S[i].push_back('.');\n            }\n\n            // Apply big action to state\n            applyBigAction(bigAct);\n\n            // Step 3: dispatch\n            step3_dispatch();\n\n            if (deliveredCount >= TOT) break;\n        }\n\n        // Pad strings to equal length\n        size_t L = 0;\n        for (int i = 0; i < N; i++) L = max(L, S[i].size());\n        for (int i = 0; i < N; i++) {\n            if (S[i].size() < L) S[i].append(L - S[i].size(), '.');\n        }\n    }\n\n    void output() {\n        for (int i = 0; i < N; i++) cout << S[i] << \"\\n\";\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.run();\n    solver.output();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct PathEvalResult {\n    long long cost;\n    int startIndex;\n    bool reversed;\n};\n\nstatic inline int vid(int N, int r, int c){ return r*N + c; }\nstatic inline pair<int,int> rc_from_id(int N, int v){ return {v / N, v % N}; }\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed=1469598103934665603ULL){ x=seed; }\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int randint(int l, int r){ // inclusive\n        return l + int(next() % (uint64_t)(r-l+1));\n    }\n    void shuffle_vec(vector<int>& a){\n        for(int i=(int)a.size()-1;i>0;i--){\n            int j = int(next() % (uint64_t)(i+1));\n            swap(a[i], a[j]);\n        }\n    }\n};\n\n// 2-regular graph adjacency utilities\nstatic inline void adj_add(vector<array<int,2>>& nb, int u, int v){\n    if(nb[u][0] == v || nb[u][1] == v) return;\n    if(nb[u][0] == -1) nb[u][0] = v;\n    else if(nb[u][1] == -1) nb[u][1] = v;\n    if(nb[v][0] == u || nb[v][1] == u) return;\n    if(nb[v][0] == -1) nb[v][0] = u;\n    else if(nb[v][1] == -1) nb[v][1] = u;\n}\nstatic inline void adj_remove(vector<array<int,2>>& nb, int u, int v){\n    if(nb[u][0] == v) nb[u][0] = -1;\n    else if(nb[u][1] == v) nb[u][1] = -1;\n    if(nb[v][0] == u) nb[v][0] = -1;\n    else if(nb[v][1] == u) nb[v][1] = -1;\n}\n\n// Cycle builder\nstruct CycleBuilder {\n    int N, M, Br, Bc;\n    vector<array<int,2>> nb;\n\n    CycleBuilder(int N): N(N), M(N*N), Br(N/2), Bc(N/2), nb(M, {-1,-1}) {}\n\n    inline void clear() { nb.assign(M, array<int,2>{-1,-1}); }\n\n    inline void add_edge(int u, int v){ adj_add(nb, u, v); }\n    inline void remove_edge(int u, int v){ adj_remove(nb, u, v); }\n\n    void build_2x2_cycles(){\n        clear();\n        for(int br=0; br<Br; ++br){\n            for(int bc=0; bc<Bc; ++bc){\n                int x = 2*br, y = 2*bc;\n                int a = vid(N, x,   y);\n                int b = vid(N, x,   y+1);\n                int c = vid(N, x+1, y+1);\n                int d = vid(N, x+1, y);\n                add_edge(a,b);\n                add_edge(b,c);\n                add_edge(c,d);\n                add_edge(d,a);\n            }\n        }\n    }\n\n    // Horizontal-first scheme: merge horizontally across all seams\n    void merge_horizontally_all(){\n        for(int br=0; br<Br; ++br){\n            int x0 = 2*br;\n            for(int bc=0; bc<Bc-1; ++bc){\n                int y1 = 2*bc+1;\n                int y2 = 2*bc+2;\n                int a = vid(N, x0,   y1);\n                int b = vid(N, x0+1, y1);\n                int c = vid(N, x0,   y2);\n                int d = vid(N, x0+1, y2);\n                remove_edge(a,b);\n                remove_edge(c,d);\n                add_edge(a,c);\n                add_edge(b,d);\n            }\n        }\n    }\n\n    // Vertical merges at a specific block-column anchor per row seam (br seam)\n    void merge_vertically_with_anchors(const vector<int>& anchors){\n        for(int br=0; br<Br-1; ++br){\n            int r1 = 2*br+1;\n            int r2 = 2*br+2;\n            int colBlock = anchors[br];\n            if(colBlock < 0) colBlock = 0;\n            if(colBlock >= Bc) colBlock = Bc-1;\n            int y0 = 2*colBlock;\n            int y1 = y0 + 1;\n            int a = vid(N, r1, y0);\n            int b = vid(N, r1, y1);\n            int c = vid(N, r2, y0);\n            int d = vid(N, r2, y1);\n            remove_edge(a,b);\n            remove_edge(c,d);\n            add_edge(a,c);\n            add_edge(b,d);\n        }\n    }\n\n    // Vertical-first scheme: merge vertically across all seams first\n    void merge_vertically_all(){\n        for(int bc=0; bc<Bc; ++bc){\n            int y0 = 2*bc;\n            int y1 = y0 + 1;\n            for(int br=0; br<Br-1; ++br){\n                int x1 = 2*br+1;\n                int x2 = 2*br+2;\n                int a = vid(N, x1, y0);\n                int b = vid(N, x1, y1);\n                int c = vid(N, x2, y1);\n                int d = vid(N, x2, y0);\n                // remove horizontal edges on the two rows\n                remove_edge(a,b);\n                remove_edge(d,c);\n                // add vertical cross edges\n                add_edge(a,d);\n                add_edge(b,c);\n            }\n        }\n    }\n\n    // Horizontal merges at a specific block-row anchor per column seam (bc seam)\n    void merge_horizontally_with_anchors(const vector<int>& anchorsCols){\n        for(int bc=0; bc<Bc-1; ++bc){\n            int cblock = anchorsCols[bc];\n            if(cblock < 0) cblock = 0;\n            if(cblock >= Br) cblock = Br-1;\n            int r0 = 2*cblock;\n            int r1 = r0 + 1;\n            int yL = 2*bc+1;\n            int yR = 2*bc+2;\n            int a = vid(N, r0, yL);\n            int b = vid(N, r1, yL);\n            int c = vid(N, r0, yR);\n            int d = vid(N, r1, yR);\n            // remove vertical edges on these columns\n            remove_edge(a,b);\n            remove_edge(c,d);\n            // add horizontal cross edges across the seam\n            add_edge(a,c);\n            add_edge(b,d);\n        }\n    }\n\n    vector<pair<int,int>> extract_cycle_path(){\n        vector<pair<int,int>> path;\n        path.reserve(M);\n        int start = vid(N, 0, 0);\n        int cur = start;\n        int prev = -1;\n        vector<char> seen(M, 0);\n        for(int cnt=0; cnt<M; ++cnt){\n            if(cur < 0 || cur >= M){ path.clear(); return path; }\n            if(seen[cur]){ path.clear(); return path; }\n            seen[cur] = 1;\n            path.emplace_back(rc_from_id(N, cur));\n            int n0 = nb[cur][0], n1 = nb[cur][1];\n            int nxt = (n0 == prev ? n1 : n0);\n            if(nxt == -1){ path.clear(); return path; }\n            prev = cur;\n            cur = nxt;\n        }\n        // Verify last connects to start\n        auto [xr, xc] = path.back();\n        int last = vid(N, xr, xc);\n        if(!(nb[last][0] == start || nb[last][1] == start)){\n            path.clear();\n        }\n        return path;\n    }\n\n    vector<pair<int,int>> build_scheme_A(const vector<int>& anchors){ // horiz-all then vert-anchors\n        build_2x2_cycles();\n        merge_horizontally_all();\n        merge_vertically_with_anchors(anchors);\n        return extract_cycle_path();\n    }\n    vector<pair<int,int>> build_scheme_B(const vector<int>& anchorsCols){ // vert-all then horiz-anchors\n        build_2x2_cycles();\n        merge_vertically_all();\n        merge_horizontally_with_anchors(anchorsCols);\n        return extract_cycle_path();\n    }\n};\n\n// Rotate path coordinates by rot=0..3 and reverse option later\nstatic vector<pair<int,int>> rotate_path(const vector<pair<int,int>>& path, int N, int rot){\n    vector<pair<int,int>> res;\n    res.reserve(path.size());\n    for(auto [r,c] : path){\n        int nr=r, nc=c;\n        if(rot==1){ nr = c; nc = N-1 - r; }\n        else if(rot==2){ nr = N-1 - r; nc = N-1 - c; }\n        else if(rot==3){ nr = N-1 - c; nc = r; }\n        res.emplace_back(nr,nc);\n    }\n    return res;\n}\n\n// Evaluate one directed path, return best cost and start\nstatic pair<long long,int> eval_directed_path(const vector<pair<int,int>>& pos,\n                                              const vector<vector<int>>& h,\n                                              long long base)\n{\n    int M = (int)pos.size();\n    vector<long long> arr(M);\n    for(int i=0;i<M;i++){\n        arr[i] = h[pos[i].first][pos[i].second];\n    }\n    vector<long long> pre2(2*M+1, 0);\n    for(int i=0;i<2*M;i++){\n        pre2[i+1] = pre2[i] + arr[i%M];\n    }\n    vector<long long> prefpre2(2*M+1, 0);\n    for(int i=1;i<=2*M;i++){\n        prefpre2[i] = prefpre2[i-1] + pre2[i-1];\n    }\n    long long minVal = LLONG_MAX;\n    for(int i=0;i<M;i++) minVal = min(minVal, pre2[i]);\n    vector<int> starts;\n    for(int s=0;s<M;s++) if(pre2[s] == minVal) starts.push_back(s);\n\n    long long bestCost = (1LL<<62);\n    int bestS = 0;\n    for(int s: starts){\n        long long sumPre2Range = prefpre2[s+M] - prefpre2[s+1]; // pre2[s+1..s+M-1]\n        long long dsum = sumPre2Range - 1LL*(M-1)*pre2[s];\n        int sx = pos[s].first, sy = pos[s].second;\n        int repositionDist = abs(sx) + abs(sy);\n        long long moveCost = 100LL*((M-1) + repositionDist);\n        long long cost = base + moveCost + dsum;\n        if(cost < bestCost){\n            bestCost = cost;\n            bestS = s;\n        }\n    }\n    return {bestCost, bestS};\n}\n\nstatic PathEvalResult eval_path_both(const vector<pair<int,int>>& pos,\n                                     const vector<vector<int>>& h,\n                                     long long base)\n{\n    auto [cost1, s1] = eval_directed_path(pos, h, base);\n    vector<pair<int,int>> pos_rev = pos;\n    reverse(pos_rev.begin(), pos_rev.end());\n    auto [cost2, s2] = eval_directed_path(pos_rev, h, base);\n    if(cost1 <= cost2){\n        return {cost1, s1, false};\n    }else{\n        return {cost2, s2, true};\n    }\n}\n\n// Build nb from path cycle\nstatic vector<array<int,2>> nb_from_path(const vector<pair<int,int>>& path, int N){\n    int M = (int)path.size();\n    vector<array<int,2>> nb(N*N, array<int,2>{-1,-1});\n    auto ID = [&](int idx){ return vid(N, path[idx].first, path[idx].second); };\n    for(int i=0;i<M;i++){\n        int u = ID(i);\n        int v = ID((i+1)%M);\n        adj_add(nb, u, v);\n    }\n    return nb;\n}\n\n// Extract path from nb (single cycle)\nstatic vector<pair<int,int>> path_from_nb(const vector<array<int,2>>& nb, int N){\n    int M = N*N;\n    vector<pair<int,int>> path;\n    path.reserve(M);\n    int start = vid(N, 0, 0);\n    int cur = start;\n    int prev = -1;\n    vector<char> seen(M, 0);\n    for(int cnt=0; cnt<M; ++cnt){\n        if(cur < 0 || cur >= M){ path.clear(); return path; }\n        if(seen[cur]){ path.clear(); return path; }\n        seen[cur] = 1;\n        path.emplace_back(rc_from_id(N, cur));\n        int n0 = nb[cur][0], n1 = nb[cur][1];\n        int nxt = (n0 == prev ? n1 : n0);\n        if(nxt == -1){ path.clear(); return path; }\n        prev = cur;\n        cur = nxt;\n    }\n    // verify closure\n    auto [xr, xc] = path.back();\n    int last = vid(N, xr, xc);\n    if(!(nb[last][0] == start || nb[last][1] == start)){\n        path.clear();\n    }\n    return path;\n}\n\n// Attempt 2x2 plaquette flip on square (x,y); returns true if flipped\nstatic bool try_flip_square(vector<array<int,2>>& nb, int N, int x, int y){\n    int a = vid(N, x,   y);\n    int b = vid(N, x,   y+1);\n    int c = vid(N, x+1, y+1);\n    int d = vid(N, x+1, y);\n\n    auto used = [&](int u, int v)->bool{\n        return nb[u][0]==v || nb[u][1]==v;\n    };\n\n    bool ab = used(a,b);\n    bool bc = used(b,c);\n    bool cd = used(c,d);\n    bool da = used(d,a);\n\n    // Only flip if exactly opposite pair is used\n    if(ab && cd && !bc && !da){\n        // replace ab, cd with bc, da\n        adj_remove(nb, a, b);\n        adj_remove(nb, c, d);\n        adj_add(nb, b, c);\n        adj_add(nb, d, a);\n        return true;\n    }else if(bc && da && !ab && !cd){\n        // replace bc, da with ab, cd\n        adj_remove(nb, b, c);\n        adj_remove(nb, d, a);\n        adj_add(nb, a, b);\n        adj_add(nb, c, d);\n        return true;\n    }\n    return false;\n}\n\n// Generate candidate cycles using both schemes and anchor patterns\nstatic vector<vector<pair<int,int>>> generate_cycle_candidates(int N, RNG& rng){\n    CycleBuilder cb(N);\n    int Br = N/2, Bc = N/2;\n    vector<vector<pair<int,int>>> cycles;\n\n    auto add_cycle_with_rot_rev = [&](const vector<pair<int,int>>& cyc){\n        if(cyc.empty()) return;\n        for(int rot=0; rot<4; ++rot){\n            auto p = rotate_path(cyc, N, rot);\n            cycles.push_back(p);\n            auto pr = p;\n            reverse(pr.begin(), pr.end());\n            cycles.push_back(pr);\n        }\n    };\n\n    // Scheme A (horizontal-first, then vertical anchors)\n    {\n        // Constant anchors\n        for(int k=0; k<Bc; ++k){\n            vector<int> anc(max(Br-1,0), k);\n            auto cyc = cb.build_scheme_A(anc);\n            add_cycle_with_rot_rev(cyc);\n        }\n        // Diagonal shift and anti-diagonal\n        for(int k=0; k<Bc; ++k){\n            vector<int> anc(max(Br-1,0));\n            for(int br=0; br<Br-1; ++br) anc[br] = (k + br) % Bc;\n            auto cyc = cb.build_scheme_A(anc);\n            add_cycle_with_rot_rev(cyc);\n        }\n        for(int k=0; k<Bc; ++k){\n            vector<int> anc(max(Br-1,0));\n            for(int br=0; br<Br-1; ++br) anc[br] = (k - br + Bc) % Bc;\n            auto cyc = cb.build_scheme_A(anc);\n            add_cycle_with_rot_rev(cyc);\n        }\n        // A few random patterns\n        for(int t=0; t<12; ++t){\n            vector<int> anc(max(Br-1,0));\n            for(int br=0; br<Br-1; ++br){\n                anc[br] = rng.randint(0, Bc-1);\n            }\n            auto cyc = cb.build_scheme_A(anc);\n            add_cycle_with_rot_rev(cyc);\n        }\n    }\n\n    // Scheme B (vertical-first, then horizontal anchors)\n    {\n        // Constant anchors\n        for(int k=0; k<Br; ++k){\n            vector<int> anc(max(Bc-1,0), k);\n            auto cyc = cb.build_scheme_B(anc);\n            add_cycle_with_rot_rev(cyc);\n        }\n        // Diagonal shift and anti-diagonal over columns\n        for(int k=0; k<Br; ++k){\n            vector<int> anc(max(Bc-1,0));\n            for(int bc=0; bc<Bc-1; ++bc) anc[bc] = (k + bc) % Br;\n            auto cyc = cb.build_scheme_B(anc);\n            add_cycle_with_rot_rev(cyc);\n        }\n        for(int k=0; k<Br; ++k){\n            vector<int> anc(max(Bc-1,0));\n            for(int bc=0; bc<Bc-1; ++bc) anc[bc] = (k - bc + Br) % Br;\n            auto cyc = cb.build_scheme_B(anc);\n            add_cycle_with_rot_rev(cyc);\n        }\n        // Random patterns\n        for(int t=0; t<12; ++t){\n            vector<int> anc(max(Bc-1,0));\n            for(int bc=0; bc<Bc-1; ++bc){\n                anc[bc] = rng.randint(0, Br-1);\n            }\n            auto cyc = cb.build_scheme_B(anc);\n            add_cycle_with_rot_rev(cyc);\n        }\n    }\n\n    return cycles;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if(!(cin>>N)) return 0;\n    vector<vector<int>> h(N, vector<int>(N));\n    long long base = 0;\n    uint64_t seedMix = 1469598103934665603ULL;\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            cin>>h[i][j];\n            base += llabs((long long)h[i][j]);\n            // mix heights for deterministic RNG\n            uint64_t v = (uint64_t)(h[i][j] + 100); // 0..200\n            seedMix ^= v + 0x9e3779b97f4a7c15ULL + (seedMix<<6) + (seedMix>>2);\n        }\n    }\n    RNG rng(seedMix ^ (uint64_t)N * 0x9e3779b97f4a7c15ULL);\n\n    // Generate many cycles\n    auto cycles = generate_cycle_candidates(N, rng);\n\n    // Evaluate all and pick best\n    long long bestCost = (1LL<<62);\n    vector<pair<int,int>> bestPath;\n    PathEvalResult bestRes{(1LL<<62), 0, false};\n\n    for(const auto& cyc : cycles){\n        auto res = eval_path_both(cyc, h, base);\n        if(res.cost < bestCost){\n            bestCost = res.cost;\n            bestPath = cyc;\n            bestRes = res;\n        }\n    }\n\n    if(bestPath.empty()){\n        // Fallback: simple row snake cycle-like path (construct a cycle by a simple pattern)\n        // Use Scheme A with anchor 0\n        CycleBuilder cb(N);\n        vector<int> anc(max(N/2-1,0), 0);\n        bestPath = cb.build_scheme_A(anc);\n        if(bestPath.empty()){\n            // As last resort, produce a trivial serpentine path (not cycle). We will still try to run.\n            bestPath.clear();\n            for(int i=0;i<N;i++){\n                if(i%2==0) for(int j=0;j<N;j++) bestPath.emplace_back(i,j);\n                else for(int j=N-1;j>=0;j--) bestPath.emplace_back(i,j);\n            }\n        }\n        bestRes = eval_path_both(bestPath, h, base);\n        bestCost = bestRes.cost;\n    }\n\n    // Local improvement: 2x2 plaquette flips hill-climbing on the best cycle\n    {\n        auto nb = nb_from_path(bestPath, N);\n        vector<int> sqIdxs((N-1)*(N-1));\n        iota(sqIdxs.begin(), sqIdxs.end(), 0);\n\n        auto rebuild_and_eval = [&](vector<array<int,2>>& nbCur)->PathEvalResult{\n            auto path2 = path_from_nb(nbCur, N);\n            if(path2.empty()){\n                // Shouldn't happen; revert\n                return { (1LL<<62), 0, false };\n            }\n            return eval_path_both(path2, h, base);\n        };\n\n        // Evaluate current nb cost (should equal best)\n        auto curRes = eval_path_both(bestPath, h, base);\n        long long curCost = curRes.cost;\n        vector<pair<int,int>> curPath = bestPath;\n\n        int maxPass = 3;\n        for(int pass=0; pass<maxPass; ++pass){\n            bool improved = false;\n            rng.shuffle_vec(sqIdxs);\n            for(int id : sqIdxs){\n                int x = id / (N-1);\n                int y = id % (N-1);\n                if(try_flip_square(nb, N, x, y)){\n                    auto res2 = rebuild_and_eval(nb);\n                    if(res2.cost < curCost){\n                        // accept\n                        curCost = res2.cost;\n                        curRes = res2;\n                        curPath = path_from_nb(nb, N);\n                        improved = true;\n                        // Optional: early continue to exploit cascade\n                        continue;\n                    }else{\n                        // revert flip\n                        try_flip_square(nb, N, x, y);\n                    }\n                }\n            }\n            if(!improved) break;\n        }\n        // If improved path obtained, update best\n        if(curCost < bestCost){\n            bestCost = curCost;\n            bestPath = curPath;\n            bestRes = curRes;\n        }\n    }\n\n    // Apply reversed if chosen\n    if(bestRes.reversed){\n        reverse(bestPath.begin(), bestPath.end());\n        // start index relative to reversed path is bestRes.startIndex already computed on reversed\n    }\n    int M = N*N;\n    int startIdx = bestRes.startIndex;\n\n    // Emit operations\n    vector<string> ops;\n    ops.reserve(M*3 + 200);\n\n    int cx = 0, cy = 0;\n    long long load = 0;\n\n    auto move_to = [&](int tx, int ty){\n        while(cy < ty){ ops.emplace_back(\"R\"); cy++; }\n        while(cy > ty){ ops.emplace_back(\"L\"); cy--; }\n        while(cx < tx){ ops.emplace_back(\"D\"); cx++; }\n        while(cx > tx){ ops.emplace_back(\"U\"); cx--; }\n    };\n\n    // Reposition to start\n    int sx = bestPath[startIdx].first, sy = bestPath[startIdx].second;\n    move_to(sx, sy);\n\n    // Traverse along the cycle from the chosen start\n    for(int t=0;t<M;t++){\n        int idx = (startIdx + t) % M;\n        int x = bestPath[idx].first, y = bestPath[idx].second;\n        int val = h[x][y];\n        if(val > 0){\n            ops.emplace_back(\"+\" + to_string(val));\n            load += val;\n            h[x][y] = 0;\n        }else if(val < 0){\n            int need = -val;\n            long long give = min<long long>(need, load);\n            if(give > 0){\n                ops.emplace_back(\"-\" + to_string(give));\n                load -= give;\n                h[x][y] += (int)give;\n            }\n            // With correct start, we should always satisfy need fully\n        }\n        if(t != M-1){\n            int nx = bestPath[(idx+1)%M].first, ny = bestPath[(idx+1)%M].second;\n            if(nx == x){\n                if(ny == y+1){ ops.emplace_back(\"R\"); cy++; }\n                else if(ny == y-1){ ops.emplace_back(\"L\"); cy--; }\n                else { move_to(nx, ny); } // Shouldn't happen\n            }else if(ny == y){\n                if(nx == x+1){ ops.emplace_back(\"D\"); cx++; }\n                else if(nx == x-1){ ops.emplace_back(\"U\"); cx--; }\n                else { move_to(nx, ny); }\n            }else{\n                move_to(nx, ny);\n            }\n        }\n    }\n\n    for(const auto& s : ops) cout << s << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\n// AHC035 \"Grain\" heuristic\n// - Preserve carriers and encourage coverage.\n// - Hybrid objective includes:\n//     * Node term (deg * importance),\n//     * Pair spread term (both-carry/one-carry weighted by Xmax/cnt),\n//     * Softmax over edge \"sum of per-dimension maxima\" to target a super edge.\n// - Selection includes anchor pair but we allow restarts with and without locking.\n\nstruct RNG {\n    uint64_t x;\n    RNG() {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        x = seed ^ (seed << 13);\n    }\n    inline uint32_t next_u32() {\n        uint64_t y = x;\n        y ^= (y << 7);\n        y ^= (y >> 9);\n        x = y;\n        return (uint32_t)(y & 0xffffffffu);\n    }\n    inline int randint(int lo, int hi) { // inclusive\n        uint32_t r = next_u32();\n        return lo + (int)(r % (uint32_t)(hi - lo + 1));\n    }\n    inline double rand01() {\n        return (next_u32() / 4294967296.0);\n    }\n};\n\nstruct Params {\n    // Node weights\n    double wV, wRare, wCnt, wMissNode;\n    // Pair spread term\n    double pairFactor, pairBoth, pairOne;\n    // Softmax over edge Q\n    double beta, mu; // objective adds mu * log(sum_e exp(beta * Q_e))\n    // Anchor pair selection\n    double anchWmax, anchBoth, anchOne, anchV;\n    // LS iterations per restart\n    int iters;\n    // Selection coverage\n    int targetCoverage;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    if (!(cin >> N >> M >> T)) return 0;\n\n    const int SEED_COUNT = 2 * N * (N - 1); // 60 for N=6\n    vector<vector<int>> X(SEED_COUNT, vector<int>(M));\n    for (int i = 0; i < SEED_COUNT; i++) for (int j = 0; j < M; j++) cin >> X[i][j];\n\n    // Compute Xmax per dimension (upper bound, fixed)\n    vector<int> Xmax(M, 0);\n    for (int l = 0; l < M; l++) {\n        int mx = 0;\n        for (int k = 0; k < SEED_COUNT; k++) mx = max(mx, X[k][l]);\n        Xmax[l] = mx;\n    }\n\n    // Grid topology\n    auto pos_id = [&](int i, int j){ return i * N + j; };\n    vector<vector<int>> neighbors(N*N);\n    vector<int> deg(N*N, 0);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int u = pos_id(i,j);\n        if (i > 0)   neighbors[u].push_back(pos_id(i-1,j));\n        if (i+1 < N) neighbors[u].push_back(pos_id(i+1,j));\n        if (j > 0)   neighbors[u].push_back(pos_id(i,j-1));\n        if (j+1 < N) neighbors[u].push_back(pos_id(i,j+1));\n        deg[u] = (int)neighbors[u].size();\n    }\n    // Edge list\n    vector<pair<int,int>> edges;\n    for (int u = 0; u < N*N; u++) for (int v: neighbors[u]) if (u < v) edges.emplace_back(u, v);\n    int E = (int)edges.size(); // 60 for 6x6 grid\n\n    // Edge indices by position\n    vector<vector<int>> edgeIdxByPos(N*N);\n    for (int ei = 0; ei < E; ei++) {\n        auto [u,v] = edges[ei];\n        edgeIdxByPos[u].push_back(ei);\n        edgeIdxByPos[v].push_back(ei);\n    }\n\n    // Position order (deg desc, center proximity asc)\n    vector<int> posOrder(N*N);\n    iota(posOrder.begin(), posOrder.end(), 0);\n    const double ci = (N-1)/2.0, cj = (N-1)/2.0;\n    sort(posOrder.begin(), posOrder.end(), [&](int a, int b){\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        int ai = a / N, aj = a % N;\n        int bi = b / N, bj = b % N;\n        double da = fabs(ai - ci) + fabs(aj - cj);\n        double db = fabs(bi - ci) + fabs(bj - cj);\n        if (da != db) return da < db;\n        return a < b;\n    });\n\n    // Choose a central adjacent pair for anchor positions\n    int centerPos = pos_id(N/2 - 1, N/2 - 1);\n    int ci0 = centerPos / N, cj0 = centerPos % N;\n    int anchorPosA = centerPos;\n    int anchorPosB = (cj0 + 1 < N ? pos_id(ci0, cj0 + 1) : pos_id(ci0 + 1, cj0));\n\n    RNG rng;\n\n    auto paramsForTurn = [&](int t)->Params{\n        if (t <= 3) {\n            return Params{\n                // Node\n                0.16, 10.0, 9.0, 8.0,\n                // Pair spread\n                2.0, 2.6, 1.6,\n                // Softmax\n                0.0040, 2600.0,\n                // Anchor select\n                1.0, 8.0, 3.0, 0.001,\n                // iters\n                45000,\n                // target coverage\n                3\n            };\n        } else if (t <= 6) {\n            return Params{\n                0.18, 9.0, 8.0, 6.0,\n                1.9, 3.2, 1.2,\n                0.0045, 3000.0,\n                1.0, 8.0, 3.0, 0.0015,\n                42000,\n                2\n            };\n        } else {\n            return Params{\n                0.20, 8.0, 7.0, 5.0,\n                1.8, 3.8, 0.8,\n                0.0050, 3600.0,\n                1.0, 8.0, 3.0, 0.0020,\n                38000,\n                2\n            };\n        }\n    };\n\n    for (int t = 0; t < T; t++) {\n        auto P = paramsForTurn(t);\n\n        // Compute V and bit masks of Xmax carriers\n        vector<int> V(SEED_COUNT, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            int s = 0;\n            for (int l = 0; l < M; l++) s += X[k][l];\n            V[k] = s;\n        }\n        vector<uint16_t> bits(SEED_COUNT, 0);\n        vector<int> cnt(M, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            uint16_t m = 0;\n            for (int l = 0; l < M; l++) if (X[k][l] == Xmax[l]) m |= (1u << l);\n            bits[k] = m;\n            for (int l = 0; l < M; l++) if ((m >> l) & 1u) cnt[l]++;\n        }\n        uint16_t dimsAvail = 0;\n        for (int l = 0; l < M; l++) if (cnt[l] > 0) dimsAvail |= (1u << l);\n\n        // Rarity weights: wdim[l] = Xmax[l] / cnt[l]\n        vector<double> wdim(M, 0.0);\n        for (int l = 0; l < M; l++) wdim[l] = (cnt[l] ? (double)Xmax[l] / (double)cnt[l] : 0.0);\n\n        // sumW over masks\n        int MASKSZ = 1 << M;\n        vector<double> sumW(MASKSZ, 0.0);\n        for (int m = 1; m < MASKSZ; m++) {\n            int lb = __builtin_ctz(m);\n            int prev = m & (m - 1);\n            sumW[m] = sumW[prev] + wdim[lb];\n        }\n\n        vector<double> rareSum(SEED_COUNT, 0.0);\n        vector<int> carrierCnt(SEED_COUNT, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            rareSum[k] = sumW[bits[k]];\n            carrierCnt[k] = __builtin_popcount((unsigned)bits[k]);\n        }\n\n        // Utility: sum of per-dimension maxima for a pair (upper bound child)\n        auto pairSumMax = [&](int a, int b)->double{\n            double s = 0.0;\n            const auto &xa = X[a];\n            const auto &xb = X[b];\n            for (int l = 0; l < M; l++) s += (xa[l] > xb[l] ? xa[l] : xb[l]);\n            return s;\n        };\n\n        // Choose anchor pair maximizing a weighted pair score\n        int anchorA = 0, anchorB = 1;\n        double bestAnch = -1e100;\n        for (int a = 0; a < SEED_COUNT; a++) {\n            for (int b = a + 1; b < SEED_COUNT; b++) {\n                double smax = pairSumMax(a,b);\n                uint16_t ba = bits[a], bb = bits[b];\n                double sboth = sumW[ba & bb];\n                double sone  = sumW[ba ^ bb];\n                double sc = P.anchWmax * smax + P.anchBoth * sboth + P.anchOne * sone + P.anchV * (V[a] + V[b]);\n                sc += (rng.rand01() - 0.5) * 1e-6;\n                if (sc > bestAnch) { bestAnch = sc; anchorA = a; anchorB = b; }\n            }\n        }\n        uint16_t maskA = bits[anchorA];\n        uint16_t maskB = bits[anchorB];\n        uint16_t missA = (uint16_t)(dimsAvail & (~maskA));\n        uint16_t missB = (uint16_t)(dimsAvail & (~maskB));\n        uint16_t missUnion = (uint16_t)(dimsAvail & (~(maskA | maskB)));\n\n        // Selection: include anchor pair, ensure at least one carrier per dim, greedily fill coverage\n        vector<int> selected; selected.reserve(N*N);\n        vector<char> used(SEED_COUNT, 0);\n        auto include = [&](int k){\n            if (!used[k]) { used[k] = 1; selected.push_back(k); }\n        };\n        include(anchorA);\n        include(anchorB);\n\n        for (int l = 0; l < M; l++) {\n            if (cnt[l] == 0) continue;\n            int best = -1, bestV = -1;\n            for (int k = 0; k < SEED_COUNT; k++) if (!used[k] && ((bits[k] >> l) & 1u)) {\n                if (V[k] > bestV) bestV = V[k], best = k;\n            }\n            if (best != -1) include(best);\n        }\n\n        vector<int> coverage(M, 0);\n        for (int k : selected) for (int l = 0; l < M; l++) if ((bits[k] >> l) & 1u) coverage[l]++;\n\n        auto needWeight = [&](int l)->double{\n            if (cnt[l] == 0) return 0.0;\n            int need = max(0, P.targetCoverage - coverage[l]);\n            if (need <= 0) return 0.0;\n            return (double)need * (1.0 + 2.5 * wdim[l]); // Xmax-weighted rarity\n        };\n\n        while ((int)selected.size() < N*N) {\n            int bestK = -1;\n            double bestSc = -1e100;\n            for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) {\n                double covGain = 0.0;\n                for (int l = 0; l < M; l++) if ((bits[k] >> l) & 1u) covGain += needWeight(l);\n                double missUnionGain = sumW[bits[k] & missUnion];\n                double sc = 0.012 * V[k] + covGain + 80.0 * missUnionGain;\n                if (sc > bestSc) bestSc = sc, bestK = k;\n            }\n            if (bestK == -1) break;\n            include(bestK);\n            for (int l = 0; l < M; l++) if ((bits[bestK] >> l) & 1u) coverage[l]++;\n        }\n        if ((int)selected.size() < N*N) {\n            vector<int> rest;\n            for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) rest.push_back(k);\n            sort(rest.begin(), rest.end(), [&](int a, int b){\n                if (V[a] != V[b]) return V[a] > V[b];\n                return a < b;\n            });\n            for (int k : rest) {\n                if ((int)selected.size() >= N*N) break;\n                include(k);\n            }\n        }\n\n        // Node weights\n        vector<double> nodeWeight(SEED_COUNT, 0.0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            nodeWeight[k] = P.wV * V[k] + P.wRare * rareSum[k] + P.wCnt * carrierCnt[k]\n                          + P.wMissNode * sumW[bits[k] & missUnion];\n        }\n\n        // Pair spread score (both/one) using rarity Xmax/cnt\n        auto pairSpread = [&](int a, int b)->double{\n            uint16_t ma = bits[a], mb = bits[b];\n            return P.pairBoth * sumW[ma & mb] + P.pairOne * sumW[ma ^ mb];\n        };\n\n        // Edge Q for softmax: sum of per-dimension maxima\n        auto edgeQ = [&](int a, int b)->double{\n            double s = 0.0;\n            const auto &xa = X[a];\n            const auto &xb = X[b];\n            for (int l = 0; l < M; l++) s += (xa[l] > xb[l] ? xa[l] : xb[l]);\n            return s;\n        };\n\n        // Restarts:\n        // 0: anchors locked\n        // 1: anchors placed but not locked\n        // 2: no anchors considered\n        int restarts = 3;\n        double bestObj = -1e100;\n        vector<int> bestAssign;\n\n        auto build_initial_assignment = [&](int mode)->vector<int>{\n            vector<int> assignPos(N*N, -1);\n            vector<char> usedSeed(SEED_COUNT, 0);\n            auto noise = [&](double amp){ return (rng.rand01() - 0.5) * amp; };\n\n            if (mode == 0 || mode == 1) {\n                // Place anchors\n                assignPos[anchorPosA] = anchorA; usedSeed[anchorA] = 1;\n                assignPos[anchorPosB] = anchorB; usedSeed[anchorB] = 1;\n                // Neighbors to cover missing dims around anchors\n                vector<int> neighA, neighB;\n                for (int nb : neighbors[anchorPosA]) if (nb != anchorPosB) neighA.push_back(nb);\n                for (int nb : neighbors[anchorPosB]) if (nb != anchorPosA) neighB.push_back(nb);\n\n                vector<int> pool = selected;\n                pool.erase(remove(pool.begin(), pool.end(), anchorA), pool.end());\n                pool.erase(remove(pool.begin(), pool.end(), anchorB), pool.end());\n\n                vector<pair<double,int>> candA;\n                vector<pair<double,int>> candB;\n                candA.reserve(pool.size());\n                candB.reserve(pool.size());\n                for (int k : pool) {\n                    double scA = 300.0 * sumW[bits[k] & missA] + 0.05 * V[k] + 10.0 * rareSum[k] + noise(0.01);\n                    double scB = 300.0 * sumW[bits[k] & missB] + 0.05 * V[k] + 10.0 * rareSum[k] + noise(0.01);\n                    candA.emplace_back(scA, k);\n                    candB.emplace_back(scB, k);\n                }\n                sort(candA.begin(), candA.end(), greater<>());\n                sort(candB.begin(), candB.end(), greater<>());\n                for (int pos : neighA) {\n                    int chosen = -1;\n                    for (auto &pr : candA) if (!usedSeed[pr.second]) { chosen = pr.second; break; }\n                    if (chosen != -1) { assignPos[pos] = chosen; usedSeed[chosen] = 1; }\n                }\n                for (int pos : neighB) {\n                    if (assignPos[pos] != -1) continue;\n                    int chosen = -1;\n                    for (auto &pr : candB) if (!usedSeed[pr.second]) { chosen = pr.second; break; }\n                    if (chosen != -1) { assignPos[pos] = chosen; usedSeed[chosen] = 1; }\n                }\n                // Fill remaining positions by nodeWeight ranking\n                vector<pair<double,int>> rankSeeds;\n                for (int k : selected) if (!usedSeed[k]) rankSeeds.emplace_back(nodeWeight[k] + noise(0.05), k);\n                sort(rankSeeds.begin(), rankSeeds.end(), greater<>());\n                for (int pos : posOrder) if (assignPos[pos] == -1) {\n                    if (!rankSeeds.empty()) {\n                        int k = rankSeeds.back().second;\n                        rankSeeds.pop_back();\n                        assignPos[pos] = k;\n                        usedSeed[k] = 1;\n                    }\n                }\n            } else {\n                // Mode 2: no anchors, pure node ranking\n                vector<pair<double,int>> rankSeeds;\n                for (int k : selected) rankSeeds.emplace_back(nodeWeight[k] + (rng.rand01()-0.5)*0.05, k);\n                sort(rankSeeds.begin(), rankSeeds.end(), greater<>());\n                int idx = 0;\n                for (int pos : posOrder) {\n                    assignPos[pos] = rankSeeds[idx++].second;\n                }\n            }\n            // Sanity fill any empty slots\n            for (int pos = 0; pos < N*N; pos++) if (assignPos[pos] == -1) {\n                for (int k : selected) if (!usedSeed[k]) { assignPos[pos] = k; usedSeed[k] = 1; break; }\n            }\n            return assignPos;\n        };\n\n        auto totalObjective = [&](const vector<int>& assignPos, vector<double>& edgeVal, vector<double>& edgeExp, double sumExp)->double{\n            double nodeTerm = 0.0;\n            for (int p = 0; p < N*N; p++) nodeTerm += deg[p] * nodeWeight[assignPos[p]];\n            double pairTerm = 0.0;\n            for (int ei = 0; ei < E; ei++) {\n                int a = assignPos[edges[ei].first];\n                int b = assignPos[edges[ei].second];\n                pairTerm += pairSpread(a, b);\n            }\n            double softTerm = P.mu * log(max(1e-300, sumExp));\n            return nodeTerm + P.pairFactor * pairTerm + softTerm;\n        };\n\n        for (int rr = 0; rr < restarts; rr++) {\n            vector<int> assignPos = build_initial_assignment(rr);\n\n            // Prepare edge Q and exp arrays\n            vector<double> edgeVal(E, 0.0), edgeExp(E, 0.0);\n            double sumExp = 0.0;\n            for (int ei = 0; ei < E; ei++) {\n                int u = edges[ei].first;\n                int v = edges[ei].second;\n                int a = assignPos[u];\n                int b = assignPos[v];\n                double q = edgeQ(a, b);\n                edgeVal[ei] = q;\n                double e = exp(P.beta * q);\n                edgeExp[ei] = e;\n                sumExp += e;\n            }\n\n            double currentObj = totalObjective(assignPos, edgeVal, edgeExp, sumExp);\n\n            int iters = P.iters;\n            for (int it = 0; it < iters; it++) {\n                int aPos = rng.randint(0, N*N-1);\n                int bPos = rng.randint(0, N*N-1);\n                if (aPos == bPos) continue;\n                if (rr == 0) { // lock anchors\n                    if (aPos == anchorPosA || aPos == anchorPosB || bPos == anchorPosA || bPos == anchorPosB) continue;\n                }\n\n                int ka = assignPos[aPos];\n                int kb = assignPos[bPos];\n\n                // Node term delta\n                double delta = 0.0;\n                delta += deg[aPos] * (nodeWeight[kb] - nodeWeight[ka]);\n                delta += deg[bPos] * (nodeWeight[ka] - nodeWeight[kb]);\n\n                // Pair spread delta and softmax updates for changed edges\n                double deltaPair = 0.0;\n\n                static int changedBuf[16];\n                int chN = 0;\n                static bool mark[256];\n                // mark changed edges once\n                for (int ei : edgeIdxByPos[aPos]) if (!mark[ei]) { mark[ei] = true; changedBuf[chN++] = ei; }\n                for (int ei : edgeIdxByPos[bPos]) if (!mark[ei]) { mark[ei] = true; changedBuf[chN++] = ei; }\n\n                double newSumExp = sumExp;\n                for (int idx = 0; idx < chN; idx++) {\n                    int ei = changedBuf[idx];\n                    int u = edges[ei].first;\n                    int v = edges[ei].second;\n                    int su = assignPos[u];\n                    int sv = assignPos[v];\n                    // after swap:\n                    if (u == aPos) su = kb;\n                    else if (u == bPos) su = ka;\n                    if (v == aPos) sv = kb;\n                    else if (v == bPos) sv = ka;\n\n                    // pair spread delta\n                    double oldPS = pairSpread(assignPos[u], assignPos[v]);\n                    double newPS = pairSpread(su, sv);\n                    deltaPair += newPS - oldPS;\n\n                    // softmax update\n                    double oldExp = edgeExp[ei];\n                    double newVal = edgeQ(su, sv);\n                    double newExp = exp(P.beta * newVal);\n                    newSumExp += (newExp - oldExp);\n                }\n                // reset marks\n                for (int idx = 0; idx < chN; idx++) mark[changedBuf[idx]] = false;\n\n                delta += P.pairFactor * deltaPair;\n\n                // Softmax delta\n                if (newSumExp <= 0) continue; // numerical safety\n                double deltaSoft = P.mu * (log(newSumExp) - log(sumExp));\n                double totalDelta = delta + deltaSoft;\n\n                if (totalDelta > 1e-12) {\n                    // Accept swap\n                    swap(assignPos[aPos], assignPos[bPos]);\n                    // Update edge arrays and sumExp\n                    for (int idx = 0; idx < chN; idx++) {\n                        int ei = changedBuf[idx];\n                        int u = edges[ei].first;\n                        int v = edges[ei].second;\n                        int su = assignPos[u];\n                        int sv = assignPos[v];\n                        double q = edgeQ(su, sv);\n                        double e = exp(P.beta * q);\n                        sumExp += (e - edgeExp[ei]);\n                        edgeExp[ei] = e;\n                        edgeVal[ei] = q;\n                    }\n                    currentObj += totalDelta;\n                }\n            }\n\n            if (currentObj > bestObj) {\n                bestObj = currentObj;\n                bestAssign = assignPos;\n            }\n        }\n\n        // Output planting plan\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int pos = i * N + j;\n                cout << bestAssign[pos] << (j + 1 == N ? '\\n' : ' ');\n            }\n        }\n        cout.flush();\n\n        // Read next generation\n        for (int i = 0; i < SEED_COUNT; i++) {\n            for (int j = 0; j < M; j++) cin >> X[i][j];\n        }\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int x, y; };\n\nstruct Hungarian {\n    // Square matrix Hungarian algorithm, O(n^3)\n    static pair<long long, vector<int>> solve(const vector<vector<int>>& cost) {\n        int n = (int)cost.size();\n        const int INF = 1e9;\n        vector<int> u(n+1), v(n+1), p(n+1), way(n+1);\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            int j0 = 0;\n            vector<int> minv(n+1, INF);\n            vector<char> used(n+1, false);\n            do {\n                used[j0] = true;\n                int i0 = p[j0], delta = INF, j1 = 0;\n                for (int j = 1; j <= n; j++) if (!used[j]) {\n                    int cur = cost[i0-1][j-1] - u[i0] - v[j];\n                    if (cur < minv[j]) { minv[j] = cur; way[j] = j0; }\n                    if (minv[j] < delta) { delta = minv[j]; j1 = j; }\n                }\n                for (int j = 0; j <= n; j++) {\n                    if (used[j]) { u[p[j]] += delta; v[j] -= delta; }\n                    else minv[j] -= delta;\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n        vector<int> assignment(n, -1);\n        for (int j = 1; j <= n; j++) if (p[j] != 0) assignment[p[j]-1] = j-1;\n        long long value = -v[0];\n        return {value, assignment};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, V;\n    if (!(cin >> N >> M >> V)) return 0;\n    vector<string> ss(N), tt(N);\n    for (int i = 0; i < N; i++) cin >> ss[i];\n    for (int i = 0; i < N; i++) cin >> tt[i];\n\n    vector<vector<int>> occ(N, vector<int>(N, 0));\n    vector<Pos> sources, targets;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int s = ss[i][j] - '0';\n        int t = tt[i][j] - '0';\n        occ[i][j] = s;\n        if (s == 1 && t == 0) sources.push_back({i,j});\n        if (s == 0 && t == 1) targets.push_back({i,j});\n    }\n    int D = (int)sources.size();\n    // Design the simplest arm: V' = 2, edge length 1\n    int Vp = 2;\n    const int DX[4] = {0, 1, 0, -1}; // E,S,W,N\n    const int DY[4] = {1, 0, -1, 0};\n\n    auto rotdist = [&](int cur, int req) {\n        int d = (req - cur + 4) % 4;\n        return min(d, 4 - d);\n    };\n    auto enumerate_adj = [&](int bx, int by) -> vector<tuple<int,int,int>> {\n        vector<tuple<int,int,int>> res;\n        if (by - 1 >= 0) res.emplace_back(bx, by - 1, 0); // left of cell, face E\n        if (by + 1 < N) res.emplace_back(bx, by + 1, 2);  // right, face W\n        if (bx - 1 >= 0) res.emplace_back(bx - 1, by, 1); // above, face S\n        if (bx + 1 < N) res.emplace_back(bx + 1, by, 3);  // below, face N\n        return res;\n    };\n\n    if ((int)targets.size() != D) {\n        // Fallback safe output\n        cout << Vp << \"\\n\";\n        cout << 0 << \" \" << 1 << \"\\n\";\n        cout << 0 << \" \" << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Pairing: Hungarian on Manhattan distances\n    vector<vector<int>> cost(D, vector<int>(D, 0));\n    for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) {\n        cost[i][j] = abs(sources[i].x - targets[j].x) + abs(sources[i].y - targets[j].y);\n    }\n    vector<int> pairTo(D, -1);\n    if (D > 0) {\n        auto res = Hungarian::solve(cost);\n        pairTo = res.second; // sources[i] -> targets[pairTo[i]]\n    }\n\n    // Build inter-task distance matrix w(i,j) = dist(target_i, source_j)\n    vector<vector<int>> W(D, vector<int>(D, 0));\n    for (int i = 0; i < D; i++) {\n        auto c = targets[pairTo[i]];\n        for (int j = 0; j < D; j++) {\n            auto b = sources[j];\n            W[i][j] = abs(c.x - b.x) + abs(c.y - b.y);\n        }\n    }\n\n    // Initial order via nearest neighbor\n    vector<int> ord;\n    ord.reserve(D);\n    if (D > 0) {\n        vector<char> used(D, 0);\n        // start = argmin_i min_j W[i][j]\n        int start = 0; int bestVal = INT_MAX;\n        for (int i = 0; i < D; i++) {\n            int mn = INT_MAX;\n            for (int j = 0; j < D; j++) mn = min(mn, W[i][j]);\n            if (mn < bestVal) { bestVal = mn; start = i; }\n        }\n        int cur = start;\n        ord.push_back(cur);\n        used[cur] = 1;\n        for (int step = 1; step < D; step++) {\n            int bestj = -1, bestd = INT_MAX;\n            for (int j = 0; j < D; j++) if (!used[j]) {\n                int d = W[cur][j];\n                if (d < bestd) { bestd = d; bestj = j; }\n            }\n            if (bestj == -1) {\n                for (int j = 0; j < D; j++) if (!used[j]) { bestj = j; break; }\n            }\n            ord.push_back(bestj);\n            used[bestj] = 1;\n            cur = bestj;\n        }\n    }\n\n    // 2-opt improvement on path cost sum W[ord[k]][ord[k+1]]\n    auto pathCost = [&]() {\n        long long sum = 0;\n        for (int i = 0; i+1 < D; i++) sum += W[ord[i]][ord[i+1]];\n        return sum;\n    };\n    if (D > 2) {\n        bool improved = true;\n        long long curCost = pathCost();\n        // Single or double pass 2-opt\n        for (int pass = 0; pass < 2 && improved; pass++) {\n            improved = false;\n            for (int i = 0; i < D - 1; i++) {\n                for (int j = i + 1; j < D; j++) {\n                    long long delta = 0;\n                    if (i > 0) delta -= W[ord[i-1]][ord[i]];\n                    if (j + 1 < D) delta -= W[ord[j]][ord[j+1]];\n                    if (i > 0) delta += W[ord[i-1]][ord[j]];\n                    if (j + 1 < D) delta += W[ord[i]][ord[j+1]];\n                    if (delta < 0) {\n                        reverse(ord.begin() + i, ord.begin() + j + 1);\n                        curCost += delta;\n                        improved = true;\n                    }\n                }\n            }\n        }\n    }\n\n    // Precompute adjacency lists per task\n    vector<vector<tuple<int,int,int>>> pickAdj(D), dropAdj(D);\n    for (int i = 0; i < D; i++) {\n        auto b = sources[i];\n        auto c = targets[pairTo[i]];\n        pickAdj[i] = enumerate_adj(b.x, b.y);\n        dropAdj[i] = enumerate_adj(c.x, c.y);\n        // Safety: if at borders there might be fewer than 4 adjacencies\n        if (pickAdj[i].empty() || dropAdj[i].empty()) {\n            // Shouldn't happen because N>=15 and edge len 1; but just in case, add a nearby valid dummy\n            if (b.y - 1 >= 0) pickAdj[i].emplace_back(b.x, b.y - 1, 0);\n            else pickAdj[i].emplace_back(b.x, b.y + 1, 2);\n            if (c.y - 1 >= 0) dropAdj[i].emplace_back(c.x, c.y - 1, 0);\n            else dropAdj[i].emplace_back(c.x, c.y + 1, 2);\n        }\n    }\n\n    // Simulator state and ops buffer\n    vector<string> ops; ops.reserve(100000);\n    int rx = 0, ry = 0; // root\n    int dir = 0;        // 0=E initially\n    bool holding = false;\n\n    auto push_turn = [&](char moveCh, char rotCh, bool P) {\n        string s(2*Vp, '.'); // length 4\n        s[0] = moveCh;\n        s[1] = (rotCh == 'L' || rotCh == 'R') ? rotCh : '.';\n        s[2] = '.';\n        s[3] = (P ? 'P' : '.');\n\n        // Apply movement\n        if (moveCh == 'U') rx -= 1;\n        else if (moveCh == 'D') rx += 1;\n        else if (moveCh == 'L') ry -= 1;\n        else if (moveCh == 'R') ry += 1;\n        rx = max(0, min(N-1, rx));\n        ry = max(0, min(N-1, ry));\n\n        // Apply rotation\n        if (rotCh == 'L') dir = (dir + 3) % 4;\n        else if (rotCh == 'R') dir = (dir + 1) % 4;\n\n        // Apply pick/place\n        if (P) {\n            int fx = rx + DX[dir];\n            int fy = ry + DY[dir];\n            if (0 <= fx && fx < N && 0 <= fy && fy < N) {\n                if (!holding) {\n                    if (occ[fx][fy] == 1) {\n                        occ[fx][fy] = 0; holding = true;\n                    }\n                } else {\n                    if (occ[fx][fy] == 0) {\n                        occ[fx][fy] = 1; holding = false;\n                    }\n                }\n            }\n        }\n\n        ops.push_back(s);\n    };\n\n    auto rotate_step_char = [&](int cur, int req) -> char {\n        int d = (req - cur + 4) % 4;\n        if (d == 0) return '.';\n        if (d == 1) return 'R';\n        if (d == 3) return 'L';\n        return 'R'; // d==2, pick 'R' twice\n    };\n\n    auto move_rotate_to = [&](int tx, int ty, int reqdir, bool fuseP) {\n        int dx = abs(rx - tx);\n        int dy = abs(ry - ty);\n        int rotNeed = rotdist(dir, reqdir);\n        int totMoves = dx + dy;\n        int rotTail = max(0, rotNeed - totMoves);\n        int totalSteps = totMoves + rotTail;\n\n        int stepIdx = 0;\n        while (rx != tx) {\n            char mv = (rx < tx ? 'D' : 'U');\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn(mv, rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000) return;\n        }\n        while (ry != ty) {\n            char mv = (ry < ty ? 'R' : 'L');\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn(mv, rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000) return;\n        }\n        while (dir != reqdir) {\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn('.', rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000) return;\n        }\n        if (fuseP && totalSteps == 0) {\n            // need one step to press P\n            push_turn('.', '.', true);\n        }\n    };\n\n    auto fusedCost = [&](int rx0, int ry0, int dir0, int ax, int ay, int adir, bool fuseP) -> int {\n        int mv = abs(rx0 - ax) + abs(ry0 - ay);\n        int rr = rotdist(dir0, adir);\n        int c = max(mv, rr);\n        if (fuseP && mv == 0 && rr == 0) return 1;\n        return c;\n    };\n    auto pureMoveCost = [&](int rx0, int ry0, int dir0, int ax, int ay, int adir) -> int {\n        int mv = abs(rx0 - ax) + abs(ry0 - ay);\n        int rr = rotdist(dir0, adir);\n        return max(mv, rr);\n    };\n\n    auto decide_task = [&](int rx0, int ry0, int dir0, int idx, int nextIdx,\n                           // outputs:\n                           int &pickIdx, int &dropIdx, int &nextPickIdx, int &estCost) {\n        const auto &PA = pickAdj[idx];\n        const auto &DA = dropAdj[idx];\n        const auto &NPA = (nextIdx >= 0 ? pickAdj[nextIdx] : vector<tuple<int,int,int>>());\n        long long best = LLONG_MAX;\n        int bp = 0, bd = 0, bnp = -1;\n        for (int pi = 0; pi < (int)PA.size(); pi++) {\n            int px, py, pdir; tie(px, py, pdir) = PA[pi];\n            int costPick = fusedCost(rx0, ry0, dir0, px, py, pdir, true);\n            for (int di = 0; di < (int)DA.size(); di++) {\n                int dx, dy, ddir; tie(dx, dy, ddir) = DA[di];\n                int costDrop = fusedCost(px, py, pdir, dx, dy, ddir, true);\n                if (nextIdx < 0 || NPA.empty()) {\n                    long long tot = (long long)costPick + costDrop;\n                    if (tot < best) { best = tot; bp = pi; bd = di; bnp = -1; }\n                } else {\n                    for (int npi = 0; npi < (int)NPA.size(); npi++) {\n                        int nx, ny, ndir; tie(nx, ny, ndir) = NPA[npi];\n                        int link = pureMoveCost(dx, dy, ddir, nx, ny, ndir);\n                        long long tot = (long long)costPick + costDrop + link;\n                        if (tot < best) { best = tot; bp = pi; bd = di; bnp = npi; }\n                    }\n                }\n            }\n        }\n        pickIdx = bp; dropIdx = bd; nextPickIdx = bnp; estCost = (int)min<long long>(best, INT_MAX);\n    };\n\n    if (D == 0) {\n        // No operations needed\n        cout << Vp << \"\\n\";\n        cout << 0 << \" \" << 1 << \"\\n\";\n        cout << 0 << \" \" << 0 << \"\\n\";\n        return 0;\n    }\n\n    // First task decision using initial orientation (dir=0) and free initial position\n    int first = ord[0];\n    int pIdx0 = 0, dIdx0 = 0, npIdx0 = -1, est0 = 0;\n    // For the first task, we can set initial position to the chosen pick adjacency -> movement=0\n    // To reflect that, we'll evaluate costPick as rotations only from dir=0 at that position.\n    // We simulate by passing rx0=px,ry0=py (movement 0) and dir0=0.\n    {\n        const auto &PA = pickAdj[first];\n        const auto &DA = dropAdj[first];\n        int nextIdx = (D >= 2 ? ord[1] : -1);\n        long long best = LLONG_MAX;\n        int bp=0, bd=0, bnp=-1, bestEst=0;\n        for (int pi = 0; pi < (int)PA.size(); pi++) {\n            int px, py, pdir; tie(px, py, pdir) = PA[pi];\n            int costPick = fusedCost(px, py, 0, px, py, pdir, true); // only rotations from dir=0\n            for (int di = 0; di < (int)DA.size(); di++) {\n                int dx, dy, ddir; tie(dx, dy, ddir) = DA[di];\n                int costDrop = fusedCost(px, py, pdir, dx, dy, ddir, true);\n                if (nextIdx < 0) {\n                    long long tot = (long long)costPick + costDrop;\n                    if (tot < best) { best = tot; bp=pi; bd=di; bnp=-1; bestEst=(int)min<long long>(tot, INT_MAX); }\n                } else {\n                    const auto &NPA = pickAdj[nextIdx];\n                    for (int npi = 0; npi < (int)NPA.size(); npi++) {\n                        int nx, ny, ndir; tie(nx, ny, ndir) = NPA[npi];\n                        int link = pureMoveCost(dx, dy, ddir, nx, ny, ndir);\n                        long long tot = (long long)costPick + costDrop + link;\n                        if (tot < best) { best = tot; bp=pi; bd=di; bnp=npi; bestEst=(int)min<long long>(tot, INT_MAX); }\n                    }\n                }\n            }\n        }\n        pIdx0 = bp; dIdx0 = bd; npIdx0 = bnp; est0 = bestEst;\n    }\n\n    // Set initial root to the chosen pick adjacency of the first task\n    int init_rx, init_ry, init_pdir;\n    tie(init_rx, init_ry, init_pdir) = pickAdj[first][pIdx0];\n    rx = init_rx; ry = init_ry; dir = 0; // initial dir is east per problem\n\n    // Output the tree and initial root position\n    cout << Vp << \"\\n\";\n    cout << 0 << \" \" << 1 << \"\\n\";\n    cout << rx << \" \" << ry << \"\\n\";\n\n    // Process tasks in the chosen order with two-step look-ahead\n    auto process_task = [&](int idx, int nextIdx, int forcedPickIdx, int forcedDropIdx, int forcedNextPickIdx) {\n        // Decide pick/drop using current state and look-ahead\n        int pickIdx, dropIdx, nextPickIdx, estCost;\n        if (forcedPickIdx >= 0 || forcedDropIdx >= 0) {\n            // Use given forced indices if available; still compute the missing ones with look-ahead\n            // But to keep code simple and robust, recompute fully; forced choices already influenced previous choices.\n            (void)forcedPickIdx; (void)forcedDropIdx; (void)forcedNextPickIdx;\n            decide_task(rx, ry, dir, idx, nextIdx, pickIdx, dropIdx, nextPickIdx, estCost);\n        } else {\n            decide_task(rx, ry, dir, idx, nextIdx, pickIdx, dropIdx, nextPickIdx, estCost);\n        }\n\n        // Move to pick adjacency and pick (fused)\n        {\n            int px, py, pdir; tie(px, py, pdir) = pickAdj[idx][pickIdx];\n            move_rotate_to(px, py, pdir, true);\n        }\n        // Move to drop adjacency and place (fused)\n        {\n            int dx, dy, ddir; tie(dx, dy, ddir) = dropAdj[idx][dropIdx];\n            move_rotate_to(dx, dy, ddir, true);\n        }\n        return nextPickIdx; // hint for next, not strictly used\n    };\n\n    // Execute the first task using the preselected adjacencies\n    {\n        // Perform pick at first chosen pick adjacency\n        int px, py, pdir; tie(px, py, pdir) = pickAdj[first][pIdx0];\n        move_rotate_to(px, py, pdir, true);\n        // Then place at chosen drop adjacency\n        int dx, dy, ddir; tie(dx, dy, ddir) = dropAdj[first][dIdx0];\n        move_rotate_to(dx, dy, ddir, true);\n    }\n\n    // Remaining tasks\n    for (int k = 1; k < D; k++) {\n        int idx = ord[k];\n        int nextIdx = (k+1 < D ? ord[k+1] : -1);\n        int hintNextPickIdx = -1;\n        hintNextPickIdx = process_task(idx, nextIdx, -1, -1, -1);\n        if ((int)ops.size() >= 100000) break;\n    }\n\n    // Output operations\n    for (auto &s : ops) cout << s << \"\\n\";\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int LIM = 100000;\nstatic const int PERIM_LIMIT = 400000;\n\nstruct Pt { int x, y, w; };\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nstruct Candidate {\n    vector<pair<int,int>> poly;\n    long long exactScore = LLONG_MIN;\n};\n\nstatic bool point_on_edge(const vector<pair<int,int>>& poly, int x, int y) {\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        int x1 = poly[i].first, y1 = poly[i].second;\n        int x2 = poly[(i+1)%m].first, y2 = poly[(i+1)%m].second;\n        if (x1 == x2) {\n            if (x == x1) {\n                int lo = min(y1, y2), hi = max(y1, y2);\n                if (lo <= y && y <= hi) return true;\n            }\n        } else if (y1 == y2) {\n            if (y == y1) {\n                int lo = min(x1, x2), hi = max(x1, x2);\n                if (lo <= x && x <= hi) return true;\n            }\n        }\n    }\n    return false;\n}\n\nstatic bool point_in_polygon(const vector<pair<int,int>>& poly, int x, int y) {\n    if (point_on_edge(poly, x, y)) return true;\n    bool inside = false;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        int x1 = poly[i].first, y1 = poly[i].second;\n        int x2 = poly[(i+1)%m].first, y2 = poly[(i+1)%m].second;\n        if (y1 == y2) continue;\n        int ymin = min(y1, y2), ymax = max(y1, y2);\n        if (y < ymin || y >= ymax) continue;\n        double xint;\n        if (x1 == x2) xint = x1;\n        else xint = x1 + (double)(x2 - x1) * (double)(y - y1) / (double)(y2 - y1);\n        if ((double)x < xint) inside = !inside;\n    }\n    return inside;\n}\n\nstatic long long exact_score_polygon(const vector<pair<int,int>>& poly, const vector<Pt>& pts) {\n    long long s = 0;\n    for (const auto& p : pts) if (point_in_polygon(poly, p.x, p.y)) s += p.w;\n    return s;\n}\n\nstatic long long polygon_perimeter(const vector<pair<int,int>>& poly) {\n    long long peri = 0;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        auto a = poly[i];\n        auto b = poly[(i+1)%m];\n        peri += llabs((long long)a.first - b.first) + llabs((long long)a.second - b.second);\n    }\n    return peri;\n}\n\n// Build grid weights\nstatic vector<vector<int>> build_grid_W(int G, const vector<Pt>& pts) {\n    vector<vector<int>> W(G, vector<int>(G, 0));\n    for (const auto& p : pts) {\n        int xi = (int)((long long)p.x * G / 100001); if (xi < 0) xi = 0; if (xi >= G) xi = G-1;\n        int yi = (int)((long long)p.y * G / 100001); if (yi < 0) yi = 0; if (yi >= G) yi = G-1;\n        W[yi][xi] += p.w;\n    }\n    return W;\n}\n\n// Grid lines: ceil(i*100001/G), capped to LIM\nstatic void build_grid_lines(int G, vector<int>& xs, vector<int>& ys) {\n    xs.resize(G+1); ys.resize(G+1);\n    for (int i = 0; i <= G; ++i) {\n        long long t = 1LL * i * 100001;\n        int v = (int)((t + G - 1) / G);\n        if (v > LIM) v = LIM;\n        xs[i] = v;\n        ys[i] = v;\n    }\n}\n\n// Coarse best rectangle (Kadane over W)\nstruct RectIdx { int L, R, B, T; };\nstatic RectIdx coarse_best_rect_from_W(const vector<vector<int>>& W) {\n    int H = (int)W.size();\n    if (H == 0) return {0,0,0,0};\n    int G = (int)W[0].size();\n    vector<long long> acc(G);\n    long long bestSum = LLONG_MIN;\n    RectIdx best{0,0,0,0};\n    for (int top = 0; top < H; ++top) {\n        fill(acc.begin(), acc.end(), 0);\n        for (int bot = top; bot < H; ++bot) {\n            for (int j = 0; j < G; ++j) acc[j] += W[bot][j];\n            long long s = 0, best1D = LLONG_MIN;\n            int start = 0, l = 0, r = -1;\n            for (int j = 0; j < G; ++j) {\n                if (s <= 0) { s = acc[j]; start = j; }\n                else s += acc[j];\n                if (best1D == LLONG_MIN || s > best1D) { best1D = s; l = start; r = j; }\n            }\n            if (best1D > bestSum) {\n                bestSum = best1D;\n                best = {l, r, top, bot};\n            }\n        }\n    }\n    return best;\n}\n\nstatic vector<pair<int,int>> rect_to_polygon(const RectIdx& r, const vector<int>& xs, const vector<int>& ys) {\n    int Lx = xs[r.L];\n    int Rx = xs[r.R+1] - 1; if (Rx < Lx) Rx = Lx;\n    int By = ys[r.B];\n    int Ty = ys[r.T+1] - 1; if (Ty < By) Ty = By;\n    vector<pair<int,int>> poly;\n    poly.emplace_back(Lx, By);\n    poly.emplace_back(Rx, By);\n    poly.emplace_back(Rx, Ty);\n    poly.emplace_back(Lx, Ty);\n    return poly;\n}\n\n// Region growth\nstruct RegionGrower {\n    int G;\n    vector<vector<int>> W;  // [j][i]\n    vector<int> xs, ys;\n    vector<int> wx, hy;\n    vector<vector<char>> inR;\n    vector<vector<unsigned char>> nmask;\n\n    RegionGrower(int G_, const vector<vector<int>>& W_, const vector<int>& xs_, const vector<int>& ys_)\n        : G(G_), W(W_), xs(xs_), ys(ys_) {\n        wx.resize(G); hy.resize(G);\n        for (int i = 0; i < G; ++i) {\n            wx[i] = xs[i+1] - xs[i]; if (wx[i] < 1) wx[i] = 1;\n            hy[i] = ys[i+1] - ys[i]; if (hy[i] < 1) hy[i] = 1;\n        }\n        inR.assign(G, vector<char>(G, 0));\n        nmask.assign(G, vector<unsigned char>(G, 0));\n    }\n\n    inline int delta_perim_for_cell(int i, int j, unsigned char mask) const {\n        int left = (mask & 1) ? 1 : 0;\n        int right = (mask & 2) ? 1 : 0;\n        int bottom = (mask & 4) ? 1 : 0;\n        int top = (mask & 8) ? 1 : 0;\n        int res = 2 * (wx[i] + hy[j]) - 2 * ( hy[j]*(left + right) + wx[i]*(bottom + top) );\n        return res;\n    }\n    inline bool inside_bounds(int i, int j) const { return 0 <= i && i < G && 0 <= j && j < G; }\n\n    void reset() {\n        for (int j = 0; j < G; ++j) {\n            fill(inR[j].begin(), inR[j].end(), 0);\n            fill(nmask[j].begin(), nmask[j].end(), 0);\n        }\n    }\n\n    struct GrowResult {\n        vector<vector<char>> inside;\n        long long approxScore = 0;\n        long long perim = 0;\n        bool valid = false;\n    };\n\n    struct PQEntry {\n        double key;\n        int i, j;\n        int ver;\n        bool operator<(const PQEntry& other) const { return key < other.key; } // largest first\n    };\n\n    // Add seed-based growth, then fill holes and prune negative leaves\n    GrowResult grow_from_seed(int si, int sj, int mode, double lambda, double time_limit_sec, Timer& tim) {\n        reset();\n        vector<vector<int>> ver(G, vector<int>(G, 0));\n        priority_queue<PQEntry> pq;\n        auto push_update = [&](int i, int j) {\n            if (inR[j][i]) return;\n            unsigned char mask = nmask[j][i];\n            if (mask == 0) return;\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                double gain = (double)sc;\n                // allow adding if sc>0 or if closing perimeter significantly\n                if (sc <= 0 && dper >= 0) return;\n                double key = (double)sc / (double)max(1, dper);\n                key += 1e-9 * sc;\n                pq.push({key, i, j, ++ver[j][i]});\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) return;\n                pq.push({gain, i, j, ++ver[j][i]});\n            }\n        };\n\n        long long perim = 0;\n\n        auto add_cell = [&](int ci, int cj) {\n            unsigned char mask = 0;\n            if (ci > 0 && inR[cj][ci-1]) mask |= 1;\n            if (ci+1 < G && inR[cj][ci+1]) mask |= 2;\n            if (cj > 0 && inR[cj-1][ci]) mask |= 4;\n            if (cj+1 < G && inR[cj+1][ci]) mask |= 8;\n            int dper = delta_perim_for_cell(ci, cj, mask);\n            perim += dper;\n            inR[cj][ci] = 1;\n            if (ci > 0 && !inR[cj][ci-1]) { nmask[cj][ci-1] |= 2; push_update(ci-1, cj); }\n            if (ci+1 < G && !inR[cj][ci+1]) { nmask[cj][ci+1] |= 1; push_update(ci+1, cj); }\n            if (cj > 0 && !inR[cj-1][ci]) { nmask[cj-1][ci] |= 8; push_update(ci, cj-1); }\n            if (cj+1 < G && !inR[cj+1][ci]) { nmask[cj+1][ci] |= 4; push_update(ci, cj+1); }\n        };\n\n        if (mode == 0 && W[sj][si] <= 0) {\n            GrowResult gr; gr.valid = false; return gr;\n        }\n        add_cell(si, sj);\n        if (perim > PERIM_LIMIT) { GrowResult gr; gr.valid = false; return gr; }\n\n        while (!pq.empty()) {\n            if (tim.elapsed() > time_limit_sec) break;\n            auto e = pq.top(); pq.pop();\n            int i = e.i, j = e.j;\n            if (inR[j][i]) continue;\n            if (e.ver != ver[j][i]) continue;\n            unsigned char mask = nmask[j][i];\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (!(sc > 0 || (dper < 0 && sc + 0.0 > -0.5))) continue;\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) continue;\n            }\n            if (perim + dper > PERIM_LIMIT) continue;\n            add_cell(i, j);\n        }\n\n        // Build inside by filling holes\n        auto inside = fill_holes(inR);\n        // Prune negative leaves\n        prune_negative_leaves(inside);\n\n        long long approxScore = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (inside[j][i]) approxScore += W[j][i];\n\n        GrowResult gr;\n        gr.inside = move(inside);\n        gr.approxScore = approxScore;\n        gr.perim = compute_perimeter(gr.inside);\n        gr.valid = true;\n        return gr;\n    }\n\n    // Continue growing from an existing mask\n    GrowResult grow_from_mask(vector<vector<char>> inside, int mode, double lambda, double time_limit_sec, Timer& tim) {\n        // Initialize inR and nmask from provided mask\n        for (int j = 0; j < G; ++j) {\n            for (int i = 0; i < G; ++i) {\n                inR[j][i] = inside[j][i] ? 1 : 0;\n                nmask[j][i] = 0;\n            }\n        }\n        vector<vector<int>> ver(G, vector<int>(G, 0));\n        priority_queue<PQEntry> pq;\n\n        auto set_frontier_for_cell = [&](int i, int j) {\n            if (!inR[j][i]) return;\n            if (i > 0 && !inR[j][i-1]) nmask[j][i-1] |= 2;\n            if (i+1 < G && !inR[j][i+1]) nmask[j][i+1] |= 1;\n            if (j > 0 && !inR[j-1][i]) nmask[j-1][i] |= 8;\n            if (j+1 < G && !inR[j+1][i]) nmask[j+1][i] |= 4;\n        };\n\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) set_frontier_for_cell(i,j);\n\n        auto push_update = [&](int i, int j) {\n            if (inR[j][i]) return;\n            unsigned char mask = nmask[j][i];\n            if (mask == 0) return;\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (!(sc > 0 || (dper < 0 && sc + 0.0 > -0.5))) return;\n                double key = (double)sc / (double)max(1, dper);\n                key += 1e-9 * sc;\n                pq.push({key, i, j, ++ver[j][i]});\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) return;\n                pq.push({gain, i, j, ++ver[j][i]});\n            }\n        };\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (!inR[j][i]) push_update(i,j);\n\n        long long perim = compute_perimeter(inR);\n        auto add_cell = [&](int ci, int cj) {\n            unsigned char mask = 0;\n            if (ci > 0 && inR[cj][ci-1]) mask |= 1;\n            if (ci+1 < G && inR[cj][ci+1]) mask |= 2;\n            if (cj > 0 && inR[cj-1][ci]) mask |= 4;\n            if (cj+1 < G && inR[cj+1][ci]) mask |= 8;\n            int dper = delta_perim_for_cell(ci, cj, mask);\n            perim += dper;\n            inR[cj][ci] = 1;\n            if (ci > 0 && !inR[cj][ci-1]) { nmask[cj][ci-1] |= 2; push_update(ci-1, cj); }\n            if (ci+1 < G && !inR[cj][ci+1]) { nmask[cj][ci+1] |= 1; push_update(ci+1, cj); }\n            if (cj > 0 && !inR[cj-1][ci]) { nmask[cj-1][ci] |= 8; push_update(ci, cj-1); }\n            if (cj+1 < G && !inR[cj+1][ci]) { nmask[cj+1][ci] |= 4; push_update(ci, cj+1); }\n        };\n\n        while (!pq.empty()) {\n            if (tim.elapsed() > time_limit_sec) break;\n            auto e = pq.top(); pq.pop();\n            int i = e.i, j = e.j;\n            if (inR[j][i]) continue;\n            if (e.ver != ver[j][i]) continue;\n            unsigned char mask = nmask[j][i];\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (!(sc > 0 || (dper < 0 && sc + 0.0 > -0.5))) continue;\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) continue;\n            }\n            if (perim + dper > PERIM_LIMIT) continue;\n            add_cell(i, j);\n        }\n\n        auto inside2 = fill_holes(inR);\n        prune_negative_leaves(inside2);\n\n        GrowResult gr;\n        gr.inside = move(inside2);\n        gr.approxScore = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (gr.inside[j][i]) gr.approxScore += W[j][i];\n        gr.perim = compute_perimeter(gr.inside);\n        gr.valid = true;\n        return gr;\n    }\n\n    // Compute perimeter of a mask\n    long long compute_perimeter(const vector<vector<char>>& mask) const {\n        long long per = 0;\n        for (int j = 0; j < G; ++j) {\n            for (int i = 0; i < G; ++i) {\n                if (!mask[j][i]) continue;\n                if (i == 0 || !mask[j][i-1]) per += hy[j];\n                if (i+1 == G || !mask[j][i+1]) per += hy[j];\n                if (j == 0 || !mask[j-1][i]) per += wx[i];\n                if (j+1 == G || !mask[j+1][i]) per += wx[i];\n            }\n        }\n        return per;\n    }\n\n    // Fill holes (outside reachable from border)\n    vector<vector<char>> fill_holes(const vector<vector<char>>& sel) const {\n        vector<vector<char>> visited(G, vector<char>(G, 0));\n        deque<pair<int,int>> dq;\n        auto push_border = [&](int i, int j) {\n            if (!inside_bounds(i,j)) return;\n            if (sel[j][i]) return;\n            if (visited[j][i]) return;\n            visited[j][i] = 1;\n            dq.emplace_back(i,j);\n        };\n        for (int i = 0; i < G; ++i) { push_border(i, 0); push_border(i, G-1); }\n        for (int j = 0; j < G; ++j) { push_border(0, j); push_border(G-1, j); }\n        while (!dq.empty()) {\n            auto [i, j] = dq.front(); dq.pop_front();\n            auto try_push = [&](int ni, int nj) {\n                if (!inside_bounds(ni,nj)) return;\n                if (sel[nj][ni]) return;\n                if (visited[nj][ni]) return;\n                visited[nj][ni] = 1;\n                dq.emplace_back(ni,nj);\n            };\n            try_push(i-1,j); try_push(i+1,j); try_push(i,j-1); try_push(i,j+1);\n        }\n        vector<vector<char>> inside(G, vector<char>(G, 0));\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) inside[j][i] = sel[j][i] || (!visited[j][i] && !sel[j][i]);\n        return inside;\n    }\n\n    // Prune negative leaves to clean spurs\n    void prune_negative_leaves(vector<vector<char>>& inside) const {\n        auto deg = [&](int i, int j)->int {\n            int d = 0;\n            if (i > 0 && inside[j][i-1]) ++d;\n            if (i+1 < G && inside[j][i+1]) ++d;\n            if (j > 0 && inside[j-1][i]) ++d;\n            if (j+1 < G && inside[j+1][i]) ++d;\n            return d;\n        };\n        deque<pair<int,int>> dq;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) {\n            if (!inside[j][i]) continue;\n            if (W[j][i] < 0 && deg(i,j) <= 1) dq.emplace_back(i,j);\n        }\n        int cntInside = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (inside[j][i]) ++cntInside;\n        while (!dq.empty()) {\n            auto [i,j] = dq.front(); dq.pop_front();\n            if (!inside[j][i]) continue;\n            if (W[j][i] >= 0) continue;\n            int d = deg(i,j);\n            if (d > 1) continue;\n            // avoid removing last cell\n            if (cntInside <= 1) break;\n            inside[j][i] = 0;\n            --cntInside;\n            // neighbors might become leaves now\n            if (i > 0 && inside[j][i-1] && W[j][i-1] < 0 && deg(i-1,j) <= 1) dq.emplace_back(i-1,j);\n            if (i+1 < G && inside[j][i+1] && W[j][i+1] < 0 && deg(i+1,j) <= 1) dq.emplace_back(i+1,j);\n            if (j > 0 && inside[j-1][i] && W[j-1][i] < 0 && deg(i,j-1) <= 1) dq.emplace_back(i,j-1);\n            if (j+1 < G && inside[j+1][i] && W[j+1][i] < 0 && deg(i,j+1) <= 1) dq.emplace_back(i,j+1);\n        }\n    }\n\n    // Convert inside mask to boundary polygon\n    vector<pair<int,int>> inside_to_polygon(const vector<vector<char>>& inside) const {\n        struct KeyHash { size_t operator()(const uint64_t& k) const noexcept { return std::hash<uint64_t>{}(k); } };\n        auto keyOf = [&](int x, int y)->uint64_t { return (uint64_t)((uint32_t)x) << 32 | (uint32_t)y; };\n        unordered_map<uint64_t, int, KeyHash> id;\n        vector<pair<int,int>> verts;\n        vector<vector<int>> adj;\n\n        auto get_id = [&](int x, int y)->int {\n            uint64_t key = keyOf(x, y);\n            auto it = id.find(key);\n            if (it != id.end()) return it->second;\n            int idx = (int)verts.size();\n            verts.emplace_back(x, y);\n            adj.emplace_back();\n            id.emplace(key, idx);\n            return idx;\n        };\n        auto add_edge = [&](int x1, int y1, int x2, int y2){\n            if (x1 == x2 && y1 == y2) return;\n            int a = get_id(x1, y1);\n            int b = get_id(x2, y2);\n            adj[a].push_back(b);\n            adj[b].push_back(a);\n        };\n\n        for (int j = 0; j < G; ++j) {\n            for (int i = 0; i < G; ++i) {\n                if (!inside[j][i]) continue;\n                int x0 = xs[i], x1 = xs[i+1];\n                int y0 = ys[j], y1 = ys[j+1];\n                if (i == 0 || !inside[j][i-1]) add_edge(x0, y0, x0, y1);\n                if (i+1 == G || !inside[j][i+1]) add_edge(x1, y0, x1, y1);\n                if (j == 0 || !inside[j-1][i]) add_edge(x0, y0, x1, y0);\n                if (j+1 == G || !inside[j+1][i]) add_edge(x0, y1, x1, y1);\n            }\n        }\n        if (verts.empty()) return {};\n        // find start vertex: minimal (y, x)\n        int start = 0;\n        for (int i = 1; i < (int)verts.size(); ++i) {\n            if (verts[i].second < verts[start].second ||\n                (verts[i].second == verts[start].second && verts[i].first < verts[start].first)) {\n                start = i;\n            }\n        }\n        // Traverse one cycle\n        vector<int> path;\n        int cur = start, prev = -1;\n        unordered_set<long long> usedEdge; usedEdge.reserve(adj.size()*2+1);\n        auto edgeKey = [&](int a, int b)->long long { if (a<b) return ((long long)a<<32)|b; else return ((long long)b<<32)|a; };\n        for (int step = 0; step < 400000; ++step) {\n            path.push_back(cur);\n            int next = -1;\n            for (int nb : adj[cur]) {\n                if (nb == prev) continue;\n                long long ek = edgeKey(cur, nb);\n                if (usedEdge.find(ek) != usedEdge.end()) continue;\n                next = nb; break;\n            }\n            if (next == -1) {\n                if (!adj[cur].empty()) {\n                    int nb = adj[cur][0];\n                    long long ek = edgeKey(cur, nb);\n                    if (usedEdge.find(ek) == usedEdge.end()) next = nb;\n                }\n            }\n            if (next == -1) break;\n            usedEdge.insert(edgeKey(cur, next));\n            prev = cur;\n            cur = next;\n            if (cur == start) break;\n        }\n        vector<pair<int,int>> poly;\n        for (int idv : path) poly.push_back(verts[idv]);\n        if (!poly.empty() && poly.front() == poly.back()) poly.pop_back();\n        // remove consecutive duplicates\n        vector<pair<int,int>> tmp;\n        for (auto &p : poly) { if (!tmp.empty() && tmp.back() == p) continue; tmp.push_back(p); }\n        poly.swap(tmp);\n        // simplify collinear\n        if (poly.size() >= 3) {\n            vector<pair<int,int>> simp;\n            int m = (int)poly.size();\n            for (int i = 0; i < m; ++i) {\n                auto p0 = poly[(i + m - 1) % m];\n                auto p1 = poly[i];\n                auto p2 = poly[(i + 1) % m];\n                bool col = ( (p0.first == p1.first && p1.first == p2.first) ||\n                             (p0.second == p1.second && p1.second == p2.second) );\n                if (!col) simp.push_back(p1);\n            }\n            poly.swap(simp);\n        }\n        return poly;\n    }\n};\n\n// Rectangle refinement baseline\nstruct Rect {\n    int L, R, B, T;\n    long long perim() const { return 2LL * (max(0, R - L) + max(0, T - B)); }\n    void ensure_min_size() {\n        L = max(L, 0); B = max(B, 0); R = min(R, LIM); T = min(T, LIM);\n        if (L >= R) { if (L > 0) L = R - 1; else R = L + 1; }\n        if (B >= T) { if (B > 0) B = T - 1; else T = B + 1; }\n        L = max(L, 0); B = max(B, 0); R = min(R, LIM); T = min(T, LIM);\n    }\n};\nstruct ColData { vector<int> xs; vector<vector<int>> ys; vector<vector<int>> pref; };\nstruct RowData { vector<int> ys; vector<vector<int>> xs; vector<vector<int>> pref; };\n\nstruct Refiner {\n    const ColData &col; const RowData &row;\n    Refiner(const ColData& c, const RowData& r): col(c), row(r) {}\n    inline int col_sum_idx(int xi, int B, int T) const {\n        if (xi < 0 || xi >= (int)col.xs.size()) return 0;\n        const auto &ysv = col.ys[xi]; const auto &pf = col.pref[xi];\n        auto itL = lower_bound(ysv.begin(), ysv.end(), B);\n        auto itR = upper_bound(ysv.begin(), ysv.end(), T);\n        int l = (int)(itL - ysv.begin()), r = (int)(itR - ysv.begin());\n        return pf[r] - pf[l];\n    }\n    inline int row_sum_idx(int yi, int L, int R) const {\n        if (yi < 0 || yi >= (int)row.ys.size()) return 0;\n        const auto &xsv = row.xs[yi]; const auto &pf = row.pref[yi];\n        auto itL = lower_bound(xsv.begin(), xsv.end(), L);\n        auto itR = upper_bound(xsv.begin(), xsv.end(), R);\n        int l = (int)(itL - xsv.begin()), r = (int)(itR - xsv.begin());\n        return pf[r] - pf[l];\n    }\n    long long rect_sum(Rect r) const {\n        auto itL = lower_bound(col.xs.begin(), col.xs.end(), r.L);\n        auto itR = upper_bound(col.xs.begin(), col.xs.end(), r.R);\n        long long s = 0;\n        for (auto it = itL; it != itR; ++it) {\n            int xi = (int)(it - col.xs.begin());\n            s += col_sum_idx(xi, r.B, r.T);\n        }\n        return s;\n    }\n    pair<long long,int> best_expand_left(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.L};\n        int kmax = (int)min<long long>(r.L, remain / 2); if (kmax <= 0) return {0, r.L};\n        int idx = (int)(lower_bound(col.xs.begin(), col.xs.end(), r.L) - col.xs.begin()) - 1;\n        if (idx < 0) return {0, r.L};\n        int xLower = r.L - kmax; long long best = 0, run = 0; int bestL = r.L;\n        for (int i = idx; i >= 0; --i) {\n            int x = col.xs[i]; if (x < xLower) break;\n            run += col_sum_idx(i, r.B, r.T);\n            if (run > best) { best = run; bestL = x; }\n        }\n        return {best, bestL};\n    }\n    pair<long long,int> best_shrink_left(const Rect& r) const {\n        if (r.L >= r.R) return {0, r.L};\n        int targetMax = r.R - 1;\n        int iL = (int)(lower_bound(col.xs.begin(), col.xs.end(), r.L) - col.xs.begin());\n        int iR = (int)(upper_bound(col.xs.begin(), col.xs.end(), targetMax) - col.xs.begin()) - 1;\n        if (iL > iR) return {0, r.L};\n        long long best = 0, run = 0; int bestL = r.L;\n        for (int i = iL; i <= iR; ++i) {\n            run += - (long long)col_sum_idx(i, r.B, r.T);\n            if (run > best) {\n                best = run;\n                int newL = col.xs[i] + 1; if (newL > targetMax) newL = targetMax;\n                bestL = newL;\n            }\n        }\n        return {best, bestL};\n    }\n    pair<long long,int> best_expand_right(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.R};\n        int kmax = (int)min<long long>(LIM - r.R, remain / 2); if (kmax <= 0) return {0, r.R};\n        int idx = (int)(upper_bound(col.xs.begin(), col.xs.end(), r.R) - col.xs.begin());\n        if (idx >= (int)col.xs.size()) return {0, r.R};\n        int xUpper = r.R + kmax; long long best = 0, run = 0; int bestR = r.R;\n        for (int i = idx; i < (int)col.xs.size(); ++i) {\n            int x = col.xs[i]; if (x > xUpper) break;\n            run += col_sum_idx(i, r.B, r.T);\n            if (run > best) { best = run; bestR = x; }\n        }\n        return {best, bestR};\n    }\n    pair<long long,int> best_shrink_right(const Rect& r) const {\n        if (r.L >= r.R) return {0, r.R};\n        int targetMin = r.L + 1;\n        int iL = (int)(lower_bound(col.xs.begin(), col.xs.end(), targetMin) - col.xs.begin());\n        int iR = (int)(upper_bound(col.xs.begin(), col.xs.end(), r.R) - col.xs.begin()) - 1;\n        if (iL > iR) return {0, r.R};\n        long long best = 0, run = 0; int bestR = r.R;\n        for (int i = iR; i >= iL; --i) {\n            run += - (long long)col_sum_idx(i, r.B, r.T);\n            if (run > best) {\n                best = run;\n                int newR = col.xs[i] - 1; if (newR < targetMin) newR = targetMin;\n                bestR = newR;\n            }\n        }\n        return {best, bestR};\n    }\n    pair<long long,int> best_expand_bottom(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.B};\n        int kmax = (int)min<long long>(r.B, remain / 2); if (kmax <= 0) return {0, r.B};\n        int idx = (int)(lower_bound(row.ys.begin(), row.ys.end(), r.B) - row.ys.begin()) - 1;\n        if (idx < 0) return {0, r.B};\n        int yLower = r.B - kmax; long long best = 0, run = 0; int bestB = r.B;\n        for (int i = idx; i >= 0; --i) {\n            int y = row.ys[i]; if (y < yLower) break;\n            run += row_sum_idx(i, r.L, r.R);\n            if (run > best) { best = run; bestB = y; }\n        }\n        return {best, bestB};\n    }\n    pair<long long,int> best_shrink_bottom(const Rect& r) const {\n        if (r.B >= r.T) return {0, r.B};\n        int targetMax = r.T - 1;\n        int iL = (int)(lower_bound(row.ys.begin(), row.ys.end(), r.B) - row.ys.begin());\n        int iR = (int)(upper_bound(row.ys.begin(), row.ys.end(), targetMax) - row.ys.begin()) - 1;\n        if (iL > iR) return {0, r.B};\n        long long best = 0, run = 0; int bestB = r.B;\n        for (int i = iL; i <= iR; ++i) {\n            run += - (long long)row_sum_idx(i, r.L, r.R);\n            if (run > best) {\n                best = run;\n                int newB = row.ys[i] + 1; if (newB > targetMax) newB = targetMax;\n                bestB = newB;\n            }\n        }\n        return {best, bestB};\n    }\n    pair<long long,int> best_expand_top(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.T};\n        int kmax = (int)min<long long>(LIM - r.T, remain / 2); if (kmax <= 0) return {0, r.T};\n        int idx = (int)(upper_bound(row.ys.begin(), row.ys.end(), r.T) - row.ys.begin());\n        if (idx >= (int)row.ys.size()) return {0, r.T};\n        int yUpper = r.T + kmax; long long best = 0, run = 0; int bestT = r.T;\n        for (int i = idx; i < (int)row.ys.size(); ++i) {\n            int y = row.ys[i]; if (y > yUpper) break;\n            run += row_sum_idx(i, r.L, r.R);\n            if (run > best) { best = run; bestT = y; }\n        }\n        return {best, bestT};\n    }\n    pair<long long,int> best_shrink_top(const Rect& r) const {\n        if (r.B >= r.T) return {0, r.T};\n        int targetMin = r.B + 1;\n        int iL = (int)(lower_bound(row.ys.begin(), row.ys.end(), targetMin) - row.ys.begin());\n        int iR = (int)(upper_bound(row.ys.begin(), row.ys.end(), r.T) - row.ys.begin()) - 1;\n        if (iL > iR) return {0, r.T};\n        long long best = 0, run = 0; int bestT = r.T;\n        for (int i = iR; i >= iL; --i) {\n            run += - (long long)row_sum_idx(i, r.L, r.R);\n            if (run > best) {\n                best = run;\n                int newT = row.ys[i] - 1; if (newT < targetMin) newT = targetMin;\n                bestT = newT;\n            }\n        }\n        return {best, bestT};\n    }\n\n    Rect refine(Rect r) const {\n        r.ensure_min_size();\n        long long curPerim = r.perim();\n        for (int it = 0; it < 200; ++it) {\n            array<long long, 8> delta{};\n            array<int, 8> newCoord{};\n            auto [d0, nl0] = best_expand_left(r, curPerim);\n            delta[0] = d0; newCoord[0] = nl0;\n            auto [d1, nl1] = best_shrink_left(r);\n            delta[1] = d1; newCoord[1] = nl1;\n            auto [d2, nr2] = best_expand_right(r, curPerim);\n            delta[2] = d2; newCoord[2] = nr2;\n            auto [d3, nr3] = best_shrink_right(r);\n            delta[3] = d3; newCoord[3] = nr3;\n            auto [d4, nb4] = best_expand_bottom(r, curPerim);\n            delta[4] = d4; newCoord[4] = nb4;\n            auto [d5, nb5] = best_shrink_bottom(r);\n            delta[5] = d5; newCoord[5] = nb5;\n            auto [d6, nt6] = best_expand_top(r, curPerim);\n            delta[6] = d6; newCoord[6] = nt6;\n            auto [d7, nt7] = best_shrink_top(r);\n            delta[7] = d7; newCoord[7] = nt7;\n            long long bestDelta = 0; int bestMove = -1;\n            for (int k = 0; k < 8; ++k) if (delta[k] > bestDelta) { bestDelta = delta[k]; bestMove = k; }\n            if (bestDelta <= 0) break;\n            if (bestMove == 0) { int oldL = r.L; r.L = newCoord[0]; curPerim += 2LL * (oldL - r.L); }\n            else if (bestMove == 1) { int oldL = r.L; r.L = newCoord[1]; curPerim -= 2LL * (r.L - oldL); }\n            else if (bestMove == 2) { int oldR = r.R; r.R = newCoord[2]; curPerim += 2LL * (r.R - oldR); }\n            else if (bestMove == 3) { int oldR = r.R; r.R = newCoord[3]; curPerim -= 2LL * (oldR - r.R); }\n            else if (bestMove == 4) { int oldB = r.B; r.B = newCoord[4]; curPerim += 2LL * (oldB - r.B); }\n            else if (bestMove == 5) { int oldB = r.B; r.B = newCoord[5]; curPerim -= 2LL * (r.B - oldB); }\n            else if (bestMove == 6) { int oldT = r.T; r.T = newCoord[6]; curPerim += 2LL * (r.T - oldT); }\n            else if (bestMove == 7) { int oldT = r.T; r.T = newCoord[7]; curPerim -= 2LL * (oldT - r.T); }\n            r.ensure_min_size();\n            if (curPerim > PERIM_LIMIT) {\n                while (r.perim() > PERIM_LIMIT && r.R - r.L > 1) --r.R;\n                while (r.perim() > PERIM_LIMIT && r.T - r.B > 1) --r.T;\n                curPerim = r.perim();\n            }\n        }\n        r.ensure_min_size();\n        return r;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<Pt> pts;\n    pts.reserve(2*N);\n    for (int i = 0; i < N; ++i) { int x,y; cin >> x >> y; pts.push_back({x,y,+1}); }\n    for (int i = 0; i < N; ++i) { int x,y; cin >> x >> y; pts.push_back({x,y,-1}); }\n\n    Timer tim;\n    const double TL = 1.98;\n\n    vector<Candidate> candidates;\n\n    // Rectangle refiner preprocessing\n    ColData col; RowData row;\n    {\n        vector<int> allX, allY;\n        allX.reserve(pts.size()); allY.reserve(pts.size());\n        for (auto &p : pts) { allX.push_back(p.x); allY.push_back(p.y); }\n        sort(allX.begin(), allX.end()); allX.erase(unique(allX.begin(), allX.end()), allX.end());\n        sort(allY.begin(), allY.end()); allY.erase(unique(allY.begin(), allY.end()), allY.end());\n        col.xs = allX; row.ys = allY;\n        col.ys.assign(col.xs.size(), {}); col.pref.assign(col.xs.size(), {});\n        row.xs.assign(row.ys.size(), {}); row.pref.assign(row.ys.size(), {});\n        vector<vector<pair<int,int>>> tempX(col.xs.size());\n        vector<vector<pair<int,int>>> tempY(row.ys.size());\n        for (const auto& p : pts) {\n            int xi = (int)(lower_bound(col.xs.begin(), col.xs.end(), p.x) - col.xs.begin());\n            int yi = (int)(lower_bound(row.ys.begin(), row.ys.end(), p.y) - row.ys.begin());\n            tempX[xi].emplace_back(p.y, p.w);\n            tempY[yi].emplace_back(p.x, p.w);\n        }\n        for (size_t i = 0; i < tempX.size(); ++i) {\n            auto &vec = tempX[i];\n            sort(vec.begin(), vec.end());\n            vector<int> ysMerged; vector<int> wsMerged;\n            ysMerged.reserve(vec.size()); wsMerged.reserve(vec.size());\n            for (size_t k = 0; k < vec.size();) {\n                int y = vec[k].first; int s = 0; size_t k2 = k;\n                while (k2 < vec.size() && vec[k2].first == y) { s += vec[k2].second; ++k2; }\n                ysMerged.push_back(y); wsMerged.push_back(s); k = k2;\n            }\n            col.ys[i] = move(ysMerged);\n            col.pref[i].assign(wsMerged.size()+1, 0);\n            for (size_t t = 0; t < wsMerged.size(); ++t) col.pref[i][t+1] = col.pref[i][t] + wsMerged[t];\n        }\n        for (size_t i = 0; i < tempY.size(); ++i) {\n            auto &vec = tempY[i];\n            sort(vec.begin(), vec.end());\n            vector<int> xsMerged; vector<int> wsMerged;\n            xsMerged.reserve(vec.size()); wsMerged.reserve(vec.size());\n            for (size_t k = 0; k < vec.size();) {\n                int x = vec[k].first; int s = 0; size_t k2 = k;\n                while (k2 < vec.size() && vec[k2].first == x) { s += vec[k2].second; ++k2; }\n                xsMerged.push_back(x); wsMerged.push_back(s); k = k2;\n            }\n            row.xs[i] = move(xsMerged);\n            row.pref[i].assign(wsMerged.size()+1, 0);\n            for (size_t t = 0; t < wsMerged.size(); ++t) row.pref[i][t+1] = row.pref[i][t] + wsMerged[t];\n        }\n    }\n    Refiner ref(col, row);\n\n    // Rectangle seeds from coarse grids with refinement\n    vector<int> Gs_rect = {64, 96, 128};\n    for (int G : Gs_rect) {\n        if (tim.elapsed() > TL * 0.55) break;\n        auto Wg = build_grid_W(G, pts);\n        auto rr = coarse_best_rect_from_W(Wg);\n        vector<int> xs, ys; build_grid_lines(G, xs, ys);\n        vector<pair<int,int>> poly = rect_to_polygon(rr, xs, ys);\n        Rect r{poly[0].first, poly[1].first, poly[0].second, poly[2].second};\n        r.ensure_min_size();\n        Rect refined = ref.refine(r);\n        vector<pair<int,int>> poly2 = {\n            {refined.L, refined.B}, {refined.R, refined.B}, {refined.R, refined.T}, {refined.L, refined.T}\n        };\n        if (polygon_perimeter(poly2) <= PERIM_LIMIT) {\n            Candidate cand; cand.poly = move(poly2);\n            cand.exactScore = exact_score_polygon(cand.poly, pts);\n            candidates.push_back(move(cand));\n        }\n    }\n\n    // Full area rectangle as always-valid fallback\n    {\n        vector<pair<int,int>> poly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n        Candidate cand; cand.poly = move(poly);\n        cand.exactScore = exact_score_polygon(cand.poly, pts);\n        candidates.push_back(move(cand));\n    }\n\n    // Multi-scale region growth with component seeds and pruning\n    struct GridCfg { int G; int maxSeeds; int minSep; vector<double> lambdas; };\n    vector<GridCfg> grids = {\n        {96, 6, 4, {0.0025, 0.005, 0.01}},\n        {128, 5, 4, {0.0025, 0.005}},\n        {160, 3, 4, {0.003, 0.006}},\n        {72, 4, 3, {0.005, 0.01}}\n    };\n\n    double growth_end_time = min(1.65, TL - 0.25); // leave time for polygon scoring and safety\n\n    for (auto cfg : grids) {\n        if (tim.elapsed() > growth_end_time) break;\n        int G = cfg.G;\n        auto Wg = build_grid_W(G, pts);\n        vector<int> xs, ys; build_grid_lines(G, xs, ys);\n        RegionGrower grower(G, Wg, xs, ys);\n\n        // seeds from top positive cells\n        struct Cell { int w, i, j; };\n        vector<Cell> cells;\n        cells.reserve(G*G);\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (Wg[j][i] > 0) cells.push_back({Wg[j][i], i, j});\n        sort(cells.begin(), cells.end(), [](const Cell& a, const Cell& b){\n            if (a.w != b.w) return a.w > b.w;\n            if (a.j != b.j) return a.j < b.j;\n            return a.i < b.i;\n        });\n        vector<pair<int,int>> seeds;\n\n        // seeds from positive components (max weight cell in component)\n        vector<vector<char>> vis(G, vector<char>(G, 0));\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) {\n            if (vis[j][i] || Wg[j][i] <= 0) continue;\n            int bestI = i, bestJ = j, bestW = Wg[j][i];\n            deque<pair<int,int>> dq; dq.emplace_back(i,j); vis[j][i] = 1;\n            while (!dq.empty()) {\n                auto [ci, cj] = dq.front(); dq.pop_front();\n                int cw = Wg[cj][ci];\n                if (cw > bestW) { bestW = cw; bestI = ci; bestJ = cj; }\n                auto try_push = [&](int ni, int nj) {\n                    if (ni<0||ni>=G||nj<0||nj>=G) return;\n                    if (vis[nj][ni]) return;\n                    if (Wg[nj][ni] <= 0) return;\n                    vis[nj][ni] = 1; dq.emplace_back(ni,nj);\n                };\n                try_push(ci-1,cj); try_push(ci+1,cj); try_push(ci,cj-1); try_push(ci,cj+1);\n            }\n            seeds.emplace_back(bestI, bestJ);\n        }\n\n        // merge with best cells, enforcing min separation and cap maxSeeds\n        for (const auto& c : cells) {\n            bool ok = true;\n            for (auto [si, sj] : seeds) if (abs(si - c.i) + abs(sj - c.j) < cfg.minSep) { ok = false; break; }\n            if (!ok) continue;\n            seeds.emplace_back(c.i, c.j);\n            if ((int)seeds.size() >= cfg.maxSeeds) break;\n        }\n        if (seeds.empty()) {\n            int bi=0,bj=0,bw=INT_MIN;\n            for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (Wg[j][i] > bw) { bw = Wg[j][i]; bi=i; bj=j; }\n            seeds.emplace_back(bi,bj);\n        }\n\n        // grow per seed/mode\n        vector<pair<long long, vector<pair<int,int>>>> local_polys; // for keeping best within this grid\n        long long bestLocalScore = LLONG_MIN;\n        vector<vector<char>> bestInside; bool haveBestInside = false;\n\n        double time_limit_sec = TL - 0.15;\n        for (auto [si, sj] : seeds) {\n            if (tim.elapsed() > growth_end_time) break;\n            // ratio-like\n            {\n                auto gr = grower.grow_from_seed(si, sj, 0, 0.0, time_limit_sec, tim);\n                if (gr.valid) {\n                    auto poly = grower.inside_to_polygon(gr.inside);\n                    if (!poly.empty()) {\n                        long long peri = polygon_perimeter(poly);\n                        if (peri <= PERIM_LIMIT && (int)poly.size() <= 1000) {\n                            long long sc = exact_score_polygon(poly, pts);\n                            candidates.push_back({poly, sc});\n                            local_polys.emplace_back(sc, poly);\n                            if (sc > bestLocalScore) { bestLocalScore = sc; bestInside = gr.inside; haveBestInside = true; }\n                        }\n                    }\n                }\n            }\n            for (double lam : cfg.lambdas) {\n                if (tim.elapsed() > growth_end_time) break;\n                auto gr = grower.grow_from_seed(si, sj, 1, lam, time_limit_sec, tim);\n                if (gr.valid) {\n                    auto poly = grower.inside_to_polygon(gr.inside);\n                    if (!poly.empty()) {\n                        long long peri = polygon_perimeter(poly);\n                        if (peri <= PERIM_LIMIT && (int)poly.size() <= 1000) {\n                            long long sc = exact_score_polygon(poly, pts);\n                            candidates.push_back({poly, sc});\n                            local_polys.emplace_back(sc, poly);\n                            if (sc > bestLocalScore) { bestLocalScore = sc; bestInside = gr.inside; haveBestInside = true; }\n                        }\n                    }\n                }\n            }\n        }\n\n        // Second stage: continue growing from the best inside of this grid (if time remains)\n        if (haveBestInside && tim.elapsed() < growth_end_time) {\n            // Try a couple of lambdas\n            vector<double> lam2 = {0.004, 0.007};\n            for (double lam : lam2) {\n                if (tim.elapsed() > growth_end_time) break;\n                auto gr2 = grower.grow_from_mask(bestInside, 1, lam, time_limit_sec, tim);\n                if (gr2.valid) {\n                    auto poly = grower.inside_to_polygon(gr2.inside);\n                    if (!poly.empty()) {\n                        long long peri = polygon_perimeter(poly);\n                        if (peri <= PERIM_LIMIT && (int)poly.size() <= 1000) {\n                            long long sc = exact_score_polygon(poly, pts);\n                            candidates.push_back({poly, sc});\n                            if (sc > bestLocalScore) {\n                                bestLocalScore = sc;\n                                bestInside = gr2.inside;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Select best candidate\n    long long bestScore = LLONG_MIN;\n    int bestIdx = -1;\n    for (int i = 0; i < (int)candidates.size(); ++i) {\n        long long sc = candidates[i].exactScore;\n        if (sc > bestScore) { bestScore = sc; bestIdx = i; }\n    }\n\n    vector<pair<int,int>> bestPoly;\n    if (bestIdx >= 0) bestPoly = candidates[bestIdx].poly;\n    else bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n\n    // Sanity: ensure constraints\n    if ((int)bestPoly.size() < 4) bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n    long long peri = polygon_perimeter(bestPoly);\n    if (peri > PERIM_LIMIT) {\n        for (int iter = 0; iter < 1000 && peri > PERIM_LIMIT; ++iter) {\n            int maxx = 0, maxy = 0;\n            for (auto &p : bestPoly) { maxx = max(maxx, p.first); maxy = max(maxy, p.second); }\n            for (auto &p : bestPoly) {\n                if (p.first == maxx && maxx > 0) --p.first;\n                if (p.second == maxy && maxy > 0) --p.second;\n            }\n            peri = polygon_perimeter(bestPoly);\n        }\n    }\n    if ((int)bestPoly.size() > 1000) {\n        // downsample conservatively (should be rare with our G)\n        vector<pair<int,int>> simp;\n        int step = (int)bestPoly.size() / 900 + 1;\n        for (int i = 0; i < (int)bestPoly.size(); i += step) simp.push_back(bestPoly[i]);\n        if (simp.front() != bestPoly.front()) simp.insert(simp.begin(), bestPoly.front());\n        bestPoly.swap(simp);\n        if (bestPoly.size() < 4) bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n    }\n\n    cout << bestPoly.size() << \"\\n\";\n    for (auto &p : bestPoly) cout << p.first << \" \" << p.second << \"\\n\";\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\n// 64-bit splitmix RNG for deterministic tie-breaking\nstatic uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct Op {\n    int p;   // rectangle index\n    int r;   // rotation 0/1\n    char d;  // 'U' or 'L'\n    int b;   // base index or -1\n};\n\nstruct Column {\n    long long cw;   // column width\n    long long ch;   // accumulated height\n    int top_id;     // top rectangle id\n    int last_id;    // last placed rectangle in this column\n};\n\nstruct Param {\n    double lamW;         // weight for W increase\n    double lamH;         // weight for H increase\n    long long fudge;     // can be negative (optimistic) or non-negative (conservative)\n    double newColBias;   // bias added to open-new-column cost (neg encourages opening)\n    int lookK;           // how many next rectangles to peek\n    double fitWeight;    // reward per future fit (subtracted from new-col cost)\n    unsigned tieRand;    // seed for tie-breaking\n    string tag;          // label for debug\n};\n\nstruct PlanResult {\n    vector<Op> ops;\n    long long W_est;\n    long long H_est;\n};\n\n// Build one plan with weighted decision and lookahead for new column\nPlanResult build_plan(\n    const vector<long long>& wp, const vector<long long>& hp,\n    const Param& P\n){\n    int N = (int)wp.size();\n    vector<Op> ops;\n    ops.reserve(N);\n    vector<Column> cols;\n    cols.reserve(N);\n\n    long long W = 0, H = 0;\n    int lastTopId = -1;\n    uint64_t rng = splitmix64((uint64_t)P.tieRand + 0x123456789abcdefULL);\n\n    auto future_fit_count = [&](int iStart, long long capWidth, long long fudge) -> int {\n        // Count how many of next K rectangles can fit into a column of width capWidth, i.e.,\n        // min(w, h) <= capWidth - fudge.\n        // If fudge is negative, capacity becomes capWidth - fudge > capWidth (optimistic).\n        long long cap = capWidth - fudge;\n        if (cap < 0) cap = 0; // if fudge too large positive\n        int K = P.lookK;\n        if (K <= 0) return 0;\n        int cnt = 0;\n        int end = min(N, iStart + K);\n        for (int j = iStart; j < end; ++j) {\n            long long mw = min(wp[j], hp[j]);\n            if (mw <= cap) cnt++;\n        }\n        return cnt;\n    };\n\n    for (int i = 0; i < N; ++i) {\n        long long w0 = wp[i], h0 = hp[i];\n        long long w1 = hp[i], h1 = wp[i];\n\n        // Best stacking candidate\n        bool hasStack = false;\n        int bestCol = -1;\n        int bestRot = 0;\n        double bestCostStack = 1e300;\n        long long bestSlack = LLONG_MAX;      // prefer minimal slack first\n        long long bestNewColH = LLONG_MAX;    // then smaller resulting column height\n\n        for (int j = 0; j < (int)cols.size(); ++j) {\n            long long cap = cols[j].cw - P.fudge;\n            if (cap < 0) cap = 0;\n            bool fit0 = (w0 <= cap);\n            bool fit1 = (w1 <= cap);\n            if (!fit0 && !fit1) continue;\n\n            int rotSel; long long useW, useH;\n            if (fit0 && fit1) {\n                // Prefer rotation giving smaller resulting column height\n                long long newH0 = cols[j].ch + h0;\n                long long newH1 = cols[j].ch + h1;\n                if (newH0 < newH1) { rotSel = 0; useW = w0; useH = h0; }\n                else if (newH1 < newH0) { rotSel = 1; useW = w1; useH = h1; }\n                else {\n                    // If equal, prefer smaller used width (preserve slack)\n                    if (w0 <= w1) { rotSel = 0; useW = w0; useH = h0; }\n                    else { rotSel = 1; useW = w1; useH = h1; }\n                }\n            } else if (fit0) { rotSel = 0; useW = w0; useH = h0; }\n            else { rotSel = 1; useW = w1; useH = h1; }\n\n            long long newColH = cols[j].ch + useH;\n            long long dH = (newColH > H ? (newColH - H) : 0LL);\n            double cost = P.lamH * (double)dH; // stacking does not change W\n\n            // Tie-breaking: lower cost, then minimal slack, then smaller new column height, then randomness\n            bool better = false;\n            long long slack = cols[j].cw - useW;\n            if (!hasStack || cost < bestCostStack) better = true;\n            else if (fabs(cost - bestCostStack) < 1e-12) {\n                if (slack < bestSlack) better = true;\n                else if (slack == bestSlack) {\n                    if (newColH < bestNewColH) better = true;\n                    else if (newColH == bestNewColH) {\n                        rng = splitmix64(rng);\n                        if ((rng & 1ULL) == 0ULL) better = true;\n                    }\n                }\n            }\n            if (better) {\n                hasStack = true;\n                bestCol = j;\n                bestRot = rotSel;\n                bestCostStack = cost;\n                bestSlack = slack;\n                bestNewColH = newColH;\n            }\n        }\n\n        // Evaluate opening a new column (both rotations) with lookahead reward\n        auto eval_newcol = [&](int rot)->tuple<double,long long,long long> {\n            long long cw = (rot==0? w0 : w1);\n            long long ch = (rot==0? h0 : h1);\n            long long dH = max(0LL, ch - H);\n            double base = P.lamW * (double)cw + P.lamH * (double)dH + P.newColBias;\n            int fitCnt = future_fit_count(i+1, cw, P.fudge);\n            double reward = P.fitWeight * (double)fitCnt;\n            return {base - reward, cw, ch};\n        };\n        auto [costNew0, cw0, ch0] = eval_newcol(0);\n        auto [costNew1, cw1, ch1] = eval_newcol(1);\n        double newColCost; long long newCW, newCH; int newRot;\n        if (costNew1 < costNew0 - 1e-12 || (fabs(costNew1 - costNew0) < 1e-12 && (cw1 < cw0 || (cw1 == cw0 && ch1 < ch0)))) {\n            newColCost = costNew1; newCW = cw1; newCH = ch1; newRot = 1;\n        } else {\n            newColCost = costNew0; newCW = cw0; newCH = ch0; newRot = 0;\n        }\n\n        // Choose action\n        if (hasStack && bestCostStack <= newColCost) {\n            // Stack\n            Op op;\n            op.p = i;\n            op.r = bestRot;\n            op.d = 'L';\n            op.b = cols[bestCol].last_id;\n            ops.push_back(op);\n\n            long long hAdd = (bestRot == 0 ? h0 : h1);\n            cols[bestCol].ch += hAdd;\n            cols[bestCol].last_id = i;\n            H = max(H, cols[bestCol].ch);\n        } else {\n            // New column appended to the right\n            Op op;\n            op.p = i;\n            op.r = newRot;\n            op.d = 'U';\n            op.b = (lastTopId == -1 ? -1 : lastTopId);\n            ops.push_back(op);\n\n            Column c;\n            c.cw = newCW;\n            c.ch = newCH;\n            c.top_id = i;\n            c.last_id = i;\n            cols.push_back(c);\n\n            lastTopId = i;\n            W += newCW;\n            H = max(H, newCH);\n        }\n    }\n\n    return {ops, W, H};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    long long sigma;\n    if (!(cin >> N >> T >> sigma)) return 0;\n    vector<long long> wp(N), hp(N);\n    for (int i = 0; i < N; ++i) cin >> wp[i] >> hp[i];\n\n    // Build a diverse set of parameter combinations\n    vector<long long> fudges = {\n        0LL,\n        max(0LL, sigma / 10),\n        max(0LL, sigma / 5),\n        max(0LL, sigma / 3)\n    };\n\n    struct Combo { Param P; };\n    vector<Combo> combos;\n\n    auto add_combo = [&](double lW, double lH, long long f, double bias, int lookK, double fitW, const string& tag) {\n        Param P;\n        P.lamW = lW; P.lamH = lH; P.fudge = f; P.newColBias = bias;\n        P.lookK = lookK; P.fitWeight = fitW;\n        uint64_t seed = 0;\n        seed ^= (uint64_t)(lW * 1000 + 7) + (uint64_t)(lH * 1000 + 13);\n        seed ^= (uint64_t)(f + 101) + ((uint64_t)(bias * 1000) << 1);\n        seed ^= ((uint64_t)lookK << 3) + (uint64_t)(fitW * 10);\n        P.tieRand = (unsigned)splitmix64(seed);\n        P.tag = tag;\n        combos.push_back({P});\n    };\n\n    // Scales\n    double Uscale = 1e5; // typical rectangle size magnitude\n    double fwSmall = Uscale * 0.10;  // 1e4\n    double fwMed   = Uscale * 0.25;  // 2.5e4\n    double fwLarge = Uscale * 0.40;  // 4e4\n\n    // Baseline families with various fudges, lookahead levels, and biases\n    for (auto f : fudges) {\n        // Balanced\n        add_combo(1.0, 1.0, f, 0.0, 6, 0.0, \"bal_f\"+to_string(f));\n        add_combo(1.0, 1.0, f, -sigma*0.02, 6, fwSmall, \"balFitS_f\"+to_string(f));\n        add_combo(1.0, 1.0, f, -sigma*0.03, 8, fwMed, \"balFitM_f\"+to_string(f));\n\n        // Favor smaller width (discourage new cols)\n        add_combo(1.4, 1.0, f, +sigma*0.03, 6, 0.0, \"W+_f\"+to_string(f));\n        add_combo(1.6, 1.0, f, +sigma*0.05, 6, 0.0, \"W++_f\"+to_string(f));\n\n        // Favor height (encourage new cols)\n        add_combo(1.0, 1.4, f, -sigma*0.02, 6, fwSmall, \"H+FitS_f\"+to_string(f));\n        add_combo(1.0, 1.6, f, -sigma*0.05, 8, fwLarge, \"H++FitL_f\"+to_string(f));\n    }\n\n    // A couple of optimistic variants with small negative fudge\n    long long negF = -(long long)max(1LL, sigma / 10);\n    add_combo(1.1, 0.9, negF, -sigma*0.01, 6, fwSmall, \"optNegF_small\");\n    add_combo(1.0, 1.0, negF, 0.0, 8, fwMed, \"optNegF_bal\");\n\n    int E = min((int)combos.size(), T);\n    long long bestApproxScore = (1LL<<62);\n    Param bestParam{};\n    bool bestSet = false;\n    long long lastWm = -1, lastHm = -1;\n\n    std::mt19937_64 rng(20250914);\n    std::uniform_real_distribution<double> ur(0.0, 1.0);\n\n    for (int t = 0; t < T; ++t) {\n        Param P;\n        string tag;\n        if (t < E) {\n            P = combos[t].P;\n            tag = P.tag;\n        } else {\n            if (!bestSet) {\n                P = combos[t % E].P;\n                tag = \"fallback_\" + combos[t%E].P.tag;\n            } else {\n                P = bestParam;\n                // Rebalance using last measurement W'/H'\n                if (lastWm > 0 && lastHm > 0) {\n                    double r = (double)lastWm / (double)lastHm;\n                    if (r > 1.2) {\n                        P.lamW *= 1.15; P.lamH *= 0.95;\n                        P.newColBias += sigma * 0.01;\n                    } else if (r < 1.0/1.2) {\n                        P.lamH *= 1.15; P.lamW *= 0.95;\n                        P.newColBias -= sigma * 0.01;\n                    }\n                }\n                // Jitter\n                double j1 = (ur(rng) - 0.5) * 0.25; // +-12.5%\n                double j2 = (ur(rng) - 0.5) * 0.25;\n                P.lamW = max(0.2, P.lamW * (1.0 + j1));\n                P.lamH = max(0.2, P.lamH * (1.0 + j2));\n                // Jitter bias and fitWeight moderately\n                P.newColBias += (ur(rng) - 0.5) * (sigma * 0.04);\n                double jf = (ur(rng) - 0.5) * 0.3; // +-30%\n                P.fitWeight = max(0.0, P.fitWeight * (1.0 + jf));\n                // Jitter fudge slightly; keep negative variants if they were best\n                long long jfudge = (long long)((ur(rng) - 0.5) * (double)max(1LL, sigma/5)); // +- sigma/10\n                long long nf = P.fudge + jfudge;\n                // Cap magnitude to ~sigma\n                long long capMag = max(1LL, sigma);\n                if (nf > capMag) nf = capMag;\n                if (nf < -capMag/2) nf = -capMag/2;\n                P.fudge = nf;\n\n                // Occasionally re-explore a baseline\n                if (ur(rng) < 0.10) {\n                    int id = (int)(rng() % E);\n                    P = combos[id].P;\n                    tag = \"reexplore_\" + P.tag;\n                } else {\n                    tag = \"exploit\";\n                }\n            }\n            uint64_t seed = splitmix64((uint64_t)rng());\n            P.tieRand = (unsigned)seed;\n        }\n\n        PlanResult res = build_plan(wp, hp, P);\n\n        // Debug comment\n        cout << \"# t=\" << t\n             << \" W_est=\" << res.W_est << \" H_est=\" << res.H_est\n             << \" lamW=\" << fixed << setprecision(2) << P.lamW\n             << \" lamH=\" << P.lamH\n             << \" fudge=\" << P.fudge\n             << \" bias=\" << P.newColBias\n             << \" lookK=\" << P.lookK\n             << \" fitW=\" << P.fitWeight\n             << \" tag=\" << tag << \"\\n\";\n\n        // Output operations\n        cout << res.ops.size() << \"\\n\";\n        for (auto &op : res.ops) {\n            cout << op.p << \" \" << op.r << \" \" << op.d << \" \" << op.b << \"\\n\";\n        }\n        cout.flush();\n\n        long long Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n        lastWm = Wm; lastHm = Hm;\n\n        long long approxScore = Wm + Hm; // all rectangles placed\n        if (approxScore < bestApproxScore) {\n            bestApproxScore = approxScore;\n            bestParam = P;\n            bestSet = true;\n        }\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double ms() const {\n        return chrono::duration<double, milli>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nstatic const uint16_t INF16 = (uint16_t)30000;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    if (!(cin >> N >> M >> H)) return 0;\n    vector<int> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n    vector<vector<int>> g(N);\n    vector<pair<int,int>> edges(M);\n    for (int i = 0; i < M; i++) {\n        int u, v; cin >> u >> v;\n        edges[i] = {u, v};\n        g[u].push_back(v);\n        g[v].push_back(u);\n    }\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n    Timer timer;\n\n    // Precompute all-pairs shortest distances\n    vector<uint16_t> Dist((size_t)N * (size_t)N, INF16);\n    {\n        vector<int> q; q.reserve(N);\n        vector<int> dist(N);\n        for (int s = 0; s < N; s++) {\n            fill(dist.begin(), dist.end(), -1);\n            q.clear(); q.push_back(s); dist[s] = 0;\n            for (size_t qi = 0; qi < q.size(); qi++) {\n                int u = q[qi];\n                for (int v : g[u]) if (dist[v] == -1) {\n                    dist[v] = dist[u] + 1;\n                    q.push_back(v);\n                }\n            }\n            uint16_t* row = &Dist[(size_t)s * N];\n            for (int v = 0; v < N; v++) row[v] = dist[v] >= 0 ? (uint16_t)dist[v] : INF16;\n        }\n    }\n\n    // Precompute within-H lists\n    vector<vector<int>> withinH(N);\n    for (int u = 0; u < N; u++) {\n        const uint16_t* Du = &Dist[(size_t)u * N];\n        for (int v = 0; v < N; v++) if (Du[v] <= (uint16_t)H) withinH[u].push_back(v);\n    }\n\n    // Greedy roots selection\n    vector<int> roots;\n    vector<char> isRoot(N, 0);\n    vector<uint16_t> dR(N, INF16);\n\n    int s0 = min_element(A.begin(), A.end()) - A.begin();\n    roots.push_back(s0);\n    isRoot[s0] = 1;\n    {\n        const uint16_t* D0 = &Dist[(size_t)s0 * N];\n        for (int v = 0; v < N; v++) dR[v] = D0[v];\n    }\n    auto recompute_dR = [&]() {\n        fill(dR.begin(), dR.end(), INF16);\n        for (int r : roots) {\n            const uint16_t* Dr = &Dist[(size_t)r * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dr[v]);\n        }\n    };\n\n    while (true) {\n        uint16_t dmax = 0;\n        for (int v = 0; v < N; v++) if (dR[v] > dmax) dmax = dR[v];\n        if (dmax <= (uint16_t)H) break;\n\n        vector<int> far;\n        for (int v = 0; v < N; v++) if (dR[v] == dmax) far.push_back(v);\n\n        int bestCand = -1, bestCover = -1, bestA = INT_MAX;\n        for (int cand : far) {\n            int cover = 0;\n            for (int u : withinH[cand]) if (dR[u] > (uint16_t)H) cover++;\n            if (cover > bestCover || (cover == bestCover && A[cand] < bestA)) {\n                bestCover = cover; bestA = A[cand]; bestCand = cand;\n            }\n        }\n        if (bestCand == -1) bestCand = far[0];\n        if (!isRoot[bestCand]) {\n            roots.push_back(bestCand);\n            isRoot[bestCand] = 1;\n            const uint16_t* Dn = &Dist[(size_t)bestCand * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dn[v]);\n        } else {\n            int cand2 = -1;\n            for (int v = 0; v < N; v++) if (dR[v] > (uint16_t)H) { cand2 = v; break; }\n            if (cand2 == -1) break;\n            roots.push_back(cand2);\n            isRoot[cand2] = 1;\n            const uint16_t* Dn = &Dist[(size_t)cand2 * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dn[v]);\n        }\n    }\n\n    // Prune redundant roots\n    auto compute_min12 = [&](vector<uint16_t>& m1, vector<uint16_t>& m2, vector<int>& arg) {\n        m1.assign(N, INF16); m2.assign(N, INF16); arg.assign(N, -1);\n        for (int r : roots) {\n            const uint16_t* Dr = &Dist[(size_t)r * N];\n            for (int v = 0; v < N; v++) {\n                uint16_t d = Dr[v];\n                if (d < m1[v]) {\n                    m2[v] = m1[v]; m1[v] = d; arg[v] = r;\n                } else if (d < m2[v]) {\n                    m2[v] = d;\n                }\n            }\n        }\n    };\n    {\n        vector<uint16_t> m1, m2; vector<int> arg;\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            compute_min12(m1, m2, arg);\n            for (int i = 0; i < (int)roots.size(); i++) {\n                int r = roots[i];\n                bool safe = true;\n                for (int v = 0; v < N; v++) if (arg[v] == r && m2[v] > (uint16_t)H) { safe = false; break; }\n                if (safe) {\n                    isRoot[r] = 0;\n                    roots.erase(roots.begin() + i);\n                    changed = true;\n                    break;\n                }\n            }\n        }\n        recompute_dR();\n    }\n\n    // Very small local swap over roots to improve sum A*dR (time-capped)\n    auto score_of_mindist = [&](const vector<uint16_t>& m1) -> long long {\n        long long S = 0;\n        for (int v = 0; v < N; v++) {\n            uint16_t d = min<uint16_t>(m1[v], (uint16_t)H);\n            S += 1LL * A[v] * d;\n        }\n        return S;\n    };\n    vector<uint16_t> m1, m2; vector<int> arg;\n    compute_min12(m1, m2, arg);\n    long long Scur = score_of_mindist(m1);\n\n    int maxSwapIter = 1; // keep small to leave time for deepening\n    for (int iter = 0; iter < maxSwapIter; iter++) {\n        if (timer.ms() > 1200.0) break;\n        bool improved = false;\n        long long bestDelta = 0;\n        int bestRootIdx = -1, bestCand = -1;\n\n        for (int ir = 0; ir < (int)roots.size(); ir++) {\n            if (timer.ms() > 1200.0) break;\n            int r = roots[ir];\n            vector<int> Z;\n            for (int v = 0; v < N; v++) if (arg[v] == r && m2[v] > (uint16_t)H) Z.push_back(v);\n\n            vector<int> candList;\n            if (Z.empty()) {\n                candList = withinH[r];\n            } else {\n                static vector<int> mark, cnt, visited;\n                static int stamp = 1;\n                if ((int)mark.size() != N) { mark.assign(N, 0); cnt.assign(N, 0); }\n                visited.clear();\n                stamp++;\n                for (int v : Z) {\n                    for (int c : withinH[v]) {\n                        if (mark[c] != stamp) { mark[c] = stamp; cnt[c] = 1; visited.push_back(c); }\n                        else cnt[c]++;\n                    }\n                }\n                for (int c : visited) if (cnt[c] == (int)Z.size()) candList.push_back(c);\n            }\n            for (int c : candList) {\n                if (c == r) continue;\n                const uint16_t* Dc = &Dist[(size_t)c * N];\n                long long Snew = 0;\n                bool ok = true;\n                for (int v = 0; v < N; v++) {\n                    uint16_t d_without = (arg[v] == r ? m2[v] : m1[v]);\n                    uint16_t dprime = min<uint16_t>(d_without, Dc[v]);\n                    if (dprime > (uint16_t)H) { ok = false; break; }\n                    Snew += 1LL * A[v] * dprime;\n                }\n                if (!ok) continue;\n                long long delta = Snew - Scur;\n                if (delta > bestDelta) { bestDelta = delta; bestRootIdx = ir; bestCand = c; }\n            }\n        }\n        if (bestDelta > 0 && bestRootIdx != -1) {\n            int oldr = roots[bestRootIdx];\n            isRoot[oldr] = 0;\n            roots[bestRootIdx] = bestCand;\n            isRoot[bestCand] = 1;\n            compute_min12(m1, m2, arg);\n            Scur = score_of_mindist(m1);\n            improved = true;\n        }\n        if (!improved) break;\n    }\n\n    // Recompute coverage mindist dR (not strictly needed now)\n    recompute_dR();\n\n    // Build initial parents via multi-source BFS\n    vector<int> parent(N, -1);\n    vector<uint16_t> depth(N, INF16);\n    deque<int> dq;\n    for (int r : roots) {\n        depth[r] = 0; parent[r] = -1; dq.push_back(r);\n    }\n    while (!dq.empty()) {\n        int u = dq.front(); dq.pop_front();\n        if (depth[u] >= (uint16_t)H) continue;\n        uint16_t nd = depth[u] + 1;\n        for (int v : g[u]) if (depth[v] == INF16) {\n            depth[v] = nd; parent[v] = u; dq.push_back(v);\n        }\n    }\n    // Safety: if any node remains unvisited (shouldn't), make it a root.\n    for (int v = 0; v < N; v++) if (depth[v] == INF16) { depth[v] = 0; parent[v] = -1; }\n\n    // Prepare children structure\n    vector<vector<int>> children(N);\n    vector<int> posInParent(N, -1);\n    for (int v = 0; v < N; v++) if (parent[v] != -1) {\n        int p = parent[v];\n        posInParent[v] = (int)children[p].size();\n        children[p].push_back(v);\n    }\n\n    // DFS info: tin/tout, order, subtree sums and max depths\n    vector<int> tin(N, 0), tout(N, 0), order(N, -1), rootsNow;\n    vector<long long> subSum(N, 0);\n    vector<uint16_t> subMax(N, 0);\n    function<void(int,int&)> dfs = [&](int u, int &timerDfs) {\n        tin[u] = timerDfs;\n        order[timerDfs] = u;\n        timerDfs++;\n        long long s = A[u];\n        uint16_t mx = depth[u];\n        for (int w : children[u]) {\n            dfs(w, timerDfs);\n            s += subSum[w];\n            mx = max<uint16_t>(mx, subMax[w]);\n        }\n        subSum[u] = s;\n        subMax[u] = mx;\n        tout[u] = timerDfs;\n    };\n    auto recompute_tree_info = [&]() {\n        rootsNow.clear();\n        for (int v = 0; v < N; v++) if (parent[v] == -1) rootsNow.push_back(v);\n        int timerDfs = 0;\n        for (int r : rootsNow) dfs(r, timerDfs);\n    };\n    recompute_tree_info();\n\n    auto is_ancestor = [&](int u, int v) -> bool {\n        return tin[u] <= tin[v] && tout[v] <= tout[u];\n    };\n\n    auto remove_from_parent = [&](int u) {\n        int p = parent[u];\n        if (p == -1) return;\n        int idx = posInParent[u];\n        int last = children[p].back();\n        swap(children[p][idx], children[p].back());\n        children[p].pop_back();\n        posInParent[last] = idx;\n        posInParent[u] = -1;\n        parent[u] = -1;\n    };\n    auto add_to_parent = [&](int u, int p) {\n        parent[u] = p;\n        posInParent[u] = (int)children[p].size();\n        children[p].push_back(u);\n    };\n\n    // Depth-increasing local improvements\n    while (timer.ms() < 1950.0) {\n        long long bestGain = 0;\n        int bestU = -1, bestX = -1;\n        int bestDelta = 0;\n\n        for (int u = 0; u < N; u++) {\n            if (subMax[u] >= (uint16_t)H) continue; // cannot deepen\n            // Try all neighbors as new parent candidates\n            for (int x : g[u]) {\n                if (x == parent[u]) continue;\n                if (is_ancestor(u, x)) continue; // would create cycle\n                int du = depth[u];\n                int dx = depth[x];\n                int delta = dx + 1 - du;\n                if (delta <= 0) continue;\n                if ((int)subMax[u] + delta > H) continue; // height violation\n                long long gain = 1LL * delta * subSum[u];\n                if (gain > bestGain) {\n                    bestGain = gain; bestU = u; bestX = x; bestDelta = delta;\n                }\n            }\n        }\n\n        if (bestGain <= 0 || bestU == -1) break;\n\n        // Apply the best move\n        int u = bestU, x = bestX, delta = bestDelta;\n        // Update depths on the subtree of u using Euler order\n        int L = tin[u], R = tout[u];\n        for (int i = L; i < R; i++) {\n            int w = order[i];\n            depth[w] = (uint16_t)(depth[w] + delta);\n        }\n        // Reparent u under x\n        remove_from_parent(u);\n        add_to_parent(u, x);\n\n        // Recompute tin/tout, subSum/subMax, order\n        recompute_tree_info();\n\n        // If time is nearly up, stop\n        if (timer.ms() > 1990.0) break;\n    }\n\n    // Output final parents\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << parent[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Action {\n    char d;      // 'L','R','U','D'\n    int p;       // row/column index\n    int k;       // length (number of shifts each way)\n    int cost;    // 2*k\n    uint64_t mask; // bitmask of covered Oni (M <= 64; here M=40)\n};\n\nstatic inline char opposite(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\nstatic inline int ctz64(uint64_t x) { return __builtin_ctzll(x); }\n\npair<int,int> simulate(const vector<string>& init, const vector<pair<char,int>>& ops) {\n    int N = init.size();\n    vector<string> g = init;\n    int rem_oni = 0;\n    for (auto &row : g) for (char ch : row) if (ch == 'x') rem_oni++;\n    int removed_oni = 0, removed_fuku = 0;\n    for (auto [d,p] : ops) {\n        if (d == 'L') {\n            char out = g[p][0];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int j = 0; j < N-1; ++j) g[p][j] = g[p][j+1];\n            g[p][N-1] = '.';\n        } else if (d == 'R') {\n            char out = g[p][N-1];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\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            char out = g[0][p];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int i = 0; i < N-1; ++i) g[i][p] = g[i+1][p];\n            g[N-1][p] = '.';\n        } else { // 'D'\n            char out = g[N-1][p];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int i = N-1; i >= 1; --i) g[i][p] = g[i-1][p];\n            g[0][p] = '.';\n        }\n    }\n    int X = rem_oni - removed_oni;\n    int Y = removed_fuku;\n    return {X, Y};\n}\n\n// Build reduced candidate actions: only k at points where we \"pass a new Oni\".\nvector<Action> build_candidates_tight(const vector<string>& grid, const vector<pair<int,int>>& oni_pos,\n                                      const vector<vector<int>>& oni_id) {\n    int N = grid.size();\n    vector<Action> acts;\n    acts.reserve(400);\n\n    // Precompute Lsafe/Rsafe/Usafe/Dsafe based on Fukunokami positions\n    vector<int> Lsafe(N), Rsafe(N);\n    for (int r = 0; r < N; ++r) {\n        int firstF = N, lastF = -1;\n        for (int j = 0; j < N; ++j) if (grid[r][j] == 'o') {\n            firstF = min(firstF, j);\n            lastF = max(lastF, j);\n        }\n        Lsafe[r] = (firstF == N ? N : firstF);\n        Rsafe[r] = (lastF == -1 ? N : (N - 1 - lastF));\n    }\n    vector<int> Usafe(N), Dsafe(N);\n    for (int c = 0; c < N; ++c) {\n        int firstF = N, lastF = -1;\n        for (int i = 0; i < N; ++i) if (grid[i][c] == 'o') {\n            firstF = min(firstF, i);\n            lastF = max(lastF, i);\n        }\n        Usafe[c] = (firstF == N ? N : firstF);\n        Dsafe[c] = (lastF == -1 ? N : (N - 1 - lastF));\n    }\n\n    // Row-left actions\n    for (int r = 0; r < N; ++r) {\n        uint64_t mask = 0;\n        for (int j = 0; j < Lsafe[r]; ++j) {\n            int id = oni_id[r][j];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = j + 1;\n                Action a; a.d = 'L'; a.p = r; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n    // Row-right actions\n    for (int r = 0; r < N; ++r) {\n        uint64_t mask = 0;\n        for (int j = N-1; j >= N - Rsafe[r]; --j) {\n            int id = oni_id[r][j];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = N - j;\n                Action a; a.d = 'R'; a.p = r; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n    // Col-up actions\n    for (int c = 0; c < N; ++c) {\n        uint64_t mask = 0;\n        for (int i = 0; i < Usafe[c]; ++i) {\n            int id = oni_id[i][c];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = i + 1;\n                Action a; a.d = 'U'; a.p = c; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n    // Col-down actions\n    for (int c = 0; c < N; ++c) {\n        uint64_t mask = 0;\n        for (int i = N-1; i >= N - Dsafe[c]; --i) {\n            int id = oni_id[i][c];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = N - i;\n                Action a; a.d = 'D'; a.p = c; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n\n    // Deduplicate identical masks keeping minimal cost\n    unordered_map<uint64_t, int> bestIdx; bestIdx.reserve(acts.size()*2);\n    vector<Action> filtered;\n    filtered.reserve(acts.size());\n    for (int i = 0; i < (int)acts.size(); ++i) {\n        auto it = bestIdx.find(acts[i].mask);\n        if (it == bestIdx.end()) {\n            bestIdx[acts[i].mask] = (int)filtered.size();\n            filtered.push_back(acts[i]);\n        } else {\n            int idx = it->second;\n            if (acts[i].cost < filtered[idx].cost) filtered[idx] = acts[i];\n        }\n    }\n    return filtered;\n}\n\nint selection_cost(const vector<int>& sel, const vector<Action>& acts) {\n    long long s = 0;\n    for (int idx : sel) s += acts[idx].cost;\n    if (s > INT_MAX) return INT_MAX;\n    return (int)s;\n}\n\nvector<int> prune_selection(const vector<int>& sel, const vector<Action>& acts, int M) {\n    if (sel.empty()) return sel;\n    vector<int> cnt(M, 0);\n    for (int idx : sel) {\n        uint64_t m = acts[idx].mask;\n        while (m) { int b = ctz64(m); cnt[b]++; m &= m - 1; }\n    }\n    vector<int> order = sel;\n    sort(order.begin(), order.end(), [&](int a, int b){\n        if (acts[a].cost != acts[b].cost) return acts[a].cost > acts[b].cost;\n        return a < b;\n    });\n    vector<char> alive(acts.size(), 0);\n    for (int idx : sel) alive[idx] = 1;\n\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        for (int idx : order) {\n            if (!alive[idx]) continue;\n            uint64_t m = acts[idx].mask;\n            bool can = true;\n            while (m) {\n                int b = ctz64(m);\n                if (cnt[b] <= 1) { can = false; break; }\n                m &= m - 1;\n            }\n            if (can) {\n                uint64_t mm = acts[idx].mask;\n                while (mm) { int b = ctz64(mm); cnt[b]--; mm &= mm - 1; }\n                alive[idx] = 0;\n                changed = true;\n            }\n        }\n    }\n    vector<int> res;\n    res.reserve(sel.size());\n    for (int idx : sel) if (alive[idx]) res.push_back(idx);\n    return res;\n}\n\n// Greedy selection with weights, per-action cost noise, and stochastic pick among top-K\nvector<int> greedy_select_weighted_noisy(const vector<Action>& acts, int M, const vector<double>& w,\n                                         std::mt19937& rng, double noise_beta = 0.15, int pickK = 3, double pickP2 = 0.15, double pickP3 = 0.05) {\n    int A = (int)acts.size();\n    vector<double> costEff(A);\n    uniform_real_distribution<double> urand(0.0, 1.0);\n    for (int i = 0; i < A; ++i) {\n        double noise = 1.0 + noise_beta * (urand(rng) * 2.0 - 1.0); // in [1-beta, 1+beta]\n        if (noise < 0.5) noise = 0.5; // clamp\n        if (noise > 2.0) noise = 2.0;\n        costEff[i] = acts[i].cost * noise;\n    }\n\n    vector<int> order(A);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    vector<int> rank(A);\n    for (int i = 0; i < A; ++i) rank[order[i]] = i;\n\n    uint64_t covered = 0;\n    uint64_t FULL = (M == 64 ? ~0ULL : ((1ULL << M) - 1));\n    vector<int> sel;\n    sel.reserve(M);\n\n    while (covered != FULL) {\n        // Find top-K by ratio\n        array<int, 3> topIdx = {-1, -1, -1};\n        array<double, 3> topRatio = {1e100, 1e100, 1e100};\n        array<int, 3> topCost = {INT_MAX, INT_MAX, INT_MAX};\n        array<int, 3> topRank = {INT_MAX, INT_MAX, INT_MAX};\n\n        for (int a = 0; a < A; ++a) {\n            uint64_t gmask = acts[a].mask & ~covered;\n            if (!gmask) continue;\n            double gain = 0.0;\n            uint64_t mm = gmask;\n            while (mm) { int b = ctz64(mm); gain += w[b]; mm &= mm - 1; }\n            if (gain <= 0.0) continue;\n            double ratio = costEff[a] / gain;\n            // Insert into top-3 if better\n            for (int k = 0; k < min(pickK, 3); ++k) {\n                if (ratio < topRatio[k] ||\n                    (ratio == topRatio[k] && (acts[a].cost < topCost[k] ||\n                                              (acts[a].cost == topCost[k] && rank[a] < topRank[k])))) {\n                    // shift down\n                    for (int t = min(pickK, 3)-1; t > k; --t) { topIdx[t] = topIdx[t-1]; topRatio[t] = topRatio[t-1]; topCost[t] = topCost[t-1]; topRank[t] = topRank[t-1]; }\n                    topIdx[k] = a; topRatio[k] = ratio; topCost[k] = acts[a].cost; topRank[k] = rank[a];\n                    break;\n                }\n            }\n        }\n        int chosen = -1;\n        if (topIdx[0] == -1) break; // shouldn't happen if coverable\n        double r = urand(rng);\n        if (pickK >= 3 && r < pickP3 && topIdx[2] != -1) chosen = topIdx[2];\n        else if (r < pickP2 && topIdx[1] != -1) chosen = topIdx[1];\n        else chosen = topIdx[0];\n\n        sel.push_back(chosen);\n        covered |= acts[chosen].mask;\n    }\n\n    sel = prune_selection(sel, acts, M);\n    return sel;\n}\n\nvector<int> compute_counts(const vector<int>& sel, const vector<Action>& acts, int M) {\n    vector<int> cnt(M, 0);\n    for (int idx : sel) {\n        uint64_t m = acts[idx].mask;\n        while (m) { int b = ctz64(m); cnt[b]++; m &= m - 1; }\n    }\n    return cnt;\n}\n\n// Greedy repair for a given uncovered mask remU\npair<vector<int>, int> greedy_repair(uint64_t remU, const vector<Action>& acts, const vector<char>& banned, const vector<double>& w) {\n    vector<int> add;\n    int addCost = 0;\n    while (remU) {\n        int best = -1;\n        double best_ratio = 1e100;\n        int best_cost = INT_MAX;\n        for (int a = 0; a < (int)acts.size(); ++a) {\n            if (banned[a]) continue;\n            uint64_t gm = acts[a].mask & remU;\n            if (!gm) continue;\n            double gain = 0.0;\n            uint64_t mm = gm;\n            while (mm) { int b = ctz64(mm); gain += w[b]; mm &= mm - 1; }\n            double ratio = acts[a].cost / gain;\n            if (ratio < best_ratio || (ratio == best_ratio && acts[a].cost < best_cost)) {\n                best = a; best_ratio = ratio; best_cost = acts[a].cost;\n            }\n        }\n        if (best == -1) return {{}, INT_MAX};\n        add.push_back(best);\n        addCost += acts[best].cost;\n        remU &= ~acts[best].mask;\n    }\n    return {add, addCost};\n}\n\n// Local improvement: 1->k and some 2->k replacements with small time budget\nvoid local_improvement(vector<int>& sel, const vector<Action>& acts, int M, std::mt19937& rng, double time_limit_ms=12.0) {\n    auto t0 = chrono::high_resolution_clock::now();\n    int A = acts.size();\n    if (sel.empty()) return;\n    vector<int> cnt = compute_counts(sel, acts, M);\n    int bestCost = selection_cost(sel, acts);\n\n    vector<double> w(M, 1.0);\n\n    auto time_ok = [&](){\n        auto t1 = chrono::high_resolution_clock::now();\n        double ms = chrono::duration<double, std::milli>(t1 - t0).count();\n        return ms < time_limit_ms;\n    };\n\n    bool improved_global = true;\n    while (improved_global && time_ok()) {\n        improved_global = false;\n        vector<int> order = sel;\n        shuffle(order.begin(), order.end(), rng);\n        for (int sIdx : order) {\n            if (!time_ok()) break;\n            uint64_t m = acts[sIdx].mask;\n            uint64_t uniqueMask = 0;\n            uint64_t mm = m;\n            while (mm) { int b = ctz64(mm); if (cnt[b] == 1) uniqueMask |= (1ULL << b); mm &= mm - 1; }\n            if (!uniqueMask) continue;\n            vector<char> banned(A, 0);\n            banned[sIdx] = 1;\n            for (int id : sel) banned[id] = 1;\n            auto [addList, addCost] = greedy_repair(uniqueMask, acts, banned, w);\n            if (addCost >= acts[sIdx].cost) continue;\n            vector<int> newSel;\n            newSel.reserve(sel.size() - 1 + addList.size());\n            for (int id : sel) if (id != sIdx) newSel.push_back(id);\n            for (int id : addList) newSel.push_back(id);\n            newSel = prune_selection(newSel, acts, M);\n            int newCost = selection_cost(newSel, acts);\n            if (newCost < bestCost) {\n                sel.swap(newSel);\n                bestCost = newCost;\n                cnt = compute_counts(sel, acts, M);\n                improved_global = true;\n                break;\n            }\n        }\n    }\n\n    if (!time_ok()) return;\n    int tries = 40;\n    while (tries-- > 0 && time_ok()) {\n        if ((int)sel.size() < 2) break;\n        int a = rng() % sel.size();\n        int b = rng() % sel.size();\n        if (a == b) continue;\n        int s1 = sel[a], s2 = sel[b];\n        uint64_t uniq1 = 0, uniq2 = 0;\n        uint64_t mm1 = acts[s1].mask;\n        while (mm1) { int bi = ctz64(mm1); if (cnt[bi] == 1) uniq1 |= (1ULL << bi); mm1 &= mm1 - 1; }\n        uint64_t mm2 = acts[s2].mask;\n        while (mm2) { int bi = ctz64(mm2); if (cnt[bi] == 1) uniq2 |= (1ULL << bi); mm2 &= mm2 - 1; }\n        uint64_t remU = uniq1 | uniq2;\n        if (!remU) continue;\n        vector<char> banned(A, 0);\n        banned[s1] = banned[s2] = 1;\n        for (int id : sel) banned[id] = 1;\n        auto [addList, addCost] = greedy_repair(remU, acts, banned, w);\n        int removedCost = acts[s1].cost + acts[s2].cost;\n        if (addCost >= removedCost) continue;\n        vector<int> newSel;\n        newSel.reserve(sel.size() - 2 + addList.size());\n        for (int id : sel) if (id != s1 && id != s2) newSel.push_back(id);\n        for (int id : addList) newSel.push_back(id);\n        newSel = prune_selection(newSel, acts, M);\n        int newCost = selection_cost(newSel, acts);\n        if (newCost < bestCost) {\n            sel.swap(newSel);\n            bestCost = newCost;\n            cnt = compute_counts(sel, acts, M);\n        }\n    }\n}\n\n// Build baseline actions: per Oni minimal safe cycle\nvector<Action> build_baseline_actions(const vector<string>& grid,\n                                      const vector<pair<int,int>>& oni_pos) {\n    int N = grid.size();\n    vector<Action> acts;\n    acts.reserve(oni_pos.size());\n\n    vector<vector<int>> fuku_row_pref(N, vector<int>(N+1, 0));\n    vector<vector<int>> fuku_col_pref(N, vector<int>(N+1, 0));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            fuku_row_pref[i][j+1] = fuku_row_pref[i][j] + (grid[i][j] == 'o');\n            fuku_col_pref[j][i+1] = fuku_col_pref[j][i] + (grid[i][j] == 'o');\n        }\n    }\n    auto no_fuku_row = [&](int r, int l, int rgt) -> bool {\n        if (l > rgt) return true;\n        return (fuku_row_pref[r][rgt+1] - fuku_row_pref[r][l]) == 0;\n    };\n    auto no_fuku_col = [&](int c, int top, int bot) -> bool {\n        if (top > bot) return true;\n        return (fuku_col_pref[c][bot+1] - fuku_col_pref[c][top]) == 0;\n    };\n\n    for (auto [i, j] : oni_pos) {\n        vector<pair<int,pair<char,int>>> cand; // cost, (dir, k)\n        if (no_fuku_col(j, 0, i-1)) { int k = i + 1; cand.push_back({2*k, {'U', k}}); }\n        if (no_fuku_col(j, i+1, N-1)) { int k = N - i; cand.push_back({2*k, {'D', k}}); }\n        if (no_fuku_row(i, 0, j-1)) { int k = j + 1; cand.push_back({2*k, {'L', k}}); }\n        if (no_fuku_row(i, j+1, N-1)) { int k = N - j; cand.push_back({2*k, {'R', k}}); }\n        if (cand.empty()) continue;\n        auto best = min_element(cand.begin(), cand.end(),\n                                [](auto& a, auto& b){ return a.first < b.first; });\n        Action a; a.d = best->second.first; a.p = (a.d == 'L' || a.d == 'R') ? i : j; a.k = best->second.second; a.cost = best->first; a.mask = 0;\n        acts.push_back(a);\n    }\n    return acts;\n}\n\nvector<pair<char,int>> actions_to_ops(const vector<int>& sel, const vector<Action>& acts) {\n    vector<pair<char,int>> ops;\n    long long total = 0;\n    for (int idx : sel) total += acts[idx].cost;\n    ops.reserve((size_t)total);\n    for (int idx : sel) {\n        const auto& a = acts[idx];\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(a.d, a.p);\n        char od = opposite(a.d);\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(od, a.p);\n    }\n    return ops;\n}\nvector<pair<char,int>> actions_to_ops_direct(const vector<Action>& acts) {\n    vector<pair<char,int>> ops;\n    long long total = 0;\n    for (auto& a : acts) total += a.cost;\n    ops.reserve((size_t)total);\n    for (auto& a : acts) {\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(a.d, a.p);\n        char od = opposite(a.d);\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(od, a.p);\n    }\n    return ops;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n\n    vector<pair<int,int>> oni_pos;\n    vector<vector<int>> oni_id(N, vector<int>(N, -1));\n    for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j)\n        if (grid[i][j] == 'x') {\n            int id = oni_pos.size();\n            oni_pos.emplace_back(i, j);\n            oni_id[i][j] = id;\n        }\n    int M = (int)oni_pos.size();\n    uint64_t FULL = (M == 64 ? ~0ULL : ((1ULL << M) - 1));\n\n    // Build reduced candidates\n    vector<Action> acts = build_candidates_tight(grid, oni_pos, oni_id);\n    int A = acts.size();\n\n    // Availability per Oni\n    vector<int> avail(M, 0);\n    for (auto &a : acts) {\n        uint64_t m = a.mask;\n        while (m) { int b = ctz64(m); avail[b]++; m &= m - 1; }\n    }\n\n    // Weight variants\n    vector<vector<double>> weightVariants;\n    {\n        vector<double> w0(M, 1.0), w1(M, 1.0), w2(M, 1.0), w3(M, 1.0);\n        for (int i = 0; i < M; ++i) {\n            int av = max(1, avail[i]);\n            w1[i] = 1.0 / sqrt((double)av);\n            w2[i] = 1.0 / (double)av;\n            w3[i] = (av <= 2 ? 3.0 : (av == 3 ? 2.0 : 1.0)); // scarcity boost\n        }\n        weightVariants.push_back(w0);\n        weightVariants.push_back(w1);\n        weightVariants.push_back(w2);\n        weightVariants.push_back(w3);\n    }\n\n    std::mt19937 rng(712367 + (uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Multiple weighted greedy restarts with noise and stochasticity\n    vector<int> bestSel;\n    int bestCost = INT_MAX;\n    int restarts = 64;\n    for (int t = 0; t < restarts; ++t) {\n        const auto& w = weightVariants[t % weightVariants.size()];\n        vector<int> sel = greedy_select_weighted_noisy(acts, M, w, rng, 0.15, 3, 0.15, 0.05);\n\n        // Ensure coverage (repair if needed)\n        uint64_t covered = 0;\n        for (int id : sel) covered |= acts[id].mask;\n        if (covered != FULL) {\n            vector<char> banned(acts.size(), 0);\n            vector<double> wu(M, 1.0);\n            auto [addList, addCost] = greedy_repair(FULL & ~covered, acts, banned, wu);\n            for (int id : addList) sel.push_back(id);\n            sel = prune_selection(sel, acts, M);\n        }\n\n        int cst = selection_cost(sel, acts);\n        if (cst < bestCost) { bestSel = move(sel); bestCost = cst; }\n    }\n\n    // Local improvement with small budget\n    local_improvement(bestSel, acts, M, rng, 12.0);\n\n    // Produce greedy ops and validate strictly\n    auto opsGreedy = actions_to_ops(bestSel, acts);\n    auto checkGreedy = simulate(grid, opsGreedy);\n    bool greedyValid = (checkGreedy.first == 0 && checkGreedy.second == 0);\n\n    // Baseline fallback (guaranteed safe)\n    vector<Action> baseActs = build_baseline_actions(grid, oni_pos);\n    auto opsBase = actions_to_ops_direct(baseActs);\n    auto checkBase = simulate(grid, opsBase);\n    bool baseValid = (checkBase.first == 0 && checkBase.second == 0);\n\n    vector<pair<char,int>> ops;\n    if (greedyValid && baseValid) {\n        ops = (opsGreedy.size() <= opsBase.size()) ? move(opsGreedy) : move(opsBase);\n    } else if (greedyValid) {\n        ops = move(opsGreedy);\n    } else if (baseValid) {\n        ops = move(opsBase);\n    } else {\n        // Unexpected; fallback to baseline anyway.\n        ops = move(opsBase);\n    }\n\n    if ((int)ops.size() > 4*N*N) {\n        if (baseValid && (int)opsBase.size() <= 4*N*N) {\n            ops = move(opsBase);\n        } else if (greedyValid && (int)opsGreedy.size() <= 4*N*N) {\n            ops = move(opsGreedy);\n        } else {\n            ops.resize(4*N*N);\n        }\n    }\n\n    for (auto &op : ops) cout << op.first << ' ' << op.second << '\\n';\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double ms() const {\n        return chrono::duration<double, std::milli>(\n            chrono::high_resolution_clock::now() - st\n        ).count();\n    }\n};\n\nstruct Candidate {\n    vector<int> a, b;\n    long long E_full = (1LL<<62);\n    long long E_part = (1LL<<62);\n};\n\nstatic long long simulate_error_full(const vector<int>& a, const vector<int>& b,\n                                     int L, const vector<int>& T) {\n    int N = (int)a.size();\n    vector<int> t(N, 0);\n    int cur = 0;\n    for (int step = 0; step < L; ++step) {\n        t[cur] += 1;\n        if (t[cur] & 1) cur = a[cur];\n        else cur = b[cur];\n    }\n    long long E = 0;\n    for (int i = 0; i < N; ++i) {\n        E += llabs((long long)t[i] - (long long)T[i]);\n    }\n    return E;\n}\n\nstatic long long simulate_error_partial(const vector<int>& a, const vector<int>& b,\n                                        int Lpart, const vector<int>& Tpart) {\n    int N = (int)a.size();\n    vector<int> t(N, 0);\n    int cur = 0;\n    for (int step = 0; step < Lpart; ++step) {\n        t[cur] += 1;\n        if (t[cur] & 1) cur = a[cur];\n        else cur = b[cur];\n    }\n    long long E = 0;\n    for (int i = 0; i < N; ++i) {\n        E += llabs((long long)t[i] - (long long)Tpart[i]);\n    }\n    return E;\n}\n\n// Build a-edge from an order\nstatic void build_a_from_order(const vector<int>& order, vector<int>& a) {\n    int N = (int)order.size();\n    a.assign(N, 0);\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    }\n}\n\n// Compute residual target D[j] = 2*T[j] - T[prev(j)] for given order (no clamping)\nstatic void residuals_from_order(const vector<int>& order, const vector<int>& T, vector<long long>& D) {\n    int N = (int)order.size();\n    D.assign(N, 0);\n    for (int k = 0; k < N; ++k) {\n        int j = order[k];\n        int prev = order[(k-1+N)%N];\n        D[j] = 2LL * (long long)T[j] - (long long)T[prev];\n    }\n}\n\n// Snake order A: evens ascending then odds descending\nstatic vector<int> build_snake_order_A(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng); // random tie-breaking\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    vector<int> evenIdx, oddIdx;\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) evenIdx.push_back(ord[i]);\n        else oddIdx.push_back(ord[i]);\n    }\n    vector<int> order;\n    order.reserve(N);\n    for (int x : evenIdx) order.push_back(x);\n    for (int k = (int)oddIdx.size()-1; k >= 0; --k) order.push_back(oddIdx[k]);\n    return order;\n}\n\n// Snake order B: odds ascending then evens descending\nstatic vector<int> build_snake_order_B(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    vector<int> evenIdx, oddIdx;\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) evenIdx.push_back(ord[i]);\n        else oddIdx.push_back(ord[i]);\n    }\n    vector<int> order;\n    order.reserve(N);\n    for (int x : oddIdx) order.push_back(x);\n    for (int k = (int)evenIdx.size()-1; k >= 0; --k) order.push_back(evenIdx[k]);\n    return order;\n}\n\n// Pure ascending order cycle\nstatic vector<int> build_ascending_order(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    return ord;\n}\n\n// Alternating extremes: low, high, low2, high2, ...\nstatic vector<int> build_alternating_extremes(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    vector<int> order;\n    order.reserve(N);\n    int l = 0, r = N - 1;\n    bool takeLow = true;\n    while (l <= r) {\n        if (takeLow) order.push_back(ord[l++]);\n        else order.push_back(ord[r--]);\n        takeLow = !takeLow;\n    }\n    return order;\n}\n\n// Greedy ring insertion to minimize sum of c(prev, curr) where c = max(0, Tprev - 2*Tcurr)\nstatic long long edge_cost(int prev, int curr, const vector<int>& T) {\n    long long v = (long long)T[prev] - 2LL * (long long)T[curr];\n    return v > 0 ? v : 0;\n}\nstatic vector<int> build_insertion_order(const vector<int>& T, mt19937_64& rng, int seedMode = 0) {\n    int N = (int)T.size();\n    vector<int> nodes(N);\n    iota(nodes.begin(), nodes.end(), 0);\n    // pick initial two nodes\n    int u = 0, v = 1;\n    if (seedMode == 0) {\n        // choose u median by T\n        vector<int> idx = nodes;\n        stable_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        u = idx[N/2];\n    } else if (seedMode == 1) {\n        // choose u from upper quartile\n        vector<int> idx = nodes;\n        stable_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        u = idx[(3*N)/4];\n    } else {\n        // random u\n        u = (int)(rng() % N);\n    }\n    // choose v minimizing edge_cost(u,v)+edge_cost(v,u)\n    long long best = (1LL<<62);\n    for (int cand : nodes) if (cand != u) {\n        long long sc = edge_cost(u, cand, T) + edge_cost(cand, u, T);\n        if (sc < best) { best = sc; v = cand; }\n    }\n    vector<int> cycle;\n    cycle.push_back(u);\n    cycle.push_back(v);\n    vector<char> used(N, 0);\n    used[u] = used[v] = 1;\n    while ((int)cycle.size() < N) {\n        int x = -1;\n        long long bestDelta = (1LL<<62);\n        // try every unused node and every insertion arc\n        for (int cand : nodes) {\n            if (used[cand]) continue;\n            int m = (int)cycle.size();\n            for (int i = 0; i < m; ++i) {\n                int p = cycle[i];\n                int q = cycle[(i+1)%m];\n                long long delta = edge_cost(p, cand, T) + edge_cost(cand, q, T) - edge_cost(p, q, T);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    x = cand;\n                }\n            }\n        }\n        // insert x at best position\n        int bestPos = -1;\n        {\n            int m = (int)cycle.size();\n            for (int i = 0; i < m; ++i) {\n                int p = cycle[i];\n                int q = cycle[(i+1)%m];\n                long long delta = edge_cost(p, x, T) + edge_cost(x, q, T) - edge_cost(p, q, T);\n                if (delta == bestDelta) { bestPos = (i+1)%m; break; }\n            }\n        }\n        if (bestPos == -1) bestPos = (int)cycle.size(); // fallback\n        cycle.insert(cycle.begin() + bestPos, x);\n        used[x] = 1;\n    }\n    return cycle;\n}\n\n// Greedy assignment of b with residual r initialized to D\nstatic void greedy_assign_b(const vector<int>& T, vector<long long>& r,\n                            mt19937_64 &rng, vector<int>& b) {\n    int N = (int)T.size();\n    b.assign(N, 0);\n    vector<int> items(N);\n    iota(items.begin(), items.end(), 0);\n    shuffle(items.begin(), items.end(), rng);\n    stable_sort(items.begin(), items.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] > T[j];\n        return i < j;\n    });\n\n    for (int idx = 0; idx < N; ++idx) {\n        int i = items[idx];\n        long long w = T[i];\n        long long bestDelta = (1LL<<62);\n        vector<int> cands;\n        for (int j = 0; j < N; ++j) {\n            long long rj = r[j];\n            long long delta = llabs(rj - w) - llabs(rj);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                cands.clear();\n                cands.push_back(j);\n            } else if (delta == bestDelta) {\n                cands.push_back(j);\n            }\n        }\n        int j = cands[rng() % cands.size()];\n        b[i] = j;\n        r[j] -= w;\n    }\n}\n\n// Local improvement: move single items from oversupplied bins (r<0) to deficit bins (r>0)\nstatic void local_improve_moves(const vector<int>& T, vector<long long>& r,\n                                vector<int>& b, mt19937_64 &rng, int passes = 2) {\n    int N = (int)T.size();\n    vector<vector<int>> itemsOfBin(N);\n    itemsOfBin.assign(N, {});\n    for (int i = 0; i < N; ++i) itemsOfBin[b[i]].push_back(i);\n\n    for (int pass = 0; pass < passes; ++pass) {\n        vector<int> deficits, overs;\n        for (int j = 0; j < N; ++j) {\n            if (r[j] > 0) deficits.push_back(j);\n            else if (r[j] < 0) overs.push_back(j);\n        }\n        if (deficits.empty() || overs.empty()) break;\n        // fill larger deficits first\n        stable_sort(deficits.begin(), deficits.end(), [&](int x, int y){ return r[x] > r[y]; });\n        for (int k : deficits) {\n            long long rk = r[k];\n            long long bestGain = 0; // negative delta means improvement\n            int bestFromBin = -1;\n            int bestItem = -1;\n            for (int j : overs) {\n                if (itemsOfBin[j].empty()) continue;\n                long long rj = r[j];\n                for (int ii : itemsOfBin[j]) {\n                    long long w = T[ii];\n                    long long delta = llabs(rj + w) + llabs(rk - w) - (llabs(rj) + llabs(rk));\n                    if (delta < bestGain) {\n                        bestGain = delta;\n                        bestFromBin = j;\n                        bestItem = ii;\n                    }\n                }\n            }\n            if (bestItem != -1) {\n                int j = bestFromBin;\n                int ii = bestItem;\n                long long w = T[ii];\n                // apply move: remove from j, add to k\n                r[j] += w;\n                r[k] -= w;\n                // update bins\n                auto &vj = itemsOfBin[j];\n                for (int idx = 0; idx < (int)vj.size(); ++idx) {\n                    if (vj[idx] == ii) {\n                        vj[idx] = vj.back();\n                        vj.pop_back();\n                        break;\n                    }\n                }\n                itemsOfBin[k].push_back(ii);\n                b[ii] = k;\n            }\n        }\n    }\n}\n\n// Pair-swap local improvement on b\nstatic void local_swap_improve(const vector<int>& T, vector<long long>& r,\n                               vector<int>& b, mt19937_64 &rng, int tries = 220) {\n    int N = (int)T.size();\n    for (int t = 0; t < tries; ++t) {\n        int i1 = rng() % N;\n        int i2 = rng() % N;\n        if (i1 == i2) continue;\n        int j1 = b[i1];\n        int j2 = b[i2];\n        if (j1 == j2) continue;\n        long long w1 = T[i1], w2 = T[i2];\n        long long old = llabs(r[j1]) + llabs(r[j2]);\n        long long r1p = r[j1] + w1 - w2;\n        long long r2p = r[j2] + w2 - w1;\n        long long nw = llabs(r1p) + llabs(r2p);\n        if (nw < old) {\n            r[j1] = r1p;\n            r[j2] = r2p;\n            b[i1] = j2;\n            b[i2] = j1;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, L;\n    if (!(cin >> N >> L)) return 0;\n    vector<int> T(N);\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    Timer timer;\n    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    const double TIME_LIMIT_MS = 1950.0;\n\n    // Prepare partial target Tpart with rounding so that sum Tpart = Lpart\n    const int Lpart = min(L, 120000);\n    vector<int> Tpart(N, 0);\n    {\n        long long sumBase = 0;\n        struct Rem { long long r; int i; };\n        vector<Rem> rems;\n        rems.reserve(N);\n        for (int i = 0; i < N; ++i) {\n            long long num = 1LL * T[i] * Lpart;\n            int base = (int)(num / L);\n            long long rem = num - 1LL * base * L;\n            Tpart[i] = base;\n            sumBase += base;\n            rems.push_back({rem, i});\n        }\n        int need = Lpart - (int)sumBase;\n        stable_sort(rems.begin(), rems.end(), [&](const Rem& a, const Rem& b){\n            if (a.r != b.r) return a.r > b.r;\n            return a.i < b.i;\n        });\n        for (int k = 0; k < need; ++k) Tpart[rems[k].i] += 1;\n    }\n\n    // Build a variety of a-edge orders (and their reverses)\n    vector<vector<int>> orders;\n    orders.reserve(16);\n    auto add_with_reverse = [&](const vector<int>& ord) {\n        orders.push_back(ord);\n        vector<int> rev = ord;\n        reverse(rev.begin(), rev.end());\n        orders.push_back(rev);\n    };\n    add_with_reverse(build_snake_order_A(T, rng));\n    add_with_reverse(build_snake_order_B(T, rng));\n    add_with_reverse(build_ascending_order(T, rng));\n    add_with_reverse(build_alternating_extremes(T, rng));\n    add_with_reverse(build_insertion_order(T, rng, 0));\n    add_with_reverse(build_insertion_order(T, rng, 1));\n    add_with_reverse(build_insertion_order(T, rng, 2));\n\n    // Precompute a-edges and D for each order\n    struct AInfo { vector<int> a; vector<long long> D; };\n    vector<AInfo> ainfos;\n    ainfos.resize(orders.size());\n    for (size_t oi = 0; oi < orders.size(); ++oi) {\n        build_a_from_order(orders[oi], ainfos[oi].a);\n        residuals_from_order(orders[oi], T, ainfos[oi].D);\n    }\n\n    // Search parameters\n    const int TOP_PART = 10;            // keep top candidates by partial error\n    const double FINAL_SIM_BUDGET_MS = 300.0; // reserve time for full sims\n\n    vector<Candidate> topCandidates;\n\n    auto try_candidate = [&](const AInfo& ai) {\n        vector<long long> r = ai.D;\n        vector<int> b(N, 0);\n        greedy_assign_b(T, r, rng, b);\n        local_improve_moves(T, r, b, rng, 2);\n        local_swap_improve(T, r, b, rng, 240);\n\n        Candidate c;\n        c.a = ai.a;\n        c.b = b;\n        c.E_part = simulate_error_partial(c.a, c.b, Lpart, Tpart);\n\n        // maintain top list by partial error\n        if ((int)topCandidates.size() < TOP_PART) {\n            topCandidates.push_back(c);\n            sort(topCandidates.begin(), topCandidates.end(),\n                 [](const Candidate& x, const Candidate& y){ return x.E_part < y.E_part; });\n        } else if (c.E_part < topCandidates.back().E_part) {\n            topCandidates.back() = c;\n            sort(topCandidates.begin(), topCandidates.end(),\n                 [](const Candidate& x, const Candidate& y){ return x.E_part < y.E_part; });\n        }\n    };\n\n    // Main loop: try many b-assignments over the different a cycles\n    size_t oi = 0;\n    while (timer.ms() < TIME_LIMIT_MS - FINAL_SIM_BUDGET_MS) {\n        try_candidate(ainfos[oi]);\n        oi++;\n        if (oi >= ainfos.size()) oi = 0;\n    }\n\n    // Fallback if no candidates generated\n    if (topCandidates.empty()) {\n        vector<int> a(N), b(N);\n        iota(a.begin(), a.end(), 0);\n        for (int i = 0; i < N; ++i) b[i] = (i+1) % N;\n        for (int i = 0; i < N; ++i) cout << a[i] << \" \" << b[i] << \"\\n\";\n        return 0;\n    }\n\n    // Full simulation for top few\n    // Simulate as many as time allows, up to 8\n    int simulate_k = min(8, (int)topCandidates.size());\n    for (int i = 0; i < simulate_k; ++i) {\n        if (timer.ms() > TIME_LIMIT_MS) break;\n        topCandidates[i].E_full = simulate_error_full(topCandidates[i].a, topCandidates[i].b, L, T);\n    }\n    // Select best by full error if available, else by partial\n    Candidate best = topCandidates[0];\n    for (int i = 0; i < simulate_k; ++i) {\n        if (topCandidates[i].E_full < best.E_full) best = topCandidates[i];\n    }\n    if (best.E_full >= (1LL<<61)) {\n        best = *min_element(topCandidates.begin(), topCandidates.end(),\n                            [](const Candidate& x, const Candidate& y){\n                                return x.E_part < y.E_part;\n                            });\n    }\n\n    // Output best\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\n// DSU\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x ? x : p[x]=find(p[x]); }\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; sz[a]+=sz[b];\n        return true;\n    }\n};\n\n// Morton (Z-order) 15-bit interleave (coords <= 10000)\nstatic inline uint64_t morton_code(uint32_t x, uint32_t y) {\n    uint64_t code = 0;\n    for (int i = 0; i < 15; ++i) {\n        code |= (uint64_t)((x >> i) & 1u) << (2*i);\n        code |= (uint64_t)((y >> i) & 1u) << (2*i + 1);\n    }\n    return code;\n}\n\n// Hilbert order (bits=15)\nstatic inline uint64_t hilbert_index(uint32_t x, uint32_t y) {\n    const uint32_t n = 1u << 15;\n    uint64_t d = 0;\n    uint32_t rx, ry, s;\n    for (s = n >> 1; s > 0; s >>= 1) {\n        rx = (x & s) ? 1u : 0u;\n        ry = (y & s) ? 1u : 0u;\n        d += (uint64_t)s * (uint64_t)s * ((3u * rx) ^ ry);\n        if (ry == 0) {\n            if (rx == 1) {\n                x = (n - 1) - x;\n                y = (n - 1) - y;\n            }\n            uint32_t t = x; x = y; y = t;\n        }\n    }\n    return d;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, Q, L, W;\n    if (!(cin >> N >> M >> Q >> L >> W)) return 0;\n    vector<int> G(M);\n    for(int i=0;i<M;i++) cin >> G[i];\n    vector<int> lx(N), rx(N), ly(N), ry(N);\n    for(int i=0;i<N;i++){\n        cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n    }\n\n    // Centers and widths\n    vector<int> xc(N), yc(N), wx(N), wy(N);\n    for (int i = 0; i < N; ++i) {\n        xc[i] = (lx[i] + rx[i]) / 2;\n        yc[i] = (ly[i] + ry[i]) / 2;\n        wx[i] = rx[i] - lx[i];\n        wy[i] = ry[i] - ly[i];\n    }\n\n    // Variances and uncertainty\n    vector<double> varx(N), vary(N), diag(N);\n    for (int i = 0; i < N; ++i) {\n        varx[i] = (double)wx[i] * (double)wx[i] / 12.0;\n        vary[i] = (double)wy[i] * (double)wy[i] / 12.0;\n        diag[i] = hypot((double)wx[i], (double)wy[i]);\n    }\n\n    auto ed2 = [&](int u, int v)->double{\n        double dx = (double)xc[u] - (double)xc[v];\n        double dy = (double)yc[u] - (double)yc[v];\n        return dx*dx + dy*dy + varx[u] + varx[v] + vary[u] + vary[v];\n    };\n\n    // Build candidate orders: Morton, Hilbert, and Greedy NN (ed2)\n    vector<vector<int>> orders;\n\n    // Morton\n    {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        vector<uint64_t> code(N);\n        for (int i = 0; i < N; ++i) code[i] = morton_code((uint32_t)xc[i], (uint32_t)yc[i]);\n        sort(ord.begin(), ord.end(), [&](int a, int b){ return code[a] < code[b]; });\n        orders.push_back(move(ord));\n    }\n    // Hilbert\n    {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        vector<uint64_t> code(N);\n        for (int i = 0; i < N; ++i) code[i] = hilbert_index((uint32_t)xc[i], (uint32_t)yc[i]);\n        sort(ord.begin(), ord.end(), [&](int a, int b){ return code[a] < code[b]; });\n        orders.push_back(move(ord));\n    }\n    // Greedy Nearest-Neighbor (open path)\n    {\n        vector<int> ord;\n        ord.reserve(N);\n        vector<char> used(N, 0);\n        // start from smallest Hilbert code node\n        int start = 0;\n        {\n            uint64_t best = (uint64_t)-1;\n            for (int i = 0; i < N; ++i) {\n                uint64_t h = hilbert_index((uint32_t)xc[i], (uint32_t)yc[i]);\n                if (h < best) { best = h; start = i; }\n            }\n        }\n        int cur = start;\n        used[cur] = 1;\n        ord.push_back(cur);\n        for (int step = 1; step < N; ++step) {\n            int bestj = -1;\n            double bd = 1e300;\n            for (int j = 0; j < N; ++j) if (!used[j]) {\n                double d2 = ed2(cur, j);\n                if (d2 < bd) { bd = d2; bestj = j; }\n            }\n            if (bestj == -1) break;\n            used[bestj] = 1;\n            ord.push_back(bestj);\n            cur = bestj;\n        }\n        if ((int)ord.size() == N) orders.push_back(move(ord));\n    }\n\n    auto path_cost = [&](const vector<int>& ord)->double{\n        double s = 0.0;\n        for (int i = 0; i+1 < (int)ord.size(); ++i) s += ed2(ord[i], ord[i+1]);\n        return s;\n    };\n\n    // Pick best by neighbor sum\n    int bestOrdIdx = 0;\n    double bestPath = 1e300;\n    for (int i = 0; i < (int)orders.size(); ++i) {\n        double sc = path_cost(orders[i]);\n        if (sc < bestPath) {\n            bestPath = sc;\n            bestOrdIdx = i;\n        }\n    }\n    vector<int> ord = orders[bestOrdIdx];\n\n    // Windowed 2-opt on open path (few passes)\n    auto two_opt_improve = [&](vector<int>& path){\n        const int Nn = (int)path.size();\n        if (Nn < 4) return;\n        const int WINDOW = 60; // local window\n        const int PASSES = 2;\n        for (int pass = 0; pass < PASSES; ++pass) {\n            bool improved = false;\n            for (int i = 1; i <= Nn - 3; ++i) {\n                int jmax = min(Nn - 2, i + WINDOW);\n                for (int j = i + 1; j <= jmax; ++j) {\n                    int a = path[i-1];\n                    int b = path[i];\n                    int c = path[j];\n                    int d = path[j+1];\n                    double before = ed2(a,b) + ed2(c,d);\n                    double after  = ed2(a,c) + ed2(b,d);\n                    if (after + 1e-9 < before) {\n                        reverse(path.begin() + i, path.begin() + j + 1);\n                        improved = true;\n                        break;\n                    }\n                }\n                if (improved) continue;\n            }\n            if (!improved) break;\n        }\n    };\n    two_opt_improve(ord);\n\n    // Build group boundaries (fixed sizes)\n    vector<int> start(M+1, 0);\n    for (int k = 0; k < M; ++k) start[k+1] = start[k] + G[k];\n\n    // One-pass boundary smoothing: swap one element across boundary if improves expected MST cost\n    auto mst_cost_ed2 = [&](const vector<int>& nodes)->double{\n        int n = (int)nodes.size();\n        if (n <= 1) return 0.0;\n        vector<char> used(n, 0);\n        vector<double> best(n, 1e300);\n        best[0] = 0.0;\n        double cost = 0.0;\n        for (int it = 0; it < n; ++it) {\n            int v = -1;\n            double bv = 1e300;\n            for (int i = 0; i < n; ++i) if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n            if (v == -1) break;\n            used[v] = 1;\n            cost += (v==0 ? 0.0 : bv);\n            for (int u = 0; u < n; ++u) if (!used[u]) {\n                double w = ed2(nodes[v], nodes[u]);\n                if (w < best[u]) best[u] = w;\n            }\n        }\n        return cost;\n    };\n\n    auto group_nodes_by_ord = [&](int l, int r)->vector<int>{\n        vector<int> v;\n        v.reserve(r-l);\n        for (int i = l; i < r; ++i) v.push_back(ord[i]);\n        return v;\n    };\n\n    for (int k = 0; k+1 < M; ++k) {\n        if (G[k] == 0 || G[k+1] == 0) continue;\n        int posL = start[k+1] - 1;\n        int posR = start[k+1];\n        int left_id = ord[posL];\n        int right_id = ord[posR];\n\n        vector<int> grpL = group_nodes_by_ord(start[k], start[k+1]);\n        vector<int> grpR = group_nodes_by_ord(start[k+1], start[k+2]);\n        double before = mst_cost_ed2(grpL) + mst_cost_ed2(grpR);\n\n        grpL.back() = right_id;\n        grpR[0] = left_id;\n        double after = mst_cost_ed2(grpL) + mst_cost_ed2(grpR);\n\n        if (after + 1e-9 < before) {\n            swap(ord[posL], ord[posR]);\n        }\n    }\n\n    // Build groups from ord\n    vector<vector<int>> groups(M);\n    {\n        int ptr = 0;\n        for (int k = 0; k < M; ++k) {\n            groups[k].reserve(G[k]);\n            for (int t = 0; t < G[k]; ++t) groups[k].push_back(ord[ptr++]);\n        }\n    }\n\n    // Group uncertainty\n    vector<double> g_unc(M, 0.0);\n    for (int k = 0; k < M; ++k) {\n        double s = 0.0;\n        for (int id : groups[k]) s += diag[id];\n        g_unc[k] = (G[k] > 0 ? s / (double)G[k] : 0.0);\n    }\n\n    // Approx MST edges per group (expected distances)\n    auto mst_edges_ed2 = [&](const vector<int>& nodes)->vector<pair<int,int>>{\n        int n = (int)nodes.size();\n        vector<char> used(n, 0);\n        vector<double> best(n, 1e300);\n        vector<int> parent(n, -1);\n        if (n > 0) best[0] = 0.0;\n        vector<pair<int,int>> edges;\n        edges.reserve(max(0, n-1));\n        for (int it = 0; it < n; ++it) {\n            int v = -1;\n            double bv = 1e300;\n            for (int i = 0; i < n; ++i) if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n            if (v == -1) break;\n            used[v] = 1;\n            if (parent[v] != -1) edges.emplace_back(nodes[parent[v]], nodes[v]);\n            for (int u = 0; u < n; ++u) if (!used[u]) {\n                double w = ed2(nodes[v], nodes[u]);\n                if (w < best[u]) { best[u] = w; parent[u] = v; }\n            }\n        }\n        return edges;\n    };\n    vector<vector<pair<int,int>>> approxEdges(M);\n    for (int k = 0; k < M; ++k) {\n        approxEdges[k] = mst_edges_ed2(groups[k]);\n    }\n\n    // Query function\n    auto do_query = [&](const vector<int>& subset)->vector<pair<int,int>>{\n        int l = (int)subset.size();\n        cout << \"? \" << l;\n        for (int i = 0; i < l; ++i) cout << \" \" << subset[i];\n        cout << \"\\n\" << flush;\n        vector<pair<int,int>> res;\n        res.reserve(max(0, l-1));\n        for (int i = 0; i < l-1; ++i) {\n            int a,b; cin >> a >> b;\n            res.emplace_back(a,b);\n        }\n        return res;\n    };\n\n    int queries_used = 0;\n    vector<vector<pair<int,int>>> oracle_edges(M);\n\n    // Stage A: small groups 3..L\n    vector<int> small_groups;\n    for (int k = 0; k < M; ++k) if (G[k] >= 3 && G[k] <= L) small_groups.push_back(k);\n    sort(small_groups.begin(), small_groups.end(), [&](int a, int b){\n        if (G[a] != G[b]) return G[a] > G[b];\n        if (g_unc[a] != g_unc[b]) return g_unc[a] > g_unc[b];\n        return a < b;\n    });\n    for (int k : small_groups) {\n        if (queries_used >= Q) break;\n        auto res = do_query(groups[k]);\n        ++queries_used;\n        oracle_edges[k].insert(oracle_edges[k].end(), res.begin(), res.end());\n    }\n\n    // Stage B: large groups -> disjoint connected chunks (BFS on approx MST) with benefit scoring\n    struct Chunk {\n        int k;\n        vector<int> sub;\n        double benefit; // sum of variances on MST edges inside the chunk\n        bool operator<(Chunk const& other) const { return benefit > other.benefit; } // for sort desc\n    };\n    vector<Chunk> chunks_all;\n    vector<Chunk> chunks2; // size-2\n    vector<int> id2pos(N, -1);\n\n    for (int k = 0; k < M; ++k) {\n        if (G[k] <= L) continue;\n        const auto &grp = groups[k];\n        int sz = (int)grp.size();\n\n        for (int i = 0; i < sz; ++i) id2pos[grp[i]] = i;\n        vector<vector<int>> adj(sz);\n        for (auto &e : approxEdges[k]) {\n            int u = id2pos[e.first];\n            int v = id2pos[e.second];\n            if (u >= 0 && v >= 0) {\n                adj[u].push_back(v);\n                adj[v].push_back(u);\n            }\n        }\n\n        vector<char> used(sz, 0);\n        int remaining = sz;\n\n        auto pick_seed = [&]()->int{\n            for (int i = 0; i < sz; ++i) if (!used[i] && (int)adj[i].size() <= 1) return i;\n            for (int i = 0; i < sz; ++i) if (!used[i]) return i;\n            return -1;\n        };\n\n        vector<vector<int>> subs_local;\n        while (remaining > 0) {\n            int seed = pick_seed();\n            if (seed == -1) break;\n            deque<int> dq;\n            dq.push_back(seed);\n            vector<char> enq(sz, 0);\n            enq[seed] = 1;\n\n            vector<int> subset_local;\n            while (!dq.empty() && (int)subset_local.size() < L) {\n                int v = dq.front(); dq.pop_front();\n                if (used[v]) continue;\n                used[v] = 1;\n                subset_local.push_back(v);\n                --remaining;\n                for (int to : adj[v]) if (!used[to] && !enq[to]) {\n                    dq.push_back(to); enq[to] = 1;\n                }\n            }\n            if (!subset_local.empty()) subs_local.push_back(move(subset_local));\n            else break;\n        }\n\n        // Convert to city IDs and compute benefit\n        for (auto &loc : subs_local) {\n            vector<int> sub; sub.reserve(loc.size());\n            for (int idx : loc) sub.push_back(grp[idx]);\n            // Compute benefit on approx MST edges inside sub\n            vector<char> in(sz, 0);\n            for (int id : sub) in[id2pos[id]] = 1;\n            double ben = 0.0;\n            for (auto &e : approxEdges[k]) {\n                int u = id2pos[e.first], v = id2pos[e.second];\n                if (in[u] && in[v]) {\n                    ben += varx[e.first] + varx[e.second] + vary[e.first] + vary[e.second];\n                }\n            }\n            if ((int)sub.size() >= 3) chunks_all.push_back({k, move(sub), ben});\n            else if ((int)sub.size() == 2) chunks2.push_back({k, move(sub), ben});\n        }\n\n        for (int i = 0; i < sz; ++i) id2pos[grp[i]] = -1;\n    }\n\n    sort(chunks_all.begin(), chunks_all.end()); // by benefit desc\n    sort(chunks2.begin(), chunks2.end());\n\n    for (auto &ch : chunks_all) {\n        if (queries_used >= Q) break;\n        auto res = do_query(ch.sub);\n        ++queries_used;\n        oracle_edges[ch.k].insert(oracle_edges[ch.k].end(), res.begin(), res.end());\n    }\n    for (auto &ch : chunks2) {\n        if (queries_used >= Q) break;\n        auto res = do_query(ch.sub);\n        ++queries_used;\n        oracle_edges[ch.k].insert(oracle_edges[ch.k].end(), res.begin(), res.end());\n    }\n\n    // If any budget remains, query size-2 groups by uncertainty\n    if (queries_used < Q) {\n        vector<int> size2groups;\n        for (int k = 0; k < M; ++k) if (G[k] == 2) size2groups.push_back(k);\n        sort(size2groups.begin(), size2groups.end(), [&](int a, int b){\n            if (g_unc[a] != g_unc[b]) return g_unc[a] > g_unc[b];\n            return a < b;\n        });\n        for (int k : size2groups) {\n            if (queries_used >= Q) break;\n            auto res = do_query(groups[k]);\n            ++queries_used;\n            oracle_edges[k].insert(oracle_edges[k].end(), res.begin(), res.end());\n        }\n    }\n\n    // Output final answer\n    cout << \"!\" << \"\\n\";\n\n    // Build final edges per group\n    vector<int> pos(N, -1);\n    for (int k = 0; k < M; ++k) {\n        const auto &grp = groups[k];\n        int sz = (int)grp.size();\n\n        // Print city IDs for this group\n        for (int i = 0; i < sz; ++i) {\n            if (i) cout << \" \";\n            cout << grp[i];\n        }\n        cout << \"\\n\";\n\n        if (sz <= 1) continue;\n\n        for (int i = 0; i < sz; ++i) pos[grp[i]] = i;\n\n        // Force oracle edges first\n        vector<pair<int,int>> final_edges;\n        final_edges.reserve(max(0, sz-1));\n        DSU dsu(sz);\n\n        auto add_edge_if = [&](int u, int v){\n            int iu = pos[u], iv = pos[v];\n            if (iu < 0 || iv < 0) return;\n            if (dsu.unite(iu, iv)) final_edges.emplace_back(u, v);\n        };\n\n        {\n            unordered_set<long long> seen;\n            seen.reserve(oracle_edges[k].size()*2+1);\n            auto enc = [](int a, int b)->long long{\n                if (a > b) swap(a,b);\n                return ((long long)a<<32) ^ (long long)b;\n            };\n            for (auto &e : oracle_edges[k]) {\n                int a = e.first, b = e.second;\n                if (a == b) continue;\n                if (pos[a] == -1 || pos[b] == -1) continue;\n                long long key = enc(a,b);\n                if (seen.insert(key).second) {\n                    add_edge_if(a,b);\n                    if ((int)final_edges.size() == sz-1) break;\n                }\n            }\n        }\n\n        // Add approximate MST edges next\n        for (auto &e : approxEdges[k]) {\n            if ((int)final_edges.size() == sz-1) break;\n            add_edge_if(e.first, e.second);\n        }\n\n        // Fallback: connect remaining components greedily by expected distance\n        if ((int)final_edges.size() < sz-1) {\n            unordered_map<int, vector<int>> comp_nodes;\n            comp_nodes.reserve(sz*2+1);\n            for (int i = 0; i < sz; ++i) comp_nodes[dsu.find(i)].push_back(grp[i]);\n\n            while ((int)comp_nodes.size() > 1 && (int)final_edges.size() < sz-1) {\n                double bestW = 1e300;\n                int bu=-1, bv=-1;\n                vector<pair<int, vector<int>>> comps;\n                comps.reserve(comp_nodes.size());\n                for (auto &kv : comp_nodes) comps.push_back(kv);\n                for (size_t i = 0; i < comps.size(); ++i) {\n                    for (size_t j = i+1; j < comps.size(); ++j) {\n                        for (int u : comps[i].second) {\n                            for (int v : comps[j].second) {\n                                double w = ed2(u, v);\n                                if (w < bestW) { bestW = w; bu = u; bv = v; }\n                            }\n                        }\n                    }\n                }\n                if (bu != -1) {\n                    add_edge_if(bu, bv);\n                    comp_nodes.clear();\n                    for (int i = 0; i < sz; ++i) comp_nodes[dsu.find(i)].push_back(grp[i]);\n                } else break;\n            }\n        }\n\n        for (auto &e : final_edges) cout << e.first << \" \" << e.second << \"\\n\";\n\n        for (int i = 0; i < sz; ++i) pos[grp[i]] = -1;\n    }\n\n    cout.flush();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Directions: 0:U, 1:D, 2:L, 3:R\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\nstatic const char dch[4] = {'U', 'D', 'L', 'R'};\n\nstruct Step {\n    char a; // 'M','S','A'\n    char d; // 'U','D','L','R'\n};\n\nstruct BFSResult {\n    bool ok = false;\n    vector<Step> path; // Non-empty only when needPath=true\n    int dist = -1;\n};\n\nstruct GridEnv {\n    int N;\n    vector<uint8_t> G; // 0 free, 1 blocked\n    GridEnv() {}\n    GridEnv(int N_) : N(N_), G(N_*N_, 0) {}\n    inline bool inside(int i, int j) const { return (0 <= i && i < N && 0 <= j && j < N); }\n    inline int id(int i, int j) const { return i * N + j; }\n    inline pair<int,int> coord(int idx) const { return {idx / N, idx % N}; }\n};\n\nstatic inline int dir_from_to(pair<int,int> a, pair<int,int> b) {\n    int di2 = b.first - a.first;\n    int dj2 = b.second - a.second;\n    if (di2 == -1 && dj2 == 0) return 0; // U\n    if (di2 == 1 && dj2 == 0)  return 1; // D\n    if (di2 == 0 && dj2 == -1) return 2; // L\n    if (di2 == 0 && dj2 == 1)  return 3; // R\n    return -1;\n}\n\n// Build local mapping around target t = (ti,tj) for enhanced BFS\nstatic inline void build_local_bits(const GridEnv &env, int ti, int tj,\n                                    vector<int> &cellToBit, vector<pair<int,int>> &bitPos) {\n    int NN = env.N * env.N;\n    cellToBit.assign(NN, -1);\n    bitPos.clear();\n    auto add_bit = [&](int i, int j) {\n        cellToBit[env.id(i, j)] = (int)bitPos.size();\n        bitPos.emplace_back(i, j);\n    };\n    add_bit(ti, tj); // bit 0 is target itself\n    if (env.inside(ti - 1, tj)) add_bit(ti - 1, tj);\n    if (env.inside(ti + 1, tj)) add_bit(ti + 1, tj);\n    if (env.inside(ti, tj - 1)) add_bit(ti, tj - 1);\n    if (env.inside(ti, tj + 1)) add_bit(ti, tj + 1);\n}\n\n// Compute slide destination with local mask\nstatic inline pair<int,int> slide_with_mask(const GridEnv &env, int i, int j, int d,\n                                            const vector<int> &cellToBit, int mask) {\n    int ci = i, cj = j;\n    while (true) {\n        int ni = ci + di[d], nj = cj + dj[d];\n        if (!env.inside(ni, nj)) break;\n        int idx = env.id(ni, nj);\n        int b = cellToBit[idx];\n        bool blocked = (b != -1 ? ((mask >> b) & 1) : env.G[idx]);\n        if (blocked) break;\n        ci = ni; cj = nj;\n    }\n    return {ci, cj};\n}\n\n// Enhanced BFS: allows M, S, and A on the target and its four neighbors only (local mask).\n// Returns both distance and, optionally, the action path.\nstatic BFSResult bfs_enhanced(const GridEnv &env, pair<int,int> s, pair<int,int> t, bool needPath) {\n    int N = env.N;\n    int NN = N * N;\n    int si = s.first, sj = s.second;\n    int ti = t.first, tj = t.second;\n    int sId = env.id(si, sj);\n    int tId = env.id(ti, tj);\n\n    vector<int> cellToBit;\n    vector<pair<int,int>> bitPos;\n    build_local_bits(env, ti, tj, cellToBit, bitPos);\n    int K = (int)bitPos.size();\n    int MS = 1 << K;\n\n    auto is_blocked = [&](int idx, int mask) -> bool {\n        int b = cellToBit[idx];\n        if (b != -1) return (mask >> b) & 1;\n        return env.G[idx];\n    };\n\n    int initMask = 0;\n    for (int b = 0; b < K; ++b) {\n        auto [bi, bj] = bitPos[b];\n        if (env.G[env.id(bi, bj)]) initMask |= (1 << b);\n    }\n\n    int SZ = NN * MS;\n    vector<char> vis(SZ, 0);\n    vector<int> distArr(SZ, -1);\n\n    vector<int> par, how, hdir;\n    if (needPath) {\n        par.assign(SZ, -1);\n        how.assign(SZ, 0);\n        hdir.assign(SZ, 0);\n    }\n\n    auto enc = [&](int pos, int mask) { return pos * MS + mask; };\n    int start = enc(sId, initMask);\n    deque<int> q;\n    vis[start] = 1;\n    distArr[start] = 0;\n    q.push_back(start);\n    int goal = -1;\n\n    while (!q.empty()) {\n        int u = q.front(); q.pop_front();\n        int pos = u / MS;\n        int mask = u % MS;\n        if (pos == tId) { goal = u; break; }\n\n        auto [ui, uj] = env.coord(pos);\n\n        // Move\n        for (int d = 0; d < 4; ++d) {\n            int vi = ui + di[d], vj = uj + dj[d];\n            if (!env.inside(vi, vj)) continue;\n            int vpos = env.id(vi, vj);\n            if (is_blocked(vpos, mask)) continue;\n            int v = enc(vpos, mask);\n            if (!vis[v]) {\n                vis[v] = 1;\n                distArr[v] = distArr[u] + 1;\n                if (needPath) { par[v] = u; how[v] = 'M'; hdir[v] = dch[d]; }\n                q.push_back(v);\n            }\n        }\n        // Slide\n        for (int d = 0; d < 4; ++d) {\n            auto [vi, vj] = slide_with_mask(env, ui, uj, d, cellToBit, mask);\n            if (vi == ui && vj == uj) continue;\n            int vpos = env.id(vi, vj);\n            int v = enc(vpos, mask);\n            if (!vis[v]) {\n                vis[v] = 1;\n                distArr[v] = distArr[u] + 1;\n                if (needPath) { par[v] = u; how[v] = 'S'; hdir[v] = dch[d]; }\n                q.push_back(v);\n            }\n        }\n        // Alter on local cells\n        for (int d = 0; d < 4; ++d) {\n            int vi = ui + di[d], vj = uj + dj[d];\n            if (!env.inside(vi, vj)) continue;\n            int b = cellToBit[env.id(vi, vj)];\n            if (b == -1) continue;\n            int nmask = mask ^ (1 << b);\n            int v = enc(pos, nmask);\n            if (!vis[v]) {\n                vis[v] = 1;\n                distArr[v] = distArr[u] + 1;\n                if (needPath) { par[v] = u; how[v] = 'A'; hdir[v] = dch[d]; }\n                q.push_back(v);\n            }\n        }\n    }\n\n    if (goal == -1) {\n        return BFSResult{false, {}, -1};\n    }\n\n    int dist = distArr[goal];\n    if (!needPath) {\n        return BFSResult{true, {}, dist};\n    }\n\n    vector<Step> path;\n    int cur = goal;\n    while (cur != start) {\n        path.push_back(Step{(char)how[cur], (char)hdir[cur]});\n        cur = par[cur];\n    }\n    reverse(path.begin(), path.end());\n    return BFSResult{true, path, dist};\n}\n\nstatic inline int dist_enhanced(const GridEnv &env, pair<int,int> s, pair<int,int> t) {\n    auto res = bfs_enhanced(env, s, t, false);\n    if (!res.ok) return INT_MAX / 4;\n    return res.dist;\n}\n\nstatic inline BFSResult path_enhanced(const GridEnv &env, pair<int,int> s, pair<int,int> t) {\n    return bfs_enhanced(env, s, t, true);\n}\n\n// Apply a Step to the state: update position and grid (for Alter).\nstatic inline void apply_step(GridEnv &env, pair<int,int> &pos, const Step &st) {\n    int i = pos.first, j = pos.second;\n    int d = 0;\n    for (int k = 0; k < 4; ++k) if (dch[k] == st.d) { d = k; break; }\n    if (st.a == 'M') {\n        int ni = i + di[d], nj = j + dj[d];\n        pos = {ni, nj};\n    } else if (st.a == 'S') {\n        int ci = i, cj = j;\n        while (true) {\n            int ni = ci + di[d], nj = cj + dj[d];\n            if (!env.inside(ni, nj)) break;\n            if (env.G[env.id(ni, nj)]) break;\n            ci = ni; cj = nj;\n        }\n        pos = {ci, cj};\n    } else if (st.a == 'A') {\n        int ni = i + di[d], nj = j + dj[d];\n        if (env.inside(ni, nj)) {\n            int idx = env.id(ni, nj);\n            env.G[idx] ^= 1;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    vector<pair<int,int>> P(M);\n    for (int k = 0; k < M; ++k) cin >> P[k].first >> P[k].second;\n\n    GridEnv env(N);\n    vector<Step> ans;\n    const long long cap = 2LL * N * M;\n\n    pair<int,int> cur = P[0];\n\n    for (int k = 1; k < M; ++k) {\n        pair<int,int> target = P[k];\n        pair<int,int> next1 = (k + 1 < M ? P[k + 1] : make_pair(-1, -1));\n        pair<int,int> next2 = (k + 2 < M ? P[k + 2] : make_pair(-1, -1));\n\n        // Plan path for current leg\n        auto plan = path_enhanced(env, cur, target);\n        if (!plan.ok) {\n            // extremely unlikely; fallback attempt\n            plan = path_enhanced(env, cur, target);\n            if (!plan.ok) {\n                // give up emitting more actions\n                break;\n            }\n        }\n        vector<Step> path = plan.path;\n\n        // Baseline distances for next legs under current env\n        int base1 = (k + 1 < M) ? dist_enhanced(env, target, next1) : 0;\n        int base2 = (k + 2 < M) ? dist_enhanced(env, next1, next2) : 0;\n\n        // Build candidate neighbor sets for opportunistic toggles (next1 and next2)\n        vector<int> candNext1, candNext2;\n        if (k + 1 < M) {\n            int ti = next1.first, tj = next1.second;\n            for (int d = 0; d < 4; ++d) {\n                int ni = ti + di[d], nj = tj + dj[d];\n                if (env.inside(ni, nj)) candNext1.push_back(env.id(ni, nj));\n            }\n        }\n        if (k + 2 < M) {\n            int ti = next2.first, tj = next2.second;\n            for (int d = 0; d < 4; ++d) {\n                int ni = ti + di[d], nj = tj + dj[d];\n                if (env.inside(ni, nj)) candNext2.push_back(env.id(ni, nj));\n            }\n        }\n\n        // Execute path with opportunistic toggles\n        pair<int,int> pos = cur;\n        int i = 0;\n        int toggledCount = 0;\n        const int maxTogglesPerLeg = 2;\n\n        auto try_opportunistic_toggle = [&](int &remLen, int &base1_ref, int &base2_ref) -> bool {\n            if (toggledCount >= maxTogglesPerLeg) return false;\n            int bestDelta = 0;\n            int bestIdx = -1;\n            char bestDir = 0;\n\n            auto consider_set = [&](const vector<int>& candSet) {\n                for (int idxB : candSet) {\n                    auto [bi, bj] = env.coord(idxB);\n                    int d = dir_from_to(pos, {bi, bj});\n                    if (d == -1) continue; // only consider cells adjacent to current pos\n                    // Try both toggling directions: add or remove (single toggle)\n                    // We'll just evaluate the effect of toggling whatever the state is (XOR).\n                    // Compute deltas\n                    // Toggle temporarily\n                    env.G[idxB] ^= 1;\n\n                    int cur_new = dist_enhanced(env, pos, target);\n                    int next1_new = (k + 1 < M) ? dist_enhanced(env, target, next1) : 0;\n                    int next2_new = (k + 2 < M) ? dist_enhanced(env, next1, next2) : 0;\n\n                    // revert\n                    env.G[idxB] ^= 1;\n\n                    if (cur_new >= INT_MAX / 8) continue; // skip infeasible\n\n                    int delta = 1 + (cur_new - remLen)\n                                  + (next1_new - base1_ref)\n                                  + (next2_new - base2_ref);\n\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestIdx = idxB;\n                        bestDir = dch[d];\n                    }\n                }\n            };\n\n            if (k + 1 < M) consider_set(candNext1);\n            if (k + 2 < M) consider_set(candNext2);\n\n            if (bestIdx != -1) {\n                if ((long long)ans.size() + 1LL > cap) return false;\n                ans.push_back(Step{'A', bestDir});\n                // Apply\n                env.G[bestIdx] ^= 1;\n                toggledCount++;\n\n                // Replan remainder from current pos\n                auto repl = path_enhanced(env, pos, target);\n                if (repl.ok) {\n                    path = repl.path;\n                    i = 0;\n                    remLen = (int)path.size();\n                    // Recompute base distances under new env\n                    if (k + 1 < M) base1_ref = dist_enhanced(env, target, next1);\n                    if (k + 2 < M) base2_ref = dist_enhanced(env, next1, next2);\n                    return true;\n                } else {\n                    // If replanning fails (very unlikely), revert the toggle to be safe\n                    env.G[bestIdx] ^= 1;\n                    ans.pop_back();\n                    toggledCount--;\n                }\n            }\n            return false;\n        };\n\n        while (i < (int)path.size()) {\n            int remLen = (int)path.size() - i;\n            // Try an opportunistic toggle before executing next step\n            if (try_opportunistic_toggle(remLen, base1, base2)) {\n                continue; // toggled and replanned; evaluate again from this state\n            }\n            // Execute next step\n            if ((long long)ans.size() + 1LL > cap) goto OUTPUT;\n            Step st = path[i];\n            ans.push_back(st);\n            apply_step(env, pos, st);\n            ++i;\n        }\n\n        cur = target;\n    }\n\nOUTPUT:\n    for (auto &st : ans) {\n        cout << st.a << ' ' << st.d << '\\n';\n    }\n    return 0;\n}"},"8":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Solver {\n    static constexpr int LIMIT_COORD = 10000;\n\n    int n;\n    vector<int> x, y;\n    vector<int> r;\n    vector<Rect> rects;\n\n    mt19937_64 rng;\n    Timer timer;\n    double time_limit;\n\n    Solver(int n_, vector<int> x_, vector<int> y_, vector<int> r_, double tl=4.85)\n        : n(n_), x(move(x_)), y(move(y_)), r(move(r_)), time_limit(tl) {\n        rects.resize(n);\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        seed ^= (uint64_t)(uintptr_t)this;\n        rng.seed(seed);\n    }\n\n    inline ll area_of(const Rect &rc) const {\n        return (ll)(rc.c - rc.a) * (ll)(rc.d - rc.b);\n    }\n\n    inline double score_si_ri(ll s, ll ri) const {\n        if (s <= 0) return 0.0;\n        ll mn = (s < ri ? s : ri);\n        ll mx = (s > ri ? s : ri);\n        double t = (double)mn / (double)mx;\n        double d = (1.0 - t);\n        return 1.0 - d * d;\n    }\n\n    inline double score_i(int i) const {\n        return score_si_ri(area_of(rects[i]), r[i]);\n    }\n\n    // Compute maximum expansions in each direction for rectangle i against others.\n    inline void compute_allowed_expansions(int i, int &leftMax, int &rightMax, int &downMax, int &upMax) const {\n        const Rect &ri = rects[i];\n        int LBound = 0, RBound = LIMIT_COORD, DBound = 0, UBound = LIMIT_COORD;\n\n        for (int j = 0; j < n; ++j) {\n            if (j == i) continue;\n            const Rect &rj = rects[j];\n            // Horizontal expansion blocked by rectangles overlapping vertically\n            if (!(ri.d <= rj.b || rj.d <= ri.b)) {\n                if (rj.a >= ri.c) RBound = min(RBound, rj.a);\n                if (rj.c <= ri.a) LBound = max(LBound, rj.c);\n            }\n            // Vertical expansion blocked by rectangles overlapping horizontally\n            if (!(ri.c <= rj.a || rj.c <= ri.a)) {\n                if (rj.b >= ri.d) UBound = min(UBound, rj.b);\n                if (rj.d <= ri.b) DBound = max(DBound, rj.d);\n            }\n        }\n        leftMax = max(0, ri.a - LBound);\n        rightMax = max(0, RBound - ri.c);\n        downMax = max(0, ri.b - DBound);\n        upMax = max(0, UBound - ri.d);\n    }\n\n    template <class T>\n    inline T clampv(T v, T lo, T hi) const {\n        if (v < lo) return lo;\n        if (v > hi) return hi;\n        return v;\n    }\n\n    inline ll expand_horiz(int i, int delta, int leftMax, int rightMax) {\n        if (delta <= 0 || (leftMax + rightMax) <= 0) return 0;\n        Rect &ri = rects[i];\n        int h = ri.d - ri.b;\n        int maxDelta = min(delta, leftMax + rightMax);\n        // Split to keep seed near center.\n        int leftDist = x[i] - ri.a;\n        int rightDist = ri.c - x[i] - 1;\n        int diff = rightDist - leftDist;\n        int l = clampv((maxDelta + diff) / 2, 0, maxDelta);\n        l = min(l, leftMax);\n        int rTake = maxDelta - l;\n        if (rTake > rightMax) {\n            rTake = rightMax;\n            l = maxDelta - rTake;\n            l = min(l, leftMax);\n        }\n        if (l > 0) ri.a -= l;\n        if (rTake > 0) ri.c += rTake;\n        return (ll)h * (ll)(l + rTake);\n    }\n\n    inline ll expand_vert(int i, int delta, int downMax, int upMax) {\n        if (delta <= 0 || (downMax + upMax) <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int maxDelta = min(delta, downMax + upMax);\n        int downDist = y[i] - ri.b;\n        int upDist = ri.d - y[i] - 1;\n        int d = clampv((maxDelta + (downDist - upDist)) / 2, 0, maxDelta);\n        d = min(d, downMax);\n        int uTake = maxDelta - d;\n        if (uTake > upMax) {\n            uTake = upMax;\n            d = maxDelta - uTake;\n            d = min(d, downMax);\n        }\n        if (d > 0) ri.b -= d;\n        if (uTake > 0) ri.d += uTake;\n        return (ll)w * (ll)(d + uTake);\n    }\n\n    inline ll shrink_horiz(int i, int delta) {\n        if (delta <= 0) return 0;\n        Rect &ri = rects[i];\n        int h = ri.d - ri.b;\n        int shrinkLeftMax = x[i] - ri.a;          // move 'a' right\n        int shrinkRightMax = ri.c - (x[i] + 1);   // move 'c' left\n        int cap = shrinkLeftMax + shrinkRightMax;\n        if (cap <= 0) return 0;\n\n        int maxDelta = min(delta, cap);\n        int leftDist = x[i] - ri.a;\n        int rightDist = ri.c - x[i] - 1;\n        int l = clampv((maxDelta + (leftDist - rightDist)) / 2, 0, maxDelta);\n        l = min(l, shrinkLeftMax);\n        int rTake = maxDelta - l;\n        if (rTake > shrinkRightMax) {\n            rTake = shrinkRightMax;\n            l = maxDelta - rTake;\n            l = min(l, shrinkLeftMax);\n        }\n        if (l > 0) ri.a += l;\n        if (rTake > 0) ri.c -= rTake;\n        return (ll)h * (ll)(l + rTake);\n    }\n\n    inline ll shrink_vert(int i, int delta) {\n        if (delta <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int shrinkDownMax = y[i] - ri.b;\n        int shrinkUpMax = ri.d - (y[i] + 1);\n        int cap = shrinkDownMax + shrinkUpMax;\n        if (cap <= 0) return 0;\n\n        int maxDelta = min(delta, cap);\n        int downDist = y[i] - ri.b;\n        int upDist = ri.d - y[i] - 1;\n        int d = clampv((maxDelta + (downDist - upDist)) / 2, 0, maxDelta);\n        d = min(d, shrinkDownMax);\n        int uTake = maxDelta - d;\n        if (uTake > shrinkUpMax) {\n            uTake = shrinkUpMax;\n            d = maxDelta - uTake;\n            d = min(d, shrinkDownMax);\n        }\n        if (d > 0) ri.b += d;\n        if (uTake > 0) ri.d -= uTake;\n        return (ll)w * (ll)(d + uTake);\n    }\n\n    // Adjust rectangle i towards its target area r[i]\n    bool adjust_one(int i) {\n        Rect &rc = rects[i];\n        bool changed = false;\n\n        for (int it = 0; it < 3; ++it) {\n            ll s = area_of(rc);\n            ll target = r[i];\n            int w = rc.c - rc.a;\n            int h = rc.d - rc.b;\n\n            int leftMax, rightMax, downMax, upMax;\n            compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n\n            if (s < target) {\n                bool tryH = (leftMax + rightMax) > 0;\n                bool tryV = (downMax + upMax) > 0;\n                bool horizFirst;\n                if (tryH && tryV) {\n                    if (w < h) horizFirst = true;\n                    else if (w > h) horizFirst = false;\n                    else horizFirst = true;\n                } else if (tryH) horizFirst = true;\n                else if (tryV) horizFirst = false;\n                else horizFirst = true;\n\n                if (horizFirst && tryH) {\n                    ll need = target - s;\n                    int delta = (int)min<ll>((ll)(leftMax + rightMax), need / max(1, h));\n                    if (delta > 0) {\n                        expand_horiz(i, delta, leftMax, rightMax);\n                        changed = true;\n                    }\n                }\n                s = area_of(rc);\n                if (s < target && tryV) {\n                    compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n                    w = rc.c - rc.a;\n                    ll need2 = target - s;\n                    int delta2 = (int)min<ll>((ll)(downMax + upMax), need2 / max(1, w));\n                    if (delta2 > 0) {\n                        expand_vert(i, delta2, downMax, upMax);\n                        changed = true;\n                    }\n                }\n                s = area_of(rc);\n                if (s < target) {\n                    compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n                    w = rc.c - rc.a; int h2 = rc.d - rc.b;\n                    ll bestImprove = 0;\n                    int bestMove = -1;\n                    auto clos = [&](ll si){ return llabs(si - target); };\n                    ll curClos = clos(s);\n                    if (leftMax > 0) {\n                        ll s2 = s + h2;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 0;\n                    }\n                    if (rightMax > 0) {\n                        ll s2 = s + h2;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 1;\n                    }\n                    if (downMax > 0) {\n                        ll s2 = s + w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 2;\n                    }\n                    if (upMax > 0) {\n                        ll s2 = s + w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 3;\n                    }\n                    if (bestImprove > 0) {\n                        if (bestMove == 0) rc.a -= 1;\n                        else if (bestMove == 1) rc.c += 1;\n                        else if (bestMove == 2) rc.b -= 1;\n                        else if (bestMove == 3) rc.d += 1;\n                        changed = true;\n                    }\n                }\n            } else if (s > target) {\n                ll over = s - target;\n                bool canH = ((x[i] - rc.a) + (rc.c - (x[i] + 1))) > 0;\n                bool canV = ((y[i] - rc.b) + (rc.d - (y[i] + 1))) > 0;\n                bool shrinkHFirst;\n                if (canH && canV) {\n                    if (w > h) shrinkHFirst = true;\n                    else if (w < h) shrinkHFirst = false;\n                    else shrinkHFirst = true;\n                } else if (canH) shrinkHFirst = true;\n                else if (canV) shrinkHFirst = false;\n                else shrinkHFirst = true;\n\n                if (shrinkHFirst && canH) {\n                    int delta = (int)(over / max(1, h));\n                    if (delta > 0) {\n                        ll dec = shrink_horiz(i, delta);\n                        if (dec > 0) changed = true;\n                    }\n                }\n                s = area_of(rc);\n                if (s > target && canV) {\n                    over = s - target;\n                    int delta2 = (int)(over / max(1, w));\n                    if (delta2 > 0) {\n                        ll dec2 = shrink_vert(i, delta2);\n                        if (dec2 > 0) changed = true;\n                    }\n                }\n                s = area_of(rc);\n                if (s > target) {\n                    int shrinkLeftMax = x[i] - rc.a;\n                    int shrinkRightMax = rc.c - (x[i] + 1);\n                    int shrinkDownMax = y[i] - rc.b;\n                    int shrinkUpMax = rc.d - (y[i] + 1);\n                    ll bestImprove = 0;\n                    int bestMove = -1;\n                    auto clos = [&](ll si){ return llabs(si - target); };\n                    ll curClos = clos(s);\n                    if (shrinkLeftMax > 0) {\n                        ll s2 = s - (ll)h;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 0;\n                    }\n                    if (shrinkRightMax > 0) {\n                        ll s2 = s - (ll)h;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 1;\n                    }\n                    if (shrinkDownMax > 0) {\n                        ll s2 = s - (ll)w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 2;\n                    }\n                    if (shrinkUpMax > 0) {\n                        ll s2 = s - (ll)w;\n                        ll imp = curClos - clos(s2);\n                        if (imp > bestImprove) bestImprove = imp, bestMove = 3;\n                    }\n                    if (bestImprove > 0) {\n                        if (bestMove == 0) rc.a += 1;\n                        else if (bestMove == 1) rc.c -= 1;\n                        else if (bestMove == 2) rc.b += 1;\n                        else if (bestMove == 3) rc.d -= 1;\n                        changed = true;\n                    }\n                }\n            } else {\n                break;\n            }\n\n            // Safety clamps\n            rc.a = clampv(rc.a, 0, LIMIT_COORD - 1);\n            rc.c = clampv(rc.c, rc.a + 1, LIMIT_COORD);\n            rc.b = clampv(rc.b, 0, LIMIT_COORD - 1);\n            rc.d = clampv(rc.d, rc.b + 1, LIMIT_COORD);\n            if (!(rc.a <= x[i] && x[i] < rc.c && rc.b <= y[i] && y[i] < rc.d)) {\n                rc.a = x[i]; rc.b = y[i]; rc.c = x[i] + 1; rc.d = y[i] + 1;\n                changed = true;\n            }\n        }\n        return changed;\n    }\n\n    void initial_setup() {\n        for (int i = 0; i < n; ++i) rects[i] = Rect{ x[i], y[i], x[i] + 1, y[i] + 1 };\n    }\n\n    static inline long long floordiv(long long a, long long b) {\n        if (b < 0) a = -a, b = -b;\n        if (a >= 0) return a / b;\n        else return - ((-a + b - 1) / b);\n    }\n    static inline long long ceildiv(long long a, long long b) {\n        return -floordiv(-a, b);\n    }\n\n    struct PairItem {\n        int i, j; // i left of j if vertical; i bottom of j if horizontal\n        bool vertical;\n    };\n\n    void build_fullside_pairs(vector<PairItem>& pairs) const {\n        pairs.clear();\n        for (int i = 0; i < n; ++i) {\n            const Rect &ri = rects[i];\n            for (int j = i+1; j < n; ++j) {\n                const Rect &rj = rects[j];\n                // Vertical adjacency full side\n                if (ri.c == rj.a && ri.b == rj.b && ri.d == rj.d) {\n                    pairs.push_back({i, j, true});\n                } else if (rj.c == ri.a && rj.b == ri.b && rj.d == ri.d) {\n                    pairs.push_back({j, i, true});\n                }\n                // Horizontal adjacency full side\n                if (ri.d == rj.b && ri.a == rj.a && ri.c == rj.c) {\n                    pairs.push_back({i, j, false});\n                } else if (rj.d == ri.b && rj.a == ri.a && rj.c == ri.c) {\n                    pairs.push_back({j, i, false});\n                }\n            }\n        }\n    }\n\n    // Geometry helpers\n    static inline bool overlapStrict(const Rect& A, const Rect& B) {\n        return (A.a < B.c && B.a < A.c && A.b < B.d && B.b < A.d);\n    }\n    inline bool containsSeed(const Rect& R, int xi, int yi) const {\n        return (R.a <= xi && xi < R.c && R.b <= yi && yi < R.d);\n    }\n    inline bool insideBounds(const Rect& R) const {\n        return (0 <= R.a && R.a < R.c && R.c <= LIMIT_COORD &&\n                0 <= R.b && R.b < R.d && R.d <= LIMIT_COORD);\n    }\n\n    bool pair_update_legal(int i, int j, const Rect& Ri, const Rect& Rj) const {\n        if (!insideBounds(Ri) || !insideBounds(Rj)) return false;\n        if (!containsSeed(Ri, x[i], y[i]) || !containsSeed(Rj, x[j], y[j])) return false;\n        if (overlapStrict(Ri, Rj)) return false;\n        for (int k = 0; k < n; ++k) {\n            if (k == i || k == j) continue;\n            const Rect &Rk = rects[k];\n            if (overlapStrict(Ri, Rk)) return false;\n            if (overlapStrict(Rj, Rk)) return false;\n        }\n        return true;\n    }\n    bool single_update_legal(int i, const Rect& Ri) const {\n        if (!insideBounds(Ri)) return false;\n        if (!containsSeed(Ri, x[i], y[i])) return false;\n        for (int k = 0; k < n; ++k) {\n            if (k == i) continue;\n            if (overlapStrict(Ri, rects[k])) return false;\n        }\n        return true;\n    }\n\n    // Greedy hill-climb to find the best slide t in [tmin, tmax] for an aligned pair.\n    inline void best_slide_hillclimb(const Rect &L, const Rect &R, bool vertical, int idxL, int idxR, int &bestT, double &bestVal) const {\n        ll sL0 = (ll)(L.c - L.a) * (ll)(L.d - L.b);\n        ll sR0 = (ll)(R.c - R.a) * (ll)(R.d - R.b);\n        int unit = vertical ? (L.d - L.b) : (L.c - L.a);\n        double base = score_si_ri(sL0, r[idxL]) + score_si_ri(sR0, r[idxR]);\n        if (unit <= 0) { bestT = 0; bestVal = base; return; }\n\n        int tmin, tmax;\n        if (vertical) {\n            tmin = (x[idxL] + 1) - L.c;\n            tmax = x[idxR] - R.a;\n        } else {\n            tmin = (y[idxL] + 1) - L.d;\n            tmax = y[idxR] - R.b;\n        }\n        if (tmin > tmax) { bestT = 0; bestVal = base; return; }\n\n        auto valAt = [&](int t)->double{\n            ll sL = sL0 + (ll)unit * (ll)t;\n            ll sR = sR0 - (ll)unit * (ll)t;\n            return score_si_ri(sL, r[idxL]) + score_si_ri(sR, r[idxR]);\n        };\n\n        int t = 0;\n        double cur = valAt(0);\n        while (true) {\n            double vp = -1e100, vm = -1e100;\n            if (t < tmax) vp = valAt(t + 1);\n            if (t > tmin) vm = valAt(t - 1);\n            if (vp <= cur + 1e-15 && vm <= cur + 1e-15) break;\n            if (vp >= vm) { t += 1; cur = vp; }\n            else { t -= 1; cur = vm; }\n        }\n        bestT = t;\n        bestVal = cur;\n    }\n\n    bool slide_pairs_pass() {\n        vector<PairItem> pairs;\n        build_fullside_pairs(pairs);\n        if (pairs.empty()) return false;\n\n        shuffle(pairs.begin(), pairs.end(), rng);\n\n        bool anyImproved = false;\n        for (const auto &pi : pairs) {\n            int i = pi.i, j = pi.j;\n            const Rect &ri = rects[i];\n            const Rect &rj = rects[j];\n\n            double base = score_i(i) + score_i(j);\n            int bestT = 0;\n            double bestVal = base;\n            best_slide_hillclimb(ri, rj, pi.vertical, i, j, bestT, bestVal);\n\n            if (bestVal > base + 1e-12 && bestT != 0) {\n                if (pi.vertical) {\n                    rects[i].c += bestT;\n                    rects[j].a += bestT;\n                } else {\n                    rects[i].d += bestT;\n                    rects[j].b += bestT;\n                }\n                anyImproved = true;\n            }\n\n            if (timer.elapsed() > time_limit * 0.95) break;\n        }\n        return anyImproved;\n    }\n\n    // Helper to choose B for height H\n    inline int choose_B_for_H(int H, int BminC, int BmaxC, int DminC, int DmaxC, int yi, int yj) const {\n        int Blo = max(BminC, DminC - H);\n        int Bhi = min(BmaxC, DmaxC - H);\n        long long ycenter = ( (long long)yi + (long long)yj + 1 - H ) / 2;\n        int B = (int)clampv(ycenter, (long long)Blo, (long long)Bhi);\n        return B;\n    }\n    inline int choose_A_for_W(int W, int AminC, int AmaxC, int CminC, int CmaxC, int xi, int xj) const {\n        int Alo = max(AminC, CminC - W);\n        int Ahi = min(AmaxC, CmaxC - W);\n        long long xcenter = ( (long long)xi + (long long)xj + 1 - W ) / 2;\n        int A = (int)clampv(xcenter, (long long)Alo, (long long)Ahi);\n        return A;\n    }\n\n    // General alignment pass: consider touching pairs (vertical/horizontal),\n    // find a feasible common height/width using expansion and shrinking,\n    // then perform the best slide via hill-climb; commit only if local sum improves and base alignment is legal.\n    bool align_general_pairs_pass() {\n        bool anyImproved = false;\n\n        // Vertical touching pairs\n        for (int i = 0; i < n; ++i) {\n            if (timer.elapsed() > time_limit * 0.92) break;\n            for (int j = i + 1; j < n; ++j) {\n                int idxL = -1, idxR = -1;\n                if (rects[i].c == rects[j].a) { idxL = i; idxR = j; }\n                else if (rects[j].c == rects[i].a) { idxL = j; idxR = i; }\n                else continue;\n\n                const Rect &Li = rects[idxL];\n                const Rect &Rj = rects[idxR];\n\n                int lL, rL, dL, uL, lR, rR, dR, uR;\n                compute_allowed_expansions(idxL, lL, rL, dL, uL);\n                compute_allowed_expansions(idxR, lR, rR, dR, uR);\n\n                int bminL = Li.b - dL;\n                int bmaxL = y[idxL];\n                int dminL = y[idxL] + 1;\n                int dmaxL = Li.d + uL;\n\n                int bminR = Rj.b - dR;\n                int bmaxR = y[idxR];\n                int dminR = y[idxR] + 1;\n                int dmaxR = Rj.d + uR;\n\n                int BminC = max(bminL, bminR);\n                int BmaxC = min(bmaxL, bmaxR);\n                int DminC = max(dminL, dminR);\n                int DmaxC = min(dmaxL, dmaxR);\n\n                int Hmin = max(1, DminC - BmaxC);\n                int Hmax = DmaxC - BminC;\n                if (Hmin > Hmax) continue;\n\n                int wL = Li.c - Li.a;\n                int wR = Rj.c - Rj.a;\n                int HL = Li.d - Li.b;\n                int HR = Rj.d - Rj.b;\n\n                double base = score_i(idxL) + score_i(idxR);\n\n                vector<int> candH;\n                candH.reserve(14);\n                auto pushH = [&](long long H) {\n                    if (H < Hmin) H = Hmin;\n                    if (H > Hmax) H = Hmax;\n                    int h = (int)H;\n                    for (int v : candH) if (v == h) return;\n                    candH.push_back(h);\n                };\n                pushH(Hmin); pushH(Hmax);\n                pushH(HL); pushH(HL-1); pushH(HL+1);\n                pushH(HR); pushH(HR-1); pushH(HR+1);\n                if (wL > 0) { long long t = r[idxL] / max(1, wL); pushH(t); pushH(t-1); pushH(t+1); }\n                if (wR > 0) { long long t = r[idxR] / max(1, wR); pushH(t); pushH(t-1); pushH(t+1); }\n\n                double bestVal = base;\n                int bestH = 0;\n                int bestT = 0;\n                int bestB = 0;\n\n                for (int H : candH) {\n                    int B = choose_B_for_H(H, BminC, BmaxC, DminC, DmaxC, y[idxL], y[idxR]);\n                    Rect L2 = Li, R2 = Rj;\n                    L2.b = B; L2.d = B + H;\n                    R2.b = B; R2.d = B + H;\n\n                    if (!pair_update_legal(idxL, idxR, L2, R2)) continue;\n\n                    int tbest = 0;\n                    double valBestSlide;\n                    best_slide_hillclimb(L2, R2, true, idxL, idxR, tbest, valBestSlide);\n\n                    if (valBestSlide > bestVal + 1e-12) {\n                        bestVal = valBestSlide;\n                        bestH = H;\n                        bestT = tbest;\n                        bestB = B;\n                    }\n                }\n\n                if (bestVal > base + 1e-12) {\n                    rects[idxL].b = bestB; rects[idxL].d = bestB + bestH;\n                    rects[idxR].b = bestB; rects[idxR].d = bestB + bestH;\n                    rects[idxL].c += bestT;\n                    rects[idxR].a += bestT;\n                    anyImproved = true;\n                }\n            }\n        }\n\n        // Horizontal touching pairs\n        for (int i = 0; i < n; ++i) {\n            if (timer.elapsed() > time_limit * 0.94) break;\n            for (int j = i + 1; j < n; ++j) {\n                int idxB = -1, idxT = -1;\n                if (rects[i].d == rects[j].b) { idxB = i; idxT = j; }\n                else if (rects[j].d == rects[i].b) { idxB = j; idxT = i; }\n                else continue;\n\n                const Rect &Bi = rects[idxB];\n                const Rect &Tj = rects[idxT];\n\n                int lB, rB, dB, uB, lT, rT, dT, uT;\n                compute_allowed_expansions(idxB, lB, rB, dB, uB);\n                compute_allowed_expansions(idxT, lT, rT, dT, uT);\n\n                int shrinkLeftB = x[idxB] - Bi.a;\n                int shrinkRightB = Bi.c - (x[idxB] + 1);\n                int shrinkLeftT = x[idxT] - Tj.a;\n                int shrinkRightT = Tj.c - (x[idxT] + 1);\n\n                int a_min_B = Bi.a - lB;\n                int a_max_B = Bi.a + shrinkLeftB;\n                int c_min_B = Bi.c - shrinkRightB;\n                int c_max_B = Bi.c + rB;\n\n                int a_min_T = Tj.a - lT;\n                int a_max_T = Tj.a + shrinkLeftT;\n                int c_min_T = Tj.c - shrinkRightT;\n                int c_max_T = Tj.c + rT;\n\n                int AminC = max(a_min_B, a_min_T);\n                int AmaxC = min(a_max_B, a_max_T);\n                int CminC = max(c_min_B, c_min_T);\n                int CmaxC = min(c_max_B, c_max_T);\n\n                int Wmin = max(1, CminC - AmaxC);\n                int Wmax = CmaxC - AminC;\n                if (Wmin > Wmax) continue;\n\n                int hB = Bi.d - Bi.b;\n                int hT = Tj.d - Tj.b;\n                int WB = Bi.c - Bi.a;\n                int WT = Tj.c - Tj.a;\n\n                double base = score_i(idxB) + score_i(idxT);\n\n                vector<int> candW;\n                candW.reserve(14);\n                auto pushW = [&](long long W) {\n                    if (W < Wmin) W = Wmin;\n                    if (W > Wmax) W = Wmax;\n                    int w = (int)W;\n                    for (int v : candW) if (v == w) return;\n                    candW.push_back(w);\n                };\n                pushW(Wmin); pushW(Wmax);\n                pushW(WB); pushW(WB-1); pushW(WB+1);\n                pushW(WT); pushW(WT-1); pushW(WT+1);\n                if (hB > 0) { long long t = r[idxB] / max(1, hB); pushW(t); pushW(t-1); pushW(t+1); }\n                if (hT > 0) { long long t = r[idxT] / max(1, hT); pushW(t); pushW(t-1); pushW(t+1); }\n\n                double bestVal = base;\n                int bestW = 0;\n                int bestT = 0;\n                int bestA = 0;\n\n                for (int W : candW) {\n                    int A = choose_A_for_W(W, AminC, AmaxC, CminC, CmaxC, x[idxB], x[idxT]);\n                    Rect B2 = Bi, T2 = Tj;\n                    B2.a = A; B2.c = A + W;\n                    T2.a = A; T2.c = A + W;\n\n                    if (!pair_update_legal(idxB, idxT, B2, T2)) continue;\n\n                    int tbest = 0;\n                    double valBestSlide;\n                    best_slide_hillclimb(B2, T2, false, idxB, idxT, tbest, valBestSlide);\n\n                    if (valBestSlide > bestVal + 1e-12) {\n                        bestVal = valBestSlide;\n                        bestW = W;\n                        bestT = tbest;\n                        bestA = A;\n                    }\n                }\n\n                if (bestVal > base + 1e-12) {\n                    rects[idxB].a = bestA; rects[idxB].c = bestA + bestW;\n                    rects[idxT].a = bestA; rects[idxT].c = bestA + bestW;\n                    rects[idxB].d += bestT;\n                    rects[idxT].b += bestT;\n                    anyImproved = true;\n                }\n            }\n        }\n\n        return anyImproved;\n    }\n\n    // Shift helpers: compute legal corridor for horizontal shift\n    bool shift_horizontal_center(int i) {\n        const Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        if (w <= 0) return false;\n        int Alo = 0, Ahi = LIMIT_COORD - w;\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect &rj = rects[j];\n            if (!(ri.d <= rj.b || rj.d <= ri.b)) {\n                if (rj.c <= ri.a) {\n                    Alo = max(Alo, rj.c);\n                } else if (rj.a >= ri.c) {\n                    Ahi = min(Ahi, rj.a - w);\n                } else {\n                    // cannot happen in valid solution (else overlap)\n                }\n            }\n        }\n        // seed constraint\n        Alo = max(Alo, x[i] - (w - 1));\n        Ahi = min(Ahi, x[i]);\n        if (Alo > Ahi) return false;\n\n        int a_center_seed = x[i] - (w - 1) / 2;\n        int a_new = clampv(a_center_seed, Alo, Ahi);\n        if (a_new == ri.a) return false;\n\n        Rect Rn = ri;\n        Rn.a = a_new; Rn.c = a_new + w;\n        if (!single_update_legal(i, Rn)) return false;\n        rects[i] = Rn;\n        return true;\n    }\n\n    bool shift_horizontal_pack(int i) {\n        const Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        if (w <= 0) return false;\n        int Alo = 0, Ahi = LIMIT_COORD - w;\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect &rj = rects[j];\n            if (!(ri.d <= rj.b || rj.d <= ri.b)) {\n                if (rj.c <= ri.a) {\n                    Alo = max(Alo, rj.c);\n                } else if (rj.a >= ri.c) {\n                    Ahi = min(Ahi, rj.a - w);\n                }\n            }\n        }\n        Alo = max(Alo, x[i] - (w - 1));\n        Ahi = min(Ahi, x[i]);\n        if (Alo > Ahi) return false;\n\n        // Fill larger gap side\n        int moveRight = Ahi - ri.a;\n        int moveLeft = ri.a - Alo;\n        int a_new = (moveRight > moveLeft) ? Ahi : Alo;\n        if (a_new == ri.a) return false;\n\n        Rect Rn = ri;\n        Rn.a = a_new; Rn.c = a_new + w;\n        if (!single_update_legal(i, Rn)) return false;\n        rects[i] = Rn;\n        return true;\n    }\n\n    bool shift_vertical_center(int i) {\n        const Rect &ri = rects[i];\n        int h = ri.d - ri.b;\n        if (h <= 0) return false;\n        int Blo = 0, Bhi = LIMIT_COORD - h;\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect &rj = rects[j];\n            if (!(ri.c <= rj.a || rj.c <= ri.a)) {\n                if (rj.d <= ri.b) {\n                    Blo = max(Blo, rj.d);\n                } else if (rj.b >= ri.d) {\n                    Bhi = min(Bhi, rj.b - h);\n                }\n            }\n        }\n        Blo = max(Blo, y[i] - (h - 1));\n        Bhi = min(Bhi, y[i]);\n        if (Blo > Bhi) return false;\n\n        int b_center_seed = y[i] - (h - 1) / 2;\n        int b_new = clampv(b_center_seed, Blo, Bhi);\n        if (b_new == ri.b) return false;\n\n        Rect Rn = ri;\n        Rn.b = b_new; Rn.d = b_new + h;\n        if (!single_update_legal(i, Rn)) return false;\n        rects[i] = Rn;\n        return true;\n    }\n\n    bool shift_vertical_pack(int i) {\n        const Rect &ri = rects[i];\n        int h = ri.d - ri.b;\n        if (h <= 0) return false;\n        int Blo = 0, Bhi = LIMIT_COORD - h;\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect &rj = rects[j];\n            if (!(ri.c <= rj.a || rj.c <= ri.a)) {\n                if (rj.d <= ri.b) {\n                    Blo = max(Blo, rj.d);\n                } else if (rj.b >= ri.d) {\n                    Bhi = min(Bhi, rj.b - h);\n                }\n            }\n        }\n        Blo = max(Blo, y[i] - (h - 1));\n        Bhi = min(Bhi, y[i]);\n        if (Blo > Bhi) return false;\n\n        int moveUp = Bhi - ri.b;\n        int moveDown = ri.b - Blo;\n        int b_new = (moveUp > moveDown) ? Bhi : Blo;\n        if (b_new == ri.b) return false;\n\n        Rect Rn = ri;\n        Rn.b = b_new; Rn.d = b_new + h;\n        if (!single_update_legal(i, Rn)) return false;\n        rects[i] = Rn;\n        return true;\n    }\n\n    bool shift_pass(bool packMode) {\n        vector<int> idx(n);\n        iota(idx.begin(), idx.end(), 0);\n        shuffle(idx.begin(), idx.end(), rng);\n        bool changed = false;\n        for (int k = 0; k < n; ++k) {\n            if ((k % 16 == 0) && timer.elapsed() > time_limit) break;\n            int i = idx[k];\n            bool ch = false;\n            if (packMode) {\n                ch |= shift_horizontal_pack(i);\n                ch |= shift_vertical_pack(i);\n            } else {\n                ch |= shift_horizontal_center(i);\n                ch |= shift_vertical_center(i);\n            }\n            changed |= ch;\n        }\n        return changed;\n    }\n\n    void expand_pass_random() {\n        vector<int> idx(n);\n        iota(idx.begin(), idx.end(), 0);\n        shuffle(idx.begin(), idx.end(), rng);\n        for (int k = 0; k < n; ++k) {\n            if ((k & 31) == 0 && timer.elapsed() > time_limit) return;\n            adjust_one(idx[k]);\n        }\n    }\n\n    void expand_pass_descR(const vector<int>& order) {\n        for (int id : order) {\n            if (timer.elapsed() > time_limit) return;\n            adjust_one(id);\n        }\n    }\n\n    void expand_pass_by_gap() {\n        vector<pair<ll,int>> arr;\n        arr.reserve(n);\n        for (int i = 0; i < n; ++i) {\n            ll s = area_of(rects[i]);\n            arr.emplace_back(llabs(s - (ll)r[i]), i);\n        }\n        sort(arr.begin(), arr.end(), [&](const auto& A, const auto& B){ return A.first > B.first; });\n        for (int k = 0; k < n; ++k) {\n            if ((k & 31) == 0 && timer.elapsed() > time_limit) return;\n            adjust_one(arr[k].second);\n        }\n    }\n\n    void solve() {\n        initial_setup();\n\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        stable_sort(order.begin(), order.end(), [&](int a, int b){ return r[a] > r[b]; });\n\n        // Phase 1: expansion/shrink passes\n        double t1 = time_limit * 0.26;\n        while (timer.elapsed() < t1) {\n            expand_pass_descR(order);\n            expand_pass_random();\n        }\n        expand_pass_by_gap();\n\n        // Phase 1.2: centering shifts to prepare for alignment/expansion\n        double t_center = time_limit * 0.34;\n        while (timer.elapsed() < t_center) {\n            bool ch = shift_pass(false);\n            if (!ch) break;\n        }\n\n        // Phase 1.5: generalized alignment to create/reshape full-side neighbors\n        double t_align1 = time_limit * 0.58;\n        while (timer.elapsed() < t_align1) {\n            bool imp = align_general_pairs_pass();\n            if (!imp) break;\n        }\n\n        // Phase 2: pairwise slides on full sides\n        double t2 = time_limit * 0.82;\n        while (timer.elapsed() < t2) {\n            bool improved = slide_pairs_pass();\n            if (!improved) break;\n        }\n\n        // Phase 2.2: try generalized alignment again\n        double t_align2 = time_limit * 0.90;\n        while (timer.elapsed() < t_align2) {\n            bool imp = align_general_pairs_pass();\n            if (!imp) break;\n        }\n\n        // Phase 2.4: packing shifts to create more adjacencies\n        double t_pack = time_limit * 0.94;\n        while (timer.elapsed() < t_pack) {\n            bool ch = shift_pass(true);\n            if (!ch) break;\n        }\n\n        // Phase 2.6: slide again after packing\n        double t_slide2 = time_limit * 0.97;\n        while (timer.elapsed() < t_slide2) {\n            bool improved = slide_pairs_pass();\n            if (!improved) break;\n        }\n\n        // Phase 3: final smoothing\n        while (timer.elapsed() < time_limit) {\n            expand_pass_by_gap();\n            if (timer.elapsed() > time_limit) break;\n            bool improved = slide_pairs_pass();\n            if (!improved) break;\n        }\n    }\n\n    void output() const {\n        for (int i = 0; i < n; ++i) {\n            const Rect &rc = rects[i];\n            cout << rc.a << ' ' << rc.b << ' ' << rc.c << ' ' << rc.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    if (!(cin >> n)) return 0;\n    vector<int> x(n), y(n), r(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> x[i] >> y[i] >> r[i];\n    }\n\n    Solver solver(n, x, y, r, 4.85);\n    solver.solve();\n    solver.output();\n\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Fast RNG (xorshift)\nstruct XorShift64 {\n    uint64_t x;\n    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    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int randint(int l, int r) { // inclusive l..r\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Params {\n    double wP;        // weight for immediate p\n    double wDeg;      // weight for degree of next cell\n    double wPot;      // weight for precomputed potential\n    double wTwinPot;  // penalty weight for twin potential\n    double wTwinDeg;  // penalty weight for twin degree\n    double wLook;     // weight for 2-ply lookahead\n    double noise;     // random noise amplitude\n    int avoidDeadMinLen; // avoid moving into dead-end before this many steps if alternatives exist\n};\n\nstruct PathResult {\n    long long score;\n    string moves;\n    int lengthTiles; // number of tiles visited\n};\n\nstatic const int H = 50, W = 50, N = H * W;\n\ninline int id_of(int i, int j) { return i * W + j; }\n\ninline char direction_char(int u, int v) {\n    int ui = u / W, uj = u % W;\n    int vi = v / W, vj = v % W;\n    if (vi == ui - 1 && vj == uj) return 'U';\n    if (vi == ui + 1 && vj == uj) return 'D';\n    if (vi == ui && vj == uj - 1) return 'L';\n    if (vi == ui && vj == uj + 1) return 'R';\n    return 'U';\n}\n\ninline int move_to(int pos, char c) {\n    int i = pos / W, j = pos % W;\n    if (c == 'U') { if (i == 0) return -1; return id_of(i-1, j); }\n    if (c == 'D') { if (i == H-1) return -1; return id_of(i+1, j); }\n    if (c == 'L') { if (j == 0) return -1; return id_of(i, j-1); }\n    if (c == 'R') { if (j == W-1) return -1; return id_of(i, j+1); }\n    return -1;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto time_start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.95; // seconds\n\n    int si, sj;\n    if (!(cin >> si >> sj)) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    vector<int> tile(N), pval(N);\n    int maxTile = -1;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int t; cin >> t;\n            tile[id_of(i, j)] = t;\n            if (t > maxTile) maxTile = t;\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            int pv; cin >> pv;\n            pval[id_of(i, j)] = pv;\n        }\n    }\n\n    // Build tileCells and twin mapping\n    vector<vector<int>> tileCells(M);\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int id = id_of(i, j);\n            tileCells[tile[id]].push_back(id);\n        }\n    }\n    vector<int> twin(N, -1);\n    for (int t = 0; t < M; t++) {\n        if (tileCells[t].size() == 2) {\n            int a = tileCells[t][0];\n            int b = tileCells[t][1];\n            twin[a] = b;\n            twin[b] = a;\n        }\n    }\n\n    // Build neighbor list: edges only across different tiles\n    vector<vector<int>> NB(N);\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = id_of(i, j);\n            if (i-1 >= 0) { int v = id_of(i-1, j); if (tile[u] != tile[v]) NB[u].push_back(v); }\n            if (i+1 <  H) { int v = id_of(i+1, j); if (tile[u] != tile[v]) NB[u].push_back(v); }\n            if (j-1 >= 0) { int v = id_of(i, j-1); if (tile[u] != tile[v]) NB[u].push_back(v); }\n            if (j+1 <  W) { int v = id_of(i, j+1); if (tile[u] != tile[v]) NB[u].push_back(v); }\n        }\n    }\n\n    // Precompute static potentials: BFS to depth 3 on allowed graph, with decays for p\n    vector<double> pot(N, 0.0);\n    {\n        static const double w1 = 1.0, w2 = 0.6, w3 = 0.3;\n        vector<char> seen(N, 0);\n        vector<int> frontier, nextf;\n        frontier.reserve(64);\n        nextf.reserve(128);\n\n        for (int s = 0; s < N; s++) {\n            fill(seen.begin(), seen.end(), 0);\n            seen[s] = 1;\n            double sum = 0.0;\n\n            frontier.clear();\n            for (int v : NB[s]) if (!seen[v]) { seen[v] = 1; frontier.push_back(v); sum += w1 * pval[v]; }\n\n            // depth 2\n            nextf.clear();\n            for (int v : frontier) {\n                for (int u : NB[v]) if (!seen[u]) { seen[u] = 1; nextf.push_back(u); sum += w2 * pval[u]; }\n            }\n            // depth 3\n            frontier.swap(nextf);\n            nextf.clear();\n            for (int v : frontier) {\n                for (int u : NB[v]) if (!seen[u]) { seen[u] = 1; nextf.push_back(u); sum += w3 * pval[u]; }\n            }\n\n            pot[s] = sum;\n        }\n    }\n\n    // RNG seed from input to diversify per test\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)si + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    seed ^= (uint64_t)sj + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    XorShift64 rng(seed);\n\n    auto dynamicDeg = [&](int cell, const vector<char>& tileUsed, int extraTile1 = -1, int extraTile2 = -1) -> int {\n        int cnt = 0;\n        for (int w : NB[cell]) {\n            int tt = tile[w];\n            if (tileUsed[tt]) continue;\n            if (tt == extraTile1 || tt == extraTile2) continue;\n            cnt++;\n        }\n        return cnt;\n    };\n\n    // Direction char mapping is global function\n\n    // Parameter presets (with minor jitter in runs)\n    vector<Params> presets;\n    presets.push_back(Params{1.00, 1.50, 0.050, 0.040, 0.30, 0.40, 1.5, 500});\n    presets.push_back(Params{1.20, 0.80, 0.080, 0.050, 0.20, 0.50, 1.2, 300});\n    presets.push_back(Params{1.00, 1.00, 0.060, 0.040, 0.25, 0.35, 1.5, 700});\n    presets.push_back(Params{1.00, 0.80, 0.030, 0.020, 0.20, 0.60, 1.0, 400});\n    presets.push_back(Params{1.00, 0.50, 0.100, 0.070, 0.15, 0.60, 1.2, 800});\n    presets.push_back(Params{1.40, 0.60, 0.040, 0.030, 0.20, 0.30, 1.5, 200});\n    presets.push_back(Params{1.00, 1.20, 0.070, 0.060, 0.25, 0.45, 1.0, 600});\n\n    auto build_path = [&](const Params& baseParam) -> PathResult {\n        // Slight random variation per run\n        Params P = baseParam;\n        auto jitter = [&](double v, double f=0.15) {\n            double m = 1.0 + (rng.next_double() * 2.0 - 1.0) * f;\n            return v * m;\n        };\n        P.wP       = jitter(P.wP,       0.10);\n        P.wDeg     = jitter(P.wDeg,     0.20);\n        P.wPot     = jitter(P.wPot,     0.25);\n        P.wTwinPot = jitter(P.wTwinPot, 0.25);\n        P.wTwinDeg = jitter(P.wTwinDeg, 0.20);\n        P.wLook    = jitter(P.wLook,    0.25);\n        P.noise    = jitter(P.noise,    0.40);\n        int avoidLimit = P.avoidDeadMinLen;\n\n        vector<char> tileUsed(M, 0);\n        int start = id_of(si, sj);\n        tileUsed[tile[start]] = 1;\n\n        long long score = pval[start];\n        int pos = start;\n        string moves;\n        moves.reserve(2000);\n\n        // We'll build until stuck\n        for (int step = 0; ; step++) {\n            // List candidate neighbors whose tile not yet visited\n            vector<int> cand;\n            cand.reserve(4);\n            for (int v : NB[pos]) {\n                int t = tile[v];\n                if (!tileUsed[t]) cand.push_back(v);\n            }\n            if (cand.empty()) break;\n\n            // Precompute degAfter for candidates and check for any non-dead options\n            vector<int> degAfter(cand.size(), 0);\n            bool hasNonDead = false;\n            for (size_t i = 0; i < cand.size(); i++) {\n                degAfter[i] = dynamicDeg(cand[i], tileUsed);\n                if (degAfter[i] > 0) hasNonDead = true;\n            }\n\n            double bestVal = -1e100;\n            int bestV = -1;\n\n            for (size_t idx = 0; idx < cand.size(); idx++) {\n                int v = cand[idx];\n                if (step < avoidLimit && hasNonDead && degAfter[idx] == 0) {\n                    // avoid entering a dead end early if alternatives exist\n                    continue;\n                }\n                double val = 0.0;\n\n                // immediate gain and local features\n                val += P.wP * pval[v];\n                val += P.wPot * pot[v];\n\n                // degree after stepping into v (available next moves)\n                val += P.wDeg * degAfter[idx];\n\n                // penalty for blocking via twin\n                int tv = twin[v];\n                if (tv != -1) {\n                    // twin degree and potential (approximate loss)\n                    int dTwin = dynamicDeg(tv, tileUsed);\n                    val -= P.wTwinDeg * dTwin;\n                    val -= P.wTwinPot * pot[tv];\n                }\n\n                // 2-ply lookahead: best child of v\n                if (degAfter[idx] > 0 && P.wLook > 1e-9) {\n                    double best2 = -1e100;\n                    for (int w : NB[v]) {\n                        int tw = tile[w];\n                        if (tileUsed[tw]) continue;\n                        // deg after moving to w, with v's tile considered newly visited\n                        int deg2 = dynamicDeg(w, tileUsed, tile[v]);\n                        double val2 = 0.0;\n                        val2 += P.wP * pval[w];\n                        val2 += P.wPot * pot[w];\n                        val2 += P.wDeg * deg2;\n                        int t2 = twin[w];\n                        if (t2 != -1) {\n                            int dtwin2 = dynamicDeg(t2, tileUsed, tile[v]);\n                            val2 -= P.wTwinDeg * dtwin2;\n                            val2 -= P.wTwinPot * pot[t2];\n                        }\n                        if (val2 > best2) best2 = val2;\n                    }\n                    if (best2 > -1e90) val += P.wLook * best2;\n                }\n\n                // noise\n                val += (rng.next_double() * 2.0 - 1.0) * P.noise;\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestV = v;\n                }\n            }\n\n            if (bestV == -1) {\n                // If all candidates were dead-ends and we avoided them, but we must choose one; pick the best ignoring avoid\n                bestVal = -1e100;\n                for (int v : cand) {\n                    double val = P.wP * pval[v] + P.wPot * pot[v] + (rng.next_double() * 2.0 - 1.0) * P.noise;\n                    if (val > bestVal) bestVal = val, bestV = v;\n                }\n                if (bestV == -1) break;\n            }\n\n            // Take the move\n            tileUsed[tile[bestV]] = 1;\n            score += pval[bestV];\n            moves.push_back(direction_char(pos, bestV));\n            pos = bestV;\n        }\n\n        PathResult res;\n        res.score = score;\n        res.moves = moves;\n        res.lengthTiles = (int)moves.size() + 1;\n        return res;\n    };\n\n    auto build_path_with_forced = [&](const Params& baseParam, const string& forced) -> PathResult {\n        // Same as build_path, but apply a forced prefix path before greedy\n        Params P = baseParam;\n        auto jitter = [&](double v, double f=0.15) {\n            double m = 1.0 + (rng.next_double() * 2.0 - 1.0) * f;\n            return v * m;\n        };\n        P.wP       = jitter(P.wP,       0.10);\n        P.wDeg     = jitter(P.wDeg,     0.20);\n        P.wPot     = jitter(P.wPot,     0.25);\n        P.wTwinPot = jitter(P.wTwinPot, 0.25);\n        P.wTwinDeg = jitter(P.wTwinDeg, 0.20);\n        P.wLook    = jitter(P.wLook,    0.25);\n        P.noise    = jitter(P.noise,    0.40);\n        int avoidLimit = P.avoidDeadMinLen;\n\n        vector<char> tileUsed(M, 0);\n        int pos = id_of(si, sj);\n        tileUsed[tile[pos]] = 1;\n        long long score = pval[pos];\n        string moves;\n        moves.reserve(2048);\n\n        // Apply forced prefix\n        for (char c : forced) {\n            int npos = move_to(pos, c);\n            if (npos < 0) break;\n            if (tile[pos] == tile[npos]) break;\n            int tt = tile[npos];\n            if (tileUsed[tt]) break;\n            tileUsed[tt] = 1;\n            score += pval[npos];\n            moves.push_back(c);\n            pos = npos;\n        }\n\n        // Continue greedy\n        for (int step = (int)moves.size(); ; step++) {\n            vector<int> cand;\n            for (int v : NB[pos]) {\n                int t = tile[v];\n                if (!tileUsed[t]) cand.push_back(v);\n            }\n            if (cand.empty()) break;\n\n            vector<int> degAfter(cand.size(), 0);\n            bool hasNonDead = false;\n            for (size_t i = 0; i < cand.size(); i++) {\n                degAfter[i] = dynamicDeg(cand[i], tileUsed);\n                if (degAfter[i] > 0) hasNonDead = true;\n            }\n\n            double bestVal = -1e100;\n            int bestV = -1;\n            for (size_t idx = 0; idx < cand.size(); idx++) {\n                int v = cand[idx];\n                if (step < avoidLimit && hasNonDead && degAfter[idx] == 0) continue;\n                double val = 0.0;\n                val += P.wP * pval[v];\n                val += P.wPot * pot[v];\n                val += P.wDeg * degAfter[idx];\n                int tv = twin[v];\n                if (tv != -1) {\n                    int dTwin = dynamicDeg(tv, tileUsed);\n                    val -= P.wTwinDeg * dTwin;\n                    val -= P.wTwinPot * pot[tv];\n                }\n                if (degAfter[idx] > 0 && P.wLook > 1e-9) {\n                    double best2 = -1e100;\n                    for (int w : NB[v]) {\n                        int tw = tile[w];\n                        if (tileUsed[tw]) continue;\n                        int deg2 = dynamicDeg(w, tileUsed, tile[v]);\n                        double val2 = 0.0;\n                        val2 += P.wP * pval[w];\n                        val2 += P.wPot * pot[w];\n                        val2 += P.wDeg * deg2;\n                        int t2 = twin[w];\n                        if (t2 != -1) {\n                            int dtwin2 = dynamicDeg(t2, tileUsed, tile[v]);\n                            val2 -= P.wTwinDeg * dtwin2;\n                            val2 -= P.wTwinPot * pot[t2];\n                        }\n                        if (val2 > best2) best2 = val2;\n                    }\n                    if (best2 > -1e90) val += P.wLook * best2;\n                }\n                val += (rng.next_double() * 2.0 - 1.0) * P.noise;\n                if (val > bestVal) bestVal = val, bestV = v;\n            }\n\n            if (bestV == -1) {\n                double bestFallback = -1e100;\n                for (int v : cand) {\n                    double val = P.wP * pval[v] + P.wPot * pot[v] + (rng.next_double() * 2.0 - 1.0) * P.noise;\n                    if (val > bestFallback) bestFallback = val, bestV = v;\n                }\n                if (bestV == -1) break;\n            }\n\n            tileUsed[tile[bestV]] = 1;\n            score += pval[bestV];\n            moves.push_back(direction_char(pos, bestV));\n            pos = bestV;\n        }\n\n        return PathResult{score, moves, (int)moves.size() + 1};\n    };\n\n    auto beam_prefix = [&](int maxDepth, int beamWidth, const Params& P) -> string {\n        struct BNode {\n            int pos;\n            long long g;\n            string path;\n            vector<char> used;\n            double pri;\n        };\n        int start = id_of(si, sj);\n        BNode root;\n        root.pos = start;\n        root.g = pval[start];\n        root.path.clear();\n        root.used.assign(M, 0);\n        root.used[tile[start]] = 1;\n        root.pri = root.g + 0.05 * pot[start] + 0.8 * (double)dynamicDeg(start, root.used);\n        vector<BNode> cur, nxt;\n        cur.reserve(beamWidth);\n        nxt.reserve(beamWidth * 4);\n        cur.push_back(std::move(root));\n\n        const double aPot = max(0.03, P.wPot * 0.8);\n        const double bDeg = max(0.5, P.wDeg * 0.5);\n        const double deadPenalty = 1e6;\n\n        for (int d = 0; d < maxDepth; d++) {\n            nxt.clear();\n            for (const auto& nd : cur) {\n                int u = nd.pos;\n                for (int v : NB[u]) {\n                    int tv = tile[v];\n                    if (nd.used[tv]) continue;\n                    BNode ch;\n                    ch.pos = v;\n                    ch.g = nd.g + pval[v];\n                    ch.path = nd.path;\n                    ch.path.push_back(direction_char(u, v));\n                    ch.used = nd.used;\n                    ch.used[tv] = 1;\n                    int degv = dynamicDeg(v, ch.used);\n                    ch.pri = ch.g + aPot * pot[v] + bDeg * degv;\n                    if (degv == 0 && d + 1 < maxDepth) ch.pri -= deadPenalty; // avoid early dead-ends\n                    nxt.push_back(std::move(ch));\n                }\n            }\n            if (nxt.empty()) break;\n            if ((int)nxt.size() > beamWidth) {\n                nth_element(nxt.begin(), nxt.begin() + beamWidth, nxt.end(),\n                            [](const BNode& a, const BNode& b){ return a.pri > b.pri; });\n                nxt.resize(beamWidth);\n            }\n            // sort to make next layer deterministic enough\n            sort(nxt.begin(), nxt.end(), [](const BNode& a, const BNode& b){ return a.pri > b.pri; });\n            cur.swap(nxt);\n        }\n\n        // pick best by g + tiny pot to break ties\n        if (cur.empty()) return string();\n        int besti = 0;\n        double bestScore = cur[0].g + 0.02 * pot[cur[0].pos];\n        for (int i = 1; i < (int)cur.size(); i++) {\n            double s = cur[i].g + 0.02 * pot[cur[i].pos];\n            if (s > bestScore) { bestScore = s; besti = i; }\n        }\n        return cur[besti].path;\n    };\n\n    // Run multiple randomized attempts within time limit\n    long long bestScore = -1;\n    string bestMoves;\n    int runs = 0;\n\n    // One beam-planned run first (prefix only), then normal restarts\n    {\n        Params P = presets[0]; // balanced for beam heuristic weights\n        string forced = beam_prefix(12, 24, P);\n        PathResult r = build_path_with_forced(presets[0], forced);\n        bestScore = r.score;\n        bestMoves = r.moves;\n        runs++;\n    }\n    {\n        Params P = presets[0];\n        PathResult r = build_path(P);\n        if (r.score > bestScore) { bestScore = r.score; bestMoves = r.moves; }\n        runs++;\n    }\n\n    while (true) {\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - time_start).count();\n        if (elapsed > TIME_LIMIT) break;\n\n        // Pick a preset randomly\n        Params baseP = presets[rng.randint(0, (int)presets.size()-1)];\n\n        // Mildly adapt avoidDeadMinLen with elapsed (later runs may allow more dead-ends to grab value)\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        if (progress > 0.6) {\n            baseP.avoidDeadMinLen = max(0, baseP.avoidDeadMinLen - (int)((progress - 0.6) * 800));\n        }\n\n        PathResult r = build_path(baseP);\n        if (r.score > bestScore) {\n            bestScore = r.score;\n            bestMoves = r.moves;\n        }\n        runs++;\n    }\n\n    // Output best path\n    cout << bestMoves << '\\n';\n\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int H = 30;\n    static constexpr int W = 30;\n    static constexpr int N = H * W;\n    // true generation range\n    static constexpr double WMIN = 1000.0;\n    static constexpr double WMAX = 9000.0;\n    // per-edge deviation clamp\n    static constexpr double DEV_CLAMP = 3000.0;\n\n    // base parameters: row-segment for horizontals, col-segment for verticals\n    // Hseg[i][s] for s=0..2: j in [0..9], [10..19], [20..28]\n    // Vseg[j][s] for s=0..2: i in [0..9], [10..19], [20..28]\n    array<array<double, 3>, H> Hseg;\n    array<array<double, 3>, W> Vseg;\n\n    // per-edge deviations\n    double dev_h[H][W-1];\n    double dev_v[H-1][W];\n\n    // query counter\n    int qid;\n\n    Solver() {\n        // initialize bases to center of allowed range\n        double init = 5000.0;\n        for (int i = 0; i < H; i++) Hseg[i] = {init, init, init};\n        for (int j = 0; j < W; j++) Vseg[j] = {init, init, init};\n        for (int i = 0; i < H; i++) for (int j = 0; j < W-1; j++) dev_h[i][j] = 0.0;\n        for (int i = 0; i < H-1; i++) for (int j = 0; j < W; j++) dev_v[i][j] = 0.0;\n        qid = 0;\n    }\n\n    static inline int segH_from_j(int j) {\n        if (j < 10) return 0;\n        if (j < 20) return 1;\n        return 2; // 20..28\n    }\n    static inline int segV_from_i(int i) {\n        if (i < 10) return 0;\n        if (i < 20) return 1;\n        return 2; // 20..28\n    }\n\n    inline double wh(int i, int j) const { // horizontal edge (i,j)-(i,j+1), j in [0..28]\n        int s = segH_from_j(j);\n        double x = Hseg[i][s] + dev_h[i][j];\n        if (x < WMIN) x = WMIN;\n        if (x > WMAX) x = WMAX;\n        return x;\n    }\n    inline double wv(int i, int j) const { // vertical edge (i,j)-(i+1,j), i in [0..28]\n        int s = segV_from_i(i);\n        double x = Vseg[j][s] + dev_v[i][j];\n        if (x < WMIN) x = WMIN;\n        if (x > WMAX) x = WMAX;\n        return x;\n    }\n\n    struct Node {\n        double d;\n        int i, j;\n        bool operator<(const Node& other) const {\n            return d > other.d; // for min-heap\n        }\n    };\n\n    // compute shortest path under current estimates using Dijkstra\n    string compute_path(int si, int sj, int ti, int tj, double &pred_len) {\n        static double dist[H][W];\n        static int pi[H][W], pj[H][W];\n        static char pdir[H][W];\n\n        for (int i = 0; i < H; i++) {\n            for (int j = 0; j < W; j++) {\n                dist[i][j] = numeric_limits<double>::infinity();\n                pi[i][j] = pj[i][j] = -1;\n                pdir[i][j] = 0;\n            }\n        }\n\n        priority_queue<Node> pq;\n        dist[si][sj] = 0.0;\n        pq.push({0.0, si, sj});\n\n        while (!pq.empty()) {\n            Node cur = pq.top(); pq.pop();\n            int i = cur.i, j = cur.j;\n            if (cur.d != dist[i][j]) continue;\n            if (i == ti && j == tj) break;\n\n            // neighbors: U,D,L,R\n            if (i > 0) {\n                double w = wv(i-1, j);\n                double nd = cur.d + w;\n                if (nd < dist[i-1][j]) {\n                    dist[i-1][j] = nd;\n                    pi[i-1][j] = i; pj[i-1][j] = j; pdir[i-1][j] = 'U';\n                    pq.push({nd, i-1, j});\n                }\n            }\n            if (i+1 < H) {\n                double w = wv(i, j);\n                double nd = cur.d + w;\n                if (nd < dist[i+1][j]) {\n                    dist[i+1][j] = nd;\n                    pi[i+1][j] = i; pj[i+1][j] = j; pdir[i+1][j] = 'D';\n                    pq.push({nd, i+1, j});\n                }\n            }\n            if (j > 0) {\n                double w = wh(i, j-1);\n                double nd = cur.d + w;\n                if (nd < dist[i][j-1]) {\n                    dist[i][j-1] = nd;\n                    pi[i][j-1] = i; pj[i][j-1] = j; pdir[i][j-1] = 'L';\n                    pq.push({nd, i, j-1});\n                }\n            }\n            if (j+1 < W) {\n                double w = wh(i, j);\n                double nd = cur.d + w;\n                if (nd < dist[i][j+1]) {\n                    dist[i][j+1] = nd;\n                    pi[i][j+1] = i; pj[i][j+1] = j; pdir[i][j+1] = 'R';\n                    pq.push({nd, i, j+1});\n                }\n            }\n        }\n\n        // reconstruct path\n        string rev;\n        int ci = ti, cj = tj;\n        while (!(ci == si && cj == sj)) {\n            char c = pdir[ci][cj];\n            rev.push_back(c);\n            int ni = pi[ci][cj], nj = pj[ci][cj];\n            ci = ni; cj = nj;\n        }\n        reverse(rev.begin(), rev.end());\n        pred_len = dist[ti][tj];\n        return rev;\n    }\n\n    struct EdgeUse {\n        bool isH; // true: horizontal; false: vertical\n        int i, j; // for horizontal: edge (i,j)-(i,j+1), j in [0..28]; for vertical: (i,j)-(i+1,j), i in [0..28]\n    };\n\n    // parse path into edges, compute predicted length and feature counts\n    void parse_path_and_features(int si, int sj, const string &path,\n                                 vector<EdgeUse> &edges,\n                                 vector<array<int,3>> &countHseg, // size H: counts per segment\n                                 vector<array<int,3>> &countVseg, // size W: counts per segment\n                                 double &S_pred) {\n        edges.clear();\n        countHseg.assign(H, {0,0,0});\n        countVseg.assign(W, {0,0,0});\n        int i = si, j = sj;\n        S_pred = 0.0;\n\n        for (char c : path) {\n            if (c == 'U') {\n                // use vertical edge (i-1,j)\n                int ei = i - 1, ej = j;\n                edges.push_back({false, ei, ej});\n                int s = segV_from_i(ei);\n                countVseg[ej][s] += 1;\n                double w = wv(ei, ej);\n                S_pred += w;\n                i -= 1;\n            } else if (c == 'D') {\n                int ei = i, ej = j;\n                edges.push_back({false, ei, ej});\n                int s = segV_from_i(ei);\n                countVseg[ej][s] += 1;\n                double w = wv(ei, ej);\n                S_pred += w;\n                i += 1;\n            } else if (c == 'L') {\n                int ei = i, ej = j - 1;\n                edges.push_back({true, ei, ej});\n                int s = segH_from_j(ej);\n                countHseg[ei][s] += 1;\n                double w = wh(ei, ej);\n                S_pred += w;\n                j -= 1;\n            } else if (c == 'R') {\n                int ei = i, ej = j;\n                edges.push_back({true, ei, ej});\n                int s = segH_from_j(ej);\n                countHseg[ei][s] += 1;\n                double w = wh(ei, ej);\n                S_pred += w;\n                j += 1;\n            }\n        }\n    }\n\n    // Update parameters using normalized LMS; devs receive larger share\n    void update_from_observation(int si, int sj, const string &path, long long y) {\n        vector<EdgeUse> edges;\n        vector<array<int,3>> countH; // per row segments\n        vector<array<int,3>> countV; // per col segments\n        double S_pred = 0.0;\n        parse_path_and_features(si, sj, path, edges, countH, countV, S_pred);\n\n        // Error\n        double delta = (double)y - S_pred;\n        int L = (int)edges.size();\n\n        // Compute norms for base features\n        double n_base = 0.0;\n        for (int i = 0; i < H; i++) {\n            for (int s = 0; s < 3; s++) {\n                int c = countH[i][s];\n                if (c) n_base += (double)c * (double)c;\n            }\n        }\n        for (int j = 0; j < W; j++) {\n            for (int s = 0; s < 3; s++) {\n                int c = countV[j][s];\n                if (c) n_base += (double)c * (double)c;\n            }\n        }\n        if (n_base < 1e-9) n_base = 0.0;\n\n        // Learning rates schedule\n        double t = (double)qid / 1000.0; // 0 ... ~1\n        // linearly decrease learning rates over time\n        double eta_dev = (1.0 - t) * 0.75 + t * 0.35;   // from 0.75 to 0.35\n        double eta_base = (1.0 - t) * 0.24 + t * 0.10;  // from 0.24 to 0.10\n        double lambda = 1.0;\n\n        // compute step sizes\n        double alpha_dev = 0.0;\n        if (L > 0) alpha_dev = eta_dev * delta / ( (double)L + lambda );\n\n        double alpha_base = 0.0;\n        if (n_base > 0.0) alpha_base = eta_base * delta / ( n_base + lambda );\n\n        // Update base parameters\n        if (alpha_base != 0.0) {\n            for (int i = 0; i < H; i++) {\n                for (int s = 0; s < 3; s++) {\n                    int c = countH[i][s];\n                    if (c) {\n                        Hseg[i][s] += alpha_base * c;\n                        if (Hseg[i][s] < WMIN) Hseg[i][s] = WMIN;\n                        else if (Hseg[i][s] > WMAX) Hseg[i][s] = WMAX;\n                    }\n                }\n            }\n            for (int j = 0; j < W; j++) {\n                for (int s = 0; s < 3; s++) {\n                    int c = countV[j][s];\n                    if (c) {\n                        Vseg[j][s] += alpha_base * c;\n                        if (Vseg[j][s] < WMIN) Vseg[j][s] = WMIN;\n                        else if (Vseg[j][s] > WMAX) Vseg[j][s] = WMAX;\n                    }\n                }\n            }\n        }\n\n        // Update per-edge deviations\n        if (alpha_dev != 0.0) {\n            for (const auto &e : edges) {\n                if (e.isH) {\n                    dev_h[e.i][e.j] += alpha_dev;\n                    if (dev_h[e.i][e.j] < -DEV_CLAMP) dev_h[e.i][e.j] = -DEV_CLAMP;\n                    else if (dev_h[e.i][e.j] > DEV_CLAMP) dev_h[e.i][e.j] = DEV_CLAMP;\n                } else {\n                    dev_v[e.i][e.j] += alpha_dev;\n                    if (dev_v[e.i][e.j] < -DEV_CLAMP) dev_v[e.i][e.j] = -DEV_CLAMP;\n                    else if (dev_v[e.i][e.j] > DEV_CLAMP) dev_v[e.i][e.j] = DEV_CLAMP;\n                }\n            }\n        }\n\n        // Small deviation decay towards 0 to regularize\n        double decay = (1.0 - t) * 0.0007 + t * 0.0018; // from ~7e-4 to ~1.8e-3\n        if (decay > 0.0) {\n            double mul = 1.0 - decay;\n            for (int i = 0; i < H; i++) {\n                for (int j = 0; j < W-1; j++) {\n                    dev_h[i][j] *= mul;\n                }\n            }\n            for (int i = 0; i < H-1; i++) {\n                for (int j = 0; j < W; j++) {\n                    dev_v[i][j] *= mul;\n                }\n            }\n        }\n\n        qid++;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int k = 0; k < 1000; k++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) {\n            return 0; // input ended unexpectedly\n        }\n\n        double pred_len = 0.0;\n        string path = solver.compute_path(si, sj, ti, tj, pred_len);\n\n        // Output path and flush\n        cout << path << '\\n' << flush;\n\n        long long observed_len;\n        if (!(cin >> observed_len)) {\n            return 0; // interactive judge ended\n        }\n\n        // Update model\n        solver.update_from_observation(si, sj, path, observed_len);\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\nusing namespace std;\n\n// Timer\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\n// Xorshift RNG\nstruct XorShift64 {\n    uint64_t x;\n    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    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n    inline double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n};\n\n// Problem constants\nstatic const int N_FIX = 20;\nstatic const int LMIN = 2;\nstatic const int LMAX = 12;\nstatic const int LCOUNT = LMAX - LMIN + 1;\n\nusing u64 = uint64_t;\nusing FlatMap = boost::unordered_flat_map<u64,int>;\n\nstatic inline u64 pack_key_str(const string& s) {\n    u64 k = 0;\n    for (char ch : s) k = (k << 3) | (u64)(ch - 'A');\n    return k;\n}\n\n// AC automaton for alphabet size 8\nstruct ACNode {\n    int next[8];\n    int fail;\n    vector<int> out; // list of uids (merged via fail)\n    ACNode() {\n        memset(next, -1, sizeof(next));\n        fail = 0;\n    }\n};\nstruct AhoCorasick {\n    vector<ACNode> nodes;\n    AhoCorasick() { nodes.reserve(4096); nodes.push_back(ACNode()); }\n\n    void add(const vector<uint8_t>& s, int uid) {\n        int v = 0;\n        for (uint8_t c : s) {\n            if (nodes[v].next[c] == -1) {\n                nodes[v].next[c] = (int)nodes.size();\n                nodes.push_back(ACNode());\n            }\n            v = nodes[v].next[c];\n        }\n        nodes[v].out.push_back(uid);\n    }\n\n    void build() {\n        queue<int> q;\n        for (int c = 0; c < 8; ++c) {\n            int u = nodes[0].next[c];\n            if (u != -1) {\n                nodes[u].fail = 0;\n                q.push(u);\n            } else {\n                nodes[0].next[c] = 0;\n            }\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int f = nodes[v].fail;\n            if (!nodes[f].out.empty()) {\n                auto &ov = nodes[v].out;\n                const auto &of = nodes[f].out;\n                ov.insert(ov.end(), of.begin(), of.end());\n            }\n            for (int c = 0; c < 8; ++c) {\n                int u = nodes[v].next[c];\n                if (u != -1) {\n                    nodes[u].fail = nodes[f].next[c];\n                    q.push(u);\n                } else {\n                    nodes[v].next[c] = nodes[f].next[c];\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    vector<string> inputS(M);\n    for (int i = 0; i < M; ++i) cin >> inputS[i];\n\n    Timer timer;\n    const double TIME_LIMIT = 2.95;\n\n    // Build unique strings (lenIdx, key) -> uid\n    struct UKeyHasher {\n        size_t operator()(const pair<int,u64>& p) const {\n            return std::hash<u64>()((p.second << 4) ^ (u64)p.first);\n        }\n    };\n    struct UKeyEq {\n        bool operator()(const pair<int,u64>& a, const pair<int,u64>& b) const {\n            return a.first == b.first && a.second == b.second;\n        }\n    };\n    boost::unordered_flat_map<pair<int,u64>, int, UKeyHasher, UKeyEq> uniqMap;\n    uniqMap.reserve(M*2);\n\n    struct Unique {\n        int len;\n        u64 key;\n        int weight;\n        vector<uint8_t> codes;\n    };\n    vector<Unique> uniqs; uniqs.reserve(M);\n\n    for (int i = 0; i < M; ++i) {\n        const string &s = inputS[i];\n        int L = (int)s.size();\n        int li = L - LMIN;\n        u64 key = pack_key_str(s);\n        auto pr = make_pair(li, key);\n        auto it = uniqMap.find(pr);\n        if (it == uniqMap.end()) {\n            int uid = (int)uniqs.size();\n            uniqMap.emplace(pr, uid);\n            Unique u;\n            u.len = L;\n            u.key = key;\n            u.weight = 1;\n            u.codes.resize(L);\n            for (int j = 0; j < L; ++j) u.codes[j] = (uint8_t)(s[j] - 'A');\n            uniqs.push_back(std::move(u));\n        } else {\n            uniqs[it->second].weight += 1;\n        }\n    }\n    int K = (int)uniqs.size();\n\n    // Per-length key->uid maps\n    array<FlatMap, LCOUNT> key2uid;\n    for (int li = 0; li < LCOUNT; ++li) key2uid[li].reserve(max(8, K / LCOUNT * 2));\n    for (int uid = 0; uid < K; ++uid) {\n        int li = uniqs[uid].len - LMIN;\n        key2uid[li].emplace(uniqs[uid].key, uid);\n    }\n\n    // Precompute bit shifts\n    int shiftAmt[LCOUNT][LMAX];\n    for (int li = 0; li < LCOUNT; ++li) {\n        int L = LMIN + li;\n        for (int t = 0; t < L; ++t) shiftAmt[li][t] = 3 * (L - 1 - t);\n    }\n\n    // Grid initialization: random\n    XorShift64 rng(123456789);\n    uint8_t g[N_FIX][N_FIX];\n    for (int i = 0; i < N_FIX; ++i) for (int j = 0; j < N_FIX; ++j) g[i][j] = (uint8_t)rng.next_int(0,7);\n\n    // windowsKey/Uid for lines: [li][line 0..39][start 0..19]\n    u64 windowsKey[LCOUNT][2*N_FIX][N_FIX];\n    int  windowsUid[LCOUNT][2*N_FIX][N_FIX];\n    for (int li = 0; li < LCOUNT; ++li)\n        for (int ln = 0; ln < 2*N_FIX; ++ln)\n            for (int s = 0; s < N_FIX; ++s) {\n                windowsKey[li][ln][s] = 0;\n                windowsUid[li][ln][s] = -1;\n            }\n\n    vector<int> occCount(K, 0);\n    vector<char> present(K, 0);\n    long long scoreC = 0;\n\n    // Initialize windows and occCount\n    for (int li = 0; li < LCOUNT; ++li) {\n        int L = LMIN + li;\n        for (int ln = 0; ln < 2*N_FIX; ++ln) {\n            for (int s = 0; s < N_FIX; ++s) {\n                u64 key = 0;\n                if (ln < N_FIX) {\n                    int i = ln;\n                    for (int r = 0; r < L; ++r) {\n                        int idx = s + r;\n                        if (idx >= N_FIX) idx -= N_FIX;\n                        key = (key << 3) | (u64)g[i][idx];\n                    }\n                } else {\n                    int j = ln - N_FIX;\n                    for (int r = 0; r < L; ++r) {\n                        int idx = s + r;\n                        if (idx >= N_FIX) idx -= N_FIX;\n                        key = (key << 3) | (u64)g[idx][j];\n                    }\n                }\n                windowsKey[li][ln][s] = key;\n                auto it = key2uid[li].find(key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    windowsUid[li][ln][s] = uid;\n                    if (occCount[uid] == 0) {\n                        scoreC += uniqs[uid].weight;\n                        present[uid] = 1;\n                    }\n                    occCount[uid] += 1;\n                } else {\n                    windowsUid[li][ln][s] = -1;\n                }\n            }\n        }\n    }\n\n    // Stamping structures for evaluating deltas\n    vector<int> deltaOcc(K, 0);\n    vector<int> lastStamp(K, -1);\n    vector<int> touched; touched.reserve(4096);\n    int stamp = 0;\n\n    // Aggregate masks for block paste row/col evaluation\n    static u64 aggMask[LCOUNT][N_FIX];\n    static int maskStamp[LCOUNT][N_FIX];\n    int aggStamp = 1; // start from 1 so 0 means \"never\"\n\n    // Common accumulator for a single change on given line at pos, with ocxor\n    auto accumulate_single_change = [&](int line, int pos, int ocxor_) {\n        for (int li = 0; li < LCOUNT; ++li) {\n            int Lw = LMIN + li;\n            for (int t = 0; t < Lw; ++t) {\n                int s = pos - t;\n                if (s < 0) s += N_FIX;\n                int old_uid = windowsUid[li][line][s];\n                if (old_uid >= 0) {\n                    if (lastStamp[old_uid] != stamp) {\n                        lastStamp[old_uid] = stamp;\n                        deltaOcc[old_uid] = 0;\n                        touched.push_back(old_uid);\n                    }\n                    deltaOcc[old_uid] -= 1;\n                }\n                u64 old_key = windowsKey[li][line][s];\n                u64 new_key = old_key ^ ((u64)ocxor_ << shiftAmt[li][t]);\n                auto it = key2uid[li].find(new_key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    if (lastStamp[uid] != stamp) {\n                        lastStamp[uid] = stamp;\n                        deltaOcc[uid] = 0;\n                        touched.push_back(uid);\n                    }\n                    deltaOcc[uid] += 1;\n                }\n            }\n        }\n    };\n\n    // Update windows and counts for a single change\n    auto update_line_single = [&](int line, int pos, int ocxor_) {\n        for (int li = 0; li < LCOUNT; ++li) {\n            int Lw = LMIN + li;\n            for (int t = 0; t < Lw; ++t) {\n                int s = pos - t;\n                if (s < 0) s += N_FIX;\n                int old_uid = windowsUid[li][line][s];\n                u64 old_key = windowsKey[li][line][s];\n                u64 new_key = old_key ^ ((u64)ocxor_ << shiftAmt[li][t]);\n                auto it = key2uid[li].find(new_key);\n                int new_uid = (it == key2uid[li].end() ? -1 : it->second);\n\n                if (old_uid >= 0) {\n                    occCount[old_uid] -= 1;\n                    if (occCount[old_uid] == 0) {\n                        scoreC -= uniqs[old_uid].weight;\n                        present[old_uid] = 0;\n                    }\n                }\n                if (new_uid >= 0) {\n                    if (occCount[new_uid] == 0) {\n                        scoreC += uniqs[new_uid].weight;\n                        present[new_uid] = 1;\n                    }\n                    occCount[new_uid] += 1;\n                }\n\n                windowsKey[li][line][s] = new_key;\n                windowsUid[li][line][s] = new_uid;\n            }\n        }\n    };\n\n    auto eval_delta_for_letter = [&](int i, int j, uint8_t newCode) -> long long {\n        uint8_t oldCode = g[i][j];\n        if (newCode == oldCode) return 0;\n        int ocxor = (int)(oldCode ^ newCode);\n\n        ++stamp;\n        touched.clear();\n\n        // row and column\n        accumulate_single_change(i, j, ocxor);\n        accumulate_single_change(N_FIX + j, i, ocxor);\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto apply_letter = [&](int i, int j, uint8_t newCode) {\n        uint8_t oldCode = g[i][j];\n        if (newCode == oldCode) return;\n        int ocxor = (int)(oldCode ^ newCode);\n\n        // update row windows\n        update_line_single(i, j, ocxor);\n        // update column windows\n        update_line_single(N_FIX + j, i, ocxor);\n\n        // update grid\n        g[i][j] = newCode;\n    };\n\n    // Aggregate evaluation for multiple changes on the same line\n    auto eval_delta_paste_line_aggregate = [&](int line, const vector<pair<int,int>>& posXor) {\n        ++aggStamp;\n        for (auto &px : posXor) {\n            int pos = px.first;\n            int ocxor = px.second;\n            if (ocxor == 0) continue;\n            for (int li = 0; li < LCOUNT; ++li) {\n                int Lw = LMIN + li;\n                for (int t = 0; t < Lw; ++t) {\n                    int s = pos - t;\n                    if (s < 0) s += N_FIX;\n                    if (maskStamp[li][s] != aggStamp) {\n                        maskStamp[li][s] = aggStamp;\n                        aggMask[li][s] = 0;\n                    }\n                    aggMask[li][s] ^= ((u64)ocxor << shiftAmt[li][t]);\n                }\n            }\n        }\n        for (int li = 0; li < LCOUNT; ++li) {\n            for (int s = 0; s < N_FIX; ++s) {\n                if (maskStamp[li][s] != aggStamp) continue;\n                u64 m = aggMask[li][s];\n                if (m == 0) continue;\n                int old_uid = windowsUid[li][line][s];\n                if (old_uid >= 0) {\n                    if (lastStamp[old_uid] != stamp) {\n                        lastStamp[old_uid] = stamp;\n                        deltaOcc[old_uid] = 0;\n                        touched.push_back(old_uid);\n                    }\n                    deltaOcc[old_uid] -= 1;\n                }\n                u64 old_key = windowsKey[li][line][s];\n                u64 new_key = old_key ^ m;\n                auto it = key2uid[li].find(new_key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    if (lastStamp[uid] != stamp) {\n                        lastStamp[uid] = stamp;\n                        deltaOcc[uid] = 0;\n                        touched.push_back(uid);\n                    }\n                    deltaOcc[uid] += 1;\n                }\n            }\n        }\n    };\n\n    // Exact evaluation for pasting an entire row/column (codes.size() == 20)\n    auto eval_delta_paste_row_full = [&](int i, const vector<uint8_t>& codes) -> long long {\n        vector<pair<int,int>> rowPosXor; rowPosXor.reserve(N_FIX);\n        vector<tuple<int,int,int>> colTriples; colTriples.reserve(N_FIX);\n        for (int j = 0; j < N_FIX; ++j) {\n            int ocxor = g[i][j] ^ codes[j];\n            if (ocxor == 0) continue;\n            rowPosXor.emplace_back(j, ocxor);\n            colTriples.emplace_back(N_FIX + j, i, ocxor);\n        }\n        if (rowPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        // row aggregate\n        eval_delta_paste_line_aggregate(i, rowPosXor);\n\n        // columns single\n        for (auto &tp : colTriples) {\n            int line = get<0>(tp), pos = get<1>(tp), ocxor = get<2>(tp);\n            accumulate_single_change(line, pos, ocxor);\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto eval_delta_paste_col_full = [&](int j, const vector<uint8_t>& codes) -> long long {\n        vector<pair<int,int>> colPosXor; colPosXor.reserve(N_FIX);\n        vector<tuple<int,int,int>> rowTriples; rowTriples.reserve(N_FIX);\n        for (int i = 0; i < N_FIX; ++i) {\n            int ocxor = g[i][j] ^ codes[i];\n            if (ocxor == 0) continue;\n            colPosXor.emplace_back(i, ocxor);\n            rowTriples.emplace_back(i, j, ocxor);\n        }\n        if (colPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        // column aggregate\n        eval_delta_paste_line_aggregate(N_FIX + j, colPosXor);\n\n        // rows single\n        for (auto &tp : rowTriples) {\n            int line = get<0>(tp), pos = get<1>(tp), ocxor = get<2>(tp);\n            accumulate_single_change(line, pos, ocxor);\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto eval_delta_paste_row_seg = [&](int i, int start, const vector<uint8_t>& codes) -> long long {\n        vector<pair<int,int>> rowPosXor; rowPosXor.reserve((int)codes.size());\n        vector<tuple<int,int,int>> colTriples; colTriples.reserve((int)codes.size());\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int j = start + p; if (j >= N_FIX) j -= N_FIX;\n            int ocxor = g[i][j] ^ codes[p];\n            if (ocxor == 0) continue;\n            rowPosXor.emplace_back(j, ocxor);\n            colTriples.emplace_back(N_FIX + j, i, ocxor);\n        }\n        if (rowPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        eval_delta_paste_line_aggregate(i, rowPosXor);\n        for (auto &tp : colTriples) {\n            int line = get<0>(tp), pos = get<1>(tp), ocxor = get<2>(tp);\n            accumulate_single_change(line, pos, ocxor);\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto eval_delta_paste_col_seg = [&](int j, int start, const vector<uint8_t>& codes) -> long long {\n        vector<pair<int,int>> colPosXor; colPosXor.reserve((int)codes.size());\n        vector<tuple<int,int,int>> rowTriples; rowTriples.reserve((int)codes.size());\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int i = start + p; if (i >= N_FIX) i -= N_FIX;\n            int ocxor = g[i][j] ^ codes[p];\n            if (ocxor == 0) continue;\n            colPosXor.emplace_back(i, ocxor);\n            rowTriples.emplace_back(i, j, ocxor);\n        }\n        if (colPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        eval_delta_paste_line_aggregate(N_FIX + j, colPosXor);\n        for (auto &tp : rowTriples) {\n            int line = get<0>(tp), pos = get<1>(tp), ocxor = get<2>(tp);\n            accumulate_single_change(line, pos, ocxor);\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto apply_paste_row_full = [&](int i, const vector<uint8_t>& codes) {\n        for (int j = 0; j < N_FIX; ++j) {\n            if (g[i][j] != codes[j]) apply_letter(i, j, codes[j]);\n        }\n    };\n    auto apply_paste_col_full = [&](int j, const vector<uint8_t>& codes) {\n        for (int i = 0; i < N_FIX; ++i) {\n            if (g[i][j] != codes[i]) apply_letter(i, j, codes[i]);\n        }\n    };\n    auto apply_paste_row_seg = [&](int i, int start, const vector<uint8_t>& codes) {\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int j = start + p; if (j >= N_FIX) j -= N_FIX;\n            if (g[i][j] != codes[p]) apply_letter(i, j, codes[p]);\n        }\n    };\n    auto apply_paste_col_seg = [&](int j, int start, const vector<uint8_t>& codes) {\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int i = start + p; if (i >= N_FIX) i -= N_FIX;\n            if (g[i][j] != codes[p]) apply_letter(i, j, codes[p]);\n        }\n    };\n\n    // Rotation evaluation and application\n    auto eval_delta_rotate_row = [&](int i, int sft) -> long long {\n        if (sft % N_FIX == 0) return 0;\n        ++stamp;\n        touched.clear();\n        for (int j = 0; j < N_FIX; ++j) {\n            int j2 = j - sft; if (j2 < 0) j2 += N_FIX;\n            int ocxor = g[i][j] ^ g[i][j2];\n            if (ocxor) {\n                accumulate_single_change(N_FIX + j, i, ocxor);\n            }\n        }\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n    auto apply_rotate_row = [&](int i, int sft) {\n        if (sft % N_FIX == 0) return;\n        uint8_t newRow[N_FIX];\n        for (int j = 0; j < N_FIX; ++j) {\n            int j2 = j - sft; if (j2 < 0) j2 += N_FIX;\n            newRow[j] = g[i][j2];\n        }\n        for (int j = 0; j < N_FIX; ++j) {\n            uint8_t oldC = g[i][j];\n            uint8_t newC = newRow[j];\n            if (oldC != newC) {\n                int ocxor = (int)(oldC ^ newC);\n                update_line_single(N_FIX + j, i, ocxor);\n                g[i][j] = newC;\n            }\n        }\n        // rotate row windows arrays without changing occCount\n        for (int li = 0; li < LCOUNT; ++li) {\n            u64 tmpK[N_FIX];\n            int tmpU[N_FIX];\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                int from = s0 - sft; if (from < 0) from += N_FIX;\n                tmpK[s0] = windowsKey[li][i][from];\n                tmpU[s0] = windowsUid[li][i][from];\n            }\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                windowsKey[li][i][s0] = tmpK[s0];\n                windowsUid[li][i][s0] = tmpU[s0];\n            }\n        }\n    };\n\n    auto eval_delta_rotate_col = [&](int j, int sft) -> long long {\n        if (sft % N_FIX == 0) return 0;\n        ++stamp;\n        touched.clear();\n        for (int i = 0; i < N_FIX; ++i) {\n            int i2 = i - sft; if (i2 < 0) i2 += N_FIX;\n            int ocxor = g[i][j] ^ g[i2][j];\n            if (ocxor) {\n                accumulate_single_change(i, j, ocxor);\n            }\n        }\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n    auto apply_rotate_col = [&](int j, int sft) {\n        if (sft % N_FIX == 0) return;\n        uint8_t newCol[N_FIX];\n        for (int i = 0; i < N_FIX; ++i) {\n            int i2 = i - sft; if (i2 < 0) i2 += N_FIX;\n            newCol[i] = g[i2][j];\n        }\n        for (int i = 0; i < N_FIX; ++i) {\n            uint8_t oldC = g[i][j];\n            uint8_t newC = newCol[i];\n            if (oldC != newC) {\n                int ocxor = (int)(oldC ^ newC);\n                update_line_single(i, j, ocxor);\n                g[i][j] = newC;\n            }\n        }\n        // rotate column windows arrays without changing occCount\n        for (int li = 0; li < LCOUNT; ++li) {\n            u64 tmpK[N_FIX];\n            int tmpU[N_FIX];\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                int from = s0 - sft; if (from < 0) from += N_FIX;\n                tmpK[s0] = windowsKey[li][N_FIX + j][from];\n                tmpU[s0] = windowsUid[li][N_FIX + j][from];\n            }\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                windowsKey[li][N_FIX + j][s0] = tmpK[s0];\n                windowsUid[li][N_FIX + j][s0] = tmpU[s0];\n            }\n        }\n    };\n\n    long long bestScore = scoreC;\n    uint8_t bestGrid[N_FIX][N_FIX];\n    memcpy(bestGrid, g, sizeof(g));\n\n    // Build AC automaton with all unique strings\n    AhoCorasick ac;\n    for (int uid = 0; uid < K; ++uid) ac.add(uniqs[uid].codes, uid);\n    ac.build();\n    int S = (int)ac.nodes.size();\n\n    // Buffers for DP per line\n    vector<int> outW(S, 0), dp(S, 0), ndp(S, 0);\n    vector<uint8_t> choice((size_t)N_FIX * S);\n\n    auto ac_build_best_line = [&](vector<uint8_t>& out) {\n        for (int v = 0; v < S; ++v) {\n            int sum = 0;\n            const auto &ov = ac.nodes[v].out;\n            for (int uid : ov) if (!present[uid]) sum += uniqs[uid].weight;\n            outW[v] = sum;\n        }\n        fill(dp.begin(), dp.end(), 0);\n        for (int pos = N_FIX - 1; pos >= 0; --pos) {\n            for (int v = 0; v < S; ++v) {\n                int bestVal = INT_MIN;\n                uint8_t bestC = 0;\n                for (int c = 0; c < 8; ++c) {\n                    int u = ac.nodes[v].next[c];\n                    int val = outW[u] + dp[u];\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestC = (uint8_t)c;\n                    }\n                }\n                ndp[v] = bestVal;\n                choice[(size_t)pos * S + v] = bestC;\n            }\n            dp.swap(ndp);\n        }\n        out.resize(N_FIX);\n        int v = 0;\n        for (int pos = 0; pos < N_FIX; ++pos) {\n            uint8_t c = choice[(size_t)pos * S + v];\n            out[pos] = c;\n            v = ac.nodes[v].next[c];\n        }\n    };\n\n    // Precompute weight-sorted uid list for block-paste targeting\n    vector<int> weightSorted(K);\n    iota(weightSorted.begin(), weightSorted.end(), 0);\n    sort(weightSorted.begin(), weightSorted.end(), [&](int a, int b){\n        if (uniqs[a].weight != uniqs[b].weight) return uniqs[a].weight > uniqs[b].weight;\n        return uniqs[a].len > uniqs[b].len;\n    });\n\n    auto pick_absent_uid = [&]() -> int {\n        int topK = min(K, 512);\n        for (int t = 0; t < 20; ++t) {\n            int idx = rng.next_int(0, topK-1);\n            int uid = weightSorted[idx];\n            if (!present[uid]) return uid;\n        }\n        for (int idx = 0; idx < K; ++idx) {\n            int uid = weightSorted[idx];\n            if (!present[uid]) return uid;\n        }\n        return rng.next_int(0, K-1);\n    };\n\n    // Stage 0: AC-guided line synthesis with best rotation\n    double T_AC = min(0.80, TIME_LIMIT * 0.28);\n    vector<int> lines(2*N_FIX);\n    iota(lines.begin(), lines.end(), 0);\n    while (timer.elapsed() < T_AC) {\n        shuffle(lines.begin(), lines.end(), std::mt19937(1234567 ^ (unsigned)rng.next_u32()));\n        bool anyApplied = false;\n        bool needRebuild = true;\n        vector<uint8_t> baseLine;\n        for (int idx = 0; idx < (int)lines.size(); ++idx) {\n            if (timer.elapsed() >= T_AC) break;\n            int ln = lines[idx];\n            if (needRebuild) {\n                ac_build_best_line(baseLine);\n                needRebuild = false;\n            }\n            // try all rotations for this line\n            long long bestDelta = LLONG_MIN;\n            int bestRot = 0;\n            vector<uint8_t> rotated(20);\n            if (ln < N_FIX) {\n                // row\n                for (int rot = 0; rot < N_FIX; ++rot) {\n                    for (int j = 0; j < N_FIX; ++j) rotated[j] = baseLine[(j + rot) % N_FIX];\n                    long long d = eval_delta_paste_row_full(ln, rotated);\n                    if (d > bestDelta) {\n                        bestDelta = d;\n                        bestRot = rot;\n                    }\n                }\n                if (bestDelta > 0) {\n                    for (int j = 0; j < N_FIX; ++j) rotated[j] = baseLine[(j + bestRot) % N_FIX];\n                    apply_paste_row_full(ln, rotated);\n                    anyApplied = true;\n                    needRebuild = true;\n                    if (scoreC > bestScore) {\n                        bestScore = scoreC;\n                        memcpy(bestGrid, g, sizeof(g));\n                    }\n                }\n            } else {\n                int j = ln - N_FIX;\n                for (int rot = 0; rot < N_FIX; ++rot) {\n                    for (int i = 0; i < N_FIX; ++i) rotated[i] = baseLine[(i + rot) % N_FIX];\n                    long long d = eval_delta_paste_col_full(j, rotated);\n                    if (d > bestDelta) {\n                        bestDelta = d;\n                        bestRot = rot;\n                    }\n                }\n                if (bestDelta > 0) {\n                    for (int i = 0; i < N_FIX; ++i) rotated[i] = baseLine[(i + bestRot) % N_FIX];\n                    apply_paste_col_full(j, rotated);\n                    anyApplied = true;\n                    needRebuild = true;\n                    if (scoreC > bestScore) {\n                        bestScore = scoreC;\n                        memcpy(bestGrid, g, sizeof(g));\n                    }\n                }\n            }\n        }\n        if (!anyApplied) break;\n    }\n\n    // Stage 0.5: Rotation pass (rows then columns)\n    auto rotation_pass = [&]() {\n        for (int i = 0; i < N_FIX; ++i) {\n            if (timer.elapsed() > TIME_LIMIT * 0.88) break;\n            long long bestD = 0;\n            int bestSft = 0;\n            for (int sft = 1; sft < N_FIX; ++sft) {\n                long long d = eval_delta_rotate_row(i, sft);\n                if (d > bestD) { bestD = d; bestSft = sft; }\n            }\n            if (bestD > 0) {\n                apply_rotate_row(i, bestSft);\n                if (scoreC > bestScore) {\n                    bestScore = scoreC;\n                    memcpy(bestGrid, g, sizeof(g));\n                }\n            }\n        }\n        for (int j = 0; j < N_FIX; ++j) {\n            if (timer.elapsed() > TIME_LIMIT * 0.90) break;\n            long long bestD = 0;\n            int bestSft = 0;\n            for (int sft = 1; sft < N_FIX; ++sft) {\n                long long d = eval_delta_rotate_col(j, sft);\n                if (d > bestD) { bestD = d; bestSft = sft; }\n            }\n            if (bestD > 0) {\n                apply_rotate_col(j, bestSft);\n                if (scoreC > bestScore) {\n                    bestScore = scoreC;\n                    memcpy(bestGrid, g, sizeof(g));\n                }\n            }\n        }\n    };\n    rotation_pass();\n\n    // Guided candidate selection for block paste\n    struct Cand {\n        bool isRow;\n        int line;\n        int start;\n        int mism;\n    };\n\n    auto guided_candidates_for_uid = [&](int uid, vector<Cand>& out, int KTOP) {\n        out.clear();\n        const auto &codes = uniqs[uid].codes;\n        int L = (int)codes.size();\n        // rows\n        for (int i = 0; i < N_FIX; ++i) {\n            for (int s = 0; s < N_FIX; ++s) {\n                int mism = 0;\n                for (int p = 0; p < L; ++p) {\n                    int j = s + p; if (j >= N_FIX) j -= N_FIX;\n                    mism += (g[i][j] != codes[p]);\n                }\n                if ((int)out.size() < KTOP) {\n                    out.push_back({true, i, s, mism});\n                    if ((int)out.size() == KTOP) {\n                        // keep as partial sorted by mism descending\n                        nth_element(out.begin(), out.begin() + KTOP/2, out.end(), [](const Cand& a, const Cand& b){ return a.mism > b.mism; });\n                        sort(out.begin(), out.end(), [](const Cand& a, const Cand& b){ return a.mism > b.mism; });\n                    }\n                } else if (mism < out.front().mism) {\n                    out.front() = {true, i, s, mism};\n                    // sink down the new worst to front\n                    int idx = 0;\n                    while (idx+1 < KTOP && out[idx].mism < out[idx+1].mism) {\n                        swap(out[idx], out[idx+1]);\n                        ++idx;\n                    }\n                }\n            }\n        }\n        // columns\n        for (int j = 0; j < N_FIX; ++j) {\n            for (int s = 0; s < N_FIX; ++s) {\n                int mism = 0;\n                for (int p = 0; p < L; ++p) {\n                    int i = s + p; if (i >= N_FIX) i -= N_FIX;\n                    mism += (g[i][j] != codes[p]);\n                }\n                if ((int)out.size() < KTOP) {\n                    out.push_back({false, j, s, mism});\n                    if ((int)out.size() == KTOP) {\n                        nth_element(out.begin(), out.begin() + KTOP/2, out.end(), [](const Cand& a, const Cand& b){ return a.mism > b.mism; });\n                        sort(out.begin(), out.end(), [](const Cand& a, const Cand& b){ return a.mism > b.mism; });\n                    }\n                } else if (mism < out.front().mism) {\n                    out.front() = {false, j, s, mism};\n                    int idx = 0;\n                    while (idx+1 < KTOP && out[idx].mism < out[idx+1].mism) {\n                        swap(out[idx], out[idx+1]);\n                        ++idx;\n                    }\n                }\n            }\n        }\n        // finally sort ascending mism (best first)\n        sort(out.begin(), out.end(), [](const Cand& a, const Cand& b){ return a.mism < b.mism; });\n    };\n\n    // Stage 1: Block paste hill-climbing (focus absent), mix guided and random\n    double T_BLOCK = TIME_LIMIT * 0.82;\n    int iter = 0;\n    vector<Cand> cands; cands.reserve(16);\n    while (timer.elapsed() < T_BLOCK) {\n        ++iter;\n        bool guided = (iter % 3 == 0); // every 3rd iteration guided\n        int uid = pick_absent_uid();\n        const auto &codes = uniqs[uid].codes;\n\n        long long bestDelta = LLONG_MIN;\n        bool bestIsRow = true;\n        int bestLine = 0, bestStart = 0;\n\n        if (guided) {\n            guided_candidates_for_uid(uid, cands, 8);\n            for (const auto& cd : cands) {\n                long long d = cd.isRow ? eval_delta_paste_row_seg(cd.line, cd.start, codes)\n                                       : eval_delta_paste_col_seg(cd.line, cd.start, codes);\n                if (d > bestDelta) {\n                    bestDelta = d;\n                    bestIsRow = cd.isRow;\n                    bestLine = cd.line;\n                    bestStart = cd.start;\n                }\n            }\n        } else {\n            int tries = 14;\n            for (int t = 0; t < tries; ++t) {\n                bool isRow = (rng.next_u32() & 1) == 0;\n                int line = rng.next_int(0, N_FIX-1);\n                int start = rng.next_int(0, N_FIX-1);\n                long long d = isRow ? eval_delta_paste_row_seg(line, start, codes)\n                                    : eval_delta_paste_col_seg(line, start, codes);\n                if (d > bestDelta) {\n                    bestDelta = d;\n                    bestIsRow = isRow;\n                    bestLine = line;\n                    bestStart = start;\n                }\n            }\n        }\n\n        if (bestDelta > 0) {\n            if (bestIsRow) apply_paste_row_seg(bestLine, bestStart, codes);\n            else apply_paste_col_seg(bestLine, bestStart, codes);\n            if (scoreC > bestScore) {\n                bestScore = scoreC;\n                memcpy(bestGrid, g, sizeof(g));\n            }\n        }\n    }\n\n    // Optional second rotation pass\n    if (timer.elapsed() < TIME_LIMIT * 0.9) rotation_pass();\n\n    // Stage 2: SA fine-tuning with single-letter moves\n    double T0 = 1.0, T1 = 0.01;\n    while (timer.elapsed() < TIME_LIMIT) {\n        int i = rng.next_int(0, N_FIX-1);\n        int j = rng.next_int(0, N_FIX-1);\n        uint8_t oldCode = g[i][j];\n\n        long long bestDelta = LLONG_MIN;\n        uint8_t bestCode = oldCode;\n        for (uint8_t nc = 0; nc < 8; ++nc) {\n            if (nc == oldCode) continue;\n            long long delta = eval_delta_for_letter(i, j, nc);\n            if (delta > bestDelta) {\n                bestDelta = delta;\n                bestCode = nc;\n            }\n        }\n\n        double t = timer.elapsed() / TIME_LIMIT;\n        if (t > 1.0) break;\n        double T = T0 + (T1 - T0) * t;\n\n        bool accept = false;\n        if (bestDelta >= 0) accept = true;\n        else {\n            double prob = exp((double)bestDelta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n        if (accept && bestCode != oldCode) {\n            apply_letter(i, j, bestCode);\n            if (scoreC > bestScore) {\n                bestScore = scoreC;\n                memcpy(bestGrid, g, sizeof(g));\n            }\n        }\n    }\n\n    // Output best grid\n    for (int i = 0; i < N_FIX; ++i) {\n        string out; out.resize(N_FIX);\n        for (int j = 0; j < N_FIX; ++j) out[j] = char('A' + bestGrid[i][j]);\n        cout << out << '\\n';\n    }\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist;\n    vector<int> matchL, matchR;\n\n    HopcroftKarp(int nL_, int nR_) : nL(nL_), nR(nR_), g(nL_), dist(nL_), matchL(nL_, -1), matchR(nR_, -1) {}\n\n    void add_edge(int u, int v) { g[u].push_back(v); }\n\n    bool bfs() {\n        queue<int> q;\n        for (int i = 0; i < nL; ++i) {\n            if (matchL[i] == -1) {\n                dist[i] = 0;\n                q.push(i);\n            } else dist[i] = -1;\n        }\n        bool found = false;\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    bool dfs(int u) {\n        for (int v : g[u]) {\n            int u2 = matchR[v];\n            if (u2 == -1 || (dist[u2] == dist[u] + 1 && dfs(u2))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int max_matching() {\n        int res = 0;\n        while (bfs()) {\n            for (int i = 0; i < nL; ++i) {\n                if (matchL[i] == -1) if (dfs(i)) ++res;\n            }\n        }\n        return res;\n    }\n\n    pair<vector<char>, vector<char>> min_vertex_cover() {\n        // Compute Z: vertices reachable from unmatched left vertices via alternating paths\n        vector<char> visL(nL, 0), visR(nR, 0);\n        queue<int> q;\n        for (int u = 0; u < nL; ++u) if (matchL[u] == -1) {\n            visL[u] = 1;\n            q.push(u);\n        }\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                if (matchL[u] != v) { // unmatched edge\n                    if (!visR[v]) {\n                        visR[v] = 1;\n                        int u2 = matchR[v];\n                        if (u2 != -1 && !visL[u2]) {\n                            visL[u2] = 1;\n                            q.push(u2);\n                        }\n                    }\n                }\n            }\n        }\n        vector<char> coverL(nL, 0), coverR(nR, 0);\n        for (int u = 0; u < nL; ++u) if (!visL[u]) coverL[u] = 1;\n        for (int v = 0; v < nR; ++v) if (visR[v]) coverR[v] = 1;\n        return {coverL, coverR};\n    }\n};\n\nstruct NodePQ {\n    int d, u;\n    bool operator<(const NodePQ& o) const { return d > o.d; }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, si, sj;\n    if (!(cin >> N >> si >> sj)) return 0;\n    vector<string> c(N);\n    for (int i = 0; i < N; ++i) cin >> c[i];\n\n    const int H = N, W = N;\n    auto id = [&](int i, int j){ return i*W + j; };\n    const int M = H*W;\n\n    vector<char> isRoad(M, 0);\n    vector<int> w(M, -1);\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        if (c[i][j] != '#') {\n            int u = id(i,j);\n            isRoad[u] = 1;\n            w[u] = c[i][j] - '0';\n        }\n    }\n\n    // Build row segments\n    vector<int> rowSegId(M, -1), colSegId(M, -1);\n    vector<int> rowPos(M, -1), colPos(M, -1);\n    vector<vector<int>> rowSegCells;\n    for (int i = 0; i < H; ++i) {\n        int j = 0;\n        while (j < W) {\n            if (isRoad[id(i,j)] && (j == 0 || !isRoad[id(i, j-1)])) {\n                int j2 = j;\n                int segId = (int)rowSegCells.size();\n                rowSegCells.emplace_back();\n                while (j2 < W && isRoad[id(i,j2)]) {\n                    int u = id(i,j2);\n                    rowSegId[u] = segId;\n                    rowPos[u] = (int)rowSegCells.back().size();\n                    rowSegCells.back().push_back(u);\n                    ++j2;\n                }\n                j = j2;\n            } else ++j;\n        }\n    }\n    // Build column segments\n    vector<vector<int>> colSegCells;\n    for (int j = 0; j < W; ++j) {\n        int i = 0;\n        while (i < H) {\n            if (isRoad[id(i,j)] && (i == 0 || !isRoad[id(i-1, j)])) {\n                int i2 = i;\n                int segId = (int)colSegCells.size();\n                colSegCells.emplace_back();\n                while (i2 < H && isRoad[id(i2,j)]) {\n                    int u = id(i2,j);\n                    colSegId[u] = segId;\n                    colPos[u] = (int)colSegCells.back().size();\n                    colSegCells.back().push_back(u);\n                    ++i2;\n                }\n                i = i2;\n            } else ++i;\n        }\n    }\n    int nR = (int)rowSegCells.size();\n    int nC = (int)colSegCells.size();\n\n    // Build bipartite graph: row segs -> col segs via edges for each road cell\n    HopcroftKarp hk(nR, nC);\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        int u = id(i,j);\n        if (!isRoad[u]) continue;\n        int r = rowSegId[u], cc = colSegId[u];\n        if (r >= 0 && cc >= 0) hk.add_edge(r, cc);\n    }\n    hk.max_matching();\n    auto [chooseRow_char, chooseCol_char] = hk.min_vertex_cover();\n    vector<char> chooseRow = chooseRow_char, chooseCol = chooseCol_char;\n\n    // Coverage states for chosen segments only\n    vector<char> coveredRow(nR, 0), coveredCol(nC, 0);\n    long long remain = 0;\n    for (int r = 0; r < nR; ++r) if (chooseRow[r]) ++remain;\n    for (int cc = 0; cc < nC; ++cc) if (chooseCol[cc]) ++remain;\n\n    // Prefix sums for along-segment costs\n    vector<vector<int>> rowPref(nR), colPref(nC);\n    for (int r = 0; r < nR; ++r) {\n        int L = (int)rowSegCells[r].size();\n        rowPref[r].resize(L);\n        for (int k = 0; k < L; ++k) {\n            int u = rowSegCells[r][k];\n            rowPref[r][k] = w[u] + (k ? rowPref[r][k-1] : 0);\n        }\n    }\n    for (int cc = 0; cc < nC; ++cc) {\n        int L = (int)colSegCells[cc].size();\n        colPref[cc].resize(L);\n        for (int k = 0; k < L; ++k) {\n            int u = colSegCells[cc][k];\n            colPref[cc][k] = w[u] + (k ? colPref[cc][k-1] : 0);\n        }\n    }\n    auto rowCost = [&](int seg, int p, int q)->int {\n        if (q >= p) return rowPref[seg][q] - rowPref[seg][p];\n        else return rowPref[seg][p-1] - (q > 0 ? rowPref[seg][q-1] : 0);\n    };\n    auto colCost = [&](int seg, int p, int q)->int {\n        if (q >= p) return colPref[seg][q] - colPref[seg][p];\n        else return colPref[seg][p-1] - (q > 0 ? colPref[seg][q-1] : 0);\n    };\n\n    int start = id(si, sj);\n    int cur = start;\n    string ans;\n\n    auto mark_covered_at_cell = [&](int u)->int {\n        int added = 0;\n        int r = rowSegId[u], cc = colSegId[u];\n        if (r >= 0 && chooseRow[r] && !coveredRow[r]) { coveredRow[r] = 1; --remain; ++added; }\n        if (cc >= 0 && chooseCol[cc] && !coveredCol[cc]) { coveredCol[cc] = 1; --remain; ++added; }\n        return added;\n    };\n    mark_covered_at_cell(cur);\n\n    const int INF = 1e9;\n    vector<int> dist(M, INF), prv(M, -1);\n    vector<char> prvDir(M, 0);\n\n    auto reconstruct_and_apply = [&](int s, int t){\n        if (s == t) return;\n        vector<char> moves;\n        int x = t;\n        while (x != s && x != -1) {\n            moves.push_back(prvDir[x]);\n            x = prv[x];\n        }\n        if (x != s) return;\n        reverse(moves.begin(), moves.end());\n        int ci = cur / W, cj = cur % W;\n        for (char mv : moves) {\n            if (mv == 'U') --ci;\n            else if (mv == 'D') ++ci;\n            else if (mv == 'L') --cj;\n            else if (mv == 'R') ++cj;\n            int nid = id(ci, cj);\n            mark_covered_at_cell(nid);\n            ans.push_back(mv);\n        }\n        cur = id(ci, cj);\n    };\n\n    auto dijkstra_to_single = [&](int target){\n        fill(dist.begin(), dist.end(), INF);\n        fill(prv.begin(), prv.end(), -1);\n        fill(prvDir.begin(), prvDir.end(), 0);\n        priority_queue<NodePQ> pq;\n        dist[cur] = 0;\n        pq.push({0, cur});\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (u == target) break;\n            int ui = u / W, uj = u % W;\n            if (ui-1 >= 0) {\n                int v = id(ui-1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'U'; pq.push({nd, v});\n                    }\n                }\n            }\n            if (ui+1 < H) {\n                int v = id(ui+1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'D'; pq.push({nd, v});\n                    }\n                }\n            }\n            if (uj-1 >= 0) {\n                int v = id(ui, uj-1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'L'; pq.push({nd, v});\n                    }\n                }\n            }\n            if (uj+1 < W) {\n                int v = id(ui, uj+1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'R'; pq.push({nd, v});\n                    }\n                }\n            }\n        }\n    };\n\n    auto dijkstra_next_target = [&]()->int {\n        const int LOOKAHEAD_MARGIN = 30;\n        fill(dist.begin(), dist.end(), INF);\n        fill(prv.begin(), prv.end(), -1);\n        fill(prvDir.begin(), prvDir.end(), 0);\n        priority_queue<NodePQ> pq;\n        dist[cur] = 0;\n        pq.push({0, cur});\n\n        auto is_union_target = [&](int u)->bool {\n            int r = rowSegId[u], cc = colSegId[u];\n            if (r >= 0 && chooseRow[r] && !coveredRow[r]) return true;\n            if (cc >= 0 && chooseCol[cc] && !coveredCol[cc]) return true;\n            return false;\n        };\n        auto is_inter_target = [&](int u)->bool {\n            int r = rowSegId[u], cc = colSegId[u];\n            bool t1 = (r >= 0 && chooseRow[r] && !coveredRow[r]);\n            bool t2 = (cc >= 0 && chooseCol[cc] && !coveredCol[cc]);\n            return t1 && t2;\n        };\n\n        int bestUnion = -1, bestUnionDist = INF;\n        int bestInter = -1, bestInterDist = INF;\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (bestInter != -1 && d >= bestInterDist) break;\n            if (bestUnion != -1 && d > bestUnionDist + LOOKAHEAD_MARGIN) break;\n\n            if (is_union_target(u)) {\n                if (d < bestUnionDist) {\n                    bestUnionDist = d;\n                    bestUnion = u;\n                }\n                if (is_inter_target(u)) {\n                    if (d < bestInterDist) {\n                        bestInterDist = d;\n                        bestInter = u;\n                    }\n                }\n            }\n\n            int ui = u / W, uj = u % W;\n            if (ui-1 >= 0) {\n                int v = id(ui-1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'U'; pq.push({nd, v}); }\n                }\n            }\n            if (ui+1 < H) {\n                int v = id(ui+1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'D'; pq.push({nd, v}); }\n                }\n            }\n            if (uj-1 >= 0) {\n                int v = id(ui, uj-1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'L'; pq.push({nd, v}); }\n                }\n            }\n            if (uj+1 < W) {\n                int v = id(ui, uj+1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'R'; pq.push({nd, v}); }\n                }\n            }\n        }\n        if (bestInter != -1) return bestInter;\n        if (bestUnion != -1) return bestUnion;\n        return cur; // fallback\n    };\n\n    auto local_sweep = [&](){\n        // Conservative sweeping to catch nearby MVC intersections\n        const int STEP_LIMIT = 40;   // max cost per single extension\n        const int TOTAL_LIMIT = 120; // total budget per call\n        int spent = 0;\n\n        while (remain > 0 && spent < TOTAL_LIMIT) {\n            int u = cur;\n            int r = rowSegId[u], cc = colSegId[u];\n            int rp = (r >= 0 ? rowPos[u] : -1);\n            int cp = (cc >= 0 ? colPos[u] : -1);\n\n            int bestRowPos = -1, bestRowCost = INT_MAX;\n            if (r >= 0) {\n                // search left for nearest uncovered chosen col segment\n                for (int q = rp - 1; q >= 0; --q) {\n                    int v = rowSegCells[r][q];\n                    int c2 = colSegId[v];\n                    if (c2 >= 0 && chooseCol[c2] && !coveredCol[c2]) {\n                        bestRowPos = q;\n                        bestRowCost = rowCost(r, rp, q);\n                        break;\n                    }\n                }\n                // search right\n                int L = (int)rowSegCells[r].size();\n                for (int q = rp + 1; q < L; ++q) {\n                    int v = rowSegCells[r][q];\n                    int c2 = colSegId[v];\n                    if (c2 >= 0 && chooseCol[c2] && !coveredCol[c2]) {\n                        int cost = rowCost(r, rp, q);\n                        if (cost < bestRowCost) { bestRowCost = cost; bestRowPos = q; }\n                        break;\n                    }\n                }\n            }\n\n            int bestColPos = -1, bestColCost = INT_MAX;\n            if (cc >= 0) {\n                // up\n                for (int q = cp - 1; q >= 0; --q) {\n                    int v = colSegCells[cc][q];\n                    int r2 = rowSegId[v];\n                    if (r2 >= 0 && chooseRow[r2] && !coveredRow[r2]) {\n                        bestColPos = q;\n                        bestColCost = colCost(cc, cp, q);\n                        break;\n                    }\n                }\n                // down\n                int L = (int)colSegCells[cc].size();\n                for (int q = cp + 1; q < L; ++q) {\n                    int v = colSegCells[cc][q];\n                    int r2 = rowSegId[v];\n                    if (r2 >= 0 && chooseRow[r2] && !coveredRow[r2]) {\n                        int cost = colCost(cc, cp, q);\n                        if (cost < bestColCost) { bestColCost = cost; bestColPos = q; }\n                        break;\n                    }\n                }\n            }\n\n            bool doRow = false, doCol = false;\n            int extCost = INT_MAX;\n            if (bestRowPos != -1) { doRow = true; extCost = bestRowCost; }\n            if (bestColPos != -1 && bestColCost < extCost) { doRow = false; doCol = true; extCost = bestColCost; }\n\n            if (extCost == INT_MAX || extCost > STEP_LIMIT || spent + extCost > TOTAL_LIMIT) break;\n\n            if (doRow) {\n                int targetPos = bestRowPos;\n                int ci = cur / W, cj = cur % W;\n                int diff = targetPos - rp;\n                char mv = (diff > 0 ? 'R' : 'L');\n                int steps = abs(diff);\n                for (int t = 0; t < steps; ++t) {\n                    if (mv == 'R') ++cj; else --cj;\n                    int nid = id(ci, cj);\n                    mark_covered_at_cell(nid);\n                    ans.push_back(mv);\n                }\n                cur = id(ci, cj);\n                spent += extCost;\n            } else if (doCol) {\n                int targetPos = bestColPos;\n                int ci = cur / W, cj = cur % W;\n                int diff = targetPos - cp;\n                char mv = (diff > 0 ? 'D' : 'U');\n                int steps = abs(diff);\n                for (int t = 0; t < steps; ++t) {\n                    if (mv == 'D') ++ci; else --ci;\n                    int nid = id(ci, cj);\n                    mark_covered_at_cell(nid);\n                    ans.push_back(mv);\n                }\n                cur = id(ci, cj);\n                spent += extCost;\n            } else {\n                break;\n            }\n        }\n    };\n\n    // Main loop\n    while (remain > 0) {\n        int dest = dijkstra_next_target();\n        if (dest == cur) {\n            // fallback: pick any target explicitly by full dijkstra\n            dijkstra_to_single(cur); // init dist/prv from current\n            int bestD = INF; dest = -1;\n            for (int u = 0; u < M; ++u) if (isRoad[u]) {\n                int r = rowSegId[u], cc = colSegId[u];\n                bool need = (r >= 0 && chooseRow[r] && !coveredRow[r]) || (cc >= 0 && chooseCol[cc] && !coveredCol[cc]);\n                if (need && dist[u] < bestD) { bestD = dist[u]; dest = u; }\n            }\n            if (dest == -1) break;\n        } else {\n            // Already have dist/prv/prvDir from the multi-target search\n        }\n        reconstruct_and_apply(cur, dest);\n        // local sweep to grab nearby MVC segments at low extra cost\n        local_sweep();\n    }\n\n    // Return to start\n    if (cur != start) {\n        dijkstra_to_single(start);\n        reconstruct_and_apply(cur, start);\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Fast RNG (used for small init noise)\nstruct FastRNG {\n    uint64_t x;\n    FastRNG(uint64_t seed=88172645463393265ull) : x(seed) {}\n    uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    double drand() { return (next() >> 11) * (1.0/9007199254740992.0); } // [0,1)\n    double uni(double a, double b){ return a + (b-a)*drand(); }\n};\n\n// Hungarian algorithm (min-cost assignment) on an n x n matrix\nstruct Hungarian {\n    static pair<double, vector<int>> solve(const vector<vector<double>>& a) {\n        int n = (int)a.size();\n        const double INF = 1e100;\n        vector<double> u(n+1, 0), v(n+1, 0);\n        vector<int> p(n+1, 0), way(n+1, 0);\n        for (int i = 1; i <= n; ++i) {\n            p[0] = i;\n            int j0 = 0;\n            vector<double> minv(n+1, INF);\n            vector<char> used(n+1, false);\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                double delta = INF;\n                for (int j = 1; j <= n; ++j) if (!used[j]) {\n                    double cur = a[i0-1][j-1] - u[i0] - v[j];\n                    if (cur < minv[j]) { minv[j] = cur; way[j] = j0; }\n                    if (minv[j] < delta) { delta = minv[j]; j1 = j; }\n                }\n                for (int j = 0; j <= n; ++j) {\n                    if (used[j]) { u[p[j]] += delta; v[j] -= delta; }\n                    else { minv[j] -= delta; }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n        vector<int> assignment(n, -1);\n        for (int j = 1; j <= n; ++j) if (p[j]) assignment[p[j]-1] = j-1;\n        double value = -v[0];\n        return {value, assignment};\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K, R;\n    if(!(cin >> N >> M >> K >> R)) return 0;\n\n    vector<vector<int>> D(N, vector<int>(K));\n    vector<double> sumD(N, 0.0), meanD(K, 0.0);\n    for(int i=0;i<N;i++){\n        double s=0.0;\n        for(int k=0;k<K;k++){\n            cin >> D[i][k];\n            s += D[i][k];\n            meanD[k] += D[i][k];\n        }\n        sumD[i] = s;\n    }\n    for(int k=0;k<K;k++) meanD[k] /= N;\n\n    vector<vector<int>> G(N);\n    vector<int> indeg(N, 0);\n    for(int e=0;e<R;e++){\n        int u,v; cin >> u >> v; --u; --v;\n        G[u].push_back(v);\n        indeg[v]++;\n    }\n\n    // Longest path depth (DAG with u<v)\n    vector<int> dp(N, 1), outdeg(N);\n    for(int i=N-1;i>=0;--i){\n        int best=0;\n        for(int v: G[i]) best = max(best, dp[v]);\n        dp[i] = 1 + best;\n        outdeg[i] = (int)G[i].size();\n    }\n    int dpMax = *max_element(dp.begin(), dp.end()); if(dpMax<=0) dpMax=1;\n    double sumDmax = *max_element(sumD.begin(), sumD.end()); if(sumDmax<=0) sumDmax=1.0;\n    int outMax = *max_element(outdeg.begin(), outdeg.end()); if(outMax<=0) outMax=1;\n\n    // Base priority (normalized)\n    vector<double> basePri(N);\n    const double wDepth = 1.0;\n    const double wOut = 0.3;\n    const double wDiff = 0.2;\n    for(int i=0;i<N;i++){\n        double nd = (double)dp[i] / dpMax;\n        double no = (double)outdeg[i] / outMax;\n        double nf = sumD[i] / sumDmax;\n        basePri[i] = wDepth*nd + wOut*no + wDiff*nf; // ~[0, ~1.5]\n    }\n\n    // Ready tracking (dynamic)\n    vector<char> in_ready(N, 0), started(N, 0), done(N, 0);\n    vector<int> readySince(N, 0);\n    vector<int> readyList; readyList.reserve(N);\n\n    // Initialize ready set\n    for(int i=0;i<N;i++){\n        if(indeg[i] == 0){\n            in_ready[i] = 1;\n            readySince[i] = 0; // available from day 1\n            readyList.push_back(i);\n        }\n    }\n\n    // Worker state\n    vector<int> workerTask(M, -1);\n    vector<int> workerStart(M, 0);\n\n    // Skill estimates and hard lower bounds\n    FastRNG rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    vector<vector<double>> S(M, vector<double>(K, 0.0));\n    vector<vector<double>> sLB(M, vector<double>(K, 0.0));\n    for(int j=0;j<M;j++){\n        for(int k=0;k<K;k++){\n            double val = meanD[k] * 1.6 + rng.uni(-0.5, 0.5);\n            if(val < 0) val = 0;\n            S[j][k] = val;\n            sLB[j][k] = 0.0;\n        }\n    }\n    vector<int> obsCnt(M, 0);\n\n    // Time model helpers\n    auto expected_time_from_w = [&](double w)->double{\n        if (w <= 1e-12) return 1.0;\n        double sum = 0.0;\n        for(int r=-3;r<=3;r++){\n            double val = w + r;\n            if(val < 1.0) val = 1.0;\n            sum += val;\n        }\n        return sum / 7.0;\n    };\n    auto dEt_dw = [&](double w)->double{\n        int cnt=0;\n        for(int r=-3;r<=3;r++){\n            if (w + r > 1.0) cnt++;\n        }\n        return cnt / 7.0;\n    };\n\n    // Softplus smoothing for SGD\n    const double beta = 0.35;\n    const double invbeta = 1.0 / beta;\n    auto softplus_sum = [&](const vector<int>& dvec, const vector<double>& svec)->double{\n        double res=0.0;\n        for(int k=0;k<K;k++){\n            double x = dvec[k] - svec[k];\n            double bx = beta * x;\n            if (bx > 30.0) res += x;\n            else if (bx < -30.0) { /* ~0 */ }\n            else res += log1p(exp(bx)) * invbeta;\n        }\n        return res;\n    };\n    auto sigmoid_beta = [&](double x)->double{\n        double bx = beta * x;\n        if (bx >= 0) {\n            double e = exp(-bx);\n            return 1.0 / (1.0 + e);\n        } else {\n            double e = exp(bx);\n            return e / (1.0 + e);\n        }\n    };\n\n    // Predict expected time using clamped skills with lower bounds\n    const double Smax = 120.0;\n    auto predict_time = [&](int i, int j)->double{\n        double w=0.0;\n        for(int k=0;k<K;k++){\n            double sj = S[j][k];\n            if (sj < sLB[j][k]) sj = sLB[j][k];\n            double z = (double)D[i][k] - sj;\n            if (z > 0) w += z;\n        }\n        return expected_time_from_w(w);\n    };\n\n    // SGD update\n    const double baseLR = 0.5;\n    auto update_skill = [&](int j, int i, int t){\n        vector<double> Sc(S[j]);\n        for(int k=0;k<K;k++) if(Sc[k] < sLB[j][k]) Sc[k] = sLB[j][k];\n        double wsoft = softplus_sum(D[i], Sc);\n        double pred = (wsoft < 0.05 ? 1.0 : expected_time_from_w(wsoft));\n        double target = max(1, t);\n        double err = pred - target;\n        double gE = dEt_dw(wsoft); // in [0,1]\n\n        double lr = baseLR / sqrt((double)obsCnt[j] + 1.0);\n        if (t <= 1) lr *= 0.2;\n        else if (t >= 5) lr *= 1.1;\n\n        if (err > 8) err = 8;\n        if (err < -8) err = -8;\n\n        double scale = lr * gE;\n        if (scale <= 0) { obsCnt[j]++; return; }\n\n        for(int k=0;k<K;k++){\n            double s_curr = S[j][k];\n            if (s_curr < sLB[j][k]) s_curr = sLB[j][k];\n            double g = sigmoid_beta((double)D[i][k] - s_curr); // d wsoft / d s_k = -g\n            double ns = s_curr + scale * err * g;\n            if (ns < sLB[j][k]) ns = sLB[j][k];\n            if (ns < 0) ns = 0;\n            if (ns > Smax) ns = Smax;\n            S[j][k] = ns;\n        }\n        obsCnt[j]++;\n    };\n\n    // Parameters for dynamic pool and matching\n    const double ageCoef = 0.25;   // bonus added to basePri\n    const int ageCap = 7;          // days to saturate age bonus\n    const double priWeight = 0.40; // weight in cost: t_pred - priWeight * score\n    const double riskCoef = 0.45;  // uncertainty penalty coefficient\n\n    int day = 0;\n    vector<double> scoreBuf(N, -1.0); // reused each day for ready tasks' scores\n    vector<char> inPool(N, 0);\n\n    while(true){\n        day++;\n\n        // Collect free workers\n        vector<int> freeWorkers;\n        freeWorkers.reserve(M);\n        for(int j=0;j<M;j++) if(workerTask[j] == -1) freeWorkers.push_back(j);\n\n        vector<pair<int,int>> assignments; // (worker, task)\n\n        if(!freeWorkers.empty()){\n            // Build full candidate list with dynamic scores\n            vector<pair<double,int>> cand; cand.reserve(readyList.size());\n            for(int idx=0; idx<(int)readyList.size(); ++idx){\n                int i = readyList[idx];\n                if(i < 0) continue;\n                if(!in_ready[i]) continue;\n                if(started[i] || done[i]) continue;\n                int age = max(0, day - max(1, readySince[i]));\n                double ageBoost = ageCoef * (double)(min(age, ageCap)) / (double)ageCap;\n                double score = basePri[i] + ageBoost;\n                cand.emplace_back(score, i);\n                scoreBuf[i] = score;\n            }\n\n            int readyCnt = (int)cand.size();\n            if(readyCnt > 0){\n                // Base pool by score\n                int F = (int)freeWorkers.size();\n                int baseTarget = min(readyCnt, max(F * 10, 20)); // base pool\n                baseTarget = min(baseTarget, 70);                // cap base pool to keep fast\n                if (baseTarget < readyCnt){\n                    nth_element(cand.begin(), cand.begin() + baseTarget, cand.end(),\n                                [](const pair<double,int>& a, const pair<double,int>& b){\n                                    return a.first > b.first; // descending\n                                });\n                } else {\n                    baseTarget = readyCnt;\n                }\n\n                // Reset inPool marks\n                for(int ii=0; ii<(int)readyList.size(); ++ii){\n                    int id = readyList[ii];\n                    if (id>=0) inPool[id] = 0;\n                }\n\n                vector<int> pool; pool.reserve(100);\n                vector<double> poolScore; poolScore.reserve(100);\n                for(int i=0;i<baseTarget;i++){\n                    int id = cand[i].second;\n                    pool.push_back(id);\n                    poolScore.push_back(cand[i].first);\n                    inPool[id] = 1;\n                }\n\n                // Augment pool with worker-centric picks from rest\n                int unionCap = 90; // final pool cap\n                int addPerWorker = 3;\n                if ((int)pool.size() < unionCap){\n                    // Build list of rest candidates (unsorted)\n                    vector<pair<double,int>> rest;\n                    rest.reserve(readyCnt - baseTarget);\n                    for(int i=baseTarget;i<readyCnt;i++) rest.push_back(cand[i]);\n\n                    // Collect candidates from workers\n                    struct Cand { int task; double metric; }; // metric = min tpred - priWeight*score\n                    unordered_map<int, double> bestMetric; bestMetric.reserve(256);\n                    for(int fi=0; fi<F; ++fi){\n                        int j = freeWorkers[fi];\n                        // select top-k by predicted time among rest\n                        vector<pair<double,int>> topk; topk.reserve(addPerWorker+2);\n                        for(auto &rp : rest){\n                            int ti = rp.second;\n                            double tpred = predict_time(ti, j);\n                            if ((int)topk.size() < addPerWorker){\n                                topk.emplace_back(tpred, ti);\n                                if ((int)topk.size() == addPerWorker){\n                                    sort(topk.begin(), topk.end(),\n                                         [](const auto& A, const auto& B){ return A.first < B.first; });\n                                }\n                            } else if (tpred < topk.back().first){\n                                topk.back() = {tpred, ti};\n                                // keep sorted small vector\n                                for (int x = (int)topk.size()-1; x>0 && topk[x].first < topk[x-1].first; --x)\n                                    swap(topk[x], topk[x-1]);\n                            }\n                        }\n                        for(auto &p : topk){\n                            int ti = p.second;\n                            if (inPool[ti]) continue;\n                            double metric = p.first - priWeight * scoreBuf[ti];\n                            auto it = bestMetric.find(ti);\n                            if (it == bestMetric.end()) bestMetric.emplace(ti, metric);\n                            else if (metric < it->second) it->second = metric;\n                        }\n                    }\n                    // Convert to vector and sort by metric\n                    vector<pair<double,int>> addList;\n                    addList.reserve(bestMetric.size());\n                    for(auto &kv : bestMetric){\n                        addList.emplace_back(kv.second, kv.first);\n                    }\n                    sort(addList.begin(), addList.end(),\n                         [](const auto& A, const auto& B){ return A.first < B.first; });\n                    for(auto &pp : addList){\n                        int ti = pp.second;\n                        if ((int)pool.size() >= unionCap) break;\n                        if (!inPool[ti]){\n                            pool.push_back(ti);\n                            poolScore.push_back(scoreBuf[ti]);\n                            inPool[ti] = 1;\n                        }\n                    }\n                }\n\n                int P = (int)pool.size();\n                if (P > 0){\n                    // Build cost matrix for Hungarian\n                    int n = max(F, P);\n                    const double BIG = 1e6;\n                    vector<vector<double>> cost(n, vector<double>(n, BIG));\n\n                    for(int fi=0; fi<F; ++fi){\n                        int j = freeWorkers[fi];\n                        double uncert = 1.0 / sqrt((double)obsCnt[j] + 1.0);\n                        for(int pi=0; pi<P; ++pi){\n                            int ti = pool[pi];\n                            double tpred = predict_time(ti, j);\n                            // Uncertainty penalty: scaled by difficulty and depth\n                            double nf = sumD[ti] / sumDmax;\n                            double nd = (double)dp[ti] / dpMax;\n                            double risk = riskCoef * uncert * (0.6*nf + 0.4*nd);\n                            double c = tpred + risk - priWeight * poolScore[pi];\n                            cost[fi][pi] = c;\n                        }\n                        for(int ccol=P; ccol<n; ++ccol) cost[fi][ccol] = 100.0; // dummy task\n                    }\n                    for(int r=F; r<n; ++r){\n                        for(int c=0;c<n;c++) cost[r][c] = 0.0; // dummy workers\n                    }\n\n                    auto res = Hungarian::solve(cost);\n                    vector<int> assignCols = res.second;\n\n                    vector<char> taskTaken(P, 0), workerTaken(F, 0);\n                    for(int fi=0; fi<F; ++fi){\n                        int col = assignCols[fi];\n                        if(col >= 0 && col < P){\n                            int j = freeWorkers[fi];\n                            int ti = pool[col];\n                            assignments.emplace_back(j, ti);\n                            workerTaken[fi] = 1;\n                            taskTaken[col] = 1;\n                        }\n                    }\n                    // Mark assigned tasks as no longer ready\n                    for(int pi=0; pi<P; ++pi){\n                        if(taskTaken[pi]){\n                            int ti = pool[pi];\n                            in_ready[ti] = 0;\n                        }\n                    }\n                }\n\n                // cleanup score buffer for next day (only clear used indices)\n                for(auto &p : cand) scoreBuf[p.second] = -1.0;\n            }\n        }\n\n        // Emit output\n        cout << assignments.size();\n        for(auto &p: assignments){\n            int j = p.first;\n            int i = p.second;\n            cout << \" \" << (j+1) << \" \" << (i+1);\n            workerTask[j] = i;\n            workerStart[j] = day;\n            started[i] = 1;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        // Read feedback\n        int ncomp;\n        if(!(cin >> ncomp)) return 0;\n        if(ncomp == -1){\n            // Completed or day limit\n            return 0;\n        }\n        vector<int> fins(ncomp);\n        for(int idx=0; idx<ncomp; ++idx){\n            int fj; cin >> fj; --fj;\n            fins[idx] = fj;\n        }\n        sort(fins.begin(), fins.end());\n        fins.erase(unique(fins.begin(), fins.end()), fins.end());\n\n        // Process completions\n        for(int fj : fins){\n            int i = workerTask[fj];\n            if(i < 0) continue; // safety\n            int t = day - workerStart[fj] + 1;\n\n            // Skill update\n            update_skill(fj, i, t);\n            // If task finished in 1 day, enforce per-dimension lower bound s >= d\n            if (t <= 1){\n                for(int k=0;k<K;k++){\n                    if (sLB[fj][k] < D[i][k]) sLB[fj][k] = D[i][k];\n                    if (S[fj][k] < sLB[fj][k]) S[fj][k] = sLB[fj][k];\n                }\n            }\n\n            workerTask[fj] = -1;\n            done[i] = 1;\n\n            // Unlock children for next day\n            for(int v: G[i]){\n                indeg[v]--;\n                if(indeg[v] == 0 && !started[v] && !done[v] && !in_ready[v]){\n                    in_ready[v] = 1;\n                    readySince[v] = day; // ready for next day\n                    readyList.push_back(v);\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 88172645463393265ull) { x = seed; }\n    inline uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int randint(int l, int r) { // inclusive\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    inline double drand() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstatic inline int manhattan(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\nstruct Order {\n    int id; // 0-based original index\n    int ax, ay, cx, cy; // pickup (a,b), drop (c,d)\n};\n\nstruct Event {\n    int oid; // 0..M-1 (index in selected array)\n    bool is_pick; // true: pickup, false: drop\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 1000;\n    const int M = 50;\n    const int OFFICE_X = 400;\n    const int OFFICE_Y = 400;\n\n    auto global_start = chrono::high_resolution_clock::now();\n    auto elapsed_sec = [&]() -> double {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - global_start).count();\n    };\n    const double GLOBAL_TL = 1.95;\n\n    vector<Order> all(N);\n    for (int i = 0; i < N; ++i) {\n        int a,b,c,d;\n        if (!(cin >> a >> b >> c >> d)) return 0;\n        all[i] = {i, a, b, c, d};\n    }\n\n    RNG rng(chrono::high_resolution_clock::now().time_since_epoch().count() * 11995408973635179863ull);\n\n    auto s_cost = [&](const Order& o)->long long {\n        long long s = 0;\n        s += manhattan(OFFICE_X, OFFICE_Y, o.ax, o.ay);\n        s += manhattan(o.ax, o.ay, o.cx, o.cy);\n        s += manhattan(o.cx, o.cy, OFFICE_X, OFFICE_Y);\n        return s;\n    };\n\n    // Rank orders by surrogate cost\n    vector<long long> sc(N);\n    vector<pair<long long,int>> score_idx;\n    score_idx.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        sc[i] = s_cost(all[i]);\n        score_idx.emplace_back(sc[i], i);\n    }\n    sort(score_idx.begin(), score_idx.end());\n\n    // Candidate pool and per-step subset size\n    const int P = min(250, N);   // pool from top s_cost\n    const int PER_STEP = 72;     // sampled per insertion step\n    const int TOPK_MAX = 6;      // maximum K for arrays\n    const int topK = 4;          // top-K pickup positions to try per candidate\n\n    vector<int> pool;\n    pool.reserve(P);\n    for (int i = 0; i < P; ++i) pool.push_back(score_idx[i].second);\n\n    // Selection + initial route via fast pair insertion\n    vector<int> selected_orig_ids; selected_orig_ids.reserve(M);\n    vector<Event> seq; seq.reserve(2*M);\n    // coords for selected orders (by internal oid)\n    vector<int> px(M), py(M), dx(M), dy(M);\n\n    auto get_seq_coord = [&](const vector<Event>& s, int idx)->pair<int,int> {\n        const Event &e = s[idx];\n        return e.is_pick ? pair<int,int>{px[e.oid], py[e.oid]} : pair<int,int>{dx[e.oid], dy[e.oid]};\n    };\n\n    auto best_insert_pair_into_current_fast = [&](const vector<Event>& s, const pair<int,int>& pC, const pair<int,int>& dC,\n                                                  int topK_local, long long &bestDelta, int &bestI, int &bestJ) {\n        int L = (int)s.size();\n        long long bestVal[TOPK_MAX]; int bestIdx[TOPK_MAX];\n        for (int t = 0; t < TOPK_MAX; ++t) { bestVal[t] = (long long)4e18; bestIdx[t] = 0; }\n        for (int i = 0; i <= L; ++i) {\n            pair<int,int> prevI = (i == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_seq_coord(s, i - 1);\n            pair<int,int> nextI = (i == L) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_seq_coord(s, i);\n            long long delta_pick = (long long)manhattan(prevI.first, prevI.second, pC.first, pC.second)\n                                 + (long long)manhattan(pC.first, pC.second, nextI.first, nextI.second)\n                                 - (long long)manhattan(prevI.first, prevI.second, nextI.first, nextI.second);\n            if (delta_pick < bestVal[topK_local-1]) {\n                bestVal[topK_local-1] = delta_pick; bestIdx[topK_local-1] = i;\n                for (int t = topK_local-1; t > 0 && bestVal[t] < bestVal[t-1]; --t) {\n                    swap(bestVal[t], bestVal[t-1]);\n                    swap(bestIdx[t], bestIdx[t-1]);\n                }\n            }\n        }\n        bestDelta = (long long)4e18; bestI = 0; bestJ = 1;\n        for (int t = 0; t < topK_local; ++t) {\n            int i = bestIdx[t];\n            long long delta_pick = bestVal[t];\n            auto coord_after_pick = [&](int pos)->pair<int,int> {\n                if (pos == i) return pC;\n                if (pos < i) return get_seq_coord(s, pos);\n                return get_seq_coord(s, pos - 1);\n            };\n            for (int j = i + 1; j <= L + 1; ++j) {\n                pair<int,int> prevJ = coord_after_pick(j - 1);\n                pair<int,int> nextJ = (j == L + 1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : coord_after_pick(j);\n                long long delta_drop = (long long)manhattan(prevJ.first, prevJ.second, dC.first, dC.second)\n                                     + (long long)manhattan(dC.first, dC.second, nextJ.first, nextJ.second)\n                                     - (long long)manhattan(prevJ.first, prevJ.second, nextJ.first, nextJ.second);\n                long long tot = delta_pick + delta_drop;\n                if (tot < bestDelta) {\n                    bestDelta = tot;\n                    bestI = i; bestJ = j;\n                }\n            }\n        }\n    };\n\n    vector<char> used_pool(N, 0);\n    for (int k = 0; k < M; ++k) {\n        // Build list of available pool ids\n        vector<int> avail;\n        avail.reserve(P);\n        for (int id : pool) if (!used_pool[id]) avail.push_back(id);\n        // Sample up to PER_STEP candidates uniformly without replacement\n        vector<int> cand;\n        int need = min(PER_STEP, (int)avail.size());\n        cand.reserve(need);\n        if ((int)avail.size() <= need) {\n            cand = avail;\n        } else {\n            // partial shuffle\n            for (int i = 0; i < (int)avail.size(); ++i) {\n                int j = rng.randint(i, (int)avail.size() - 1);\n                swap(avail[i], avail[j]);\n            }\n            for (int i = 0; i < need; ++i) cand.push_back(avail[i]);\n        }\n\n        long long bestDelta = (long long)4e18;\n        int bestIdx = -1;\n        int insI = 0, insJ = 1;\n        for (int id : cand) {\n            pair<int,int> pC = {all[id].ax, all[id].ay};\n            pair<int,int> dC = {all[id].cx, all[id].cy};\n            long long bD; int bi, bj;\n            best_insert_pair_into_current_fast(seq, pC, dC, topK, bD, bi, bj);\n            if (bD < bestDelta || (bD == bestDelta && sc[id] < sc[(bestIdx==-1)?id:bestIdx])) {\n                bestDelta = bD;\n                bestIdx = id;\n                insI = bi; insJ = bj;\n            }\n        }\n        // Insert chosen pair\n        int oid = k;\n        selected_orig_ids.push_back(bestIdx);\n        used_pool[bestIdx] = 1;\n        px[oid] = all[bestIdx].ax; py[oid] = all[bestIdx].ay;\n        dx[oid] = all[bestIdx].cx; dy[oid] = all[bestIdx].cy;\n        Event ep{oid, true}, ed{oid, false};\n        seq.insert(seq.begin() + insI, ep);\n        seq.insert(seq.begin() + insJ, ed);\n    }\n\n    // Improvement and SA setup\n\n    auto coord_of_event = [&](const Event &e) -> pair<int,int> {\n        return e.is_pick ? pair<int,int>{px[e.oid], py[e.oid]} : pair<int,int>{dx[e.oid], dy[e.oid]};\n    };\n    auto route_cost = [&](const vector<Event> &s)->long long {\n        long long t = 0;\n        int lx = OFFICE_X, ly = OFFICE_Y;\n        for (auto &e : s) {\n            auto [nx, ny] = coord_of_event(e);\n            t += manhattan(lx, ly, nx, ny);\n            lx = nx; ly = ny;\n        }\n        t += manhattan(lx, ly, OFFICE_X, OFFICE_Y);\n        return t;\n    };\n\n    int L = (int)seq.size(); // 2*M\n    vector<int> posPick(M, -1), posDel(M, -1);\n    auto recompute_positions = [&](){\n        fill(posPick.begin(), posPick.end(), -1);\n        fill(posDel.begin(), posDel.end(), -1);\n        for (int i = 0; i < (int)seq.size(); ++i) {\n            if (seq[i].is_pick) posPick[seq[i].oid] = i;\n            else posDel[seq[i].oid] = i;\n        }\n        L = (int)seq.size();\n    };\n    recompute_positions();\n\n    auto get_coord_by_index = [&](int idx)->pair<int,int>{\n        const Event &e = seq[idx];\n        return e.is_pick ? pair<int,int>{px[e.oid], py[e.oid]} : pair<int,int>{dx[e.oid], dy[e.oid]};\n    };\n\n    // Single-event relocation delta\n    auto delta_move_single = [&](int p, int q)->long long {\n        const Event &ev = seq[p];\n        int oid = ev.oid;\n        if (ev.is_pick) {\n            int pos_del_prime = posDel[oid] - 1; // after removal\n            if (q > pos_del_prime) return (long long)4e18; // invalid\n        } else {\n            int pos_pick_prime = posPick[oid];\n            if (q <= pos_pick_prime) return (long long)4e18; // invalid\n        }\n        auto curr = get_coord_by_index(p);\n        pair<int,int> prevc = (p == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p-1);\n        pair<int,int> nextc = (p == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p+1);\n        long long delta = 0;\n        delta += (long long)manhattan(prevc.first, prevc.second, nextc.first, nextc.second)\n               - (long long)manhattan(prevc.first, prevc.second, curr.first, curr.second)\n               - (long long)manhattan(curr.first, curr.second, nextc.first, nextc.second);\n\n        pair<int,int> prev2, next2;\n        if (q == 0) prev2 = {OFFICE_X, OFFICE_Y};\n        else {\n            int j1 = q - 1;\n            int orig1 = (j1 < p ? j1 : j1 + 1);\n            prev2 = get_coord_by_index(orig1);\n        }\n        if (q == L-1) next2 = {OFFICE_X, OFFICE_Y};\n        else {\n            int orig2 = (q < p ? q : q + 1);\n            next2 = get_coord_by_index(orig2);\n        }\n        delta += (long long)manhattan(prev2.first, prev2.second, curr.first, curr.second)\n               + (long long)manhattan(curr.first, curr.second, next2.first, next2.second)\n               - (long long)manhattan(prev2.first, prev2.second, next2.first, next2.second);\n\n        return delta;\n    };\n\n    auto apply_move_single = [&](int p, int q) {\n        Event ev = seq[p];\n        seq.erase(seq.begin() + p);\n        seq.insert(seq.begin() + q, ev);\n        recompute_positions();\n    };\n\n    // Helpers for pair removal mapping\n    auto get_after_removals_coord = [&](int p1, int p2, int k)->pair<int,int>{\n        int orig;\n        if (k < p1) orig = k;\n        else if (k < p2 - 1) orig = k + 1;\n        else orig = k + 2;\n        return get_coord_by_index(orig);\n    };\n    auto get_after_removals_and_pick_coord = [&](int p1, int p2, int i, const pair<int,int>& pickCoord, int k)->pair<int,int>{\n        if (k == i) return pickCoord;\n        if (k < i) return get_after_removals_coord(p1, p2, k);\n        return get_after_removals_coord(p1, p2, k - 1);\n    };\n\n    // Pair relocation delta (remove both, insert at i<j)\n    auto delta_move_pair = [&](int oid, int i, int j)->long long {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        if (!(0 <= p1 && p1 < p2 && p2 < L)) return (long long)4e18;\n        int L2 = L - 2;\n        if (i < 0 || i > L2) return (long long)4e18;\n        if (j <= i || j > L2 + 1) return (long long)4e18;\n\n        auto curr1 = get_coord_by_index(p1);\n        pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n        long long delta = 0;\n        delta += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n               - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n               - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n\n        auto curr2 = get_coord_by_index(p2);\n        pair<int,int> prev2prime, next2prime;\n        if (p2 == p1 + 1) {\n            prev2prime = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        } else {\n            prev2prime = get_coord_by_index(p2 - 1);\n        }\n        next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n        delta += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n               - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n               - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n\n        // Insertion\n        auto pC = pair<int,int>{px[oid], py[oid]};\n        auto dC = pair<int,int>{dx[oid], dy[oid]};\n        pair<int,int> prevI = (i == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i - 1);\n        pair<int,int> nextI = (i == L2) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i);\n        delta += (long long)manhattan(prevI.first, prevI.second, pC.first, pC.second)\n               + (long long)manhattan(pC.first, pC.second, nextI.first, nextI.second)\n               - (long long)manhattan(prevI.first, prevI.second, nextI.first, nextI.second);\n\n        pair<int,int> prevJ = (j == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j - 1);\n        pair<int,int> nextJ = (j == L2 + 1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j);\n        delta += (long long)manhattan(prevJ.first, prevJ.second, dC.first, dC.second)\n               + (long long)manhattan(dC.first, dC.second, nextJ.first, nextJ.second)\n               - (long long)manhattan(prevJ.first, prevJ.second, nextJ.first, nextJ.second);\n\n        return delta;\n    };\n\n    auto apply_move_pair = [&](int oid, int i, int j) {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        seq.erase(seq.begin() + p2);\n        seq.erase(seq.begin() + p1);\n        Event ep{oid, true}, ed{oid, false};\n        seq.insert(seq.begin() + i, ep);\n        seq.insert(seq.begin() + j, ed);\n        recompute_positions();\n    };\n\n    // Fast best insertion after removal (top-K pickup positions)\n    auto best_insertion_after_removal_fast = [&](int p1, int p2, const pair<int,int>& pC, const pair<int,int>& dC, int topK_local,\n                                                 long long &bestDelta, int &bestI, int &bestJ) {\n        int L2 = L - 2;\n        long long bestVal[TOPK_MAX]; int bestIdx[TOPK_MAX];\n        for (int t = 0; t < TOPK_MAX; ++t) { bestVal[t] = (long long)4e18; bestIdx[t] = 0; }\n        for (int i = 0; i <= L2; ++i) {\n            pair<int,int> prevI = (i == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i - 1);\n            pair<int,int> nextI = (i == L2) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i);\n            long long delta_pick = (long long)manhattan(prevI.first, prevI.second, pC.first, pC.second)\n                                 + (long long)manhattan(pC.first, pC.second, nextI.first, nextI.second)\n                                 - (long long)manhattan(prevI.first, prevI.second, nextI.first, nextI.second);\n            if (delta_pick < bestVal[topK_local-1]) {\n                bestVal[topK_local-1] = delta_pick; bestIdx[topK_local-1] = i;\n                for (int t = topK_local-1; t > 0 && bestVal[t] < bestVal[t-1]; --t) {\n                    swap(bestVal[t], bestVal[t-1]);\n                    swap(bestIdx[t], bestIdx[t-1]);\n                }\n            }\n        }\n        bestDelta = (long long)4e18; bestI = 0; bestJ = 1;\n        for (int t = 0; t < topK_local; ++t) {\n            int i = bestIdx[t];\n            long long delta_pick = bestVal[t];\n            for (int j = i + 1; j <= L2 + 1; ++j) {\n                pair<int,int> prevJ = (j == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j - 1);\n                pair<int,int> nextJ = (j == L2 + 1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j);\n                long long delta_drop = (long long)manhattan(prevJ.first, prevJ.second, dC.first, dC.second)\n                                     + (long long)manhattan(dC.first, dC.second, nextJ.first, nextJ.second)\n                                     - (long long)manhattan(prevJ.first, prevJ.second, nextJ.first, nextJ.second);\n                long long tot = delta_pick + delta_drop;\n                if (tot < bestDelta) {\n                    bestDelta = tot;\n                    bestI = i; bestJ = j;\n                }\n            }\n        }\n    };\n\n    auto delta_pair_best_fast = [&](int oid, long long &bestDelta, int &bi, int &bj) -> long long {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        // removal delta\n        auto curr1 = get_coord_by_index(p1);\n        pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n        long long delta_rem = 0;\n        delta_rem += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n                   - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n                   - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n        auto curr2 = get_coord_by_index(p2);\n        pair<int,int> prev2prime = (p2 == p1 + 1) ? ((p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1))\n                                                  : get_coord_by_index(p2 - 1);\n        pair<int,int> next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n        delta_rem += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n                   - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n                   - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n\n        long long bestIns; int iBest, jBest;\n        best_insertion_after_removal_fast(p1, p2, {px[oid], py[oid]}, {dx[oid], dy[oid]}, topK, bestIns, iBest, jBest);\n        bestDelta = delta_rem + bestIns;\n        bi = iBest; bj = jBest;\n        return bestDelta;\n    };\n\n    // Small order-replacement stage: replace selected order with an outside candidate if it strictly improves route\n    vector<char> in_selected(N, 0);\n    for (int i = 0; i < M; ++i) in_selected[selected_orig_ids[i]] = 1;\n    // Build outside candidate list from top of score ranking\n    vector<int> cand_out;\n    int P2 = min(400, N);\n    cand_out.reserve(P2);\n    for (int i = 0; i < P2; ++i) {\n        int id = score_idx[i].second;\n        if (!in_selected[id]) cand_out.push_back(id);\n    }\n\n    auto removal_delta_for_oid = [&](int oid)->long long {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        auto curr1 = get_coord_by_index(p1);\n        pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n        long long delta = 0;\n        delta += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n               - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n               - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n        auto curr2 = get_coord_by_index(p2);\n        pair<int,int> prev2prime, next2prime;\n        if (p2 == p1 + 1) {\n            prev2prime = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        } else {\n            prev2prime = get_coord_by_index(p2 - 1);\n        }\n        next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n        delta += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n               - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n               - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n        return delta;\n    };\n\n    auto apply_replace_order = [&](int oid, int new_orig_id, int insI, int insJ) {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        // remove old\n        seq.erase(seq.begin() + p2);\n        seq.erase(seq.begin() + p1);\n        // update coords and mapping\n        selected_orig_ids[oid] = new_orig_id;\n        px[oid] = all[new_orig_id].ax; py[oid] = all[new_orig_id].ay;\n        dx[oid] = all[new_orig_id].cx; dy[oid] = all[new_orig_id].cy;\n        // insert new\n        Event ep{oid, true}, ed{oid, false};\n        seq.insert(seq.begin() + insI, ep);\n        seq.insert(seq.begin() + insJ, ed);\n        recompute_positions();\n    };\n\n    double replace_budget = 0.25; // seconds\n    double replace_end = elapsed_sec() + replace_budget;\n    if (!cand_out.empty()) {\n        while (elapsed_sec() < replace_end) {\n            int oid = rng.randint(0, M - 1);\n            if (cand_out.empty()) break;\n            // pick a random candidate not selected\n            int idx = rng.randint(0, (int)cand_out.size() - 1);\n            int new_id = cand_out[idx];\n            if (in_selected[new_id]) {\n                // refresh cand_out lazily\n                cand_out.clear();\n                for (int i = 0; i < P2; ++i) {\n                    int id = score_idx[i].second;\n                    if (!in_selected[id]) cand_out.push_back(id);\n                }\n                if (cand_out.empty()) break;\n                continue;\n            }\n            long long delta_rem = removal_delta_for_oid(oid);\n            int p1 = posPick[oid];\n            int p2 = posDel[oid];\n            long long bestIns; int bi, bj;\n            pair<int,int> newP{all[new_id].ax, all[new_id].ay};\n            pair<int,int> newD{all[new_id].cx, all[new_id].cy};\n            best_insertion_after_removal_fast(p1, p2, newP, newD, topK, bestIns, bi, bj);\n            long long delta_tot = delta_rem + bestIns;\n            if (delta_tot < 0) {\n                int old_orig = selected_orig_ids[oid];\n                in_selected[old_orig] = 0;\n                in_selected[new_id] = 1;\n                apply_replace_order(oid, new_id, bi, bj);\n                // refresh cand_out maybe (optional)\n            }\n        }\n    }\n\n    // Quick local improvement: one pass of fast best pair relocations\n    for (int oid = 0; oid < M; ++oid) {\n        long long bestDelta; int bi, bj;\n        long long d = delta_pair_best_fast(oid, bestDelta, bi, bj);\n        if (d < 0) apply_move_pair(oid, bi, bj);\n    }\n\n    // Extra cheap local improvement: best single-event relocation for each pickup and delivery\n    auto single_improve_pass = [&](){\n        bool improved = false;\n        // deliveries\n        for (int oid = 0; oid < M; ++oid) {\n            int p = posDel[oid];\n            long long bestD = 0;\n            int bestQ = p;\n            for (int q = 0; q <= L - 1; ++q) if (q != p) {\n                long long d = delta_move_single(p, q);\n                if (d == (long long)4e18) continue;\n                if (q > posPick[oid]) { // valid delivered after its pick\n                    if (bestQ == p || d < bestD) { bestD = d; bestQ = q; }\n                }\n            }\n            if (bestQ != p && bestD < 0) {\n                apply_move_single(p, bestQ);\n                improved = true;\n            }\n        }\n        // pickups\n        for (int oid = 0; oid < M; ++oid) {\n            int p = posPick[oid];\n            long long bestD = 0;\n            int bestQ = p;\n            for (int q = 0; q <= L - 1; ++q) if (q != p) {\n                long long d = delta_move_single(p, q);\n                if (d == (long long)4e18) continue;\n                if (q <= posDel[oid] - 1) { // pickup before its delivery\n                    if (bestQ == p || d < bestD) { bestD = d; bestQ = q; }\n                }\n            }\n            if (bestQ != p && bestD < 0) {\n                apply_move_single(p, bestQ);\n                improved = true;\n            }\n        }\n        return improved;\n    };\n    for (int t = 0; t < 2; ++t) {\n        if (!single_improve_pass()) break;\n    }\n\n    // SA setup\n    long long cur_cost = route_cost(seq);\n    long long best_cost = cur_cost;\n    vector<Event> best_seq = seq;\n\n    const double T0 = 180.0;\n    const double T1 = 1.0;\n\n    // Lambda to get coord at index or office if out of bounds\n    auto coordAtIdxOrOfficeLocal = [&](int idx)->pair<int,int> {\n        if (idx < 0 || idx >= L) return pair<int,int>{OFFICE_X, OFFICE_Y};\n        return get_coord_by_index(idx);\n    };\n\n    // Swap move: try swapping nodes at positions p<q with precedence checks; O(1) delta\n    auto delta_swap_nodes = [&](int p, int q)->long long {\n        if (p == q) return (long long)4e18;\n        if (p > q) swap(p, q);\n        const Event &Aev = seq[p];\n        const Event &Bev = seq[q];\n\n        // validity checks for precedence after swap\n        if (Aev.is_pick && Bev.is_pick) {\n            if (!(posDel[Aev.oid] > q && posDel[Bev.oid] > p)) return (long long)4e18;\n        } else if (!Aev.is_pick && !Bev.is_pick) {\n            if (!(posPick[Aev.oid] < q && posPick[Bev.oid] < p)) return (long long)4e18;\n        } else if (Aev.is_pick && !Bev.is_pick) {\n            if (!(q < posDel[Aev.oid] && posPick[Bev.oid] < p)) return (long long)4e18;\n        } else { // A is drop, B is pick\n            if (!(p < posDel[Bev.oid] && posPick[Aev.oid] < q)) return (long long)4e18;\n        }\n\n        auto A = get_coord_by_index(p);\n        auto B = get_coord_by_index(q);\n        auto up = coordAtIdxOrOfficeLocal(p-1);\n        auto ap = coordAtIdxOrOfficeLocal(p+1);\n        auto vq = coordAtIdxOrOfficeLocal(q-1);\n        auto bq = coordAtIdxOrOfficeLocal(q+1);\n\n        long long oldSum = 0, newSum = 0;\n        if (q == p + 1) {\n            // adjacent\n            oldSum += manhattan(up.first, up.second, A.first, A.second);\n            oldSum += manhattan(A.first, A.second, B.first, B.second);\n            oldSum += manhattan(B.first, B.second, bq.first, bq.second);\n\n            newSum += manhattan(up.first, up.second, B.first, B.second);\n            newSum += manhattan(B.first, B.second, A.first, A.second);\n            newSum += manhattan(A.first, A.second, bq.first, bq.second);\n        } else {\n            oldSum += manhattan(up.first, up.second, A.first, A.second);\n            oldSum += manhattan(A.first, A.second, ap.first, ap.second);\n            oldSum += manhattan(vq.first, vq.second, B.first, B.second);\n            oldSum += manhattan(B.first, B.second, bq.first, bq.second);\n\n            newSum += manhattan(up.first, up.second, B.first, B.second);\n            newSum += manhattan(B.first, B.second, ap.first, ap.second);\n            newSum += manhattan(vq.first, vq.second, A.first, A.second);\n            newSum += manhattan(A.first, A.second, bq.first, bq.second);\n        }\n        return newSum - oldSum;\n    };\n\n    auto apply_swap_nodes = [&](int p, int q) {\n        if (p == q) return;\n        if (p > q) swap(p, q);\n        Event A = seq[p], B = seq[q];\n        swap(seq[p], seq[q]);\n        if (A.is_pick) posPick[A.oid] = q; else posDel[A.oid] = q;\n        if (B.is_pick) posPick[B.oid] = p; else posDel[B.oid] = p;\n        // L unchanged\n    };\n\n    int iter = 0;\n    double last_check = 0.0;\n    while (true) {\n        if ((iter & 1023) == 0) {\n            double t = elapsed_sec();\n            if (t > GLOBAL_TL) break;\n            last_check = t;\n        }\n        ++iter;\n        double tfrac = min(1.0, last_check / GLOBAL_TL);\n        double temp = T0 + (T1 - T0) * tfrac;\n\n        int moveType = rng.randint(0, 99);\n        bool accepted = false;\n        long long d = 0;\n\n        if (moveType < 30) {\n            // Single-event relocation\n            int p = rng.randint(0, L - 1);\n            int Lp = L - 1;\n            if (Lp <= 0) continue;\n            int q = rng.randint(0, Lp);\n            if (q == p) continue;\n            d = delta_move_single(p, q);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_single(p, q);\n                cur_cost += d;\n                accepted = true;\n            }\n        } else if (moveType < 80) {\n            // Random pair relocation\n            int oid = rng.randint(0, M - 1);\n            if (L < 4) continue;\n            int i = rng.randint(0, L - 2);\n            int j = rng.randint(i + 1, L - 1);\n            d = delta_move_pair(oid, i, j);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_pair(oid, i, j);\n                cur_cost += d;\n                accepted = true;\n            }\n        } else if (moveType < 98) {\n            // Node swap\n            int p = rng.randint(0, L - 1);\n            int q = rng.randint(0, L - 1);\n            if (p == q) continue;\n            d = delta_swap_nodes(p, q);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_swap_nodes(p, q);\n                cur_cost += d;\n                accepted = true;\n            }\n        } else {\n            // Rare fast best pair relocation\n            int oid = rng.randint(0, M - 1);\n            long long bestDelta; int bi, bj;\n            d = delta_pair_best_fast(oid, bestDelta, bi, bj);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_pair(oid, bi, bj);\n                cur_cost += d;\n                accepted = true;\n            }\n        }\n\n        if (accepted && cur_cost < best_cost) {\n            best_cost = cur_cost;\n            best_seq = seq;\n        }\n    }\n\n    // Apply final cheap improvement pass on the best sequence and keep it\n    seq = best_seq;\n    recompute_positions();\n    auto single_improve_pass2 = [&](){\n        bool improved = false;\n        for (int oid = 0; oid < M; ++oid) {\n            int p = posDel[oid];\n            long long bestD = 0; int bestQ = p;\n            for (int q = 0; q <= L - 1; ++q) if (q != p) {\n                long long d = delta_move_single(p, q);\n                if (d == (long long)4e18) continue;\n                if (q > posPick[oid]) { if (bestQ == p || d < bestD) { bestD = d; bestQ = q; } }\n            }\n            if (bestQ != p && bestD < 0) { apply_move_single(p, bestQ); improved = true; }\n        }\n        for (int oid = 0; oid < M; ++oid) {\n            int p = posPick[oid];\n            long long bestD = 0; int bestQ = p;\n            for (int q = 0; q <= L - 1; ++q) if (q != p) {\n                long long d = delta_move_single(p, q);\n                if (d == (long long)4e18) continue;\n                if (q <= posDel[oid] - 1) { if (bestQ == p || d < bestD) { bestD = d; bestQ = q; } }\n            }\n            if (bestQ != p && bestD < 0) { apply_move_single(p, bestQ); improved = true; }\n        }\n        return improved;\n    };\n    for (int t = 0; t < 2; ++t) {\n        if (!single_improve_pass2()) break;\n    }\n\n    // Output\n    cout << M;\n    for (int i = 0; i < M; ++i) cout << ' ' << (selected_orig_ids[i] + 1);\n    cout << '\\n';\n\n    int n = 2*M + 2;\n    cout << n << ' ' << OFFICE_X << ' ' << OFFICE_Y;\n    for (int i = 0; i < (int)seq.size(); ++i) {\n        auto [x, y] = coord_of_event(seq[i]);\n        cout << ' ' << x << ' ' << y;\n    }\n    cout << ' ' << OFFICE_X << ' ' << OFFICE_Y << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\n#include <boost/dynamic_bitset.hpp>\nusing namespace std;\n\n// Fixed sizes\nstatic constexpr int N = 400;\nstatic constexpr int M = 5 * (N - 1);\n\nstruct Edge {\n    int u, v;\n    int d;              // rounded Euclidean distance\n    int level = 6;      // 1..5 if chosen in k-th spanning tree on E by d, else 6\n    bool is_nn = false; // among top-K nearest by d for an endpoint\n};\n\n// DSU with cut-edge bitsets per component: inc[C] is XOR of per-vertex incident edges in C\nstruct DSU {\n    vector<int> parent, sz;\n    vector<boost::dynamic_bitset<unsigned long long>> inc; // cut edges per component\n    DSU(int n, int m_bits) : parent(n), sz(n,1), inc(n, boost::dynamic_bitset<unsigned long long>(m_bits)) {\n        iota(parent.begin(), parent.end(), 0);\n    }\n    int find(int x){\n        while(parent[x]!=x){\n            parent[x]=parent[parent[x]];\n            x=parent[x];\n        }\n        return x;\n    }\n    int unite(int a, int b){\n        a=find(a); b=find(b);\n        if(a==b) return a;\n        if(sz[a] < sz[b]) swap(a,b);\n        inc[a] ^= inc[b]; // exact cut update\n        parent[b] = a;\n        sz[a] += sz[b];\n        return a;\n    }\n};\n\n// Count up to cap set bits strictly after pos\nstatic inline int count_suffix_capped(const boost::dynamic_bitset<unsigned long long>& bs, int pos, int cap) {\n    int c = 0;\n    auto idx = bs.find_next(pos);\n    while (idx != boost::dynamic_bitset<unsigned long long>::npos) {\n        ++c;\n        if (c >= cap) break;\n        idx = bs.find_next(idx);\n    }\n    return c;\n}\n\n// Quick check if there exists a set bit strictly after pos\nstatic inline bool has_future(const boost::dynamic_bitset<unsigned long long>& bs, int pos) {\n    auto idx = bs.find_next(pos);\n    return idx != boost::dynamic_bitset<unsigned long long>::npos;\n}\n\nstatic inline int round_int(double x) {\n    return (int)llround(x);\n}\n\n// Assign levels 1..K by extracting K spanning trees (on E) using weights d\nstatic void assign_mst_levels(vector<Edge>& edges, int K) {\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    stable_sort(idx.begin(), idx.end(), [&](int a, int b){\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n\n    vector<char> available(M, 1);\n    for (int lev = 1; lev <= K; lev++) {\n        vector<int> par(N), rnk(N,0);\n        iota(par.begin(), par.end(), 0);\n        function<int(int)> fnd = [&](int x){ return par[x]==x ? x : par[x]=fnd(par[x]); };\n        auto uni = [&](int a, int b)->bool {\n            a=fnd(a); b=fnd(b);\n            if(a==b) return false;\n            if(rnk[a]<rnk[b]) swap(a,b);\n            par[b]=a;\n            if(rnk[a]==rnk[b]) rnk[a]++;\n            return true;\n        };\n\n        int picked = 0;\n        for (int id : idx) {\n            if (!available[id]) continue;\n            int u = edges[id].u, v = edges[id].v;\n            if (uni(u, v)) {\n                edges[id].level = lev;\n                available[id] = 0;\n                picked++;\n                if (picked == N-1) break;\n            }\n        }\n        // If not enough edges to complete a tree, remaining edges keep level=6.\n    }\n}\n\n// Temporary DSU for connectivity check among current components using only future edges\nstruct TempDSU {\n    vector<int> par;\n    int comps;\n    explicit TempDSU(int n=0) { init(n); }\n    void init(int n) {\n        par.resize(n);\n        iota(par.begin(), par.end(), 0);\n        comps = n;\n    }\n    int find(int a){\n        while(par[a]!=a){ par[a]=par[par[a]]; a=par[a]; }\n        return a;\n    }\n    bool unite(int a, int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        par[b]=a;\n        --comps;\n        return true;\n    }\n};\n\n// Check if rejecting current edge keeps the \"future graph\" connected:\n// Nodes = current DSU components; Edges = edges with index > i connecting different components.\nstatic bool future_connected_after_reject(int i, DSU& dsu, const vector<Edge>& edges) {\n    static vector<int> root_idx;\n    root_idx.assign(N, -1);\n    int K = 0;\n    for (int v = 0; v < N; v++) {\n        if (dsu.parent[v] == v) { // v is a root\n            root_idx[v] = K++;\n        }\n    }\n    if (K <= 1) return true;\n\n    TempDSU tmp(K);\n\n    for (int j = i + 1; j < M; j++) {\n        int ru = dsu.find(edges[j].u);\n        int rv = dsu.find(edges[j].v);\n        if (ru == rv) continue;\n        int iu = root_idx[ru];\n        int iv = root_idx[rv];\n        if (iu < 0 || iv < 0) continue; // safety\n        if (tmp.unite(iu, iv) && tmp.comps == 1) {\n            return true; // connected\n        }\n    }\n    return tmp.comps == 1;\n}\n\n// Deterministic PRNG for perturbed MSTs\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed=88172645463393265ULL): x(seed) {}\n    uint64_t next() {\n        uint64_t y = x;\n        y ^= y << 7;\n        y ^= y >> 9;\n        return x = y;\n    }\n    double next_double() {\n        return (next() >> 11) * (1.0 / (1ULL << 53));\n    }\n    double uniform(double a, double b) { return a + (b - a) * next_double(); }\n};\n\n// Build multiple perturbed MSTs on E (weights near d) to compute frequency\nstatic vector<int> mst_frequency(const vector<Edge>& edges, int rounds, double sigma) {\n    vector<int> freq(M, 0);\n    vector<int> idx(M);\n    vector<double> w(M);\n    XorShift64 rng(2025813ULL); // deterministic\n\n    for (int r = 0; r < rounds; r++) {\n        for (int i = 0; i < M; i++) {\n            double noise = rng.uniform(-sigma, sigma);\n            w[i] = edges[i].d * (1.0 + noise);\n            idx[i] = i;\n        }\n        sort(idx.begin(), idx.end(), [&](int a, int b){\n            if (w[a] != w[b]) return w[a] < w[b];\n            return a < b;\n        });\n        // DSU\n        vector<int> par(N), rnk(N,0);\n        iota(par.begin(), par.end(), 0);\n        function<int(int)> fnd = [&](int x){ return par[x]==x ? x : par[x]=fnd(par[x]); };\n        auto uni = [&](int a, int b)->bool {\n            a=fnd(a); b=fnd(b);\n            if(a==b) return false;\n            if(rnk[a]<rnk[b]) swap(a,b);\n            par[b]=a;\n            if(rnk[a]==rnk[b]) rnk[a]++;\n            return true;\n        };\n        int picked = 0;\n        for (int id : idx) {\n            if (uni(edges[id].u, edges[id].v)) {\n                freq[id]++;\n                picked++;\n                if (picked == N-1) break;\n            }\n        }\n    }\n    return freq;\n}\n\n// Expected-MST inclusion test for current edge i with length l:\n// Contract current accepted edges (DSU components). Consider remaining edges j>i with weight 2*d_j.\n// Process all with 2*d_j < l; if after that, endpoints of edge i are still in different components,\n// then edge i would be included by the expected MST -> return true.\nstatic bool expected_mst_includes_edge(int i, int l, DSU& dsu, const vector<Edge>& edges, const vector<int>& orderBy2d) {\n    // Map current DSU roots to compact indices\n    static vector<int> root_idx;\n    root_idx.assign(N, -1);\n    int K = 0;\n    for (int v = 0; v < N; v++) {\n        if (dsu.parent[v] == v) {\n            root_idx[v] = K++;\n        }\n    }\n    if (K <= 1) return false;\n\n    // Initialize temporary DSU on component indices\n    vector<int> par(K);\n    iota(par.begin(), par.end(), 0);\n    function<int(int)> fnd = [&](int a){ while(par[a]!=a){ par[a]=par[par[a]]; a=par[a]; } return a; };\n    auto uni = [&](int a, int b){ a=fnd(a); b=fnd(b); if(a==b) return false; par[b]=a; return true; };\n\n    const int ru = dsu.find(edges[i].u);\n    const int rv = dsu.find(edges[i].v);\n    const int iu = root_idx[ru];\n    const int iv = root_idx[rv];\n\n    // Scan edges in ascending 2*d, but only those with index > i and 2*d < l\n    for (int eid : orderBy2d) {\n        if (eid <= i) continue;\n        int w2 = 2 * edges[eid].d;\n        if (w2 >= l) break;\n        int r1 = dsu.find(edges[eid].u);\n        int r2 = dsu.find(edges[eid].v);\n        if (r1 == r2) continue;\n        int a = root_idx[r1], b = root_idx[r2];\n        if (a < 0 || b < 0) continue;\n        uni(a, b);\n    }\n\n    // If still disconnected, edge i would be taken by expected MST\n    return fnd(iu) != fnd(iv);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Read coordinates\n    vector<int> x(N), y(N);\n    for (int i = 0; i < N; i++) {\n        if (!(cin >> x[i] >> y[i])) {\n            return 0;\n        }\n    }\n\n    // Read edges and compute distances\n    vector<Edge> edges(M);\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        edges[i].u = u;\n        edges[i].v = v;\n        long long dx = x[u] - x[v];\n        long long dy = y[u] - y[v];\n        double dist = sqrt((double)dx * dx + (double)dy * dy);\n        int d = round_int(dist);\n        if (d <= 0) d = 1;\n        edges[i].d = d;\n    }\n\n    // Precompute nearest edges per vertex (by d)\n    const int KNN = 4;\n    vector<vector<pair<int,int>>> adj(N); // (d, edge_index)\n    for (int i = 0; i < M; i++) {\n        adj[edges[i].u].push_back({edges[i].d, i});\n        adj[edges[i].v].push_back({edges[i].d, i});\n    }\n    for (int v = 0; v < N; v++) {\n        auto &lst = adj[v];\n        sort(lst.begin(), lst.end(), [](const auto& a, const auto& b){ return a.first < b.first; });\n        int limit = min<int>(KNN, lst.size());\n        for (int j = 0; j < limit; j++) {\n            edges[lst[j].second].is_nn = true;\n        }\n    }\n\n    // Assign 5 spanning tree levels on E by d\n    assign_mst_levels(edges, 5);\n\n    // MST frequency over perturbed weights\n    const int FREQ_ROUNDS = 16;\n    const double FREQ_SIGMA = 0.03;\n    vector<int> freq = mst_frequency(edges, FREQ_ROUNDS, FREQ_SIGMA);\n\n    // Distance quantiles for small/large d adjustments\n    vector<int> all_d; all_d.reserve(M);\n    for (auto &e : edges) all_d.push_back(e.d);\n    vector<int> tmp = all_d;\n    nth_element(tmp.begin(), tmp.begin() + M/4, tmp.end());\n    int q25 = tmp[M/4];\n    tmp = all_d;\n    nth_element(tmp.begin(), tmp.begin() + (3*M)/4, tmp.end());\n    int q75 = tmp[(3*M)/4];\n\n    // Pre-sort edges by 2*d ascending for expected-MST scan\n    vector<int> orderBy2d(M);\n    iota(orderBy2d.begin(), orderBy2d.end(), 0);\n    stable_sort(orderBy2d.begin(), orderBy2d.end(), [&](int a, int b){\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n\n    // DSU with cut-bitsets\n    DSU dsu(N, M);\n    for (int i = 0; i < M; i++) {\n        dsu.inc[edges[i].u].set(i);\n        dsu.inc[edges[i].v].set(i);\n    }\n\n    // Heuristic parameters\n    static const double levelAdd[7] = {0.0, 0.28, 0.20, 0.13, 0.08, 0.04, 0.0}; // 1..5 used\n    const double nnAdd        = 0.05;\n    const double smallDAdd    = 0.04;\n    const double largeDPen    = 0.06;\n    const double tRelaxCoeff  = 0.05;\n    const int    kCapCount    = 256;\n    const double freqScale    = 0.010; // up to ~0.16\n\n    auto k_small_bonus = [](int kmin)->double{\n        if (kmin <= 1) return 0.18;\n        if (kmin == 2) return 0.15;\n        if (kmin == 3) return 0.08;\n        if (kmin == 4) return 0.04;\n        return 0.0;\n    };\n\n    boost::dynamic_bitset<unsigned long long> pairBS(M);\n\n    // Interactive loop\n    for (int i = 0; i < M; i++) {\n        int l;\n        if (!(cin >> l)) return 0;\n\n        const Edge &e = edges[i];\n        int ru = dsu.find(e.u);\n        int rv = dsu.find(e.v);\n\n        int decision = 0;\n\n        if (ru == rv) {\n            // Reject to avoid cycle\n            decision = 0;\n        } else {\n            // Safety first: if rejecting disconnects future contracted graph, accept\n            bool must_accept = false;\n            if (!has_future(dsu.inc[ru], i) || !has_future(dsu.inc[rv], i)) {\n                must_accept = true;\n            } else if (!future_connected_after_reject(i, dsu, edges)) {\n                must_accept = true;\n            }\n\n            if (must_accept) {\n                decision = 1;\n                dsu.unite(ru, rv);\n            } else {\n                // Expected-MST inclusion test: if expected MST (unknown edges weight 2d) would include this edge, accept\n                bool exp_includes = expected_mst_includes_edge(i, l, dsu, edges, orderBy2d);\n                if (exp_includes) {\n                    decision = 1;\n                    dsu.unite(ru, rv);\n                } else {\n                    // Scarcity-aware threshold\n                    int k1 = count_suffix_capped(dsu.inc[ru], i, kCapCount);\n                    int k2 = count_suffix_capped(dsu.inc[rv], i, kCapCount);\n                    int kmin = min(k1, k2);\n\n                    double r = (double)l / (double)e.d;\n                    double baseExp = 1.0 + 2.0 / (double)(kmin + 1);\n                    double thr = baseExp;\n\n                    // Pair-specific alternatives between ru and rv\n                    pairBS = dsu.inc[ru];\n                    pairBS &= dsu.inc[rv];\n                    int kpair = 0;\n                    int dminpair = INT_MAX;\n                    auto idxb = pairBS.find_next(i);\n                    while (idxb != boost::dynamic_bitset<unsigned long long>::npos) {\n                        ++kpair;\n                        int eid = (int)idxb;\n                        dminpair = min(dminpair, edges[eid].d);\n                        idxb = pairBS.find_next(idxb);\n                    }\n                    if (kpair > 0 && dminpair < INT_MAX) {\n                        double pairExp = (double)dminpair / (double)e.d * (1.0 + 2.0 / (double)(kpair + 1));\n                        double factor = pairExp / baseExp;\n                        if (factor < 0.70) factor = 0.70;\n                        if (factor > 1.20) factor = 1.20;\n                        thr *= factor;\n                    }\n\n                    // Offline/geometry adjustments\n                    if (e.level >= 1 && e.level <= 5) thr += levelAdd[e.level];\n                    if (e.is_nn) thr += nnAdd;\n                    if (e.d <= q25) thr += smallDAdd;\n                    else if (e.d >= q75) thr -= largeDPen;\n\n                    // MST frequency bonus\n                    thr += freq[i] * freqScale;\n\n                    // Small extra help for small k\n                    thr += k_small_bonus(kmin);\n\n                    // Mild relaxation over time\n                    double t = (double)i / (double)M;\n                    thr += tRelaxCoeff * t;\n\n                    if (thr < 1.0) thr = 1.0;\n                    if (thr > 3.0) thr = 3.0;\n\n                    if (r <= thr) {\n                        decision = 1;\n                        dsu.unite(ru, rv);\n                    } else {\n                        decision = 0;\n                    }\n                }\n            }\n        }\n\n        cout << decision << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pet { int x, y, t; };\n\nstruct Plan {\n    bool active = false;\n    bool sealed = false;\n    int L = 0; // number of interior cells\n    vector<pair<int,int>> cells; // interior cells in a straight line\n    vector<pair<int,int>> boundary; // boundary target cells\n    vector<int> adjIdx; // which interior cell a boundary belongs to\n    vector<char> done; // boundary cell is already blocked or OOB\n    int pos = 0; // index in cells where human currently is\n    int idle_turns = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int H = 30, W = 30;\n    auto inb = [&](int x, int y)->bool { return 0 <= x && x < H && 0 <= y && y < W; };\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<Pet> pets(N);\n    for (int i = 0; i < N; i++) {\n        int px, py, pt; cin >> px >> py >> pt;\n        pets[i] = {px-1, py-1, pt};\n    }\n    int M; cin >> M;\n    vector<int> hx(M), hy(M);\n    for (int i = 0; i < M; i++) {\n        int x, y; cin >> x >> y;\n        hx[i] = x-1; hy[i] = y-1;\n    }\n\n    vector<vector<char>> blocked(H, vector<char>(W, 0));\n    vector<vector<int>> pet_here(H, vector<int>(W, 0));\n    vector<vector<int>> human_here(H, vector<int>(W, 0));\n\n    auto rebuild_human_here = [&]() {\n        for (int i = 0; i < H; i++) fill(human_here[i].begin(), human_here[i].end(), 0);\n        for (int i = 0; i < M; i++) human_here[hx[i]][hy[i]]++;\n    };\n    auto rebuild_pet_here = [&]() {\n        for (int i = 0; i < H; i++) fill(pet_here[i].begin(), pet_here[i].end(), 0);\n        for (int i = 0; i < N; i++) pet_here[pets[i].x][pets[i].y]++;\n    };\n\n    rebuild_human_here();\n    rebuild_pet_here();\n\n    const int dx4[4] = {-1, 0, 1, 0};\n    const int dy4[4] = {0, 1, 0, -1};\n    const char blockChar[4] = {'u','r','d','l'};\n    const char moveChar[4]  = {'U','R','D','L'};\n\n    // Preferred direction order for fallback 1-cell closure\n    vector<array<int,4>> prefDir(M);\n    for (int i = 0; i < M; i++) {\n        int topDist = hx[i];\n        int bottomDist = (H-1) - hx[i];\n        int leftDist = hy[i];\n        int rightDist = (W-1) - hy[i];\n        int firstV = (topDist <= bottomDist ? 0 : 2);   // up or down\n        int firstH = (leftDist <= rightDist ? 3 : 1);   // left or right\n        int otherV = firstV ^ 2;\n        int otherH = firstH ^ 2;\n        prefDir[i] = { firstV, firstH, otherV, otherH };\n    }\n\n    vector<char> fully_closed(M, 0); // closed with either 1/2/3/..-cell chamber\n    vector<Plan> plan(M);\n\n    auto count_open_neighbors = [&](int x, int y)->int {\n        int c = 0;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (!blocked[nx][ny]) c++;\n        }\n        return c;\n    };\n\n    auto can_block = [&](int tx, int ty)->bool {\n        if (!inb(tx, ty)) return false;\n        if (blocked[tx][ty]) return false;\n        if (human_here[tx][ty] > 0) return false;\n        if (pet_here[tx][ty] > 0) return false;\n        for (int k = 0; k < 4; k++) {\n            int ax = tx + dx4[k], ay = ty + dy4[k];\n            if (!inb(ax, ay)) continue;\n            if (pet_here[ax][ay] > 0) return false;\n        }\n        return true;\n    };\n\n    auto onWall = [&](int x, int y)->bool {\n        return (x == 0 || x == H-1 || y == 0 || y == W-1);\n    };\n\n    auto minDistToPet = [&](int tx, int ty)->int {\n        int best = INT_MAX;\n        for (const auto &p : pets) {\n            int dist = abs(tx - p.x) + abs(ty - p.y);\n            if (dist < best) best = dist;\n        }\n        return best;\n    };\n\n    // Build centered straight-line corridor plan of length L\n    auto build_centered_plan = [&](int i, int L)->bool {\n        int cx = hx[i], cy = hy[i];\n        int best_score = -1;\n        long long best_dist_sum = -1;\n        vector<pair<int,int>> best_cells;\n        vector<pair<int,int>> best_boundary;\n        vector<int> best_adjIdx;\n\n        // axis 0: horizontal, axis 1: vertical\n        for (int axis = 0; axis < 2; axis++) {\n            for (int left = 0; left <= L-1; left++) {\n                int right = (L-1) - left;\n                vector<pair<int,int>> cells;\n                bool ok = true;\n                if (axis == 0) {\n                    int l = cy - left, r = cy + right;\n                    if (l < 0 || r >= W) continue;\n                    for (int y = l; y <= r; y++) {\n                        if (blocked[cx][y]) { ok = false; break; }\n                        cells.emplace_back(cx, y);\n                    }\n                } else {\n                    int u = cx - left, d = cx + right;\n                    if (u < 0 || d >= H) continue;\n                    for (int x = u; x <= d; x++) {\n                        if (blocked[x][cy]) { ok = false; break; }\n                        cells.emplace_back(x, cy);\n                    }\n                }\n                if (!ok) continue;\n\n                // Build boundary set\n                vector<pair<int,int>> boundary;\n                vector<int> adjIdx;\n                auto add_unique = [&](int tx, int ty, int idx) {\n                    for (size_t p = 0; p < boundary.size(); p++) {\n                        if (boundary[p].first == tx && boundary[p].second == ty) return;\n                    }\n                    boundary.emplace_back(tx, ty);\n                    adjIdx.push_back(idx);\n                };\n                for (int idx = 0; idx < (int)cells.size(); idx++) {\n                    int x = cells[idx].first, y = cells[idx].second;\n                    for (int d = 0; d < 4; d++) {\n                        int nx = x + dx4[d], ny = y + dy4[d];\n                        bool isInterior = false;\n                        for (auto &q : cells) {\n                            if (q.first == nx && q.second == ny) { isInterior = true; break; }\n                        }\n                        if (isInterior) continue;\n                        add_unique(nx, ny, idx);\n                    }\n                }\n                // Score OOB/blocked boundary\n                int score = 0;\n                long long dist_sum = 0;\n                for (auto &b : boundary) {\n                    int tx = b.first, ty = b.second;\n                    if (!inb(tx, ty)) score++;\n                    else if (blocked[tx][ty]) score++;\n                    // tie-break by distance to pets (prefer farther)\n                    int md = inb(tx, ty) ? minDistToPet(tx, ty) : 100; // out-of-bounds treated as far\n                    dist_sum += md;\n                }\n\n                if (score > best_score || (score == best_score && dist_sum > best_dist_sum)) {\n                    best_score = score;\n                    best_dist_sum = dist_sum;\n                    best_cells = cells;\n                    best_boundary = boundary;\n                    best_adjIdx = adjIdx;\n                }\n            }\n        }\n\n        if (best_score < 0) return false;\n\n        plan[i].active = true;\n        plan[i].sealed = false;\n        plan[i].L = L;\n        plan[i].cells = best_cells;\n        plan[i].boundary = best_boundary;\n        plan[i].adjIdx = best_adjIdx;\n        plan[i].done.assign(plan[i].boundary.size(), 0);\n        plan[i].idle_turns = 0;\n\n        // Init done flags\n        for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n            int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n            if (!inb(tx, ty) || blocked[tx][ty]) plan[i].done[k] = 1;\n        }\n        // Set pos to index where current cell lies\n        int found = -1;\n        for (int idx = 0; idx < plan[i].L; idx++) {\n            if (plan[i].cells[idx].first == cx && plan[i].cells[idx].second == cy) { found = idx; break; }\n        }\n        plan[i].pos = (found == -1 ? 0 : found);\n        return true;\n    };\n\n    // Fallback 1-cell action (baseline)\n    auto fallback_one_cell_action = [&](int i)->char {\n        if (fully_closed[i]) return '.';\n        int x = hx[i], y = hy[i];\n        int openN = 0;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (!blocked[nx][ny]) openN++;\n        }\n        if (openN == 0) {\n            fully_closed[i] = 1;\n            return '.';\n        }\n        bool petOnMyCell = (pet_here[x][y] > 0);\n        if (openN == 1 && petOnMyCell) {\n            return '.';\n        }\n        for (int order = 0; order < 4; order++) {\n            int d = prefDir[i][order];\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (blocked[nx][ny]) continue;\n            if (can_block(nx, ny)) {\n                return blockChar[d];\n            }\n        }\n        return '.';\n    };\n\n    const int panic_turn = 260;\n    vector<int> Lcands = {12, 10, 9, 8, 7, 6, 5, 4, 3, 2};\n\n    for (int turn = 0; turn < 300; turn++) {\n        // Sync plan pos with current human positions; decide relocation; build plan if none and on wall\n        vector<char> relocating(M, 0);\n\n        for (int i = 0; i < M; i++) {\n            if (fully_closed[i]) continue;\n\n            // Panic mode: abandon plans and relocation late in the game\n            if (turn >= panic_turn) {\n                plan[i].active = false;\n            }\n\n            if (plan[i].active) {\n                int found = -1;\n                for (int idx = 0; idx < plan[i].L; idx++) {\n                    if (hx[i] == plan[i].cells[idx].first && hy[i] == plan[i].cells[idx].second) { found = idx; break; }\n                }\n                if (found == -1) {\n                    plan[i].active = false;\n                } else {\n                    plan[i].pos = found;\n                }\n            }\n\n            bool atWall = onWall(hx[i], hy[i]);\n            if (!plan[i].active && turn < panic_turn && !atWall) {\n                relocating[i] = 1;\n            } else if (!plan[i].active && atWall && turn < panic_turn) {\n                // build plan at wall\n                bool ok = false;\n                for (int L : Lcands) {\n                    if (build_centered_plan(i, L)) { ok = true; break; }\n                }\n                (void)ok;\n            }\n        }\n\n        string actions(M, '.');\n        vector<char> is_move(M, 0);\n        vector<int> move_dir(M, -1);\n\n        // Tentative actions\n        for (int i = 0; i < M; i++) {\n            if (fully_closed[i]) { actions[i] = '.'; continue; }\n\n            if (turn >= panic_turn) {\n                actions[i] = fallback_one_cell_action(i);\n                continue;\n            }\n\n            if (relocating[i]) {\n                // Move towards nearest wall; prefer destination farther from pets\n                int x = hx[i], y = hy[i];\n                int dTop = x, dBottom = (H-1)-x, dLeft = y, dRight = (W-1)-y;\n                int minv = min(min(dTop, dBottom), min(dLeft, dRight));\n                vector<int> cand;\n                if (dTop == minv) cand.push_back(0);\n                if (dLeft == minv) cand.push_back(3);\n                if (dBottom == minv) cand.push_back(2);\n                if (dRight == minv) cand.push_back(1);\n                int chosen_dir = -1;\n                int bestDist = -1;\n                for (int d : cand) {\n                    int nx = x + dx4[d], ny = y + dy4[d];\n                    if (!inb(nx, ny)) continue;\n                    if (blocked[nx][ny]) continue;\n                    int md = minDistToPet(nx, ny);\n                    if (md > bestDist) { bestDist = md; chosen_dir = d; }\n                }\n                if (chosen_dir != -1) {\n                    actions[i] = moveChar[chosen_dir];\n                    is_move[i] = 1;\n                    move_dir[i] = chosen_dir;\n                } else {\n                    actions[i] = '.';\n                }\n                continue;\n            }\n\n            if (!plan[i].active) {\n                actions[i] = fallback_one_cell_action(i);\n                continue;\n            }\n\n            // Update boundary done flags\n            for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                if (!inb(tx, ty) || blocked[tx][ty]) plan[i].done[k] = 1;\n            }\n            // If any interior cell got blocked, abort plan\n            bool interior_broken = false;\n            for (int idx = 0; idx < plan[i].L; idx++) {\n                int cx = plan[i].cells[idx].first, cy = plan[i].cells[idx].second;\n                if (!inb(cx, cy) || blocked[cx][cy]) { interior_broken = true; break; }\n            }\n            if (interior_broken) {\n                plan[i].active = false;\n                actions[i] = fallback_one_cell_action(i);\n                continue;\n            }\n\n            int remain = 0;\n            for (char d : plan[i].done) if (!d) remain++;\n\n            if (remain == 0) {\n                plan[i].sealed = true;\n                fully_closed[i] = 1;\n                actions[i] = '.';\n                continue;\n            }\n\n            // Determine if pet is inside the chamber\n            bool petInside = false;\n            for (int idx = 0; idx < plan[i].L; idx++) {\n                if (pet_here[plan[i].cells[idx].first][plan[i].cells[idx].second] > 0) { petInside = true; break; }\n            }\n\n            int cx = plan[i].cells[plan[i].pos].first;\n            int cy = plan[i].cells[plan[i].pos].second;\n\n            // Try to block from current pos; choose the safest candidate (furthest from pets)\n            int chosen_dir = -1;\n            int bestDist = -1;\n            for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                if (plan[i].done[k]) continue;\n                if (plan[i].adjIdx[k] != plan[i].pos) continue;\n                int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                if (!inb(tx, ty)) continue;\n                if (remain == 1 && petInside) continue; // avoid closing with pet inside\n                if (!can_block(tx, ty)) continue;\n                int dd = -1;\n                for (int d = 0; d < 4; d++) {\n                    if (cx + dx4[d] == tx && cy + dy4[d] == ty) { dd = d; break; }\n                }\n                if (dd == -1) continue;\n                int md = minDistToPet(tx, ty);\n                if (md > bestDist) {\n                    bestDist = md;\n                    chosen_dir = dd;\n                }\n            }\n\n            if (chosen_dir != -1) {\n                actions[i] = blockChar[chosen_dir];\n                continue;\n            } else {\n                // Find another interior cell with a candidate boundary to block\n                int target_idx = -1;\n                int target_bestDist = -1;\n                for (int idx = 0; idx < plan[i].L; idx++) {\n                    if (idx == plan[i].pos) continue;\n                    int localBest = -1;\n                    for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                        if (plan[i].done[k]) continue;\n                        if (plan[i].adjIdx[k] != idx) continue;\n                        int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                        if (!inb(tx, ty)) continue;\n                        if (remain == 1 && petInside) continue;\n                        if (!can_block(tx, ty)) continue;\n                        int md = minDistToPet(tx, ty);\n                        if (md > localBest) localBest = md;\n                    }\n                    if (localBest > target_bestDist) {\n                        target_bestDist = localBest;\n                        target_idx = idx;\n                    }\n                }\n                if (target_idx != -1) {\n                    // Move one step along the corridor toward target_idx\n                    int next_idx = plan[i].pos;\n                    if (target_idx > plan[i].pos) next_idx = plan[i].pos + 1;\n                    else if (target_idx < plan[i].pos) next_idx = plan[i].pos - 1;\n                    int nx = plan[i].cells[next_idx].first;\n                    int ny = plan[i].cells[next_idx].second;\n                    if (inb(nx, ny) && !blocked[nx][ny]) {\n                        int dd = -1;\n                        for (int d = 0; d < 4; d++) {\n                            if (hx[i] + dx4[d] == nx && hy[i] + dy4[d] == ny) { dd = d; break; }\n                        }\n                        if (dd != -1) {\n                            actions[i] = moveChar[dd];\n                            is_move[i] = 1;\n                            move_dir[i] = dd;\n                        } else {\n                            actions[i] = '.';\n                        }\n                    } else {\n                        actions[i] = '.';\n                    }\n                } else {\n                    actions[i] = '.';\n                }\n            }\n        }\n\n        // Phase-2: prevent moving into a cell that becomes blocked by anyone this turn\n        vector<vector<char>> blocked_this_turn(H, vector<char>(W, 0));\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'u' || c == 'r' || c == 'd' || c == 'l') {\n                int d = (c=='u'?0:(c=='r'?1:(c=='d'?2:3)));\n                int tx = hx[i] + dx4[d], ty = hy[i] + dy4[d];\n                if (inb(tx, ty)) blocked_this_turn[tx][ty] = 1;\n            }\n        }\n        vector<char> canceled(M, 0);\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'U' || c == 'R' || c == 'D' || c == 'L') {\n                int d = (c=='U'?0:(c=='R'?1:(c=='D'?2:3)));\n                int nx = hx[i] + dx4[d], ny = hy[i] + dy4[d];\n                if (inb(nx, ny) && blocked_this_turn[nx][ny]) {\n                    actions[i] = '.';\n                    canceled[i] = 1;\n                }\n            }\n        }\n        // Relocation alternate move if canceled\n        for (int i = 0; i < M; i++) {\n            if (!canceled[i]) continue;\n            // only try alternate if we were relocating this turn\n            if (turn >= panic_turn) continue;\n            // A rough check: we considered relocating if not on wall and no active plan\n            if (onWall(hx[i], hy[i]) || plan[i].active || fully_closed[i]) continue;\n            int x = hx[i], y = hy[i];\n            int dTop = x, dBottom = (H-1)-x, dLeft = y, dRight = (W-1)-y;\n            int minv = min(min(dTop, dBottom), min(dLeft, dRight));\n            vector<int> cand;\n            if (dTop == minv) cand.push_back(0);\n            if (dLeft == minv) cand.push_back(3);\n            if (dBottom == minv) cand.push_back(2);\n            if (dRight == minv) cand.push_back(1);\n            int bestDir = -1, bestDist = -1;\n            for (int d : cand) {\n                int nx = x + dx4[d], ny = y + dy4[d];\n                if (!inb(nx, ny)) continue;\n                if (blocked[nx][ny]) continue;\n                if (blocked_this_turn[nx][ny]) continue;\n                int md = minDistToPet(nx, ny);\n                if (md > bestDist) { bestDist = md; bestDir = d; }\n            }\n            if (bestDir != -1) actions[i] = moveChar[bestDir];\n            else actions[i] = '.';\n        }\n\n        // Adjust idle turns after final actions; degrade long-stalling plans\n        for (int i = 0; i < M; i++) {\n            if (!plan[i].active || fully_closed[i]) continue;\n            if (actions[i] == '.') plan[i].idle_turns++;\n            else plan[i].idle_turns = 0;\n            int threshold;\n            if (plan[i].L >= 12) threshold = 90;\n            else if (plan[i].L >= 10) threshold = 80;\n            else if (plan[i].L == 9) threshold = 75;\n            else if (plan[i].L == 8) threshold = 70;\n            else if (plan[i].L == 7) threshold = 65;\n            else if (plan[i].L == 6) threshold = 60;\n            else if (plan[i].L == 5) threshold = 55;\n            else if (plan[i].L == 4) threshold = 50;\n            else if (plan[i].L == 3) threshold = 45;\n            else threshold = 45;\n\n            if (plan[i].idle_turns >= threshold) {\n                plan[i].active = false;\n                // Rebuild a smaller plan from current position if on wall and not in panic\n                if (onWall(hx[i], hy[i]) && turn < panic_turn) {\n                    for (int L : Lcands) {\n                        if (L < plan[i].L) {\n                            if (build_centered_plan(i, L)) break;\n                        }\n                    }\n                }\n            }\n        }\n\n        // Output final actions and flush\n        cout << actions << '\\n' << flush;\n\n        // Apply blocks and moves locally\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'u' || c == 'r' || c == 'd' || c == 'l') {\n                int d = (c=='u'?0:(c=='r'?1:(c=='d'?2:3)));\n                int tx = hx[i] + dx4[d], ty = hy[i] + dy4[d];\n                if (inb(tx, ty)) blocked[tx][ty] = 1;\n            } else if (c == 'U' || c == 'R' || c == 'D' || c == 'L') {\n                int d = (c=='U'?0:(c=='R'?1:(c=='D'?2:3)));\n                int nx = hx[i] + dx4[d], ny = hy[i] + dy4[d];\n                if (inb(nx, ny) && !blocked[nx][ny]) {\n                    hx[i] = nx; hy[i] = ny;\n                }\n            }\n        }\n\n        // Read pet moves\n        for (int i = 0; i < N; i++) {\n            string s; cin >> s;\n            if (s == \".\") continue;\n            for (char mv : s) {\n                if (mv == 'U') pets[i].x -= 1;\n                else if (mv == 'D') pets[i].x += 1;\n                else if (mv == 'L') pets[i].y -= 1;\n                else if (mv == 'R') pets[i].y += 1;\n            }\n        }\n\n        // Rebuild occupancy for next turn\n        rebuild_pet_here();\n        rebuild_human_here();\n\n        // Update closure status\n        for (int i = 0; i < M; i++) {\n            if (fully_closed[i]) continue;\n            if (plan[i].active) {\n                int remain = 0;\n                for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                    int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                    if (!inb(tx, ty) || blocked[tx][ty]) plan[i].done[k] = 1;\n                    if (!plan[i].done[k]) remain++;\n                }\n                if (remain == 0) {\n                    plan[i].sealed = true;\n                    fully_closed[i] = 1;\n                }\n                // update pos index\n                int found = -1;\n                for (int idx = 0; idx < plan[i].L; idx++) {\n                    if (hx[i] == plan[i].cells[idx].first && hy[i] == plan[i].cells[idx].second) { found = idx; break; }\n                }\n                if (found != -1) plan[i].pos = found;\n                else plan[i].active = false;\n            } else {\n                if (count_open_neighbors(hx[i], hy[i]) == 0) {\n                    fully_closed[i] = 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static auto st = steady_clock::now();\n    auto cur = steady_clock::now();\n    return duration<double>(cur - st).count();\n}\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int randint(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    int si, sj, ti, tj;\n    double p;\n    if (!(cin >> si >> sj >> ti >> tj >> p)) return 0;\n    vector<string> h(20);\n    for (int i = 0; i < 20; i++) cin >> h[i];\n    vector<string> v(19);\n    for (int i = 0; i < 19; i++) cin >> v[i];\n\n    const int H = 20, W = 20, N = H * W;\n    auto id = [&](int r, int c) { return r * W + c; };\n    int s_id = id(si, sj);\n    int t_id = id(ti, tj);\n\n    if (s_id == t_id) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    // Directions: 0=U,1=D,2=L,3=R\n    const char DIRC[4] = {'U','D','L','R'};\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n\n    const double q = 1.0 - p;\n\n    // Precompute dest for each state and direction\n    static int dest[400][4];\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = id(i, j);\n            // U\n            if (i > 0 && v[i-1][j] == '0') dest[u][0] = id(i-1, j);\n            else dest[u][0] = -1;\n            // D\n            if (i < H-1 && v[i][j] == '0') dest[u][1] = id(i+1, j);\n            else dest[u][1] = -1;\n            // L\n            if (j > 0 && h[i][j-1] == '0') dest[u][2] = id(i, j-1);\n            else dest[u][2] = -1;\n            // R\n            if (j < W-1 && h[i][j] == '0') dest[u][3] = id(i, j+1);\n            else dest[u][3] = -1;\n        }\n    }\n\n    // Precompute right-transition weights:\n    // out[u] += self_w_right[dir][u] * in[u];\n    // and if other exists: out[other_idx_right[dir][u]] += other_w_right[dir][u] * in[u]\n    static double self_w_right[4][400], other_w_right[4][400];\n    static int other_idx_right[4][400];\n    for (int d = 0; d < 4; d++) {\n        for (int u = 0; u < N; u++) {\n            if (u == t_id) {\n                self_w_right[d][u] = 1.0;\n                other_w_right[d][u] = 0.0;\n                other_idx_right[d][u] = u;\n            } else {\n                int y = dest[u][d];\n                if (y >= 0) {\n                    self_w_right[d][u] = p;     // forget => stay\n                    other_w_right[d][u] = q;    // remember and move\n                    other_idx_right[d][u] = y;\n                } else {\n                    self_w_right[d][u] = 1.0;  // blocked => stay\n                    other_w_right[d][u] = 0.0;\n                    other_idx_right[d][u] = u;\n                }\n            }\n        }\n    }\n\n    const int L0 = 200;\n\n    // Helpers\n    auto apply_right = [&](int dir, const double* vin, double* vout) {\n        for (int i = 0; i < N; i++) vout[i] = 0.0;\n        const double* selfw = self_w_right[dir];\n        const double* otherw = other_w_right[dir];\n        const int* otheri = other_idx_right[dir];\n        for (int u = 0; u < N; u++) {\n            double val = vin[u];\n            if (val == 0.0) continue;\n            vout[u] += selfw[u] * val;\n            double ow = otherw[u];\n            if (ow != 0.0) {\n                int oi = otheri[u];\n                vout[oi] += ow * val;\n            }\n        }\n    };\n    auto apply_right_and_dot = [&](int dir, const double* vin, double* vout, const double* gvec) -> double {\n        double sum = 0.0;\n        for (int i = 0; i < N; i++) vout[i] = 0.0;\n        const double* selfw = self_w_right[dir];\n        const double* otherw = other_w_right[dir];\n        const int* otheri = other_idx_right[dir];\n        for (int u = 0; u < N; u++) {\n            double val = vin[u];\n            if (val == 0.0) continue;\n            double self_add = selfw[u] * val;\n            vout[u] += self_add;\n            sum += gvec[u] * self_add;\n            double ow = otherw[u];\n            if (ow != 0.0) {\n                int oi = otheri[u];\n                double add = ow * val;\n                vout[oi] += add;\n                sum += gvec[oi] * add;\n            }\n        }\n        return sum;\n    };\n    auto apply_left = [&](int dir, const double* gcur, double* gprev) {\n        // gprev[u] = sum_y P(u->y) * gcur[y]\n        const double* selfw = self_w_right[dir];\n        const double* otherw = other_w_right[dir];\n        const int* otheri = other_idx_right[dir];\n        for (int u = 0; u < N; u++) {\n            double s = selfw[u] * gcur[u];\n            double ow = otherw[u];\n            if (ow != 0.0) {\n                int oi = otheri[u];\n                s += ow * gcur[oi];\n            }\n            gprev[u] = s;\n        }\n    };\n\n    // Build shortest path by BFS with direction order\n    auto bfs_path = [&](array<int,4> order) -> vector<int> {\n        vector<int> par(N, -1), pdir(N, -1);\n        deque<int> dq;\n        dq.push_back(s_id);\n        par[s_id] = s_id;\n        while (!dq.empty() && par[t_id] == -1) {\n            int u = dq.front(); dq.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int d = order[k];\n                int vtx = dest[u][d];\n                if (vtx == -1) continue;\n                if (par[vtx] != -1) continue;\n                par[vtx] = u;\n                pdir[vtx] = d;\n                dq.push_back(vtx);\n            }\n        }\n        vector<int> dirs;\n        if (par[t_id] != -1) {\n            int cur = t_id;\n            while (cur != s_id) {\n                dirs.push_back(pdir[cur]);\n                cur = par[cur];\n            }\n            reverse(dirs.begin(), dirs.end());\n        }\n        return dirs;\n    };\n\n    auto build_seq_from_path = [&](const vector<int>& path) -> vector<int> {\n        vector<int> seq;\n        seq.reserve(L0);\n        if (path.empty()) {\n            int cr = si, cc = sj;\n            vector<int> tmp;\n            for (int steps = 0; steps < 400 && !(cr == ti && cc == tj); steps++) {\n                int bestd = 0, bestdist = INT_MAX;\n                for (int d = 0; d < 4; d++) {\n                    int nr = cr + dr[d], nc = cc + dc[d];\n                    if (nr < 0 || nr >= H || nc < 0 || nc >= W) continue;\n                    if (dest[id(cr,cc)][d] == -1) continue;\n                    int md = abs(nr - ti) + abs(nc - tj);\n                    if (md < bestdist) { bestdist = md; bestd = d; }\n                }\n                tmp.push_back(bestd);\n                cr += dr[bestd]; cc += dc[bestd];\n            }\n            while ((int)seq.size() < L0) {\n                for (int d: tmp) {\n                    seq.push_back(d);\n                    if ((int)seq.size() >= L0) break;\n                }\n            }\n        } else {\n            while ((int)seq.size() < L0) {\n                for (int d: path) {\n                    seq.push_back(d);\n                    if ((int)seq.size() >= L0) break;\n                }\n            }\n        }\n        return seq;\n    };\n\n    // Buffers used across passes\n    vector<array<double, 400>> g(L0);\n    array<double, 400> gtmp;\n    array<double, 400> vcur, vtmp, vbest;\n\n    auto compute_backward_g_len = [&](const vector<int>& seq, int Len) {\n        // g[Len-1] = (401 - Len) * e_target\n        for (int i = 0; i < N; i++) g[Len-1][i] = 0.0;\n        g[Len-1][t_id] = double(401 - Len);\n        for (int t = Len - 2; t >= 0; t--) {\n            for (int i = 0; i < N; i++) g[t][i] = 0.0;\n            g[t][t_id] = 1.0;\n            int dir_next = seq[t+1];\n            apply_left(dir_next, g[t+1].data(), gtmp.data());\n            for (int i = 0; i < N; i++) g[t][i] += gtmp[i];\n        }\n    };\n\n    auto evaluate_best_prefix = [&](const vector<int>& seq) -> pair<double,int> {\n        for (int i = 0; i < N; i++) vcur[i] = 0.0;\n        vcur[s_id] = 1.0;\n        double sum_prev = 0.0;\n        double best_score = -1e300;\n        int best_len = 1;\n        for (int t = 0; t < L0; t++) {\n            apply_right(seq[t], vcur.data(), vtmp.data());\n            for (int i = 0; i < N; i++) vcur[i] = vtmp[i];\n            double Ft = vcur[t_id];\n            int Lcur = t + 1;\n            double score = sum_prev + (401.0 - Lcur) * Ft;\n            if (score > best_score) {\n                best_score = score;\n                best_len = Lcur;\n            }\n            sum_prev += Ft;\n        }\n        return {best_score, best_len};\n    };\n\n    // Single-step pass\n    auto forward_single_pass = [&](vector<int>& seq, int Len, double TL, double t0) -> bool {\n        compute_backward_g_len(seq, Len);\n        for (int i = 0; i < N; i++) vcur[i] = 0.0;\n        vcur[s_id] = 1.0;\n        bool changed = false;\n        for (int t = 0; t < Len; t++) {\n            int old_dir = seq[t];\n            double best_val = -1e300;\n            int best_dir = old_dir;\n            for (int d = 0; d < 4; d++) {\n                double val = apply_right_and_dot(d, vcur.data(), vtmp.data(), g[t].data());\n                if (val > best_val + 1e-12 || (fabs(val - best_val) <= 1e-12 && d == old_dir)) {\n                    best_val = val;\n                    best_dir = d;\n                    for (int i = 0; i < N; i++) vbest[i] = vtmp[i];\n                }\n            }\n            if (best_dir != old_dir) {\n                changed = true;\n                seq[t] = best_dir;\n            }\n            for (int i = 0; i < N; i++) vcur[i] = vbest[i];\n            if ((t & 31) == 0) {\n                if (now_sec() - t0 > TL) break;\n            }\n        }\n        return changed;\n    };\n\n    // Pair pass\n    auto forward_pair_pass = [&](vector<int>& seq, int Len, double TL, double t0) -> bool {\n        compute_backward_g_len(seq, Len);\n        for (int i = 0; i < N; i++) vcur[i] = 0.0;\n        vcur[s_id] = 1.0;\n        bool changed = false;\n\n        array<array<double,400>,4> X;      // x_a = P^a vcur\n        array<array<double,400>,4> GB;     // gb_b = e_target + (P^b)^T g[t+1]\n\n        int t = 0;\n        while (t < Len) {\n            if ((t & 15) == 0 && now_sec() - t0 > TL) break;\n            if (t == Len - 1) {\n                // Last step: single update\n                int old_dir = seq[t];\n                int best_dir = old_dir;\n                double best_val = -1e-300;\n                for (int d = 0; d < 4; d++) {\n                    double val = apply_right_and_dot(d, vcur.data(), vtmp.data(), g[t].data());\n                    if (val > best_val + 1e-12 || (fabs(val - best_val) <= 1e-12 && d == old_dir)) {\n                        best_val = val;\n                        best_dir = d;\n                        for (int i = 0; i < N; i++) vbest[i] = vtmp[i];\n                    }\n                }\n                if (best_dir != old_dir) { changed = true; seq[t] = best_dir; }\n                for (int i = 0; i < N; i++) vcur[i] = vbest[i];\n                t++;\n                continue;\n            }\n\n            // Precompute X for 4 actions from current vcur\n            for (int a = 0; a < 4; a++) {\n                apply_right(a, vcur.data(), X[a].data());\n            }\n            // Precompute GB for 4 actions based on g[t+1]\n            for (int b = 0; b < 4; b++) {\n                apply_left(b, g[t+1].data(), GB[b].data());\n                GB[b][t_id] += 1.0; // add e_target\n            }\n\n            int old_a = seq[t];\n            int old_b = seq[t+1];\n            int best_a = old_a, best_b = old_b;\n            double best_val = -1e300;\n\n            for (int a = 0; a < 4; a++) {\n                const double* xa = X[a].data();\n                for (int b = 0; b < 4; b++) {\n                    const double* gb = GB[b].data();\n                    double val = 0.0;\n                    for (int i = 0; i < N; i++) val += xa[i] * gb[i];\n                    bool tie_keep = (a == old_a && b == old_b);\n                    if (val > best_val + 1e-12 || (fabs(val - best_val) <= 1e-12 && tie_keep)) {\n                        best_val = val;\n                        best_a = a;\n                        best_b = b;\n                    }\n                }\n            }\n\n            if (best_a != old_a || best_b != old_b) changed = true;\n            seq[t] = best_a;\n            seq[t+1] = best_b;\n\n            const double* v1 = X[best_a].data();\n            apply_right(best_b, v1, vtmp.data());\n            for (int i = 0; i < N; i++) vcur[i] = vtmp[i];\n            t += 2;\n        }\n        // If we broke early due to time, just return whether any change occurred\n        return changed;\n    };\n\n    // Triple pass\n    auto forward_triple_pass = [&](vector<int>& seq, int Len, double TL, double t0) -> bool {\n        compute_backward_g_len(seq, Len);\n        for (int i = 0; i < N; i++) vcur[i] = 0.0;\n        vcur[s_id] = 1.0;\n        bool changed = false;\n\n        array<array<double,400>,4> X;      // x_a = P^a vcur\n        array<array<double,400>,4> Hc;     // Hc[c] = e + (P^c)^T g[t+2]\n        array<array<double,400>,4> GB2c;   // (P^b)^T Hc[c] for current b\n\n        int t = 0;\n        while (t < Len) {\n            if ((t & 7) == 0 && now_sec() - t0 > TL) break;\n            int remain = Len - t;\n            if (remain >= 3) {\n                for (int a = 0; a < 4; a++) {\n                    apply_right(a, vcur.data(), X[a].data());\n                }\n                for (int c = 0; c < 4; c++) {\n                    apply_left(c, g[t+2].data(), Hc[c].data());\n                    Hc[c][t_id] += 1.0;\n                }\n                int old_a = seq[t], old_b = seq[t+1], old_c = seq[t+2];\n                int best_a = old_a, best_b = old_b, best_c = old_c;\n                double best_val = -1e300;\n\n                for (int b = 0; b < 4; b++) {\n                    for (int c = 0; c < 4; c++) {\n                        apply_left(b, Hc[c].data(), GB2c[c].data());\n                    }\n                    for (int a = 0; a < 4; a++) {\n                        const double* xa = X[a].data();\n                        for (int c = 0; c < 4; c++) {\n                            const double* gb = GB2c[c].data();\n                            double val = xa[t_id];\n                            for (int i = 0; i < N; i++) val += xa[i] * gb[i];\n                            bool tie_keep = (a == old_a && b == old_b && c == old_c);\n                            if (val > best_val + 1e-12 || (fabs(val - best_val) <= 1e-12 && tie_keep)) {\n                                best_val = val;\n                                best_a = a; best_b = b; best_c = c;\n                            }\n                        }\n                    }\n                }\n\n                if (best_a != old_a || best_b != old_b || best_c != old_c) changed = true;\n                seq[t] = best_a; seq[t+1] = best_b; seq[t+2] = best_c;\n\n                const double* v1 = X[best_a].data();\n                apply_right(best_b, v1, vtmp.data());\n                array<double,400> v2 = vtmp;\n                apply_right(best_c, v2.data(), vtmp.data());\n                for (int i = 0; i < N; i++) vcur[i] = vtmp[i];\n                t += 3;\n            } else if (remain == 2) {\n                // Do a pair update\n                array<array<double,400>,4> Xloc, GBloc;\n                for (int a = 0; a < 4; a++) apply_right(a, vcur.data(), Xloc[a].data());\n                for (int b = 0; b < 4; b++) { apply_left(b, g[t+1].data(), GBloc[b].data()); GBloc[b][t_id] += 1.0; }\n                int old_a = seq[t], old_b = seq[t+1];\n                int best_a = old_a, best_b = old_b;\n                double best_val = -1e300;\n                for (int a = 0; a < 4; a++) {\n                    const double* xa = Xloc[a].data();\n                    for (int b = 0; b < 4; b++) {\n                        const double* gb = GBloc[b].data();\n                        double val = 0.0;\n                        for (int i = 0; i < N; i++) val += xa[i] * gb[i];\n                        bool tie_keep = (a == old_a && b == old_b);\n                        if (val > best_val + 1e-12 || (fabs(val - best_val) <= 1e-12 && tie_keep)) {\n                            best_val = val;\n                            best_a = a; best_b = b;\n                        }\n                    }\n                }\n                if (best_a != old_a || best_b != old_b) changed = true;\n                seq[t] = best_a; seq[t+1] = best_b;\n                const double* v1 = Xloc[best_a].data();\n                apply_right(best_b, v1, vtmp.data());\n                for (int i = 0; i < N; i++) vcur[i] = vtmp[i];\n                t += 2;\n            } else {\n                // Single update\n                int old_dir = seq[t];\n                int best_dir = old_dir;\n                double best_val = -1e300;\n                for (int d = 0; d < 4; d++) {\n                    double val = apply_right_and_dot(d, vcur.data(), vtmp.data(), g[t].data());\n                    if (val > best_val + 1e-12 || (fabs(val - best_val) <= 1e-12 && d == old_dir)) {\n                        best_val = val;\n                        best_dir = d;\n                        for (int i = 0; i < N; i++) vbest[i] = vtmp[i];\n                    }\n                }\n                if (best_dir != old_dir) { changed = true; seq[t] = best_dir; }\n                for (int i = 0; i < N; i++) vcur[i] = vbest[i];\n                t += 1;\n            }\n        }\n        return changed;\n    };\n\n    // Prepare multiple randomized BFS initial paths\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift rng(seed);\n\n    vector<array<int,4>> orders;\n    array<int,4> base = {0,1,2,3};\n    orders.push_back({0,1,2,3});\n    orders.push_back({1,0,3,2});\n    orders.push_back({2,3,0,1});\n    orders.push_back({3,2,1,0});\n    for (int k = 0; k < 8; k++) {\n        array<int,4> ord = base;\n        for (int i = 3; i > 0; --i) {\n            int j = rng.randint(0, i);\n            swap(ord[i], ord[j]);\n        }\n        orders.push_back(ord);\n    }\n\n    const double TL = 1.95;\n    double t0 = now_sec();\n\n    double global_best_score = -1e300;\n    int global_best_len = L0;\n    vector<int> global_best_seq;\n\n    int restart_idx = 0;\n    while (now_sec() - t0 < TL && restart_idx < (int)orders.size()) {\n        array<int,4> ord = orders[restart_idx++];\n        vector<int> path = bfs_path(ord);\n        vector<int> seq = build_seq_from_path(path);\n\n        auto [best_score_here, best_len_here] = evaluate_best_prefix(seq);\n\n        bool any_improve = true;\n        int iter = 0;\n        while (any_improve && now_sec() - t0 < TL) {\n            any_improve = false;\n\n            bool ch_triple = forward_triple_pass(seq, L0, TL, t0);\n            if (now_sec() - t0 >= TL) break;\n            auto [sc_triple, len_triple] = evaluate_best_prefix(seq);\n            if (sc_triple > best_score_here + 1e-9) {\n                best_score_here = sc_triple;\n                best_len_here = len_triple;\n                any_improve = true;\n            }\n\n            bool ch_pair = forward_pair_pass(seq, L0, TL, t0);\n            if (now_sec() - t0 >= TL) break;\n            auto [sc_pair, len_pair] = evaluate_best_prefix(seq);\n            if (sc_pair > best_score_here + 1e-9) {\n                best_score_here = sc_pair;\n                best_len_here = len_pair;\n                any_improve = true;\n            }\n\n            bool ch_single = forward_single_pass(seq, L0, TL, t0);\n            if (now_sec() - t0 >= TL) break;\n            auto [sc_single, len_single] = evaluate_best_prefix(seq);\n            if (sc_single > best_score_here + 1e-9) {\n                best_score_here = sc_single;\n                best_len_here = len_single;\n                any_improve = true;\n            }\n\n            iter++;\n            if (iter >= 10) break;\n        }\n\n        if (best_score_here > global_best_score + 1e-9) {\n            global_best_score = best_score_here;\n            global_best_len = best_len_here;\n            global_best_seq = seq;\n        }\n    }\n\n    // A few random perturbation restarts near the best found\n    int perturb_trials = 0;\n    while (now_sec() - t0 < TL && perturb_trials < 6 && !global_best_seq.empty()) {\n        perturb_trials++;\n        vector<int> seq = global_best_seq;\n        int K = 6 + rng.randint(0, 8);\n        for (int k = 0; k < K; k++) {\n            int tpos = rng.randint(0, L0 - 1);\n            int ndir = rng.randint(0, 3);\n            seq[tpos] = ndir;\n        }\n        auto [sc0, len0] = evaluate_best_prefix(seq);\n        bool any_improve = true;\n        int iter = 0;\n        while (any_improve && now_sec() - t0 < TL) {\n            any_improve = false;\n\n            bool ch_triple = forward_triple_pass(seq, L0, TL, t0);\n            if (now_sec() - t0 >= TL) break;\n            auto [sc_triple, len_triple] = evaluate_best_prefix(seq);\n            if (sc_triple > sc0 + 1e-9) {\n                sc0 = sc_triple;\n                len0 = len_triple;\n                any_improve = true;\n            }\n\n            bool ch_pair = forward_pair_pass(seq, L0, TL, t0);\n            if (now_sec() - t0 >= TL) break;\n            auto [sc_pair, len_pair] = evaluate_best_prefix(seq);\n            if (sc_pair > sc0 + 1e-9) {\n                sc0 = sc_pair;\n                len0 = len_pair;\n                any_improve = true;\n            }\n\n            bool ch_single = forward_single_pass(seq, L0, TL, t0);\n            if (now_sec() - t0 >= TL) break;\n            auto [sc_single, len_single] = evaluate_best_prefix(seq);\n            if (sc_single > sc0 + 1e-9) {\n                sc0 = sc_single;\n                len0 = len_single;\n                any_improve = true;\n            }\n\n            iter++;\n            if (iter >= 8) break;\n        }\n        if (sc0 > global_best_score + 1e-9) {\n            global_best_score = sc0;\n            global_best_len = len0;\n            global_best_seq = seq;\n        }\n    }\n\n    // Final refinement under the best chosen prefix length (align weights with final objective)\n    if (!global_best_seq.empty() && now_sec() - t0 < TL) {\n        int Len = global_best_len;\n        for (int it = 0; it < 3 && now_sec() - t0 < TL; it++) {\n            bool ch = forward_triple_pass(global_best_seq, Len, TL, t0);\n            auto [scp, lnp] = evaluate_best_prefix(global_best_seq);\n            if (scp > global_best_score + 1e-9) {\n                global_best_score = scp;\n                global_best_len = lnp;\n                Len = lnp;\n            }\n            if (now_sec() - t0 >= TL) break;\n            ch = forward_pair_pass(global_best_seq, Len, TL, t0);\n            auto [sc2, ln2] = evaluate_best_prefix(global_best_seq);\n            if (sc2 > global_best_score + 1e-9) {\n                global_best_score = sc2;\n                global_best_len = ln2;\n                Len = ln2;\n            }\n            if (now_sec() - t0 >= TL) break;\n            ch = forward_single_pass(global_best_seq, Len, TL, t0);\n            auto [sc3, ln3] = evaluate_best_prefix(global_best_seq);\n            if (sc3 > global_best_score + 1e-9) {\n                global_best_score = sc3;\n                global_best_len = ln3;\n                Len = ln3;\n            }\n        }\n    }\n\n    if (global_best_seq.empty()) {\n        vector<int> path = bfs_path({0,1,2,3});\n        global_best_seq = build_seq_from_path(path);\n        auto [scb, lnb] = evaluate_best_prefix(global_best_seq);\n        global_best_len = lnb;\n    }\n\n    // Output best prefix\n    string out;\n    int out_len = max(1, min(global_best_len, L0));\n    out.reserve(out_len);\n    for (int i = 0; i < out_len; i++) out.push_back(DIRC[global_best_seq[i]]);\n    cout << out << \"\\n\";\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const { return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count(); }\n};\n\n// RNG\nstruct XorShift {\n    uint64_t x;\n    XorShift() { x = 88172645463393265ull; }\n    void reseed(uint64_t s) {\n        if (s == 0) s = 88172645463393265ull;\n        x = s ^ (s << 13) ^ (s >> 7) ^ (s << 17);\n        if (x == 0) x = 88172645463393265ull;\n    }\n    inline uint64_t next() { x ^= x << 7; x ^= x << 13; x ^= x >> 9; return x; }\n    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline int randint(int l, int r) { return l + (int)(next_u32() % (uint32_t)(r - l + 1)); }\n    inline double rand01() { return (next_u32() & 0xFFFFFF) / double(0x1000000); }\n} rng;\n\n// Directions: 0=left,1=up,2=right,3=down\nstatic const int di[4] = {0,-1,0,1};\nstatic const int dj[4] = {-1,0,1,0};\n\n// to[t][d] as in statement\nstatic const int TO[8][4] = {\n    {1, 0, -1, -1},\n    {3, -1, -1, 0},\n    {-1, -1, 3, 2},\n    {-1, 2, 1, -1},\n    {1, 0, 3, 2},\n    {3, 2, 1, 0},\n    {2, -1, 0, -1},\n    {-1, 3, -1, 1},\n};\n\n// Presence and helpers\nstatic bool PRES[8][4];\nstatic int OUT_COUNT_TO[8][4];\nstatic bool EXIST_OUT[8][4];\n\n// rotate mapping\ninline int rotate_t(int t, int r) {\n    if (t < 4) return (t + r) & 3;\n    if (t < 6) return (r & 1) ? 9 - t : t; // 4<->5 on odd\n    return (r & 1) ? 13 - t : t;           // 6<->7 on odd\n}\n\nstatic inline int state_id(int i, int j, int d) {\n    return ((i * 30 + j) << 2) | d;\n}\n\nstruct LoopEval {\n    long long L1=0, L2=0;\n    long long sumCycles=0;\n    int cycleCount=0;\n    long long product() const { return (L2==0 ? 0LL : L1*L2); }\n};\n\n// Efficient loop evaluator: returns top two cycle lengths, sum of all cycle lengths, and cycle count\nLoopEval evaluate_loops(const array<array<int,30>,30>& eff) {\n    const int N=30, M=30, TOT=N*M*4;\n    static int next_state[30*30*4];\n    static unsigned char allowed[30*30*4];\n    for (int i=0;i<N;i++){\n        for (int j=0;j<M;j++){\n            int t = eff[i][j];\n            for (int d=0; d<4; d++){\n                int idx = state_id(i,j,d);\n                int d2 = TO[t][d];\n                if (d2 == -1) {\n                    allowed[idx] = 0;\n                    next_state[idx] = -1;\n                    continue;\n                }\n                allowed[idx] = 1;\n                int i2 = i + di[d2], j2 = j + dj[d2];\n                if (i2 < 0 || i2 >= N || j2 < 0 || j2 >= M) {\n                    next_state[idx] = -1;\n                } else {\n                    int t2 = eff[i2][j2];\n                    int d_rev = (d2 + 2) & 3;\n                    if (TO[t2][d_rev] == -1) next_state[idx] = -1;\n                    else next_state[idx] = state_id(i2,j2,d_rev);\n                }\n            }\n        }\n    }\n\n    static unsigned char visited[30*30*4];\n    static int seen_pass[30*30*4];\n    static int seen_pos[30*30*4];\n    memset(visited, 0, sizeof(visited));\n    int pass_id = 1;\n    long long best1=0, best2=0, sumC=0;\n    int cntC = 0;\n    int stack_arr[30*30*4];\n\n    for (int v0=0; v0<TOT; v0++){\n        if (!allowed[v0] || visited[v0]) continue;\n        int v = v0;\n        int top = 0;\n        ++pass_id;\n        while (true) {\n            if (v < 0 || !allowed[v] || next_state[v] == -1) {\n                while (top) visited[stack_arr[--top]] = 1;\n                break;\n            }\n            if (visited[v]) {\n                while (top) visited[stack_arr[--top]] = 1;\n                break;\n            }\n            if (seen_pass[v] == pass_id) {\n                int cycle_len = top - seen_pos[v];\n                long long L = cycle_len;\n                sumC += L;\n                cntC += 1;\n                if (L > best1) { best2 = best1; best1 = L; }\n                else if (L > best2) { best2 = L; }\n                while (top) visited[stack_arr[--top]] = 1;\n                break;\n            }\n            seen_pass[v] = pass_id;\n            seen_pos[v] = top;\n            stack_arr[top++] = v;\n            v = next_state[v];\n        }\n    }\n    LoopEval le; le.L1=best1; le.L2=best2; le.sumCycles = sumC; le.cycleCount = cntC;\n    return le;\n}\n\n// Score2: number of valid next transitions (i,j,d) that lead to in-bounds neighbor accepting entry.\nstruct Score2 {\n    int N=30, M=30;\n    inline int count_outgoing(const array<array<int,30>,30>& eff, int i, int j, int t) const {\n        int s=0;\n        for (int d=0; d<4; d++){\n            int d2 = TO[t][d];\n            if (d2 == -1) continue;\n            int i2 = i + di[d2], j2 = j + dj[d2];\n            if (i2 < 0 || i2 >= N || j2 < 0 || j2 >= M) continue;\n            int t2 = eff[i2][j2];\n            int d_rev = (d2 + 2) & 3;\n            if (TO[t2][d_rev] != -1) s++;\n        }\n        return s;\n    }\n    long long compute_all(const array<array<int,30>,30>& eff) const {\n        long long s=0;\n        for (int i=0;i<N;i++) for (int j=0;j<M;j++) s += count_outgoing(eff, i, j, eff[i][j]);\n        return s;\n    }\n    long long delta_change(const array<array<int,30>,30>& eff, int i, int j, int curT, int newT) const {\n        long long delta = 0;\n        delta += count_outgoing(eff, i, j, newT) - count_outgoing(eff, i, j, curT);\n        if (j-1 >= 0) {\n            int tL = eff[i][j-1];\n            int c = OUT_COUNT_TO[tL][2];\n            delta += c * ( (PRES[newT][0] ? 1:0) - (PRES[curT][0] ? 1:0) );\n        }\n        if (j+1 < M) {\n            int tR = eff[i][j+1];\n            int c = OUT_COUNT_TO[tR][0];\n            delta += c * ( (PRES[newT][2] ? 1:0) - (PRES[curT][2] ? 1:0) );\n        }\n        if (i-1 >= 0) {\n            int tU = eff[i-1][j];\n            int c = OUT_COUNT_TO[tU][3];\n            delta += c * ( (PRES[newT][1] ? 1:0) - (PRES[curT][1] ? 1:0) );\n        }\n        if (i+1 < N) {\n            int tD = eff[i+1][j];\n            int c = OUT_COUNT_TO[tD][1];\n            delta += c * ( (PRES[newT][3] ? 1:0) - (PRES[curT][3] ? 1:0) );\n        }\n        return delta;\n    }\n};\n\n// Boundary-friendly rotation\nstatic int boundary_friendly_rotation(int base_t, int i, int j) {\n    const int N=30, M=30;\n    int bestR = 0, bestBad = 1e9;\n    for (int r=0; r<4; r++){\n        int tt = rotate_t(base_t, r);\n        int bad = 0;\n        if (i==0 && PRES[tt][1]) bad++;\n        if (i==N-1 && PRES[tt][3]) bad++;\n        if (j==0 && PRES[tt][0]) bad++;\n        if (j==M-1 && PRES[tt][2]) bad++;\n        if (bad < bestBad) { bestBad = bad; bestR = r; }\n    }\n    return bestR;\n}\n\n// Count invalid exits for tile (focus metric for SA)\ninline int count_invalid_exits(const array<array<int,30>,30>& eff, int i, int j) {\n    const int N=30, M=30;\n    int t = eff[i][j];\n    int bad = 0;\n    for (int d=0; d<4; d++){\n        int d2 = TO[t][d];\n        if (d2 == -1) continue;\n        int i2 = i + di[d2], j2 = j + dj[d2];\n        if (i2 < 0 || i2 >= N || j2 < 0 || j2 >= M) { bad++; continue; }\n        int t2 = eff[i2][j2];\n        int d_rev = (d2 + 2) & 3;\n        if (TO[t2][d_rev] == -1) bad++;\n    }\n    return bad;\n}\n\n// 2x2 block improvement under S2\nvoid improve_blocks_2x2(array<array<int,30>,30>& eff, array<array<int,30>,30>& rot,\n                        const array<array<int,30>,30>& base, Score2& scorer2,\n                        long long& S2, double end_time, Timer& timer) {\n    const int N=30, M=30;\n    vector<pair<int,int>> blocks;\n    blocks.reserve((N-1)*(M-1));\n    for (int i=0;i<N-1;i++) for (int j=0;j<M-1;j++) blocks.emplace_back(i,j);\n    shuffle(blocks.begin(), blocks.end(), std::mt19937(rng.next_u32()));\n    for (auto &p : blocks) {\n        if (timer.elapsed() > end_time) break;\n        int si = p.first, sj = p.second;\n        for (int sweep=0;sweep<2;sweep++) {\n            bool improved=false;\n            for (int k=0;k<4;k++){\n                int i = si + (k>>1);\n                int j = sj + (k&1);\n                int base_t = base[i][j];\n                int curR = rot[i][j];\n                int curT = eff[i][j];\n                long long bestDelta = 0;\n                int bestR = curR;\n                for (int r=0;r<4;r++){\n                    if (r == curR) continue;\n                    int newT = rotate_t(base_t, r);\n                    long long delta = scorer2.delta_change(eff, i, j, curT, newT);\n                    if (delta > bestDelta) {\n                        bestDelta = delta; bestR = r;\n                    }\n                }\n                if (bestR != curR) {\n                    int newT = rotate_t(base_t, bestR);\n                    S2 += scorer2.delta_change(eff, i, j, curT, newT);\n                    rot[i][j] = bestR;\n                    eff[i][j] = newT;\n                    improved = true;\n                }\n            }\n            if (!improved) break;\n        }\n    }\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Precompute PRES, OUT_COUNT_TO, EXIST_OUT\n    for (int t=0;t<8;t++){\n        for (int d=0; d<4; d++){\n            PRES[t][d] = (TO[t][d] != -1);\n        }\n        for (int dir=0; dir<4; dir++){\n            int c=0;\n            for (int d=0; d<4; d++) if (TO[t][d] == dir) c++;\n            OUT_COUNT_TO[t][dir] = c;\n            EXIST_OUT[t][dir] = (c > 0);\n        }\n    }\n\n    const int N=30, M=30;\n    array<array<int,30>,30> base{};\n    for (int i=0;i<N;i++){\n        string s; if(!(cin>>s)) return 0;\n        for (int j=0;j<M;j++){\n            base[i][j] = s[j]-'0';\n        }\n    }\n\n    // Deterministic RNG seed from input grid\n    {\n        uint64_t h = 1469598103934665603ull; // FNV offset\n        for (int i=0;i<N;i++) for (int j=0;j<M;j++) {\n            h ^= (uint64_t)base[i][j];\n            h *= 1099511628211ull;\n        }\n        rng.reseed(h);\n    }\n\n    Timer timer;\n    const double TIME_LIMIT = 1.98;\n\n    array<array<int,30>,30> rot{};\n    array<array<int,30>,30> eff{};\n\n    // Initialize rotations: boundary-friendly with mild randomness\n    for (int i=0;i<N;i++){\n        for (int j=0;j<M;j++){\n            int t0 = base[i][j];\n            int rr = boundary_friendly_rotation(t0, i, j);\n            if (rng.rand01() < 0.4) rr = (rr + rng.randint(0,3)) & 3;\n            rot[i][j] = rr;\n            eff[i][j] = rotate_t(t0, rr);\n        }\n    }\n\n    // Phase 1: Coordinate ascent on S2 (~0.52s)\n    Score2 scorer2;\n    long long S2 = scorer2.compute_all(eff);\n    {\n        vector<pair<int,int>> order;\n        order.reserve(N*M);\n        for (int i=0;i<N;i++) for (int j=0;j<M;j++) order.emplace_back(i,j);\n        double t_end = min(0.55, TIME_LIMIT * 0.52);\n        while (timer.elapsed() < t_end) {\n            shuffle(order.begin(), order.end(), std::mt19937(rng.next_u32()));\n            bool improved_any = false;\n            for (auto &p : order) {\n                int i = p.first, j = p.second;\n                int base_t = base[i][j];\n                int curR = rot[i][j];\n                int curT = eff[i][j];\n                long long bestDelta = 0;\n                int bestR = curR;\n                for (int r=0;r<4;r++){\n                    if (r == curR) continue;\n                    int newT = rotate_t(base_t, r);\n                    long long delta = scorer2.delta_change(eff, i, j, curT, newT);\n                    if (delta > bestDelta || (delta == bestDelta && rng.rand01() < 0.1)) {\n                        bestDelta = delta; bestR = r;\n                    }\n                }\n                if (bestR != curR) {\n                    int newT = rotate_t(base_t, bestR);\n                    S2 += scorer2.delta_change(eff, i, j, curT, newT);\n                    rot[i][j] = bestR;\n                    eff[i][j] = newT;\n                    improved_any = true;\n                }\n                if (timer.elapsed() >= t_end) break;\n            }\n            if (!improved_any) break;\n        }\n        // Quick pass for straights: toggle if improves S2\n        for (int i=0;i<N;i++){\n            for (int j=0;j<M;j++){\n                int t0 = base[i][j];\n                int curR = rot[i][j];\n                int curT = eff[i][j];\n                if (t0 >= 6) {\n                    int newR = (curR ^ 1) & 3;\n                    int newT = rotate_t(t0, newR);\n                    long long delta = scorer2.delta_change(eff, i, j, curT, newT);\n                    if (delta > 0) {\n                        S2 += delta;\n                        rot[i][j] = newR;\n                        eff[i][j] = newT;\n                    }\n                }\n            }\n        }\n    }\n\n    // Phase 1.5: 2x2 block local improvements (~0.06s)\n    {\n        double t_budget = min(0.06, TIME_LIMIT * 0.03);\n        improve_blocks_2x2(eff, rot, base, scorer2, S2, timer.elapsed() + t_budget, timer);\n    }\n\n    // Initial loop evaluation\n    LoopEval initEval = evaluate_loops(eff);\n    long long bestProduct = initEval.product();\n    auto bestRot = rot;\n    auto bestEff = eff;\n\n    // Shaped objective with decay\n    auto shapedF = [&](const LoopEval& le, double a, double b, double c)->double {\n        return (double)le.product() + a * (double)min(le.L1, le.L2) + b * (double)(le.L1 + le.L2) - c * (double)le.cycleCount;\n    };\n\n    // Tournament helper for picking problematic tiles\n    auto pick_problem_tile = [&](const array<array<int,30>,30>& effCur, int K, bool allow_random)->pair<int,int>{\n        if (allow_random && rng.rand01() < 0.1) return {rng.randint(0,N-1), rng.randint(0,M-1)};\n        int bi=-1, bj=-1, bbad=-1;\n        for (int k=0;k<K;k++){\n            int ci = rng.randint(0,N-1), cj = rng.randint(0,M-1);\n            int bad = count_invalid_exits(effCur, ci, cj);\n            if (bad > bbad || (bad == bbad && rng.rand01() < 0.5)) { bbad = bad; bi = ci; bj = cj; }\n        }\n        if (bi<0) { bi=rng.randint(0,N-1); bj=rng.randint(0,M-1); }\n        return {bi,bj};\n    };\n\n    // SA total time budget\n    double used = timer.elapsed();\n    double SA_TIME = TIME_LIMIT - used - 0.05;\n    if (SA_TIME < 0.0) SA_TIME = 0.0;\n\n    if (SA_TIME > 0.01) {\n        auto currRot = rot;\n        auto currEff = eff;\n        long long S2cur = S2;\n\n        LoopEval leCur = initEval;\n        long long curProd = leCur.product();\n        double currF = shapedF(leCur, 3.0, 0.2, 0.8);\n\n        double t0 = timer.elapsed();\n        double startT = 7.0, endT = 0.03;\n\n        while (true) {\n            double e = timer.elapsed() - t0;\n            if (e >= SA_TIME) break;\n            double progress = e / SA_TIME;\n            double T = startT + (endT - startT) * progress;\n            double a = 3.0 * (1.0 - progress);\n            double b = 0.2 * (1.0 - progress);\n            double c = 0.8 * (1.0 - progress);\n\n            double r = rng.rand01();\n            bool moved = false;\n\n            if (r < 0.25) {\n                // Targeted adjacency-fix: pick broken edge\n                auto [i1, j1] = pick_problem_tile(currEff, 6, true);\n                int tt1 = currEff[i1][j1];\n\n                int candDirs[4], cnt=0;\n                for (int d=0; d<4; d++){\n                    int d2 = TO[tt1][d];\n                    if (d2 == -1) continue;\n                    int i2 = i1 + di[d2], j2 = j1 + dj[d2];\n                    if (i2 < 0 || i2 >= N || j2 < 0 || j2 >= M) continue;\n                    int tt2 = currEff[i2][j2];\n                    int d_rev = (d2 + 2) & 3;\n                    if (TO[tt2][d_rev] == -1) candDirs[cnt++] = d2;\n                }\n                if (cnt > 0) {\n                    int d2 = candDirs[rng.randint(0, cnt-1)];\n                    int i2 = i1 + di[d2], j2 = j1 + dj[d2];\n                    int t2 = base[i2][j2];\n                    int oldR2 = currRot[i2][j2];\n                    int oldT2 = currEff[i2][j2];\n                    int d_rev = (d2 + 2) & 3;\n\n                    // Choose neighbor rotation that accepts d_rev with best S2 delta\n                    int bestR2 = -1;\n                    long long bestDeltaS2 = LLONG_MIN;\n                    for (int r2=0;r2<4;r2++){\n                        int nt2 = rotate_t(t2, r2);\n                        if (TO[nt2][d_rev] == -1) continue;\n                        long long delta = scorer2.delta_change(currEff, i2, j2, oldT2, nt2);\n                        if (delta > bestDeltaS2) { bestDeltaS2 = delta; bestR2 = r2; }\n                    }\n                    if (bestR2 != -1) {\n                        // S2 pre-filter: if very bad, skip with high probability\n                        if (bestDeltaS2 < -2 && rng.rand01() < 0.9) { /* skip */ }\n                        else {\n                            int newR2 = bestR2;\n                            int newT2 = rotate_t(t2, newR2);\n                            currRot[i2][j2] = newR2;\n                            currEff[i2][j2] = newT2;\n\n                            LoopEval le = evaluate_loops(currEff);\n                            double newF = shapedF(le, a, b, c);\n                            double diff = newF - currF;\n                            bool accept = diff >= 0 || rng.rand01() < exp(diff / max(1.0, T));\n                            if (accept) {\n                                currF = newF; leCur = le; curProd = le.product();\n                                S2cur += scorer2.delta_change(currEff, i2, j2, oldT2, newT2); // recompute for robustness\n                                if (curProd > bestProduct) { bestProduct = curProd; bestRot = currRot; bestEff = currEff; }\n                            } else {\n                                // Try both-tiles move on same edge (best S2 pair)\n                                int t1 = base[i1][j1];\n                                int oldR1 = currRot[i1][j1];\n                                int oldT1 = currEff[i1][j1];\n                                long long bestPairDelta = LLONG_MIN;\n                                int bestR1p = -1, bestR2p = -1;\n\n                                // Compute exact S2 delta sequentially for pre-filter\n                                for (int r1=0;r1<4;r1++){\n                                    int nt1 = rotate_t(t1, r1);\n                                    if (!EXIST_OUT[nt1][d2]) continue;\n                                    // delta1\n                                    long long d1 = scorer2.delta_change(currEff, i1, j1, oldT1, nt1);\n                                    // apply nt1 temporarily\n                                    currEff[i1][j1] = nt1;\n                                    for (int r2=0;r2<4;r2++){\n                                        int nt2 = rotate_t(t2, r2);\n                                        if (TO[nt2][d_rev] == -1) continue;\n                                        long long d2s = scorer2.delta_change(currEff, i2, j2, oldT2, nt2);\n                                        long long dsum = d1 + d2s;\n                                        if (dsum > bestPairDelta) {\n                                            bestPairDelta = dsum; bestR1p = r1; bestR2p = r2;\n                                        }\n                                    }\n                                    currEff[i1][j1] = oldT1;\n                                }\n                                if (bestR1p != -1) {\n                                    // S2 pre-filter\n                                    if (bestPairDelta < -2 && rng.rand01() < 0.9) {\n                                        currRot[i2][j2] = oldR2; currEff[i2][j2] = oldT2;\n                                    } else {\n                                        int newR1 = bestR1p, newR2b = bestR2p;\n                                        int newT1 = rotate_t(t1, newR1), newT2b = rotate_t(t2, newR2b);\n                                        currRot[i1][j1] = newR1; currEff[i1][j1] = newT1;\n                                        currRot[i2][j2] = newR2b; currEff[i2][j2] = newT2b;\n                                        LoopEval le2 = evaluate_loops(currEff);\n                                        double newF2 = shapedF(le2, a, b, c);\n                                        double diff2 = newF2 - currF;\n                                        bool accept2 = diff2 >= 0 || rng.rand01() < exp(diff2 / max(1.0, T));\n                                        if (accept2) {\n                                            currF = newF2; leCur = le2; curProd = le2.product();\n                                            // update S2cur exactly\n                                            S2cur += scorer2.delta_change(currEff, i1, j1, oldT1, newT1);\n                                            S2cur += scorer2.delta_change(currEff, i2, j2, oldT2, newT2b);\n                                            if (curProd > bestProduct) { bestProduct = curProd; bestRot = currRot; bestEff = currEff; }\n                                        } else {\n                                            currRot[i1][j1] = oldR1; currEff[i1][j1] = oldT1;\n                                            currRot[i2][j2] = oldR2; currEff[i2][j2] = oldT2;\n                                        }\n                                    }\n                                } else {\n                                    currRot[i2][j2] = oldR2; currEff[i2][j2] = oldT2;\n                                }\n                            }\n                            moved = true;\n                        }\n                    }\n                }\n            } else if (r < 0.5) {\n                // Two-tile neighbor move\n                auto [i1, j1] = pick_problem_tile(currEff, 6, true);\n                int dir = rng.randint(0,3);\n                int i2 = i1 + di[dir], j2 = j1 + dj[dir];\n                if (i2>=0 && i2<N && j2>=0 && j2<M) {\n                    int t1 = base[i1][j1], t2 = base[i2][j2];\n                    int oldR1 = currRot[i1][j1], oldR2 = currRot[i2][j2];\n                    int newR1 = (oldR1 + rng.randint(1,3)) & 3;\n                    int newR2 = (oldR2 + rng.randint(1,3)) & 3;\n                    if (newR1 == oldR1) newR1 = (newR1 + 1) & 3;\n                    if (newR2 == oldR2) newR2 = (newR2 + 1) & 3;\n                    int oldT1 = currEff[i1][j1], oldT2 = currEff[i2][j2];\n                    int newT1 = rotate_t(t1, newR1), newT2 = rotate_t(t2, newR2);\n\n                    // Pre-filter using S2 delta (exact sequentially)\n                    long long d1 = scorer2.delta_change(currEff, i1, j1, oldT1, newT1);\n                    currEff[i1][j1] = newT1;\n                    long long d2 = scorer2.delta_change(currEff, i2, j2, oldT2, newT2);\n                    currEff[i1][j1] = oldT1;\n                    long long s2delta = d1 + d2;\n                    if (s2delta < -2 && rng.rand01() < 0.9) {\n                        // skip\n                    } else {\n                        currRot[i1][j1] = newR1; currEff[i1][j1] = newT1;\n                        currRot[i2][j2] = newR2; currEff[i2][j2] = newT2;\n\n                        LoopEval le = evaluate_loops(currEff);\n                        double newF = shapedF(le, a, b, c);\n                        double diff = newF - currF;\n                        bool accept = diff >= 0 || rng.rand01() < exp(diff / max(1.0, T));\n                        if (accept) {\n                            currF = newF; leCur = le; curProd = le.product();\n                            // update S2cur\n                            S2cur += scorer2.delta_change(currEff, i1, j1, oldT1, newT1);\n                            S2cur += scorer2.delta_change(currEff, i2, j2, oldT2, newT2);\n                            if (curProd > bestProduct) { bestProduct = curProd; bestRot = currRot; bestEff = currEff; }\n                        } else {\n                            currRot[i1][j1] = oldR1; currEff[i1][j1] = oldT1;\n                            currRot[i2][j2] = oldR2; currEff[i2][j2] = oldT2;\n                        }\n                        moved = true;\n                    }\n                }\n            }\n\n            if (!moved) {\n                // Single-tile move with tournament selection (some randomness)\n                auto [i, j] = pick_problem_tile(currEff, 6, true);\n                int tbase = base[i][j];\n                int oldR = currRot[i][j];\n                int newR = (oldR + rng.randint(1,3)) & 3;\n                if (newR == oldR) newR = (newR + 1) & 3;\n                int oldT = currEff[i][j];\n                int newT = rotate_t(tbase, newR);\n\n                long long s2delta = scorer2.delta_change(currEff, i, j, oldT, newT);\n                if (s2delta < -1 && rng.rand01() < 0.9) {\n                    // skip obviously bad move\n                    continue;\n                }\n\n                currRot[i][j] = newR;\n                currEff[i][j] = newT;\n\n                LoopEval le = evaluate_loops(currEff);\n                double newF = shapedF(le, a, b, c);\n                double diff = newF - currF;\n\n                bool accept = diff >= 0 || rng.rand01() < exp(diff / max(1.0, T));\n                if (accept) {\n                    currF = newF; leCur = le; curProd = le.product();\n                    S2cur += scorer2.delta_change(currEff, i, j, oldT, newT);\n                    if (curProd > bestProduct) { bestProduct = curProd; bestRot = currRot; bestEff = currEff; }\n                } else {\n                    currRot[i][j] = oldR;\n                    currEff[i][j] = oldT;\n                }\n            }\n        }\n        // Update to best found\n        rot = bestRot;\n        eff = bestEff;\n    }\n\n    // Greedy tail: few improving single flips if time remains\n    if (timer.elapsed() < TIME_LIMIT - 0.015) {\n        auto currRot = bestRot;\n        auto currEff = bestEff;\n        LoopEval leBest = evaluate_loops(currEff);\n        long long currSc = leBest.product();\n        int trials = 600;\n        for (int t=0; t<trials; ++t) {\n            if (timer.elapsed() >= TIME_LIMIT - 0.01) break;\n            int bi=-1, bj=-1, bbad=-1;\n            const int K=4;\n            for (int k=0;k<K;k++){\n                int ci = rng.randint(0,N-1), cj = rng.randint(0,M-1);\n                int bad = count_invalid_exits(currEff, ci, cj);\n                if (bad > bbad || (bad == bbad && rng.rand01() < 0.5)) { bbad = bad; bi = ci; bj = cj; }\n            }\n            if (bi<0) { bi=rng.randint(0,N-1); bj=rng.randint(0,M-1); }\n            int i=bi,j=bj;\n            int base_t = base[i][j];\n            int curR = currRot[i][j];\n            int bestR = curR;\n            int bestT = currEff[i][j];\n            long long bestLocalSc = currSc;\n\n            for (int r=0;r<4;r++){\n                if (r == curR) continue;\n                int newT = rotate_t(base_t, r);\n                auto saveT = currEff[i][j];\n                currEff[i][j] = newT;\n                long long sc = evaluate_loops(currEff).product();\n                if (sc > bestLocalSc) {\n                    bestLocalSc = sc; bestR = r; bestT = newT;\n                }\n                currEff[i][j] = saveT;\n            }\n            if (bestLocalSc > currSc) {\n                currSc = bestLocalSc;\n                currRot[i][j] = bestR;\n                currEff[i][j] = bestT;\n            }\n        }\n        if (currSc > bestProduct) {\n            bestProduct = currSc;\n            bestRot = currRot;\n            bestEff = currEff;\n        }\n    }\n\n    // Output best rotations\n    {\n        string out;\n        out.reserve(N*M);\n        for (int i=0;i<N;i++){\n            for (int j=0;j<M;j++){\n                out.push_back(char('0' + bestRot[i][j]));\n            }\n        }\n        cout << out << \"\\n\";\n    }\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\n// High resolution timer\nstatic inline double now_sec() {\n    using clk = chrono::high_resolution_clock;\n    return chrono::duration<double>(clk::now().time_since_epoch()).count();\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n_) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        p.resize(n);\n        sz.assign(n, 0);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Eval {\n    int largestTree = 0;\n    int largestCC = 0;\n    int cyclesInLargestCC = 0;\n    int totalEdges = 0;\n    int loops2x2 = 0;\n    int cyclesTotal = 0;\n    int treePotential = 0; // largestCC - cyclesInLargestCC\n};\n\nstruct ScoreKey {\n    // Larger is better.\n    int largestTree;\n    int novelty;             // 1 if not visited recently, 0 if repeated\n    int treePotential;\n    int negCyclesTotal;\n    int largestCC;\n    int negCyclesInLargestCC;\n    int totalEdges;\n    int negLoops2x2;\n    uint32_t tieRand;\n};\n\nstatic inline bool better_key(const ScoreKey& a, const ScoreKey& b) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.novelty != b.novelty) return a.novelty > b.novelty;\n    if (a.treePotential != b.treePotential) return a.treePotential > b.treePotential;\n    if (a.negCyclesTotal != b.negCyclesTotal) return a.negCyclesTotal > b.negCyclesTotal;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.negCyclesInLargestCC != b.negCyclesInLargestCC) return a.negCyclesInLargestCC > b.negCyclesInLargestCC;\n    if (a.totalEdges != b.totalEdges) return a.totalEdges > b.totalEdges;\n    if (a.negLoops2x2 != b.negLoops2x2) return a.negLoops2x2 > b.negLoops2x2;\n    return a.tieRand < b.tieRand; // final tie-break\n}\n\nstatic inline int hexchar_to_int(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    if ('a' <= c && c <= 'f') return 10 + (c - 'a');\n    if ('A' <= c && c <= 'F') return 10 + (c - 'A');\n    return 0;\n}\n\nstruct Board {\n    int N;\n    vector<int> a; // size N*N, 0 is empty\n    int zr, zc;\n\n    inline bool in_bounds(int r, int c) const {\n        return (0 <= r && r < N && 0 <= c && c < N);\n    }\n};\n\nstruct Evaluator {\n    int N, n2;\n    DSU dsu;\n    vector<char> occ;\n    vector<int> deg;         // degree per vertex in matched graph\n    vector<int> compDegSum;  // sum of deg per component\n\n    Evaluator() {}\n    Evaluator(int N_) { init(N_); }\n    void init(int N_) {\n        N = N_; n2 = N*N;\n        dsu.init(n2);\n        occ.assign(n2, 0);\n        deg.assign(n2, 0);\n        compDegSum.assign(n2, 0);\n    }\n\n    Eval evaluate(const Board& B) {\n        const int L = 1, U = 2, R = 4, D = 8;\n        // reset\n        fill(occ.begin(), occ.end(), 0);\n        fill(deg.begin(), deg.end(), 0);\n        iota(dsu.p.begin(), dsu.p.end(), 0);\n        fill(dsu.sz.begin(), dsu.sz.end(), 0);\n\n        // mark occupied and init DSU sizes\n        for (int i = 0; i < N; ++i) {\n            int base = i * N;\n            for (int j = 0; j < N; ++j) {\n                int id = base + j;\n                if (B.a[id] != 0) {\n                    occ[id] = 1;\n                    dsu.sz[id] = 1;\n                }\n            }\n        }\n\n        int totalEdges = 0;\n        // Unite along matched edges and accumulate degrees\n        // Vertical\n        for (int i = 0; i < N-1; ++i) {\n            int base = i * N;\n            int base2 = (i+1) * N;\n            for (int j = 0; j < N; ++j) {\n                int id1 = base + j;\n                int id2 = base2 + j;\n                int m1 = B.a[id1], m2 = B.a[id2];\n                if ((m1 & D) && (m2 & U)) {\n                    totalEdges++;\n                    deg[id1]++; deg[id2]++;\n                    if (occ[id1] && occ[id2]) dsu.unite(id1, id2);\n                }\n            }\n        }\n        // Horizontal\n        for (int i = 0; i < N; ++i) {\n            int base = i * N;\n            for (int j = 0; j < N-1; ++j) {\n                int id1 = base + j;\n                int id2 = base + (j+1);\n                int m1 = B.a[id1], m2 = B.a[id2];\n                if ((m1 & R) && (m2 & L)) {\n                    totalEdges++;\n                    deg[id1]++; deg[id2]++;\n                    if (occ[id1] && occ[id2]) dsu.unite(id1, id2);\n                }\n            }\n        }\n\n        // Count 2x2 loops\n        int loops2x2 = 0;\n        for (int i = 0; i < N-1; ++i) {\n            int base = i * N;\n            int base2 = (i+1) * N;\n            for (int j = 0; j < N-1; ++j) {\n                int id00 = base + j;\n                int id01 = base + (j+1);\n                int id10 = base2 + j;\n                int id11 = base2 + (j+1);\n                int m00 = B.a[id00], m01 = B.a[id01], m10 = B.a[id10], m11 = B.a[id11];\n                bool v1 = (m00 & 8) && (m10 & 2);\n                bool v2 = (m01 & 8) && (m11 & 2);\n                bool h1 = (m00 & 4) && (m01 & 1);\n                bool h2 = (m10 & 4) && (m11 & 1);\n                if (v1 && v2 && h1 && h2) loops2x2++;\n            }\n        }\n\n        // Sum degrees per component\n        fill(compDegSum.begin(), compDegSum.end(), 0);\n        for (int id = 0; id < n2; ++id) {\n            if (!occ[id]) continue;\n            int r = dsu.find(id);\n            compDegSum[r] += deg[id];\n        }\n\n        int largestCC = 0;\n        int largestTree = 0;\n        int cyclesInLargestCC = 0;\n        int cyclesTotal = 0;\n\n        vector<char> seen(n2, 0);\n        for (int id = 0; id < n2; ++id) {\n            if (!occ[id]) continue;\n            int r = dsu.find(id);\n            if (seen[r]) continue;\n            seen[r] = 1;\n            int V = dsu.sz[r];\n            int E = compDegSum[r] / 2; // edges counted twice in deg sum\n            int cyc = E - (V - 1);\n            if (V > largestCC) {\n                largestCC = V;\n                cyclesInLargestCC = max(0, cyc);\n            } else if (V == largestCC) {\n                cyclesInLargestCC = min(cyclesInLargestCC, max(0, cyc));\n            }\n            if (E == V - 1) {\n                if (V > largestTree) largestTree = V;\n            }\n            if (cyc > 0) cyclesTotal += cyc;\n        }\n\n        Eval ev;\n        ev.largestTree = largestTree;\n        ev.largestCC = largestCC;\n        ev.cyclesInLargestCC = cyclesInLargestCC;\n        ev.totalEdges = totalEdges;\n        ev.loops2x2 = loops2x2;\n        ev.cyclesTotal = cyclesTotal;\n        ev.treePotential = largestCC - cyclesInLargestCC;\n        return ev;\n    }\n};\n\nstatic inline ScoreKey make_key(const Eval& ev, std::mt19937& rng, int novelty) {\n    ScoreKey k;\n    k.largestTree = ev.largestTree;\n    k.novelty = novelty;\n    k.treePotential = ev.treePotential;\n    k.negCyclesTotal = -ev.cyclesTotal;\n    k.largestCC = ev.largestCC;\n    k.negCyclesInLargestCC = -ev.cyclesInLargestCC;\n    k.totalEdges = ev.totalEdges;\n    k.negLoops2x2 = -ev.loops2x2;\n    k.tieRand = rng();\n    return k;\n}\n\n// Local heuristic for ordering: delta matched edges and delta 2x2 loops around swapped cells\nstruct LocalHeu {\n    int deltaEdges;  // more is better\n    int deltaLoops;  // fewer is better (negative preferred)\n    int score() const { return 3*deltaEdges - 2*deltaLoops; }\n};\n\nstruct Searcher {\n    int N;\n    Evaluator &evaluator;\n    Board &B;\n    std::mt19937 &rng;\n    unordered_set<uint64_t> *visited; // pointer to global visited set\n    vector<uint64_t> zob; // zobrist table pos*16 + tile\n    uint64_t curHash;\n\n    // Directions: 0=U,1=D,2=L,3=R and opposites\n    static constexpr int dr[4] = {-1, +1, 0, 0};\n    static constexpr int dc[4] = {0, 0, -1, +1};\n    static constexpr int opp[4] = {1, 0, 3, 2};\n    static constexpr char mvch[4] = {'U','D','L','R'};\n\n    vector<int> curPath, bestPath;\n\n    Searcher(int N_, Evaluator &ev, Board &b, std::mt19937 &r, unordered_set<uint64_t>* visited_)\n        : N(N_), evaluator(ev), B(b), rng(r), visited(visited_) {\n        curPath.reserve(16);\n        bestPath.reserve(16);\n        // init zobrist\n        std::uniform_int_distribution<uint64_t> dist64(0, std::numeric_limits<uint64_t>::max());\n        zob.resize(N*N*16);\n        for (auto &x : zob) x = dist64(rng);\n        // init curHash\n        curHash = 0;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int id = i*N + j;\n                int v = B.a[id] & 15;\n                curHash ^= zob[id*16 + v];\n            }\n        }\n    }\n\n    inline bool in_bounds(int r, int c) const {\n        return (0 <= r && r < N && 0 <= c && c < N);\n    }\n\n    // Apply move with hash update\n    inline bool applyMove(int dir) {\n        int zr = B.zr, zc = B.zc;\n        int nr = zr + dr[dir], nc = zc + dc[dir];\n        if (!in_bounds(nr, nc)) return false;\n        int zidx = zr * N + zc;\n        int nidx = nr * N + nc;\n        int valn = B.a[nidx]; // tile moving into empty\n        // update hash: remove old entries and add new\n        curHash ^= zob[zidx*16 + 0];\n        curHash ^= zob[nidx*16 + (valn & 15)];\n        curHash ^= zob[zidx*16 + (valn & 15)];\n        curHash ^= zob[nidx*16 + 0];\n        // apply swap\n        swap(B.a[zidx], B.a[nidx]);\n        B.zr = nr; B.zc = nc;\n        return true;\n    }\n\n    inline void undoMove(int dir) {\n        // undo by applying opposite dir\n        applyMove(opp[dir]);\n    }\n\n    // Count matched edges incident to (r,c)\n    int incidentEdgesAt(const Board& BB, int r, int c) const {\n        int id = r * N + c;\n        int m = BB.a[id];\n        if (m == 0) return 0;\n        int cnt = 0;\n        // up\n        if (r-1 >= 0) {\n            int m2 = BB.a[(r-1)*N + c];\n            if ((m & 2) && (m2 & 8)) cnt++;\n        }\n        // down\n        if (r+1 < N) {\n            int m2 = BB.a[(r+1)*N + c];\n            if ((m & 8) && (m2 & 2)) cnt++;\n        }\n        // left\n        if (c-1 >= 0) {\n            int m2 = BB.a[r*N + (c-1)];\n            if ((m & 1) && (m2 & 4)) cnt++;\n        }\n        // right\n        if (c+1 < N) {\n            int m2 = BB.a[r*N + (c+1)];\n            if ((m & 4) && (m2 & 1)) cnt++;\n        }\n        return cnt;\n    }\n\n    // Does 2x2 square with top-left (i,j) form a cycle?\n    bool isLoop2x2At(const Board& BB, int i, int j) const {\n        if (i < 0 || j < 0 || i+1 >= N || j+1 >= N) return false;\n        int id00 = i*N + j;\n        int id01 = i*N + (j+1);\n        int id10 = (i+1)*N + j;\n        int id11 = (i+1)*N + (j+1);\n        int m00 = BB.a[id00], m01 = BB.a[id01], m10 = BB.a[id10], m11 = BB.a[id11];\n        bool v1 = (m00 & 8) && (m10 & 2);\n        bool v2 = (m01 & 8) && (m11 & 2);\n        bool h1 = (m00 & 4) && (m01 & 1);\n        bool h2 = (m10 & 4) && (m11 & 1);\n        return v1 && v2 && h1 && h2;\n    }\n\n    // Local heuristic: deltaEdges and deltaLoops caused by move dir\n    LocalHeu local_delta_for_dir(int dir) {\n        LocalHeu h{0, 0};\n        int zr = B.zr, zc = B.zc;\n        int nr = zr + dr[dir], nc = zc + dc[dir];\n        if (!in_bounds(nr, nc)) return h;\n\n        // Pre counts\n        int preEdges = incidentEdgesAt(B, zr, zc) + incidentEdgesAt(B, nr, nc);\n\n        // collect affected 2x2 top-left corners (up to 8) with manual dedup\n        pair<int,int> buf[8];\n        int bsz = 0;\n        auto push_unique = [&](int r, int c) {\n            if (r < 0 || c < 0 || r+1 >= N || c+1 >= N) return;\n            for (int i = 0; i < bsz; ++i) if (buf[i].first == r && buf[i].second == c) return;\n            buf[bsz++] = {r, c};\n        };\n        push_unique(zr, zc);\n        push_unique(zr-1, zc);\n        push_unique(zr, zc-1);\n        push_unique(zr-1, zc-1);\n        push_unique(nr, nc);\n        push_unique(nr-1, nc);\n        push_unique(nr, nc-1);\n        push_unique(nr-1, nc-1);\n\n        int preLoops = 0;\n        for (int i = 0; i < bsz; ++i) if (isLoop2x2At(B, buf[i].first, buf[i].second)) preLoops++;\n\n        // Apply move\n        applyMove(dir);\n\n        int postEdges = incidentEdgesAt(B, zr, zc) + incidentEdgesAt(B, nr, nc);\n        int postLoops = 0;\n        for (int i = 0; i < bsz; ++i) if (isLoop2x2At(B, buf[i].first, buf[i].second)) postLoops++;\n\n        // Undo\n        undoMove(dir);\n\n        h.deltaEdges = postEdges - preEdges;\n        h.deltaLoops = postLoops - preLoops;\n        return h;\n    }\n\n    void dfs(int depth, int maxD, int lastDir, ScoreKey& bestKey, double endTime, bool& timeUp) {\n        // Time guard\n        if (now_sec() > endTime) {\n            timeUp = true;\n            return;\n        }\n\n        if (depth == maxD) {\n            Eval ev = evaluator.evaluate(B);\n            int novelty = (visited && visited->find(curHash) == visited->end()) ? 1 : 0;\n            ScoreKey key = make_key(ev, rng, novelty);\n            if (better_key(key, bestKey)) {\n                bestKey = key;\n                bestPath = curPath;\n            }\n            return;\n        }\n\n        // Generate candidate moves\n        array<int,4> cand;\n        int cn = 0;\n        for (int dir = 0; dir < 4; ++dir) {\n            if (lastDir != -1 && dir == opp[lastDir]) continue; // avoid immediate reverse in path\n            int nr = B.zr + dr[dir];\n            int nc = B.zc + dc[dir];\n            if (!in_bounds(nr, nc)) continue;\n            cand[cn++] = dir;\n        }\n        if (cn == 0) return;\n\n        // Order candidates by local heuristic + tiny randomness\n        vector<pair<int,int>> ord; // (score, dir)\n        ord.reserve(cn);\n        for (int i = 0; i < cn; ++i) {\n            int dir = cand[i];\n            LocalHeu h = local_delta_for_dir(dir);\n            int noise = (int)(rng() & 1);\n            ord.push_back({h.score() * 2 + noise, dir});\n        }\n        sort(ord.begin(), ord.end(), [&](const auto& A, const auto& B){\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n\n        for (int i = 0; i < cn; ++i) {\n            int dir = ord[i].second;\n\n            bool ok = applyMove(dir);\n            if (!ok) continue;\n            curPath.push_back(dir);\n\n            dfs(depth+1, maxD, dir, bestKey, endTime, timeUp);\n\n            curPath.pop_back();\n            undoMove(dir);\n            if (timeUp) return;\n        }\n    }\n\n    // Choose best move with time budget; avoid immediate reverse at root if possible\n    int choose_move_with_budget(int maxDepth, double budget_sec, int lastGlobalDir, ScoreKey& outKey) {\n        curPath.clear();\n        bestPath.clear();\n        ScoreKey bestKey = {-1, -1, -1, INT_MIN, -1, INT_MIN, -1, INT_MIN, 0};\n        bool timeUp = false;\n        double endTime = now_sec() + budget_sec;\n\n        // Kick a DFS; at root, forbid opposite of lastGlobalDir\n        dfs(0, maxDepth, lastGlobalDir, bestKey, endTime, timeUp);\n\n        outKey = bestKey;\n        if (!bestPath.empty()) return bestPath[0];\n        return -1;\n    }\n\n    // Very cheap fallback: use local heuristic only\n    int choose_move_local(int lastGlobalDir) {\n        int bestDir = -1;\n        int bestScore = INT_MIN;\n\n        // Collect legal moves, avoid immediate reverse if possible\n        array<int,4> legal;\n        int ln = 0;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nr = B.zr + dr[dir];\n            int nc = B.zc + dc[dir];\n            if (!in_bounds(nr, nc)) continue;\n            legal[ln++] = dir;\n        }\n        if (ln == 0) return -1;\n\n        bool hasNonReverse = false;\n        for (int i = 0; i < ln; ++i) if (lastGlobalDir == -1 || legal[i] != opp[lastGlobalDir]) hasNonReverse = true;\n\n        for (int i = 0; i < ln; ++i) {\n            int dir = legal[i];\n            if (hasNonReverse && lastGlobalDir != -1 && dir == opp[lastGlobalDir]) continue;\n            LocalHeu h = local_delta_for_dir(dir);\n            int sc = h.score();\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestDir = dir;\n            }\n        }\n        if (bestDir == -1) bestDir = legal[0];\n        return bestDir;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    if (!(cin >> N >> T)) return 0;\n    vector<string> ts(N);\n    for (int i = 0; i < N; ++i) cin >> ts[i];\n\n    Board B;\n    B.N = N;\n    B.a.assign(N*N, 0);\n    B.zr = -1; B.zc = -1;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int v = hexchar_to_int(ts[i][j]);\n            B.a[i*N + j] = v;\n            if (v == 0) { B.zr = i; B.zc = j; }\n        }\n    }\n\n    Evaluator evaluator(N);\n\n    string ans;\n    ans.reserve(T);\n\n    // RNG\n    std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Directions helpers\n    static const int dr[4] = {-1, +1, 0, 0};\n    static const int dc[4] = {0, 0, -1, +1};\n    static const char mvch[4] = {'U', 'D', 'L', 'R'};\n    static const int opp[4] = {1, 0, 3, 2};\n\n    // Timer\n    double t_start = now_sec();\n    const double TIME_LIMIT = 2.95; // seconds\n    const double SAFETY_MARGIN = 0.03; // margin\n\n    // Early perfect check\n    Eval ev0 = evaluator.evaluate(B);\n    if (ev0.largestTree == N*N - 1) {\n        cout << \"\" << '\\n';\n        return 0;\n    }\n\n    // Visited state memory\n    unordered_set<uint64_t> visited;\n    visited.reserve(1 << 15);\n    deque<uint64_t> vorder;\n    const size_t VIS_CAP = 4096;\n\n    Searcher searcher(N, evaluator, B, rng, &visited);\n\n    // Seed visited with initial hash\n    visited.insert(searcher.curHash);\n    vorder.push_back(searcher.curHash);\n\n    int lastDirGlobal = -1;\n\n    // Stagnation tracking\n    int bestLargestTree = ev0.largestTree;\n    int stagnation = 0;\n\n    for (int step = 0; step < T; ++step) {\n        double elapsed = now_sec() - t_start;\n        double timeLeft = TIME_LIMIT - elapsed - SAFETY_MARGIN;\n        if (timeLeft <= 0.0) break;\n\n        // Per-step budget: conservative base\n        double remainSteps = double(T - step);\n        double budget = (remainSteps > 0 ? timeLeft / remainSteps : 0.0);\n        // Clamp budget\n        double minBudget = 0.0002; // 0.2 ms\n        double maxBudget = 0.0022; // 2.2 ms cap\n        if (budget < minBudget) budget = minBudget;\n        if (budget > maxBudget) budget = maxBudget;\n\n        // Stagnation-aware boost\n        double boost = 0.0;\n        if (stagnation > 60) boost = 0.35;\n        if (stagnation > 120) boost = 0.7;\n        budget *= (1.0 + boost);\n        if (budget > maxBudget * 1.4) budget = maxBudget * 1.4;\n\n        // Dynamic depth selection with stagnation\n        int maxDepth;\n        if (N <= 7) {\n            if (budget > 0.0018) maxDepth = 5;\n            else if (budget > 0.0011) maxDepth = 4;\n            else maxDepth = 3;\n        } else {\n            if (budget > 0.0016) maxDepth = 4;\n            else maxDepth = 3;\n        }\n        if (boost > 0.0 && maxDepth < 5 && N <= 7) maxDepth++;\n\n        // Search within budget\n        ScoreKey outKey;\n        int chosenDir = searcher.choose_move_with_budget(maxDepth, budget, lastDirGlobal, outKey);\n\n        if (chosenDir == -1) {\n            // Fallbacks\n            if (budget <= 0.0003) {\n                chosenDir = searcher.choose_move_local(lastDirGlobal);\n            } else {\n                // 1-ply greedy with time guard\n                double t0 = now_sec();\n                double greedyBudget = budget * 0.8;\n                ScoreKey bestKey = {-1, -1, -1, INT_MIN, -1, INT_MIN, -1, INT_MIN, 0};\n                int bestDir = -1;\n\n                // Collect legal moves; avoid immediate reverse if possible\n                array<int,4> legal;\n                int ln = 0;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int nr = B.zr + dr[dir];\n                    int nc = B.zc + dc[dir];\n                    if (0 <= nr && nr < N && 0 <= nc && nc < N) legal[ln++] = dir;\n                }\n                if (ln == 0) break;\n                bool hasNonReverse = false;\n                for (int i = 0; i < ln; ++i) if (lastDirGlobal == -1 || legal[i] != opp[lastDirGlobal]) hasNonReverse = true;\n\n                for (int i = 0; i < ln; ++i) {\n                    int dir = legal[i];\n                    if (hasNonReverse && lastDirGlobal != -1 && dir == opp[lastDirGlobal]) continue;\n                    searcher.applyMove(dir);\n                    Eval ev = evaluator.evaluate(B);\n                    int novelty = (visited.find(searcher.curHash) == visited.end()) ? 1 : 0;\n                    ScoreKey key = make_key(ev, rng, novelty);\n                    if (better_key(key, bestKey)) {\n                        bestKey = key;\n                        bestDir = dir;\n                    }\n                    searcher.undoMove(dir);\n                    if (now_sec() - t0 > greedyBudget) break;\n                }\n                if (bestDir != -1) chosenDir = bestDir;\n                else chosenDir = searcher.choose_move_local(lastDirGlobal);\n            }\n        }\n\n        if (chosenDir == -1) {\n            // No legal move (should not happen)\n            break;\n        }\n\n        // Execute\n        searcher.applyMove(chosenDir);\n        ans.push_back(mvch[chosenDir]);\n        lastDirGlobal = chosenDir;\n\n        // Update visited set\n        if (visited.find(searcher.curHash) == visited.end()) {\n            visited.insert(searcher.curHash);\n            vorder.push_back(searcher.curHash);\n            if (vorder.size() > VIS_CAP) {\n                uint64_t oldh = vorder.front();\n                vorder.pop_front();\n                // optional: keep set size bounded; but unordered_set doesn't support erasing only if unique.\n                // We can leave old entries; capacity is small anyway.\n            }\n        }\n\n        // Early stop if perfect\n        Eval ev = evaluator.evaluate(B);\n        if (ev.largestTree == N*N - 1) {\n            break;\n        }\n        // Update stagnation\n        if (ev.largestTree > bestLargestTree) {\n            bestLargestTree = ev.largestTree;\n            stagnation = 0;\n        } else {\n            stagnation++;\n        }\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\nstruct Normal { long long nx, ny; };\n\nstruct WeightSpec {\n    int mode;      // 0: uniform; 1: symmetric center-heavy (r<1); 2: monotonic (r<1)\n    long double r; // ratio parameter (unused for uniform)\n};\n\nstatic inline long long now_us() {\n    using namespace std::chrono;\n    return duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();\n}\n\n// Build weights\nstatic vector<long double> make_weights(int m, const WeightSpec& ws) {\n    vector<long double> w(max(m, 1), 1.0L);\n    if (m <= 0) return w;\n    if (ws.mode == 0) {\n        for (int i = 0; i < m; ++i) w[i] = 1.0L;\n    } else if (ws.mode == 1) {\n        long double mid = (m - 1) * 0.5L;\n        for (int i = 0; i < m; ++i) {\n            long double d = fabsl((long double)i - mid);\n            w[i] = pow(ws.r, d);\n        }\n    } else if (ws.mode == 2) {\n        long double v = 1.0L;\n        for (int i = 0; i < m; ++i) {\n            w[i] = v;\n            v *= ws.r;\n        }\n    } else {\n        for (int i = 0; i < m; ++i) w[i] = 1.0L;\n    }\n    long double s = 0;\n    for (auto &x : w) s += x;\n    if (s > 0) for (auto &x : w) x /= s;\n    return w;\n}\n\n// Largest Remainder Method\nstatic vector<int> targets_from_weights(const vector<long double>& w, int N) {\n    int m = (int)w.size();\n    vector<int> tgt(m, 0);\n    vector<pair<long double,int>> frac; frac.reserve(m);\n    long double sum_floor = 0;\n    for (int i = 0; i < m; ++i) {\n        long double val = (long double)N * w[i];\n        int f = (int)floor(val);\n        tgt[i] = f;\n        sum_floor += f;\n        frac.emplace_back(val - f, i);\n    }\n    int rem = N - (int)sum_floor;\n    if (rem > 0) {\n        sort(frac.begin(), frac.end(), [](const auto& a, const auto& b){ return a.first > b.first; });\n        for (int k = 0; k < rem && k < m; ++k) {\n            tgt[frac[k].second]++;\n        }\n    }\n    return tgt;\n}\n\n// Safe j positions where integer cut is possible between arr[j] and arr[j+1], with sentinels -1 and N-1\nstatic vector<int> build_safe_indices(const vector<long long>& arr) {\n    int N = (int)arr.size();\n    vector<int> safe;\n    safe.reserve(N + 2);\n    safe.push_back(-1);\n    for (int j = 0; j + 1 < N; ++j) {\n        if (arr[j+1] - arr[j] >= 2) {\n            safe.push_back(j);\n        }\n    }\n    safe.push_back(N - 1);\n    return safe;\n}\n\nstatic int choose_nearest_safe(const vector<int>& safe, int t, int min_j) {\n    int lo = 0, hi = (int)safe.size();\n    while (lo < hi) {\n        int mid = (lo + hi) >> 1;\n        if (safe[mid] < t) lo = mid + 1;\n        else hi = mid;\n    }\n    long long bestDist = (1LL<<60);\n    int best = -1;\n    for (int k = lo - 1; k <= lo; ++k) {\n        if (k < 0 || k >= (int)safe.size()) continue;\n        int cand = safe[k];\n        if (cand < min_j) continue;\n        long long dist = llabs((long long)cand - (long long)t);\n        if (dist < bestDist) {\n            bestDist = dist;\n            best = cand;\n        }\n    }\n    if (best == -1) {\n        int idx = lower_bound(safe.begin(), safe.end(), min_j) - safe.begin();\n        if (idx >= (int)safe.size()) idx = (int)safe.size() - 1;\n        best = safe[idx];\n    }\n    return best;\n}\n\n// Plan boundary j-values (in terms of index into arr_sorted: cut between j and j+1) given per-segment counts\nstatic vector<int> plan_boundaries_from_targets(const vector<long long>& arr_sorted, const vector<int>& inc) {\n    int N = (int)arr_sorted.size();\n    int L = (int)inc.size();\n    vector<int> safe = build_safe_indices(arr_sorted);\n    vector<int> js; js.reserve(L);\n    int pos = 0;\n    for (int i = 0; i < L; ++i) {\n        int c = inc[i];\n        if (pos >= N) {\n            js.push_back(N - 1); // far right\n            continue;\n        }\n        if (c <= 0) {\n            js.push_back(-1); // far left\n            continue;\n        }\n        int desired = pos + c - 1;\n        desired = max(desired, pos - 1);\n        desired = min(desired, N - 1);\n        int j = choose_nearest_safe(safe, desired, pos - 1);\n        js.push_back(j);\n        if (j >= pos - 1) pos = max(pos, j + 1);\n    }\n    sort(js.begin(), js.end()); // monotone sequence\n    return js;\n}\n\nstruct Projected {\n    vector<long long> u, v;         // raw projections\n    vector<pair<long long,int>> up, vp; // value,id sorted\n    vector<long long> uSorted, vSorted;\n    vector<int> ru, rv;             // ranks in sorted arrays\n    vector<int> safeU, safeV;       // safe j lists\n};\n\nstatic void build_projection(const vector<Point>& pts, const Normal& nx, const Normal& ny, Projected& P) {\n    int N = (int)pts.size();\n    P.u.resize(N); P.v.resize(N);\n    for (int i = 0; i < N; ++i) {\n        P.u[i] = nx.nx * (long long)pts[i].x + nx.ny * (long long)pts[i].y;\n        P.v[i] = ny.nx * (long long)pts[i].x + ny.ny * (long long)pts[i].y;\n    }\n    P.up.resize(N); P.vp.resize(N);\n    for (int i = 0; i < N; ++i) {\n        P.up[i] = {P.u[i], i};\n        P.vp[i] = {P.v[i], i};\n    }\n    stable_sort(P.up.begin(), P.up.end());\n    stable_sort(P.vp.begin(), P.vp.end());\n    P.uSorted.resize(N);\n    P.vSorted.resize(N);\n    P.ru.assign(N, 0);\n    P.rv.assign(N, 0);\n    for (int i = 0; i < N; ++i) {\n        P.uSorted[i] = P.up[i].first;\n        P.vSorted[i] = P.vp[i].first;\n        P.ru[P.up[i].second] = i;\n        P.rv[P.vp[i].second] = i;\n    }\n    // Build safe indices\n    P.safeU = build_safe_indices(P.uSorted);\n    P.safeV = build_safe_indices(P.vSorted);\n}\n\nstatic long long evaluate_score_from_boundaries(const vector<int>& jx, const vector<int>& jy,\n                                                const Projected& P,\n                                                const array<int,11>& a) {\n    int V = (int)jx.size();\n    int H = (int)jy.size();\n    int C = V + 1;\n    int R = H + 1;\n    vector<int> counts(C * R, 0);\n    // For each point, get ci = # {j in jx | j <= ru-1} and ri similar\n    for (size_t i = 0; i < P.u.size(); ++i) {\n        int ru = P.ru[i];\n        int rv = P.rv[i];\n        int ci = int(upper_bound(jx.begin(), jx.end(), ru - 1) - jx.begin());\n        int ri = int(upper_bound(jy.begin(), jy.end(), rv - 1) - jy.begin());\n        counts[ri * C + ci] += 1;\n    }\n    array<int,11> b{}; // b[1..10]\n    for (int val : counts) {\n        if (val >= 1 && val <= 10) b[val]++;\n    }\n    long long s = 0;\n    for (int d = 1; d <= 10; ++d) s += min(a[d], b[d]);\n    return s;\n}\n\nstatic long long extgcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) { x = (a >= 0 ? 1 : -1); y = 0; return llabs(a); }\n    long long x1, y1;\n    long long g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\n// Convert boundary j list to integer constants T for the line equation nx*x + ny*y = T\nstatic vector<long long> constants_from_boundaries(const vector<int>& jlist, const vector<long long>& arrSorted) {\n    int N = (int)arrSorted.size();\n    long long minV = arrSorted.front();\n    long long maxV = arrSorted.back();\n    vector<int> js = jlist;\n    sort(js.begin(), js.end());\n    vector<long long> T; T.reserve(js.size());\n    int leftExtra = 0, rightExtra = 0;\n    for (int j : js) {\n        if (j <= -1) {\n            T.push_back(minV - 1 - leftExtra);\n            leftExtra++;\n        } else if (j >= N - 1) {\n            T.push_back(maxV + 1 + rightExtra);\n            rightExtra++;\n        } else {\n            T.push_back(arrSorted[j] + 1);\n        }\n    }\n    return T;\n}\n\nstatic pair<pair<long long,long long>, pair<long long,long long>> line_endpoints(const Normal& n, long long T) {\n    long long nx = n.nx, ny = n.ny;\n    long long x0, y0;\n    long long g = extgcd(nx, ny, x0, y0);\n    if (g < 0) { g = -g; x0 = -x0; y0 = -y0; }\n    long long mul = T / g;\n    long long px = x0 * mul;\n    long long py = y0 * mul;\n    long long dx = -ny;\n    long long dy = nx;\n    long long px2 = px + dx, py2 = py + dy;\n    return {{px, py}, {px2, py2}};\n}\n\nstruct Candidate {\n    Normal nx, ny;\n    vector<int> jx, jy; // boundary j-values\n    long long score;\n};\n\n// Generate orientation pairs (coprime small normals)\nstatic vector<pair<Normal,Normal>> generate_orientations() {\n    vector<pair<Normal,Normal>> O;\n    auto add = [&](long long ax, long long ay, long long bx, long long by) {\n        if (std::gcd(llabs(ax), llabs(ay)) != 1) return;\n        if (std::gcd(llabs(bx), llabs(by)) != 1) return;\n        // Non-collinear\n        if (ax * by - ay * bx == 0) return;\n        O.push_back({{ax, ay}, {bx, by}});\n    };\n    add(1,0,  0,1);\n    add(1,1,  1,-1);\n    add(2,1,  1,2);\n    add(3,1,  1,3);\n    add(3,2,  2,3);\n    add(4,1,  1,4);\n    add(2,1,  1,-2);\n    add(5,2,  2,5);\n    return O;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    long long start_us = now_us();\n    const long long TIME_LIMIT_US = 2900000; // 2.9s\n    const long long SEARCH_BUDGET_US = 1700000; // ~1.7s for global search\n    const long long LOCAL_BUDGET_US = 1000000;  // ~1.0s for local search (rest is slack)\n\n    int N, K;\n    if (!(cin >> N >> K)) return 0;\n    array<int,11> a{}; for (int d = 1; d <= 10; ++d) cin >> a[d];\n    vector<Point> pts(N); for (int i = 0; i < N; ++i) cin >> pts[i].x >> pts[i].y;\n\n    // Orientation candidates\n    vector<pair<Normal,Normal>> orientations = generate_orientations();\n\n    // Budgeted k values and V/H ratios\n    vector<int> kList;\n    for (int x : {50, 70, 90, 100}) if (x <= K) kList.push_back(x);\n    if (kList.empty()) kList.push_back(min(K, 50));\n    vector<long double> alphaList = {0.35L, 0.45L, 0.55L, 0.65L};\n\n    // Weight options\n    vector<WeightSpec> weightOptions = {\n        {0, 1.0L},   // uniform\n        {1, 0.95L},  // symmetric mild\n        {1, 0.90L},  // symmetric medium\n        {1, 0.85L},  // symmetric strong\n        {2, 0.95L},  // monotonic mild\n        {2, 0.90L},  // monotonic medium\n        {2, 0.80L},  // monotonic strong\n    };\n\n    mt19937_64 rng(123456789); // deterministic for stability\n\n    Candidate best; best.score = -1;\n\n    // Global search\n    for (auto &orn : orientations) {\n        if (now_us() - start_us > SEARCH_BUDGET_US) break;\n\n        Projected P;\n        build_projection(pts, orn.first, orn.second, P);\n\n        for (int kUse : kList) {\n            if (now_us() - start_us > SEARCH_BUDGET_US) break;\n\n            for (long double alpha : alphaList) {\n                if (now_us() - start_us > SEARCH_BUDGET_US) break;\n\n                int V = (int)llround(alpha * kUse);\n                V = max(1, min(V, kUse - 1));\n                int H = kUse - V;\n                int C = V + 1, R = H + 1;\n\n                for (const auto &wc : weightOptions) {\n                    if (now_us() - start_us > SEARCH_BUDGET_US) break;\n                    vector<long double> wcol = make_weights(C, wc);\n                    vector<int> colCounts = targets_from_weights(wcol, N);\n                    vector<int> colInc(colCounts.begin(), colCounts.end() - 1);\n\n                    for (const auto &wr : weightOptions) {\n                        if (now_us() - start_us > SEARCH_BUDGET_US) break;\n                        vector<long double> wrow = make_weights(R, wr);\n                        vector<int> rowCounts = targets_from_weights(wrow, N);\n                        vector<int> rowInc(rowCounts.begin(), rowCounts.end() - 1);\n\n                        vector<int> jx = plan_boundaries_from_targets(P.uSorted, colInc);\n                        vector<int> jy = plan_boundaries_from_targets(P.vSorted, rowInc);\n\n                        long long sc = evaluate_score_from_boundaries(jx, jy, P, a);\n                        if (sc > best.score) {\n                            best.score = sc;\n                            best.nx = orn.first;\n                            best.ny = orn.second;\n                            best.jx = move(jx);\n                            best.jy = move(jy);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Local improvement (hill-climbing) on the best grid\n    if (best.score < 0) {\n        // Fallback: no cuts\n        cout << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Prepare projection for best orientation\n    Projected Pbest;\n    build_projection(pts, best.nx, best.ny, Pbest);\n\n    // Convert j-values to indices in safe arrays for quick move steps\n    auto to_safe_indices = [&](const vector<int>& jlist, const vector<int>& safe) {\n        vector<int> sidx(jlist.size());\n        for (size_t i = 0; i < jlist.size(); ++i) {\n            int j = jlist[i];\n            int idx = int(lower_bound(safe.begin(), safe.end(), j) - safe.begin());\n            if (idx == (int)safe.size() || safe[idx] != j) {\n                // due to sorting, j should be in safe; handle extremes anyway\n                // adjust to nearest\n                if (idx > 0) --idx;\n            }\n            // ensure exact match\n            if (safe[idx] != j) {\n                // fallback search small window\n                int k1 = idx;\n                if (k1+1 < (int)safe.size() && safe[k1+1] == j) idx = k1+1;\n                else if (k1 > 0 && safe[k1-1] == j) idx = k1-1;\n            }\n            sidx[i] = idx;\n        }\n        sort(sidx.begin(), sidx.end());\n        return sidx;\n    };\n\n    auto sx = to_safe_indices(best.jx, Pbest.safeU);\n    auto sy = to_safe_indices(best.jy, Pbest.safeV);\n\n    auto rebuild_j_from_s = [&](const vector<int>& sidx, const vector<int>& safe) {\n        vector<int> jv; jv.reserve(sidx.size());\n        for (int si : sidx) jv.push_back(safe[si]);\n        // jv must be nondecreasing if sidx is nondecreasing\n        return jv;\n    };\n\n    auto evaluate_s = [&](const vector<int>& sx, const vector<int>& sy) {\n        vector<int> jx = rebuild_j_from_s(sx, Pbest.safeU);\n        vector<int> jy = rebuild_j_from_s(sy, Pbest.safeV);\n        return evaluate_score_from_boundaries(jx, jy, Pbest, a);\n    };\n\n    long long currentScore = evaluate_s(sx, sy);\n    if (currentScore != best.score) {\n        // in rare cases due to rounding differences; sync\n        best.score = currentScore;\n    }\n\n    uniform_int_distribution<int> coin(0, 1);\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    auto try_move_line = [&](bool vertical, int idx, int dir, int step)->bool{\n        if (vertical) {\n            if (sx.empty()) return false;\n            int V = (int)sx.size();\n            if (idx < 0 || idx >= V) return false;\n            int new_val = sx[idx] + dir * step;\n            int lo = (idx == 0 ? sx[idx] : sx[idx-1]);\n            int hi = (idx == V-1 ? sx[idx] : sx[idx+1]);\n            if (dir < 0) {\n                new_val = max(new_val, lo);\n            } else {\n                new_val = min(new_val, hi);\n            }\n            if (new_val == sx[idx]) return false;\n\n            int old = sx[idx];\n            sx[idx] = new_val;\n            long long sc = evaluate_s(sx, sy);\n            if (sc > currentScore) {\n                currentScore = sc;\n                return true;\n            } else {\n                sx[idx] = old;\n                return false;\n            }\n        } else {\n            if (sy.empty()) return false;\n            int H = (int)sy.size();\n            if (idx < 0 || idx >= H) return false;\n            int new_val = sy[idx] + dir * step;\n            int lo = (idx == 0 ? sy[idx] : sy[idx-1]);\n            int hi = (idx == H-1 ? sy[idx] : sy[idx+1]);\n            if (dir < 0) new_val = max(new_val, lo);\n            else new_val = min(new_val, hi);\n            if (new_val == sy[idx]) return false;\n\n            int old = sy[idx];\n            sy[idx] = new_val;\n            long long sc = evaluate_s(sx, sy);\n            if (sc > currentScore) {\n                currentScore = sc;\n                return true;\n            } else {\n                sy[idx] = old;\n                return false;\n            }\n        }\n    };\n\n    // Hill-climb loop within time budget\n    while (now_us() - start_us < SEARCH_BUDGET_US + LOCAL_BUDGET_US) {\n        bool vertical = coin(rng);\n        if ((vertical && sx.empty()) || (!vertical && sy.empty())) vertical = !vertical;\n        int idx = 0;\n        int step = 1;\n        if (vertical) {\n            if (sx.empty()) break;\n            uniform_int_distribution<int> pick(0, (int)sx.size() - 1);\n            idx = pick(rng);\n        } else {\n            if (sy.empty()) break;\n            uniform_int_distribution<int> pick(0, (int)sy.size() - 1);\n            idx = pick(rng);\n        }\n        double r = uni01(rng);\n        if (r < 0.15) step = 2;\n        else if (r < 0.20) step = 3;\n        int dir = (coin(rng) ? 1 : -1);\n        try_move_line(vertical, idx, dir, step);\n    }\n\n    // Rebuild final j lists and compute T constants for output\n    vector<int> finalJx = rebuild_j_from_s(sx, Pbest.safeU);\n    vector<int> finalJy = rebuild_j_from_s(sy, Pbest.safeV);\n    vector<long long> Tx = constants_from_boundaries(finalJx, Pbest.uSorted);\n    vector<long long> Ty = constants_from_boundaries(finalJy, Pbest.vSorted);\n\n    // Output lines\n    int V = (int)Tx.size();\n    int H = (int)Ty.size();\n    cout << (V + H) << \"\\n\";\n    // Family X\n    for (int i = 0; i < V; ++i) {\n        auto ep = line_endpoints(best.nx, Tx[i]);\n        auto [p, q] = ep;\n        cout << p.first << \" \" << p.second << \" \" << q.first << \" \" << q.second << \"\\n\";\n    }\n    // Family Y\n    for (int j = 0; j < H; ++j) {\n        auto ep = line_endpoints(best.ny, Ty[j]);\n        auto [p, q] = ep;\n        cout << p.first << \" \" << p.second << \" \" << q.first << \" \" << q.second << \"\\n\";\n    }\n\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Operation {\n    int x1,y1,x2,y2,x3,y3,x4,y4;\n};\n\nstruct Solver {\n    int N, M;\n    int c; // center coordinate (N-1)/2\n    vector<uint8_t> occ; // occupancy grid N*N\n\n    // used unit segments\n    vector<uint8_t> usedH;  // horizontal: size N*(N-1), seg (x,y)-(x+1,y)\n    vector<uint8_t> usedV;  // vertical:   size (N-1)*N, seg (x,y)-(x,y+1)\n    vector<uint8_t> usedD1; // diag +1:    size (N-1)*(N-1), (x,y)-(x+1,y+1)\n    vector<uint8_t> usedD2; // diag -1:    size (N-1)*(N-1), (x,y)-(x+1,y-1) mapped by y-1\n\n    vector<pair<int,int>> points; // all dots (initial + added)\n    vector<Operation> ops;\n\n    // line indices for fast 45\u00b0 generation\n    // diagPlus id: d = x - y, in [-(N-1), +(N-1)] -> index d + (N - 1)\n    // diagMinus id: s = x + y, in [0, 2(N-1)] -> index s\n    vector<vector<pair<int,int>>> diagPlus;  // size 2N-1\n    vector<vector<pair<int,int>>> diagMinus; // size 2N-1\n\n    // row/column indices for axis generation\n    vector<vector<int>> rowXs; // rowXs[y] = list of x such that (x,y) occupied\n    vector<vector<int>> colYs; // colYs[x] = list of y such that (x,y) occupied\n\n    // dedup sets\n    unordered_set<uint64_t> seenAxis;\n    unordered_set<uint64_t> seenRot;\n\n    // bounding box of current occupied points\n    int minX, maxX, minY, maxY;\n\n    // committed ops count (for phase-dependent bias)\n    int opsCount = 0;\n\n    inline int idx(int x, int y) const { return y*N + x; }\n    inline bool isInside(int x, int y) const { return (0 <= x && x < N && 0 <= y && y < N); }\n\n    inline int idxH(int x, int y) const { return y*(N-1) + x; } // x in [0..N-2], y in [0..N-1]\n    inline int idxV(int x, int y) const { return y*N + x; }     // x in [0..N-1], y in [0..N-2]\n    inline int idxD1_fromPoints(int x0, int y0, int x1, int y1) const {\n        // slope +1 segment normalized to (min x, min y)\n        int x = min(x0, x1);\n        int y = min(y0, y1);\n        return y*(N-1) + x; // y in [0..N-2], x in [0..N-2]\n    }\n    inline int idxD2_fromPoints(int x0, int y0, int x1, int y1) const {\n        // slope -1 segment normalized to (min x, max y), index (y-1)*(N-1) + x\n        int x = min(x0, x1);\n        int y = max(y0, y1); // y in [1..N-1]\n        return (y-1)*(N-1) + x;\n    }\n\n    inline int weight(int x, int y) const {\n        int dx = x - c;\n        int dy = y - c;\n        return dx*dx + dy*dy + 1;\n    }\n\n    struct Candidate {\n        // type 0: axis-aligned rectangle\n        // type 1: rotated 45\u00b0 rectangle (sides parallel to y=x and y=-x)\n        int type;\n        int p1x, p1y; // new dot\n        // scoring\n        int w;           // weight(p1)\n        int perim;       // perimeter measured in unit segments\n        long long score; // priority key: higher is better\n\n        // axis fields\n        int xL, xR, yB, yT;\n        int insideLen; // total unit segments lying inside current bbox at push-time (axis or rotated)\n\n        // rot45 fields: store three existing corners A,B,C (D=p1)\n        int ax, ay, bx, by, cx, cy;\n    };\n\n    struct CandCmp {\n        bool operator()(const Candidate& a, const Candidate& b) const {\n            if (a.score != b.score) return a.score < b.score; // max-heap by score\n            if (a.w != b.w) return a.w < b.w; // then by raw weight\n            // tie-breaker: prefer larger span\n            int aa;\n            if (a.type==0) aa = (a.xR - a.xL) + (a.yT - a.yB);\n            else {\n                int d1 = abs(a.bx - a.ax);\n                int d2 = abs(a.cx - a.ax);\n                aa = d1 + d2;\n            }\n            int bb;\n            if (b.type==0) bb = (b.xR - b.xL) + (b.yT - b.yB);\n            else {\n                int d1 = abs(b.bx - b.ax);\n                int d2 = abs(b.cx - b.ax);\n                bb = d1 + d2;\n            }\n            if (aa != bb) return aa < bb;\n            if (a.p1x != b.p1x) return a.p1x < b.p1x;\n            return a.p1y < b.p1y;\n        }\n    };\n\n    priority_queue<Candidate, vector<Candidate>, CandCmp> pq;\n\n    Solver(int N_, int M_) : N(N_), M(M_) {\n        c = (N - 1) / 2;\n        occ.assign(N*N, 0);\n        usedH.assign(N*(N-1), 0);\n        usedV.assign((N-1)*N, 0);\n        usedD1.assign((N-1)*(N-1), 0);\n        usedD2.assign((N-1)*(N-1), 0);\n        diagPlus.assign(2*N-1, {});\n        diagMinus.assign(2*N-1, {});\n        rowXs.assign(N, {});\n        colYs.assign(N, {});\n        seenAxis.reserve(1<<20);\n        seenRot.reserve(1<<20);\n        minX = 1e9; maxX = -1e9; minY = 1e9; maxY = -1e9;\n    }\n\n    inline int diagPlusId(int x, int y) const { return (x - y) + (N - 1); }\n    inline int diagMinusId(int x, int y) const { return (x + y); }\n\n    // bounding box area ratio\n    inline double bboxAreaRatio() const {\n        if (minX > maxX) return 1.0; // no points set yet\n        long long w = (maxX - minX + 1);\n        long long h = (maxY - minY + 1);\n        double area = double(w) * double(h);\n        return area / double(N * N);\n    }\n\n    // Compute fan-out-based and phase-based priority adjustments; insideLen penalty for both types\n    inline long long computePriority(int px, int py, int perim, int w, int type, int insideLen) const {\n        // base term\n        long long base = (long long)w * 100000LL / (perim + 4);\n\n        // fan-out estimate from current occupancy (p1 not yet inserted)\n        int rowD = (py>=0 && py<N) ? (int)rowXs[py].size() : 0;\n        int colD = (px>=0 && px<N) ? (int)colYs[px].size() : 0;\n        int degPlus = (int)diagPlus[diagPlusId(px,py)].size();\n        int degMinus = (int)diagMinus[diagMinusId(px,py)].size();\n        long long fan = (long long)rowD * colD + (long long)degPlus * degMinus;\n        const long long FAN_COEF = 15LL; // small\n        long long fanTerm = FAN_COEF * fan;\n\n        // bounding-box expansion bonus, dynamic by area ratio\n        double ar = bboxAreaRatio(); // in (0..1]\n        long long expCoef = (long long)(9000.0 * (1.0 + 0.6 * (1.0 - ar)));\n        int margin = 0;\n        if (minX <= maxX) {\n            margin = max(margin, (px < minX) ? (minX - px) : 0);\n            margin = max(margin, (px > maxX) ? (px - maxX) : 0);\n            margin = max(margin, (py < minY) ? (minY - py) : 0);\n            margin = max(margin, (py > maxY) ? (py - maxY) : 0);\n        }\n        long long expandTerm = (long long)margin * expCoef;\n\n        // early bias for rotated rectangles (decays to 0 after ~600 ops)\n        long long rotBias = 0;\n        if (type == 1) {\n            const long long B0 = 40000LL;\n            int rem = max(0, 600 - opsCount);\n            rotBias = (B0 * rem) / 600;\n        }\n\n        // penalty for edges lying inside bbox\n        long long insidePenalty = 0;\n        if (insideLen > 0 && minX <= maxX) {\n            // dynamic penalty coefficients (stronger when box is compact)\n            if (type == 0) {\n                long long penCoef = (long long)(5500.0 * (1.0 + 0.5 * (1.0 - ar)));\n                insidePenalty = penCoef * (long long)insideLen;\n            } else {\n                long long penCoef = (long long)(2300.0 * (1.0 + 0.5 * (1.0 - ar)));\n                insidePenalty = penCoef * (long long)insideLen;\n            }\n        }\n\n        return base + fanTerm + expandTerm + rotBias - insidePenalty;\n    }\n\n    // dedup keys\n    static inline uint64_t axisKey(int xL, int yB, int xR, int yT) {\n        // pack into 32 bits (N <= 61 < 256)\n        return ( (uint64_t)(uint8_t)xL << 24 ) |\n               ( (uint64_t)(uint8_t)yB << 16 ) |\n               ( (uint64_t)(uint8_t)xR << 8  ) |\n               ( (uint64_t)(uint8_t)yT );\n    }\n    inline uint64_t rotKeyFromABC(int ax, int ay, int bx, int by, int cx, int cy) const {\n        int d1 = ax - ay; // slope +1 side constant AB\n        int d2 = cx - cy; // slope +1 side constant DC (same as D)\n        if (d1 > d2) swap(d1, d2);\n        int s1 = ax + ay; // slope -1 side constant AC\n        int s2 = bx + by; // slope -1 side constant BD\n        if (s1 > s2) swap(s1, s2);\n        // shift d by (N-1) to be non-negative; s already in [0..2(N-1)]\n        int sd1 = d1 + (N - 1);\n        int sd2 = d2 + (N - 1);\n        return ( (uint64_t)(uint8_t)sd1 << 24 ) |\n               ( (uint64_t)(uint8_t)sd2 << 16 ) |\n               ( (uint64_t)(uint8_t)s1  << 8  ) |\n               ( (uint64_t)(uint8_t)s2 );\n    }\n\n    // -------- Validation --------\n    bool validateAxis(const Candidate& cd) const {\n        if (!isInside(cd.p1x, cd.p1y)) return false;\n        if (occ[idx(cd.p1x, cd.p1y)]) return false;\n\n        // other three corners must be occupied\n        int cx[4] = {cd.xL, cd.xR, cd.xR, cd.xL};\n        int cy[4] = {cd.yB, cd.yB, cd.yT, cd.yT};\n        int cntExist = 0;\n        for (int i=0;i<4;i++) {\n            int x = cx[i], y = cy[i];\n            if (x==cd.p1x && y==cd.p1y) continue;\n            if (!isInside(x,y)) return false;\n            if (!occ[idx(x,y)]) return false;\n            cntExist++;\n        }\n        if (cntExist != 3) return false;\n\n        // Perimeter must have no other dots (interior points along sides)\n        for (int x = cd.xL+1; x <= cd.xR-1; ++x) {\n            if (occ[idx(x, cd.yB)]) return false;\n            if (occ[idx(x, cd.yT)]) return false;\n        }\n        for (int y = cd.yB+1; y <= cd.yT-1; ++y) {\n            if (occ[idx(cd.xL, y)]) return false;\n            if (occ[idx(cd.xR, y)]) return false;\n        }\n\n        // No used unit segments on perimeter\n        for (int x = cd.xL; x <= cd.xR-1; ++x) {\n            if (usedH[idxH(x, cd.yB)]) return false;\n            if (usedH[idxH(x, cd.yT)]) return false;\n        }\n        for (int y = cd.yB; y <= cd.yT-1; ++y) {\n            if (usedV[idxV(cd.xL, y)]) return false;\n            if (usedV[idxV(cd.xR, y)]) return false;\n        }\n        return true;\n    }\n\n    bool validateRot45(const Candidate& cd) const {\n        // A(ax,ay), B(bx,by) on +1 diag, C(cx,cy) on -1 diag, D=p1=B+C-A\n        int ax=cd.ax, ay=cd.ay, bx=cd.bx, by=cd.by, cx=cd.cx, cy=cd.cy;\n        int dx=cd.p1x, dy=cd.p1y;\n\n        // basic checks\n        if (!isInside(dx,dy) || occ[idx(dx,dy)]) return false;\n        if (!isInside(ax,ay) || !isInside(bx,by) || !isInside(cx,cy)) return false;\n        if (!occ[idx(ax,ay)] || !occ[idx(bx,by)] || !occ[idx(cx,cy)]) return false;\n\n        // Check geometry: AB slope +1, AC slope -1\n        if (abs(bx - ax) != abs(by - ay)) return false;\n        if (abs(cx - ax) != abs(cy - ay)) return false;\n        int d1 = abs(bx - ax);\n        int d2 = abs(cx - ax);\n        if (d1 == 0 || d2 == 0) return false;\n\n        // D must equal B + C - A\n        if (!(dx == bx + cx - ax && dy == by + cy - ay)) return false;\n\n        int s1x = (bx > ax) ? 1 : -1;\n        int s1y = (by > ay) ? 1 : -1;\n        int s2x = (cx > ax) ? 1 : -1;\n        int s2y = (cy > ay) ? 1 : -1;\n\n        // Perimeter interior points empty\n        // AB interior (+1)\n        for (int t=1; t<=d1-1; ++t) {\n            if (occ[idx(ax + s1x*t, ay + s1y*t)]) return false;\n        }\n        // AC interior (-1)\n        for (int t=1; t<=d2-1; ++t) {\n            if (occ[idx(ax + s2x*t, ay + s2y*t)]) return false;\n        }\n        // BD interior (-1)\n        for (int t=1; t<=d2-1; ++t) {\n            if (occ[idx(bx + s2x*t, by + s2y*t)]) return false;\n        }\n        // DC interior (+1), direction is from D to C which is -s1\n        int ns1x = -s1x, ns1y = -s1y;\n        for (int t=1; t<=d1-1; ++t) {\n            if (occ[idx(dx + ns1x*t, dy + ns1y*t)]) return false;\n        }\n\n        // No used segments: AB and DC are diag +1; BD and CA are diag -1\n        // AB (+1)\n        for (int t=0; t<=d1-1; ++t) {\n            int x0 = ax + s1x*t, y0 = ay + s1y*t;\n            int x1 = ax + s1x*(t+1), y1 = ay + s1y*(t+1);\n            if (usedD1[idxD1_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n        // BD (-1)\n        for (int t=0; t<=d2-1; ++t) {\n            int x0 = bx + s2x*t, y0 = by + s2y*t;\n            int x1 = bx + s2x*(t+1), y1 = by + s2y*(t+1);\n            if (usedD2[idxD2_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n        // DC (+1) from D towards C with -s1\n        for (int t=0; t<=d1-1; ++t) {\n            int x0 = dx + ns1x*t, y0 = dy + ns1y*t;\n            int x1 = dx + ns1x*(t+1), y1 = dy + ns1y*(t+1);\n            if (usedD1[idxD1_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n        // CA (-1) from C towards A with -s2\n        for (int t=0; t<=d2-1; ++t) {\n            int x0 = cx - s2x*t, y0 = cy - s2y*t;\n            int x1 = cx - s2x*(t+1), y1 = cy - s2y*(t+1);\n            if (usedD2[idxD2_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n\n        return true;\n    }\n\n    bool validate(const Candidate& cd) const {\n        if (cd.type == 0) return validateAxis(cd);\n        else return validateRot45(cd);\n    }\n\n    // -------- Mark used segments after committing --------\n    void markUsedSegments(const Candidate& cd) {\n        if (cd.type == 0) {\n            for (int x = cd.xL; x <= cd.xR-1; ++x) {\n                usedH[idxH(x, cd.yB)] = 1;\n                usedH[idxH(x, cd.yT)] = 1;\n            }\n            for (int y = cd.yB; y <= cd.yT-1; ++y) {\n                usedV[idxV(cd.xL, y)] = 1;\n                usedV[idxV(cd.xR, y)] = 1;\n            }\n        } else {\n            int ax=cd.ax, ay=cd.ay, bx=cd.bx, by=cd.by, cx=cd.cx, cy=cd.cy;\n            int dx=cd.p1x, dy=cd.p1y;\n            int s1x = (bx > ax) ? 1 : -1;\n            int s1y = (by > ay) ? 1 : -1;\n            int s2x = (cx > ax) ? 1 : -1;\n            int s2y = (cy > ay) ? 1 : -1;\n            int ns1x = -s1x, ns1y = -s1y;\n            int d1 = abs(bx - ax);\n            int d2 = abs(cx - ax);\n\n            // AB (+1)\n            for (int t=0; t<=d1-1; ++t) {\n                int x0 = ax + s1x*t, y0 = ay + s1y*t;\n                int x1 = ax + s1x*(t+1), y1 = ay + s1y*(t+1);\n                usedD1[idxD1_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n            // BD (-1)\n            for (int t=0; t<=d2-1; ++t) {\n                int x0 = bx + s2x*t, y0 = by + s2y*t;\n                int x1 = bx + s2x*(t+1), y1 = by + s2y*(t+1);\n                usedD2[idxD2_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n            // DC (+1)\n            for (int t=0; t<=d1-1; ++t) {\n                int x0 = dx + ns1x*t, y0 = dy + ns1y*t;\n                int x1 = dx + ns1x*(t+1), y1 = dy + ns1y*(t+1);\n                usedD1[idxD1_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n            // CA (-1)\n            for (int t=0; t<=d2-1; ++t) {\n                int x0 = cx - s2x*t, y0 = cy - s2y*t;\n                int x1 = cx - s2x*(t+1), y1 = cy - s2y*(t+1);\n                usedD2[idxD2_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n        }\n    }\n\n    void emitOperation(const Candidate& cd) {\n        Operation op;\n        if (cd.type == 0) {\n            // order cycle LL -> LR -> UR -> UL; rotate so p1 is first\n            int LLx = cd.xL, LLy = cd.yB;\n            int LRx = cd.xR, LRy = cd.yB;\n            int URx = cd.xR, URy = cd.yT;\n            int ULx = cd.xL, ULy = cd.yT;\n            array<pair<int,int>,4> seq = {{{LLx,LLy},{LRx,LRy},{URx,URy},{ULx,ULy}}};\n            int pos = 0;\n            for (int i=0;i<4;i++) if (seq[i].first==cd.p1x && seq[i].second==cd.p1y) { pos=i; break; }\n            auto get = [&](int k)->pair<int,int> { return seq[(pos + k) % 4]; };\n            auto p1 = get(0);\n            auto p2 = get(1);\n            auto p3 = get(2);\n            auto p4 = get(3);\n            op = {p1.first,p1.second,p2.first,p2.second,p3.first,p3.second,p4.first,p4.second};\n        } else {\n            // cycle is A -> B -> D -> C -> A; start with D\n            int ax=cd.ax, ay=cd.ay, bx=cd.bx, by=cd.by, cx=cd.cx, cy=cd.cy;\n            int dx=cd.p1x, dy=cd.p1y;\n            op = {dx,dy, cx,cy, ax,ay, bx,by};\n        }\n        ops.push_back(op);\n    }\n\n    // -------- Axis inside-perimeter estimator --------\n    inline int axisInsideLen(int xL, int yB, int xR, int yT) const {\n        if (minX > maxX) return 0;\n        int inside = 0;\n        // horizontal at yB\n        if (yB >= minY && yB <= maxY) {\n            int L = max(xL, minX);\n            int R = min(xR, maxX);\n            if (R > L) inside += (R - L);\n        }\n        // horizontal at yT\n        if (yT >= minY && yT <= maxY) {\n            int L = max(xL, minX);\n            int R = min(xR, maxX);\n            if (R > L) inside += (R - L);\n        }\n        // vertical at xL\n        if (xL >= minX && xL <= maxX) {\n            int B = max(yB, minY);\n            int T = min(yT, maxY);\n            if (T > B) inside += (T - B);\n        }\n        // vertical at xR\n        if (xR >= minX && xR <= maxX) {\n            int B = max(yB, minY);\n            int T = min(yT, maxY);\n            if (T > B) inside += (T - B);\n        }\n        return inside;\n    }\n\n    // -------- Diagonal inside-perimeter estimator (segments entirely inside bbox) --------\n    inline int diagInsideSegs(int x0, int y0, int sx, int sy, int len) const {\n        if (minX > maxX) return 0;\n        int tLowX, tHighX, tLowY, tHighY;\n        if (sx == 1) { tLowX = minX - x0; tHighX = maxX - x0; }\n        else         { tLowX = x0 - maxX; tHighX = x0 - minX; }\n        if (sy == 1) { tLowY = minY - y0; tHighY = maxY - y0; }\n        else         { tLowY = y0 - maxY; tHighY = y0 - minY; }\n        int L = max({0, tLowX, tLowY});\n        int R = min({len, tHighX, tHighY});\n        int cnt = R - L;\n        if (cnt < 0) cnt = 0;\n        return cnt;\n    }\n\n    inline int rotInsideLen(int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy) const {\n        int d1 = abs(bx - ax);\n        int d2 = abs(cx - ax);\n        int s1x = (bx > ax) ? 1 : -1;\n        int s1y = (by > ay) ? 1 : -1;\n        int s2x = (cx > ax) ? 1 : -1;\n        int s2y = (cy > ay) ? 1 : -1;\n        int ns1x = -s1x, ns1y = -s1y;\n        // AB (+1), BD (-1), DC (+1), CA (-1)\n        int inside = 0;\n        inside += diagInsideSegs(ax, ay, s1x, s1y, d1);\n        inside += diagInsideSegs(bx, by, s2x, s2y, d2);\n        inside += diagInsideSegs(dx, dy, ns1x, ns1y, d1);\n        inside += diagInsideSegs(cx, cy, -s2x, -s2y, d2);\n        return inside;\n    }\n\n    // -------- Candidate generation helpers --------\n\n    void pushAxisCandidateFromPair(int x1, int y1, int x2, int y2) {\n        if (x1 == x2 || y1 == y2) return; // need diagonal pair\n        int xL = min(x1, x2), xR = max(x1, x2);\n        int yB = min(y1, y2), yT = max(y1, y2);\n        int c1x = x1, c1y = y2; // (x1,y2)\n        int c2x = x2, c2y = y1; // (x2,y1)\n        bool occ1 = occ[idx(c1x, c1y)];\n        bool occ2 = occ[idx(c2x, c2y)];\n        if (occ1 == occ2) return; // need exactly one occupied\n\n        uint64_t key = axisKey(xL, yB, xR, yT);\n        if (seenAxis.find(key) != seenAxis.end()) return;\n\n        Candidate cd;\n        cd.type = 0;\n        if (!occ1) { cd.p1x = c1x; cd.p1y = c1y; }\n        else       { cd.p1x = c2x; cd.p1y = c2y; }\n        cd.xL = xL; cd.xR = xR; cd.yB = yB; cd.yT = yT;\n        cd.w = weight(cd.p1x, cd.p1y);\n        cd.perim = 2 * ((xR - xL) + (yT - yB));\n        cd.insideLen = axisInsideLen(xL, yB, xR, yT);\n        cd.score = computePriority(cd.p1x, cd.p1y, cd.perim, cd.w, cd.type, cd.insideLen);\n        if (validate(cd)) {\n            pq.push(cd);\n            seenAxis.insert(key);\n        }\n    }\n\n    void pushRot45CandidateFromPivotABC(int ax, int ay, int bx, int by, int cx, int cy) {\n        // D = B + C - A\n        int dx = bx + cx - ax;\n        int dy = by + cy - ay;\n        if (!isInside(dx,dy)) return;\n        if (occ[idx(dx,dy)]) return; // must be empty\n\n        uint64_t key = rotKeyFromABC(ax,ay,bx,by,cx,cy);\n        if (seenRot.find(key) != seenRot.end()) return;\n\n        Candidate cd;\n        cd.type = 1;\n        cd.ax = ax; cd.ay = ay; cd.bx = bx; cd.by = by; cd.cx = cx; cd.cy = cy;\n        cd.p1x = dx; cd.p1y = dy;\n        cd.w = weight(dx,dy);\n\n        int d1 = abs(bx - ax);\n        int d2 = abs(cx - ax);\n        if (d1 == 0 || d2 == 0) return;\n        cd.perim = 2*(d1 + d2);\n        cd.insideLen = rotInsideLen(ax, ay, bx, by, cx, cy, dx, dy);\n        cd.score = computePriority(cd.p1x, cd.p1y, cd.perim, cd.w, cd.type, cd.insideLen);\n\n        if (validate(cd)) {\n            pq.push(cd);\n            seenRot.insert(key);\n        }\n    }\n\n    void generateRot45FromPivot(int ax, int ay) {\n        int idp = diagPlusId(ax, ay);\n        int idm = diagMinusId(ax, ay);\n        auto &Blist = diagPlus[idp];\n        auto &Clist = diagMinus[idm];\n        if (Blist.size() <= 1 || Clist.size() <= 1) return;\n\n        for (auto &B : Blist) {\n            int bx = B.first, by = B.second;\n            if (bx == ax && by == ay) continue;\n            for (auto &C : Clist) {\n                int cx = C.first, cy = C.second;\n                if (cx == ax && cy == ay) continue;\n                pushRot45CandidateFromPivotABC(ax, ay, bx, by, cx, cy);\n            }\n        }\n    }\n\n    // incremental 45\u00b0 generation using the new point as B (same +1 diagonal as A)\n    void generateRot45WithNewAsB(int nx, int ny) {\n        int idp = diagPlusId(nx, ny);\n        auto &AList = diagPlus[idp];\n        for (auto &A : AList) {\n            int ax = A.first, ay = A.second;\n            if (ax == nx && ay == ny) continue; // skip itself\n            auto &Clist = diagMinus[diagMinusId(ax, ay)];\n            if (Clist.empty()) continue;\n            for (auto &C : Clist) {\n                int cx = C.first, cy = C.second;\n                if (cx == ax && cy == ay) continue; // avoid zero length\n                pushRot45CandidateFromPivotABC(ax, ay, nx, ny, cx, cy);\n            }\n        }\n    }\n\n    // incremental 45\u00b0 generation using the new point as C (same -1 diagonal as A)\n    void generateRot45WithNewAsC(int nx, int ny) {\n        int idm = diagMinusId(nx, ny);\n        auto &AList = diagMinus[idm];\n        for (auto &A : AList) {\n            int ax = A.first, ay = A.second;\n            if (ax == nx && ay == ny) continue; // skip itself\n            auto &Blist = diagPlus[diagPlusId(ax, ay)];\n            if (Blist.empty()) continue;\n            for (auto &B : Blist) {\n                int bx = B.first, by = B.second;\n                if (bx == ax && by == ay) continue; // avoid zero length\n                pushRot45CandidateFromPivotABC(ax, ay, bx, by, nx, ny);\n            }\n        }\n    }\n\n    // incremental axis generation: new point as off-diagonal corner\n    void generateAxisWithNewAsOffDiag(int nx, int ny) {\n        auto &colList = colYs[nx]; // y's in same column\n        auto &rowList = rowXs[ny]; // x's in same row\n        if (colList.empty() || rowList.empty()) return;\n\n        for (int yA : colList) {\n            if (yA == ny) continue;\n            for (int xB : rowList) {\n                if (xB == nx) continue;\n                // The other off-diagonal corner is (xB, yA); if it's occupied, not valid\n                if (occ[idx(xB, yA)]) continue;\n                // A = (nx, yA), B = (xB, ny)\n                pushAxisCandidateFromPair(nx, yA, xB, ny);\n            }\n        }\n    }\n\n    void initialCandidates() {\n        // fill line indices and bounding box\n        for (auto &p : points) {\n            int x = p.first, y = p.second;\n            diagPlus[diagPlusId(x,y)].emplace_back(x,y);\n            diagMinus[diagMinusId(x,y)].emplace_back(x,y);\n            rowXs[y].push_back(x);\n            colYs[x].push_back(y);\n            minX = min(minX, x);\n            maxX = max(maxX, x);\n            minY = min(minY, y);\n            maxY = max(maxY, y);\n        }\n\n        int P = (int)points.size();\n        // Axis-aligned candidates from diagonal pairs\n        for (int i=0;i<P;i++) {\n            auto [x1,y1] = points[i];\n            for (int j=i+1;j<P;j++) {\n                auto [x2,y2] = points[j];\n                pushAxisCandidateFromPair(x1,y1,x2,y2);\n            }\n        }\n\n        // Rotated 45\u00b0 rectangles: generate from every pivot\n        for (auto &p : points) {\n            generateRot45FromPivot(p.first, p.second);\n        }\n    }\n\n    void generateFromNewPointAxisDiagPairs(int nx, int ny) {\n        int P = (int)points.size() - 1; // points[0..P-1] are old points\n        for (int i=0;i<P;i++) {\n            int x2 = points[i].first;\n            int y2 = points[i].second;\n            if (nx != x2 && ny != y2) {\n                pushAxisCandidateFromPair(nx,ny,x2,y2);\n            }\n        }\n    }\n\n    void addPointToLines(int x, int y) {\n        diagPlus[diagPlusId(x,y)].emplace_back(x,y);\n        diagMinus[diagMinusId(x,y)].emplace_back(x,y);\n        rowXs[y].push_back(x);\n        colYs[x].push_back(y);\n        if (minX > maxX) {\n            minX = maxX = x;\n            minY = maxY = y;\n        } else {\n            minX = min(minX, x);\n            maxX = max(maxX, x);\n            minY = min(minY, y);\n            maxY = max(maxY, y);\n        }\n    }\n\n    void solve() {\n        auto start = chrono::steady_clock::now();\n        const double TIME_LIMIT = 4.95; // seconds\n\n        // initial candidates\n        initialCandidates();\n\n        while (!pq.empty()) {\n            // time check\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - start).count();\n            if (elapsed > TIME_LIMIT) break;\n\n            Candidate cd = pq.top(); pq.pop();\n            if (!validate(cd)) continue;\n\n            // Commit this operation\n            occ[idx(cd.p1x, cd.p1y)] = 1;\n            points.emplace_back(cd.p1x, cd.p1y);\n            addPointToLines(cd.p1x, cd.p1y);\n            markUsedSegments(cd);\n            emitOperation(cd);\n            opsCount++;\n\n            // Generate new candidates involving the new point\n            // Axis-aligned:\n            // 1) diag pairs with new as one diagonal corner\n            generateFromNewPointAxisDiagPairs(cd.p1x, cd.p1y);\n            // 2) new as off-diagonal corner\n            generateAxisWithNewAsOffDiag(cd.p1x, cd.p1y);\n\n            // Rotated 45\u00b0:\n            // 1) new point as pivot (opposite corner missing)\n            generateRot45FromPivot(cd.p1x, cd.p1y);\n            // 2) new point as B and as C relative to existing pivots\n            generateRot45WithNewAsB(cd.p1x, cd.p1y);\n            generateRot45WithNewAsC(cd.p1x, cd.p1y);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    Solver solver(N, M);\n    solver.points.reserve(N*N);\n    for (int i=0;i<M;i++) {\n        int x,y; cin >> x >> y;\n        solver.points.emplace_back(x,y);\n        solver.occ[solver.idx(x,y)] = 1;\n    }\n\n    solver.solve();\n\n    cout << solver.ops.size() << '\\n';\n    for (auto &op : solver.ops) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << ' '\n             << op.x3 << ' ' << op.y3 << ' ' << op.x4 << ' ' << op.y4 << '\\n';\n    }\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    void reset(int m){ n=m; p.resize(n); sz.assign(n,1); iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\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; sz[a]+=sz[b];\n        return true;\n    }\n    int size(int x){ return sz[find(x)]; }\n};\n\nstruct Simulator {\n    static const int H = 10;\n    static const int W = 10;\n    array<array<int,W>,H> board;\n\n    Simulator() { for (int r=0;r<H;r++) for (int c=0;c<W;c++) board[r][c]=0; }\n\n    pair<int,int> emptyIndexToRC(int p) const {\n        int cnt=0;\n        for (int r=0;r<H;r++){\n            for (int c=0;c<W;c++){\n                if (board[r][c]==0){\n                    ++cnt;\n                    if (cnt==p) return {r,c};\n                }\n            }\n        }\n        return {-1,-1};\n    }\n\n    struct SimResult {\n        array<array<int,W>,H> b;\n        int new_r, new_c;\n    };\n\n    // dir: 0=F,1=B,2=L,3=R\n    SimResult simulateTilt(const array<array<int,W>,H>& inputBoard, int dir, int src_r, int src_c) const {\n        SimResult res;\n        for (int r=0;r<H;r++) for (int c=0;c<W;c++) res.b[r][c]=0;\n\n        if (dir == 0) { // F (up)\n            int cnt = 0;\n            for (int r=0; r<=src_r; ++r) if (inputBoard[r][src_c]!=0) ++cnt;\n            res.new_r = cnt-1; res.new_c = src_c;\n            for (int c=0;c<W;c++){\n                int to=0;\n                for (int r=0;r<H;r++){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[to++][c] = v;\n                }\n            }\n        } else if (dir == 1) { // B (down)\n            int cnt = 0;\n            for (int r=src_r; r<H; ++r) if (inputBoard[r][src_c]!=0) ++cnt;\n            res.new_r = H-1-(cnt-1); res.new_c = src_c;\n            for (int c=0;c<W;c++){\n                int to=H-1;\n                for (int r=H-1;r>=0;r--){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[to--][c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            int cnt = 0;\n            for (int c=0; c<=src_c; ++c) if (inputBoard[src_r][c]!=0) ++cnt;\n            res.new_r = src_r; res.new_c = cnt-1;\n            for (int r=0;r<H;r++){\n                int to=0;\n                for (int c=0;c<W;c++){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[r][to++] = v;\n                }\n            }\n        } else { // R\n            int cnt = 0;\n            for (int c=src_c; c<W; ++c) if (inputBoard[src_r][c]!=0) ++cnt;\n            res.new_r = src_r; res.new_c = W-1-(cnt-1);\n            for (int r=0;r<H;r++){\n                int to=W-1;\n                for (int c=W-1;c>=0;c--){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[r][to--] = v;\n                }\n            }\n        }\n        return res;\n    }\n};\n\nstatic const int H = Simulator::H;\nstatic const int W = Simulator::W;\n\ninline int id(int r,int c){ return r*W + c; }\n\nstruct BoardStats {\n    long long sumSq;\n    long long sameAdj;\n    long long crossAdj;\n};\n\n// Compute sumSq, same-adjacency pairs, cross-adjacency pairs\nBoardStats computeStats(const array<array<int,W>,H>& b) {\n    DSU dsu(H*W);\n    long long sameAdj = 0, crossAdj = 0;\n    for (int r=0;r<H;r++){\n        for (int c=0;c<W;c++){\n            int v = b[r][c];\n            if (!v) continue;\n            if (r+1<H) {\n                int u = b[r+1][c];\n                if (u) {\n                    if (u==v) { sameAdj++; dsu.unite(id(r,c), id(r+1,c)); }\n                    else crossAdj++;\n                }\n            }\n            if (c+1<W) {\n                int u = b[r][c+1];\n                if (u) {\n                    if (u==v) { sameAdj++; dsu.unite(id(r,c), id(r,c+1)); }\n                    else crossAdj++;\n                }\n            }\n        }\n    }\n    vector<int> cnt(H*W,0);\n    for (int r=0;r<H;r++) for (int c=0;c<W;c++) if (b[r][c]!=0) cnt[dsu.find(id(r,c))]++;\n    long long sumSq = 0;\n    for (int i=0;i<H*W;i++) if (cnt[i]>0) sumSq += 1LL*cnt[i]*cnt[i];\n    return {sumSq, sameAdj, crossAdj};\n}\n\nlong long totalMovementDistance(const array<array<int,W>,H>& b0, int dir) {\n    long long mv=0;\n    if (dir==0){ // F\n        for (int c=0;c<W;c++){\n            vector<int> rows; rows.reserve(H);\n            for (int r=0;r<H;r++) if (b0[r][c]!=0) rows.push_back(r);\n            for (int i=0;i<(int)rows.size();i++) mv += rows[i] - i;\n        }\n    } else if (dir==1){ // B\n        for (int c=0;c<W;c++){\n            vector<int> rows; rows.reserve(H);\n            for (int r=0;r<H;r++) if (b0[r][c]!=0) rows.push_back(r);\n            int k=(int)rows.size();\n            for (int i=0;i<k;i++){\n                int newr = H - k + i;\n                mv += newr - rows[i];\n            }\n        }\n    } else if (dir==2){ // L\n        for (int r=0;r<H;r++){\n            vector<int> cols; cols.reserve(W);\n            for (int c=0;c<W;c++) if (b0[r][c]!=0) cols.push_back(c);\n            for (int j=0;j<(int)cols.size();j++) mv += cols[j] - j;\n        }\n    } else { // R\n        for (int r=0;r<H;r++){\n            vector<int> cols; cols.reserve(W);\n            for (int c=0;c<W;c++) if (b0[r][c]!=0) cols.push_back(c);\n            int k=(int)cols.size();\n            for (int j=0;j<k;j++){\n                int newc = W - k + j;\n                mv += newc - cols[j];\n            }\n        }\n    }\n    return mv;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> f(100);\n    for (int i=0;i<100;i++){\n        if(!(cin>>f[i])) return 0;\n    }\n\n    Simulator sim;\n\n    // Corners: 0 TL, 1 TR, 2 BL, 3 BR\n    array<pair<int,int>,4> corners = { pair<int,int>{0,0}, {0,9}, {9,0}, {9,9} };\n    int distToCorner[4][H][W];\n    for (int k=0;k<4;k++){\n        auto [tr,tc] = corners[k];\n        for (int r=0;r<H;r++) for (int c=0;c<W;c++) distToCorner[k][r][c] = abs(r-tr)+abs(c-tc);\n    }\n\n    // All 4P3 mappings: color->corner (colors 1..3)\n    vector<array<int,4>> mappings;\n    array<int,4> perm = {0,1,2,3};\n    sort(perm.begin(), perm.end());\n    do{\n        array<int,4> m = {0, perm[0], perm[1], perm[2]};\n        mappings.push_back(m);\n    }while(next_permutation(perm.begin(), perm.end()));\n\n    // Start with a simple mapping: 1->TL,2->TR,3->BL\n    array<int,4> currentMap = {0,0,1,2};\n\n    static const int dr4[4] = {-1,1,0,0};\n    static const int dc4[4] = {0,0,-1,1};\n\n    // RNG for lookahead sampling (deterministic)\n    std::mt19937 rng(123456789);\n\n    for (int t=0;t<100;t++){\n        int p; if(!(cin>>p)) return 0;\n        auto [r,c] = sim.emptyIndexToRC(p);\n        auto board0 = sim.board;\n        int color = f[t];\n        board0[r][c] = color;\n\n        double progress = (t<=99 ? (double)t/99.0 : 1.0);\n\n        // Immediate evaluation weights\n        double w_comp       = 10.0 + 22.0*progress;\n        double w_compDelta  = 2.0 + 6.0*progress;\n        double w_adjDelta   = 1.0 + 4.0*progress;\n\n        double w_crossAbs   = 0.2 + 0.4*progress;\n        double w_crossDelta = 0.1 + 0.3*progress;\n\n        double w_sumDist    = 0.25 - 0.15*progress;\n\n        double w_newAbs     = 0.6*(1.0-progress) + 0.1;\n        double w_newDelta   = 1.5*(1.0 - 0.3*progress);\n\n        double w_adjNewSame = 2.0 + 1.0*progress;\n        double w_adjNewDiff = 0.3;\n\n        double w_move       = 0.02 + 0.06*progress;\n\n        // Mapping handling (moderate inertia and late freeze)\n        double mapConsistencyBonus = 0.2;\n        double mapPenalty = 12.0 + 100.0*progress;\n        int freezeT = 80;\n        double changeMargin = (80.0 + 200.0*progress);\n\n        // Next-candy lookahead settings\n        int nextColor = (t+1<100 ? f[t+1] : 0);\n        int sampleK = 14; // number of sampled empty placements for next candy\n        double look_cross_w = 4.0 + 2.0*progress; // penalty for cross adjacency in lookahead\n        double look_move_w = 0.02 + 0.04*progress; // movement penalty in lookahead\n\n        // Precompute before-stats (with placed candy before tilt)\n        BoardStats beforeStats = computeStats(board0);\n        long long sumSq0 = beforeStats.sumSq;\n        long long adjBefore = beforeStats.sameAdj;\n        long long crossBefore = beforeStats.crossAdj;\n\n        array<Simulator::SimResult,4> ress;\n        array<BoardStats,4> statsAfter;\n        array<long long,4> moveDist;\n        array<int,4> adjNewSame;\n        array<int,4> adjNewDiff;\n        array<long long,4> sumDistAfterCurrentMap;\n        array<int,4> newDistAfterCurrentMap;\n\n        for (int d=0; d<4; d++){\n            ress[d] = sim.simulateTilt(board0, d, r, c);\n            statsAfter[d] = computeStats(ress[d].b);\n            moveDist[d] = totalMovementDistance(board0, d);\n\n            // new candy neighborhood after tilt\n            int nr = ress[d].new_r, nc = ress[d].new_c;\n            int same=0, diff=0;\n            for (int k=0;k<4;k++){\n                int rr = nr + dr4[k], cc = nc + dc4[k];\n                if (0<=rr && rr<H && 0<=cc && cc<W){\n                    int v = ress[d].b[rr][cc];\n                    if (!v) continue;\n                    if (v == color) same++;\n                    else diff++;\n                }\n            }\n            adjNewSame[d] = same;\n            adjNewDiff[d] = diff;\n\n            // distances for current mapping\n            long long sumDist = 0;\n            for (int rr=0; rr<H; rr++){\n                for (int cc=0; cc<W; cc++){\n                    int v = ress[d].b[rr][cc];\n                    if (!v) continue;\n                    int cornerIdx = currentMap[v];\n                    sumDist += distToCorner[cornerIdx][rr][cc];\n                }\n            }\n            sumDistAfterCurrentMap[d] = sumDist;\n            int cornerIdx = currentMap[color];\n            newDistAfterCurrentMap[d] = distToCorner[cornerIdx][ress[d].new_r][ress[d].new_c];\n        }\n\n        int cornerIdxCur = currentMap[color];\n        int newDistBeforeCur = distToCorner[cornerIdxCur][r][c];\n\n        // Immediate scores for current mapping (used for guard)\n        array<double,4> immScore{};\n        double bestImmScore = -1e100;\n        int bestImmDir = 0;\n        for (int d=0; d<4; d++){\n            double score = 0.0;\n            score += w_comp * (double)statsAfter[d].sumSq;\n            score += w_compDelta * (double)(statsAfter[d].sumSq - sumSq0);\n            score += w_adjDelta * (double)(statsAfter[d].sameAdj - adjBefore);\n            score -= w_crossAbs * (double)statsAfter[d].crossAdj;\n            score -= w_crossDelta * (double)(statsAfter[d].crossAdj - crossBefore);\n            score -= w_sumDist * (double)sumDistAfterCurrentMap[d];\n\n            score -= w_newAbs * (double)newDistAfterCurrentMap[d];\n            score += w_newDelta * (double)(newDistBeforeCur - newDistAfterCurrentMap[d]);\n            score += w_adjNewSame * (double)adjNewSame[d];\n            score -= w_adjNewDiff * (double)adjNewDiff[d];\n\n            score -= w_move * (double)moveDist[d];\n\n            // small consistency bonus to sticking with current mapping (already fixed here)\n            score += mapConsistencyBonus;\n\n            immScore[d] = score;\n            if (score > bestImmScore) {\n                bestImmScore = score;\n                bestImmDir = d;\n            }\n        }\n\n        // 1-step lookahead (mapping-independent, focuses on sumSq and slight penalties)\n        array<double,4> exp2{};\n        int emptiesNow = 100 - (t+1);\n        if (nextColor && emptiesNow > 0) {\n            for (int d0=0; d0<4; d0++){\n                const auto& B1 = ress[d0].b;\n                vector<pair<int,int>> empties;\n                empties.reserve(H*W);\n                for (int rr=0; rr<H; rr++) for (int cc=0; cc<W; cc++) if (B1[rr][cc]==0) empties.emplace_back(rr,cc);\n                int M = (int)empties.size();\n                if (M == 0) { exp2[d0] = (double)statsAfter[d0].sumSq; continue; }\n                // sample K positions without replacement (or all if small)\n                vector<int> idx(M);\n                iota(idx.begin(), idx.end(), 0);\n                if (M > sampleK) {\n                    // partial shuffle for first sampleK\n                    for (int i=0;i<sampleK;i++){\n                        uniform_int_distribution<int> dist(i, M-1);\n                        int j = dist(rng);\n                        swap(idx[i], idx[j]);\n                    }\n                    idx.resize(sampleK);\n                }\n                double accum = 0.0;\n                for (int s=0; s<(int)idx.size(); s++){\n                    int rr = empties[idx[s]].first;\n                    int cc = empties[idx[s]].second;\n                    auto board1plus = B1;\n                    board1plus[rr][cc] = nextColor;\n                    double best2 = -1e100;\n                    for (int d1=0; d1<4; d1++){\n                        auto res2 = sim.simulateTilt(board1plus, d1, rr, cc);\n                        BoardStats st2 = computeStats(res2.b);\n                        double mv2 = totalMovementDistance(board1plus, d1);\n                        double val = (double)st2.sumSq\n                                     - look_cross_w * (double)st2.crossAdj\n                                     - look_move_w * mv2;\n                        if (val > best2) best2 = val;\n                    }\n                    accum += best2;\n                }\n                exp2[d0] = accum / (double)idx.size();\n            }\n        } else {\n            // no next candy or no empties: fallback to immediate sumSq\n            for (int d0=0; d0<4; d0++) exp2[d0] = (double)statsAfter[d0].sumSq;\n        }\n\n        int lhDir = 0;\n        double bestExp2 = -1e100;\n        for (int d=0; d<4; d++){\n            if (exp2[d] > bestExp2) { bestExp2 = exp2[d]; lhDir = d; }\n        }\n\n        // Guard: don't accept lookahead if immediate score is much worse\n        double tol = 0.03 * fabs(bestImmScore) + 50.0;\n        int chosenDir = lhDir;\n        if (immScore[lhDir] + tol < bestImmScore) {\n            chosenDir = bestImmDir;\n        }\n\n        // Choose mapping for chosenDir with inertia and optional freeze\n        // Precompute distances for this direction's board for all corners\n        long long Sfinal[4][4]; memset(Sfinal, 0, sizeof(Sfinal)); // color 1..3, corner 0..3\n        long long Eempty[4] = {0,0,0,0};\n        int emptyCntFinal = 0;\n        const auto& Bfinal = ress[chosenDir].b;\n        for (int rr=0; rr<H; rr++){\n            for (int cc=0; cc<W; cc++){\n                int v = Bfinal[rr][cc];\n                if (v == 0) {\n                    for (int k=0;k<4;k++){\n                        Eempty[k] += distToCorner[k][rr][cc];\n                    }\n                    emptyCntFinal++;\n                } else {\n                    for (int k=0;k<4;k++){\n                        Sfinal[v][k] += distToCorner[k][rr][cc];\n                    }\n                }\n            }\n        }\n        int newDistAfterChosen_CurrentCorner = distToCorner[currentMap[color]][ress[chosenDir].new_r][ress[chosenDir].new_c];\n        int newDistBefore_CurrentCorner = distToCorner[currentMap[color]][r][c];\n\n        // Score for a given mapping on chosenDir\n        auto mappingScore = [&](const array<int,4>& cmap, bool isCurrent)->double{\n            long long sumDist = Sfinal[1][cmap[1]] + Sfinal[2][cmap[2]] + Sfinal[3][cmap[3]];\n            int newDistAfter = distToCorner[cmap[color]][ress[chosenDir].new_r][ress[chosenDir].new_c];\n            int newDistBefore = distToCorner[cmap[color]][r][c];\n            double sc = 0.0;\n            sc += w_comp * (double)statsAfter[chosenDir].sumSq;\n            sc += w_compDelta * (double)(statsAfter[chosenDir].sumSq - sumSq0);\n            sc += w_adjDelta * (double)(statsAfter[chosenDir].sameAdj - adjBefore);\n            sc -= w_crossAbs * (double)statsAfter[chosenDir].crossAdj;\n            sc -= w_crossDelta * (double)(statsAfter[chosenDir].crossAdj - crossBefore);\n            sc -= w_sumDist * (double)sumDist;\n            sc -= w_newAbs * (double)newDistAfter;\n            sc += w_newDelta * (double)(newDistBefore - newDistAfter);\n            sc += w_adjNewSame * (double)adjNewSame[chosenDir];\n            sc -= w_adjNewDiff * (double)adjNewDiff[chosenDir];\n            sc -= w_move * (double)moveDist[chosenDir];\n            if (isCurrent) sc += mapConsistencyBonus;\n            return sc;\n        };\n\n        double scoreCurrentMap = mappingScore(currentMap, true);\n        double bestMapScore = scoreCurrentMap;\n        array<int,4> bestMap = currentMap;\n        for (const auto& cmap : mappings) {\n            if (cmap == currentMap) continue;\n            double sc = mappingScore(cmap, false) - mapPenalty;\n            if (sc > bestMapScore) {\n                bestMapScore = sc;\n                bestMap = cmap;\n            }\n        }\n        if (t >= freezeT && bestMap != currentMap) {\n            if (bestMapScore < scoreCurrentMap + changeMargin) {\n                bestMap = currentMap;\n                bestMapScore = scoreCurrentMap;\n            }\n        }\n\n        if (t < 99) {\n            static const char dirs[4] = {'F','B','L','R'};\n            cout << dirs[chosenDir] << '\\n' << flush;\n        }\n\n        sim.board = ress[chosenDir].b;\n        currentMap = bestMap;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Utilities\nstatic inline int ceil_log2_int(int x) {\n    int l = 0; int v = 1;\n    while (v < x) { v <<= 1; l++; }\n    return l;\n}\n\n// Build an R x A binary matrix alpha with column sums t[a],\n// keeping row sums balanced and pairwise distances large.\nstatic vector<vector<int>> build_alpha(int R, int A, const vector<int>& t, mt19937_64 &rng) {\n    vector<vector<int>> alpha(R, vector<int>(A, 0));\n    vector<int> rowSum(R, 0);\n\n    // Greedy column fill by balancing row sums\n    for (int a = 0; a < A; ++a) {\n        int need = t[a];\n        vector<int> idx(R);\n        iota(idx.begin(), idx.end(), 0);\n        stable_sort(idx.begin(), idx.end(), [&](int r1, int r2){\n            if (rowSum[r1] != rowSum[r2]) return rowSum[r1] < rowSum[r2];\n            return r1 < r2;\n        });\n        for (int k = 0; k < need && k < R; ++k) {\n            int r = idx[k];\n            alpha[r][a] = 1;\n            rowSum[r]++;\n        }\n    }\n\n    // Small local improvement\n    auto min_pairwise_dist = [&]() {\n        if (R <= 1) return A;\n        int mind = INT_MAX;\n        for (int i = 0; i < R; ++i) {\n            for (int j = i+1; j < R; ++j) {\n                int d = 0;\n                for (int a = 0; a < A; ++a) if (alpha[i][a] != alpha[j][a]) d++;\n                mind = min(mind, d);\n            }\n        }\n        if (mind == INT_MAX) mind = 0;\n        return mind;\n    };\n    int currentMinD = min_pairwise_dist();\n\n    auto penalty = [&](const vector<int>& rs) {\n        int p = 0;\n        int target = A/2;\n        for (int r = 0; r < R; ++r) {\n            int d = abs(rs[r] - target);\n            p += d*d;\n        }\n        return p;\n    };\n    int oldPen = penalty(rowSum);\n\n    uniform_int_distribution<int> distA(0, max(0, A-1));\n    uniform_int_distribution<int> distR(0, max(0, R-1));\n    for (int iter = 0; iter < 2000; ++iter) {\n        if (A <= 0 || R <= 1) break;\n        int a = distA(rng);\n        int r1 = distR(rng), r2 = distR(rng);\n        if (r1 == r2) continue;\n        if (alpha[r1][a] == alpha[r2][a]) continue;\n\n        alpha[r1][a] ^= 1;\n        alpha[r2][a] ^= 1;\n\n        int newMinD = min_pairwise_dist();\n        vector<int> rowSumNew = rowSum;\n        rowSumNew[r1] += (alpha[r1][a] ? 1 : -1);\n        rowSumNew[r2] += (alpha[r2][a] ? 1 : -1);\n        int newPen = penalty(rowSumNew);\n\n        bool accept = false;\n        if (newMinD > currentMinD) accept = true;\n        else if (newMinD == currentMinD && newPen <= oldPen) accept = true;\n\n        if (accept) {\n            currentMinD = newMinD;\n            rowSum = rowSumNew;\n            oldPen = newPen;\n        } else {\n            alpha[r1][a] ^= 1;\n            alpha[r2][a] ^= 1;\n        }\n    }\n    return alpha;\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    mt19937_64 rng(123456789);\n\n    // Bits required (for reference)\n    int Lbits = max(1, ceil_log2_int(M));\n\n    // Choose cluster size g more aggressively small for tiny eps to reduce N.\n    int g;\n    if (eps <= 0.02) g = 6;\n    else if (eps <= 0.06) g = 7;\n    else if (eps <= 0.12) g = 8;\n    else if (eps <= 0.20) g = 9;\n    else g = 10;\n\n    // Number of cluster rows R (redundancy). Keep R=Lbits; extra redundancy hurts N.\n    int R = Lbits;\n\n    // Anchors: A = min(R + 1, cap). We use full A=R+1 for maximal separation if fits.\n    int A = R + 1;\n\n    // Column sums t[a] = a in 0..R (strictly increasing)\n    vector<int> t(A);\n    for (int a = 0; a < A; ++a) t[a] = a;\n\n    // Build alpha\n    auto alpha = build_alpha(R, A, t, rng);\n\n    // Row sums\n    vector<int> rowSum(R, 0);\n    for (int i = 0; i < R; ++i) for (int a = 0; a < A; ++a) rowSum[i] += alpha[i][a];\n    int rowSumMax = 0;\n    for (int i = 0; i < R; ++i) rowSumMax = max(rowSumMax, rowSum[i]);\n\n    // Pads U with eps-dependent margin\n    int margin;\n    if (eps <= 0.04) margin = 1;\n    else if (eps <= 0.10) margin = 2;\n    else if (eps <= 0.20) margin = 3;\n    else margin = 3;\n\n    int U = 0;\n    while (true) {\n        int clusterMaxDeg = rowSumMax + (g - 1);\n        int Utarget = max(0, clusterMaxDeg + margin - (A - 1));\n        int N0 = A + R * g;\n        if (N0 > 100) {\n            if (g > 4) { g--; continue; }\n            // reduce A if necessary (choose distinct t[a] spread)\n            if (A > 6) { A--; t.resize(A); for (int a=0;a<A;++a) t[a] = (int)llround( (double)a * R / (double)(A-1) ); alpha = build_alpha(R, A, t, rng);\n                // recompute rowSumMax\n                rowSum.assign(R,0); for(int i=0;i<R;++i) for(int a=0;a<A;++a) rowSum[i]+=alpha[i][a];\n                rowSumMax = 0; for(int i=0;i<R;++i) rowSumMax = max(rowSumMax, rowSum[i]);\n                continue;\n            }\n            // If still too big, reduce R (last resort)\n            if (R > Lbits) { R--; g = max(g, 4); A = min(A, R+1); t.resize(A); for (int a=0;a<A;++a) t[a] = (int)llround( (double)a * R / (double)(A-1) ); alpha = build_alpha(R, A, t, rng);\n                rowSum.assign(R,0); for(int i=0;i<R;++i) for(int a=0;a<A;++a) rowSum[i]+=alpha[i][a];\n                rowSumMax = 0; for(int i=0;i<R;++i) rowSumMax = max(rowSumMax, rowSum[i]);\n                continue;\n            }\n            // fallback\n            break;\n        }\n        if (N0 + Utarget <= 100) {\n            U = Utarget;\n            break;\n        } else {\n            if (g > 4) { g--; continue; }\n            if (A > 6) { A--; t.resize(A); for (int a=0;a<A;++a) t[a] = (int)llround( (double)a * R / (double)(A-1) ); alpha = build_alpha(R, A, t, rng);\n                rowSum.assign(R,0); for(int i=0;i<R;++i) for(int a=0;a<A;++a) rowSum[i]+=alpha[i][a];\n                rowSumMax = 0; for(int i=0;i<R;++i) rowSumMax = max(rowSumMax, rowSum[i]);\n                continue;\n            }\n            // Reduce U to fit\n            U = max(0, 100 - (A + R * g));\n            break;\n        }\n    }\n\n    int N = A + U + R * g;\n    int T = N * (N - 1) / 2;\n\n    // Index mapping (i<j) -> position in string\n    vector<int> offset(N+1, 0);\n    for (int i = 1; i <= N; ++i) offset[i] = offset[i-1] + (N - i);\n    auto idx = [&](int i, int j) -> int {\n        if (i > j) swap(i, j);\n        return offset[i] + (j - i - 1);\n    };\n\n    // Cluster ranges\n    auto cluster_start = [&](int r) { return A + U + r * g; };\n    auto cluster_end = [&](int r) { return A + U + (r + 1) * g - 1; };\n\n    // Build base adjacency string\n    string base(T, '0');\n\n    // Anchors clique\n    for (int i = 0; i < A; ++i)\n        for (int j = i + 1; j < A; ++j)\n            base[idx(i,j)] = '1';\n\n    // Pads connect to all anchors\n    for (int a = 0; a < A; ++a)\n        for (int p = A; p < A + U; ++p)\n            base[idx(a,p)] = '1';\n\n    // Anchor-to-cluster edges via alpha\n    for (int r = 0; r < R; ++r) {\n        int s = cluster_start(r), e = cluster_end(r);\n        for (int a = 0; a < A; ++a) if (alpha[r][a]) {\n            for (int v = s; v <= e; ++v) base[idx(a,v)] = '1';\n        }\n    }\n\n    // Precompute internal edge positions for clusters\n    vector<vector<int>> clusterEdgePos(R);\n    for (int r = 0; r < R; ++r) {\n        int s = cluster_start(r), e = cluster_end(r);\n        for (int u = s; u <= e; ++u)\n            for (int v = u + 1; v <= e; ++v)\n                clusterEdgePos[r].push_back(idx(u,v));\n    }\n\n    // Simple codebook: use identity mapping on R clusters (same as before).\n    // For robustness w.r.t. ML we could design custom codewords, but keeping the simple\n    // mapping retains previous strong performance and benefits from improved assignment.\n    // codebit[r] = bit r of s.\n    // Output N and M graphs\n    cout << N << \"\\n\";\n    cout.flush();\n    for (int k = 0; k < M; ++k) {\n        string out = base;\n        for (int r = 0; r < R; ++r) {\n            int bit = (k >> r) & 1;\n            if (bit) {\n                for (int pos : clusterEdgePos[r]) out[pos] = '1';\n            } else {\n                for (int pos : clusterEdgePos[r]) out[pos] = '0';\n            }\n        }\n        cout << out << \"\\n\";\n    }\n    cout.flush();\n\n    // ML constants\n    double log_p1 = log(max(1e-12, 1.0 - eps));\n    double log_q1 = log(max(1e-12, eps));\n    double log_p0 = log(max(1e-12, eps));\n    double log_q0 = log(max(1e-12, 1.0 - eps));\n\n    // Decoding helper: assign clusters with improved greedy + refinement\n    auto assign_clusters = [&](const vector<vector<char>>& adj, const vector<int>& anchors_ordered){\n        int n = (int)adj.size();\n        vector<int> isAnchorIndex(n, -1);\n        for (int a = 0; a < A; ++a) isAnchorIndex[anchors_ordered[a]] = a;\n\n        vector<int> nonAnchors;\n        nonAnchors.reserve(n - A);\n        for (int v = 0; v < n; ++v) if (isAnchorIndex[v] < 0) nonAnchors.push_back(v);\n\n        // Distances to rows and best rows\n        vector<array<int, 32>> distToRow(n); // R <= 16 in this setup\n        vector<int> bestRow(n, -1), bestD(n, 0), secondD(n, 0);\n        for (int v : nonAnchors) {\n            int d1 = INT_MAX, d2 = INT_MAX, r1 = -1;\n            for (int r = 0; r < R; ++r) {\n                int d = 0;\n                for (int a = 0; a < A; ++a) {\n                    int av = anchors_ordered[a];\n                    int bit = alpha[r][a];\n                    if ((int)adj[v][av] != bit) d++;\n                }\n                distToRow[v][r] = d;\n                if (d < d1) { d2 = d1; d1 = d; r1 = r; }\n                else if (d < d2) d2 = d;\n            }\n            bestRow[v] = r1; bestD[v] = d1; secondD[v] = d2;\n        }\n\n        // Primary candidate lists: for each row, vertices that prefer this row\n        vector<vector<pair<int,int>>> primary(R); // (dist, v)\n        vector<vector<tuple<int,int,int>>> secondary(R); // (gap, dist, v)\n        for (int v : nonAnchors) {\n            int r1 = bestRow[v];\n            primary[r1].push_back({bestD[v], v});\n        }\n        // Prepare secondary lists for fallback: vertices that don't prefer row r\n        for (int r = 0; r < R; ++r) {\n            secondary[r].reserve(nonAnchors.size());\n        }\n        for (int v : nonAnchors) {\n            int r1 = bestRow[v];\n            for (int r = 0; r < R; ++r) if (r != r1) {\n                int gap = distToRow[v][r] - bestD[v]; // >= 0\n                secondary[r].emplace_back(gap, distToRow[v][r], v);\n            }\n        }\n        for (int r = 0; r < R; ++r) {\n            sort(primary[r].begin(), primary[r].end()); // by dist asc\n            sort(secondary[r].begin(), secondary[r].end()); // by gap asc, then dist asc\n        }\n\n        vector<vector<int>> clusterVerts(R);\n        vector<char> used(n, 0);\n        // First pass: take from primary lists\n        for (int r = 0; r < R; ++r) {\n            for (auto &pr : primary[r]) {\n                if ((int)clusterVerts[r].size() >= g) break;\n                int v = pr.second;\n                if (!used[v]) {\n                    clusterVerts[r].push_back(v);\n                    used[v] = 1;\n                }\n            }\n        }\n        // Second pass: fill from secondary lists\n        for (int r = 0; r < R; ++r) {\n            if ((int)clusterVerts[r].size() < g) {\n                for (auto &tp : secondary[r]) {\n                    if ((int)clusterVerts[r].size() >= g) break;\n                    int v = get<2>(tp);\n                    if (!used[v]) {\n                        clusterVerts[r].push_back(v);\n                        used[v] = 1;\n                    }\n                }\n            }\n        }\n        // Last resort: fill any gaps with remaining non-anchors\n        if (true) {\n            for (int r = 0; r < R; ++r) {\n                if ((int)clusterVerts[r].size() < g) {\n                    for (int v : nonAnchors) if (!used[v]) {\n                        clusterVerts[r].push_back(v);\n                        used[v] = 1;\n                        if ((int)clusterVerts[r].size() >= g) break;\n                    }\n                }\n            }\n        }\n        for (int r = 0; r < R; ++r) if ((int)clusterVerts[r].size() > g) clusterVerts[r].resize(g);\n\n        // Local refinement: try beneficial swaps to reduce total distance to rows\n        // Limit iterations for speed\n        for (int it = 0; it < 2; ++it) { // a couple of passes\n            bool improved = false;\n            for (int r1 = 0; r1 < R; ++r1) {\n                for (int r2 = r1+1; r2 < R; ++r2) {\n                    for (int i1 = 0; i1 < (int)clusterVerts[r1].size(); ++i1) {\n                        int v1 = clusterVerts[r1][i1];\n                        int d11 = distToRow[v1][r1];\n                        int d12 = distToRow[v1][r2];\n                        for (int i2 = 0; i2 < (int)clusterVerts[r2].size(); ++i2) {\n                            int v2 = clusterVerts[r2][i2];\n                            int d22 = distToRow[v2][r2];\n                            int d21 = distToRow[v2][r1];\n                            int delta = (d11 + d22) - (d12 + d21);\n                            if (delta > 0) {\n                                // swap\n                                swap(clusterVerts[r1][i1], clusterVerts[r2][i2]);\n                                d11 = distToRow[clusterVerts[r1][i1]][r1]; // update for next\n                                improved = true;\n                            }\n                        }\n                    }\n                }\n            }\n            if (!improved) break;\n        }\n        return clusterVerts;\n    };\n\n    // Decode for a given anchor ordering: returns {bestS, bestLL}\n    auto decode_with_order = [&](const vector<vector<char>>& adj, const vector<int>& deg, const vector<int>& anchors_ordered)->pair<int,double>{\n        // Build assignment\n        auto clusterVerts = assign_clusters(adj, anchors_ordered);\n\n        // Count intra-cluster edges\n        vector<int> x(R, 0), pairCount(R, 0);\n        for (int r = 0; r < R; ++r) {\n            auto &vec = clusterVerts[r];\n            int gi = (int)vec.size();\n            pairCount[r] = gi * (gi - 1) / 2;\n            int cnt = 0;\n            for (int i = 0; i < gi; ++i)\n                for (int j = i + 1; j < gi; ++j)\n                    if (adj[vec[i]][vec[j]]) cnt++;\n            x[r] = cnt;\n        }\n\n        // ML over s in [0..M-1] using codebit[r] = ((s>>r)&1)\n        int bestS = 0;\n        double bestLL = -1e300;\n        for (int s = 0; s < M; ++s) {\n            double ll = 0.0;\n            for (int r = 0; r < R; ++r) {\n                int bit = (s >> r) & 1;\n                int xi = x[r];\n                int ni = pairCount[r];\n                if (bit) ll += xi * log_p1 + (ni - xi) * log_q1;\n                else ll += xi * log_p0 + (ni - xi) * log_q0;\n            }\n            if (ll > bestLL) { bestLL = ll; bestS = s; }\n        }\n        return {bestS, bestLL};\n    };\n\n    // Prepare adj/deg buffers\n    vector<vector<char>> adj(N, vector<char>(N, 0));\n    vector<int> deg(N, 0);\n\n    for (int q = 0; q < 100; ++q) {\n        string H; cin >> H;\n\n        // Build adjacency and degrees\n        int pos = 0;\n        for (int i = 0; i < N; ++i) {\n            deg[i] = 0;\n            for (int j = 0; j < N; ++j) adj[i][j] = 0;\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = i+1; j < N; ++j) {\n                char c = H[pos++];\n                if (c == '1') {\n                    adj[i][j] = adj[j][i] = 1;\n                    deg[i]++; deg[j]++;\n                }\n            }\n        }\n\n        // Identify anchors: top A by degree\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        nth_element(ord.begin(), ord.begin() + A, ord.end(), [&](int x, int y){\n            return deg[x] > deg[y];\n        });\n        vector<int> anchors(ord.begin(), ord.begin() + A);\n\n        // Build 4 candidate orderings\n        vector<vector<int>> orderings;\n\n        // 1) ascending by degree\n        {\n            vector<int> o = anchors;\n            sort(o.begin(), o.end(), [&](int x, int y){\n                if (deg[x] != deg[y]) return deg[x] < deg[y];\n                return x < y;\n            });\n            orderings.push_back(o);\n            reverse(o.begin(), o.end());\n            orderings.push_back(o);\n        }\n        // 2) ascending by degree to non-anchors\n        vector<char> inA(N, 0);\n        for (int v : anchors) inA[v] = 1;\n        {\n            vector<pair<int,int>> tmp;\n            tmp.reserve(A);\n            for (int v : anchors) {\n                int ext = 0;\n                for (int u = 0; u < N; ++u) if (!inA[u] && adj[v][u]) ext++;\n                tmp.emplace_back(ext, v);\n            }\n            sort(tmp.begin(), tmp.end());\n            vector<int> o; o.reserve(A);\n            for (auto &p : tmp) o.push_back(p.second);\n            orderings.push_back(o);\n            reverse(o.begin(), o.end());\n            orderings.push_back(o);\n        }\n\n        // Try all candidate orderings\n        int finalS = 0;\n        double finalLL = -1e300;\n        for (auto &ordA : orderings) {\n            auto res = decode_with_order(adj, deg, ordA);\n            if (res.second > finalLL) {\n                finalLL = res.second;\n                finalS = res.first;\n            }\n        }\n\n        cout << finalS << \"\\n\";\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Edge { int u, v; ll w; };\nstruct AdjEdge { int to, id; ll w; };\n\nconst ll INFLL = (ll)4e18;\n\nint N, M, D, K;\nvector<Edge> edges;\nvector<vector<AdjEdge>> adj;\nvector<int> Xcoord, Ycoord;\n\n// Morton Z-order for tie-breaking\nstatic inline uint64_t part1by1(uint32_t x) {\n    uint64_t v = x & 0x0000ffffu;\n    v = (v | (v << 8)) & 0x00FF00FFu;\n    v = (v | (v << 4)) & 0x0F0F0F0Fu;\n    v = (v | (v << 2)) & 0x33333333u;\n    v = (v | (v << 1)) & 0x55555555u;\n    return v;\n}\nstatic inline uint64_t morton2D_32(uint32_t x, uint32_t y) {\n    return (part1by1(y) << 1) | part1by1(x);\n}\n\n// Dijkstra from s to t while ignoring one banned edge (early exit on t), output parentEdge\nll dijkstra_exclude_with_parent(int s, int t, int banned_edge_id, vector<ll>& dist, vector<int>& parentEdge) {\n    dist.assign(N, INFLL);\n    parentEdge.assign(N, -1);\n    vector<char> vis(N, 0);\n    struct Node { ll d; int v; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n    dist[s] = 0;\n    pq.push({0, s});\n    while (!pq.empty()) {\n        auto [dcur, u] = pq.top(); pq.pop();\n        if (vis[u]) continue;\n        vis[u] = 1;\n        if (u == t) break;\n        for (const auto& ae : adj[u]) {\n            if (ae.id == banned_edge_id) continue;\n            int v = ae.to;\n            ll nd = dcur + ae.w;\n            if (dist[v] > nd) {\n                dist[v] = nd;\n                parentEdge[v] = ae.id;\n                pq.push({nd, v});\n            }\n        }\n    }\n    return dist[t];\n}\n\n// Dijkstra SPT from src (full graph) -> dist, parentEdge\nvoid dijkstra_tree(int src, vector<ll>& dist, vector<int>& parentEdge) {\n    dist.assign(N, INFLL);\n    parentEdge.assign(N, -1);\n    vector<char> vis(N, 0);\n    struct Node { ll d; int v; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n    dist[src] = 0;\n    pq.push({0, src});\n    while (!pq.empty()) {\n        auto [dcur, u] = pq.top(); pq.pop();\n        if (vis[u]) continue;\n        vis[u] = 1;\n        for (const auto& ae : adj[u]) {\n            int v = ae.to;\n            ll nd = dcur + ae.w;\n            if (dist[v] > nd) {\n                dist[v] = nd;\n                parentEdge[v] = ae.id;\n                pq.push({nd, v});\n            }\n        }\n    }\n}\n\n// Components of complement graph for a day (exclude edges scheduled on that day)\nvoid compute_components_for_day(int day, const vector<int>& assign, vector<int>& compId, int& compCount) {\n    compId.assign(N, -1);\n    compCount = 0;\n    deque<int> dq;\n    for (int i = 0; i < N; i++) {\n        if (compId[i] != -1) continue;\n        compId[i] = compCount;\n        dq.push_back(i);\n        while (!dq.empty()) {\n            int u = dq.front(); dq.pop_front();\n            for (const auto& ae : adj[u]) {\n                if (assign[ae.id] == day) continue; // removed that day\n                int v = ae.to;\n                if (compId[v] == -1) {\n                    compId[v] = compCount;\n                    dq.push_back(v);\n                }\n            }\n        }\n        compCount++;\n    }\n}\n\n// Tarjan bridges on complement graph for a day (edges with assign != day)\nvoid compute_bridges_for_day(int day, const vector<int>& assign, vector<char>& isBridge) {\n    isBridge.assign(M, false);\n    vector<int> tin(N, -1), low(N, -1);\n    int timer = 0;\n    function<void(int,int)> dfs = [&](int u, int peid) {\n        tin[u] = low[u] = timer++;\n        for (const auto& ae : adj[u]) {\n            int id = ae.id;\n            if (assign[id] == day) continue; // absent that day\n            if (id == peid) continue;\n            int v = ae.to;\n            if (tin[v] == -1) {\n                dfs(v, id);\n                low[u] = min(low[u], low[v]);\n                if (low[v] > tin[u]) isBridge[id] = true;\n            } else {\n                low[u] = min(low[u], tin[v]);\n            }\n        }\n    };\n    for (int i = 0; i < N; i++) if (tin[i] == -1) dfs(i, -1);\n}\nvoid precompute_bridges_all_days(const vector<int>& assign, vector<vector<char>>& isBridgeDays) {\n    isBridgeDays.assign(D, vector<char>(M, false));\n    for (int d = 0; d < D; d++) compute_bridges_for_day(d, assign, isBridgeDays[d]);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> D >> K;\n    edges.resize(M);\n    for (int i = 0; i < M; i++) {\n        int u, v; ll w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[i] = {u, v, w};\n    }\n    Xcoord.resize(N);\n    Ycoord.resize(N);\n    for (int i = 0; i < N; i++) cin >> Xcoord[i] >> Ycoord[i];\n\n    adj.assign(N, {});\n    for (int i = 0; i < M; i++) {\n        auto &e = edges[i];\n        adj[e.u].push_back({e.v, i, e.w});\n        adj[e.v].push_back({e.u, i, e.w});\n    }\n\n    auto time_start = chrono::steady_clock::now();\n    const double T_budget = 5.80;\n\n    // 1) Per-edge importance and bypass paths (bitsets)\n    int Wbits = (M + 63) >> 6;\n    vector<vector<uint64_t>> backupBits(M, vector<uint64_t>(Wbits, 0ULL));\n    vector<ll> importance(M, 0);\n    vector<ll> distTmp;\n    vector<int> parentEdge;\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        ll alt = dijkstra_exclude_with_parent(u, v, i, distTmp, parentEdge);\n        if (alt >= INFLL/2) {\n            importance[i] = (ll)1e9;\n        } else {\n            ll imp = alt - edges[i].w;\n            if (imp < 0) imp = 0;\n            importance[i] = imp;\n            // reconstruct path from v to u via parentEdge\n            int cur = v;\n            while (cur != u) {\n                int pe = parentEdge[cur];\n                if (pe < 0) break; // safety\n                int a = edges[pe].u, b = edges[pe].v;\n                int prev = (a == cur ? b : a);\n                // set bit pe\n                backupBits[i][pe >> 6] |= (1ULL << (pe & 63));\n                cur = prev;\n            }\n        }\n    }\n\n    // 2) Edge usage via S shortest path trees with subtree sizes\n    vector<int> usage(M, 0);\n    vector<int> deg(N);\n    for (int u = 0; u < N; u++) deg[u] = (int)adj[u].size();\n    vector<int> vid(N);\n    iota(vid.begin(), vid.end(), 0);\n    sort(vid.begin(), vid.end(), [&](int a, int b){\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        return a < b;\n    });\n    int SCount = min(48, max(24, N / 20));\n    vector<int> sources;\n    int n1 = min((int)vid.size(), SCount / 2);\n    for (int i = 0; i < n1; i++) sources.push_back(vid[i]);\n    for (int i = 0; (int)sources.size() < SCount && i < SCount * 3; i++) {\n        int id = (int)((1LL * i * N) / SCount);\n        if (id >= N) id = N - 1;\n        sources.push_back(id);\n        sort(sources.begin(), sources.end());\n        sources.erase(unique(sources.begin(), sources.end()), sources.end());\n    }\n    for (int i = 0; (int)sources.size() < SCount && i < N; i++) {\n        sources.push_back(i);\n        sort(sources.begin(), sources.end());\n        sources.erase(unique(sources.begin(), sources.end()), sources.end());\n    }\n    if ((int)sources.size() > SCount) sources.resize(SCount);\n\n    vector<ll> distFull;\n    vector<int> parentEdgeFull;\n    vector<int> orderNodes(N), parentVertex(N), subtree(N);\n    for (int s : sources) {\n        dijkstra_tree(s, distFull, parentEdgeFull);\n        for (int v = 0; v < N; v++) {\n            int pe = parentEdgeFull[v];\n            if (pe < 0) parentVertex[v] = -1;\n            else {\n                int a = edges[pe].u, b = edges[pe].v;\n                parentVertex[v] = (a == v ? b : a);\n            }\n        }\n        iota(orderNodes.begin(), orderNodes.end(), 0);\n        sort(orderNodes.begin(), orderNodes.end(), [&](int a, int b){\n            return distFull[a] > distFull[b];\n        });\n        for (int v = 0; v < N; v++) subtree[v] = 1;\n        for (int v : orderNodes) {\n            int p = parentVertex[v];\n            if (p >= 0) {\n                int pe = parentEdgeFull[v];\n                usage[pe] += subtree[v];\n                subtree[p] += subtree[v];\n            }\n        }\n    }\n    int maxUsage = 0;\n    for (int i = 0; i < M; i++) maxUsage = max(maxUsage, usage[i]);\n\n    // 3) Heavy metric\n    const double alphaUsage = 2.0;\n    vector<double> heavy(M, 0.0);\n    for (int i = 0; i < M; i++) {\n        double uNorm = (maxUsage > 0 ? (double)usage[i] / (double)maxUsage : 0.0);\n        heavy[i] = (double)importance[i] * (1.0 + alphaUsage * uNorm);\n    }\n\n    // Spatial key\n    vector<uint64_t> zkey(M);\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        int mx = (Xcoord[u] + Xcoord[v]) >> 1;\n        int my = (Ycoord[u] + Ycoord[v]) >> 1;\n        zkey[i] = morton2D_32((uint32_t)mx, (uint32_t)my);\n    }\n\n    // Grid partition\n    const int GW = 20, GH = 20;\n    const int strideX = (1001 + GW - 1) / GW;\n    const int strideY = (1001 + GH - 1) / GH;\n    auto cell_of_point = [&](int x, int y) -> int {\n        int cx = x / strideX; if (cx >= GW) cx = GW - 1;\n        int cy = y / strideY; if (cy >= GH) cy = GH - 1;\n        return cy * GW + cx;\n    };\n    vector<int> edgeCell(M);\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        int mx = (Xcoord[u] + Xcoord[v]) >> 1;\n        int my = (Ycoord[u] + Ycoord[v]) >> 1;\n        edgeCell[i] = cell_of_point(mx, my);\n    }\n    const int nCells = GW * GH;\n\n    // Edge order: heavy desc then spatial key asc\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    stable_sort(order.begin(), order.end(), [&](int a, int b){\n        if (heavy[a] != heavy[b]) return heavy[a] > heavy[b];\n        if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n        return a < b;\n    });\n\n    // Assignment state\n    vector<int> assign(M, -1);\n    vector<vector<int>> dayEdges(D);\n    vector<int> daySize(D, 0);\n\n    vector<vector<double>> PV(N, vector<double>(D, 0.0));    // per-vertex/day\n    vector<vector<double>> PC(nCells, vector<double>(D, 0.0)); // per-cell/day\n    vector<double> daySum(D, 0.0);                           // per-day sum\n    vector<vector<int>> cnt(N, vector<int>(D, 0));           // incident edges count per vertex/day\n\n    // Bypass interaction penalty state\n    vector<vector<uint64_t>> Rbits(D, vector<uint64_t>(Wbits, 0ULL)); // set of edges scheduled on day d\n    vector<vector<double>> sumHeavyBack(D, vector<double>(M, 0.0));   // sum heavy[g] for g in day d s.t. e in backup[g]\n\n    // Objective weights\n    const long double lamV = 1.0L;\n    const long double lamC = 0.30L;\n    const long double lamD = 0.02L;\n    const long double lamB = 1.0L; // bypass interaction: set to ~1 to influence tie-breaks but not overpower squares\n\n    auto sqDelta = [&](double s, double dw) -> long double {\n        long double ss = (long double)s;\n        long double ddw = (long double)dw;\n        return (ss + ddw) * (ss + ddw) - ss * ss;\n    };\n    auto overlapCount = [&](int e, int d) -> int {\n        int c = 0;\n        const auto &be = backupBits[e];\n        const auto &Rd = Rbits[d];\n        for (int w = 0; w < Wbits; w++) {\n            uint64_t x = be[w] & Rd[w];\n            c += __builtin_popcountll(x);\n        }\n        return c;\n    };\n    auto add_delta = [&](int e, int d) -> long double {\n        int u = edges[e].u, v = edges[e].v;\n        int c = edgeCell[e];\n        double w = heavy[e];\n        long double delta = 0.0L;\n        // quadratic parts\n        delta += lamV * ( sqDelta(PV[u][d], w) + sqDelta(PV[v][d], w) );\n        delta += lamC * ( sqDelta(PC[c][d], w) );\n        delta += lamD * ( sqDelta(daySum[d], w) );\n        // bypass penalty\n        int ov = overlapCount(e, d);\n        delta += lamB * ( (long double)w * (long double)ov + (long double)sumHeavyBack[d][e] );\n        return delta;\n    };\n    auto remove_delta = [&](int e, int d) -> long double {\n        int u = edges[e].u, v = edges[e].v;\n        int c = edgeCell[e];\n        double w = heavy[e];\n        long double delta = 0.0L;\n        // quadratic parts\n        delta += lamV * ( sqDelta(PV[u][d], -w) + sqDelta(PV[v][d], -w) );\n        delta += lamC * ( sqDelta(PC[c][d], -w) );\n        delta += lamD * ( sqDelta(daySum[d], -w) );\n        // bypass penalty\n        int ov = overlapCount(e, d);\n        delta += lamB * ( -(long double)w * (long double)ov - (long double)sumHeavyBack[d][e] );\n        return delta;\n    };\n\n    // Greedy assignment (respect K)\n    for (int idx = 0; idx < M; idx++) {\n        int e = order[idx];\n        int u = edges[e].u, v = edges[e].v;\n\n        int best_d = -1;\n        int best_conf = INT_MAX;\n        long double best_incr = 1e300L;\n        int best_size = INT_MAX;\n\n        for (int d = 0; d < D; d++) {\n            if (daySize[d] >= K) continue;\n            int conf = cnt[u][d] + cnt[v][d];\n            long double incr = add_delta(e, d);\n            if (conf < best_conf ||\n                (conf == best_conf && (incr < best_incr - 1e-12L ||\n                                       (fabsl(incr - best_incr) <= 1e-12L && daySize[d] < best_size)))) {\n                best_conf = conf;\n                best_incr = incr;\n                best_size = daySize[d];\n                best_d = d;\n            }\n        }\n        if (best_d == -1) best_d = 0;\n\n        // apply\n        assign[e] = best_d;\n        dayEdges[best_d].push_back(e);\n        daySize[best_d]++;\n        cnt[u][best_d]++; cnt[v][best_d]++;\n        int c = edgeCell[e];\n        double w = heavy[e];\n        PV[u][best_d] += w; PV[v][best_d] += w;\n        PC[c][best_d] += w;\n        daySum[best_d] += w;\n        // update bypass state\n        Rbits[best_d][e >> 6] |= (1ULL << (e & 63));\n        // sumHeavyBack[d][j] += w for j in backup[e]\n        for (int widx = 0; widx < Wbits; widx++) {\n            uint64_t bits = backupBits[e][widx];\n            while (bits) {\n                uint64_t b = bits & -bits;\n                int j = (widx << 6) + __builtin_ctzll(bits);\n                if (j < M) sumHeavyBack[best_d][j] += w;\n                bits ^= b;\n            }\n        }\n    }\n\n    // posInDay\n    vector<int> posInDay(M, -1);\n    for (int d = 0; d < D; d++) for (int i = 0; i < (int)dayEdges[d].size(); i++) posInDay[dayEdges[d][i]] = i;\n\n    // Connectivity enforcement helpers\n    vector<vector<char>> isBridgeDays;\n    precompute_bridges_all_days(assign, isBridgeDays);\n\n    auto applyMove = [&](int e, int dFrom, int dTo) {\n        if (dFrom == dTo) return;\n        int u = edges[e].u, v = edges[e].v;\n        int c = edgeCell[e];\n        double w = heavy[e];\n\n        // remove from dFrom structures\n        {\n            int p = posInDay[e];\n            int last = dayEdges[dFrom].back();\n            dayEdges[dFrom][p] = last;\n            posInDay[last] = p;\n            dayEdges[dFrom].pop_back();\n            daySize[dFrom]--;\n        }\n        // update stats for removal\n        cnt[u][dFrom]--; cnt[v][dFrom]--;\n        PV[u][dFrom] -= w; PV[v][dFrom] -= w;\n        PC[c][dFrom] -= w;\n        daySum[dFrom] -= w;\n        // Rbits clear\n        Rbits[dFrom][e >> 6] &= ~(1ULL << (e & 63));\n        // sumHeavyBack subtract for backup[e]\n        for (int widx = 0; widx < Wbits; widx++) {\n            uint64_t bits = backupBits[e][widx];\n            while (bits) {\n                uint64_t b = bits & -bits;\n                int j = (widx << 6) + __builtin_ctzll(bits);\n                if (j < M) sumHeavyBack[dFrom][j] -= w;\n                bits ^= b;\n            }\n        }\n\n        // add to dTo\n        posInDay[e] = (int)dayEdges[dTo].size();\n        dayEdges[dTo].push_back(e);\n        daySize[dTo]++;\n\n        cnt[u][dTo]++; cnt[v][dTo]++;\n        PV[u][dTo] += w; PV[v][dTo] += w;\n        PC[c][dTo] += w;\n        daySum[dTo] += w;\n        Rbits[dTo][e >> 6] |= (1ULL << (e & 63));\n        for (int widx = 0; widx < Wbits; widx++) {\n            uint64_t bits = backupBits[e][widx];\n            while (bits) {\n                uint64_t b = bits & -bits;\n                int j = (widx << 6) + __builtin_ctzll(bits);\n                if (j < M) sumHeavyBack[dTo][j] += w;\n                bits ^= b;\n            }\n        }\n        assign[e] = dTo;\n\n        // Update bridges for the two days\n        compute_bridges_for_day(dFrom, assign, isBridgeDays[dFrom]);\n        compute_bridges_for_day(dTo, assign, isBridgeDays[dTo]);\n    };\n\n    // Connectivity enforcement: fix disconnected days\n    int maxPass = 4;\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool changedAny = false;\n        for (int d = 0; d < D; d++) {\n            vector<int> compId;\n            int compCount = 0;\n            compute_components_for_day(d, assign, compId, compCount);\n            if (compCount <= 1) continue;\n\n            vector<int> crossEdges;\n            for (int e : dayEdges[d]) {\n                int u = edges[e].u, v = edges[e].v;\n                if (compId[u] != compId[v]) crossEdges.push_back(e);\n            }\n            if (crossEdges.empty()) continue;\n\n            sort(crossEdges.begin(), crossEdges.end(), [&](int a, int b){\n                if (heavy[a] != heavy[b]) return heavy[a] > heavy[b];\n                return a < b;\n            });\n\n            struct DSU { vector<int> p, r; int comps;\n                DSU(int n=0){ if(n) init(n); }\n                void init(int n){ p.resize(n); r.assign(n,0); iota(p.begin(),p.end(),0); comps=n; }\n                int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n                bool unite(int a,int b){ a=find(a); b=find(b); if(a==b) return false;\n                    if(r[a]<r[b]) swap(a,b); p[b]=a; if(r[a]==r[b]) r[a]++; comps--; return true; }\n            } dsu(compCount);\n\n            for (int e : crossEdges) {\n                int cu = dsu.find(compId[edges[e].u]);\n                int cv = dsu.find(compId[edges[e].v]);\n                if (cu == cv) continue;\n\n                int bestSafe = -1, bestAny = -1;\n                long double bestSafeDelta = 1e300L, bestAnyDelta = 1e300L;\n                for (int tday = 0; tday < D; tday++) {\n                    if (tday == d) continue;\n                    if (daySize[tday] >= K) continue;\n                    bool safe = !isBridgeDays[tday][e];\n                    long double delta = add_delta(e, tday); // removal from d is beneficial, ignore here\n                    if (safe) {\n                        if (delta < bestSafeDelta) { bestSafeDelta = delta; bestSafe = tday; }\n                    } else {\n                        if (delta < bestAnyDelta) { bestAnyDelta = delta; bestAny = tday; }\n                    }\n                }\n                int tday = (bestSafe != -1 ? bestSafe : bestAny);\n                if (tday == -1) continue;\n                applyMove(e, d, tday);\n                dsu.unite(cu, cv);\n                changedAny = true;\n                if (dsu.comps == 1) break;\n            }\n        }\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - time_start).count();\n        if (elapsed > T_budget) break;\n        if (!changedAny) break;\n    }\n\n    // Local search\n    auto computeObj = [&]() -> long double {\n        long double obj = 0;\n        for (int v = 0; v < N; v++) for (int d = 0; d < D; d++) {\n            long double s = (long double)PV[v][d];\n            obj += lamV * s * s;\n        }\n        for (int c = 0; c < nCells; c++) for (int d = 0; d < D; d++) {\n            long double s = (long double)PC[c][d];\n            obj += lamC * s * s;\n        }\n        for (int d = 0; d < D; d++) {\n            long double s = (long double)daySum[d];\n            obj += lamD * s * s;\n        }\n        // bypass penalty\n        for (int d = 0; d < D; d++) {\n            for (int e : dayEdges[d]) {\n                int ov = overlapCount(e, d);\n                obj += lamB * (long double)heavy[e] * (long double)ov;\n            }\n        }\n        return obj;\n    };\n    long double obj = computeObj();\n\n    auto now = chrono::steady_clock::now();\n    double elapsed = chrono::duration<double>(now - time_start).count();\n    double time_left = T_budget - elapsed;\n    if (time_left > 0.10) {\n        mt19937 rng(1234567);\n        uniform_int_distribution<int> dayDist(0, D-1);\n        uniform_int_distribution<int> edgeDist(0, M-1);\n\n        int attemptsMove = 70000;\n        int attemptsSwap = 60000;\n\n        // 1-move attempts\n        for (int it = 0; it < attemptsMove; it++) {\n            if ((it & 1023) == 0) {\n                now = chrono::steady_clock::now();\n                elapsed = chrono::duration<double>(now - time_start).count();\n                if (elapsed > T_budget) break;\n            }\n            int e = edgeDist(rng);\n            int dFrom = assign[e];\n            if (dFrom < 0) continue;\n            int bestTo = -1;\n            long double bestDelta = -1e-12L;\n            const int trials = min(D, 6);\n            for (int t = 0; t < trials; t++) {\n                int dTo = dayDist(rng);\n                if (dTo == dFrom) continue;\n                if (daySize[dTo] >= K) continue;\n                if (isBridgeDays[dTo][e]) continue; // adding e to dTo would disconnect\n                long double delta = remove_delta(e, dFrom) + add_delta(e, dTo);\n                if (delta < bestDelta) { bestDelta = delta; bestTo = dTo; }\n            }\n            if (bestTo != -1) {\n                applyMove(e, dFrom, bestTo);\n                obj += bestDelta;\n            }\n        }\n\n        // 2-swap attempts\n        for (int it = 0; it < attemptsSwap; it++) {\n            if ((it & 1023) == 0) {\n                now = chrono::steady_clock::now();\n                elapsed = chrono::duration<double>(now - time_start).count();\n                if (elapsed > T_budget) break;\n            }\n            int d1 = dayDist(rng), d2 = dayDist(rng);\n            if (d1 == d2) continue;\n            if (dayEdges[d1].empty() || dayEdges[d2].empty()) continue;\n\n            int e1 = dayEdges[d1][ (int)(rng() % dayEdges[d1].size()) ];\n            int e2 = dayEdges[d2][ (int)(rng() % dayEdges[d2].size()) ];\n            if (e1 == e2) continue;\n            if (isBridgeDays[d2][e1]) continue;\n            if (isBridgeDays[d1][e2]) continue;\n\n            long double delta = remove_delta(e1, d1) + add_delta(e1, d2)\n                              + remove_delta(e2, d2) + add_delta(e2, d1);\n            if (delta < -1e-12L) {\n                applyMove(e1, d1, d2);\n                applyMove(e2, d2, d1);\n                obj += delta;\n            }\n        }\n    }\n\n    // Output\n    for (int i = 0; i < M; i++) {\n        if (i) cout << ' ';\n        cout << (assign[i] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Hopcroft-Karp for bipartite matching (left: 0..nL-1, right: 0..nR-1)\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> adj; // adj[u] -> list of right vertices\n    vector<int> dist, matchL, matchR;\n\n    HopcroftKarp(int nL=0, int nR=0): nL(nL), nR(nR), adj(nL) {}\n\n    void init(int _nL, int _nR) {\n        nL = _nL; nR = _nR;\n        adj.assign(nL, {});\n    }\n\n    void addEdge(int u, int v) {\n        adj[u].push_back(v);\n    }\n\n    bool bfs() {\n        dist.assign(nL, -1);\n        queue<int> q;\n        for (int u = 0; u < nL; ++u) {\n            if (matchL[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        bool found = false;\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : adj[u]) {\n                int w = matchR[v];\n                if (w >= 0) {\n                    if (dist[w] < 0) {\n                        dist[w] = dist[u] + 1;\n                        q.push(w);\n                    }\n                } else {\n                    found = true;\n                }\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for (int v : adj[u]) {\n            int w = matchR[v];\n            if (w < 0 || (dist[w] == dist[u] + 1 && dfs(w))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int maxMatching(vector<int>* outMatchL = nullptr, vector<int>* outMatchR = nullptr) {\n        matchL.assign(nL, -1);\n        matchR.assign(nR, -1);\n        int matching = 0;\n        while (bfs()) {\n            for (int u = 0; u < nL; ++u) {\n                if (matchL[u] == -1) {\n                    if (dfs(u)) matching++;\n                }\n            }\n        }\n        if (outMatchL) *outMatchL = matchL;\n        if (outMatchR) *outMatchR = matchR;\n        return matching;\n    }\n};\n\nstatic inline int idx3(int D, int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\nstruct Arrangement {\n    int D;\n    vector<char> present; // size D^3\n    long long volume = 0;\n};\n\nstruct Run {\n    int x, y, z0, len;\n    int off; // how many voxels consumed from the start\n};\n\n// Build arrangement with vertical preservation using matching,\n// minimal per-layer occupancy and some randomness to diversify.\nArrangement build_arrangement(const vector<string>& fz, const vector<string>& rz, int D, uint32_t seed) {\n    Arrangement arr;\n    arr.D = D;\n    int N = D * D * D;\n    arr.present.assign(N, 0);\n\n    // Precompute per-layer A (xs) and B (ys)\n    vector<vector<int>> Ax(D), By(D);\n    for (int z = 0; z < D; ++z) {\n        for (int x = 0; x < D; ++x) if (fz[z][x] == '1') Ax[z].push_back(x);\n        for (int y = 0; y < D; ++y) if (rz[z][y] == '1') By[z].push_back(y);\n    }\n\n    // RNG\n    uint32_t rng_state = seed ? seed : 123456789u;\n    auto rng = [&]() -> uint32_t {\n        rng_state ^= rng_state << 13;\n        rng_state ^= rng_state >> 17;\n        rng_state ^= rng_state << 5;\n        return rng_state;\n    };\n\n    vector<vector<char>> prevOcc(D, vector<char>(D, 0));\n    for (int z = 0; z < D; ++z) {\n        auto& A = Ax[z];\n        auto& B = By[z];\n        int Nx = (int)A.size();\n        int Ny = (int)B.size();\n        // xId/yId if needed\n        if (Nx >= Ny) {\n            // x-dominant: assign y to each x, cover all y\n            // Stage 1: preserve prev columns using matching y->x\n            HopcroftKarp hk(Ny, Nx);\n            for (int j = 0; j < Ny; ++j) {\n                int y = B[j];\n                for (int i = 0; i < Nx; ++i) {\n                    int x = A[i];\n                    if (prevOcc[x][y]) hk.addEdge(j, i);\n                }\n            }\n            vector<int> matchY, matchX;\n            hk.maxMatching(&matchY, &matchX);\n\n            vector<int> xToY(Nx, -1);\n            vector<int> loadY(Ny, 0);\n            vector<char> usedX(Nx, 0), yCovered(Ny, 0);\n            for (int j = 0; j < Ny; ++j) if (matchY[j] != -1) {\n                xToY[matchY[j]] = j;\n                usedX[matchY[j]] = 1;\n                yCovered[j] = 1;\n                loadY[j]++;\n            }\n            // Pref counts for x\n            vector<int> prefCountX(Nx, 0);\n            for (int i = 0; i < Nx; ++i) {\n                int x = A[i];\n                int cnt = 0;\n                for (int j = 0; j < Ny; ++j) if (prevOcc[x][B[j]]) cnt++;\n                prefCountX[i] = cnt;\n            }\n            // Cover remaining y\n            for (int j = 0; j < Ny; ++j) if (!yCovered[j]) {\n                int pick_i = -1;\n                int bestScore = INT_MAX;\n                for (int i = 0; i < Nx; ++i) if (!usedX[i]) {\n                    int score = prefCountX[i] * 10 + (int)(rng() & 7u);\n                    if (score < bestScore) { bestScore = score; pick_i = i; }\n                }\n                if (pick_i == -1) {\n                    for (int i = 0; i < Nx; ++i) if (xToY[i] != -1) { pick_i = i; break; }\n                }\n                if (pick_i == -1) pick_i = 0;\n                xToY[pick_i] = j;\n                usedX[pick_i] = 1;\n                yCovered[j] = 1;\n                loadY[j]++;\n            }\n            // Stage 2: assign remaining x\n            vector<vector<int>> xsPerY(Ny);\n            for (int i = 0; i < Nx; ++i) if (xToY[i] != -1) xsPerY[xToY[i]].push_back(i);\n            for (int i = 0; i < Nx; ++i) if (!usedX[i]) {\n                int x = A[i];\n                int bestY = 0;\n                int bestScore = -1e9;\n                for (int j = 0; j < Ny; ++j) {\n                    int y = B[j];\n                    int sc = 0;\n                    if (prevOcc[x][y]) sc += 100;\n                    for (int xi : xsPerY[j]) {\n                        if (abs(A[xi] - x) == 1) { sc += 10; break; }\n                    }\n                    sc -= loadY[j];\n                    sc += (int)(rng() & 3u);\n                    if (sc > bestScore) { bestScore = sc; bestY = j; }\n                }\n                xToY[i] = bestY;\n                loadY[bestY]++;\n                xsPerY[bestY].push_back(i);\n            }\n            // Emit cells\n            for (int i = 0; i < Nx; ++i) {\n                int x = A[i];\n                int y = B[xToY[i]];\n                arr.present[idx3(D, x, y, z)] = 1;\n                arr.volume++;\n            }\n        } else {\n            // y-dominant: assign x to each y, cover all x\n            HopcroftKarp hk(Nx, Ny); // left X, right Y\n            for (int i = 0; i < Nx; ++i) {\n                int x = A[i];\n                for (int j = 0; j < Ny; ++j) {\n                    int y = B[j];\n                    if (prevOcc[x][y]) hk.addEdge(i, j);\n                }\n            }\n            vector<int> matchX, matchY;\n            hk.maxMatching(&matchX, &matchY);\n\n            vector<int> yToX(Ny, -1);\n            vector<char> usedY(Ny, 0);\n            vector<int> loadX(Nx, 0);\n            vector<vector<int>> ysPerX(Nx);\n\n            for (int i = 0; i < Nx; ++i) if (matchX[i] != -1) {\n                int j = matchX[i];\n                yToX[j] = i;\n                usedY[j] = 1;\n                loadX[i]++;\n                ysPerX[i].push_back(j);\n            }\n            vector<int> prefCountY(Ny, 0);\n            for (int j = 0; j < Ny; ++j) {\n                int y = B[j];\n                int cnt = 0;\n                for (int i = 0; i < Nx; ++i) if (prevOcc[A[i]][y]) cnt++;\n                prefCountY[j] = cnt;\n            }\n            // Cover unmatched x\n            for (int i = 0; i < Nx; ++i) if (matchX[i] == -1) {\n                int pick_j = -1;\n                int bestScore = INT_MAX;\n                for (int j = 0; j < Ny; ++j) if (!usedY[j]) {\n                    int score = prefCountY[j] * 10 + (int)(rng() & 7u);\n                    if (score < bestScore) { bestScore = score; pick_j = j; }\n                }\n                if (pick_j == -1) {\n                    for (int j = 0; j < Ny; ++j) if (!usedY[j]) { pick_j = j; break; }\n                    if (pick_j == -1) pick_j = 0;\n                }\n                yToX[pick_j] = i;\n                usedY[pick_j] = 1;\n                loadX[i]++;\n                ysPerX[i].push_back(pick_j);\n            }\n            // Assign remaining y\n            for (int j = 0; j < Ny; ++j) if (!usedY[j]) {\n                int y = B[j];\n                int bestX = 0;\n                int bestScore = -1e9;\n                for (int i = 0; i < Nx; ++i) {\n                    int x = A[i];\n                    int sc = 0;\n                    if (prevOcc[x][y]) sc += 100;\n                    for (int yj : ysPerX[i]) {\n                        if (abs(B[yj] - y) == 1) { sc += 10; break; }\n                    }\n                    sc -= loadX[i];\n                    sc += (int)(rng() & 3u);\n                    if (sc > bestScore) { bestScore = sc; bestX = i; }\n                }\n                yToX[j] = bestX;\n                usedY[j] = 1;\n                loadX[bestX]++;\n                ysPerX[bestX].push_back(j);\n            }\n            // Emit cells\n            for (int j = 0; j < Ny; ++j) {\n                int i = yToX[j];\n                int x = A[i], y = B[j];\n                arr.present[idx3(D, x, y, z)] = 1;\n                arr.volume++;\n            }\n        }\n\n        // Update prevOcc for next layer\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) prevOcc[x][y] = 0;\n        for (int x = 0; x < D; ++x) {\n            for (int y = 0; y < D; ++y) {\n                int p = idx3(D, x, y, z);\n                if (arr.present[p]) prevOcc[x][y] = 1;\n            }\n        }\n    }\n    return arr;\n}\n\nstatic vector<Run> extract_runs(const Arrangement& arr) {\n    int D = arr.D;\n    vector<Run> runs;\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            int z = 0;\n            while (z < D) {\n                while (z < D) {\n                    int p = idx3(D, x, y, z);\n                    if (arr.present[p]) break;\n                    ++z;\n                }\n                if (z >= D) break;\n                int z0 = z;\n                while (z < D) {\n                    int p = idx3(D, x, y, z);\n                    if (!arr.present[p]) break;\n                    ++z;\n                }\n                int len = z - z0;\n                if (len > 0) runs.push_back({x, y, z0, len, 0});\n            }\n        }\n    }\n    return runs;\n}\n\nstruct PairingScore {\n    double penalty;\n    long long sharedVolume;\n};\n\n// Compute greedy pairing score only (no assignment), pairing longest runs first\nstatic PairingScore evaluate_pairing(const vector<Run>& r1, const vector<Run>& r2) {\n    struct Node { int len; int id; };\n    struct Cmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.len != b.len) return a.len < b.len; // max-heap\n            return a.id > b.id;\n        }\n    };\n    priority_queue<Node, vector<Node>, Cmp> pq1, pq2;\n    int n1 = (int)r1.size(), n2 = (int)r2.size();\n    vector<int> rem1(n1), rem2(n2);\n    long long V1 = 0, V2 = 0;\n    for (int i = 0; i < n1; ++i) { rem1[i] = r1[i].len; V1 += r1[i].len; if (rem1[i] > 0) pq1.push({rem1[i], i}); }\n    for (int i = 0; i < n2; ++i) { rem2[i] = r2[i].len; V2 += r2[i].len; if (rem2[i] > 0) pq2.push({rem2[i], i}); }\n    double penalty = 0;\n    long long shared = 0;\n    while (!pq1.empty() && !pq2.empty()) {\n        auto a = pq1.top(); pq1.pop();\n        auto b = pq2.top(); pq2.pop();\n        int L = min(a.len, b.len);\n        penalty += 1.0 / (double)L;\n        shared += L;\n        a.len -= L;\n        b.len -= L;\n        if (a.len > 0) pq1.push(a);\n        if (b.len > 0) pq2.push(b);\n    }\n    // In principle, shared should equal min(V1, V2)\n    return {penalty, shared};\n}\n\n// Assign shared and arrangement-only sticks using the same greedy pairing\nstatic void assign_blocks_from_runs(\n    const vector<Run>& r1, const vector<Run>& r2,\n    int D, vector<int>& b1, vector<int>& b2, int& nblocks\n) {\n    struct Node { int len; int id; };\n    struct Cmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.len != b.len) return a.len < b.len; // max-heap\n            return a.id > b.id;\n        }\n    };\n    priority_queue<Node, vector<Node>, Cmp> pq1, pq2;\n    int n1 = (int)r1.size(), n2 = (int)r2.size();\n    vector<int> rem1(n1), rem2(n2);\n    vector<int> off1(n1), off2(n2);\n    for (int i = 0; i < n1; ++i) { rem1[i] = r1[i].len; off1[i] = 0; if (rem1[i] > 0) pq1.push({rem1[i], i}); }\n    for (int i = 0; i < n2; ++i) { rem2[i] = r2[i].len; off2[i] = 0; if (rem2[i] > 0) pq2.push({rem2[i], i}); }\n\n    // Shared sticks first\n    while (!pq1.empty() && !pq2.empty()) {\n        auto a = pq1.top(); pq1.pop();\n        auto b = pq2.top(); pq2.pop();\n        int i = a.id, j = b.id;\n        int L = min(rem1[i], rem2[j]);\n        int id = ++nblocks;\n        // assign in b1\n        for (int t = 0; t < L; ++t) {\n            int z = r1[i].z0 + off1[i] + t;\n            int p = idx3(D, r1[i].x, r1[i].y, z);\n            b1[p] = id;\n        }\n        // assign in b2\n        for (int t = 0; t < L; ++t) {\n            int z = r2[j].z0 + off2[j] + t;\n            int p = idx3(D, r2[j].x, r2[j].y, z);\n            b2[p] = id;\n        }\n        rem1[i] -= L; off1[i] += L;\n        rem2[j] -= L; off2[j] += L;\n        if (rem1[i] > 0) pq1.push({rem1[i], i});\n        if (rem2[j] > 0) pq2.push({rem2[j], j});\n    }\n\n    // Remaining arrangement-only sticks in A1\n    for (int i = 0; i < n1; ++i) if (rem1[i] > 0) {\n        int id = ++nblocks;\n        for (int t = 0; t < rem1[i]; ++t) {\n            int z = r1[i].z0 + off1[i] + t;\n            int p = idx3(D, r1[i].x, r1[i].y, z);\n            b1[p] = id;\n        }\n    }\n    // Remaining arrangement-only sticks in A2\n    for (int j = 0; j < n2; ++j) if (rem2[j] > 0) {\n        int id = ++nblocks;\n        for (int t = 0; t < rem2[j]; ++t) {\n            int z = r2[j].z0 + off2[j] + t;\n            int p = idx3(D, r2[j].x, r2[j].y, z);\n            b2[p] = id;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    if (!(cin >> D)) return 0;\n    vector<string> f[2], r[2];\n    for (int t = 0; t < 2; ++t) {\n        f[t].resize(D);\n        for (int i = 0; i < D; ++i) cin >> f[t][i];\n        r[t].resize(D);\n        for (int i = 0; i < D; ++i) cin >> r[t][i];\n    }\n\n    // Iterative improvement with small time budget\n    auto start = chrono::steady_clock::now();\n    const double timeLimit = 1.6; // seconds, keep margin\n    double elapsed = 0.0;\n\n    Arrangement bestA1, bestA2;\n    vector<Run> bestRuns1, bestRuns2;\n    double bestScore = 1e100;\n\n    uint32_t baseSeed = 146527u;\n\n    int iter = 0;\n    while (true) {\n        uint32_t seed1 = baseSeed + 10007u * (iter + 1);\n        uint32_t seed2 = baseSeed ^ (0x9E3779B9u * (iter + 137));\n        Arrangement A1 = build_arrangement(f[0], r[0], D, seed1);\n        Arrangement A2 = build_arrangement(f[1], r[1], D, seed2);\n        auto runs1 = extract_runs(A1);\n        auto runs2 = extract_runs(A2);\n        auto ps = evaluate_pairing(runs1, runs2);\n        // Total absolute-ish score proxy: |V1 - V2| + penalty\n        double score = (double)llabs(A1.volume - A2.volume) + ps.penalty;\n\n        if (score < bestScore) {\n            bestScore = score;\n            bestA1 = move(A1);\n            bestA2 = move(A2);\n            bestRuns1 = move(runs1);\n            bestRuns2 = move(runs2);\n        }\n\n        ++iter;\n        if ((iter & 7) == 0) {\n            auto now = chrono::steady_clock::now();\n            elapsed = chrono::duration<double>(now - start).count();\n            if (elapsed > timeLimit) break;\n        }\n        // Limit iterations to avoid too many on small inputs\n        if (iter > 4000) break;\n    }\n\n    // Final assignment\n    int N = D * D * D;\n    vector<int> b1(N, 0), b2(N, 0);\n    int nblocks = 0;\n    assign_blocks_from_runs(bestRuns1, bestRuns2, D, b1, b2, nblocks);\n\n    // Safety: ensure every occupied cell is assigned\n    // (not strictly necessary, but good to be safe)\n    // If any present cell remains zero, assign as unit block.\n    for (int p = 0; p < N; ++p) {\n        if (bestA1.present[p] && b1[p] == 0) {\n            int id = ++nblocks;\n            b1[p] = id;\n        }\n    }\n    for (int p = 0; p < N; ++p) {\n        if (bestA2.present[p] && b2[p] == 0) {\n            int id = ++nblocks;\n            b2[p] = id;\n        }\n    }\n\n    cout << nblocks << \"\\n\";\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            for (int z = 0; z < D; ++z) {\n                int p = idx3(D, x, y, z);\n                cout << b1[p] << ( (x==D-1 && y==D-1 && z==D-1) ? '\\n' : ' ' );\n            }\n        }\n    }\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            for (int z = 0; z < D; ++z) {\n                int p = idx3(D, x, y, z);\n                cout << b2[p] << ( (x==D-1 && y==D-1 && z==D-1) ? '\\n' : ' ' );\n            }\n        }\n    }\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge { int u, v; long long w; };\n\nstruct Solution {\n    vector<int> P;           // size N\n    vector<char> edgeOn;     // size M\n    long long edgeSum = 0;\n    long long pSum = 0;\n    long long S = (1LL<<62);\n};\n\nstatic inline int sqrt_ceil_ll(long long x) {\n    if (x <= 0) return 0;\n    long double dx = (long double)x;\n    long long r = (long long)floor(sqrt(dx) + 1e-12L);\n    while ((r+1) * (r+1) <= x) ++r;\n    while (r * r > x) --r;\n    if (r * r == x) return (int)r;\n    return (int)(r + 1);\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, r;\n    DSU(int n=0):n(n),p(n),r(n,0){ iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n    bool unite(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, M, K;\n    if(!(cin>>N>>M>>K)) return 0;\n    vector<long long> xs(N), ys(N);\n    for(int i=0;i<N;i++){ cin>>xs[i]>>ys[i]; }\n    vector<Edge> edges(M);\n    for(int j=0;j<M;j++){\n        int u,v; long long w;\n        cin>>u>>v>>w; --u; --v;\n        edges[j] = {u,v,w};\n    }\n    vector<long long> ax(K), ay(K);\n    for(int k=0;k<K;k++){ cin>>ax[k]>>ay[k]; }\n\n    // build adjacency\n    vector<vector<pair<int,int>>> adj(N);\n    for(int e=0;e<M;e++){\n        int u=edges[e].u, v=edges[e].v;\n        adj[u].push_back({v,e});\n        adj[v].push_back({u,e});\n    }\n\n    // Precompute squared distances station-resident and coverage sets\n    const long long R2 = 5000LL*5000LL;\n    vector<vector<int>> covList(N);\n    vector<vector<uint64_t>> covBits(N);\n    int B = (K + 63) >> 6;\n    uint64_t lastMask = (K%64 == 0) ? ~0ULL : ((1ULL << (K%64)) - 1ULL);\n    vector<vector<int>> d2sr(N, vector<int>(K, 0));\n    // reverse mapping: for each resident, list of stations within 5000\n    vector<vector<int>> nearStationsForResid(K);\n    for(int i=0;i<N;i++){\n        covBits[i].assign(B, 0ULL);\n        for(int k=0;k<K;k++){\n            long long dx = xs[i] - ax[k];\n            long long dy = ys[i] - ay[k];\n            long long d2 = dx*dx + dy*dy;\n            if (d2 > INT_MAX) d2 = INT_MAX; // clamp to int\n            d2sr[i][k] = (int)d2;\n            if(d2 <= R2){\n                covList[i].push_back(k);\n                nearStationsForResid[k].push_back(i);\n                int blk = k >> 6, off = k & 63;\n                covBits[i][blk] |= (1ULL << off);\n            }\n        }\n    }\n\n    // All-pairs shortest paths (weight) with parents to reconstruct paths\n    const long long INF = (1LL<<60);\n    vector<vector<long long>> distW(N, vector<long long>(N, INF));\n    vector<vector<int>> prevV(N, vector<int>(N, -1));\n    vector<vector<int>> prevE(N, vector<int>(N, -1));\n    auto dijkstra_from = [&](int s){\n        auto &d = distW[s];\n        auto &pv = prevV[s];\n        auto &pe = prevE[s];\n        fill(d.begin(), d.end(), INF);\n        fill(pv.begin(), pv.end(), -1);\n        fill(pe.begin(), pe.end(), -1);\n        d[s] = 0;\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        pq.push({0, s});\n        while(!pq.empty()){\n            auto [cd,u] = pq.top(); pq.pop();\n            if(cd != d[u]) continue;\n            for(auto [v,eid] : adj[u]){\n                long long nd = cd + edges[eid].w;\n                if(nd < d[v]){\n                    d[v] = nd;\n                    pv[v] = u;\n                    pe[v] = eid;\n                    pq.push({nd, v});\n                }\n            }\n        }\n    };\n    for(int i=0;i<N;i++) dijkstra_from(i);\n\n    // SPT from root 0\n    vector<int> parentSPT(N, -1);\n    vector<int> parentEdgeSPT(N, -1);\n    for(int v=0; v<N; v++){\n        parentSPT[v] = prevV[0][v];\n        parentEdgeSPT[v] = prevE[0][v];\n    }\n\n    auto build_inV = [&](const vector<char>& edgeOn)->vector<char>{\n        vector<char> inV(N, 0);\n        queue<int> q;\n        inV[0] = 1; q.push(0);\n        while(!q.empty()){\n            int u=q.front(); q.pop();\n            for(auto [v,eid]: adj[u]){\n                if(edgeOn[eid] && !inV[v]){\n                    inV[v]=1; q.push(v);\n                }\n            }\n        }\n        return inV;\n    };\n\n    auto count_covered_bits = [&](const vector<char>& inV)->int{\n        vector<uint64_t> uni(B, 0ULL);\n        for(int i=0;i<N;i++){\n            if(!inV[i]) continue;\n            for(int b=0;b<B;b++) uni[b] |= covBits[i][b];\n        }\n        long long cnt = 0;\n        for(int b=0;b<B;b++){\n            uint64_t mask = (b==B-1 ? lastMask : ~0ULL);\n            cnt += __builtin_popcountll(uni[b] & mask);\n        }\n        return (int)cnt;\n    };\n\n    auto prune_unused_leaves = [&](vector<char>& edgeOn, const vector<int>& P){\n        vector<vector<int>> inc(N);\n        for(int e=0;e<M;e++){\n            if(edgeOn[e]){\n                int u=edges[e].u, v=edges[e].v;\n                inc[u].push_back(e);\n                inc[v].push_back(e);\n            }\n        }\n        vector<int> deg(N,0);\n        for(int i=0;i<N;i++){\n            for(int e: inc[i]) if(edgeOn[e]) deg[i]++;\n        }\n        deque<int> dq;\n        for(int i=0;i<N;i++){\n            if(i==0) continue;\n            if(deg[i]==1 && P[i]==0) dq.push_back(i);\n        }\n        vector<char> rm(N,0);\n        while(!dq.empty()){\n            int v = dq.front(); dq.pop_front();\n            if(rm[v]) continue;\n            if(deg[v]!=1 || P[v]!=0) continue;\n            int euniq=-1, u=-1;\n            for(int eid: inc[v]){\n                if(edgeOn[eid]){\n                    euniq=eid;\n                    u = (edges[eid].u==v? edges[eid].v : edges[eid].u);\n                    break;\n                }\n            }\n            if(euniq==-1) continue;\n            edgeOn[euniq]=0;\n            deg[v]--; deg[u]--;\n            rm[v]=1;\n            if(u!=0 && deg[u]==1 && P[u]==0) dq.push_back(u);\n        }\n    };\n\n    struct FastEval {\n        vector<char> inV;\n        vector<int> bestTo;   // size K\n        vector<int> bestD2;   // size K\n        vector<int> P;\n        long long pSum=0, edgeSum=0, S=0;\n        bool allCovered=false;\n    };\n\n    auto fast_evaluate = [&](const vector<char>& edgeOn){\n        FastEval fe;\n        fe.edgeSum = 0;\n        for(int e=0;e<M;e++) if(edgeOn[e]) fe.edgeSum += edges[e].w;\n        fe.inV = build_inV(edgeOn);\n        int covered = count_covered_bits(fe.inV);\n        fe.allCovered = (covered == K);\n        // Assign nearest reachable station\n        fe.bestTo.assign(K, -1);\n        fe.bestD2.assign(K, INT_MAX);\n        for(int k=0;k<K;k++){\n            int besti=-1, bestd2 = INT_MAX;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                int d2 = d2sr[i][k];\n                if(d2 < bestd2){\n                    bestd2 = d2; besti = i;\n                }\n            }\n            fe.bestTo[k] = besti;\n            fe.bestD2[k] = bestd2;\n        }\n        vector<long long> maxD2(N, 0);\n        for(int k=0;k<K;k++){\n            int i = fe.bestTo[k];\n            if(i<0) continue;\n            long long d2 = fe.bestD2[k];\n            if(d2 > maxD2[i]) maxD2[i] = d2;\n        }\n        fe.P.assign(N, 0);\n        fe.pSum = 0;\n        for(int i=0;i<N;i++){\n            if(!fe.inV[i]) { fe.P[i]=0; continue; }\n            int rad = sqrt_ceil_ll(maxD2[i]);\n            if(rad>5000) rad=5000; // clamp\n            fe.P[i]=rad;\n            fe.pSum += 1LL*rad*rad;\n        }\n        fe.S = fe.edgeSum + fe.pSum;\n        return fe;\n    };\n\n    struct FullEval {\n        Solution sol;\n        vector<char> inV;\n        vector<int> assignTo; // K -> i\n    };\n\n    auto optimize_assignment = [&](const vector<char>& edgeOn){\n        FullEval fe;\n        fe.inV = build_inV(edgeOn);\n        // nearest assignment\n        fe.assignTo.assign(K, -1);\n        vector<vector<int>> assigned(N);\n        vector<multiset<int>> dsets(N);\n        vector<long long> maxD2(N, 0);\n        for(int k=0;k<K;k++){\n            int besti=-1, bestd2=INT_MAX;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                int d2 = d2sr[i][k];\n                if(d2 < bestd2){ bestd2=d2; besti=i; }\n            }\n            fe.assignTo[k]=besti;\n            if(besti>=0){\n                assigned[besti].push_back(k);\n                dsets[besti].insert(bestd2);\n                if(bestd2 > maxD2[besti]) maxD2[besti] = bestd2;\n            }\n        }\n        vector<int> P(N,0);\n        vector<int> rad2(N,0);\n        for(int i=0;i<N;i++){\n            if(!fe.inV[i]) { P[i]=0; rad2[i]=0; continue; }\n            int rad = sqrt_ceil_ll(maxD2[i]);\n            if(rad>5000) rad=5000;\n            P[i]=rad;\n            rad2[i]=rad*rad;\n        }\n\n        auto recompute_max_after_removal = [&](int i, int d2val)->long long{\n            if(dsets[i].empty()) return 0;\n            auto it = dsets[i].find(d2val);\n            if(it == dsets[i].end()){\n                return (long long)(*dsets[i].rbegin());\n            }\n            dsets[i].erase(it);\n            long long res = dsets[i].empty() ? 0 : (long long)(*dsets[i].rbegin());\n            dsets[i].insert(d2val);\n            return res;\n        };\n\n        // Step A: move unique farthest to a station that already covers it\n        bool changedA = true;\n        int guardA = 0;\n        while(changedA && guardA < 2*N){\n            changedA = false; guardA++;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                if(dsets[i].empty()) continue;\n                int dmax = *prev(dsets[i].end());\n                int cntMax = (int)dsets[i].count(dmax);\n                if(cntMax != 1) continue;\n                // find a resident r having d2 == dmax\n                int r = -1;\n                for(int idx : assigned[i]){\n                    if(d2sr[i][idx] == dmax){ r = idx; break; }\n                }\n                if(r==-1) continue;\n                // find j in near stations that already covers r\n                int jbest = -1;\n                for(int j : nearStationsForResid[r]){\n                    if(!fe.inV[j] || j==i) continue;\n                    if(rad2[j] >= d2sr[j][r]){ jbest = j; break; }\n                }\n                if(jbest==-1) continue;\n                // move r i -> jbest\n                dsets[i].erase(dsets[i].find(dmax));\n                auto itv = find(assigned[i].begin(), assigned[i].end(), r);\n                if(itv != assigned[i].end()) assigned[i].erase(itv);\n                assigned[jbest].push_back(r);\n                dsets[jbest].insert(d2sr[jbest][r]);\n                fe.assignTo[r] = jbest;\n                // update i's P\n                long long newMaxI = dsets[i].empty() ? 0 : (long long)(*dsets[i].rbegin());\n                int newPi = sqrt_ceil_ll(newMaxI); if(newPi>5000) newPi=5000;\n                P[i] = newPi; rad2[i] = newPi*newPi;\n                changedA = true;\n            }\n        }\n\n        // Step B: move an outlier to reduce total pSum (within 5000 only)\n        bool improved = true;\n        int iter = 0;\n        while(improved && iter < 300){\n            improved = false; iter++;\n            long long bestDelta = 0;\n            int bi=-1, bj=-1, br=-1;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                if(dsets[i].empty()) continue;\n                int dmax = *prev(dsets[i].end());\n                // find one r with dmax\n                int r = -1;\n                for(int idx : assigned[i]){\n                    if(d2sr[i][idx] == dmax){ r = idx; break; }\n                }\n                if(r==-1) continue;\n                // compute new rad2 for i after removing r\n                long long newMaxI_d2 = recompute_max_after_removal(i, dmax);\n                int newPi = sqrt_ceil_ll(newMaxI_d2); if(newPi>5000) newPi=5000;\n                int newPi_sq = newPi*newPi;\n                int curPi_sq = rad2[i];\n                // try all j within 5000 for resident r\n                for(int j : nearStationsForResid[r]){\n                    if(!fe.inV[j] || j==i) continue;\n                    long long curMaxJ_d2 = dsets[j].empty() ? 0 : (long long)(*dsets[j].rbegin());\n                    long long newMaxJ_d2 = max(curMaxJ_d2, (long long)d2sr[j][r]);\n                    int newPj = sqrt_ceil_ll(newMaxJ_d2);\n                    if(newPj>5000) newPj=5000;\n                    int newPj_sq = newPj*newPj;\n                    long long curPj_sq = rad2[j];\n                    long long delta = (long long)newPi_sq + newPj_sq - curPi_sq - curPj_sq;\n                    if(delta < bestDelta){\n                        bestDelta = delta;\n                        bi = i; bj = j; br = r;\n                    }\n                }\n            }\n            if(bestDelta < 0 && bi>=0){\n                // apply move\n                int i = bi, j = bj, r = br;\n                int dmax = d2sr[i][r];\n                // remove from i\n                auto itf = dsets[i].find(dmax);\n                if(itf != dsets[i].end()) dsets[i].erase(itf);\n                auto itv = find(assigned[i].begin(), assigned[i].end(), r);\n                if(itv != assigned[i].end()) assigned[i].erase(itv);\n                // add to j\n                dsets[j].insert(d2sr[j][r]);\n                assigned[j].push_back(r);\n                fe.assignTo[r] = j;\n                // update rad2 both\n                long long newMaxI_d2 = dsets[i].empty() ? 0 : (long long)(*dsets[i].rbegin());\n                int newPi2 = sqrt_ceil_ll(newMaxI_d2); if(newPi2>5000) newPi2=5000;\n                P[i] = newPi2; rad2[i] = newPi2*newPi2;\n\n                long long newMaxJ_d2 = (long long)(*dsets[j].rbegin());\n                int newPj2 = sqrt_ceil_ll(newMaxJ_d2); if(newPj2>5000) newPj2=5000;\n                P[j] = newPj2; rad2[j] = newPj2*newPj2;\n\n                improved = true;\n            }\n        }\n\n        // finalize costs\n        long long pSum = 0;\n        for(int i=0;i<N;i++) pSum += 1LL*P[i]*P[i];\n        long long edgeSum = 0;\n        for(int e=0;e<M;e++) if(edgeOn[e]) edgeSum += edges[e].w;\n        fe.sol.P = P;\n        fe.sol.edgeOn = edgeOn;\n        fe.sol.pSum = pSum;\n        fe.sol.edgeSum = edgeSum;\n        fe.sol.S = pSum + edgeSum;\n        return fe;\n    };\n\n    auto start = chrono::steady_clock::now();\n    auto time_ms = [&](){\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count();\n    };\n\n    // Steinerization: build metric MST connecting terminals and re-optimize P\n    auto build_tree_for_terminals = [&](const vector<int>& T)->vector<char>{\n        int TS = (int)T.size();\n        vector<char> edgeOn(M, 0);\n        if(TS <= 1) return edgeOn;\n        // Prim on metric closure\n        vector<char> used(TS,0);\n        vector<long long> low(TS, INF);\n        vector<int> par(TS,-1);\n        used[0]=1;\n        for(int i=1;i<TS;i++){ low[i]=distW[T[0]][T[i]]; par[i]=0; }\n        vector<pair<int,int>> mstPairs; mstPairs.reserve(TS-1);\n        for(int it=0; it<TS-1; it++){\n            int v=-1; long long best=INF;\n            for(int j=0;j<TS;j++){\n                if(!used[j] && low[j] < best){\n                    best=low[j]; v=j;\n                }\n            }\n            if(v==-1) break;\n            used[v]=1;\n            mstPairs.emplace_back(T[par[v]], T[v]);\n            for(int j=0;j<TS;j++){\n                if(!used[j]){\n                    long long nd = distW[T[v]][T[j]];\n                    if(nd < low[j]){ low[j]=nd; par[j]=v; }\n                }\n            }\n        }\n        // Union of shortest paths for pairs\n        for(auto [u,v] : mstPairs){\n            int cur = v;\n            while(cur != u){\n                int eid = prevE[u][cur];\n                if(eid<0) break;\n                edgeOn[eid]=1;\n                cur = prevV[u][cur];\n                if(cur<0) break;\n            }\n        }\n        // Reduce within union by Kruskal\n        vector<int> unionEdges;\n        for(int e=0;e<M;e++) if(edgeOn[e]) unionEdges.push_back(e);\n        sort(unionEdges.begin(), unionEdges.end(), [&](int a,int b){ return edges[a].w < edges[b].w; });\n        DSU dsu(N);\n        vector<char> edgeOn2(M,0);\n        for(int e: unionEdges){\n            int u=edges[e].u, v=edges[e].v;\n            if(dsu.unite(u,v)) edgeOn2[e]=1;\n        }\n        // prune non-terminal leaves\n        vector<char> isTerm(N,0);\n        for(int v: T) isTerm[v]=1;\n        vector<vector<int>> inc(N);\n        for(int e=0;e<M;e++){\n            if(!edgeOn2[e]) continue;\n            int u=edges[e].u, v=edges[e].v;\n            inc[u].push_back(e);\n            inc[v].push_back(e);\n        }\n        vector<int> deg(N,0);\n        for(int i=0;i<N;i++){\n            for(int e: inc[i]) if(edgeOn2[e]) deg[i]++;\n        }\n        deque<int> dq;\n        for(int i=0;i<N;i++) if(deg[i]==1 && !isTerm[i]) dq.push_back(i);\n        vector<char> rm(N,0);\n        while(!dq.empty()){\n            int v=dq.front(); dq.pop_front();\n            if(rm[v]) continue;\n            if(deg[v]!=1 || isTerm[v]) continue;\n            int euniq=-1, u=-1;\n            for(int eid: inc[v]) if(edgeOn2[eid]){ euniq=eid; u=(edges[eid].u==v? edges[eid].v : edges[eid].u); break; }\n            if(euniq==-1) continue;\n            edgeOn2[euniq]=0; deg[v]--; deg[u]--; rm[v]=1;\n            if(deg[u]==1 && !isTerm[u]) dq.push_back(u);\n        }\n        return edgeOn2;\n    };\n\n    auto steinerize_from_P = [&](const Solution& sol)->Solution{\n        vector<int> T;\n        T.push_back(0);\n        for(int i=0;i<N;i++) if(sol.P[i] > 0 && i!=0) T.push_back(i);\n        vector<char> edgeOn = build_tree_for_terminals(T);\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    // Weighted set cover + MST\n    auto build_solution_setcover = [&](){\n        vector<char> selected(N, 0);\n        vector<char> uncovered(K, 1);\n        int remaining = K;\n        vector<long long> dRoot(N);\n        for(int i=0;i<N;i++) dRoot[i] = distW[0][i];\n\n        while(remaining > 0){\n            int besti = -1;\n            long long bestScore = LLONG_MIN/4;\n            int bestc = -1;\n            for(int i=0;i<N;i++){\n                if(selected[i]) continue;\n                int cnt = 0;\n                for(int k: covList[i]) if(uncovered[k]) cnt++;\n                if(cnt == 0) continue;\n                // score: balance coverage gain vs connection cost\n                long long score = 1'000'000LL * cnt - dRoot[i];\n                if(score > bestScore || (score == bestScore && cnt > bestc)){\n                    bestScore = score;\n                    bestc = cnt;\n                    besti = i;\n                }\n            }\n            if(besti==-1){\n                break;\n            }\n            selected[besti]=1;\n            for(int k : covList[besti]) if(uncovered[k]){ uncovered[k]=0; remaining--; }\n        }\n\n        // Remove redundant greedily\n        vector<int> coverCnt(K, 0);\n        for(int i=0;i<N;i++){\n            if(!selected[i]) continue;\n            for(int k: covList[i]) coverCnt[k]++;\n        }\n        bool ch = true;\n        int safe = 0;\n        while(ch && safe++ < N){\n            ch=false;\n            for(int i=0;i<N;i++){\n                if(!selected[i]) continue;\n                bool canRem = true;\n                for(int k: covList[i]) if(coverCnt[k] <= 1){ canRem=false; break; }\n                if(canRem){\n                    selected[i]=0;\n                    for(int k: covList[i]) coverCnt[k]--;\n                    ch=true;\n                }\n            }\n        }\n\n        // Terminals T\n        vector<int> T;\n        T.push_back(0);\n        for(int i=0;i<N;i++) if(selected[i] && i!=0) T.push_back(i);\n        vector<char> edgeOn = build_tree_for_terminals(T);\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    // SPT greedy coverage\n    auto build_solution_spt = [&](){\n        vector<char> inV(N, 0);\n        vector<char> edgeOn(M, 0);\n        inV[0]=1;\n        vector<uint64_t> covered(B, 0ULL);\n        for(int b=0;b<B;b++) covered[b] |= covBits[0][b];\n        auto allCovered = [&](){\n            for(int b=0;b<B;b++){\n                uint64_t mask = (b==B-1? lastMask : ~0ULL);\n                if( (covered[b] & mask) != mask) return false;\n            }\n            return true;\n        };\n        vector<uint64_t> tmp(B);\n        while(!allCovered()){\n            int bestV = -1;\n            long long bestGain = -1;\n            long long bestIncW = (1LL<<60);\n            for(int v=0; v<N; v++){\n                if(inV[v]) continue;\n                for(int b=0;b<B;b++) tmp[b]=0ULL;\n                long long incW=0;\n                int cur=v; bool any=false;\n                while(cur!=-1 && !inV[cur]){\n                    for(int b=0;b<B;b++) tmp[b] |= covBits[cur][b];\n                    int pe = parentEdgeSPT[cur];\n                    if(pe>=0) incW += edges[pe].w;\n                    cur = parentSPT[cur];\n                    any=true;\n                }\n                if(!any) continue;\n                long long gain=0;\n                for(int b=0;b<B;b++){\n                    uint64_t mask = (b==B-1? lastMask : ~0ULL);\n                    uint64_t nc = (~covered[b]) & mask;\n                    uint64_t add = tmp[b] & nc;\n                    gain += __builtin_popcountll(add);\n                }\n                if(gain > bestGain || (gain==bestGain && incW < bestIncW)){\n                    bestGain=gain; bestIncW=incW; bestV=v;\n                }\n            }\n            if(bestV==-1) break;\n            for(int b=0;b<B;b++) tmp[b]=0ULL;\n            int cur=bestV;\n            while(cur!=-1 && !inV[cur]){\n                for(int b=0;b<B;b++) tmp[b] |= covBits[cur][b];\n                int pe = parentEdgeSPT[cur];\n                if(pe>=0) edgeOn[pe]=1;\n                inV[cur]=1;\n                cur = parentSPT[cur];\n            }\n            for(int b=0;b<B;b++) covered[b] |= tmp[b];\n        }\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    Solution sol1 = build_solution_setcover();\n    Solution sol2 = build_solution_spt();\n\n    // Steinerize both initial solutions based on P>0 terminals to reduce edge costs\n    auto maybe_steinerize_iters = [&](Solution s)->Solution{\n        if (s.P.empty()) return s;\n        for(int it=0; it<2; ++it){\n            Solution s2 = steinerize_from_P(s);\n            if(s2.S < s.S) s = s2;\n            else break;\n        }\n        return s;\n    };\n    sol1 = maybe_steinerize_iters(sol1);\n    sol2 = maybe_steinerize_iters(sol2);\n    Solution best = (sol1.S <= sol2.S ? sol1 : sol2);\n\n    // Local search: edge removals with fast evaluation\n    auto removal_pass = [&](Solution cur)->Solution{\n        vector<char> edgeOn = cur.edgeOn;\n        auto fe = fast_evaluate(edgeOn);\n        long long curS = fe.S;\n        // Sort ON edges by descending weight\n        vector<int> onEdges;\n        for(int e=0;e<M;e++) if(edgeOn[e]) onEdges.push_back(e);\n        sort(onEdges.begin(), onEdges.end(), [&](int a,int b){ return edges[a].w > edges[b].w; });\n        bool improved=true;\n        int rounds=0;\n        while(improved && rounds<2){\n            improved=false; rounds++;\n            for(int e : onEdges){\n                if(!edgeOn[e]) continue;\n                edgeOn[e]=0;\n                // check coverage possibility (5000 reachability)\n                vector<char> inV = build_inV(edgeOn);\n                int covered = count_covered_bits(inV);\n                if(covered < K){\n                    edgeOn[e]=1;\n                    continue;\n                }\n                auto fe2 = fast_evaluate(edgeOn);\n                if(fe2.S <= curS){\n                    fe = fe2;\n                    curS = fe2.S;\n                    improved=true;\n                }else{\n                    edgeOn[e]=1;\n                }\n            }\n        }\n        // finalize with full optimization + pruning\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    auto addition_pass = [&](Solution cur)->Solution{\n        // perform a few greedy additions\n        vector<char> edgeOn = cur.edgeOn;\n        auto fe = fast_evaluate(edgeOn);\n        long long curS = fe.S;\n        int tries = 0;\n        while(tries < 12){\n            vector<char> inV = fe.inV;\n            vector<int>& bestD2 = fe.bestD2;\n            vector<pair<long long,int>> cand; // (score, edge)\n            cand.reserve(M);\n            for(int e=0;e<M;e++){\n                if(edgeOn[e]) continue;\n                int u=edges[e].u, v=edges[e].v;\n                int a = inV[u], b = inV[v];\n                if(a ^ b){\n                    int t = a? v : u;\n                    long long better = 0;\n                    for(int k=0;k<K;k++){\n                        int d2 = d2sr[t][k];\n                        if(d2 < bestD2[k]) better++;\n                    }\n                    if(better>0){\n                        long long score = better*1000000LL - (edges[e].w / 1000LL);\n                        cand.emplace_back(score, e);\n                    }\n                }\n            }\n            if(cand.empty()) break;\n            sort(cand.begin(), cand.end(), greater<>());\n            bool added=false;\n            int upto = min((int)cand.size(), 10);\n            for(int idx=0; idx<upto; idx++){\n                int e = cand[idx].second;\n                edgeOn[e]=1;\n                auto fe2 = fast_evaluate(edgeOn);\n                if(fe2.allCovered && fe2.S < curS){\n                    fe = fe2;\n                    curS = fe2.S;\n                    added=true;\n                    break;\n                }else{\n                    edgeOn[e]=0;\n                }\n            }\n            if(!added) break;\n            tries++;\n        }\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    // Ensure final coverage helper\n    auto ensure_full_coverage = [&](Solution& sol){\n        vector<char> inV = build_inV(sol.edgeOn);\n\n        auto isCoveredByP = [&](int k)->bool{\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                long long d2 = d2sr[i][k];\n                if(1LL*sol.P[i]*sol.P[i] >= d2) return true;\n            }\n            return false;\n        };\n\n        vector<int> uncovered;\n        uncovered.reserve(K);\n        for(int k=0;k<K;k++){\n            if(!isCoveredByP(k)) uncovered.push_back(k);\n        }\n\n        // First try to cover by increasing P on existing reachable stations\n        vector<int> needConnectResidents;\n        for(int k : uncovered){\n            int bestI = -1;\n            long long bestInc = (1LL<<62);\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                int needR = sqrt_ceil_ll(d2sr[i][k]);\n                if(needR > 5000) continue;\n                long long inc = 1LL*needR*needR - 1LL*sol.P[i]*sol.P[i];\n                if(inc < 0) inc = 0;\n                if(inc < bestInc){\n                    bestInc = inc; bestI = i;\n                }\n            }\n            if(bestI == -1){\n                // no reachable station within 5000: need to connect\n                needConnectResidents.push_back(k);\n            }else{\n                int needR = sqrt_ceil_ll(d2sr[bestI][k]);\n                if(needR > sol.P[bestI]) sol.P[bestI] = needR;\n            }\n        }\n\n        // Connect necessary stations: choose nearest in terms of root path\n        vector<char> toAddEdge(M, 0);\n        for(int k : needConnectResidents){\n            long long bestDist = (1LL<<60);\n            int bestI = -1;\n            for(int i : nearStationsForResid[k]){\n                if(distW[0][i] < bestDist){\n                    bestDist = distW[0][i];\n                    bestI = i;\n                }\n            }\n            if(bestI == -1) continue; // should not happen per input guarantee\n            int cur = bestI;\n            while(cur != 0){\n                int eid = prevE[0][cur];\n                if(eid < 0) break;\n                toAddEdge[eid] = 1;\n                cur = prevV[0][cur];\n                if(cur < 0) break;\n            }\n        }\n        bool anyAdd = false;\n        if(!needConnectResidents.empty()){\n            for(int e=0;e<M;e++){\n                if(toAddEdge[e] && !sol.edgeOn[e]){\n                    sol.edgeOn[e] = 1; anyAdd = true;\n                    sol.edgeSum += edges[e].w;\n                }\n            }\n            if(anyAdd){\n                inV = build_inV(sol.edgeOn);\n            }\n        }\n\n        // After connecting, cover remaining uncovered by increasing P\n        vector<int> uncovered2;\n        for(int k=0;k<K;k++){\n            bool ok = false;\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                if(1LL*sol.P[i]*sol.P[i] >= (long long)d2sr[i][k]){ ok = true; break; }\n            }\n            if(!ok) uncovered2.push_back(k);\n        }\n        for(int k : uncovered2){\n            int bestI = -1;\n            long long bestInc = (1LL<<62);\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                int needR = sqrt_ceil_ll(d2sr[i][k]);\n                if(needR > 5000) continue;\n                long long inc = 1LL*needR*needR - 1LL*sol.P[i]*sol.P[i];\n                if(inc < 0) inc = 0;\n                if(inc < bestInc){\n                    bestInc = inc; bestI = i;\n                }\n            }\n            if(bestI != -1){\n                int needR = sqrt_ceil_ll(d2sr[bestI][k]);\n                if(needR > sol.P[bestI]) sol.P[bestI] = needR;\n            }\n        }\n\n        // Recompute pSum and S\n        sol.pSum = 0;\n        for(int i=0;i<N;i++){\n            if(sol.P[i] > 5000) sol.P[i] = 5000;\n            sol.pSum += 1LL*sol.P[i]*sol.P[i];\n        }\n        sol.edgeSum = 0;\n        for(int e=0;e<M;e++) if(sol.edgeOn[e]) sol.edgeSum += edges[e].w;\n        sol.S = sol.pSum + sol.edgeSum;\n    };\n\n    auto terminal_drop_search = [&](Solution cur)->Solution{\n        Solution bestS = cur;\n        int outer = 0;\n        while(outer < 2){\n            outer++;\n            auto fe = optimize_assignment(bestS.edgeOn);\n            vector<int> countAssigned(N, 0);\n            for(int r=0;r<K;r++){\n                int i = fe.assignTo[r];\n                if(i>=0) countAssigned[i]++;\n            }\n            vector<int> terminals;\n            for(int i=0;i<N;i++) if(fe.sol.P[i]>0) terminals.push_back(i);\n            // candidates: terminals except root, prioritize small P then small assigned count\n            vector<pair<pair<int,int>, int>> cand; // ((P^2, assigned), i)\n            for(int i: terminals){\n                if(i==0) continue;\n                cand.push_back({{fe.sol.P[i]*fe.sol.P[i], countAssigned[i]}, i});\n            }\n            sort(cand.begin(), cand.end()); // ascending\n            bool improved = false;\n            int limit = min((int)cand.size(), 15);\n            for(int idx=0; idx<limit; idx++){\n                int drop = cand[idx].second;\n                vector<int> T;\n                T.push_back(0);\n                for(int v: terminals) if(v!=drop && v!=0) T.push_back(v);\n                vector<char> edgeOn = build_tree_for_terminals(T);\n                auto f2 = optimize_assignment(edgeOn);\n                vector<char> edgeOn2 = f2.sol.edgeOn;\n                prune_unused_leaves(edgeOn2, f2.sol.P);\n                auto f3 = optimize_assignment(edgeOn2);\n                Solution candSol = f3.sol;\n                ensure_full_coverage(candSol);\n                // a short steinerize after ensure (can reduce edges)\n                Solution candSol2 = steinerize_from_P(candSol);\n                if(candSol2.S < candSol.S) candSol = candSol2;\n                if(candSol.S < bestS.S){\n                    bestS = candSol;\n                    improved = true;\n                    break;\n                }\n            }\n            if(!improved) break;\n        }\n        return bestS;\n    };\n\n    // Apply local search passes\n    Solution afterRem = removal_pass(best);\n    if(afterRem.S < best.S) best = afterRem;\n\n    Solution afterDrop = terminal_drop_search(best);\n    if(afterDrop.S < best.S) best = afterDrop;\n\n    Solution afterAdd = addition_pass(best);\n    if(afterAdd.S < best.S) best = afterAdd;\n\n    Solution afterRem2 = removal_pass(best);\n    if(afterRem2.S < best.S) best = afterRem2;\n\n    // Ensure final coverage and a final steinerization\n    auto finalize_solution = [&](Solution s)->Solution{\n        ensure_full_coverage(s);\n        Solution s2 = steinerize_from_P(s);\n        if(s2.S < s.S) s = s2;\n        return s;\n    };\n    best = finalize_solution(best);\n\n    // Output final solution\n    for(int i=0;i<N;i++){\n        if(i) cout << ' ';\n        cout << best.P[i];\n    }\n    cout << '\\n';\n    for(int j=0;j<M;j++){\n        if(j) cout << ' ';\n        cout << (best.edgeOn[j] ? 1 : 0);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Move {\n    int x1, y1, x2, y2;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 30;\n    vector<vector<int>> A(N);\n    for (int x = 0; x < N; ++x) {\n        A[x].resize(x + 1);\n        for (int y = 0; y <= x; ++y) cin >> A[x][y];\n    }\n\n    const int LIMIT = 10000;\n    vector<Move> ops;\n    ops.reserve(LIMIT);\n\n    auto inRange = [&](int x, int y) -> bool {\n        return 0 <= x && x < N && 0 <= y && y <= x;\n    };\n\n    auto isViolation = [&](int x, int y) -> bool {\n        if (x >= N - 1) return false;\n        int v = A[x][y];\n        int c1 = A[x + 1][y];\n        int c2 = A[x + 1][y + 1];\n        return v > (c1 < c2 ? c1 : c2);\n    };\n\n    auto severityNow = [&](int x, int y) -> int {\n        if (x >= N - 1) return INT_MIN / 2;\n        int v = A[x][y];\n        int c1 = A[x + 1][y];\n        int c2 = A[x + 1][y + 1];\n        return v - (c1 < c2 ? c1 : c2);\n    };\n\n    // Subtriangle minima M[x][y] = min over subtriangle rooted at (x,y)\n    vector<vector<int>> M(N);\n    for (int x = 0; x < N; ++x) M[x].assign(x + 1, 0);\n\n    auto recomputeM = [&]() {\n        for (int y = 0; y < N; ++y) M[N - 1][y] = A[N - 1][y];\n        for (int x = N - 2; x >= 0; --x) {\n            for (int y = 0; y <= x; ++y) {\n                int m = A[x][y];\n                int ml = M[x + 1][y];\n                int mr = M[x + 1][y + 1];\n                if (ml < m) m = ml;\n                if (mr < m) m = mr;\n                M[x][y] = m;\n            }\n        }\n    };\n\n    recomputeM();\n\n    auto edgeDistance = [&](int x, int y) -> int {\n        return min(y, x - y);\n    };\n\n    auto chooseChild = [&](int x, int y) -> pair<int,int> {\n        // Choose smaller child; on tie, prefer smaller subtree min via M; then edge preference.\n        int v1 = A[x + 1][y];\n        int v2 = A[x + 1][y + 1];\n        if (v1 < v2) return {x + 1, y};\n        if (v2 < v1) return {x + 1, y + 1};\n        int mL = M[x + 1][y];\n        int mR = M[x + 1][y + 1];\n        if (mL < mR) return {x + 1, y};\n        if (mR < mL) return {x + 1, y + 1};\n        // still tie: prefer closer to edge (fewer parents)\n        int dL = edgeDistance(x + 1, y);\n        int dR = edgeDistance(x + 1, y + 1);\n        if (dL < dR) return {x + 1, y};\n        if (dR < dL) return {x + 1, y + 1};\n        // fallback\n        return {x + 1, y};\n    };\n\n    auto planPath = [&](int sx, int sy) {\n        vector<pair<int,int>> path;\n        int x = sx, y = sy;\n        int cur = A[x][y];\n        path.emplace_back(x, y);\n        while (x < N - 1) {\n            int c1 = A[x + 1][y];\n            int c2 = A[x + 1][y + 1];\n            int mn = (c1 < c2 ? c1 : c2);\n            if (cur <= mn) break;\n            auto [nx, ny] = chooseChild(x, y);\n            x = nx; y = ny;\n            path.emplace_back(x, y);\n        }\n        return path;\n    };\n\n    auto pathLen = [&](int sx, int sy) -> int {\n        int x = sx, y = sy;\n        int cur = A[x][y];\n        int len = 0;\n        while (x < N - 1) {\n            int c1 = A[x + 1][y];\n            int c2 = A[x + 1][y + 1];\n            int mn = (c1 < c2 ? c1 : c2);\n            if (cur <= mn) break;\n            auto [nx, ny] = chooseChild(x, y);\n            x = nx; y = ny;\n            ++len;\n        }\n        return len;\n    };\n\n    // Bottom-up pass; within each row, pick candidate by longest estimated path\n    for (int x = N - 2; x >= 0 && (int)ops.size() < LIMIT; --x) {\n        vector<char> done(x + 1, 0);\n        while ((int)ops.size() < LIMIT) {\n            int best_y = -1;\n            int best_len = -1;\n            int best_sev = INT_MIN;\n            int best_edge = INT_MAX;\n\n            // Scan current row for best candidate\n            for (int y = 0; y <= x; ++y) {\n                if (done[y]) continue;\n                if (!isViolation(x, y)) { done[y] = 1; continue; }\n                int len = pathLen(x, y);\n                int sev = severityNow(x, y);\n                int edg = edgeDistance(x, y);\n                if (len > best_len ||\n                    (len == best_len && sev > best_sev) ||\n                    (len == best_len && sev == best_sev && edg < best_edge)) {\n                    best_len = len;\n                    best_sev = sev;\n                    best_edge = edg;\n                    best_y = y;\n                }\n            }\n\n            if (best_y == -1 || best_len <= 0) break; // no more violations on this row\n\n            // Plan and execute path for best candidate\n            auto path = planPath(x, best_y);\n            int steps = (int)path.size() - 1;\n            if (steps > 0) {\n                int can = min(steps, LIMIT - (int)ops.size());\n                for (int i = 0; i < can; ++i) {\n                    auto [x1, y1] = path[i];\n                    auto [x2, y2] = path[i + 1];\n                    swap(A[x1][y1], A[x2][y2]);\n                    ops.push_back({x1, y1, x2, y2});\n                }\n                // Recompute subtriangle minima after this path\n                recomputeM();\n                if (can < steps) break; // hit budget\n            }\n            // Mark this y as done; heap property at (x, best_y) is stable thereafter\n            done[best_y] = 1;\n        }\n    }\n\n    // Safety net: event-driven cleanup if any violation persists and budget remains (rare)\n    if ((int)ops.size() < LIMIT) {\n        bool any = false;\n        for (int x = 0; x <= N - 2 && !any; ++x)\n            for (int y = 0; y <= x; ++y)\n                if (isViolation(x, y)) { any = true; break; }\n        if (any) {\n            vector<vector<char>> inQ(N);\n            for (int x = 0; x < N; ++x) inQ[x].assign(x + 1, 0);\n            deque<pair<int,int>> q;\n            auto pushQ = [&](int x, int y) {\n                if (!inRange(x, y) || x >= N - 1) return;\n                if (inQ[x][y]) return;\n                if (!isViolation(x, y)) return;\n                inQ[x][y] = 1;\n                q.emplace_back(x, y);\n            };\n            for (int x = 0; x <= N - 2; ++x)\n                for (int y = 0; y <= x; ++y)\n                    if (isViolation(x, y)) pushQ(x, y);\n\n            while (!q.empty() && (int)ops.size() < LIMIT) {\n                auto [sx, sy] = q.front(); q.pop_front();\n                inQ[sx][sy] = 0;\n                int x = sx, y = sy;\n                while (x < N - 1) {\n                    int v = A[x][y];\n                    int v1 = A[x + 1][y];\n                    int v2 = A[x + 1][y + 1];\n                    int mn = min(v1, v2);\n                    if (v <= mn) break;\n                    int tx = (v1 < v2 ? x + 1 : x + 1);\n                    int ty = (v1 < v2 ? y     : y + 1);\n                    if ((int)ops.size() >= LIMIT) break;\n                    swap(A[x][y], A[tx][ty]);\n                    ops.push_back({x, y, tx, ty});\n                    if (y - 1 >= 0) pushQ(x - 1, y - 1);\n                    if (y <= x - 1) pushQ(x - 1, y);\n                    x = tx; y = ty;\n                }\n                if (x < N - 1 && isViolation(x, y)) pushQ(x, y);\n            }\n        }\n    }\n\n    int K = min<int>((int)ops.size(), LIMIT);\n    cout << K << '\\n';\n    for (int i = 0; i < K; ++i) {\n        cout << ops[i].x1 << ' ' << ops[i].y1 << ' ' << ops[i].x2 << ' ' << ops[i].y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int i, j; };\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    const int H = D, W = D;\n    const int ei = 0, ej = (D - 1) / 2; // entrance coordinates\n    const int INF = 1e9;\n\n    // Obstacles\n    vector<vector<char>> obs(H, vector<char>(W, 0));\n    for (int k = 0; k < N; ++k) {\n        int r, c;\n        cin >> r >> c;\n        obs[r][c] = 1;\n    }\n\n    auto inside = [&](int i, int j){ return 0 <= i && i < H && 0 <= j && j < W; };\n    int di[4] = {-1, 0, 1, 0};\n    int dj[4] = {0, 1, 0, -1};\n\n    // Precompute BFS distances from entrance (ignoring containers)\n    vector<vector<int>> dist(H, vector<int>(W, INF));\n    deque<Pos> dq;\n    dist[ei][ej] = 0;\n    dq.push_back({ei, ej});\n    while (!dq.empty()) {\n        auto p = dq.front(); dq.pop_front();\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = p.i + di[dir], nj = p.j + dj[dir];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (dist[ni][nj] > dist[p.i][p.j] + 1) {\n                dist[ni][nj] = dist[p.i][p.j] + 1;\n                dq.push_back({ni, nj});\n            }\n        }\n    }\n\n    // Build target order: increasing distance from entrance, tie by (i,j)\n    vector<Pos> order;\n    order.reserve(H*W);\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            if (obs[i][j]) continue;\n            if (i == ei && j == ej) continue;\n            order.push_back({i, j});\n        }\n    }\n    sort(order.begin(), order.end(), [&](const Pos &a, const Pos &b){\n        if (dist[a.i][a.j] != dist[b.i][b.j]) return dist[a.i][a.j] < dist[b.i][b.j];\n        if (a.i != b.i) return a.i < b.i;\n        return a.j < b.j;\n    });\n    int M = (int)order.size();\n\n    // rank index of each cell in the order\n    vector<vector<int>> rankIndex(H, vector<int>(W, -1));\n    for (int idx = 0; idx < (int)order.size(); ++idx) {\n        rankIndex[order[idx].i][order[idx].j] = idx;\n    }\n\n    // State during placement\n    vector<vector<char>> empty(H, vector<char>(W, 0)); // currently empty and not obstacle (entrance included)\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) empty[i][j] = !obs[i][j];\n    vector<vector<int>> labelAt(H, vector<int>(W, -1)); // label placed at cell (if any), -1 if none\n\n    // Tarjan articulation points on current empty graph (including entrance)\n    auto compute_articulation = [&](const vector<vector<char>>& curEmpty)->vector<vector<char>> {\n        vector<vector<int>> id(H, vector<int>(W, -1));\n        vector<Pos> nodes; nodes.reserve(H*W);\n        int vid = 0;\n        for (int i = 0; i < H; ++i)\n            for (int j = 0; j < W; ++j)\n                if (curEmpty[i][j]) { id[i][j] = vid++; nodes.push_back({i,j}); }\n\n        int n = vid;\n        vector<vector<int>> g(n);\n        for (auto &p : nodes) {\n            int u = id[p.i][p.j];\n            for (int d = 0; d < 4; ++d) {\n                int ni = p.i + di[d], nj = p.j + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (!curEmpty[ni][nj]) continue;\n                int v = id[ni][nj];\n                g[u].push_back(v);\n            }\n        }\n        vector<int> tin(n, -1), low(n, -1), parent(n, -1);\n        vector<char> isArtV(n, 0);\n        int timer = 0;\n        function<void(int)> dfs = [&](int u){\n            tin[u] = low[u] = timer++;\n            int child = 0;\n            for (int v : g[u]) {\n                if (tin[v] == -1) {\n                    parent[v] = u;\n                    ++child;\n                    dfs(v);\n                    low[u] = min(low[u], low[v]);\n                    if (parent[u] != -1 && low[v] >= tin[u]) isArtV[u] = 1;\n                } else if (v != parent[u]) {\n                    low[u] = min(low[u], tin[v]);\n                }\n            }\n            if (parent[u] == -1 && child > 1) isArtV[u] = 1;\n        };\n        for (int u = 0; u < n; ++u) if (tin[u] == -1) dfs(u);\n\n        vector<vector<char>> isArt(H, vector<char>(W, 0));\n        for (auto &p : nodes) {\n            int u = id[p.i][p.j];\n            isArt[p.i][p.j] = isArtV[u];\n        }\n        return isArt;\n    };\n\n    auto count_safe_prefix = [&](const vector<vector<char>> &isArt, const vector<vector<char>> &curEmpty, int prefixLen)->int {\n        int cnt = 0;\n        for (int k = 0; k < (int)order.size() && k < prefixLen; ++k) {\n            int i = order[k].i, j = order[k].j;\n            if (!curEmpty[i][j]) continue;\n            if (!isArt[i][j]) cnt++;\n        }\n        return cnt;\n    };\n\n    int step = 0;\n\n    auto choose_position = [&](int label)->Pos {\n        vector<vector<char>> baseArt = compute_articulation(empty);\n\n        struct Cand { int i, j, idx, baseCost, deg; };\n        vector<Cand> cands;\n        cands.reserve(order.size());\n        for (int k = 0; k < (int)order.size(); ++k) {\n            int i = order[k].i, j = order[k].j;\n            if (!empty[i][j]) continue;     // already occupied\n            if (baseArt[i][j]) continue;    // avoid articulation to keep connectivity\n            int deg = 0;\n            for (int d = 0; d < 4; ++d) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (empty[ni][nj]) deg++;\n            }\n            int cost = abs(k - label);\n            cands.push_back({i, j, k, cost, deg});\n        }\n\n        if (cands.empty()) {\n            // Fallback: any empty non-entrance cell\n            for (int k = 0; k < (int)order.size(); ++k) {\n                int i = order[k].i, j = order[k].j;\n                if (!empty[i][j]) continue;\n                return {i, j};\n            }\n        }\n\n        // Prefer candidates within a window around the target index (keeps labels near their ideal spot)\n        int Wrange = max(8, M / 6); // ~12 for M~80\n        vector<Cand> windowCands;\n        windowCands.reserve(cands.size());\n        for (auto &c : cands) if (abs(c.idx - label) <= Wrange) windowCands.push_back(c);\n        vector<Cand> &useCands = windowCands.empty() ? cands : windowCands;\n\n        sort(useCands.begin(), useCands.end(), [&](const Cand& a, const Cand& b){\n            if (a.baseCost != b.baseCost) return a.baseCost < b.baseCost;\n            if (a.deg != b.deg) return a.deg < b.deg;\n            if (dist[a.i][a.j] != dist[b.i][b.j]) return dist[a.i][a.j] < dist[b.i][b.j];\n            if (a.i != b.i) return a.i < b.i;\n            return a.j < b.j;\n        });\n\n        int K = min<int>(25, useCands.size());      // evaluate top-K\n        int P = min<int>(20, (int)order.size());    // protect early prefix\n        int baseSafePrefix = count_safe_prefix(baseArt, empty, P);\n        int wUnlock = 2; // mild bonus\n\n        long long bestScoreLL = LLONG_MIN;\n        Pos best{-1, -1};\n        int bestBaseCost = INT_MAX;\n        int bestDist = INT_MAX;\n\n        for (int z = 0; z < K; ++z) {\n            auto c = useCands[z];\n            // Tentative placement\n            empty[c.i][c.j] = 0;\n            vector<vector<char>> art2 = compute_articulation(empty);\n            int afterSafe = count_safe_prefix(art2, empty, P);\n            int benefit = afterSafe - baseSafePrefix;\n\n            long long score = -(long long)c.baseCost + (long long)wUnlock * benefit;\n            // tiny tie-breaker\n            score -= (c.deg >= 3 ? 1 : 0);\n\n            empty[c.i][c.j] = 1;\n\n            if (score > bestScoreLL) {\n                bestScoreLL = score;\n                best = {c.i, c.j};\n                bestBaseCost = c.baseCost;\n                bestDist = dist[c.i][c.j];\n            } else if (score == bestScoreLL) {\n                if (c.baseCost < bestBaseCost) {\n                    best = {c.i, c.j};\n                    bestBaseCost = c.baseCost;\n                    bestDist = dist[c.i][c.j];\n                } else if (c.baseCost == bestBaseCost) {\n                    if (dist[c.i][c.j] < bestDist) {\n                        best = {c.i, c.j};\n                        bestDist = dist[c.i][c.j];\n                    }\n                }\n            }\n        }\n\n        if (best.i == -1) {\n            auto c = useCands[0];\n            best = {c.i, c.j};\n        }\n        return best;\n    };\n\n    // Interactive placement\n    for (step = 0; step < M; ++step) {\n        int t;\n        cin >> t;\n        Pos p = choose_position(t);\n        empty[p.i][p.j] = 0;\n        labelAt[p.i][p.j] = t;\n        cout << p.i << ' ' << p.j << '\\n' << flush;\n    }\n\n    // Retrieval strategies: simulate and choose the one with fewer inversions\n    auto inversion_count = [&](const vector<int>& a)->long long {\n        int n = (int)a.size();\n        int MX = n + 2;\n        vector<int> bit(MX, 0);\n        auto add = [&](int i){\n            for (++i; i < MX; i += i & -i) bit[i] += 1;\n        };\n        auto sum = [&](int i){\n            int s = 0;\n            for (++i; i > 0; i -= i & -i) s += bit[i];\n            return s;\n        };\n        long long inv = 0;\n        for (int i = 0; i < n; ++i) {\n            inv += i - sum(a[i]);\n            add(a[i]);\n        }\n        return inv;\n    };\n\n    // Base occupancy\n    vector<vector<char>> occ0(H, vector<char>(W, 0));\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        if (obs[i][j]) continue;\n        if (i == ei && j == ej) continue;\n        if (labelAt[i][j] >= 0) occ0[i][j] = 1;\n    }\n\n    // Strategy B: greedy smallest-label frontier\n    vector<pair<int,int>> seqB;\n    {\n        auto occ = occ0;\n        struct Node { int label, i, j; bool operator<(const Node& o) const { return label > o.label; } };\n        priority_queue<Node> pq;\n        vector<vector<char>> inFrontier(H, vector<char>(W, 0));\n        auto try_push = [&](int i, int j){\n            if (!inside(i,j)) return;\n            if (obs[i][j]) return;\n            if (!occ[i][j]) return;\n            if (inFrontier[i][j]) return;\n            inFrontier[i][j] = 1;\n            pq.push({labelAt[i][j], i, j});\n        };\n        for (int d = 0; d < 4; ++d) {\n            int ni = ei + di[d], nj = ej + dj[d];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (occ[ni][nj]) try_push(ni, nj);\n        }\n        for (int step2 = 0; step2 < M; ++step2) {\n            while (!pq.empty() && !occ[pq.top().i][pq.top().j]) pq.pop();\n            if (pq.empty()) {\n                // Shouldn't happen; robustness: find any frontier cell\n                bool pushed = false;\n                for (int i = 0; i < H && !pushed; ++i) for (int j = 0; j < W && !pushed; ++j) {\n                    if (!occ[i][j]) continue;\n                    for (int d = 0; d < 4; ++d) {\n                        int ni = i + di[d], nj = j + dj[d];\n                        if (!inside(ni, nj)) continue;\n                        if (obs[ni][nj]) continue;\n                        if (!occ[ni][nj]) { try_push(i, j); pushed = true; break; }\n                    }\n                }\n                if (pq.empty()) break;\n            }\n            auto cur = pq.top(); pq.pop();\n            int ci = cur.i, cj = cur.j;\n            occ[ci][cj] = 0;\n            seqB.emplace_back(ci, cj);\n            for (int d = 0; d < 4; ++d) {\n                int ni = ci + di[d], nj = cj + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (obs[ni][nj]) continue;\n                if (occ[ni][nj]) try_push(ni, nj);\n            }\n        }\n    }\n    vector<int> labelsB; labelsB.reserve(M);\n    for (auto &p : seqB) labelsB.push_back(labelAt[p.first][p.second]);\n    long long invB = inversion_count(labelsB);\n\n    // Strategy C: greedy closest to BFS-rank head\n    vector<pair<int,int>> seqC;\n    {\n        auto occ = occ0;\n        struct NodeC {\n            int key, idx, label, i, j;\n            bool operator<(const NodeC& o) const {\n                if (key != o.key) return key > o.key;\n                if (label != o.label) return label > o.label;\n                return idx > o.idx;\n            }\n        };\n        priority_queue<NodeC> pq;\n        vector<vector<char>> inFrontier(H, vector<char>(W, 0));\n        int headIdx = 0;\n        auto try_push = [&](int i, int j){\n            if (!inside(i,j)) return;\n            if (obs[i][j]) return;\n            if (!occ[i][j]) return;\n            if (inFrontier[i][j]) return;\n            inFrontier[i][j] = 1;\n            int idx = rankIndex[i][j];\n            int key = abs(idx - headIdx);\n            pq.push(NodeC{key, idx, labelAt[i][j], i, j});\n        };\n        for (int d = 0; d < 4; ++d) {\n            int ni = ei + di[d], nj = ej + dj[d];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (occ[ni][nj]) try_push(ni, nj);\n        }\n        for (int step2 = 0; step2 < M; ++step2) {\n            while (!pq.empty() && !occ[pq.top().i][pq.top().j]) pq.pop();\n            if (pq.empty()) {\n                bool pushed = false;\n                for (int i = 0; i < H && !pushed; ++i) for (int j = 0; j < W && !pushed; ++j) {\n                    if (!occ[i][j]) continue;\n                    for (int d = 0; d < 4; ++d) {\n                        int ni = i + di[d], nj = j + dj[d];\n                        if (!inside(ni, nj)) continue;\n                        if (obs[ni][nj]) continue;\n                        if (!occ[ni][nj]) { try_push(i, j); pushed = true; break; }\n                    }\n                }\n                if (pq.empty()) break;\n            }\n            auto cur = pq.top(); pq.pop();\n            int ci = cur.i, cj = cur.j;\n            occ[ci][cj] = 0;\n            seqC.emplace_back(ci, cj);\n            // advance headIdx to next unremoved index\n            while (headIdx < M) {\n                auto p = order[headIdx];\n                if (occ[p.i][p.j]) break;\n                headIdx++;\n            }\n            for (int d = 0; d < 4; ++d) {\n                int ni = ci + di[d], nj = cj + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (obs[ni][nj]) continue;\n                if (occ[ni][nj]) try_push(ni, nj);\n            }\n        }\n    }\n    vector<int> labelsC; labelsC.reserve(M);\n    for (auto &p : seqC) labelsC.push_back(labelAt[p.first][p.second]);\n    long long invC = inversion_count(labelsC);\n\n    // Choose the better legal sequence\n    vector<pair<int,int>>* bestSeq = &seqB;\n    long long bestInv = invB;\n    if ((int)seqC.size() == M && invC < bestInv) { bestInv = invC; bestSeq = &seqC; }\n    // ensure we output exactly M lines; if a sequence is short due to unforeseen issue, fallback to the other\n    if ((int)bestSeq->size() != M) {\n        if ((int)seqB.size() == M) bestSeq = &seqB;\n        else bestSeq = &seqC; // one of them should be full; as a last resort\n    }\n\n    for (auto &p : *bestSeq) {\n        cout << p.first << ' ' << p.second << '\\n';\n    }\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    if (!(cin >> n >> m)) return 0;\n    const int N = n * n;\n\n    vector<int> origGrid(N);\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j < n; ++j)\n            cin >> origGrid[i*n + j];\n\n    auto inb = [&](int r, int c)->bool { return 0 <= r && r < n && 0 <= c && c < n; };\n    const int dr[4] = {1, -1, 0, 0};\n    const int dc[4] = {0, 0, 1, -1};\n\n    // Boundary flags and BC/IC classification\n    vector<char> isBoundaryPos(N, 0);\n    vector<int> boundaryCount0(m+1, 0);\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j;\n            if (i == 0 || j == 0 || i == n-1 || j == n-1) {\n                isBoundaryPos[id] = 1;\n                boundaryCount0[origGrid[id]]++;\n            }\n        }\n    vector<char> isBC(m+1, 0), isIC(m+1, 0);\n    for (int c = 1; c <= m; ++c) isBC[c] = (boundaryCount0[c] > 0);\n    for (int c = 1; c <= m; ++c) isIC[c] = !isBC[c];\n\n    // Initial same-color degree on original\n    vector<int> degSame0(N, 0);\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j, c = origGrid[id], d = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                if (origGrid[ni*n + nj] == c) d++;\n            }\n            degSame0[id] = d;\n        }\n\n    // Cells adjacent to interior colors (guard cells)\n    vector<char> adjToIC(N, 0);\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j;\n            bool flag = false;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = origGrid[ni*n + nj];\n                if (d != 0 && isIC[d]) { flag = true; break; }\n            }\n            adjToIC[id] = flag ? 1 : 0;\n        }\n\n    // Adjacency edges for each non-zero pair (u, v), u < v (original)\n    unordered_map<int, vector<pair<int,int>>> pairEdgesOrig;\n    pairEdgesOrig.reserve(4000);\n    auto add_pair_edge = [&](unordered_map<int, vector<pair<int,int>>> &mp, int a, int b, int idA, int idB){\n        if (a == 0 || b == 0 || a == b) return;\n        int u = a, v = b, idU = idA, idV = idB;\n        if (u > v) { swap(u, v); swap(idU, idV); }\n        int key = u*(m+1) + v;\n        mp[key].emplace_back(idU, idV);\n    };\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j+1 < n; ++j) {\n            int idA = i*n + j, idB = i*n + j + 1;\n            int a = origGrid[idA], b = origGrid[idB];\n            if (a != b) add_pair_edge(pairEdgesOrig, a, b, idA, idB);\n        }\n    for (int i = 0; i+1 < n; ++i)\n        for (int j = 0; j < n; ++j) {\n            int idA = i*n + j, idB = (i+1)*n + j;\n            int a = origGrid[idA], b = origGrid[idB];\n            if (a != b) add_pair_edge(pairEdgesOrig, a, b, idA, idB);\n        }\n\n    auto borderSides = [&](int id)->int {\n        int i = id / n, j = id % n;\n        return (i == 0) + (i == n-1) + (j == 0) + (j == n-1);\n    };\n\n    Timer timer;\n    const double TIME_LIMIT = 1.95;\n    std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    auto build_pair_edges_from_grid = [&](const vector<int> &grid) {\n        unordered_map<int, vector<pair<int,int>>> mp;\n        mp.reserve(4000);\n        for (int i = 0; i < n; ++i)\n            for (int j = 0; j+1 < n; ++j) {\n                int idA = i*n + j, idB = i*n + j + 1;\n                int a = grid[idA], b = grid[idB];\n                if (a != b) add_pair_edge(mp, a, b, idA, idB);\n            }\n        for (int i = 0; i+1 < n; ++i)\n            for (int j = 0; j < n; ++j) {\n                int idA = i*n + j, idB = (i+1)*n + j;\n                int a = grid[idA], b = grid[idB];\n                if (a != b) add_pair_edge(mp, a, b, idA, idB);\n            }\n        return mp;\n    };\n\n    auto run_once = [&](int runType, double time_budget)->pair<int, vector<int>> {\n        vector<int> grid = origGrid;\n        vector<int> sizeCount(m+1, 0);\n        for (int id = 0; id < N; ++id) sizeCount[grid[id]]++;\n        vector<int> degSame = degSame0;\n\n        // Non-zero pair counts\n        vector<vector<int>> pairCount(m+1, vector<int>(m+1, 0));\n        auto add_pair_cnt = [&](int a, int b, int delta){\n            if (a == 0 || b == 0 || a == b) return;\n            if (a > b) swap(a, b);\n            pairCount[a][b] += delta;\n        };\n        for (int i = 0; i < n; ++i)\n            for (int j = 0; j+1 < n; ++j) {\n                int a = grid[i*n + j], b = grid[i*n + j + 1];\n                if (a != b) add_pair_cnt(a, b, +1);\n            }\n        for (int i = 0; i+1 < n; ++i)\n            for (int j = 0; j < n; ++j) {\n                int a = grid[i*n + j], b = grid[(i+1)*n + j];\n                if (a != b) add_pair_cnt(a, b, +1);\n            }\n\n        // Adjacency to 0 edge counts\n        vector<int> adj0Count(m+1, 0);\n        for (int j = 0; j < n; ++j) {\n            int t = grid[0*n + j]; if (t) adj0Count[t]++;\n            int b = grid[(n-1)*n + j]; if (b) adj0Count[b]++;\n        }\n        for (int i = 0; i < n; ++i) {\n            int l = grid[i*n + 0]; if (l) adj0Count[l]++;\n            int r = grid[i*n + (n-1)]; if (r) adj0Count[r]++;\n        }\n        // internal 0 edges (initially none, but keep generic)\n        for (int i = 0; i < n; ++i)\n            for (int j = 0; j+1 < n; ++j) {\n                int a = grid[i*n + j], b = grid[i*n + j + 1];\n                if (a == 0 && b != 0) adj0Count[b]++;\n                if (a != 0 && b == 0) adj0Count[a]++;\n            }\n        for (int i = 0; i+1 < n; ++i)\n            for (int j = 0; j < n; ++j) {\n                int a = grid[i*n + j], b = grid[(i+1)*n + j];\n                if (a == 0 && b != 0) adj0Count[b]++;\n                if (a != 0 && b == 0) adj0Count[a]++;\n            }\n\n        // Anchors: choose endpoints for each pair (u, v)\n        vector<char> protectAnchor(N, 0);\n        auto choose_anchors = [&](const unordered_map<int, vector<pair<int,int>>> &pairEdges, int heuristicType) {\n            fill(protectAnchor.begin(), protectAnchor.end(), 0);\n            for (auto &kv : pairEdges) {\n                auto &vec = kv.second;\n                if (vec.empty()) continue;\n                int bestIdx = 0, bestCost = INT_MAX;\n                for (int idx = 0; idx < (int)vec.size(); ++idx) {\n                    int idU = vec[idx].first;\n                    int idV = vec[idx].second;\n                    int cost = 0;\n                    // Prefer endpoints adjacent to interior (effectively unremovable)\n                    if (!(adjToIC[idU] || adjToIC[idV])) cost += 5;\n                    // Prefer lower same-color degrees\n                    cost += (degSame0[idU] > 2) + (degSame0[idV] > 2);\n                    // Prefer border edges slightly\n                    if (!(isBoundaryPos[idU] || isBoundaryPos[idV])) cost += 1;\n                    // Heuristic variants\n                    if (heuristicType == 2) {\n                        cost += (isBoundaryPos[idU] ? 0 : 1) + (isBoundaryPos[idV] ? 0 : 1);\n                    } else if (heuristicType == 3) {\n                        cost += (degSame0[idU] + degSame0[idV] > 4) ? 2 : 0;\n                    } else if (heuristicType == 4) {\n                        // Stronger bias to small local degree\n                        cost += (degSame[idU] + degSame[idV]) * 2;\n                    }\n                    // Random jitter\n                    cost = cost * 8 + (int)(rng() & 7);\n                    if (cost < bestCost) { bestCost = cost; bestIdx = idx; }\n                }\n                int idU = vec[bestIdx].first;\n                int idV = vec[bestIdx].second;\n                protectAnchor[idU] = 1;\n                protectAnchor[idV] = 1;\n            }\n        };\n\n        if (runType >= 1 && runType <= 3) {\n            choose_anchors(pairEdgesOrig, runType);\n        }\n\n        auto hasZeroNeighbor = [&](int id)->bool {\n            int i = id / n, j = id % n;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                if (grid[ni*n + nj] == 0) return true;\n            }\n            return false;\n        };\n        auto is_accessible = [&](int id)->bool {\n            return isBoundaryPos[id] || hasZeroNeighbor(id);\n        };\n\n        // Articulation test: same-color neighbors remain connected after removing id\n        vector<int> seen(N, 0);\n        int stamp = 1;\n        auto neighbors_connected_after_remove = [&](int id, int color)->bool {\n            int i = id / n, j = id % n;\n            int sameNei[4], sn = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int nid = ni*n + nj;\n                if (grid[nid] == color) sameNei[sn++] = nid;\n            }\n            if (sn <= 1) return true;\n            stamp++;\n            deque<int> dq;\n            dq.push_back(sameNei[0]);\n            seen[sameNei[0]] = stamp;\n            int targetsLeft = sn - 1;\n            while (!dq.empty()) {\n                int u = dq.front(); dq.pop_front();\n                int ui = u / n, uj = u % n;\n                for (int k = 0; k < 4; ++k) {\n                    int vi = ui + dr[k], vj = uj + dc[k];\n                    if (!inb(vi, vj)) continue;\n                    int v = vi*n + vj;\n                    if (v == id) continue;\n                    if (grid[v] != color) continue;\n                    if (seen[v] == stamp) continue;\n                    seen[v] = stamp;\n                    for (int t = 1; t < sn; ++t) {\n                        if (v == sameNei[t]) { targetsLeft--; break; }\n                    }\n                    if (targetsLeft == 0) return true;\n                    dq.push_back(v);\n                }\n            }\n            return false;\n        };\n\n        // Core removal check (ignores anchor locking)\n        auto can_remove_core = [&](int id)->bool {\n            int c = grid[id];\n            if (c == 0) return false;\n            if (!isBC[c]) return false; // never touch interior colors\n            if (!is_accessible(id)) return false;\n            if (sizeCount[c] <= 1) return false;\n\n            // Do not create adjacency 0\u2013interior\n            int i = id / n, j = id % n;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d != 0 && isIC[d]) return false;\n            }\n\n            // Preserve non-zero adjacencies: don't remove last c\u2013d contact\n            int neighCols[4], counts[4], cnt = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d == 0 || d == c) continue;\n                bool found = false;\n                for (int t = 0; t < cnt; ++t) {\n                    if (neighCols[t] == d) { counts[t]++; found = true; break; }\n                }\n                if (!found) { neighCols[cnt] = d; counts[cnt] = 1; cnt++; }\n            }\n            for (int t = 0; t < cnt; ++t) {\n                int d = neighCols[t];\n                int a = c, b = d; if (a > b) swap(a, b);\n                if (pairCount[a][b] <= counts[t]) return false;\n            }\n\n            // Preserve adjacency to 0\n            int sameN = 0, zeroN = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d == c) sameN++;\n                else if (d == 0) zeroN++;\n            }\n            int bSides = borderSides(id);\n            int delta0 = sameN - zeroN - bSides;\n            if (adj0Count[c] + delta0 <= 0) return false;\n\n            // Connectivity: avoid articulation points\n            if (degSame[id] > 1) {\n                if (!neighbors_connected_after_remove(id, c)) return false;\n            }\n            return true;\n        };\n\n        auto can_remove = [&](int id)->bool {\n            if (protectAnchor[id]) return false;\n            return can_remove_core(id);\n        };\n        auto can_remove_allow_anchor = [&](int id)->bool {\n            return can_remove_core(id);\n        };\n\n        auto remove_cell = [&](int id) {\n            int c = grid[id];\n            int i = id / n, j = id % n;\n            // Update pair counts\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d != 0 && d != c) {\n                    int a = c, b = d; if (a > b) swap(a, b);\n                    if (pairCount[a][b] > 0) pairCount[a][b]--;\n                }\n            }\n            // Update degSame and adj0Count\n            int sameN = 0, zeroN = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int nid = ni*n + nj;\n                int d = grid[nid];\n                if (d == c) { degSame[nid]--; sameN++; }\n                else if (d == 0) zeroN++;\n            }\n            int bSides = borderSides(id);\n            adj0Count[c] += (sameN - zeroN - bSides);\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d != 0 && d != c) adj0Count[d]++;\n            }\n\n            sizeCount[c]--;\n            grid[id] = 0;\n            degSame[id] = 0;\n            if (protectAnchor[id]) protectAnchor[id] = 0;\n        };\n\n        auto hasZeroNeighbor_cached = [&](int id)->bool {\n            int i = id / n, j = id % n;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                if (grid[ni*n + nj] == 0) return true;\n            }\n            return false;\n        };\n\n        // Candidate priority\n        auto candidate_priority = [&](int id)->int {\n            int c = grid[id];\n            int i = id / n, j = id % n;\n            int neighCols[4], counts[4], cnt = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d == 0 || d == c) continue;\n                bool found = false;\n                for (int t = 0; t < cnt; ++t) {\n                    if (neighCols[t] == d) { counts[t]++; found = true; break; }\n                }\n                if (!found) { neighCols[cnt] = d; counts[cnt] = 1; cnt++; }\n            }\n            int slackMin = 1000000, slackSum = 0;\n            for (int t = 0; t < cnt; ++t) {\n                int d = neighCols[t];\n                int a = c, b = d; if (a > b) swap(a, b);\n                int slack = pairCount[a][b] - counts[t];\n                slackMin = min(slackMin, slack);\n                slackSum += slack;\n            }\n            if (cnt == 0) slackMin = 1000, slackSum = 1000;\n            // delta0 estimate\n            int sameN = 0, zeroN = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d == c) sameN++;\n                else if (d == 0) zeroN++;\n            }\n            int bSides = borderSides(id);\n            int delta0 = sameN - zeroN - bSides;\n\n            int score = 0;\n            score += degSame[id] * 8; // lower deg preferred\n            score += (slackMin >= 3 ? 0 : (slackMin == 2 ? 6 : 12));\n            score += max(0, 6 - min(slackSum, 6)); // prefer larger total slack\n            if (adj0Count[c] > 2 && delta0 < 0) score -= 2; // reduce extra 0-edges\n            if (adjToIC[id]) score += 60; // deprioritize guards (we won't remove)\n            score += (hasZeroNeighbor_cached(id) ? 0 : 3);\n            return score;\n        };\n\n        deque<int> Q;\n        vector<char> inQ(N, 0);\n        vector<int> boundaryIds;\n        boundaryIds.reserve(N);\n        for (int id = 0; id < N; ++id) if (isBoundaryPos[id]) boundaryIds.push_back(id);\n        if (runType == 3) {\n            shuffle(boundaryIds.begin(), boundaryIds.end(), rng);\n        }\n\n        auto push_cand = [&](int id) {\n            if (inQ[id]) return;\n            if (grid[id] == 0) return;\n            int c = grid[id];\n            if (!isBC[c]) return;\n            if (!isBoundaryPos[id] && !hasZeroNeighbor_cached(id)) return;\n            int pr = candidate_priority(id);\n            if (pr <= 12) Q.push_front(id);\n            else Q.push_back(id);\n            inQ[id] = 1;\n        };\n\n        // Seed candidates\n        for (int id : boundaryIds) {\n            int c = grid[id];\n            if (c == 0 || !isBC[c]) continue;\n            push_cand(id);\n        }\n\n        double start_t = timer.elapsed();\n        double budget_main = time_budget * 0.78;\n        double budget_cleanup = time_budget * 0.22;\n\n        // Optional pre-thinning for runType 4/5 (no anchors initially)\n        if (runType == 4 || runType == 5) {\n            double pre_budget = budget_main * 0.45;\n            double pre_start = timer.elapsed();\n            while (!Q.empty() && timer.elapsed() - pre_start < pre_budget) {\n                int id = Q.front(); Q.pop_front();\n                inQ[id] = 0;\n                if (grid[id] == 0) continue;\n                if (!is_accessible(id)) continue;\n                if (can_remove_core(id)) {\n                    int i = id / n, j = id % n;\n                    remove_cell(id);\n                    for (int k = 0; k < 4; ++k) {\n                        int ni = i + dr[k], nj = j + dc[k];\n                        if (!inb(ni, nj)) continue;\n                        int nid = ni*n + nj;\n                        if (grid[nid] != 0) push_cand(nid);\n                    }\n                } else {\n                    if (timer.elapsed() - pre_start < pre_budget * 0.95) {\n                        Q.push_back(id);\n                        inQ[id] = 1;\n                    }\n                }\n            }\n            // Recompute anchors on current grid\n            auto pairEdgesNow = build_pair_edges_from_grid(grid);\n            choose_anchors(pairEdgesNow, 4);\n        }\n\n        // Main carving\n        while (!Q.empty() && timer.elapsed() - start_t < budget_main) {\n            int id = Q.front(); Q.pop_front();\n            inQ[id] = 0;\n            if (grid[id] == 0) continue;\n            if (!is_accessible(id)) continue;\n            if (protectAnchor[id]) continue;\n            if (can_remove(id)) {\n                int i = id / n, j = id % n;\n                remove_cell(id);\n                for (int k = 0; k < 4; ++k) {\n                    int ni = i + dr[k], nj = j + dc[k];\n                    if (!inb(ni, nj)) continue;\n                    int nid = ni*n + nj;\n                    if (grid[nid] != 0) push_cand(nid);\n                }\n            } else {\n                if (timer.elapsed() - start_t < budget_main * 0.95) {\n                    Q.push_back(id);\n                    inQ[id] = 1;\n                }\n            }\n        }\n\n        // Cleanup: allow anchors to be removed too, if safe\n        if (budget_cleanup > 0 && timer.elapsed() - start_t < time_budget) {\n            bool improved = true;\n            int rounds = 0;\n            while (improved && timer.elapsed() - start_t < time_budget) {\n                improved = false;\n                rounds++;\n                for (int id = 0; id < N; ++id) {\n                    if (timer.elapsed() - start_t > time_budget) break;\n                    if (grid[id] == 0) continue;\n                    int c = grid[id];\n                    if (!isBC[c]) continue;\n                    if (!is_accessible(id)) continue;\n                    if (rounds <= 2 && !protectAnchor[id]) continue; // target anchors first\n                    if (can_remove_allow_anchor(id)) {\n                        int i = id / n, j = id % n;\n                        remove_cell(id);\n                        improved = true;\n                        for (int k = 0; k < 4; ++k) {\n                            int ni = i + dr[k], nj = j + dc[k];\n                            if (!inb(ni, nj)) continue;\n                            int nid = ni*n + nj;\n                            if (grid[nid] != 0) push_cand(nid);\n                        }\n                    }\n                }\n                int steps = 0;\n                while (!Q.empty() && timer.elapsed() - start_t < time_budget && steps < 800) {\n                    int id = Q.front(); Q.pop_front();\n                    inQ[id] = 0;\n                    if (grid[id] == 0) continue;\n                    if (!is_accessible(id)) continue;\n                    if (can_remove_allow_anchor(id)) {\n                        int i = id / n, j = id % n;\n                        remove_cell(id);\n                        improved = true;\n                        for (int k = 0; k < 4; ++k) {\n                            int ni = i + dr[k], nj = j + dc[k];\n                            if (!inb(ni, nj)) continue;\n                            int nid = ni*n + nj;\n                            if (grid[nid] != 0) push_cand(nid);\n                        }\n                    }\n                    steps++;\n                }\n            }\n        }\n\n        int zeros = 0;\n        for (int id = 0; id < N; ++id) if (grid[id] == 0) zeros++;\n        return {zeros, grid};\n    };\n\n    vector<int> bestGrid = origGrid;\n    int bestZeros = 0;\n\n    // Runs: baseline + two anchored variants + two-phase anchored (two variants) as time allows\n    vector<int> plan = {0, 1, 2, 4, 5};\n    for (int rt : plan) {\n        double remain = TIME_LIMIT - timer.elapsed();\n        if (remain < 0.15) break;\n        double budget;\n        if (rt == 0) budget = min(0.75, max(0.28, remain * 0.36));\n        else if (rt == 4 || rt == 5) budget = min(0.70, max(0.18, remain * 0.50));\n        else budget = min(0.60, max(0.17, remain * 0.42));\n        auto [zeros, grid] = run_once(rt, budget);\n        if (zeros > bestZeros) { bestZeros = zeros; bestGrid = move(grid); }\n    }\n\n    // Output best grid\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            if (j) cout << ' ';\n            cout << bestGrid[i*n + j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, D, Q;\n    if (!(cin >> N >> D >> Q)) return 0;\n\n    // RNG (deterministic per N,D,Q)\n    uint64_t seed = 1469598103934665603ull;\n    auto mix = [&](uint64_t x){ seed ^= x + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2); };\n    mix((uint64_t)N); mix((uint64_t)D); mix((uint64_t)Q);\n    mt19937_64 rng(seed);\n    uniform_real_distribution<double> ur01(0.0, 1.0);\n    uniform_real_distribution<double> urSym(-1.0, 1.0);\n\n    // Correlator estimate for 1-bit sensing\n    vector<int> score(N, 0);\n    vector<double> w_est(N, 1.0); // positive estimate for adaptive queries\n    vector<int> count_pm(N, 0);   // track +1 vs -1 usage per item\n\n    // Store rows for post-phase logistic regression (without intercept)\n    vector<int8_t> Aflat; Aflat.reserve((size_t)Q * N);\n    vector<int8_t> Y;     Y.reserve(Q);\n\n    vector<int> a(N, 0);\n    string resp;\n\n    auto output_query = [&](const vector<int>& a_out){\n        int nL = 0, nR = 0;\n        for (int i = 0; i < N; i++) {\n            if (a_out[i] == +1) nL++; else nR++;\n        }\n        cout << nL << ' ' << nR;\n        for (int i = 0; i < N; i++) if (a_out[i] == +1) cout << ' ' << i;\n        for (int i = 0; i < N; i++) if (a_out[i] == -1) cout << ' ' << i;\n        cout << \"\\n\" << flush;\n    };\n\n    auto build_balanced_query = [&](const vector<double>& w_cur, vector<int>& a_out){\n        vector<int> perm(N);\n        iota(perm.begin(), perm.end(), 0);\n        shuffle(perm.begin(), perm.end(), rng);\n\n        vector<int> L; L.reserve(N);\n        vector<int> R; R.reserve(N);\n        double sumL = 0.0, sumR = 0.0;\n\n        // Greedy balance predicted sums\n        for (int idx : perm) {\n            double wi = w_cur[idx];\n            if (sumL < sumR) {\n                L.push_back(idx); sumL += wi;\n            } else if (sumR < sumL) {\n                R.push_back(idx); sumR += wi;\n            } else {\n                // sums equal: use side-usage bias, then random\n                if (count_pm[idx] > 0) { R.push_back(idx); sumR += wi; }\n                else if (count_pm[idx] < 0) { L.push_back(idx); sumL += wi; }\n                else {\n                    if (ur01(rng) < 0.5) { L.push_back(idx); sumL += wi; }\n                    else { R.push_back(idx); sumR += wi; }\n                }\n            }\n        }\n        // Ensure both sides non-empty\n        if (L.empty()) { L.push_back(R.back()); sumL += w_cur[R.back()]; sumR -= w_cur[R.back()]; R.pop_back(); }\n        if (R.empty()) { R.push_back(L.back()); sumR += w_cur[L.back()]; sumL -= w_cur[L.back()]; L.pop_back(); }\n\n        // Small random perturbation (swap one random pair) to diversify queries\n        if (ur01(rng) < 0.10 && !L.empty() && !R.empty()) {\n            int il = uniform_int_distribution<int>(0, (int)L.size()-1)(rng);\n            int ir = uniform_int_distribution<int>(0, (int)R.size()-1)(rng);\n            swap(L[il], R[ir]);\n        }\n\n        // Randomly assign which side is +1 (\"left\")\n        bool flip = (ur01(rng) < 0.5);\n        a_out.assign(N, -1);\n        if (!flip) for (int idx : L) a_out[idx] = +1;\n        else for (int idx : R) a_out[idx] = +1;\n\n        // Update usage counts\n        for (int i = 0; i < N; i++) count_pm[i] += (a_out[i] > 0 ? +1 : -1);\n    };\n\n    // Query loop: adaptive balanced from the start\n    for (int q = 0; q < Q; q++) {\n        build_balanced_query(w_est, a);\n        output_query(a);\n\n        if (!(cin >> resp)) return 0;\n        int y = 0;\n        if (resp[0] == '>') y = +1;\n        else if (resp[0] == '<') y = -1;\n        else if (resp[0] == '=') y = 0;\n\n        if (y != 0) {\n            for (int i = 0; i < N; i++) {\n                score[i] += y * a[i];\n            }\n            for (int i = 0; i < N; i++) Aflat.push_back((int8_t)(a[i] > 0 ? 1 : -1));\n            Y.push_back((int8_t)y);\n        }\n\n        // Refresh w_est from correlator (shift to positive)\n        int mn = INT_MAX;\n        for (int i = 0; i < N; i++) mn = min(mn, score[i]);\n        double shift = -(double)mn + 1.0;\n        for (int i = 0; i < N; i++) w_est[i] = max(1e-3, (double)score[i] + shift);\n    }\n\n    // Initial weights from correlator\n    vector<double> w(N, 1.0);\n    {\n        int mn = INT_MAX;\n        for (int i = 0; i < N; i++) mn = min(mn, score[i]);\n        double shift = -(double)mn + 1.0;\n        for (int i = 0; i < N; i++) w[i] = max(1e-6, (double)score[i] + shift);\n    }\n\n    // Post-phase 1-bit logistic regression without intercept\n    int M = (int)Y.size();\n    if (M > 0) {\n        vector<double> x = w; // init from correlator\n        // Normalize to mean ~1 for stability\n        double meanx = 0.0;\n        for (double v : x) meanx += v;\n        meanx = (meanx > 0 ? meanx / N : 1.0);\n        for (double &v : x) v /= meanx;\n\n        double lambda = 1e-3; // L2 regularization\n        double Lg = 0.25 * (double)N * (double)M + 2.0 * lambda; // coarse Lipschitz bound\n        double eta = 1.0 / Lg;\n        int iters = min(220, max(80, M / 4));\n\n        vector<double> grad(N, 0.0);\n        const int8_t* Adata = Aflat.data();\n\n        for (int it = 0; it < iters; it++) {\n            fill(grad.begin(), grad.end(), 0.0);\n            for (int r = 0; r < M; r++) {\n                const int8_t* row = Adata + (size_t)r * N;\n                int8_t yr = Y[r];\n                double s = 0.0;\n                for (int i = 0; i < N; i++) s += (double)row[i] * x[i];\n                // p = - y * sigma(-y s)\n                double ys = (double)yr * s;\n                double p;\n                if (ys >= 0) {\n                    double e = exp(-ys);\n                    p = -(double)yr * (e / (1.0 + e));\n                } else {\n                    double e = exp(ys);\n                    p = -(double)yr * (1.0 / (1.0 + e));\n                }\n                for (int i = 0; i < N; i++) grad[i] += p * (double)row[i];\n            }\n            for (int i = 0; i < N; i++) {\n                grad[i] += 2.0 * lambda * x[i];\n                x[i] -= eta * grad[i];\n                if (x[i] < 1e-12) x[i] = 1e-12; // nonnegativity\n            }\n        }\n        w.swap(x);\n    }\n\n    // Multi-start LPT initializations (3 starts with small jitters), pick best by surrogate objective\n    auto build_assignment_by_LPT = [&](const vector<double>& wt) -> vector<int> {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng); // random tie-break\n        stable_sort(ord.begin(), ord.end(), [&](int i, int j){ return wt[i] > wt[j]; });\n        vector<int> assign(N, -1);\n        vector<double> binSum(D, 0.0);\n        for (int idx : ord) {\n            int best = 0;\n            double bestSum = binSum[0];\n            for (int b = 1; b < D; b++) {\n                if (binSum[b] < bestSum) { bestSum = binSum[b]; best = b; }\n            }\n            assign[idx] = best;\n            binSum[best] += w[idx]; // use true estimated weights w for objective\n        }\n        return assign;\n    };\n    auto objective_sqsum = [&](const vector<int>& assign)->double{\n        vector<double> s(D, 0.0);\n        for (int i = 0; i < N; i++) s[assign[i]] += w[i];\n        double v = 0.0;\n        for (int b = 0; b < D; b++) v += s[b] * s[b];\n        return v;\n    };\n\n    vector<int> best_assign;\n    double best_obj = 1e300;\n\n    // Start 0: plain w\n    {\n        vector<double> wt = w;\n        auto assign0 = build_assignment_by_LPT(wt);\n        double obj0 = objective_sqsum(assign0);\n        if (obj0 < best_obj) { best_obj = obj0; best_assign.swap(assign0); }\n    }\n    // Start 1: small jitter\n    {\n        vector<double> wt = w;\n        for (int i = 0; i < N; i++) wt[i] *= (1.0 + 0.05 * urSym(rng));\n        auto assign1 = build_assignment_by_LPT(wt);\n        double obj1 = objective_sqsum(assign1);\n        if (obj1 < best_obj) { best_obj = obj1; best_assign.swap(assign1); }\n    }\n    // Start 2: slightly larger jitter\n    {\n        vector<double> wt = w;\n        for (int i = 0; i < N; i++) wt[i] *= (1.0 + 0.10 * urSym(rng));\n        auto assign2 = build_assignment_by_LPT(wt);\n        double obj2 = objective_sqsum(assign2);\n        if (obj2 < best_obj) { best_obj = obj2; best_assign.swap(assign2); }\n    }\n\n    // Build bins from best assignment\n    vector<vector<int>> bins(D);\n    vector<double> binSum(D, 0.0);\n    vector<int> posInBin(N, -1);\n    auto addToBin = [&](int b, int id){\n        posInBin[id] = (int)bins[b].size();\n        bins[b].push_back(id);\n        binSum[b] += w[id];\n    };\n    auto removeFromBin = [&](int b, int id){\n        int pos = posInBin[id];\n        int last = bins[b].back();\n        bins[b][pos] = last;\n        posInBin[last] = pos;\n        bins[b].pop_back();\n        posInBin[id] = -1;\n        binSum[b] -= w[id];\n    };\n    auto moveItem = [&](int from, int to, int id){\n        removeFromBin(from, id);\n        addToBin(to, id);\n    };\n    auto swapItems = [&](int b1, int b2, int id1, int id2){\n        removeFromBin(b1, id1);\n        removeFromBin(b2, id2);\n        addToBin(b1, id2);\n        addToBin(b2, id1);\n    };\n\n    for (int i = 0; i < N; i++) addToBin(best_assign[i], i);\n    vector<int> assign = best_assign;\n\n    // Local search: single moves to lightest and exhaustive pair swaps across heavier\u2013lighter pairs\n    Timer timer;\n    const double TIME_BUDGET = 0.35; // seconds\n\n    auto extremes = [&](){\n        int l = 0, h = 0;\n        for (int b = 1; b < D; b++) {\n            if (binSum[b] < binSum[l]) l = b;\n            if (binSum[b] > binSum[h]) h = b;\n        }\n        return pair<int,int>(l,h);\n    };\n\n    while (timer.elapsed() < TIME_BUDGET) {\n        auto [lbin, hbin] = extremes();\n\n        // 1) Single move from any bin to lightest bin\n        double best_delta = 0.0;\n        int mv_from = -1, mv_id = -1;\n        for (int b = 0; b < D; b++) {\n            if (b == lbin) continue;\n            double gap = binSum[b] - binSum[lbin];\n            if (gap <= 1e-12) continue;\n            double target = 0.5 * gap;\n            for (int id : bins[b]) {\n                double wi = w[id];\n                if (wi < gap) {\n                    double delta = -2.0 * wi * gap + 2.0 * wi * wi; // change in s_b^2 + s_l^2\n                    if (mv_from == -1 || delta < best_delta - 1e-15 ||\n                        (fabs(delta - best_delta) <= 1e-15 && fabs(wi - target) < fabs(w[mv_id] - target))) {\n                        best_delta = delta;\n                        mv_from = b;\n                        mv_id = id;\n                    }\n                }\n            }\n        }\n        if (mv_from != -1 && best_delta < -1e-12) {\n            moveItem(mv_from, lbin, mv_id);\n            assign[mv_id] = lbin;\n            continue;\n        }\n\n        // 2) Pair swap across all heavier-lighter bin pairs\n        double best_swap_delta = 0.0;\n        int sw_bh = -1, sw_bl = -1, sw_i = -1, sw_j = -1;\n        for (int bh = 0; bh < D; bh++) {\n            for (int bl = 0; bl < D; bl++) {\n                if (binSum[bh] <= binSum[bl] + 1e-12) continue;\n                double gap = binSum[bh] - binSum[bl];\n                double target = 0.5 * gap;\n                for (int i_id : bins[bh]) {\n                    double wi = w[i_id];\n                    for (int j_id : bins[bl]) {\n                        double wj = w[j_id];\n                        double d = wi - wj;\n                        if (d <= 1e-12 || d >= gap - 1e-12) continue;\n                        double delta = 2.0 * (d * d - d * gap); // change in s_h^2 + s_l^2\n                        if (sw_bh == -1 || delta < best_swap_delta - 1e-15 ||\n                            (fabs(delta - best_swap_delta) <= 1e-15 && fabs(d - target) < fabs((w[sw_i] - w[sw_j]) - target))) {\n                            best_swap_delta = delta;\n                            sw_bh = bh; sw_bl = bl; sw_i = i_id; sw_j = j_id;\n                        }\n                    }\n                }\n            }\n        }\n        if (sw_bh != -1 && best_swap_delta < -1e-12) {\n            swapItems(sw_bh, sw_bl, sw_i, sw_j);\n            assign[sw_i] = sw_bl;\n            assign[sw_j] = sw_bh;\n            continue;\n        }\n\n        // No improving move found\n        break;\n    }\n\n    // Output final assignment\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << assign[i];\n    }\n    cout << '\\n' << flush;\n\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Heuristic solver with destination scoring by min-below and improved, safe splitting.\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    if (!(cin >> n >> m)) return 0;\n    vector<vector<int>> st(m); // bottom -> top\n    int per = n / m;\n    for (int i = 0; i < m; ++i) {\n        st[i].resize(per);\n        for (int j = 0; j < per; ++j) cin >> st[i][j];\n    }\n\n    const int INF = n + 1;\n    vector<pair<int,int>> ops;\n    ops.reserve(3000);\n\n    auto get_min_stack = [&](int idx)->int{\n        if (st[idx].empty()) return INF;\n        int mn = st[idx][0];\n        for (int v : st[idx]) if (v < mn) mn = v;\n        return mn;\n    };\n\n    auto carry_chain = [&](int &t) {\n        bool changed = true;\n        while (changed && t <= n) {\n            changed = false;\n            for (int i = 0; i < m && t <= n; ++i) {\n                if (!st[i].empty() && st[i].back() == t) {\n                    st[i].pop_back();\n                    ops.emplace_back(t, 0);\n                    ++t;\n                    changed = true;\n                }\n            }\n        }\n    };\n\n    auto move_suffix = [&](int src, int start_idx, int dest) {\n        // Move st[src][start_idx..end] to top of st[dest]\n        int S = (int)st[src].size();\n        if (!(0 <= start_idx && start_idx < S)) return; // safety\n        for (int k = start_idx; k < S; ++k) {\n            st[dest].push_back(st[src][k]);\n        }\n        st[src].resize(start_idx);\n    };\n\n    auto find_box = [&](int v, int &src, int &idx) {\n        src = -1; idx = -1;\n        for (int i = 0; i < m; ++i) {\n            for (int j = (int)st[i].size() - 1; j >= 0; --j) {\n                if (st[i][j] == v) { src = i; idx = j; return; }\n            }\n        }\n    };\n\n    auto choose_dest_minPrefix = [&](int src, int jv, int exclude1=-1, int exclude2=-1) -> int {\n        // Score candidates by how many from the block top are < min(old dest content).\n        int s = (int)st[src].size() - jv;\n        vector<int> topDown;\n        topDown.reserve(s);\n        for (int k = (int)st[src].size() - 1; k >= jv; --k) topDown.push_back(st[src][k]);\n\n        int bestD = -1;\n        int bestPrefix = -1;\n        int bestM = -1;\n        int bestTop = -1;\n        int bestNegSize = 0; // prefer smaller size\n        for (int d = 0; d < m; ++d) {\n            if (d == src || d == exclude1 || d == exclude2) continue;\n            int M = get_min_stack(d);\n            int prefix = 0;\n            while (prefix < s && topDown[prefix] < M) ++prefix; // strictly less than M\n\n            int topVal = st[d].empty() ? INF : st[d].back();\n            int negSize = - (int)st[d].size();\n\n            // tie-breakers: larger prefix, then larger M, then larger topVal, then smaller size\n            if (prefix > bestPrefix ||\n                (prefix == bestPrefix && (M > bestM ||\n                 (M == bestM && (topVal > bestTop ||\n                  (topVal == bestTop && negSize > bestNegSize)))))) {\n                bestPrefix = prefix;\n                bestM = M;\n                bestTop = topVal;\n                bestNegSize = negSize;\n                bestD = d;\n            }\n        }\n        if (bestD == -1) {\n            // fallback respecting excludes\n            for (int d = 0; d < m; ++d) {\n                if (d != src && d != exclude1 && d != exclude2) { bestD = d; break; }\n            }\n        }\n        return bestD;\n    };\n\n    auto choose_heavy_dest = [&](int src, int avoid)->int{\n        // For the heavy segment, prefer destination with large min (M) and large top.\n        int bestD = -1;\n        int bestM = -1;\n        int bestTop = -1;\n        int bestNegSize = 0;\n        for (int d = 0; d < m; ++d) {\n            if (d == src || d == avoid) continue;\n            int M = get_min_stack(d);\n            int topVal = st[d].empty() ? INF : st[d].back();\n            int negSize = - (int)st[d].size();\n            if (M > bestM || (M == bestM && (topVal > bestTop ||\n                 (topVal == bestTop && negSize > bestNegSize)))) {\n                bestM = M;\n                bestTop = topVal;\n                bestNegSize = negSize;\n                bestD = d;\n            }\n        }\n        if (bestD == -1) {\n            for (int d = 0; d < m; ++d) {\n                if (d != src && d != avoid) { bestD = d; break; }\n            }\n        }\n        return bestD;\n    };\n\n    auto attempt_split_then_move = [&](int src, int idx) -> bool {\n        // Try to split the above-block to create a good prefix >= 2 for the remainder on a good destination.\n        int jv = idx + 1;\n        int s = (int)st[src].size() - jv;\n        if (s <= 1) return false;\n\n        // Block top-down\n        vector<int> topDown;\n        topDown.reserve(s);\n        for (int k = (int)st[src].size() - 1; k >= jv; --k) topDown.push_back(st[src][k]);\n\n        // Choose best destination for the remainder\n        int destBest = choose_dest_minPrefix(src, jv);\n        if (destBest == -1) return false;\n        int Mbest = get_min_stack(destBest);\n\n        // Compute overall best-prefix for this dest; if already good (>=2), no need to split\n        int bestPrefix = 0;\n        while (bestPrefix < s && topDown[bestPrefix] < Mbest) ++bestPrefix;\n        if (bestPrefix >= 2) return false;\n\n        // Compute split point r: number of top elements >= Mbest\n        int r = 0;\n        while (r < s && topDown[r] >= Mbest) ++r;\n        if (r >= s) return false; // no \"good\" part\n        // Count consecutive \"good\" elements after r\n        int p = 0;\n        while (r + p < s && topDown[r + p] < Mbest) ++p;\n\n        // Require at least 2 good elements to justify an extra move AND r > 0 to move a non-empty heavy segment\n        if (p < 2 || r == 0) return false;\n\n        // Choose destination for the heavy top segment\n        int heavyDest = choose_heavy_dest(src, destBest);\n        if (heavyDest == -1) return false;\n\n        // First move: heavy top segment of size r to heavyDest\n        int startA = (int)st[src].size() - r; // start index of top r segment\n        if (!(0 <= startA && startA < (int)st[src].size())) return false; // safety\n        int vA = st[src][startA];\n        move_suffix(src, startA, heavyDest);\n        ops.emplace_back(vA, heavyDest + 1);\n\n        // Second move: remainder above t to a good destination (avoid heavyDest)\n        int new_jv = idx + 1;\n        if (!(0 <= new_jv && new_jv < (int)st[src].size())) {\n            // If nothing remains above t, no second move is needed\n            return true;\n        }\n        int dest2 = choose_dest_minPrefix(src, new_jv, heavyDest, -1);\n        if (dest2 == -1) {\n            // As a last resort, put it back onto best dest\n            dest2 = destBest;\n        }\n        int vB = st[src][new_jv];\n        move_suffix(src, new_jv, dest2);\n        ops.emplace_back(vB, dest2 + 1);\n\n        return true;\n    };\n\n    int t = 1;\n    carry_chain(t);\n\n    while (t <= n) {\n        int src, idx;\n        find_box(t, src, idx);\n        if (src == -1) break; // shouldn't happen\n\n        if (idx == (int)st[src].size() - 1) {\n            // Already top\n            st[src].pop_back();\n            ops.emplace_back(t, 0);\n            ++t;\n            carry_chain(t);\n            continue;\n        }\n\n        // Try improved, safe split\n        if (attempt_split_then_move(src, idx)) {\n            carry_chain(t);\n            continue;\n        }\n\n        // Normal: move whole suffix with destination chosen by min-prefix\n        int jv = idx + 1;\n        int dest = choose_dest_minPrefix(src, jv);\n        if (dest == -1) {\n            // Fallback: choose any stack != src\n            for (int d = 0; d < m; ++d) if (d != src) { dest = d; break; }\n        }\n        int v = st[src][jv];\n        move_suffix(src, jv, dest);\n        ops.emplace_back(v, dest + 1);\n\n        carry_chain(t);\n    }\n\n    if ((int)ops.size() > 5000) {\n        // Should not happen\n        ops.resize(5000);\n    }\n    for (auto &op : ops) {\n        cout << op.first << ' ' << op.second << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    unsigned long long x;\n    XorShift64(unsigned long long seed=88172645463393265ULL){x=seed;}\n    unsigned long long next() { x ^= x<<7; x ^= x>>9; return x; }\n    unsigned int nextUInt() { return (unsigned int)(next() & 0xFFFFFFFFULL); }\n};\n\nstruct UEdge {\n    int u, v;\n    char ch_uv, ch_vu;\n};\n\nstruct AdjPort {\n    int to;\n    int eid;\n    char ch;\n    long long target; // desired departures from this node along this edge\n    long long used;   // used departures\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    using ld = long double;\n    auto T0 = chrono::high_resolution_clock::now();\n    auto elapsed_ms = [&](){\n        return (double)chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - T0).count();\n    };\n\n    int N;\n    if (!(cin >> N)) return 0;\n\n    vector<string> hWall(max(0, N-1));\n    for (int i = 0; i < N-1; i++) cin >> hWall[i];\n    vector<string> vWall(N);\n    for (int i = 0; i < N; i++) cin >> vWall[i];\n\n    vector<vector<int>> d(N, vector<int>(N));\n    long long Dsum_ll = 0;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) { cin >> d[i][j]; Dsum_ll += d[i][j]; }\n    ld Dsum = (ld)Dsum_ll;\n\n    auto inb = [&](int i, int j) -> bool { return (0 <= i && i < N && 0 <= j && j < N); };\n    auto canMove = [&](int i, int j, int di, int dj) -> bool {\n        int ni = i + di, nj = j + dj;\n        if (!inb(ni, nj)) return false;\n        if (di == 0 && dj == 1) { // right\n            return vWall[i][j] == '0';\n        } else if (di == 0 && dj == -1) { // left\n            return vWall[i][j-1] == '0';\n        } else if (di == 1 && dj == 0) { // down\n            return hWall[i][j] == '0';\n        } else if (di == -1 && dj == 0) { // up\n            return hWall[i-1][j] == '0';\n        }\n        return false;\n    };\n    auto id = [&](int i, int j) { return i * N + j; };\n    auto coord = [&](int v) { return pair<int,int>(v / N, v % N); };\n\n    int V = N * N;\n    int root = 0;\n\n    // Build undirected grid edges\n    vector<UEdge> edges; edges.reserve(2*N*(N-1));\n    vector<vector<pair<int,int>>> nodeNbrEid(V);\n    auto add_edge = [&](int u, int v, char ch_uv, char ch_vu){\n        UEdge e{u,v,ch_uv,ch_vu};\n        int eid = (int)edges.size();\n        edges.push_back(e);\n        nodeNbrEid[u].push_back({v, eid});\n        nodeNbrEid[v].push_back({u, eid});\n    };\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int u = id(i,j);\n        if (j+1 < N && canMove(i,j,0,1)) {\n            int v = id(i, j+1);\n            add_edge(u, v, 'R', 'L');\n        }\n        if (i+1 < N && canMove(i,j,1,0)) {\n            int v = id(i+1, j);\n            add_edge(u, v, 'D', 'U');\n        }\n    }\n    int M = (int)edges.size();\n\n    // Build adjacency for BFS\n    vector<vector<int>> adjGrid(V);\n    for (int u = 0; u < V; u++) {\n        for (auto [v, eid] : nodeNbrEid[u]) adjGrid[u].push_back(v);\n    }\n\n    // BFS distances\n    vector<int> dist(V, -1);\n    deque<int> dq;\n    dist[root] = 0; dq.push_back(root);\n    while (!dq.empty()) {\n        int u = dq.front(); dq.pop_front();\n        for (int v : adjGrid[u]) if (dist[v] == -1) { dist[v] = dist[u] + 1; dq.push_back(v); }\n    }\n    int maxDist = 0;\n    for (int v = 0; v < V; v++) if (dist[v] > maxDist) maxDist = dist[v];\n\n    // Candidate parents: neighbors with dist-1\n    vector<vector<int>> candPar(V);\n    for (int v = 0; v < V; v++) {\n        if (v == root) continue;\n        for (int u : adjGrid[v]) if (dist[u] == dist[v] - 1) candPar[v].push_back(u);\n    }\n    vector<vector<int>> layers(maxDist + 1);\n    for (int v = 0; v < V; v++) layers[dist[v]].push_back(v);\n\n    // Balanced shortest-path tree builder for given weights\n    auto build_par_balanced = [&](const vector<ld>& w) -> vector<int> {\n        vector<int> par(V, -1);\n        vector<int> rootBranch(V, -1);\n        vector<ld> load(V, 0.0L);\n        vector<ld> branchLoad(V, 0.0L);\n        vector<int> childCnt(V, 0);\n\n        // layer 1\n        for (int v : layers[1]) {\n            par[v] = root;\n            rootBranch[v] = v;\n            load[root] += w[v];\n            branchLoad[v] += w[v];\n            childCnt[root]++;\n        }\n        // layers >= 2\n        for (int L = 2; L <= maxDist; L++) {\n            for (int v : layers[L]) {\n                ld best1 = 1e300L, best2 = 1e300L;\n                int best3 = INT_MAX, bestP = candPar[v][0];\n                for (int p : candPar[v]) {\n                    int b = rootBranch[p];\n                    ld key1 = branchLoad[b];\n                    ld key2 = load[p];\n                    int key3 = childCnt[p];\n                    if (key1 < best1 - 1e-18L ||\n                       (fabsl(key1 - best1) <= 1e-18L &&\n                       (key2 < best2 - 1e-18L ||\n                       (fabsl(key2 - best2) <= 1e-18L &&\n                       (key3 < best3 || (key3 == best3 && p < bestP)))))) {\n                        best1 = key1; best2 = key2; best3 = key3; bestP = p;\n                    }\n                }\n                int p = bestP;\n                par[v] = p;\n                int b = rootBranch[p];\n                rootBranch[v] = b;\n                int u = p;\n                while (u != -1) {\n                    load[u] += w[v];\n                    u = par[u];\n                }\n                branchLoad[b] += w[v];\n                childCnt[p]++;\n            }\n        }\n        return par;\n    };\n\n    const long long Lmax = 100000;\n\n    // Parameter candidates for base tree selection only: w_i = sqrt(d_i) / (dist_i + gamma)^beta\n    struct Param { ld beta, gamma; };\n    vector<Param> params = {\n        {0.0L, 0.0L}, {0.3L, 0.0L}, {0.5L, 0.0L}, {0.7L, 0.0L},\n        {0.3L, 0.5L}, {0.5L, 0.5L}, {0.7L, 0.5L}, {0.5L, 1.0L}\n    };\n\n    auto find_eid = [&](int a, int b)->int{\n        for (auto [to, eid] : nodeNbrEid[a]) if (to == b) return eid;\n        return -1;\n    };\n\n    // Choose best base tree by proxy on base multiplicity\n    vector<int> best_par;\n    ld best_score = numeric_limits<ld>::infinity();\n    for (auto prm : params) {\n        vector<ld> w(V, 0.0L);\n        for (int v = 0; v < V; v++) {\n            auto [i,j] = coord(v);\n            ld dd = (ld)d[i][j];\n            ld base = sqrtl(max((ld)0.0, dd));\n            ld dep = (ld)dist[v] + prm.gamma;\n            if (v == root) dep = 1.0L + prm.gamma;\n            w[v] = (prm.beta > 0.0L) ? base / powl(max(1e-12L, dep), prm.beta) : base;\n        }\n        vector<int> par = build_par_balanced(w);\n\n        vector<long long> deg0(V, 0);\n        long long L0 = 0;\n        for (int v = 0; v < V; v++) if (v != root) {\n            int p = par[v];\n            int eid = find_eid(v, p);\n            if (eid < 0) continue;\n            deg0[v] += 2;\n            deg0[p] += 2;\n            L0 += 2;\n        }\n        ld Ad0 = 0.0L;\n        for (int v = 0; v < V; v++) {\n            long long kv = max(1LL, deg0[v] / 2);\n            auto [i,j] = coord(v);\n            Ad0 += (ld)d[i][j] / (ld)kv;\n        }\n        ld score = 0.5L * ((ld)L0 * Ad0 - Dsum);\n        if (score < best_score) {\n            best_score = score;\n            best_par = move(par);\n        }\n    }\n    vector<int> par = best_par;\n\n    // Base multiplicity: tree edges doubled\n    vector<long long> m(M, 0), base_m(M, 0);\n    vector<long long> deg(V, 0);\n    long long L = 0;\n    for (int v = 0; v < V; v++) if (v != root) {\n        int p = par[v];\n        int eid = find_eid(v, p);\n        if (eid < 0) continue;\n        m[eid] += 2;\n        base_m[eid] = 2;\n        deg[v] += 2;\n        deg[p] += 2;\n        L += 2;\n    }\n\n    // Initialize k and Ad\n    vector<long long> k(V, 1);\n    ld Ad = 0.0L;\n    for (int v = 0; v < V; v++) {\n        long long kv = max(1LL, deg[v] / 2);\n        k[v] = kv;\n        auto [i,j] = coord(v);\n        Ad += (ld)d[i][j] / (ld)kv;\n    }\n\n    // Precompute arrays and incidence lists\n    vector<int> eu(M), ev(M);\n    vector<char> ch_uv(M), ch_vu(M);\n    for (int eid = 0; eid < M; eid++) {\n        eu[eid] = edges[eid].u; ev[eid] = edges[eid].v;\n        ch_uv[eid] = edges[eid].ch_uv; ch_vu[eid] = edges[eid].ch_vu;\n    }\n    vector<vector<int>> incEdges(V);\n    for (int eid = 0; eid < M; eid++) {\n        incEdges[eu[eid]].push_back(eid);\n        incEdges[ev[eid]].push_back(eid);\n    }\n\n    auto val_for_edge = [&](int eid)->ld{\n        int u = eu[eid], v = ev[eid];\n        auto [ui, uj] = coord(u);\n        auto [vi, vj] = coord(v);\n        ld du = (ld)d[ui][uj];\n        ld dv = (ld)d[vi][vj];\n        ld ku0 = (ld)k[u];\n        ld kv0 = (ld)k[v];\n        if (ku0 <= 0.5L) ku0 = 1.0L;\n        if (kv0 <= 0.5L) kv0 = 1.0L;\n        return du / (ku0 * (ku0 + 1.0L)) + dv / (kv0 * (kv0 + 1.0L));\n    };\n    auto harm_for_edge = [&](int eid)->ld{\n        if (m[eid] <= base_m[eid]) return (ld)1e300;\n        int u = eu[eid], v = ev[eid];\n        ld ku0 = (ld)k[u];\n        ld kv0 = (ld)k[v];\n        if (ku0 <= 1.0L || kv0 <= 1.0L) return (ld)1e300;\n        auto [ui, uj] = coord(u);\n        auto [vi, vj] = coord(v);\n        ld du = (ld)d[ui][uj];\n        ld dv = (ld)d[vi][vj];\n        return du / (ku0 * (ku0 - 1.0L)) + dv / (kv0 * (kv0 - 1.0L));\n    };\n    auto val_for_edge_with_delta = [&](int eid, int du_k, int dv_k)->ld{\n        int u = eu[eid], v = ev[eid];\n        ld ku0 = (ld)k[u] + (ld)du_k;\n        ld kv0 = (ld)k[v] + (ld)dv_k;\n        if (ku0 < 1.0L) ku0 = 1.0L;\n        if (kv0 < 1.0L) kv0 = 1.0L;\n        auto [ui, uj] = coord(u);\n        auto [vi, vj] = coord(v);\n        ld du = (ld)d[ui][uj];\n        ld dv = (ld)d[vi][vj];\n        return du / (ku0 * (ku0 + 1.0L)) + dv / (kv0 * (kv0 + 1.0L));\n    };\n\n    // Greedy edge additions by KKT threshold with lazy PQ\n    struct AddItem { ld val; int eid; int ku, kv; bool operator<(AddItem const& o) const { return val < o.val; } };\n    priority_queue<AddItem> pqAdd;\n    for (int eid = 0; eid < M; eid++) pqAdd.push(AddItem{val_for_edge(eid), eid, (int)k[eu[eid]], (int)k[ev[eid]]});\n\n    long long remLen = Lmax - L;\n    const ld eps = 1e-18L;\n    while (remLen >= 2 && !pqAdd.empty()) {\n        if (elapsed_ms() > 1650.0) break;\n        AddItem it = pqAdd.top(); pqAdd.pop();\n        int eid = it.eid;\n        int u = eu[eid], v = ev[eid];\n        if (it.ku != (int)k[u] || it.kv != (int)k[v]) {\n            pqAdd.push(AddItem{val_for_edge(eid), eid, (int)k[u], (int)k[v]});\n            continue;\n        }\n        ld theta = 2.0L * Ad / ((ld)L + 2.0L);\n        if (it.val <= theta + eps) break;\n        if (remLen < 2) break;\n\n        long long ku_old = k[u], kv_old = k[v];\n        m[eid] += 2;\n        deg[u] += 2; deg[v] += 2;\n        k[u] += 1; k[v] += 1;\n        L += 2;\n        remLen -= 2;\n\n        auto [ui, uj] = coord(u);\n        auto [vi, vj] = coord(v);\n        ld du = (ld)d[ui][uj];\n        ld dv = (ld)d[vi][vj];\n        Ad += du * (1.0L / (ld)k[u] - 1.0L / (ld)ku_old);\n        Ad += dv * (1.0L / (ld)k[v] - 1.0L / (ld)kv_old);\n\n        for (int e2 : incEdges[u]) pqAdd.push(AddItem{val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n        for (int e2 : incEdges[v]) pqAdd.push(AddItem{val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n    }\n\n    // Length-preserving 2-opt reallocation with small top-K scanning for removals\n    struct RemItem {\n        ld harm;\n        int eid;\n        int ku, kv;\n    };\n    struct RemComp {\n        bool operator()(RemItem const& a, RemItem const& b) const {\n            return a.harm > b.harm; // min-heap\n        }\n    };\n    priority_queue<RemItem, vector<RemItem>, RemComp> pqRem;\n    for (int eid = 0; eid < M; eid++) {\n        if (m[eid] > base_m[eid]) {\n            pqRem.push(RemItem{harm_for_edge(eid), eid, (int)k[eu[eid]], (int)k[ev[eid]]});\n        }\n    }\n\n    int swapLimit = 2000;\n    int swaps = 0;\n    const int ATRIES = 4;\n    const int RTRIES = 6;\n    while (swaps < swapLimit && !pqAdd.empty() && !pqRem.empty()) {\n        if (elapsed_ms() > 1900.0) break;\n\n        // collect up to ATRIES valid add candidates\n        vector<AddItem> addPopped;\n        addPopped.reserve(ATRIES);\n        while ((int)addPopped.size() < ATRIES && !pqAdd.empty()) {\n            AddItem a = pqAdd.top(); pqAdd.pop();\n            int u = eu[a.eid], v = ev[a.eid];\n            if (a.ku != (int)k[u] || a.kv != (int)k[v]) {\n                pqAdd.push(AddItem{val_for_edge(a.eid), a.eid, (int)k[u], (int)k[v]});\n                continue;\n            }\n            addPopped.push_back(a);\n        }\n        if (addPopped.empty()) break;\n\n        ld bestGain = 0.0L;\n        int bestAdd = -1, bestRem = -1;\n        vector<RemItem> remBuffer; remBuffer.reserve(RTRIES);\n\n        for (auto &a : addPopped) {\n            int eAdd = a.eid;\n            int ua = eu[eAdd], va = ev[eAdd];\n\n            // take up to RTRIES valid remove candidates\n            remBuffer.clear();\n            int tries = 0;\n            while (tries < RTRIES && !pqRem.empty()) {\n                RemItem r = pqRem.top(); pqRem.pop();\n                int ur = eu[r.eid], vr = ev[r.eid];\n                if (m[r.eid] <= base_m[r.eid]) {\n                    // outdated\n                } else if (r.ku != (int)k[ur] || r.kv != (int)k[vr]) {\n                    pqRem.push(RemItem{harm_for_edge(r.eid), r.eid, (int)k[ur], (int)k[vr]});\n                } else {\n                    // recompute current harm to ensure freshness\n                    ld hcur = harm_for_edge(r.eid);\n                    if (hcur >= 1e299L) {\n                        // not removable\n                    } else {\n                        r.harm = hcur;\n                        remBuffer.push_back(r);\n                        tries++;\n                    }\n                }\n            }\n            // evaluate pairs with this add\n            for (auto &r : remBuffer) {\n                int eRem = r.eid;\n                int ur = eu[eRem], vr = ev[eRem];\n                int du_k = 0, dv_k = 0;\n                if (ua == ur) du_k--;\n                if (ua == vr) du_k--;\n                if (va == ur) dv_k--;\n                if (va == vr) dv_k--;\n                ld valA = val_for_edge_with_delta(eAdd, du_k, dv_k);\n                ld harmR = r.harm;\n                ld gain = valA - harmR;\n                if (gain > bestGain + 1e-18L) {\n                    bestGain = gain;\n                    bestAdd = eAdd;\n                    bestRem = eRem;\n                }\n            }\n            // push back remove candidates\n            for (auto &r : remBuffer) pqRem.push(r);\n        }\n\n        // push back unused add candidates\n        for (auto &a : addPopped) pqAdd.push(a);\n\n        if (bestAdd == -1 || bestGain <= 1e-18L) break;\n\n        // Apply the swap: remove 2 from bestRem, add 2 to bestAdd\n        int ur = eu[bestRem], vr = ev[bestRem];\n        long long ku_old = k[ur], kv_old = k[vr];\n        m[bestRem] -= 2;\n        deg[ur] -= 2; deg[vr] -= 2;\n        k[ur] -= 1; k[vr] -= 1;\n        auto [uri, urj] = coord(ur);\n        auto [vri, vrj] = coord(vr);\n        ld dur = (ld)d[uri][urj];\n        ld dvr = (ld)d[vri][vrj];\n        Ad += dur * (1.0L / (ld)k[ur] - 1.0L / (ld)ku_old);\n        Ad += dvr * (1.0L / (ld)k[vr] - 1.0L / (ld)kv_old);\n\n        int ua = eu[bestAdd], va = ev[bestAdd];\n        long long kua_old = k[ua], kva_old = k[va];\n        m[bestAdd] += 2;\n        deg[ua] += 2; deg[va] += 2;\n        k[ua] += 1; k[va] += 1;\n        auto [uai, uaj] = coord(ua);\n        auto [vai, vaj] = coord(va);\n        ld dua = (ld)d[uai][uaj];\n        ld dva = (ld)d[vai][vaj];\n        Ad += dua * (1.0L / (ld)k[ua] - 1.0L / (ld)kua_old);\n        Ad += dva * (1.0L / (ld)k[va] - 1.0L / (ld)kva_old);\n\n        // Update PQs in neighborhoods\n        for (int e2 : incEdges[ur]) {\n            pqAdd.push(AddItem{val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n            if (m[e2] > base_m[e2]) pqRem.push(RemItem{harm_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n        }\n        for (int e2 : incEdges[vr]) {\n            pqAdd.push(AddItem{val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n            if (m[e2] > base_m[e2]) pqRem.push(RemItem{harm_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n        }\n        for (int e2 : incEdges[ua]) {\n            pqAdd.push(AddItem{val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n            if (m[e2] > base_m[e2]) pqRem.push(RemItem{harm_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n        }\n        for (int e2 : incEdges[va]) {\n            pqAdd.push(AddItem{val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n            if (m[e2] > base_m[e2]) pqRem.push(RemItem{harm_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n        }\n\n        swaps++;\n    }\n\n    // Build adjacency ports for Euler traversal\n    vector<vector<AdjPort>> ports(V);\n    vector<long long> rem(m);\n    for (int eid = 0; eid < M; eid++) if (m[eid] > 0) {\n        int u = eu[eid], v = ev[eid];\n        long long tgt = m[eid] / 2;\n        ports[u].push_back(AdjPort{v, eid, ch_uv[eid], tgt, 0});\n        ports[v].push_back(AdjPort{u, eid, ch_vu[eid], tgt, 0});\n    }\n\n    // Hierholzer with weighted round-robin per vertex\n    XorShift64 rng(123456789ULL);\n    vector<int> st; st.reserve(L + 5);\n    vector<int> out; out.reserve(L + 5);\n    st.push_back(root);\n    while (!st.empty()) {\n        int v = st.back();\n        int bestIdx = -1;\n        ld bestKey = 1e100L;\n        long long bestRem = -1;\n        for (int idx = 0; idx < (int)ports[v].size(); idx++) {\n            int eid = ports[v][idx].eid;\n            if (rem[eid] <= 0) continue;\n            ld t = (ld)ports[v][idx].target;\n            ld uused = (ld)ports[v][idx].used;\n            ld noise = (ld)( (rng.nextUInt() & 1023U) ) * 1e-6L;\n            ld key = (t > 0.0L) ? ((uused + noise)/t) : noise;\n            if (key < bestKey - 1e-15L || (fabsl(key - bestKey) <= 1e-15L && rem[eid] > bestRem)) {\n                bestKey = key; bestIdx = idx; bestRem = rem[eid];\n            }\n        }\n        if (bestIdx != -1) {\n            int eid = ports[v][bestIdx].eid;\n            int to = ports[v][bestIdx].to;\n            rem[eid]--;\n            ports[v][bestIdx].used++;\n            st.push_back(to);\n        } else {\n            out.push_back(v);\n            st.pop_back();\n        }\n    }\n    reverse(out.begin(), out.end());\n\n    // Build move string\n    string ans;\n    ans.reserve(out.size() ? out.size() - 1 : 0);\n    for (size_t i = 0; i + 1 < out.size(); i++) {\n        int a = out[i], b = out[i+1];\n        char ch = '?';\n        for (auto &pp : ports[a]) if (pp.to == b) { ch = pp.ch; break; }\n        if (ch == '?') {\n            auto [ai, aj] = coord(a);\n            auto [bi, bj] = coord(b);\n            if (bi == ai && bj == aj + 1) ch = 'R';\n            else if (bi == ai && bj == aj - 1) ch = 'L';\n            else if (bi == ai + 1 && bj == aj) ch = 'D';\n            else if (bi == ai - 1 && bj == aj) ch = 'U';\n            else ch = 'U';\n        }\n        ans.push_back(ch);\n    }\n    if ((int)ans.size() > (int)Lmax) ans.resize((size_t)Lmax);\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, r;\n    DSU(int n=0): n(n), p(n), r(n,0) { iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n    bool same(int a, int b){ return find(a)==find(b); }\n    bool unite(int a, int b){\n        a = find(a); b = find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n};\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed=88172645463393265ull){ x=seed; }\n    uint64_t next(){\n        x ^= x<<7;\n        x ^= x>>9;\n        return x;\n    }\n    int next_int(int l, int r){ // inclusive\n        return l + (int)(next() % (uint64_t)(r-l+1));\n    }\n    double next_double(){ return (next() >> 11) * (1.0 / (1ull<<53)); }\n};\n\nstruct Pos { short i, j; };\n\nstatic inline int manhattan(const Pos& a, const Pos& b){\n    return abs(a.i - b.i) + abs(a.j - b.j);\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if(!(cin >> N >> M)) return 0; // N=15, M=200\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> A(N);\n    for(int i=0;i<N;i++) cin >> A[i];\n    vector<string> t(M);\n    for(int k=0;k<M;k++) cin >> t[k];\n\n    auto time_start = chrono::high_resolution_clock::now();\n    auto elapsed = [&](){\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - time_start).count();\n    };\n    const double TIME_LIMIT = 1.95;\n\n    XorShift rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Positions per letter\n    vector<vector<Pos>> pos(26);\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            int c = A[i][j]-'A';\n            pos[c].push_back(Pos{(short)i,(short)j});\n        }\n    }\n\n    // Start distance per letter\n    vector<int> startDist(26, INT_MAX/4);\n    for(int c=0;c<26;c++){\n        for(auto &p : pos[c]){\n            startDist[c] = min(startDist[c], abs(p.i - si) + abs(p.j - sj));\n        }\n        if(startDist[c] == INT_MAX/4) startDist[c] = 20; // safety\n    }\n\n    // Letter-to-letter proxy distance: average of K smallest distances\n    const int K_MIN = 3;\n    vector<vector<double>> dLL(26, vector<double>(26, 0.0));\n    for(int a=0;a<26;a++){\n        for(int b=0;b<26;b++){\n            vector<int> ds;\n            ds.reserve(pos[a].size() * pos[b].size());\n            for(auto &pa : pos[a]){\n                for(auto &pb : pos[b]){\n                    ds.push_back(abs(pa.i - pb.i) + abs(pa.j - pb.j));\n                }\n            }\n            if(ds.empty()){\n                dLL[a][b] = 8.0; // fallback\n            }else{\n                int cnt = min((int)ds.size(), K_MIN);\n                nth_element(ds.begin(), ds.begin()+cnt-1, ds.end());\n                sort(ds.begin(), ds.begin()+cnt);\n                double s=0;\n                for(int i=0;i<cnt;i++) s += ds[i];\n                dLL[a][b] = s / cnt;\n            }\n        }\n    }\n\n    // Overlap matrix f[i][j] in [0..4]\n    auto overlap = [&](const string& a, const string& b)->int{\n        for(int k=4;k>=1;k--){\n            bool ok = true;\n            for(int x=0;x<k;x++){\n                if(a[5-k+x] != b[x]){ ok=false; break; }\n            }\n            if(ok) return k;\n        }\n        return 0;\n    };\n    vector<vector<int>> f(M, vector<int>(M, 0));\n    for(int i=0;i<M;i++){\n        for(int j=0;j<M;j++){\n            if(i==j) continue;\n            f[i][j] = overlap(t[i], t[j]);\n        }\n    }\n\n    // Word letters\n    vector<array<int,5>> wlett(M);\n    for(int i=0;i<M;i++){\n        for(int k=0;k<5;k++) wlett[i][k] = t[i][k] - 'A';\n    }\n\n    // Intra-word suffix proxy movement costs for each possible overlap ov (0..4)\n    vector<array<double,5>> intraSuf(M);\n    for(int j=0;j<M;j++){\n        double pref[6]={0};\n        pref[0]=0;\n        for(int k=0;k<4;k++){\n            int a = wlett[j][k], b = wlett[j][k+1];\n            pref[k+1] = pref[k] + dLL[a][b];\n        }\n        for(int ov=0; ov<=4; ov++){\n            intraSuf[j][ov] = pref[4] - pref[ov];\n        }\n    }\n\n    // Estimated edge weights (maximize) and start weights\n    vector<vector<double>> W_est(M, vector<double>(M, -1e100));\n    vector<double> Wstart(M, 0.0);\n    for(int i=0;i<M;i++){\n        for(int j=0;j<M;j++){\n            if(i==j){ W_est[i][j] = -1e100; continue; }\n            int ov = f[i][j];\n            int lastc = wlett[i][4];\n            int firstNew = wlett[j][ov];\n            double boundary = dLL[lastc][firstNew];\n            double c = (5 - ov) + boundary + intraSuf[j][ov];\n            W_est[i][j] = -c;\n        }\n    }\n    for(int i=0;i<M;i++){\n        double c = 5.0 + startDist[wlett[i][0]] + intraSuf[i][0];\n        Wstart[i] = -c;\n    }\n\n    // Overlap sum for sequence\n    auto sum_overlaps = [&](const vector<int>& pi)->int{\n        int s=0;\n        for(int i=0;i+1<(int)pi.size();i++) s += f[pi[i]][pi[i+1]];\n        return s;\n    };\n\n    // Initial construction: arc packing using overlaps\n    auto build_by_arc_packing = [&]()->vector<int>{\n        struct Arc { int u, v; int w; uint64_t r; };\n        vector<Arc> arcs;\n        arcs.reserve((size_t)M*(M-1));\n        for(int i=0;i<M;i++){\n            for(int j=0;j<M;j++){\n                if(i==j) continue;\n                arcs.push_back({ i, j, f[i][j], (uint64_t)rng.next() });\n            }\n        }\n        sort(arcs.begin(), arcs.end(), [](const Arc& a, const Arc& b){\n            if(a.w != b.w) return a.w > b.w;\n            return a.r < b.r;\n        });\n        vector<int> succ(M, -1), pred(M, -1);\n        DSU uf(M);\n        for(const auto& e : arcs){\n            int u=e.u, v=e.v;\n            if(succ[u]!=-1) continue;\n            if(pred[v]!=-1) continue;\n            if(uf.same(u, v)) continue; // avoid cycle\n            succ[u]=v;\n            pred[v]=u;\n            uf.unite(u, v);\n        }\n        // Extract chains\n        vector<char> used(M, 0);\n        vector<vector<int>> chains;\n        for(int i=0;i<M;i++){\n            if(pred[i]==-1){ // head\n                vector<int> chain;\n                int cur=i;\n                while(cur!=-1){\n                    chain.push_back(cur);\n                    used[cur]=1;\n                    cur = succ[cur];\n                }\n                chains.push_back(move(chain));\n            }\n        }\n        for(int i=0;i<M;i++){\n            if(!used[i]){\n                chains.push_back(vector<int>{i});\n                used[i]=1;\n            }\n        }\n        int Cn = (int)chains.size();\n        vector<int> head(Cn), tail(Cn);\n        for(int c=0;c<Cn;c++){\n            head[c] = chains[c].front();\n            tail[c] = chains[c].back();\n        }\n        // Choose start chain with worst incoming overlap\n        vector<int> inBest(Cn, 0);\n        for(int j=0;j<Cn;j++){\n            int best=0;\n            for(int i=0;i<Cn;i++){\n                if(i==j) continue;\n                best = max(best, f[tail[i]][head[j]]);\n            }\n            inBest[j]=best;\n        }\n        int start = 0;\n        int minIn = INT_MAX;\n        for(int j=0;j<Cn;j++){\n            if(inBest[j] < minIn){\n                minIn = inBest[j];\n                start = j;\n            }\n        }\n        vector<char> usedC(Cn,0);\n        vector<int> order; order.reserve(Cn);\n        int cur = start; usedC[cur]=1; order.push_back(cur);\n        for(int step=1; step<Cn; step++){\n            int bestW=-1, bestJ=-1;\n            for(int j=0;j<Cn;j++){\n                if(usedC[j]) continue;\n                int w = f[tail[cur]][head[j]];\n                if(w>bestW){ bestW=w; bestJ=j; }\n            }\n            if(bestJ==-1){\n                for(int j=0;j<Cn;j++){ if(!usedC[j]){ bestJ=j; break; } }\n            }\n            usedC[bestJ]=1;\n            order.push_back(bestJ);\n            cur = bestJ;\n        }\n        vector<int> pi;\n        pi.reserve(M);\n        for(int idx : order){\n            for(int node : chains[idx]) pi.push_back(node);\n        }\n        return pi;\n    };\n\n    // Nearest-neighbor on overlaps\n    auto build_by_nn = [&](int s)->vector<int>{\n        vector<char> used(M,0);\n        vector<int> pi; pi.reserve(M);\n        int cur = s; used[cur]=1; pi.push_back(cur);\n        for(int k=1;k<M;k++){\n            int bestW=-1, bestJ=-1;\n            for(int j=0;j<M;j++){\n                if(used[j]) continue;\n                int w = f[cur][j];\n                if(w>bestW){ bestW=w; bestJ=j; }\n            }\n            if(bestJ==-1){\n                for(int j=0;j<M;j++){ if(!used[j]){ bestJ=j; break; } }\n            }\n            used[bestJ]=1;\n            pi.push_back(bestJ);\n            cur = bestJ;\n        }\n        return pi;\n    };\n\n    // Overlap insertion LS (simple)\n    auto insertion_ls_overlap = [&](vector<int>& p, double time_budget_sec){\n        int n = p.size();\n        auto getEdge = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        auto compute_insert_delta = [&](int i, int j2)->int{\n            int N = n;\n            int x = p[i];\n            int delta = 0;\n            if(i == 0){\n                if(N >= 2){\n                    delta -= getEdge(p[0], p[1]);\n                }\n            }else{\n                delta -= getEdge(p[i-1], p[i]);\n                if(i < N-1){\n                    delta -= getEdge(p[i], p[i+1]);\n                    delta += getEdge(p[i-1], p[i+1]);\n                }\n            }\n            int len = N - 1;\n            auto getAfter = [&](int k)->int{\n                if(k < i) return p[k];\n                else return p[k+1];\n            };\n            if(len == 0){\n                return delta;\n            }\n            if(j2 == 0){\n                int R = getAfter(0);\n                delta += getEdge(x, R);\n            }else if(j2 == len){\n                int L = getAfter(len-1);\n                delta += getEdge(L, x);\n            }else{\n                int L = getAfter(j2-1);\n                int R = getAfter(j2);\n                delta -= getEdge(L, R);\n                delta += getEdge(L, x);\n                delta += getEdge(x, R);\n            }\n            return delta;\n        };\n        auto apply_insert = [&](int i, int j2){\n            int x = p[i];\n            p.erase(p.begin()+i);\n            p.insert(p.begin()+j2, x);\n        };\n        double t0 = elapsed();\n        while(elapsed() - t0 < time_budget_sec){\n            bool improved = false;\n            for(int i=0;i<n;i++){\n                int best_j=-1, best_d=0;\n                for(int j2=0;j2<=n-1;j2++){\n                    if(j2==i) continue;\n                    int d = compute_insert_delta(i,j2);\n                    if(d > best_d){ best_d=d; best_j=j2; }\n                }\n                if(best_d > 0){\n                    apply_insert(i,best_j);\n                    improved = true;\n                    break;\n                }\n            }\n            if(!improved) break;\n        }\n    };\n\n    // Build initial candidates\n    vector<vector<int>> candidates;\n    vector<int> pi1 = build_by_arc_packing();\n    insertion_ls_overlap(pi1, 0.05);\n    candidates.push_back(pi1);\n    // NN starts\n    int nn_trials = 10;\n    for(int s=0;s<nn_trials;s++){\n        int start = rng.next_int(0, M-1);\n        vector<int> pi = build_by_nn(start);\n        insertion_ls_overlap(pi, 0.03);\n        candidates.push_back(move(pi));\n    }\n\n    // Select top few by overlap sum\n    struct Cand { vector<int> pi; int ov; };\n    vector<Cand> cands;\n    cands.reserve(candidates.size());\n    for(auto &pi : candidates){\n        cands.push_back({pi, sum_overlaps(pi)});\n    }\n    sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){\n        return a.ov > b.ov;\n    });\n    int keep = min<int>(cands.size(), 4);\n\n    // Utilities to build letter sequence and DP\n    auto build_letters_from_pi = [&](const vector<int>& pi)->vector<int>{\n        vector<int> letters;\n        letters.reserve(5*M);\n        // Add first word fully\n        for(int k=0;k<5;k++) letters.push_back(t[pi[0]][k]-'A');\n        for(int i=1;i<M;i++){\n            int a = pi[i-1], b = pi[i];\n            int ov = f[a][b];\n            for(int k=ov;k<5;k++) letters.push_back(t[b][k]-'A');\n        }\n        return letters;\n    };\n\n    auto dp_cost = [&](const vector<int>& letters)->long long{\n        int L = (int)letters.size();\n        int c0 = letters[0];\n        int P0 = (int)pos[c0].size();\n        if(P0==0) return (long long)1e18;\n        vector<int> dp_prev(P0);\n        for(int q=0;q<P0;q++){\n            int ii=pos[c0][q].i, jj=pos[c0][q].j;\n            dp_prev[q] = abs(ii-si) + abs(jj-sj) + 1;\n        }\n        for(int l=1;l<L;l++){\n            int c = letters[l];\n            int Pc = (int)pos[c].size();\n            int cp = letters[l-1];\n            int Pp = (int)pos[cp].size();\n            vector<int> dp_curr(Pc, INT_MAX/4);\n            for(int q=0;q<Pc;q++){\n                int qi=pos[c][q].i, qj=pos[c][q].j;\n                int best = INT_MAX/4;\n                for(int pidx=0;pidx<Pp;pidx++){\n                    int pi_i=pos[cp][pidx].i, pi_j=pos[cp][pidx].j;\n                    int cand = dp_prev[pidx] + abs(qi-pi_i) + abs(qj-pi_j) + 1;\n                    if(cand < best) best = cand;\n                }\n                dp_curr[q] = best;\n            }\n            dp_prev.swap(dp_curr);\n        }\n        int lastc = letters.back();\n        int Pl = (int)pos[lastc].size();\n        int bestv = INT_MAX/4;\n        for(int q=0;q<Pl;q++) bestv = min(bestv, dp_prev[q]);\n        return bestv;\n    };\n\n    auto dp_solve = [&](const vector<int>& letters)->pair<long long, vector<pair<int,int>>>{\n        int L = (int)letters.size();\n        vector<vector<int>> parent(L);\n        vector<int> dp_prev, dp_curr;\n        // init\n        int c0 = letters[0];\n        int P0 = (int)pos[c0].size();\n        dp_prev.assign(P0, INT_MAX/4);\n        parent[0].assign(P0, -1);\n        for(int q=0;q<P0;q++){\n            int ii = pos[c0][q].i, jj = pos[c0][q].j;\n            int dist = abs(ii - si) + abs(jj - sj);\n            dp_prev[q] = dist + 1;\n        }\n        for(int l=1;l<L;l++){\n            int c = letters[l];\n            int Pc = (int)pos[c].size();\n            int cp = letters[l-1];\n            int Pp = (int)pos[cp].size();\n            dp_curr.assign(Pc, INT_MAX/4);\n            parent[l].assign(Pc, -1);\n            for(int q=0;q<Pc;q++){\n                int qi = pos[c][q].i, qj = pos[c][q].j;\n                int best = INT_MAX/4, bestp=-1;\n                for(int pidx=0;pidx<Pp;pidx++){\n                    int pi_i = pos[cp][pidx].i, pi_j = pos[cp][pidx].j;\n                    int cand = dp_prev[pidx] + abs(qi - pi_i) + abs(qj - pi_j) + 1;\n                    if(cand < best){\n                        best = cand;\n                        bestp = pidx;\n                    }\n                }\n                dp_curr[q] = best;\n                parent[l][q] = bestp;\n            }\n            dp_prev.swap(dp_curr);\n        }\n        int lastc = letters.back();\n        int Pl = (int)pos[lastc].size();\n        int bestq=0, bestv=INT_MAX/4;\n        for(int q=0;q<Pl;q++){\n            if(dp_prev[q] < bestv){ bestv = dp_prev[q]; bestq=q; }\n        }\n        vector<pair<int,int>> ops(letters.size());\n        int idx = bestq;\n        for(int l=L-1;l>=0;l--){\n            int c = letters[l];\n            ops[l] = {pos[c][idx].i, pos[c][idx].j};\n            if(l>0){\n                idx = parent[l][idx];\n                if(idx < 0) idx = 0;\n            }\n        }\n        return { (long long)bestv, ops };\n    };\n\n    // Pick best baseline by DP cost; also consider reversed\n    long long best_T = (1LL<<60);\n    vector<int> best_pi;\n    vector<int> best_letters;\n    for(int i=0;i<keep;i++){\n        if(elapsed() > TIME_LIMIT) break;\n        auto &pi = cands[i].pi;\n        vector<int> letters = build_letters_from_pi(pi);\n        long long Tcost = dp_cost(letters);\n        if(Tcost < best_T){\n            best_T = Tcost;\n            best_pi = pi;\n            best_letters = letters;\n        }\n        // reversed candidate\n        vector<int> pir = pi;\n        reverse(pir.begin(), pir.end());\n        vector<int> letters_r = build_letters_from_pi(pir);\n        long long Tr = dp_cost(letters_r);\n        if(Tr < best_T){\n            best_T = Tr;\n            best_pi.swap(pir);\n            best_letters.swap(letters_r);\n        }\n    }\n    if(best_pi.empty()){\n        best_pi = build_by_arc_packing();\n        best_letters = build_letters_from_pi(best_pi);\n        best_T = dp_cost(best_letters);\n    }\n    int curOv = sum_overlaps(best_pi);\n\n    // Helpers: overlap deltas\n    auto overlap_insert_delta = [&](const vector<int>& p, int i, int j2)->int{\n        int N = p.size();\n        int x = p[i];\n        auto e = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        int delta = 0;\n        if(i == 0){\n            if(N >= 2){\n                delta -= e(p[0], p[1]);\n            }\n        }else{\n            delta -= e(p[i-1], p[i]);\n            if(i < N-1){\n                delta -= e(p[i], p[i+1]);\n                delta += e(p[i-1], p[i+1]);\n            }\n        }\n        int len = N - 1;\n        auto getAfter = [&](int k)->int{\n            if(k < i) return p[k];\n            else return p[k+1];\n        };\n        if(len == 0){\n            return delta;\n        }\n        if(j2 == 0){\n            int R = getAfter(0);\n            delta += e(x, R);\n        }else if(j2 == len){\n            int L = getAfter(len-1);\n            delta += e(L, x);\n        }else{\n            int L = getAfter(j2-1);\n            int R = getAfter(j2);\n            delta -= e(L, R);\n            delta += e(L, x);\n            delta += e(x, R);\n        }\n        return delta;\n    };\n\n    auto overlap_swap_delta = [&](const vector<int>& p, int i, int j)->int{\n        if(i==j) return 0;\n        if(i>j) swap(i,j);\n        int n = p.size();\n        auto e = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        int a = p[i], b = p[j];\n        int before = 0, after = 0;\n        if(i+1 == j){\n            if(i-1>=0){ before += e(p[i-1], a); after += e(p[i-1], b); }\n            before += e(a, b);\n            after += e(b, a);\n            if(j+1<n){ before += e(b, p[j+1]); after += e(a, p[j+1]); }\n        }else{\n            if(i-1>=0){ before += e(p[i-1], a); after += e(p[i-1], b); }\n            if(i+1<n){ before += e(a, p[i+1]); after += e(b, p[i+1]); }\n            if(j-1>=0){ before += e(p[j-1], b); after += e(p[j-1], a); }\n            if(j+1<n){ before += e(b, p[j+1]); after += e(a, p[j+1]); }\n        }\n        return after - before;\n    };\n\n    auto overlap_block_delta = [&](const vector<int>& p, int L, int R, int K)->int{\n        int N = p.size();\n        int B = R-L+1;\n        auto e = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        int delta = 0;\n        // Before edges to remove\n        if(L>0) delta -= e(p[L-1], p[L]);\n        if(R<N-1) delta -= e(p[R], p[R+1]);\n        // The pair at insertion site in original sequence (left->right) to remove:\n        if(!(K==0 || K==N-B)){\n            if(K <= L){\n                // pair (p[K-1], p[K])\n                delta -= e(p[K-1], p[K]);\n            }else{\n                // pair (p[K-1+B], p[K+B])\n                if(K-1+B >= 0 && K+B < N){\n                    delta -= e(p[K-1+B], p[K+B]);\n                }\n            }\n        }\n        // After edges to add\n        if(L>0 && R<N-1) delta += e(p[L-1], p[R+1]);\n        auto getAfter = [&](int k)->int{\n            if(k < L) return p[k];\n            else return p[k+B];\n        };\n        if(K>0){\n            int left = getAfter(K-1);\n            delta += e(left, p[L]);\n        }\n        if(K < N-B){\n            int right = getAfter(K);\n            delta += e(p[R], right);\n        }\n        return delta;\n    };\n\n    // Estimated deltas (W_est with start)\n    auto est_insert_delta = [&](const vector<int>& p, int i, int j2)->double{\n        int n = p.size();\n        int x = p[i];\n        double delta = 0.0;\n        // start changes?\n        if(i == 0){\n            delta -= Wstart[p[0]];\n            if(n >= 2){\n                delta -= W_est[p[0]][p[1]];\n                delta += Wstart[p[1]];\n            }\n        }else{\n            delta -= W_est[p[i-1]][p[i]];\n            if(i < n-1){\n                delta -= W_est[p[i]][p[i+1]];\n                delta += W_est[p[i-1]][p[i+1]];\n            }\n        }\n        int len = n - 1;\n        auto getAfter = [&](int k)->int{\n            if(k < i) return p[k];\n            else return p[k+1];\n        };\n        if(len == 0){\n            delta += Wstart[x];\n            return delta;\n        }\n        if(j2 == 0){\n            int R = getAfter(0);\n            delta -= Wstart[R];\n            delta += Wstart[x];\n            delta += W_est[x][R];\n        }else if(j2 == len){\n            int L = getAfter(len-1);\n            delta += W_est[L][x];\n        }else{\n            int L = getAfter(j2-1);\n            int R = getAfter(j2);\n            delta -= W_est[L][R];\n            delta += W_est[L][x];\n            delta += W_est[x][R];\n        }\n        return delta;\n    };\n\n    auto est_swap_delta = [&](const vector<int>& p, int i, int j)->double{\n        if(i==j) return 0.0;\n        if(i>j) swap(i,j);\n        int n = p.size();\n        auto edge_sum_partial = [&](const vector<int>& arr, int i, int j)->double{\n            double s = 0.0;\n            // start changes if i==0 or j==0\n            if(i==0 || j==0){\n                s += Wstart[arr[0]];\n            }\n            // edges around i-1,i and j-1,j and adjacent\n            int a=i, b=j;\n            vector<int> idxs;\n            for(int k=a-1;k<=a;k++) if(k>=0 && k<n-1) idxs.push_back(k);\n            for(int k=b-1;k<=b;k++) if(k>=0 && k<n-1) idxs.push_back(k);\n            sort(idxs.begin(), idxs.end());\n            idxs.erase(unique(idxs.begin(), idxs.end()), idxs.end());\n            for(int k: idxs){\n                s += W_est[arr[k]][arr[k+1]];\n            }\n            return s;\n        };\n        double before = edge_sum_partial(p, i, j);\n        vector<int> q = p;\n        swap(q[i], q[j]);\n        double after  = edge_sum_partial(q, i, j);\n        return after - before;\n    };\n\n    auto est_block_delta = [&](const vector<int>& p, int L, int R, int K)->double{\n        int N = p.size();\n        int B = R-L+1;\n        double delta = 0.0;\n        // Start contribution\n        double beforeStart = Wstart[p[0]];\n        double afterStart = beforeStart;\n        if(K==0){\n            afterStart = Wstart[p[L]];\n        }else if(L==0 && K>0){\n            // new head is q[0] = p[R+1]\n            if(R+1 < N) afterStart = Wstart[p[R+1]];\n        }else{\n            // unchanged\n            afterStart = beforeStart;\n        }\n        delta += (afterStart - beforeStart);\n\n        auto E = [&](int a, int b)->double{ if(a<0||b<0) return 0.0; return W_est[a][b]; };\n        // Before edges to remove\n        if(L>0) delta -= E(p[L-1], p[L]);\n        if(R<N-1) delta -= E(p[R], p[R+1]);\n        // The pair at insertion site in original sequence to remove:\n        if(!(K==0 || K==N-B)){\n            if(K <= L){\n                // pair (p[K-1], p[K])\n                delta -= E(p[K-1], p[K]);\n            }else{\n                if(K-1+B >= 0 && K+B < N){\n                    delta -= E(p[K-1+B], p[K+B]);\n                }\n            }\n        }\n        // After edges to add\n        if(L>0 && R<N-1) delta += E(p[L-1], p[R+1]);\n        auto getAfter = [&](int k)->int{\n            if(k < L) return p[k];\n            else return p[k+B];\n        };\n        if(K>0){\n            int left = getAfter(K-1);\n            delta += E(left, p[L]);\n        }\n        if(K < N-B){\n            int right = getAfter(K);\n            delta += E(p[R], right);\n        }\n        return delta;\n    };\n\n    auto apply_insert = [&](vector<int>& p, int i, int j2){\n        int x = p[i];\n        p.erase(p.begin()+i);\n        p.insert(p.begin()+j2, x);\n    };\n    auto apply_block = [&](vector<int>& p, int L, int R, int K){\n        vector<int> block;\n        block.reserve(R-L+1);\n        for(int i=L;i<=R;i++) block.push_back(p[i]);\n        p.erase(p.begin()+L, p.begin()+R+1);\n        p.insert(p.begin()+K, block.begin(), block.end());\n    };\n\n    // DP-based local improvements with movement-aware gating\n    double t_ls_start = elapsed();\n    while(elapsed() < TIME_LIMIT - 0.08){\n        int moveTypeSel = rng.next_int(0, 99);\n        if(moveTypeSel < 50){\n            // insertion\n            int i = rng.next_int(0, M-1);\n            int j2 = rng.next_int(0, M-1);\n            if(j2==i) continue;\n            int dOv = overlap_insert_delta(best_pi, i, j2);\n            if(dOv < -1) continue;\n            double dEst = est_insert_delta(best_pi, i, j2);\n            // gate: prefer dEst>0 or non-negative overlap change\n            if(!(dEst > 1e-9 || dOv >= 0 || rng.next_int(0,99)<5)) continue;\n            vector<int> cand_pi = best_pi;\n            apply_insert(cand_pi, i, j2);\n            vector<int> letters = build_letters_from_pi(cand_pi);\n            long long Tcost = dp_cost(letters);\n            if(Tcost < best_T){\n                best_T = Tcost;\n                best_pi.swap(cand_pi);\n                best_letters.swap(letters);\n                curOv += dOv;\n            }\n        }else if(moveTypeSel < 80){\n            // swap\n            int i = rng.next_int(0, M-1);\n            int j = rng.next_int(0, M-1);\n            if(i==j) continue;\n            if(i>j) swap(i,j);\n            int dOv = overlap_swap_delta(best_pi, i, j);\n            if(dOv < -1) continue;\n            double dEst = est_swap_delta(best_pi, i, j);\n            if(!(dEst > 1e-9 || dOv >= 0 || rng.next_int(0,99)<3)) continue;\n            vector<int> cand_pi = best_pi;\n            swap(cand_pi[i], cand_pi[j]);\n            vector<int> letters = build_letters_from_pi(cand_pi);\n            long long Tcost = dp_cost(letters);\n            if(Tcost < best_T){\n                best_T = Tcost;\n                best_pi.swap(cand_pi);\n                best_letters.swap(letters);\n                curOv += dOv;\n            }\n        }else{\n            // block insertion\n            int L = rng.next_int(0, M-2);\n            int maxlen = min(8, M - L); // limit block size\n            int len = rng.next_int(2, maxlen);\n            int R = L + len - 1;\n            int K = rng.next_int(0, M - len);\n            // Avoid no-op where K equals original position of block\n            if(K >= L && K <= R+1) continue;\n            int dOv = overlap_block_delta(best_pi, L, R, K);\n            if(dOv < -1) continue;\n            double dEst = est_block_delta(best_pi, L, R, K);\n            if(!(dEst > 1e-9 || dOv >= 0 || rng.next_int(0,99)<3)) continue;\n            vector<int> cand_pi = best_pi;\n            apply_block(cand_pi, L, R, K);\n            vector<int> letters = build_letters_from_pi(cand_pi);\n            long long Tcost = dp_cost(letters);\n            if(Tcost < best_T){\n                best_T = Tcost;\n                best_pi.swap(cand_pi);\n                best_letters.swap(letters);\n                curOv += dOv;\n            }\n        }\n    }\n\n    // Final DP with path reconstruction\n    auto [finalT, ops] = dp_solve(best_letters);\n\n    for(auto &p : ops){\n        cout << p.first << \" \" << p.second << \"\\n\";\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer for internal time management\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::steady_clock::now(); }\n    double elapsed() const { return chrono::duration<double>(chrono::steady_clock::now() - st).count(); }\n};\n\nstatic inline int cell_id(int i, int j, int N) { return i * N + j; }\nstatic inline pair<int,int> cell_ij(int id, int N) { return {id / N, id % N}; }\n\nstruct Shape {\n    int id;\n    vector<pair<int,int>> offsets; // relative coordinates within shape\n    int H=0, W=0;\n    vector<vector<int>> shiftsCells; // per shift: global cell ids covered\n    vector<vector<int>> coverShiftsByCell; // for each global cell, list of shifts that cover it\n};\n\nstruct Problem {\n    int N, M;\n    double eps;\n    vector<Shape> shapes;\n};\n\nstruct State {\n    int N, M;\n    const Problem* prob;\n\n    // Known v(i,j) via drilling, -1 unknown\n    vector<int> known; // size N*N\n    vector<int> drilledCells;\n    vector<int> vDrilled;\n    vector<int> drilledIndexOf; // map cell -> drilled index\n\n    // Candidate shifts per shape\n    vector<vector<uint8_t>> active;\n    vector<int> activeCount;\n\n    // Coverage bounds for drilled cells\n    int D = 0;\n    vector<vector<int>> anyCoverKD;  // [k][d] could cover\n    vector<vector<int>> mustCoverKD; // [k][d] must cover\n    vector<int> sumAnyD, sumMustD;\n\n    // Cache: for each (shape, shift), drilled indices covered\n    vector<vector<vector<int>>> coverDrilledCache;\n\n    int opCount = 0;\n    int opLimit;\n\n    mt19937 rng;\n    Timer timer;\n    double timeLimitSec = 2.25; // strict internal limit\n\n    State(const Problem* pr) : prob(pr) {\n        N = pr->N; M = pr->M;\n        known.assign(N*N, -1);\n        drilledIndexOf.assign(N*N, -1);\n        active.resize(M);\n        activeCount.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            active[k].assign(Pk, 1);\n            activeCount[k] = Pk;\n        }\n        rng.seed(chrono::high_resolution_clock::now().time_since_epoch().count());\n        opLimit = 2 * N * N;\n    }\n\n    inline void flush() { cout.flush(); }\n\n    inline bool removeShift(int k, int p) {\n        if (active[k][p]) {\n            active[k][p] = 0;\n            --activeCount[k];\n            return true;\n        }\n        return false;\n    }\n\n    inline int drill_cell(int c) {\n        if (known[c] != -1) return known[c];\n        auto [i,j] = cell_ij(c, N);\n        cout << \"q 1 \" << i << \" \" << j << \"\\n\";\n        flush();\n        string s;\n        if (!(cin >> s)) exit(0);\n        int val = stoi(s);\n        known[c] = val;\n        drilledIndexOf[c] = (int)drilledCells.size();\n        drilledCells.push_back(c);\n        vDrilled.push_back(val);\n        ++opCount;\n        if (val == 0) {\n            // eliminate shifts covering this cell\n            for (int k = 0; k < M; ++k) {\n                if (activeCount[k] == 0) continue;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) {\n                    removeShift(k, p);\n                }\n            }\n        }\n        return val;\n    }\n\n    bool allShapesHaveCandidates() const {\n        for (int k = 0; k < M; ++k) if (activeCount[k] <= 0) return false;\n        return true;\n    }\n\n    void recomputeCoverageBounds() {\n        D = (int)drilledCells.size();\n        anyCoverKD.assign(M, vector<int>(D, 0));\n        mustCoverKD.assign(M, vector<int>(D, 0));\n        sumAnyD.assign(D, 0);\n        sumMustD.assign(D, 0);\n        for (int k = 0; k < M; ++k) {\n            if (activeCount[k] <= 0) continue;\n            for (int d = 0; d < D; ++d) {\n                int c = drilledCells[d];\n                int cnt = 0;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) ++cnt;\n                anyCoverKD[k][d] = (cnt > 0) ? 1 : 0;\n                mustCoverKD[k][d] = (cnt == activeCount[k]) ? 1 : 0;\n                sumAnyD[d] += anyCoverKD[k][d];\n                sumMustD[d] += mustCoverKD[k][d];\n            }\n        }\n    }\n\n    void buildCoverDrilledCache() {\n        D = (int)drilledCells.size();\n        coverDrilledCache.clear();\n        coverDrilledCache.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            coverDrilledCache[k].resize(Pk);\n            for (int p = 0; p < Pk; ++p) {\n                if (!active[k][p]) { coverDrilledCache[k][p].clear(); continue; }\n                const auto& cells = prob->shapes[k].shiftsCells[p];\n                auto& v = coverDrilledCache[k][p];\n                v.clear();\n                for (int c : cells) {\n                    int d = drilledIndexOf[c];\n                    if (d >= 0) v.push_back(d);\n                }\n                sort(v.begin(), v.end());\n                v.erase(unique(v.begin(), v.end()), v.end());\n            }\n        }\n    }\n\n    // Constraint propagation using drilled cells info\n    bool propagateConstraints(int maxIter = 200) {\n        for (int iter = 0; iter < maxIter; ++iter) {\n            bool changed = false;\n            recomputeCoverageBounds();\n            // quick contradiction check\n            for (int d = 0; d < D; ++d) {\n                int v = vDrilled[d];\n                if (sumAnyD[d] < v || sumMustD[d] > v) {\n                    // Contradiction; return false to trigger fallback\n                    return false;\n                }\n            }\n            for (int d = 0; d < D; ++d) {\n                int c = drilledCells[d];\n                int v = vDrilled[d];\n                // v == 0: ensure elimination\n                if (v == 0) {\n                    for (int k = 0; k < M; ++k) {\n                        if (activeCount[k] <= 0) continue;\n                        if (anyCoverKD[k][d]) {\n                            for (int p : prob->shapes[k].coverShiftsByCell[c]) {\n                                if (removeShift(k, p)) changed = true;\n                            }\n                        }\n                    }\n                    continue;\n                }\n                // sumAny == v: all potential shapes must cover c\n                if (sumAnyD[d] == v) {\n                    for (int k = 0; k < M; ++k) {\n                        if (activeCount[k] <= 0) continue;\n                        if (anyCoverKD[k][d]) {\n                            // remove shifts NOT covering c\n                            int Pk = (int)prob->shapes[k].shiftsCells.size();\n                            // Mark covering shifts for quick test\n                            static vector<uint8_t> mark;\n                            mark.assign(Pk, 0);\n                            for (int p : prob->shapes[k].coverShiftsByCell[c]) mark[p] = 1;\n                            for (int p = 0; p < Pk; ++p) if (active[k][p] && !mark[p]) {\n                                if (removeShift(k, p)) changed = true;\n                            }\n                        }\n                    }\n                }\n                // sumMust == v: all other shapes must NOT cover c\n                if (sumMustD[d] == v) {\n                    for (int k = 0; k < M; ++k) {\n                        if (activeCount[k] <= 0) continue;\n                        if (anyCoverKD[k][d] && mustCoverKD[k][d] == 0) {\n                            for (int p : prob->shapes[k].coverShiftsByCell[c]) {\n                                if (removeShift(k, p)) changed = true;\n                            }\n                        }\n                    }\n                }\n            }\n            if (!changed) break;\n            // continue to next iteration until fixpoint\n        }\n        return allShapesHaveCandidates();\n    }\n\n    vector<int> chooseOrder(int targetCell = -1, int requireCovered = -1) {\n        vector<int> ord(M); iota(ord.begin(), ord.end(), 0);\n        auto canCover = [&](int k)->int {\n            if (targetCell < 0) return 0;\n            for (int p : prob->shapes[k].coverShiftsByCell[targetCell]) if (active[k][p]) return 1;\n            return 0;\n        };\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b){\n            if (requireCovered == 1) {\n                int ca = canCover(a), cb = canCover(b);\n                if (ca != cb) return ca > cb;\n            }\n            if (activeCount[a] != activeCount[b]) return activeCount[a] < activeCount[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    struct DFSContext {\n        State* st;\n        vector<int> order;\n        vector<int> cur; // current contributions at drilled cells\n        vector<int> assign; // chosen shift per shape id\n        int solutionsLimit;\n        int solutionsFound;\n        vector<int> lastAssignment;\n        vector<int> unionCounts;\n        bool respectTime;\n        int targetCell;     // -1 none\n        int requireCovered; // -1 none, 0 force uncovered, 1 force covered\n        vector<vector<int>> sufAny;\n        vector<vector<int>> sufMust;\n        vector<vector<vector<int>>> *coverDrilledCachePtr;\n        vector<vector<int>> *anyCoverKDPtr;\n        vector<vector<int>> *mustCoverKDPtr;\n\n        DFSContext(State* st_, const vector<int>& order_, int solLim, bool respectTime_,\n                   int targetCell_ = -1, int requireCovered_ = -1)\n            : st(st_), order(order_), solutionsLimit(solLim), solutionsFound(0),\n              respectTime(respectTime_), targetCell(targetCell_), requireCovered(requireCovered_) {\n            int D = (int)st->drilledCells.size();\n            int M = st->M;\n            cur.assign(D, 0);\n            assign.assign(st->M, -1);\n            lastAssignment.assign(st->M, -1);\n            unionCounts.assign(st->N * st->N, 0);\n            coverDrilledCachePtr = &st->coverDrilledCache;\n            anyCoverKDPtr = &st->anyCoverKD;\n            mustCoverKDPtr = &st->mustCoverKD;\n            sufAny.assign(M + 1, vector<int>(D, 0));\n            sufMust.assign(M + 1, vector<int>(D, 0));\n            for (int pos = M - 1; pos >= 0; --pos) {\n                int k = order[pos];\n                for (int d = 0; d < D; ++d) {\n                    sufAny[pos][d] = sufAny[pos + 1][d] + (*anyCoverKDPtr)[k][d];\n                    sufMust[pos][d] = sufMust[pos + 1][d] + (*mustCoverKDPtr)[k][d];\n                }\n            }\n        }\n\n        void recordSolution() {\n            vector<uint8_t> covered(st->N * st->N, 0);\n            for (int pos = 0; pos < st->M; ++pos) {\n                int k = order[pos];\n                int p = assign[k];\n                if (p < 0) return;\n                for (int c : st->prob->shapes[k].shiftsCells[p]) covered[c] = 1;\n            }\n            for (int c = 0; c < st->N * st->N; ++c) if (covered[c]) ++unionCounts[c];\n            lastAssignment = assign;\n            ++solutionsFound;\n        }\n\n        bool viableChoice(int pos, int k, int p) {\n            if (requireCovered == 0 && targetCell >= 0) {\n                for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) return false;\n            }\n            const vector<int>& vDrilled = st->vDrilled;\n            const vector<int>& coverD = (*coverDrilledCachePtr)[k][p];\n            int D = (int)st->drilledCells.size();\n            int ptr = 0;\n            for (int d = 0; d < D; ++d) {\n                int cover = 0;\n                if (ptr < (int)coverD.size() && coverD[ptr] == d) { cover = 1; ++ptr; }\n                int remp = vDrilled[d] - (cur[d] + cover);\n                if (remp < 0) return false;\n                int ub_rem = sufAny[pos + 1][d];\n                int lb_rem = sufMust[pos + 1][d];\n                if (remp < lb_rem) return false;\n                if (remp > ub_rem) return false;\n            }\n            return true;\n        }\n\n        void dfs(int pos) {\n            if (solutionsFound >= solutionsLimit) return;\n            if (respectTime && st->timer.elapsed() > st->timeLimitSec) return;\n            if (pos == st->M) {\n                if (requireCovered == 1 && targetCell >= 0) {\n                    bool cov = false;\n                    for (int t = 0; t < st->M && !cov; ++t) {\n                        int k = order[t];\n                        int p = assign[k];\n                        if (p < 0) continue;\n                        for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) { cov = true; break; }\n                    }\n                    if (!cov) return;\n                }\n                recordSolution();\n                return;\n            }\n            int k = order[pos];\n\n            if (requireCovered == 1 && targetCell >= 0) {\n                bool coveredNow = false;\n                for (int t = 0; t < pos && !coveredNow; ++t) {\n                    int kk = order[t];\n                    int psel = assign[kk];\n                    if (psel < 0) continue;\n                    for (int c : st->prob->shapes[kk].shiftsCells[psel]) if (c == targetCell) { coveredNow = true; break; }\n                }\n                if (!coveredNow) {\n                    bool exists = false;\n                    for (int t = pos; t < st->M && !exists; ++t) {\n                        int kk = order[t];\n                        for (int p2 : st->prob->shapes[kk].coverShiftsByCell[targetCell]) if (st->active[kk][p2]) { exists = true; break; }\n                    }\n                    if (!exists) return;\n                }\n            }\n\n            const int Pk = (int)st->prob->shapes[k].shiftsCells.size();\n            vector<int> candidates;\n            candidates.reserve(st->activeCount[k]);\n            if (requireCovered == 1 && targetCell >= 0) {\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) {\n                    bool cov = false;\n                    for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) { cov = true; break; }\n                    if (cov) candidates.push_back(p);\n                }\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) {\n                    bool cov = false;\n                    for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) { cov = true; break; }\n                    if (!cov) candidates.push_back(p);\n                }\n            } else {\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) candidates.push_back(p);\n            }\n\n            for (int p : candidates) {\n                if (!viableChoice(pos, k, p)) continue;\n                assign[k] = p;\n                const auto& coverD = (*coverDrilledCachePtr)[k][p];\n                for (int d : coverD) ++cur[d];\n                dfs(pos + 1);\n                for (int d : coverD) --cur[d];\n                assign[k] = -1;\n                if (solutionsFound >= solutionsLimit) return;\n                if (respectTime && st->timer.elapsed() > st->timeLimitSec) return;\n            }\n        }\n    };\n\n    void enumerateSolutionsLimited(int L, vector<int>& oneAssignOut, vector<int>& unionCountsOut, int& found) {\n        recomputeCoverageBounds();\n        buildCoverDrilledCache();\n        vector<int> order = chooseOrder();\n        DFSContext ctx(this, order, L, true);\n        ctx.dfs(0);\n        found = ctx.solutionsFound;\n        oneAssignOut = ctx.lastAssignment;\n        unionCountsOut = ctx.unionCounts;\n    }\n\n    // Alternative existence using prepared caches\n    bool existsAlternativeForCellPrepared(int c, int wantStatus) {\n        if (known[c] == 0 && wantStatus == 1) return false;\n        if (known[c] > 0 && wantStatus == 0) return false;\n\n        if (wantStatus == 1) {\n            bool anyCan = false;\n            for (int k = 0; k < M && !anyCan; ++k) {\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) { anyCan = true; break; }\n            }\n            if (!anyCan) return false;\n        }\n        if (wantStatus == 0) {\n            for (int k = 0; k < M; ++k) {\n                int coverCnt = 0;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) ++coverCnt;\n                if (activeCount[k] > 0 && coverCnt == activeCount[k]) return false;\n            }\n        }\n\n        int requireCovered = (wantStatus == 1) ? 1 : 0;\n        vector<int> order = chooseOrder(c, requireCovered);\n        DFSContext ctx(this, order, 1, true, c, requireCovered);\n        ctx.dfs(0);\n        return ctx.solutionsFound >= 1;\n    }\n\n    vector<uint8_t> buildUnionFromAssignment(const vector<int>& assign) {\n        vector<uint8_t> covered(N*N, 0);\n        for (int k = 0; k < M; ++k) {\n            int p = assign[k];\n            if (p < 0) continue;\n            for (int c : prob->shapes[k].shiftsCells[p]) covered[c] = 1;\n        }\n        return covered;\n    }\n\n    // Compute min/max cover per cell given current active sets\n    void computeMinMaxCover(vector<int>& minCover, vector<int>& maxCover) {\n        minCover.assign(N*N, 0);\n        maxCover.assign(N*N, 0);\n        for (int k = 0; k < M; ++k) {\n            if (activeCount[k] <= 0) continue;\n            // For each cell c that is covered by some shift, count coverActive\n            // Approach: iterate all cells 0..N*N and count active covering shifts\n            for (int c = 0; c < N*N; ++c) {\n                int coverCnt = 0;\n                const auto& vec = prob->shapes[k].coverShiftsByCell[c];\n                if (vec.empty()) continue;\n                for (int p : vec) if (active[k][p]) ++coverCnt;\n                if (coverCnt > 0) ++maxCover[c];\n                if (coverCnt == activeCount[k]) ++minCover[c];\n            }\n        }\n    }\n\n    // Choose a cell with maximum elimination potential (sum of active covering shifts)\n    int bestCoverageDrillCandidate() {\n        int bestC = -1;\n        int bestScore = -1;\n        for (int c = 0; c < N*N; ++c) {\n            if (known[c] != -1) continue;\n            int score = 0;\n            for (int k = 0; k < M; ++k) {\n                if (activeCount[k] <= 0) continue;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) ++score;\n            }\n            if (score > bestScore) { bestScore = score; bestC = c; }\n        }\n        if (bestC == -1) {\n            // fallback: random unknown\n            vector<int> unknown;\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) unknown.push_back(c);\n            if (!unknown.empty()) bestC = unknown[rng() % unknown.size()];\n        }\n        return bestC;\n    }\n\n    // Drill all remaining cells and return exact union\n    vector<uint8_t> drillAllAndBuildUnion() {\n        for (int c = 0; c < N*N; ++c) {\n            if (opCount >= opLimit - 1) break;\n            if (known[c] == -1) drill_cell(c);\n        }\n        vector<uint8_t> res(N*N, 0);\n        for (int c = 0; c < N*N; ++c) res[c] = (known[c] > 0) ? 1 : 0;\n        return res;\n    }\n\n    pair<vector<uint8_t>, bool> solveUnion() {\n        // Initial coarse drilling grid step based on M\n        int s = max(2, min(4, (int)floor(sqrt((double)N * (double)N / (double)(max(1,M) * 2.0)))));\n        for (int i = 0; i < N; i += s) {\n            for (int j = 0; j < N; j += s) {\n                if (opCount >= opLimit) break;\n                int c = cell_id(i, j, N);\n                if (known[c] == -1) drill_cell(c);\n            }\n        }\n        // Propagate\n        if (!propagateConstraints()) {\n            vector<uint8_t> res = drillAllAndBuildUnion();\n            return {res, true};\n        }\n\n        vector<int> oneAssign, unionCounts;\n        int found = 0;\n\n        while (true) {\n            if (opCount >= opLimit - 1) break;\n            if (timer.elapsed() > timeLimitSec) break;\n\n            // Deterministic classification via min/max cover\n            vector<int> minCover, maxCover;\n            computeMinMaxCover(minCover, maxCover);\n            bool allClassified = true;\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) {\n                if (!(maxCover[c] == 0 || minCover[c] > 0)) { allClassified = false; break; }\n            }\n            if (allClassified) {\n                vector<uint8_t> res(N*N, 0);\n                for (int c = 0; c < N*N; ++c) {\n                    if (known[c] != -1) res[c] = (known[c] > 0);\n                    else res[c] = (minCover[c] > 0) ? 1 : 0;\n                }\n                return {res, true};\n            }\n\n            // Enumerate some solutions for ambiguity guidance\n            enumerateSolutionsLimited(60, oneAssign, unionCounts, found);\n            if (found == 0) {\n                if (!allShapesHaveCandidates()) {\n                    vector<uint8_t> res = drillAllAndBuildUnion();\n                    return {res, true};\n                }\n                // Drill high-potential cell\n                int cPick = bestCoverageDrillCandidate();\n                if (cPick == -1) break;\n                drill_cell(cPick);\n                if (!propagateConstraints()) {\n                    vector<uint8_t> res = drillAllAndBuildUnion();\n                    return {res, true};\n                }\n                continue;\n            }\n\n            // Build base union and ambiguous list limited by min/max cover classification\n            vector<uint8_t> baseUnion = buildUnionFromAssignment(oneAssign);\n            vector<pair<int,int>> cells; // (score, cell)\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) {\n                if (maxCover[c] == 0 || minCover[c] > 0) continue; // already decided\n                int cnt = unionCounts[c];\n                int score = abs(found - 2*cnt);\n                cells.emplace_back(score, c);\n            }\n            sort(cells.begin(), cells.end(), [&](const auto& a, const auto& b){\n                if (a.first != b.first) return a.first < b.first;\n                return a.second < b.second;\n            });\n\n            // Prepare caches once\n            recomputeCoverageBounds();\n            buildCoverDrilledCache();\n\n            bool alternativeFound = false;\n            bool completeScan = true;\n            int ambiguousCell = -1;\n\n            for (auto &pr : cells) {\n                if (timer.elapsed() > timeLimitSec) { completeScan = false; break; }\n                int c = pr.second;\n                int want = baseUnion[c] ? 0 : 1;\n                if (existsAlternativeForCellPrepared(c, want)) {\n                    ambiguousCell = c;\n                    alternativeFound = true;\n                    break;\n                }\n            }\n\n            if (!completeScan) {\n                // Time low: drill a high-potential cell\n                int cPick = bestCoverageDrillCandidate();\n                if (cPick == -1) break;\n                drill_cell(cPick);\n                if (!propagateConstraints()) {\n                    vector<uint8_t> res = drillAllAndBuildUnion();\n                    return {res, true};\n                }\n                continue;\n            }\n\n            if (!alternativeFound) {\n                // Proven unique\n                return {baseUnion, true};\n            } else {\n                drill_cell(ambiguousCell);\n                if (!propagateConstraints()) {\n                    vector<uint8_t> res = drillAllAndBuildUnion();\n                    return {res, true};\n                }\n            }\n        }\n\n        // Fallback: drill remaining cells for correctness\n        vector<uint8_t> res = drillAllAndBuildUnion();\n        return {res, true};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem prob;\n    if (!(cin >> prob.N >> prob.M >> prob.eps)) return 0;\n    prob.shapes.resize(prob.M);\n    for (int k = 0; k < prob.M; ++k) {\n        prob.shapes[k].id = k;\n        int d; cin >> d;\n        vector<pair<int,int>> offs;\n        offs.reserve(d);\n        int minI = INT_MAX, minJ = INT_MAX, maxI = INT_MIN, maxJ = INT_MIN;\n        for (int t = 0; t < d; ++t) {\n            int ii, jj; cin >> ii >> jj;\n            offs.emplace_back(ii, jj);\n            minI = min(minI, ii);\n            minJ = min(minJ, jj);\n            maxI = max(maxI, ii);\n            maxJ = max(maxJ, jj);\n        }\n        for (auto &p : offs) { p.first -= minI; p.second -= minJ; }\n        prob.shapes[k].offsets = offs;\n        prob.shapes[k].H = maxI - minI + 1;\n        prob.shapes[k].W = maxJ - minJ + 1;\n    }\n\n    // Precompute all shifts and mapping\n    for (int k = 0; k < prob.M; ++k) {\n        auto &S = prob.shapes[k];\n        int maxDI = prob.N - S.H;\n        int maxDJ = prob.N - S.W;\n        for (int di = 0; di <= maxDI; ++di) {\n            for (int dj = 0; dj <= maxDJ; ++dj) {\n                vector<int> cells;\n                cells.reserve(S.offsets.size());\n                for (auto [oi, oj] : S.offsets) {\n                    int i = di + oi;\n                    int j = dj + oj;\n                    cells.push_back(cell_id(i, j, prob.N));\n                }\n                sort(cells.begin(), cells.end());\n                S.shiftsCells.push_back(move(cells));\n            }\n        }\n        S.coverShiftsByCell.assign(prob.N * prob.N, {});\n        for (int p = 0; p < (int)S.shiftsCells.size(); ++p) {\n            for (int c : S.shiftsCells[p]) S.coverShiftsByCell[c].push_back(p);\n        }\n    }\n\n    State st(&prob);\n\n    auto resPair = st.solveUnion();\n    vector<uint8_t> unionSet = resPair.first;\n\n    // Build answer vector; ensure inclusion of drilled positives\n    vector<int> ans;\n    ans.reserve(st.N * st.N);\n    for (int c = 0; c < st.N * st.N; ++c) if (unionSet[c]) ans.push_back(c);\n    for (int idx = 0; idx < (int)st.drilledCells.size(); ++idx) {\n        int c = st.drilledCells[idx];\n        if (st.known[c] > 0 && !unionSet[c]) { ans.push_back(c); unionSet[c] = 1; }\n    }\n    sort(ans.begin(), ans.end());\n    ans.erase(unique(ans.begin(), ans.end()), ans.end());\n\n    auto print_answer = [&](const vector<int>& cells){\n        cout << \"a \" << cells.size();\n        for (int c : cells) {\n            auto [i,j] = cell_ij(c, st.N);\n            cout << \" \" << i << \" \" << j;\n        }\n        cout << \"\\n\";\n        cout.flush();\n    };\n\n    print_answer(ans);\n    string resp;\n    if (!(cin >> resp)) return 0;\n\n    if (resp == \"0\") {\n        // Recovery: drill all remaining cells and re-answer exactly\n        vector<uint8_t> exactUnion = st.drillAllAndBuildUnion();\n        vector<int> ans2;\n        for (int c = 0; c < st.N * st.N; ++c) if (exactUnion[c]) ans2.push_back(c);\n        print_answer(ans2);\n        if (!(cin >> resp)) return 0;\n    }\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Greedy water-filling for one day: full-width stripes, minimize deficiency\n// Produces heights k[i] >= 1 with sum k[i] = W.\nstatic vector<int> compute_heights_one_day(int W, const vector<int>& a_sorted) {\n    int N = (int)a_sorted.size();\n    struct MaxItem { int s; int i; bool operator<(const MaxItem& o) const { return s < o.s; } };\n    struct MinItem { int h; int i; bool operator<(const MinItem& o) const { if (h != o.h) return h > o.h; return i > o.i; } };\n\n    vector<int> k(N, 1);            // base height 1 for each rectangle\n    int R = W - N;                  // remaining height units to distribute\n    priority_queue<MaxItem> pq;\n    for (int i = 0; i < N; i++) {\n        int s = a_sorted[i] - W;    // shortage after base height=1\n        if (s < 0) s = 0;\n        pq.push(MaxItem{s, i});\n    }\n    while (R > 0 && !pq.empty()) {\n        MaxItem cur = pq.top(); pq.pop();\n        if (cur.s <= 0) break; // no more benefit\n        k[cur.i] += 1;\n        cur.s -= W;\n        if (cur.s < 0) cur.s = 0;\n        pq.push(cur);\n        R--;\n    }\n    // If leftover height units remain (all shortages eliminated), distribute evenly to smallest heights\n    if (R > 0) {\n        priority_queue<MinItem> minpq;\n        for (int i = 0; i < N; i++) minpq.push(MinItem{k[i], i});\n        while (R > 0) {\n            auto cur = minpq.top(); minpq.pop();\n            cur.h += 1;\n            k[cur.i] = cur.h;\n            minpq.push(cur);\n            R--;\n        }\n    }\n    // Safety: ensure sum == W\n    int sumh = 0;\n    for (int h : k) sumh += h;\n    if (sumh != W && N > 0) {\n        // Adjust last minimally (shouldn't happen)\n        k.back() += (W - sumh);\n    }\n    return k;\n}\n\n// Compute boundary positions (prefix sums excluding W) from heights (physical order).\nstatic vector<int> boundaries_from_heights(const vector<int>& H) {\n    int N = (int)H.size();\n    vector<int> B;\n    B.reserve(max(0, N - 1));\n    int acc = 0;\n    for (int i = 0; i + 1 < N; i++) {\n        acc += H[i];\n        B.push_back(acc);\n    }\n    return B;\n}\n\n// Count matches between two boundary sets (exact coordinate equality).\nstatic int count_matches(const vector<int>& B1, const vector<int>& B2) {\n    int i = 0, j = 0, m = (int)B1.size(), n = (int)B2.size(), cnt = 0;\n    while (i < m && j < n) {\n        if (B1[i] == B2[j]) { cnt++; i++; j++; }\n        else if (B1[i] < B2[j]) i++;\n        else j++;\n    }\n    return cnt;\n}\n\n// Subset-sum with bitset + reconstruction. Reorders 'rem' implicitly by using an index order.\n// If prefer_more is true, prefer taking items when both take/no-take are possible (more items).\n// If prefer_more is false, prefer not taking when both are possible (fewer items).\n// The order of items in DP also affects cardinality: we choose ascending when prefer_more, descending otherwise.\nstatic bool take_subset_sum_bitset(vector<int>& rem, int gap, vector<int>& seq, bool prefer_more) {\n    if (gap <= 0) return (gap == 0);\n    int m = (int)rem.size();\n    if (m == 0) return false;\n\n    // Order indices\n    vector<int> idx(m);\n    iota(idx.begin(), idx.end(), 0);\n    if (prefer_more) {\n        sort(idx.begin(), idx.end(), [&](int x, int y){ return rem[x] < rem[y]; }); // ascending for more items\n    } else {\n        sort(idx.begin(), idx.end(), [&](int x, int y){ return rem[x] > rem[y]; }); // descending for fewer items\n    }\n    vector<int> w(m), origIndex(m);\n    for (int t = 0; t < m; t++) { w[t] = rem[idx[t]]; origIndex[t] = idx[t]; }\n\n    int G = gap;\n    int BS = G + 1;\n    int wordN = (BS + 63) >> 6;\n    vector<vector<unsigned long long>> dp(m + 1, vector<unsigned long long>(wordN, 0ULL));\n    auto setbit = [&](vector<unsigned long long>& b, int pos){\n        b[pos >> 6] |= (1ULL << (pos & 63));\n    };\n    auto getbit = [&](const vector<unsigned long long>& b, int pos)->bool {\n        return (b[pos >> 6] >> (pos & 63)) & 1ULL;\n    };\n    setbit(dp[0], 0);\n\n    for (int t = 0; t < m; t++) {\n        dp[t + 1] = dp[t];\n        int shift = w[t];\n        if (shift <= G) {\n            int fullShiftWords = shift >> 6;\n            int bitShift = shift & 63;\n            for (int wi = wordN - 1; wi >= 0; --wi) {\n                unsigned long long v = 0;\n                int srcIdx = wi - fullShiftWords;\n                if (srcIdx >= 0 && srcIdx < wordN) {\n                    v |= (dp[t][srcIdx] << bitShift);\n                    if (bitShift && srcIdx > 0) {\n                        v |= (dp[t][srcIdx - 1] >> (64 - bitShift));\n                    }\n                }\n                dp[t + 1][wi] |= v;\n            }\n        }\n    }\n\n    if (!getbit(dp[m], G)) return false;\n\n    vector<char> chosen(m, 0);\n    int s = G;\n    for (int t = m; t >= 1; --t) {\n        int wt = w[t - 1];\n        bool can_not_take = getbit(dp[t - 1], s);\n        bool can_take = (s - wt >= 0) && getbit(dp[t - 1], s - wt);\n        if (can_not_take && can_take) {\n            if (prefer_more) {\n                chosen[t - 1] = 1; s -= wt;\n            } else {\n                // prefer not take\n            }\n        } else if (!can_not_take && can_take) {\n            chosen[t - 1] = 1; s -= wt;\n        } else {\n            // can_not_take true, can_take false -> do nothing\n            // both false shouldn't happen\n        }\n    }\n\n    // Map chosen indices to original rem indices\n    vector<int> chosenOrig;\n    chosenOrig.reserve(m);\n    for (int t = 0; t < m; t++) if (chosen[t]) chosenOrig.push_back(origIndex[t]);\n\n    // Append their weights to seq in ascending order to keep deterministic\n    vector<int> chosenWeights;\n    chosenWeights.reserve(chosenOrig.size());\n    for (int id : chosenOrig) chosenWeights.push_back(rem[id]);\n    sort(chosenWeights.begin(), chosenWeights.end());\n    for (int wv : chosenWeights) seq.push_back(wv);\n\n    // Remove selected items from rem\n    vector<char> mark(m, 0);\n    for (int id : chosenOrig) mark[id] = 1;\n    vector<int> rem2; rem2.reserve(m - (int)chosenOrig.size());\n    for (int i = 0; i < m; i++) if (!mark[i]) rem2.push_back(rem[i]);\n    rem.swap(rem2);\n\n    return true;\n}\n\n// Arrange heights to align with 'targets' (sorted boundary list) via sequential subset-sum.\n// Does not change multiset of heights; keeps sum == W.\n// prefer_more: see take_subset_sum_bitset.\nstatic vector<int> arrange_align_subset_pref(const vector<int>& heights, const vector<int>& targets, int W, bool prefer_more) {\n    vector<int> rem = heights;\n    sort(rem.begin(), rem.end()); // deterministic\n    vector<int> seq; seq.reserve(rem.size());\n    int pos = 0;\n    for (int b : targets) {\n        if (b <= pos) continue;\n        int gap = b - pos;\n        if (take_subset_sum_bitset(rem, gap, seq, prefer_more)) {\n            pos = b;\n            if (rem.empty()) break;\n        }\n    }\n    for (int h : rem) seq.push_back(h);\n    // Safety\n    int sum = 0; for (int h : seq) sum += h;\n    if (sum != W && !seq.empty()) seq.back() += (W - sum);\n    return seq;\n}\n\n// Two-sided alignment: prioritize matching intersection of prev/next boundaries as anchors, then within each interval\n// attempt to match remaining boundaries (from prev-only and next-only). Heights multiset remains unchanged.\n// prefer_more parameter forwarded to subset-sum.\nstatic vector<int> align_two_sided_pref(const vector<int>& heights, const vector<int>& Bprev, const vector<int>& Bnext, int W, bool prefer_more) {\n    vector<int> rem = heights;\n    sort(rem.begin(), rem.end());\n    vector<int> seq; seq.reserve(rem.size());\n    int pos = 0;\n\n    vector<char> inPrev(W + 1, 0), inNext(W + 1, 0);\n    for (int b : Bprev) if (0 <= b && b <= W) inPrev[b] = 1;\n    for (int b : Bnext) if (0 <= b && b <= W) inNext[b] = 1;\n\n    // Match anchors at intersection\n    vector<int> anchors;\n    anchors.push_back(0);\n    for (int x = 1; x < W; x++) if (inPrev[x] && inNext[x]) {\n        int gap = x - pos;\n        if (gap > 0 && take_subset_sum_bitset(rem, gap, seq, prefer_more)) {\n            pos = x;\n            anchors.push_back(pos);\n            if (rem.empty()) break;\n        }\n    }\n    anchors.push_back(W);\n\n    // Build prev-only and next-only lists\n    vector<int> prevOnly, nextOnly;\n    for (int b : Bprev) if (b > 0 && b < W && !inNext[b]) prevOnly.push_back(b);\n    for (int b : Bnext) if (b > 0 && b < W && !inPrev[b]) nextOnly.push_back(b);\n\n    // Process segments\n    for (int sidx = 0; sidx + 1 < (int)anchors.size(); sidx++) {\n        int segStart = anchors[sidx];\n        int segEnd = anchors[sidx + 1];\n        pos = segStart;\n\n        vector<int> Tseg;\n        auto it1 = lower_bound(prevOnly.begin(), prevOnly.end(), segStart + 1);\n        while (it1 != prevOnly.end() && *it1 < segEnd) { Tseg.push_back(*it1); ++it1; }\n        auto it2 = lower_bound(nextOnly.begin(), nextOnly.end(), segStart + 1);\n        while (it2 != nextOnly.end() && *it2 < segEnd) { Tseg.push_back(*it2); ++it2; }\n        sort(Tseg.begin(), Tseg.end());\n        Tseg.erase(unique(Tseg.begin(), Tseg.end()), Tseg.end());\n\n        for (int b : Tseg) {\n            if (b <= pos) continue;\n            int gap = b - pos;\n            if (take_subset_sum_bitset(rem, gap, seq, prefer_more)) {\n                pos = b;\n            }\n            if (rem.empty()) break;\n        }\n        if (rem.empty()) break;\n    }\n\n    // Append remaining items\n    for (int h : rem) seq.push_back(h);\n\n    int sum = 0; for (int h : seq) sum += h;\n    if (sum != W && !seq.empty()) seq.back() += (W - sum);\n\n    return seq;\n}\n\n// Build rectangles from heights (physical order) and assign to reservations by ascending area.\n// Returns vector of rectangles for day: each as {i0, j0, i1, j1}.\nstatic vector<array<int,4>> build_rectangles_and_assign(int W, const vector<int>& heights, const vector<int>& a_sorted) {\n    int N = (int)heights.size();\n    // Compute physical rectangles for each stripe index t (0..N-1)\n    vector<array<int,4>> rect_by_index(N);\n    int cur = 0;\n    for (int t = 0; t < N; t++) {\n        int h = heights[t];\n        int i0 = cur, i1 = cur + h;\n        if (i0 < 0) i0 = 0;\n        if (i1 > W) i1 = W;\n        rect_by_index[t] = {i0, 0, i1, W};\n        cur = i1;\n    }\n    if (cur != W && N > 0) {\n        rect_by_index[N - 1][2] += (W - cur);\n        if (rect_by_index[N - 1][2] < rect_by_index[N - 1][0]) rect_by_index[N - 1][2] = rect_by_index[N - 1][0] + 1;\n        if (rect_by_index[N - 1][2] > W) rect_by_index[N - 1][2] = W;\n    }\n\n    // Assign reservations by pairing ascending a with ascending stripe heights.\n    vector<pair<int,int>> height_with_idx;\n    height_with_idx.reserve(N);\n    for (int t = 0; t < N; t++) height_with_idx.emplace_back(heights[t], t);\n    sort(height_with_idx.begin(), height_with_idx.end()); // ascending by height\n\n    vector<array<int,4>> rect_out(N);\n    for (int k = 0; k < N; k++) {\n        int stripe_idx = height_with_idx[k].second;\n        rect_out[k] = rect_by_index[stripe_idx];\n    }\n    return rect_out;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int W, D, N;\n    if (!(cin >> W >> D >> N)) return 0;\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    // Heights per day via water-filling (deficiency-minimizing), sum to W.\n    vector<vector<int>> heightsByDay(D);\n    for (int d = 0; d < D; d++) {\n        heightsByDay[d] = compute_heights_one_day(W, a[d]);\n    }\n\n    // Initial arrangements\n    vector<vector<int>> dayHeights(D);\n\n    // Day 0: simple baseline (sorted ascending).\n    dayHeights[0] = heightsByDay[0];\n    sort(dayHeights[0].begin(), dayHeights[0].end());\n\n    // Forward pass: align each day to previous day's boundaries (single-sided with two preferences).\n    for (int d = 1; d < D; d++) {\n        vector<int> prevB = boundaries_from_heights(dayHeights[d - 1]);\n        vector<int> c1 = arrange_align_subset_pref(heightsByDay[d], prevB, W, false);\n        vector<int> c2 = arrange_align_subset_pref(heightsByDay[d], prevB, W, true);\n        vector<int> b1 = boundaries_from_heights(c1);\n        vector<int> b2 = boundaries_from_heights(c2);\n        int m1 = count_matches(b1, prevB);\n        int m2 = count_matches(b2, prevB);\n        dayHeights[d] = (m2 > m1 ? move(c2) : move(c1));\n    }\n\n    auto score_with_neighbors = [&](const vector<int>& seq, const vector<int>& Bprev, const vector<int>& Bnext) -> pair<int,pair<int,int>> {\n        vector<int> Bcur = boundaries_from_heights(seq);\n        int mp = (Bprev.empty() ? 0 : count_matches(Bcur, Bprev));\n        int mn = (Bnext.empty() ? 0 : count_matches(Bcur, Bnext));\n        return {mp + mn, {mp, mn}};\n    };\n\n    // Iterative two-sided refinement: a couple of sweeps.\n    int sweeps = 2;\n    for (int sw = 0; sw < sweeps; sw++) {\n        // Forward sweep\n        for (int d = 0; d < D; d++) {\n            vector<int> Bprev = (d > 0) ? boundaries_from_heights(dayHeights[d - 1]) : vector<int>();\n            vector<int> Bnext = (d + 1 < D) ? boundaries_from_heights(dayHeights[d + 1]) : vector<int>();\n            auto curScore = score_with_neighbors(dayHeights[d], Bprev, Bnext);\n\n            // Build union of targets\n            vector<int> U = Bprev;\n            U.insert(U.end(), Bnext.begin(), Bnext.end());\n            sort(U.begin(), U.end());\n            U.erase(unique(U.begin(), U.end()), U.end());\n\n            vector<vector<int>> cands;\n            cands.reserve(6);\n            cands.push_back(align_two_sided_pref(heightsByDay[d], Bprev, Bnext, W, false));\n            cands.push_back(align_two_sided_pref(heightsByDay[d], Bprev, Bnext, W, true));\n            cands.push_back(arrange_align_subset_pref(heightsByDay[d], Bprev, W, false));\n            cands.push_back(arrange_align_subset_pref(heightsByDay[d], Bprev, W, true));\n            cands.push_back(arrange_align_subset_pref(heightsByDay[d], U, W, false));\n            cands.push_back(arrange_align_subset_pref(heightsByDay[d], U, W, true));\n\n            int bestIdx = -1;\n            pair<int,pair<int,int>> bestScore = curScore;\n            for (int i = 0; i < (int)cands.size(); i++) {\n                auto sc = score_with_neighbors(cands[i], Bprev, Bnext);\n                if (sc.first > bestScore.first) {\n                    bestScore = sc; bestIdx = i;\n                } else if (sc.first == bestScore.first) {\n                    // Optional tiebreaker: prefer more matches with prev (affects L_d directly)\n                    if (sc.second.first > bestScore.second.first) {\n                        bestScore = sc; bestIdx = i;\n                    }\n                }\n            }\n            if (bestIdx != -1) dayHeights[d] = move(cands[bestIdx]);\n        }\n        // Backward sweep\n        for (int d = D - 1; d >= 0; d--) {\n            vector<int> Bprev = (d > 0) ? boundaries_from_heights(dayHeights[d - 1]) : vector<int>();\n            vector<int> Bnext = (d + 1 < D) ? boundaries_from_heights(dayHeights[d + 1]) : vector<int>();\n            auto curScore = score_with_neighbors(dayHeights[d], Bprev, Bnext);\n\n            vector<int> U = Bprev;\n            U.insert(U.end(), Bnext.begin(), Bnext.end());\n            sort(U.begin(), U.end());\n            U.erase(unique(U.begin(), U.end()), U.end());\n\n            vector<vector<int>> cands;\n            cands.reserve(6);\n            cands.push_back(align_two_sided_pref(heightsByDay[d], Bprev, Bnext, W, false));\n            cands.push_back(align_two_sided_pref(heightsByDay[d], Bprev, Bnext, W, true));\n            cands.push_back(arrange_align_subset_pref(heightsByDay[d], Bnext, W, false));\n            cands.push_back(arrange_align_subset_pref(heightsByDay[d], Bnext, W, true));\n            cands.push_back(arrange_align_subset_pref(heightsByDay[d], U, W, false));\n            cands.push_back(arrange_align_subset_pref(heightsByDay[d], U, W, true));\n\n            int bestIdx = -1;\n            pair<int,pair<int,int>> bestScore = curScore;\n            for (int i = 0; i < (int)cands.size(); i++) {\n                auto sc = score_with_neighbors(cands[i], Bprev, Bnext);\n                if (sc.first > bestScore.first) {\n                    bestScore = sc; bestIdx = i;\n                } else if (sc.first == bestScore.first) {\n                    // In backward sweep, prefer matches with next (affects L_{d+1})\n                    if (sc.second.second > bestScore.second.second) {\n                        bestScore = sc; bestIdx = i;\n                    }\n                }\n            }\n            if (bestIdx != -1) dayHeights[d] = move(cands[bestIdx]);\n        }\n    }\n\n    // Output rectangles for each day based on final heights, assign to reservations by ascending area.\n    for (int d = 0; d < D; d++) {\n        vector<array<int,4>> rects = build_rectangles_and_assign(W, dayHeights[d], a[d]);\n        for (int k = 0; k < N; k++) {\n            auto &r = rects[k];\n            int i0 = max(0, min(W, r[0]));\n            int j0 = max(0, min(W, r[1]));\n            int i1 = max(0, min(W, r[2]));\n            int j1 = max(0, min(W, r[3]));\n            if (i1 <= i0) i1 = min(W, i0 + 1);\n            if (j1 <= j0) j1 = min(W, j0 + 1);\n            cout << i0 << ' ' << j0 << ' ' << i1 << ' ' << j1 << '\\n';\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic const ll MOD = 998244353LL;\n\ninline ll cell_gain(ll rcur, int sval) {\n    return ((ll)sval >= (MOD - rcur)) ? ((ll)sval - MOD) : (ll)sval;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto T0 = chrono::steady_clock::now();\n    auto elapsed_ms = [&](){\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - T0).count();\n    };\n    const long long TIME_LIMIT_MS = 1950;\n\n    int N, M, K;\n    if (!(cin >> N >> M >> K)) return 0;\n\n    const int SZ = N * N; // 81\n    vector<ll> r0(SZ), r(SZ);\n    for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) { ll x; cin >> x; r0[i*N+j] = x % MOD; }\n    r = r0;\n\n    vector<array<int, 9>> stamp(M);\n    for (int m = 0; m < M; ++m) {\n        for (int u = 0; u < 3; ++u) for (int v = 0; v < 3; ++v) {\n            int x; cin >> x;\n            stamp[m][u*3+v] = x;\n        }\n    }\n\n    const int P = N - 2;        // 7\n    const int POS_CNT = P * P;  // 49\n    const int OPS = M * POS_CNT;// 980\n\n    vector<int> pos_p(POS_CNT), pos_q(POS_CNT);\n    for (int p = 0, idx = 0; p < P; ++p) for (int q = 0; q < P; ++q, ++idx) pos_p[idx]=p, pos_q[idx]=q;\n\n    vector<array<int, 9>> op_cells(OPS);\n    vector<array<int, 9>> op_svals(OPS);\n    vector<int> op_m(OPS), op_p(OPS), op_q(OPS), op_pos(OPS);\n    for (int m = 0; m < M; ++m) {\n        for (int pos = 0; pos < POS_CNT; ++pos) {\n            int p = pos_p[pos], q = pos_q[pos];\n            int op = m * POS_CNT + pos;\n            op_m[op] = m; op_p[op] = p; op_q[op] = q; op_pos[op] = pos;\n            for (int u = 0; u < 3; ++u) for (int v = 0; v < 3; ++v) {\n                int k = u*3+v;\n                int i = p + u, j = q + v;\n                op_cells[op][k] = i * N + j;\n                op_svals[op][k] = stamp[m][k];\n            }\n        }\n    }\n\n    // Precompute overlap operations list for each op:\n    vector<vector<int>> overlOps(OPS);\n    overlOps.assign(OPS, {});\n    for (int op = 0; op < OPS; ++op) {\n        int p = op_p[op], q = op_q[op];\n        overlOps[op].reserve(25 * M);\n        for (int dp = -2; dp <= 2; ++dp) {\n            int p2 = p + dp; if (p2 < 0 || p2 >= P) continue;\n            for (int dq = -2; dq <= 2; ++dq) {\n                int q2 = q + dq; if (q2 < 0 || q2 >= P) continue;\n                int pos2 = p2 * P + q2;\n                for (int m2 = 0; m2 < M; ++m2) {\n                    int op2 = m2 * POS_CNT + pos2;\n                    overlOps[op].push_back(op2);\n                }\n            }\n        }\n    }\n\n    auto apply_op = [&](vector<ll>& board, int op){\n        const auto &cells = op_cells[op];\n        const auto &svals = op_svals[op];\n        ll nr;\n        nr = board[cells[0]] + (ll)svals[0]; if (nr >= MOD) nr -= MOD; board[cells[0]] = nr;\n        nr = board[cells[1]] + (ll)svals[1]; if (nr >= MOD) nr -= MOD; board[cells[1]] = nr;\n        nr = board[cells[2]] + (ll)svals[2]; if (nr >= MOD) nr -= MOD; board[cells[2]] = nr;\n        nr = board[cells[3]] + (ll)svals[3]; if (nr >= MOD) nr -= MOD; board[cells[3]] = nr;\n        nr = board[cells[4]] + (ll)svals[4]; if (nr >= MOD) nr -= MOD; board[cells[4]] = nr;\n        nr = board[cells[5]] + (ll)svals[5]; if (nr >= MOD) nr -= MOD; board[cells[5]] = nr;\n        nr = board[cells[6]] + (ll)svals[6]; if (nr >= MOD) nr -= MOD; board[cells[6]] = nr;\n        nr = board[cells[7]] + (ll)svals[7]; if (nr >= MOD) nr -= MOD; board[cells[7]] = nr;\n        nr = board[cells[8]] + (ll)svals[8]; if (nr >= MOD) nr -= MOD; board[cells[8]] = nr;\n    };\n\n    auto compute_gain_for_op = [&](const vector<ll>& board, int op)->ll{\n        const auto &cells = op_cells[op];\n        const auto &svals = op_svals[op];\n        ll sum = 0;\n        sum += cell_gain(board[cells[0]], svals[0]);\n        sum += cell_gain(board[cells[1]], svals[1]);\n        sum += cell_gain(board[cells[2]], svals[2]);\n        sum += cell_gain(board[cells[3]], svals[3]);\n        sum += cell_gain(board[cells[4]], svals[4]);\n        sum += cell_gain(board[cells[5]], svals[5]);\n        sum += cell_gain(board[cells[6]], svals[6]);\n        sum += cell_gain(board[cells[7]], svals[7]);\n        sum += cell_gain(board[cells[8]], svals[8]);\n        return sum;\n    };\n\n    auto compute_gain_all = [&](const vector<ll>& board, vector<ll>& gain){\n        for (int op = 0; op < OPS; ++op) gain[op] = compute_gain_for_op(board, op);\n    };\n\n    vector<ll> gain(OPS, 0);\n    vector<int> overlapMark(OPS, 0);\n    int overlapTag = 1;\n\n    // Temporary remainder buffers for hypothetical updates\n    vector<ll> tmpR(SZ, 0), tmpR2(SZ, 0);\n    vector<int> tmpRMark(SZ, 0), tmpR2Mark(SZ, 0);\n    int tmpRTag = 1, tmpR2Tag = 1;\n\n    // Mark array for dedup in union scanning\n    vector<int> seen(OPS, 0);\n    int seenTag = 1;\n\n    vector<int> selectedOps; selectedOps.reserve(K);\n\n    // Evaluate and apply presses greedily with 3-step lookahead (select op1 only)\n    auto global_refill = [&](){\n        compute_gain_all(r, gain);\n        while ((int)selectedOps.size() < K) {\n            if (elapsed_ms() > TIME_LIMIT_MS) return;\n\n            // Build sorted order by current gain\n            static vector<int> order;\n            order.resize(OPS);\n            iota(order.begin(), order.end(), 0);\n            sort(order.begin(), order.end(), [&](int a, int b){\n                if (gain[a] != gain[b]) return gain[a] > gain[b];\n                return a < b;\n            });\n\n            // Dynamic candidate count and whether to use triple lookahead\n            bool useTriple = (elapsed_ms() < TIME_LIMIT_MS * 0.65);\n            int T = useTriple ? 96 : 196;\n            if (T > OPS) T = OPS;\n\n            ll bestCombined = LLONG_MIN;\n            ll bestG1 = LLONG_MIN;\n            int bestOp = -1;\n\n            for (int idx = 0; idx < T; ++idx) {\n                int op1 = order[idx];\n                ll g1 = gain[op1];\n\n                // Mark overlapped ops for op1\n                ++overlapTag;\n                for (int t : overlOps[op1]) overlapMark[t] = overlapTag;\n\n                // Candidate op2: best unaffected base gain\n                int op2_un = -1; ll g2_un = LLONG_MIN;\n                for (int j = 0; j < OPS; ++j) {\n                    int cand = order[j];\n                    if (overlapMark[cand] != overlapTag) {\n                        op2_un = cand; g2_un = gain[cand];\n                        break;\n                    }\n                }\n\n                // Hypothetical apply op1: compute r' for its 9 cells\n                ++tmpRTag;\n                const auto &cells1 = op_cells[op1];\n                const auto &svals1 = op_svals[op1];\n                for (int k = 0; k < 9; ++k) {\n                    int c = cells1[k];\n                    ll nr = r[c] + (ll)svals1[k];\n                    if (nr >= MOD) nr -= MOD;\n                    tmpR[c] = nr;\n                    tmpRMark[c] = tmpRTag;\n                }\n\n                // Top overlapped op2 candidates (evaluate under r'): keep top 2\n                ll topG2a = LLONG_MIN, topG2b = LLONG_MIN;\n                int topOp2a = -1, topOp2b = -1;\n                for (int t : overlOps[op1]) {\n                    ll sum = 0;\n                    const auto &cells = op_cells[t];\n                    const auto &svals = op_svals[t];\n                    // compute under r'\n                    ll rr;\n                    rr = (tmpRMark[cells[0]] == tmpRTag) ? tmpR[cells[0]] : r[cells[0]];\n                    sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                    rr = (tmpRMark[cells[1]] == tmpRTag) ? tmpR[cells[1]] : r[cells[1]];\n                    sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                    rr = (tmpRMark[cells[2]] == tmpRTag) ? tmpR[cells[2]] : r[cells[2]];\n                    sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                    rr = (tmpRMark[cells[3]] == tmpRTag) ? tmpR[cells[3]] : r[cells[3]];\n                    sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                    rr = (tmpRMark[cells[4]] == tmpRTag) ? tmpR[cells[4]] : r[cells[4]];\n                    sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                    rr = (tmpRMark[cells[5]] == tmpRTag) ? tmpR[cells[5]] : r[cells[5]];\n                    sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                    rr = (tmpRMark[cells[6]] == tmpRTag) ? tmpR[cells[6]] : r[cells[6]];\n                    sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                    rr = (tmpRMark[cells[7]] == tmpRTag) ? tmpR[cells[7]] : r[cells[7]];\n                    sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                    rr = (tmpRMark[cells[8]] == tmpRTag) ? tmpR[cells[8]] : r[cells[8]];\n                    sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n\n                    if (sum > topG2a) { topG2b = topG2a; topOp2b = topOp2a; topG2a = sum; topOp2a = t; }\n                    else if (sum > topG2b && t != topOp2a) { topG2b = sum; topOp2b = t; }\n                }\n\n                // Evaluate combined score\n                ll combined = LLONG_MIN;\n\n                if (useTriple) {\n                    // Build candidate list for op2: up to 3 items\n                    array<int, 3> cand2 = {topOp2a, topOp2b, op2_un};\n                    array<ll, 3> cand2g = {topG2a, topG2b, g2_un};\n\n                    ll best2plus3 = 0;\n                    for (int ci = 0; ci < 3; ++ci) {\n                        int op2 = cand2[ci];\n                        if (op2 < 0) continue;\n                        ll g2 = cand2g[ci];\n\n                        // Mark union of overlapped ops of op1 and op2\n                        ++overlapTag;\n                        for (int t : overlOps[op1]) overlapMark[t] = overlapTag;\n                        for (int t : overlOps[op2]) overlapMark[t] = overlapTag;\n\n                        // Prepare r'' after applying op2 on top of r'\n                        ++tmpR2Tag;\n                        const auto &cells2 = op_cells[op2];\n                        const auto &svals2 = op_svals[op2];\n                        for (int k = 0; k < 9; ++k) {\n                            int c = cells2[k];\n                            ll rr1 = (tmpRMark[c] == tmpRTag) ? tmpR[c] : r[c];\n                            ll nr = rr1 + (ll)svals2[k]; if (nr >= MOD) nr -= MOD;\n                            tmpR2[c] = nr;\n                            tmpR2Mark[c] = tmpR2Tag;\n                        }\n\n                        // Best overlapped third op under r''\n                        ll bestOv3 = LLONG_MIN;\n                        ++seenTag;\n                        for (int t : overlOps[op1]) seen[t] = seenTag;\n                        for (int t : overlOps[op2]) {\n                            if (seen[t] == seenTag) continue; // skip duplicates\n                            seen[t] = seenTag;\n                        }\n                        // Scan union via two loops, computing gain under r''\n                        // First loop: overlOps[op1]\n                        for (int t : overlOps[op1]) {\n                            ll sum = 0;\n                            const auto &cells = op_cells[t];\n                            const auto &svals = op_svals[t];\n                            // pick the correct remainder: tmpR2 > tmpR > r\n                            ll rr;\n                            rr = (tmpR2Mark[cells[0]] == tmpR2Tag) ? tmpR2[cells[0]] :\n                                 (tmpRMark[cells[0]] == tmpRTag ? tmpR[cells[0]] : r[cells[0]]);\n                            sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                            rr = (tmpR2Mark[cells[1]] == tmpR2Tag) ? tmpR2[cells[1]] :\n                                 (tmpRMark[cells[1]] == tmpRTag ? tmpR[cells[1]] : r[cells[1]]);\n                            sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                            rr = (tmpR2Mark[cells[2]] == tmpR2Tag) ? tmpR2[cells[2]] :\n                                 (tmpRMark[cells[2]] == tmpRTag ? tmpR[cells[2]] : r[cells[2]]);\n                            sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                            rr = (tmpR2Mark[cells[3]] == tmpR2Tag) ? tmpR2[cells[3]] :\n                                 (tmpRMark[cells[3]] == tmpRTag ? tmpR[cells[3]] : r[cells[3]]);\n                            sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                            rr = (tmpR2Mark[cells[4]] == tmpR2Tag) ? tmpR2[cells[4]] :\n                                 (tmpRMark[cells[4]] == tmpRTag ? tmpR[cells[4]] : r[cells[4]]);\n                            sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                            rr = (tmpR2Mark[cells[5]] == tmpR2Tag) ? tmpR2[cells[5]] :\n                                 (tmpRMark[cells[5]] == tmpRTag ? tmpR[cells[5]] : r[cells[5]]);\n                            sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                            rr = (tmpR2Mark[cells[6]] == tmpR2Tag) ? tmpR2[cells[6]] :\n                                 (tmpRMark[cells[6]] == tmpRTag ? tmpR[cells[6]] : r[cells[6]]);\n                            sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                            rr = (tmpR2Mark[cells[7]] == tmpR2Tag) ? tmpR2[cells[7]] :\n                                 (tmpRMark[cells[7]] == tmpRTag ? tmpR[cells[7]] : r[cells[7]]);\n                            sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                            rr = (tmpR2Mark[cells[8]] == tmpR2Tag) ? tmpR2[cells[8]] :\n                                 (tmpRMark[cells[8]] == tmpRTag ? tmpR[cells[8]] : r[cells[8]]);\n                            sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n                            if (sum > bestOv3) bestOv3 = sum;\n                        }\n                        // Second loop: overlOps[op2] excluding those already seen\n                        for (int t : overlOps[op2]) {\n                            if (seen[t] != seenTag) continue; // ensure in union\n                            // Actually we marked all in union into seen; We need to recompute for those unique to op2 only\n                            // To avoid recomputing those from op1 again, we can skip if overlapMark==overlapTag in previous step,\n                            // but seenTag used as union marker; Let's compute for all unique in op2 not in op1:\n                            // Keep a different guard:\n                        }\n                        // The above way is cumbersome; instead do a simple dedup: use another marker to compute union properly.\n                        // Simpler approach: recompute second loop only for those not in op1:\n                        ++overlapTag;\n                        for (int t2 : overlOps[op1]) overlapMark[t2] = overlapTag;\n                        for (int t : overlOps[op2]) {\n                            if (overlapMark[t] == overlapTag) continue; // already done in first loop\n                            ll sum = 0;\n                            const auto &cells = op_cells[t];\n                            const auto &svals = op_svals[t];\n                            ll rr;\n                            rr = (tmpR2Mark[cells[0]] == tmpR2Tag) ? tmpR2[cells[0]] :\n                                 (tmpRMark[cells[0]] == tmpRTag ? tmpR[cells[0]] : r[cells[0]]);\n                            sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                            rr = (tmpR2Mark[cells[1]] == tmpR2Tag) ? tmpR2[cells[1]] :\n                                 (tmpRMark[cells[1]] == tmpRTag ? tmpR[cells[1]] : r[cells[1]]);\n                            sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                            rr = (tmpR2Mark[cells[2]] == tmpR2Tag) ? tmpR2[cells[2]] :\n                                 (tmpRMark[cells[2]] == tmpRTag ? tmpR[cells[2]] : r[cells[2]]);\n                            sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                            rr = (tmpR2Mark[cells[3]] == tmpR2Tag) ? tmpR2[cells[3]] :\n                                 (tmpRMark[cells[3]] == tmpRTag ? tmpR[cells[3]] : r[cells[3]]);\n                            sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                            rr = (tmpR2Mark[cells[4]] == tmpR2Tag) ? tmpR2[cells[4]] :\n                                 (tmpRMark[cells[4]] == tmpRTag ? tmpR[cells[4]] : r[cells[4]]);\n                            sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                            rr = (tmpR2Mark[cells[5]] == tmpR2Tag) ? tmpR2[cells[5]] :\n                                 (tmpRMark[cells[5]] == tmpRTag ? tmpR[cells[5]] : r[cells[5]]);\n                            sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                            rr = (tmpR2Mark[cells[6]] == tmpR2Tag) ? tmpR2[cells[6]] :\n                                 (tmpRMark[cells[6]] == tmpRTag ? tmpR[cells[6]] : r[cells[6]]);\n                            sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                            rr = (tmpR2Mark[cells[7]] == tmpR2Tag) ? tmpR2[cells[7]] :\n                                 (tmpRMark[cells[7]] == tmpRTag ? tmpR[cells[7]] : r[cells[7]]);\n                            sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                            rr = (tmpR2Mark[cells[8]] == tmpR2Tag) ? tmpR2[cells[8]] :\n                                 (tmpRMark[cells[8]] == tmpRTag ? tmpR[cells[8]] : r[cells[8]]);\n                            sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n                            if (sum > bestOv3) bestOv3 = sum;\n                        }\n\n                        // Best unaffected third op (base gains) outside union\n                        ll bestUn3 = 0;\n                        for (int j = 0; j < OPS; ++j) {\n                            int cand = order[j];\n                            if (overlapMark[cand] != overlapTag) { // not in union\n                                bestUn3 = max(bestUn3, gain[cand]);\n                                break;\n                            }\n                        }\n\n                        ll best3 = max(bestOv3, bestUn3);\n                        if (best3 < 0) best3 = 0;\n                        ll twoPlusThree = g2 + best3;\n                        if (twoPlusThree < 0) twoPlusThree = 0;\n                        if (twoPlusThree > best2plus3) best2plus3 = twoPlusThree;\n                    }\n\n                    combined = g1 + best2plus3;\n                } else {\n                    // 2-step: best of unaffected vs overlapped under r'\n                    ll bestUn = 0; if (op2_un >= 0 && g2_un > bestUn) bestUn = g2_un;\n                    ll bestOv = LLONG_MIN;\n                    for (int t : overlOps[op1]) {\n                        ll sum = 0;\n                        const auto &cells = op_cells[t];\n                        const auto &svals = op_svals[t];\n                        ll rr;\n                        rr = (tmpRMark[cells[0]] == tmpRTag) ? tmpR[cells[0]] : r[cells[0]];\n                        sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                        rr = (tmpRMark[cells[1]] == tmpRTag) ? tmpR[cells[1]] : r[cells[1]];\n                        sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                        rr = (tmpRMark[cells[2]] == tmpRTag) ? tmpR[cells[2]] : r[cells[2]];\n                        sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                        rr = (tmpRMark[cells[3]] == tmpRTag) ? tmpR[cells[3]] : r[cells[3]];\n                        sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                        rr = (tmpRMark[cells[4]] == tmpRTag) ? tmpR[cells[4]] : r[cells[4]];\n                        sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                        rr = (tmpRMark[cells[5]] == tmpRTag) ? tmpR[cells[5]] : r[cells[5]];\n                        sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                        rr = (tmpRMark[cells[6]] == tmpRTag) ? tmpR[cells[6]] : r[cells[6]];\n                        sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                        rr = (tmpRMark[cells[7]] == tmpRTag) ? tmpR[cells[7]] : r[cells[7]];\n                        sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                        rr = (tmpRMark[cells[8]] == tmpRTag) ? tmpR[cells[8]] : r[cells[8]];\n                        sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n                        if (sum > bestOv) bestOv = sum;\n                    }\n                    ll best2 = max(bestUn, bestOv);\n                    if (best2 < 0) best2 = 0;\n                    combined = g1 + best2;\n                }\n\n                if (combined > bestCombined || (combined == bestCombined && g1 > bestG1)) {\n                    bestCombined = combined;\n                    bestG1 = g1;\n                    bestOp = op1;\n                }\n            }\n\n            if (bestOp == -1) break;\n            if (bestCombined <= 0) break;\n\n            // Apply bestOp and update r and gains incrementally\n            selectedOps.push_back(bestOp);\n            apply_op(r, bestOp);\n\n            // Incrementally recompute gains for overlapping ops only\n            for (int t : overlOps[bestOp]) {\n                gain[t] = compute_gain_for_op(r, t);\n            }\n        }\n    };\n\n    // Initial global search\n    global_refill();\n\n    // Deterministic RNG seeded from input dimensions\n    uint64_t seed = 0x9e3779b97f4a7c15ULL ^ (uint64_t)N * 0xBF58476D1CE4E5B9ULL ^ (uint64_t)M * 0x94D049BB133111EBULL ^ (uint64_t)K;\n    auto rng64 = [&]()->uint64_t {\n        seed ^= seed << 7; seed ^= seed >> 9; seed *= 0xD6E8FEB86659FD93ULL; return seed;\n    };\n    auto rnd_int = [&](int L, int R)->int { return L + (int)(rng64() % (uint64_t)(R - L + 1)); };\n\n    // Local Neighborhood Search (LNS): restricted to anchors in a small rectangle\n    vector<char> allowedMark(OPS, 0);\n    vector<int> keptOpsBuf; keptOpsBuf.reserve(K);\n    vector<int> removedOpsBuf; removedOpsBuf.reserve(K);\n    vector<ll> r_work(SZ);\n    vector<ll> lgain(OPS, LLONG_MIN);\n    vector<int> allowedOps; allowedOps.reserve(OPS);\n\n    vector<ll> tmpR_local(SZ, 0);\n    vector<int> tmpRMark_local(SZ, 0);\n    int tmpRTag_local = 1;\n\n    auto recompute_local_gain_for_op = [&](int op)->ll{\n        const auto &cells = op_cells[op];\n        const auto &svals = op_svals[op];\n        ll sum = 0;\n        sum += cell_gain(r_work[cells[0]], svals[0]);\n        sum += cell_gain(r_work[cells[1]], svals[1]);\n        sum += cell_gain(r_work[cells[2]], svals[2]);\n        sum += cell_gain(r_work[cells[3]], svals[3]);\n        sum += cell_gain(r_work[cells[4]], svals[4]);\n        sum += cell_gain(r_work[cells[5]], svals[5]);\n        sum += cell_gain(r_work[cells[6]], svals[6]);\n        sum += cell_gain(r_work[cells[7]], svals[7]);\n        sum += cell_gain(r_work[cells[8]], svals[8]);\n        return sum;\n    };\n\n    auto sum_region_cells = [&](const vector<ll>& board, int sp, int sq, int RA)->ll {\n        int i0 = sp, i1 = sp + RA + 1;\n        int j0 = sq, j1 = sq + RA + 1;\n        ll sum = 0;\n        for (int i = i0; i <= i1; ++i) for (int j = j0; j <= j1; ++j) sum += board[i*N + j];\n        return sum;\n    };\n\n    vector<int> newOps; newOps.reserve(K);\n\n    // Local refill using 2-step lookahead restricted to allowedMark, with incremental gain updates\n    auto local_refill = [&](int cap, vector<int>& outOps){\n        outOps.clear();\n        allowedOps.clear();\n        for (int op = 0; op < OPS; ++op) if (allowedMark[op]) allowedOps.push_back(op);\n        if (allowedOps.empty() || cap <= 0) return;\n\n        // Initialize local gains\n        for (int op : allowedOps) lgain[op] = recompute_local_gain_for_op(op);\n\n        vector<int> order;\n        order.reserve(allowedOps.size());\n\n        int steps = 0;\n        while (steps < cap) {\n            if (elapsed_ms() > TIME_LIMIT_MS) return;\n\n            order = allowedOps;\n            sort(order.begin(), order.end(), [&](int a, int b){\n                if (lgain[a] != lgain[b]) return lgain[a] > lgain[b];\n                return a < b;\n            });\n\n            int T = min(64, (int)order.size());\n\n            ll bestCombined = LLONG_MIN, bestG1 = LLONG_MIN;\n            int bestOp = -1;\n\n            for (int idx = 0; idx < T; ++idx) {\n                int op1 = order[idx];\n                ll g1 = lgain[op1];\n\n                // Mark overlapped within allowed\n                ++overlapTag;\n                for (int t : overlOps[op1]) if (allowedMark[t]) overlapMark[t] = overlapTag;\n\n                // Best unaffected second\n                ll bestUn = 0;\n                for (int j = 0; j < (int)order.size(); ++j) {\n                    int cand = order[j];\n                    if (overlapMark[cand] != overlapTag) { bestUn = max(bestUn, lgain[cand]); break; }\n                }\n\n                // Hypothetical apply op1 on r_work\n                ++tmpRTag_local;\n                const auto &cells1 = op_cells[op1];\n                const auto &svals1 = op_svals[op1];\n                for (int k = 0; k < 9; ++k) {\n                    int c = cells1[k];\n                    ll nr = r_work[c] + (ll)svals1[k];\n                    if (nr >= MOD) nr -= MOD;\n                    tmpR_local[c] = nr;\n                    tmpRMark_local[c] = tmpRTag_local;\n                }\n\n                // Best overlapped under r'\n                ll bestOv = LLONG_MIN;\n                for (int t : overlOps[op1]) {\n                    if (!allowedMark[t]) continue;\n                    ll sum = 0;\n                    const auto &cells = op_cells[t];\n                    const auto &svals = op_svals[t];\n                    ll rr;\n                    rr = (tmpRMark_local[cells[0]] == tmpRTag_local) ? tmpR_local[cells[0]] : r_work[cells[0]];\n                    sum += ((ll)svals[0] >= (MOD - rr)) ? ((ll)svals[0] - MOD) : (ll)svals[0];\n                    rr = (tmpRMark_local[cells[1]] == tmpRTag_local) ? tmpR_local[cells[1]] : r_work[cells[1]];\n                    sum += ((ll)svals[1] >= (MOD - rr)) ? ((ll)svals[1] - MOD) : (ll)svals[1];\n                    rr = (tmpRMark_local[cells[2]] == tmpRTag_local) ? tmpR_local[cells[2]] : r_work[cells[2]];\n                    sum += ((ll)svals[2] >= (MOD - rr)) ? ((ll)svals[2] - MOD) : (ll)svals[2];\n                    rr = (tmpRMark_local[cells[3]] == tmpRTag_local) ? tmpR_local[cells[3]] : r_work[cells[3]];\n                    sum += ((ll)svals[3] >= (MOD - rr)) ? ((ll)svals[3] - MOD) : (ll)svals[3];\n                    rr = (tmpRMark_local[cells[4]] == tmpRTag_local) ? tmpR_local[cells[4]] : r_work[cells[4]];\n                    sum += ((ll)svals[4] >= (MOD - rr)) ? ((ll)svals[4] - MOD) : (ll)svals[4];\n                    rr = (tmpRMark_local[cells[5]] == tmpRTag_local) ? tmpR_local[cells[5]] : r_work[cells[5]];\n                    sum += ((ll)svals[5] >= (MOD - rr)) ? ((ll)svals[5] - MOD) : (ll)svals[5];\n                    rr = (tmpRMark_local[cells[6]] == tmpRTag_local) ? tmpR_local[cells[6]] : r_work[cells[6]];\n                    sum += ((ll)svals[6] >= (MOD - rr)) ? ((ll)svals[6] - MOD) : (ll)svals[6];\n                    rr = (tmpRMark_local[cells[7]] == tmpRTag_local) ? tmpR_local[cells[7]] : r_work[cells[7]];\n                    sum += ((ll)svals[7] >= (MOD - rr)) ? ((ll)svals[7] - MOD) : (ll)svals[7];\n                    rr = (tmpRMark_local[cells[8]] == tmpRTag_local) ? tmpR_local[cells[8]] : r_work[cells[8]];\n                    sum += ((ll)svals[8] >= (MOD - rr)) ? ((ll)svals[8] - MOD) : (ll)svals[8];\n                    if (sum > bestOv) bestOv = sum;\n                }\n\n                ll best2 = max(bestUn, bestOv);\n                if (best2 < 0) best2 = 0;\n                ll combined = g1 + best2;\n\n                if (combined > bestCombined || (combined == bestCombined && g1 > bestG1)) {\n                    bestCombined = combined;\n                    bestG1 = g1;\n                    bestOp = op1;\n                }\n            }\n\n            if (bestOp == -1) break;\n            if (bestCombined <= 0) break;\n\n            outOps.push_back(bestOp);\n            apply_op(r_work, bestOp);\n\n            // Incrementally update lgain for allowed overlapping ops\n            for (int t : overlOps[bestOp]) if (allowedMark[t]) lgain[t] = recompute_local_gain_for_op(t);\n\n            ++steps;\n        }\n    };\n\n    // LNS loop (time-bounded)\n    for (;;) {\n        if (elapsed_ms() > TIME_LIMIT_MS) break;\n        if (selectedOps.empty()) break;\n\n        // Region size: favor 3 and 4; occasionally 5 if time permits\n        int roll = (int)(rng64() % 100);\n        int RA = (roll < 55 ? 3 : (roll < 95 ? 4 : 5));\n        if (RA > P) RA = P;\n        int sp = rnd_int(0, P - RA);\n        int sq = rnd_int(0, P - RA);\n\n        // Mark allowed ops (anchors in [sp..sp+RA-1] x [sq..sq+RA-1])\n        fill(allowedMark.begin(), allowedMark.end(), 0);\n        for (int p = sp; p < sp + RA; ++p) {\n            for (int q = sq; q < sq + RA; ++q) {\n                int pos = p * P + q;\n                for (int m = 0; m < M; ++m) allowedMark[m * POS_CNT + pos] = 1;\n            }\n        }\n\n        // Split selected ops into kept and removed\n        keptOpsBuf.clear(); removedOpsBuf.clear();\n        for (int op : selectedOps) {\n            if (allowedMark[op]) removedOpsBuf.push_back(op);\n            else keptOpsBuf.push_back(op);\n        }\n        if (removedOpsBuf.empty()) continue;\n\n        // Build r_work: apply kept ops to r0\n        r_work = r0;\n        for (int op : keptOpsBuf) apply_op(r_work, op);\n\n        // Region cell sum before change (on current global r)\n        ll sumBefore = sum_region_cells(r, sp, sq, RA);\n\n        // Capacity for local rebuild\n        int cap = K - (int)keptOpsBuf.size();\n        int capMin = (int)removedOpsBuf.size();\n        int capBound = 2 * RA * RA;\n        cap = max(min(cap, capBound), min(cap, capMin));\n        if (cap <= 0) continue;\n\n        // Local refill\n        local_refill(cap, newOps);\n\n        // Evaluate after local change\n        ll sumAfter = sum_region_cells(r_work, sp, sq, RA);\n        if (sumAfter > sumBefore) {\n            // Accept\n            selectedOps = keptOpsBuf;\n            selectedOps.insert(selectedOps.end(), newOps.begin(), newOps.end());\n            r = r_work;\n\n            // Quick global refill with remaining capacity\n            global_refill();\n        }\n    }\n\n    // Output\n    cout << (int)selectedOps.size() << '\\n';\n    for (int op : selectedOps) {\n        cout << op_m[op] << ' ' << op_p[op] << ' ' << op_q[op] << '\\n';\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 5;\n    static constexpr int TOT = N * N;\n\n    int A[N][N];\n\n    // Grid occupancy: -1 for empty, otherwise container id\n    int occ[N][N];\n\n    // Spawn pointers per receiving row (col = 0)\n    int spawnIdx[N];\n\n    // Large crane state\n    int br = 0, bc = 0; // position\n    int hold = -1;      // container id held or -1\n\n    // Output strings\n    vector<string> S;\n\n    // Delivered tracking\n    bool delivered[TOT];\n    int deliveredCount = 0;\n\n    // Next expected id per dispatch row (row i expects i*N .. i*N+N-1 in order)\n    int nextExpected[N];\n\n    // Source row/index for each id\n    int srcRow[TOT], srcIdx[TOT];\n\n    // Persistent fetch target\n    bool hasFetch = false;\n    int trg_r = -1, trg_c = -1, trg_id = -1;\n\n    Solver() {\n        memset(occ, -1, sizeof(occ));\n        memset(spawnIdx, 0, sizeof(spawnIdx));\n        memset(delivered, 0, sizeof(delivered));\n        S.assign(N, \"\");\n        for (int i = 0; i < N; i++) nextExpected[i] = i * N;\n    }\n\n    void readInput() {\n        int n;\n        if (!(cin >> n)) exit(0); // N is always 5\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                cin >> A[i][j];\n            }\n        }\n        // Precompute sources\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = A[i][j];\n                srcRow[id] = i;\n                srcIdx[id] = j;\n            }\n        }\n    }\n\n    // Step 1: Spawn if possible at receiving gates (col 0)\n    void step1_spawn() {\n        for (int i = 0; i < N; i++) {\n            if (spawnIdx[i] >= N) continue; // no more to spawn for this row\n            if (occ[i][0] == -1) {\n                // Spawn is blocked only if a crane holding a container is at that gate\n                if (!(br == i && bc == 0 && hold != -1)) {\n                    int id = A[i][spawnIdx[i]];\n                    occ[i][0] = id;\n                    spawnIdx[i]++;\n                }\n            }\n        }\n    }\n\n    // Step 3: Dispatch at gates (col 4)\n    void step3_dispatch() {\n        for (int i = 0; i < N; i++) {\n            if (occ[i][4] != -1) {\n                int id = occ[i][4];\n                occ[i][4] = -1;\n                if (!delivered[id]) {\n                    delivered[id] = true;\n                    deliveredCount++;\n                }\n            }\n        }\n        // Update nextExpected per row according to delivered flags\n        for (int r = 0; r < N; r++) {\n            int lo = r * N;\n            int hi = lo + N;\n            while (nextExpected[r] < hi && delivered[nextExpected[r]]) nextExpected[r]++;\n        }\n    }\n\n    inline int manhattan(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    // Choose a new fetch target: returns true if found, and sets (trg_r, trg_c, trg_id)\n    bool chooseFetchTarget() {\n        // Pass 1: look for any in-order containers (id == nextExpected[row of id]), excluding dispatch gates\n        int bestR = -1, bestC = -1, bestID = -1;\n        int bestTravel = INT_MAX;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = occ[r][c];\n                if (id == -1) continue;\n                if (c == N - 1) continue; // ignore dispatch gates\n                int dr = id / N;\n                if (id == nextExpected[dr]) {\n                    int travel = manhattan(br, bc, r, c) + manhattan(r, c, dr, N - 1);\n                    if (travel < bestTravel || (travel == bestTravel && id < bestID)) {\n                        bestTravel = travel;\n                        bestR = r; bestC = c; bestID = id;\n                    }\n                }\n            }\n        }\n        if (bestID != -1) {\n            trg_r = bestR; trg_c = bestC; trg_id = bestID;\n            hasFetch = true;\n            return true;\n        }\n\n        // Pass 2: use weighted cost to discourage inversions at true price 100\n        long long bestCost = (1LL << 60);\n        bestR = bestC = bestID = -1;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = occ[r][c];\n                if (id == -1) continue;\n                if (c == N - 1) continue; // ignore dispatch gates\n                int dr = id / N;\n                int expected = nextExpected[dr];\n                int m = (id >= expected ? (id - expected) : 0);\n                int travel = manhattan(br, bc, r, c) + manhattan(r, c, dr, N - 1);\n                long long cost = (long long)travel + 100LL * m;\n                if (cost < bestCost || (cost == bestCost && id < bestID)) {\n                    bestCost = cost;\n                    bestR = r; bestC = c; bestID = id;\n                }\n            }\n        }\n        if (bestID != -1) {\n            trg_r = bestR; trg_c = bestC; trg_id = bestID;\n            hasFetch = true;\n            return true;\n        }\n        return false;\n    }\n\n    // If we have a non-inorder target but an inorder candidate exists now, retarget to best inorder\n    void maybeRetargetToInOrder() {\n        if (!hasFetch) return;\n        int dr_t = trg_id / N;\n        if (trg_id == nextExpected[dr_t]) return; // already inorder\n        int curBestR = -1, curBestC = -1, curBestID = -1;\n        int curBestTravel = INT_MAX;\n        bool found = false;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = occ[r][c];\n                if (id == -1 || c == N - 1) continue;\n                int dr = id / N;\n                if (id == nextExpected[dr]) {\n                    found = true;\n                    int travel = manhattan(br, bc, r, c) + manhattan(r, c, dr, N - 1);\n                    if (travel < curBestTravel || (travel == curBestTravel && id < curBestID)) {\n                        curBestTravel = travel;\n                        curBestR = r; curBestC = c; curBestID = id;\n                    }\n                }\n            }\n        }\n        if (found) {\n            trg_r = curBestR; trg_c = curBestC; trg_id = curBestID;\n            hasFetch = true;\n        }\n    }\n\n    char stepToward(int tr, int tc) {\n        if (br < tr) return 'D';\n        if (br > tr) return 'U';\n        if (bc < tc) return 'R';\n        if (bc > tc) return 'L';\n        return '.';\n    }\n\n    // Decide the large crane's action\n    char decideAction() {\n        if (hold != -1) {\n            int dr = hold / N;\n            int dc = N - 1; // 4\n            if (br == dr && bc == dc) {\n                // Drop if empty\n                if (occ[br][bc] == -1) return 'Q';\n                // If occupied (very unlikely), wait\n                return '.';\n            } else {\n                return stepToward(dr, dc);\n            }\n        } else {\n            // Opportunistic in-order pick at current cell (avoid dispatch gate)\n            if (occ[br][bc] != -1 && bc != N - 1) {\n                int id = occ[br][bc];\n                int dr = id / N;\n                if (id == nextExpected[dr]) {\n                    return 'P';\n                }\n            }\n\n            // Not holding: ensure fetch target exists and is valid\n            if (hasFetch) {\n                // If target cell no longer contains the target id, invalidate\n                if (!(trg_r >= 0 && trg_r < N && trg_c >= 0 && trg_c < N && occ[trg_r][trg_c] == trg_id)) {\n                    hasFetch = false;\n                }\n            }\n\n            // Possibly retarget to an in-order container if available\n            if (hasFetch) {\n                maybeRetargetToInOrder();\n            }\n\n            if (!hasFetch) {\n                if (!chooseFetchTarget()) {\n                    // No fetchable containers (only at gates): proactive positioning\n                    // Move toward source row of the global next undelivered id (min over rows)\n                    int globalNext = TOT;\n                    for (int r = 0; r < N; r++) {\n                        int hi = (r + 1) * N;\n                        if (nextExpected[r] < hi) {\n                            globalNext = min(globalNext, nextExpected[r]);\n                        }\n                    }\n                    if (globalNext < TOT) {\n                        int sr = srcRow[globalNext];\n                        int sc = 0; // stand at (sr,0) to spawn and pick immediately\n                        if (br == sr && bc == sc) return '.';\n                        return stepToward(sr, sc);\n                    } else {\n                        // Everything done or only gates left (will be dispatched), stay\n                        return '.';\n                    }\n                }\n            }\n\n            // We have a target: move toward it; only pick when exactly on it\n            if (br == trg_r && bc == trg_c) {\n                if (occ[br][bc] == trg_id) {\n                    return 'P';\n                } else {\n                    // Target disappeared; replan next turn\n                    hasFetch = false;\n                    return '.';\n                }\n            } else {\n                return stepToward(trg_r, trg_c);\n            }\n        }\n    }\n\n    // Apply the big crane action to our simulation state\n    void applyBigAction(char act) {\n        if (act == 'U') br--;\n        else if (act == 'D') br++;\n        else if (act == 'L') bc--;\n        else if (act == 'R') bc++;\n        else if (act == 'P') {\n            // Pick: valid if not holding and cell has a container (we avoid dispatch gate in decisions)\n            if (hold == -1 && occ[br][bc] != -1) {\n                hold = occ[br][bc];\n                occ[br][bc] = -1;\n                hasFetch = false; // reset target after picking\n            }\n        } else if (act == 'Q') {\n            // Drop: valid if holding and cell empty\n            if (hold != -1 && occ[br][bc] == -1) {\n                occ[br][bc] = hold;\n                hold = -1;\n            }\n        }\n        // '.' and 'B' not used for big\n    }\n\n    void run() {\n        const int MAX_TURNS = 10000;\n        for (int t = 0; t < MAX_TURNS; t++) {\n            // Step 1: spawn\n            step1_spawn();\n\n            // Step 2: actions\n            char bigAct = decideAction();\n\n            // Record outputs\n            S[0].push_back(bigAct);\n            for (int i = 1; i < N; i++) {\n                // Bomb small cranes at t=0, then idle\n                if (t == 0) S[i].push_back('B');\n                else S[i].push_back('.');\n            }\n\n            // Apply big action to state\n            applyBigAction(bigAct);\n\n            // Step 3: dispatch\n            step3_dispatch();\n\n            if (deliveredCount >= TOT) break;\n        }\n\n        // Pad strings to equal length\n        size_t L = 0;\n        for (int i = 0; i < N; i++) L = max(L, S[i].size());\n        for (int i = 0; i < N; i++) {\n            if (S[i].size() < L) S[i].append(L - S[i].size(), '.');\n        }\n    }\n\n    void output() {\n        for (int i = 0; i < N; i++) cout << S[i] << \"\\n\";\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.run();\n    solver.output();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\n// RNG for deterministic randomness\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed=1469598103934665603ULL){ x=seed; }\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int randint(int l, int r){ // inclusive\n        return l + int(next() % (uint64_t)(r-l+1));\n    }\n    template<class T>\n    void shuffle_vec(vector<T>& a){\n        for(int i=(int)a.size()-1;i>0;i--){\n            int j = int(next() % (uint64_t)(i+1));\n            swap(a[i], a[j]);\n        }\n    }\n};\n\n// Helpers to convert between (r,c) and linear id\nstatic inline int vid(int N, int r, int c){ return r*N + c; }\nstatic inline pair<int,int> rc_from_id(int N, int v){ return {v / N, v % N}; }\n\n// 2-regular graph adjacency utilities\nstatic inline void adj_add(vector<array<int,2>>& nb, int u, int v){\n    if(nb[u][0] == v || nb[u][1] == v) return;\n    if(nb[u][0] == -1) nb[u][0] = v;\n    else if(nb[u][1] == -1) nb[u][1] = v;\n    if(nb[v][0] == u || nb[v][1] == u) return;\n    if(nb[v][0] == -1) nb[v][0] = u;\n    else if(nb[v][1] == -1) nb[v][1] = u;\n}\nstatic inline void adj_remove(vector<array<int,2>>& nb, int u, int v){\n    if(nb[u][0] == v) nb[u][0] = -1;\n    else if(nb[u][1] == v) nb[u][1] = -1;\n    if(nb[v][0] == u) nb[v][0] = -1;\n    else if(nb[v][1] == u) nb[v][1] = -1;\n}\n\n// Cycle builder with two schemes\nstruct CycleBuilder {\n    int N, M, Br, Bc;\n    vector<array<int,2>> nb;\n\n    CycleBuilder(int N): N(N), M(N*N), Br(N/2), Bc(N/2), nb(M, {-1,-1}) {}\n\n    inline void clear() { nb.assign(M, array<int,2>{-1,-1}); }\n\n    inline void add_edge(int u, int v){ adj_add(nb, u, v); }\n    inline void remove_edge(int u, int v){ adj_remove(nb, u, v); }\n\n    void build_2x2_cycles(){\n        clear();\n        for(int br=0; br<Br; ++br){\n            for(int bc=0; bc<Bc; ++bc){\n                int x = 2*br, y = 2*bc;\n                int a = vid(N, x,   y);\n                int b = vid(N, x,   y+1);\n                int c = vid(N, x+1, y+1);\n                int d = vid(N, x+1, y);\n                add_edge(a,b);\n                add_edge(b,c);\n                add_edge(c,d);\n                add_edge(d,a);\n            }\n        }\n    }\n\n    // Horizontal-first scheme: merge horizontally across all seams\n    void merge_horizontally_all(){\n        for(int br=0; br<Br; ++br){\n            int x0 = 2*br;\n            for(int bc=0; bc<Bc-1; ++bc){\n                int y1 = 2*bc+1;\n                int y2 = 2*bc+2;\n                int a = vid(N, x0,   y1);\n                int b = vid(N, x0+1, y1);\n                int c = vid(N, x0,   y2);\n                int d = vid(N, x0+1, y2);\n                remove_edge(a,b);\n                remove_edge(c,d);\n                add_edge(a,c);\n                add_edge(b,d);\n            }\n        }\n    }\n\n    // Vertical merges at a specific block-column anchor per row seam (br seam)\n    void merge_vertically_with_anchors(const vector<int>& anchors){\n        for(int br=0; br<Br-1; ++br){\n            int r1 = 2*br+1;\n            int r2 = 2*br+2;\n            int colBlock = anchors[br];\n            if(colBlock < 0) colBlock = 0;\n            if(colBlock >= Bc) colBlock = Bc-1;\n            int y0 = 2*colBlock;\n            int y1 = y0 + 1;\n            int a = vid(N, r1, y0);\n            int b = vid(N, r1, y1);\n            int c = vid(N, r2, y0);\n            int d = vid(N, r2, y1);\n            remove_edge(a,b);\n            remove_edge(c,d);\n            add_edge(a,c);\n            add_edge(b,d);\n        }\n    }\n\n    // Vertical-first scheme: merge vertically across all seams first\n    void merge_vertically_all(){\n        for(int bc=0; bc<Bc; ++bc){\n            int y0 = 2*bc;\n            int y1 = y0 + 1;\n            for(int br=0; br<Br-1; ++br){\n                int x1 = 2*br+1;\n                int x2 = 2*br+2;\n                int a = vid(N, x1, y0);\n                int b = vid(N, x1, y1);\n                int c = vid(N, x2, y1);\n                int d = vid(N, x2, y0);\n                remove_edge(a,b);\n                remove_edge(d,c);\n                add_edge(a,d);\n                add_edge(b,c);\n            }\n        }\n    }\n\n    // Horizontal merges at a specific block-row anchor per column seam (bc seam)\n    void merge_horizontally_with_anchors(const vector<int>& anchorsCols){\n        for(int bc=0; bc<Bc-1; ++bc){\n            int cblock = anchorsCols[bc];\n            if(cblock < 0) cblock = 0;\n            if(cblock >= Br) cblock = Br-1;\n            int r0 = 2*cblock;\n            int r1 = r0 + 1;\n            int yL = 2*bc+1;\n            int yR = 2*bc+2;\n            int a = vid(N, r0, yL);\n            int b = vid(N, r1, yL);\n            int c = vid(N, r0, yR);\n            int d = vid(N, r1, yR);\n            remove_edge(a,b);\n            remove_edge(c,d);\n            add_edge(a,c);\n            add_edge(b,d);\n        }\n    }\n\n    vector<pair<int,int>> extract_cycle_path(){\n        vector<pair<int,int>> path;\n        path.reserve(M);\n        int start = vid(N, 0, 0);\n        int cur = start;\n        int prev = -1;\n        vector<char> seen(M, 0);\n        for(int cnt=0; cnt<M; ++cnt){\n            if(cur < 0 || cur >= M){ path.clear(); return path; }\n            if(seen[cur]){ path.clear(); return path; }\n            seen[cur] = 1;\n            path.emplace_back(rc_from_id(N, cur));\n            int n0 = nb[cur][0], n1 = nb[cur][1];\n            int nxt = (n0 == prev ? n1 : n0);\n            if(nxt == -1){ path.clear(); return path; }\n            prev = cur;\n            cur = nxt;\n        }\n        // Verify last connects to start\n        auto [xr, xc] = path.back();\n        int last = vid(N, xr, xc);\n        if(!(nb[last][0] == start || nb[last][1] == start)){\n            path.clear();\n        }\n        return path;\n    }\n\n    vector<pair<int,int>> build_scheme_A(const vector<int>& anchors){ // horiz-all then vert-anchors\n        build_2x2_cycles();\n        merge_horizontally_all();\n        merge_vertically_with_anchors(anchors);\n        return extract_cycle_path();\n    }\n    vector<pair<int,int>> build_scheme_B(const vector<int>& anchorsCols){ // vert-all then horiz-anchors\n        build_2x2_cycles();\n        merge_vertically_all();\n        merge_horizontally_with_anchors(anchorsCols);\n        return extract_cycle_path();\n    }\n};\n\n// Rotate path coordinates by rot=0..3\nstatic vector<pair<int,int>> rotate_path(const vector<pair<int,int>>& path, int N, int rot){\n    vector<pair<int,int>> res;\n    res.reserve(path.size());\n    for(auto [r,c] : path){\n        int nr=r, nc=c;\n        if(rot==1){ nr = c; nc = N-1 - r; }\n        else if(rot==2){ nr = N-1 - r; nc = N-1 - c; }\n        else if(rot==3){ nr = N-1 - c; nc = r; }\n        res.emplace_back(nr,nc);\n    }\n    return res;\n}\n\n// Evaluate one directed path, return best cost and start\nstatic pair<long long,int> eval_directed_path(const vector<pair<int,int>>& pos,\n                                              const vector<vector<int>>& h,\n                                              long long base)\n{\n    int M = (int)pos.size();\n    vector<long long> arr(M);\n    for(int i=0;i<M;i++){\n        arr[i] = h[pos[i].first][pos[i].second];\n    }\n    vector<long long> pre2(2*M+1, 0);\n    for(int i=0;i<2*M;i++){\n        pre2[i+1] = pre2[i] + arr[i%M];\n    }\n    vector<long long> prefpre2(2*M+1, 0);\n    for(int i=1;i<=2*M;i++){\n        prefpre2[i] = prefpre2[i-1] + pre2[i-1];\n    }\n    long long minVal = LLONG_MAX;\n    for(int i=0;i<M;i++) minVal = min(minVal, pre2[i]);\n    vector<int> starts;\n    for(int s=0;s<M;s++) if(pre2[s] == minVal) starts.push_back(s);\n\n    long long bestCost = (1LL<<62);\n    int bestS = 0;\n    for(int s: starts){\n        long long sumPre2Range = prefpre2[s+M] - prefpre2[s+1]; // pre2[s+1..s+M-1]\n        long long dsum = sumPre2Range - 1LL*(M-1)*pre2[s];\n        int sx = pos[s].first, sy = pos[s].second;\n        int repositionDist = abs(sx) + abs(sy);\n        long long moveCost = 100LL*((M-1) + repositionDist);\n        long long cost = base + moveCost + dsum;\n        if(cost < bestCost){\n            bestCost = cost;\n            bestS = s;\n        }\n    }\n    return {bestCost, bestS};\n}\n\nstruct EvalResult {\n    long long cost;\n    int startIndex;\n    int rot;\n    bool reversed;\n};\n\n// Evaluate best among 4 rotations and both directions\nstatic EvalResult eval_cycle_any_orientation(const vector<pair<int,int>>& cyc,\n                                             const vector<vector<int>>& h,\n                                             long long base, int N)\n{\n    EvalResult best{(1LL<<62), 0, 0, false};\n    for(int rot=0; rot<4; ++rot){\n        auto p = rotate_path(cyc, N, rot);\n        auto [c1, s1] = eval_directed_path(p, h, base);\n        if(c1 < best.cost){\n            best = {c1, s1, rot, false};\n        }\n        auto pr = p;\n        reverse(pr.begin(), pr.end());\n        auto [c2, s2] = eval_directed_path(pr, h, base);\n        if(c2 < best.cost){\n            best = {c2, s2, rot, true};\n        }\n    }\n    return best;\n}\n\n// Build nb from path cycle\nstatic vector<array<int,2>> nb_from_path(const vector<pair<int,int>>& path, int N){\n    int M = (int)path.size();\n    vector<array<int,2>> nb(N*N, array<int,2>{-1,-1});\n    auto ID = [&](int idx){ return vid(N, path[idx].first, path[idx].second); };\n    for(int i=0;i<M;i++){\n        int u = ID(i);\n        int v = ID((i+1)%M);\n        adj_add(nb, u, v);\n    }\n    return nb;\n}\n\n// Extract path from nb (single cycle)\nstatic vector<pair<int,int>> path_from_nb(const vector<array<int,2>>& nb, int N){\n    int M = N*N;\n    vector<pair<int,int>> path;\n    path.reserve(M);\n    int start = vid(N, 0, 0);\n    int cur = start;\n    int prev = -1;\n    vector<char> seen(M, 0);\n    for(int cnt=0; cnt<M; ++cnt){\n        if(cur < 0 || cur >= M){ path.clear(); return path; }\n        if(seen[cur]){ path.clear(); return path; }\n        seen[cur] = 1;\n        path.emplace_back(rc_from_id(N, cur));\n        int n0 = nb[cur][0], n1 = nb[cur][1];\n        int nxt = (n0 == prev ? n1 : n0);\n        if(nxt == -1){ path.clear(); return path; }\n        prev = cur;\n        cur = nxt;\n    }\n    auto [xr, xc] = path.back();\n    int last = vid(N, xr, xc);\n    if(!(nb[last][0] == start || nb[last][1] == start)){\n        path.clear();\n    }\n    return path;\n}\n\n// Attempt 2x2 plaquette flip on square (x,y); returns true if flipped\nstatic bool try_flip_square(vector<array<int,2>>& nb, int N, int x, int y){\n    int a = vid(N, x,   y);\n    int b = vid(N, x,   y+1);\n    int c = vid(N, x+1, y+1);\n    int d = vid(N, x+1, y);\n\n    auto used = [&](int u, int v)->bool{\n        return nb[u][0]==v || nb[u][1]==v;\n    };\n\n    bool ab = used(a,b);\n    bool bc = used(b,c);\n    bool cd = used(c,d);\n    bool da = used(d,a);\n\n    if(ab && cd && !bc && !da){\n        adj_remove(nb, a, b);\n        adj_remove(nb, c, d);\n        adj_add(nb, b, c);\n        adj_add(nb, d, a);\n        return true;\n    }else if(bc && da && !ab && !cd){\n        adj_remove(nb, b, c);\n        adj_remove(nb, d, a);\n        adj_add(nb, a, b);\n        adj_add(nb, c, d);\n        return true;\n    }\n    return false;\n}\n\n// Greedy optimization of anchors for Scheme A and Scheme B\nstatic vector<pair<int,int>> optimize_scheme_A(int N, const vector<vector<int>>& h, long long base, RNG& rng){\n    CycleBuilder cb(N);\n    int Br = N/2, Bc = N/2;\n    vector<vector<int>> initAnchors;\n    // constant k\n    for(int k=0;k<Bc;k++){\n        vector<int> anc(max(Br-1,0), k);\n        initAnchors.push_back(anc);\n        if((int)initAnchors.size() >= 4) break;\n    }\n    // diag k\n    for(int k=0;k<Bc && (int)initAnchors.size()<8;k++){\n        vector<int> anc(max(Br-1,0));\n        for(int br=0;br<Br-1;br++) anc[br] = (k + br) % Bc;\n        initAnchors.push_back(anc);\n    }\n    // anti-diag k\n    for(int k=0;k<Bc && (int)initAnchors.size()<12;k++){\n        vector<int> anc(max(Br-1,0));\n        for(int br=0;br<Br-1;br++) anc[br] = (k - br + Bc) % Bc;\n        initAnchors.push_back(anc);\n    }\n    // random\n    for(int t=0; t<6; ++t){\n        vector<int> anc(max(Br-1,0));\n        for(int br=0;br<Br-1;br++) anc[br] = rng.randint(0, Bc-1);\n        initAnchors.push_back(anc);\n    }\n\n    long long bestCostGlobal = (1LL<<62);\n    vector<pair<int,int>> bestPathGlobal;\n\n    for(auto anchors : initAnchors){\n        long long currentBestCost = (1LL<<62);\n        vector<pair<int,int>> bestPathThisSeed;\n        vector<int> currentAnch = anchors;\n        bool improvedOverall = true;\n        int pass = 0;\n        while(improvedOverall && pass < 4){\n            improvedOverall = false;\n            pass++;\n            for(int br=0;br<Br-1;br++){\n                long long localBest = (1LL<<62);\n                int bestK = currentAnch[br];\n                for(int k=0;k<Bc;k++){\n                    currentAnch[br] = k;\n                    auto cyc = cb.build_scheme_A(currentAnch);\n                    if(cyc.empty()) continue;\n                    auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n                    if(ev.cost < localBest){\n                        localBest = ev.cost;\n                        bestK = k;\n                    }\n                }\n                currentAnch[br] = bestK;\n            }\n            // Evaluate after full pass\n            auto cyc = cb.build_scheme_A(currentAnch);\n            if(!cyc.empty()){\n                auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n                if(ev.cost + 1e-9 < currentBestCost){\n                    currentBestCost = ev.cost;\n                    improvedOverall = true;\n                    bestPathThisSeed = rotate_path(cyc, N, ev.rot);\n                    if(ev.reversed) reverse(bestPathThisSeed.begin(), bestPathThisSeed.end());\n                }\n            }\n        }\n        if(currentBestCost < bestCostGlobal && !bestPathThisSeed.empty()){\n            bestCostGlobal = currentBestCost;\n            bestPathGlobal = bestPathThisSeed;\n        }\n    }\n\n    if(bestPathGlobal.empty()){\n        // Fallback: simple\n        vector<int> anc(max(Br-1,0), 0);\n        auto cyc = cb.build_scheme_A(anc);\n        if(cyc.empty()) return {};\n        auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n        bestPathGlobal = rotate_path(cyc, N, ev.rot);\n        if(ev.reversed) reverse(bestPathGlobal.begin(), bestPathGlobal.end());\n    }\n    return bestPathGlobal;\n}\n\nstatic vector<pair<int,int>> optimize_scheme_B(int N, const vector<vector<int>>& h, long long base, RNG& rng){\n    CycleBuilder cb(N);\n    int Br = N/2, Bc = N/2;\n    vector<vector<int>> initAnchors;\n    // constant k\n    for(int k=0;k<Br;k++){\n        vector<int> anc(max(Bc-1,0), k);\n        initAnchors.push_back(anc);\n        if((int)initAnchors.size() >= 4) break;\n    }\n    // diag k along columns\n    for(int k=0;k<Br && (int)initAnchors.size()<8;k++){\n        vector<int> anc(max(Bc-1,0));\n        for(int bc=0;bc<Bc-1;bc++) anc[bc] = (k + bc) % Br;\n        initAnchors.push_back(anc);\n    }\n    // anti-diag\n    for(int k=0;k<Br && (int)initAnchors.size()<12;k++){\n        vector<int> anc(max(Bc-1,0));\n        for(int bc=0;bc<Bc-1;bc++) anc[bc] = (k - bc + Br) % Br;\n        initAnchors.push_back(anc);\n    }\n    // random\n    for(int t=0; t<6; ++t){\n        vector<int> anc(max(Bc-1,0));\n        for(int bc=0;bc<Bc-1;bc++) anc[bc] = rng.randint(0, Br-1);\n        initAnchors.push_back(anc);\n    }\n\n    long long bestCostGlobal = (1LL<<62);\n    vector<pair<int,int>> bestPathGlobal;\n\n    for(auto anchors : initAnchors){\n        long long currentBestCost = (1LL<<62);\n        vector<pair<int,int>> bestPathThisSeed;\n        vector<int> currentAnch = anchors;\n        bool improvedOverall = true;\n        int pass = 0;\n        while(improvedOverall && pass < 4){\n            improvedOverall = false;\n            pass++;\n            for(int bc=0; bc<Bc-1; bc++){\n                long long localBest = (1LL<<62);\n                int bestK = currentAnch[bc];\n                for(int k=0;k<Br;k++){\n                    currentAnch[bc] = k;\n                    auto cyc = cb.build_scheme_B(currentAnch);\n                    if(cyc.empty()) continue;\n                    auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n                    if(ev.cost < localBest){\n                        localBest = ev.cost;\n                        bestK = k;\n                    }\n                }\n                currentAnch[bc] = bestK;\n            }\n            auto cyc = cb.build_scheme_B(currentAnch);\n            if(!cyc.empty()){\n                auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n                if(ev.cost + 1e-9 < currentBestCost){\n                    currentBestCost = ev.cost;\n                    improvedOverall = true;\n                    bestPathThisSeed = rotate_path(cyc, N, ev.rot);\n                    if(ev.reversed) reverse(bestPathThisSeed.begin(), bestPathThisSeed.end());\n                }\n            }\n        }\n        if(currentBestCost < bestCostGlobal && !bestPathThisSeed.empty()){\n            bestCostGlobal = currentBestCost;\n            bestPathGlobal = bestPathThisSeed;\n        }\n    }\n\n    if(bestPathGlobal.empty()){\n        vector<int> anc(max(Bc-1,0), 0);\n        auto cyc = cb.build_scheme_B(anc);\n        if(cyc.empty()) return {};\n        auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n        bestPathGlobal = rotate_path(cyc, N, ev.rot);\n        if(ev.reversed) reverse(bestPathGlobal.begin(), bestPathGlobal.end());\n    }\n    return bestPathGlobal;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if(!(cin>>N)) return 0;\n    vector<vector<int>> h(N, vector<int>(N));\n    long long base = 0;\n    uint64_t seedMix = 1469598103934665603ULL;\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            cin>>h[i][j];\n            base += llabs((long long)h[i][j]);\n            uint64_t v = (uint64_t)(h[i][j] + 100); // 0..200\n            seedMix ^= v + 0x9e3779b97f4a7c15ULL + (seedMix<<6) + (seedMix>>2);\n        }\n    }\n    RNG rng(seedMix ^ (uint64_t)N * 0x9e3779b97f4a7c15ULL);\n\n    // Optimize cycles using both schemes\n    auto pathA = optimize_scheme_A(N, h, base, rng);\n    auto pathB = optimize_scheme_B(N, h, base, rng);\n\n    // Evaluate both final candidates (both directions and best start)\n    vector<pair<int,int>> bestPath;\n    long long bestCost = (1LL<<62);\n    int bestStart = 0;\n\n    if(!pathA.empty()){\n        auto [costA, sA] = eval_directed_path(pathA, h, base);\n        auto pr = pathA; reverse(pr.begin(), pr.end());\n        auto [costAr, sAr] = eval_directed_path(pr, h, base);\n        if(costAr < costA){\n            pathA.swap(pr);\n            costA = costAr;\n            sA = sAr;\n        }\n        if(costA < bestCost){\n            bestCost = costA;\n            bestStart = sA;\n            bestPath = pathA;\n        }\n    }\n    if(!pathB.empty()){\n        auto [costB, sB] = eval_directed_path(pathB, h, base);\n        auto pr = pathB; reverse(pr.begin(), pr.end());\n        auto [costBr, sBr] = eval_directed_path(pr, h, base);\n        if(costBr < costB){\n            pathB.swap(pr);\n            costB = costBr;\n            sB = sBr;\n        }\n        if(costB < bestCost){\n            bestCost = costB;\n            bestStart = sB;\n            bestPath = pathB;\n        }\n    }\n    if(bestPath.empty()){\n        // Absolute fallback: simple scheme A anchor 0\n        CycleBuilder cb(N);\n        vector<int> anc(max(N/2-1,0), 0);\n        auto cyc = cb.build_scheme_A(anc);\n        if(cyc.empty()){\n            // Fallback to simple serpentine path (not a cycle)\n            for(int i=0;i<N;i++){\n                if(i%2==0) for(int j=0;j<N;j++) bestPath.emplace_back(i,j);\n                else for(int j=N-1;j>=0;j--) bestPath.emplace_back(i,j);\n            }\n        }else{\n            auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n            bestPath = rotate_path(cyc, N, ev.rot);\n            if(ev.reversed) reverse(bestPath.begin(), bestPath.end());\n        }\n        // Re-evaluate start\n        auto p = eval_directed_path(bestPath, h, base);\n        bestCost = p.first;\n        bestStart = p.second;\n    }\n\n    // Local improvement: 2x2 plaquette flips hill-climbing on the best cycle\n    {\n        auto nb = nb_from_path(bestPath, N);\n        vector<int> sqIdxs((N-1)*(N-1));\n        iota(sqIdxs.begin(), sqIdxs.end(), 0);\n\n        auto rebuild_and_eval = [&](vector<array<int,2>>& nbCur)->pair<long long, vector<pair<int,int>>>{\n            auto path2 = path_from_nb(nbCur, N);\n            if(path2.empty()){\n                return { (1LL<<62), {} };\n            }\n            auto [costF, sF] = eval_directed_path(path2, h, base);\n            auto pr = path2;\n            reverse(pr.begin(), pr.end());\n            auto [costR, sR] = eval_directed_path(pr, h, base);\n            if(costF <= costR) return {costF, path2};\n            else return {costR, pr};\n        };\n\n        // Evaluate current nb cost (should equal bestPath)\n        auto [curCost, curPath] = rebuild_and_eval(nb);\n        if(curPath.empty()){\n            curPath = bestPath;\n            curCost = bestCost;\n        }\n\n        int maxPass = 4; // conservative\n        for(int pass=0; pass<maxPass; ++pass){\n            bool improved = false;\n            rng.shuffle_vec(sqIdxs);\n            for(int id : sqIdxs){\n                int x = id / (N-1);\n                int y = id % (N-1);\n                if(try_flip_square(nb, N, x, y)){\n                    auto [newCost, newPath] = rebuild_and_eval(nb);\n                    if(newCost < curCost){\n                        // accept\n                        curCost = newCost;\n                        curPath.swap(newPath);\n                        improved = true;\n                    }else{\n                        // revert flip\n                        try_flip_square(nb, N, x, y);\n                    }\n                }\n            }\n            if(!improved) break;\n        }\n        if(curCost < bestCost){\n            bestCost = curCost;\n            bestPath = curPath;\n            auto p = eval_directed_path(bestPath, h, base);\n            bestStart = p.second;\n        }\n    }\n\n    // Compute best start index on final oriented path\n    auto [finalCost, startIdx] = eval_directed_path(bestPath, h, base);\n    (void)finalCost; // not used further\n    int M = N*N;\n\n    // Emit operations\n    vector<string> ops;\n    ops.reserve(M*3 + 200);\n\n    int cx = 0, cy = 0;\n    long long load = 0;\n\n    auto move_to = [&](int tx, int ty){\n        while(cy < ty){ ops.emplace_back(\"R\"); cy++; }\n        while(cy > ty){ ops.emplace_back(\"L\"); cy--; }\n        while(cx < tx){ ops.emplace_back(\"D\"); cx++; }\n        while(cx > tx){ ops.emplace_back(\"U\"); cx--; }\n    };\n\n    // Reposition to start\n    int sx = bestPath[startIdx].first, sy = bestPath[startIdx].second;\n    move_to(sx, sy);\n\n    // Traverse along the cycle from the chosen start\n    for(int t=0;t<M;t++){\n        int idx = (startIdx + t) % M;\n        int x = bestPath[idx].first, y = bestPath[idx].second;\n        int val = h[x][y];\n        if(val > 0){\n            ops.emplace_back(\"+\" + to_string(val));\n            load += val;\n            h[x][y] = 0;\n        }else if(val < 0){\n            int need = -val;\n            long long give = min<long long>(need, load);\n            if(give > 0){\n                ops.emplace_back(\"-\" + to_string(give));\n                load -= give;\n                h[x][y] += (int)give;\n            }\n        }\n        if(t != M-1){\n            int nx = bestPath[(idx+1)%M].first, ny = bestPath[(idx+1)%M].second;\n            if(nx == x){\n                if(ny == y+1){ ops.emplace_back(\"R\"); cy++; }\n                else if(ny == y-1){ ops.emplace_back(\"L\"); cy--; }\n                else { move_to(nx, ny); }\n            }else if(ny == y){\n                if(nx == x+1){ ops.emplace_back(\"D\"); cx++; }\n                else if(nx == x-1){ ops.emplace_back(\"U\"); cx--; }\n                else { move_to(nx, ny); }\n            }else{\n                move_to(nx, ny);\n            }\n        }\n    }\n\n    for(const auto& s : ops) cout << s << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\n// AHC035 \"Grain\" heuristic with hybrid edge softmax and pairwise precomputation.\n// - Two anchor edges near the center.\n// - Selection: anchors + per-dim carriers + some top-V + dynamic coverage (weighted by Xmax/cnt).\n// - Arrangement: hill-climb objective = node term + pair spread (expected carriers) +\n//   muQ * log(sum_e exp(betaQ * q_e)) + muM * log(sum_e exp(betaM * smax_e)),\n//   where q_e = mean_e + alpha * sigma_e (quantile proxy), smax_e = sum_l max(xa, xb).\n// - 4 restarts: lock both anchors, lock first anchor, place anchors but unlock, no anchors.\n// - Pairwise (mean, sigma, smax) precomputed per turn to speed swaps.\n\nstruct RNG {\n    uint64_t x;\n    RNG() {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        x = seed ^ (seed << 13);\n    }\n    inline uint32_t next_u32() {\n        uint64_t y = x;\n        y ^= (y << 7);\n        y ^= (y >> 9);\n        x = y;\n        return (uint32_t)(y & 0xffffffffu);\n    }\n    inline int randint(int lo, int hi) { // inclusive\n        uint32_t r = next_u32();\n        return lo + (int)(r % (uint32_t)(hi - lo + 1));\n    }\n    inline double rand01() { return (next_u32() / 4294967296.0); }\n};\n\nstruct Params {\n    // Node weights\n    double wV, wRare, wCnt, wMissNode;\n    // Pair spread scaling (pairBoth=1, pairOne=0.5)\n    double pairFactor;\n    // Quantile softmax\n    double alpha, betaQ, muQ;\n    // Sum-of-max softmax\n    double betaM, muM;\n    // Anchor pair selection\n    double anchQuant, anchBoth, anchOne, anchV;\n    // Iterations per restart\n    int iters;\n    // Base target coverage\n    int baseTarget;\n    // Force include top-V\n    int forceTopV;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    if (!(cin >> N >> M >> T)) return 0;\n\n    const int SEED_COUNT = 2 * N * (N - 1); // 60 for N=6\n    vector<vector<int>> X(SEED_COUNT, vector<int>(M));\n    for (int i = 0; i < SEED_COUNT; i++)\n        for (int j = 0; j < M; j++) cin >> X[i][j];\n\n    // Xmax per dimension\n    vector<int> Xmax(M, 0);\n    for (int l = 0; l < M; l++) {\n        int mx = 0;\n        for (int k = 0; k < SEED_COUNT; k++) mx = max(mx, X[k][l]);\n        Xmax[l] = mx;\n    }\n\n    // Grid\n    auto pos_id = [&](int i, int j){ return i * N + j; };\n    vector<vector<int>> neighbors(N*N);\n    vector<int> deg(N*N, 0);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int u = pos_id(i,j);\n        if (i > 0)   neighbors[u].push_back(pos_id(i-1,j));\n        if (i+1 < N) neighbors[u].push_back(pos_id(i+1,j));\n        if (j > 0)   neighbors[u].push_back(pos_id(i,j-1));\n        if (j+1 < N) neighbors[u].push_back(pos_id(i,j+1));\n        deg[u] = (int)neighbors[u].size();\n    }\n    // Undirected edges\n    vector<pair<int,int>> edges;\n    for (int u = 0; u < N*N; u++) for (int v: neighbors[u]) if (u < v) edges.emplace_back(u, v);\n    const int E = (int)edges.size(); // 60\n    // Edge indices per position\n    vector<vector<int>> edgeIdxByPos(N*N);\n    for (int ei = 0; ei < E; ei++) {\n        auto [u,v] = edges[ei];\n        edgeIdxByPos[u].push_back(ei);\n        edgeIdxByPos[v].push_back(ei);\n    }\n\n    // Position order: degree desc, center proximity asc\n    vector<int> posOrder(N*N);\n    iota(posOrder.begin(), posOrder.end(), 0);\n    const double ci = (N-1)/2.0, cj = (N-1)/2.0;\n    sort(posOrder.begin(), posOrder.end(), [&](int a, int b){\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        int ai = a / N, aj = a % N;\n        int bi = b / N, bj = b % N;\n        double da = fabs(ai - ci) + fabs(aj - cj);\n        double db = fabs(bi - ci) + fabs(bj - cj);\n        if (da != db) return da < db;\n        return a < b;\n    });\n\n    // Two central horizontal edges as anchor positions\n    int i1 = N/2 - 1, j1 = N/2 - 1;\n    int i2 = N/2,     j2 = N/2 - 1;\n    int anchor1Apos = pos_id(i1, j1);\n    int anchor1Bpos = pos_id(i1, j1 + 1);\n    int anchor2Apos = pos_id(i2, j2);\n    int anchor2Bpos = pos_id(i2, j2 + 1);\n\n    RNG rng;\n\n    auto paramsForTurn = [&](int t)->Params{\n        if (t <= 3) {\n            return Params{\n                // Node\n                0.16, 10.0, 9.0, 8.5,\n                // Pair spread scaling\n                240.0,\n                // Quantile softmax\n                1.8, 0.0050, 3000.0,\n                // Sum-of-max softmax\n                0.0045, 1200.0,\n                // Anchor selection\n                1.0, 9.0, 3.5, 0.001,\n                // iters/restart\n                24000,\n                // base coverage\n                3,\n                // force top-V\n                4\n            };\n        } else if (t <= 6) {\n            return Params{\n                0.18, 9.0, 8.0, 6.0,\n                210.0,\n                2.2, 0.0052, 3400.0,\n                0.0049, 1500.0,\n                1.0, 9.0, 3.0, 0.0015,\n                23000,\n                2,\n                5\n            };\n        } else if (t <= 8) {\n            return Params{\n                0.20, 8.0, 7.0, 5.0,\n                180.0,\n                2.6, 0.0058, 3800.0,\n                0.0052, 1800.0,\n                1.0, 9.0, 2.5, 0.0020,\n                22000,\n                2,\n                6\n            };\n        } else {\n            return Params{\n                0.24, 6.0, 5.0, 1.5,\n                150.0,\n                3.2, 0.0065, 5000.0,\n                0.0058, 2200.0,\n                1.0, 10.0, 2.0, 0.0030,\n                20000,\n                1,\n                8\n            };\n        }\n    };\n\n    for (int t = 0; t < T; t++) {\n        auto P = paramsForTurn(t);\n\n        // V and carriers\n        vector<int> V(SEED_COUNT, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            int s = 0;\n            for (int l = 0; l < M; l++) s += X[k][l];\n            V[k] = s;\n        }\n        vector<uint16_t> bits(SEED_COUNT, 0);\n        vector<int> cnt(M, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            uint16_t m = 0;\n            for (int l = 0; l < M; l++) if (X[k][l] == Xmax[l]) m |= (1u << l);\n            bits[k] = m;\n            for (int l = 0; l < M; l++) if ((m >> l) & 1u) cnt[l]++;\n        }\n        uint16_t dimsAvail = 0;\n        for (int l = 0; l < M; l++) if (cnt[l] > 0) dimsAvail |= (1u << l);\n\n        // Rarity weights: Xmax[l] / cnt[l]\n        vector<double> wdim(M, 0.0);\n        for (int l = 0; l < M; l++) wdim[l] = (cnt[l] ? (double)Xmax[l] / (double)cnt[l] : 0.0);\n\n        // sumW over masks\n        int MASKSZ = 1 << M;\n        vector<double> sumW(MASKSZ, 0.0);\n        for (int m = 1; m < MASKSZ; m++) {\n            int lb = __builtin_ctz(m);\n            int prev = m & (m - 1);\n            sumW[m] = sumW[prev] + wdim[lb];\n        }\n\n        vector<double> rareSum(SEED_COUNT, 0.0);\n        vector<int> carrierCnt(SEED_COUNT, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            rareSum[k] = sumW[bits[k]];\n            carrierCnt[k] = __builtin_popcount((unsigned)bits[k]);\n        }\n\n        // Precompute pairwise mean, sigma, smax for all pairs\n        static float pairMean[64][64], pairSigma[64][64], pairSMax[64][64];\n        for (int a = 0; a < SEED_COUNT; a++) {\n            pairMean[a][a] = 0.5f * V[a];\n            pairSigma[a][a] = 0.0f;\n            pairSMax[a][a] = (float)V[a];\n            for (int b = a + 1; b < SEED_COUNT; b++) {\n                float mean = 0.5f * (V[a] + V[b]);\n                double s2 = 0.0;\n                int smax = 0;\n                const auto &xa = X[a], &xb = X[b];\n                for (int l = 0; l < M; l++) {\n                    int aa = xa[l], bb = xb[l];\n                    int d = aa - bb;\n                    s2 += (double)d * (double)d;\n                    smax += (aa > bb ? aa : bb);\n                }\n                float sigma = 0.5f * (float)sqrt(max(0.0, s2));\n                pairMean[a][b] = pairMean[b][a] = mean;\n                pairSigma[a][b] = pairSigma[b][a] = sigma;\n                pairSMax[a][b] = pairSMax[b][a] = (float)smax;\n            }\n        }\n\n        auto edgeQuant = [&](int a, int b)->double{\n            return (double)pairMean[a][b] + P.alpha * (double)pairSigma[a][b];\n        };\n        auto edgeSMax = [&](int a, int b)->double{\n            return (double)pairSMax[a][b];\n        };\n\n        // Anchor 1\n        int anchor1A = 0, anchor1B = 1;\n        double bestSc1 = -1e100;\n        for (int a = 0; a < SEED_COUNT; a++) {\n            for (int b = a + 1; b < SEED_COUNT; b++) {\n                double q = edgeQuant(a,b);\n                uint16_t ba = bits[a], bb = bits[b];\n                double sboth = sumW[ba & bb];\n                double sone  = sumW[ba ^ bb];\n                double sc = P.anchQuant * q + P.anchBoth * sboth + P.anchOne * sone + P.anchV * (V[a] + V[b]);\n                sc += (rng.rand01() - 0.5) * 1e-6;\n                if (sc > bestSc1) { bestSc1 = sc; anchor1A = a; anchor1B = b; }\n            }\n        }\n        // Anchor 2 disjoint\n        int anchor2A = -1, anchor2B = -1;\n        double bestSc2 = -1e100;\n        for (int a = 0; a < SEED_COUNT; a++) {\n            if (a == anchor1A || a == anchor1B) continue;\n            for (int b = a + 1; b < SEED_COUNT; b++) {\n                if (b == anchor1A || b == anchor1B) continue;\n                double q = edgeQuant(a,b);\n                uint16_t ba = bits[a], bb = bits[b];\n                double sboth = sumW[ba & bb];\n                double sone  = sumW[ba ^ bb];\n                double sc = P.anchQuant * q + P.anchBoth * sboth + P.anchOne * sone + P.anchV * (V[a] + V[b]);\n                sc += (rng.rand01() - 0.5) * 1e-6;\n                if (sc > bestSc2) { bestSc2 = sc; anchor2A = a; anchor2B = b; }\n            }\n        }\n        if (anchor2A == -1) {\n            for (int a = 0; a < SEED_COUNT; a++) if (a != anchor1A && a != anchor1B) {\n                for (int b = a + 1; b < SEED_COUNT; b++) if (b != anchor1A && b != anchor1B) {\n                    anchor2A = a; anchor2B = b; break;\n                }\n                if (anchor2A != -1) break;\n            }\n        }\n\n        uint16_t maskA1 = bits[anchor1A], maskB1 = bits[anchor1B];\n        uint16_t maskA2 = bits[anchor2A], maskB2 = bits[anchor2B];\n        uint16_t missA1 = (uint16_t)(dimsAvail & (~maskA1));\n        uint16_t missB1 = (uint16_t)(dimsAvail & (~maskB1));\n        uint16_t missA2 = (uint16_t)(dimsAvail & (~maskA2));\n        uint16_t missB2 = (uint16_t)(dimsAvail & (~maskB2));\n        uint16_t missAll = (uint16_t)(dimsAvail & (~(maskA1 | maskB1 | maskA2 | maskB2)));\n\n        // Selection: anchors -> one carrier per dim -> top-V -> dynamic coverage\n        vector<int> selected; selected.reserve(N*N);\n        vector<char> used(SEED_COUNT, 0);\n        auto include = [&](int k){ if (!used[k]) { used[k] = 1; selected.push_back(k); } };\n\n        include(anchor1A); include(anchor1B);\n        if (anchor2A != -1) include(anchor2A);\n        if (anchor2B != -1) include(anchor2B);\n\n        for (int l = 0; l < M; l++) {\n            if (cnt[l] == 0) continue;\n            int best = -1, bestV = -1;\n            for (int k = 0; k < SEED_COUNT; k++) if (!used[k] && ((bits[k] >> l) & 1u)) {\n                if (V[k] > bestV) bestV = V[k], best = k;\n            }\n            if (best != -1 && (int)selected.size() < N*N) include(best);\n        }\n\n        // Force top-V seeds\n        vector<int> ordV(SEED_COUNT);\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        int forced = 0;\n        for (int k : ordV) {\n            if (forced >= P.forceTopV) break;\n            if (!used[k]) { include(k); forced++; }\n        }\n\n        // Dynamic coverage targets\n        vector<int> targetCov(M, P.baseTarget);\n        for (int l = 0; l < M; l++) {\n            if (cnt[l] <= 2) targetCov[l] = min(P.baseTarget + 2, 5);\n            else if (cnt[l] <= 4) targetCov[l] = min(P.baseTarget + 1, 4);\n        }\n        vector<int> cov(M, 0);\n        for (int k : selected) for (int l = 0; l < M; l++) if ((bits[k] >> l) & 1u) cov[l]++;\n\n        auto needWeight = [&](int l)->double{\n            if (cnt[l] == 0) return 0.0;\n            int need = max(0, targetCov[l] - cov[l]);\n            if (need <= 0) return 0.0;\n            return (double)need * (1.0 + 2.5 * wdim[l]);\n        };\n\n        while ((int)selected.size() < N*N) {\n            int bestK = -1; double bestSc = -1e100;\n            for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) {\n                double covGain = 0.0;\n                for (int l = 0; l < M; l++) if ((bits[k] >> l) & 1u) covGain += needWeight(l);\n                double missGain = sumW[bits[k] & missAll];\n                double sc = 0.012 * V[k] + covGain + 80.0 * missGain;\n                if (sc > bestSc) bestSc = sc, bestK = k;\n            }\n            if (bestK == -1) break;\n            include(bestK);\n            for (int l = 0; l < M; l++) if ((bits[bestK] >> l) & 1u) cov[l]++;\n        }\n        if ((int)selected.size() < N*N) {\n            vector<int> rest;\n            for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) rest.push_back(k);\n            sort(rest.begin(), rest.end(), [&](int a, int b){\n                if (V[a] != V[b]) return V[a] > V[b];\n                return a < b;\n            });\n            for (int k : rest) { if ((int)selected.size() >= N*N) break; include(k); }\n        }\n\n        // Node weights\n        vector<double> nodeWeight(SEED_COUNT, 0.0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            nodeWeight[k] = P.wV * V[k] + P.wRare * rareSum[k] + P.wCnt * carrierCnt[k]\n                          + P.wMissNode * sumW[bits[k] & missAll];\n        }\n\n        auto pairSpread = [&](int a, int b)->double{\n            // Expected next-generation carriers: both=1, one=0.5; we aggregate with wdim via sumW\n            uint16_t ma = bits[a], mb = bits[b];\n            double both = sumW[ma & mb];\n            double one  = sumW[ma ^ mb];\n            return P.pairFactor * (1.0 * both + 0.5 * one);\n        };\n\n        // Initial assignment builder for modes: 0 lock both, 1 lock first, 2 place-unlock, 3 no anchors\n        auto build_initial_assignment = [&](int mode)->vector<int>{\n            vector<int> assignPos(N*N, -1);\n            vector<char> usedSeed(SEED_COUNT, 0);\n            auto noise = [&](double amp){ return (rng.rand01() - 0.5) * amp; };\n\n            if (mode == 0 || mode == 1 || mode == 2) {\n                // Place anchors\n                assignPos[anchor1Apos] = anchor1A; usedSeed[anchor1A] = 1;\n                assignPos[anchor1Bpos] = anchor1B; usedSeed[anchor1B] = 1;\n                assignPos[anchor2Apos] = anchor2A; usedSeed[anchor2A] = 1;\n                assignPos[anchor2Bpos] = anchor2B; usedSeed[anchor2B] = 1;\n\n                auto neighExcluding = [&](int pos, int excl){\n                    vector<int> v; v.reserve(3);\n                    for (int nb : neighbors[pos]) if (nb != excl) v.push_back(nb);\n                    return v;\n                };\n                vector<int> neigh1A = neighExcluding(anchor1Apos, anchor1Bpos);\n                vector<int> neigh1B = neighExcluding(anchor1Bpos, anchor1Apos);\n                vector<int> neigh2A = neighExcluding(anchor2Apos, anchor2Bpos);\n                vector<int> neigh2B = neighExcluding(anchor2Bpos, anchor2Apos);\n\n                vector<int> pool = selected;\n                auto eraseSeed = [&](int s){\n                    auto it = find(pool.begin(), pool.end(), s);\n                    if (it != pool.end()) pool.erase(it);\n                };\n                eraseSeed(anchor1A); eraseSeed(anchor1B);\n                eraseSeed(anchor2A); eraseSeed(anchor2B);\n\n                auto scoreForMask = [&](int k, uint16_t miss)->double{\n                    return 300.0 * sumW[bits[k] & miss] + 0.05 * V[k] + 10.0 * rareSum[k] + noise(0.01);\n                };\n\n                auto assign_neigh = [&](const vector<int>& neigh, uint16_t miss){\n                    vector<pair<double,int>> cand;\n                    for (int k : pool) if (!usedSeed[k]) cand.emplace_back(scoreForMask(k, miss), k);\n                    sort(cand.begin(), cand.end(), greater<>());\n                    for (int p : neigh) {\n                        if (assignPos[p] != -1) continue;\n                        int chosen = -1;\n                        for (auto &pr : cand) {\n                            int k = pr.second;\n                            if (!usedSeed[k]) { chosen = k; break; }\n                        }\n                        if (chosen != -1) { assignPos[p] = chosen; usedSeed[chosen] = 1; }\n                    }\n                };\n                assign_neigh(neigh1A, missA1);\n                assign_neigh(neigh1B, missB1);\n                assign_neigh(neigh2A, missA2);\n                assign_neigh(neigh2B, missB2);\n\n                vector<pair<double,int>> ord;\n                for (int k : selected) if (!usedSeed[k]) ord.emplace_back(nodeWeight[k] + noise(0.05), k);\n                sort(ord.begin(), ord.end(), greater<>());\n                for (int pos : posOrder) if (assignPos[pos] == -1) {\n                    if (!ord.empty()) {\n                        int k = ord.back().second; ord.pop_back();\n                        assignPos[pos] = k; usedSeed[k] = 1;\n                    }\n                }\n            } else {\n                vector<pair<double,int>> ord;\n                for (int k : selected) ord.emplace_back(nodeWeight[k] + (rng.rand01()-0.5)*0.05, k);\n                sort(ord.begin(), ord.end(), greater<>());\n                int idx = 0;\n                for (int pos : posOrder) assignPos[pos] = ord[idx++].second;\n            }\n\n            for (int pos = 0; pos < N*N; pos++) if (assignPos[pos] == -1) {\n                for (int k : selected) if (!usedSeed[k]) { assignPos[pos] = k; usedSeed[k] = 1; break; }\n            }\n            return assignPos;\n        };\n\n        auto totalObjective = [&](const vector<int>& assignPos,\n                                  const vector<double>& edgeExpQ, double sumExpQ,\n                                  const vector<double>& edgeExpM, double sumExpM)->double{\n            double nodeTerm = 0.0;\n            for (int p = 0; p < N*N; p++) nodeTerm += deg[p] * nodeWeight[assignPos[p]];\n            double pairTerm = 0.0;\n            for (auto &e : edges) {\n                int a = assignPos[e.first], b = assignPos[e.second];\n                pairTerm += pairSpread(a, b);\n            }\n            double softQ = P.muQ * log(max(1e-300, sumExpQ));\n            double softM = P.muM * log(max(1e-300, sumExpM));\n            return nodeTerm + pairTerm + softQ + softM;\n        };\n\n        int restarts = 4;\n        double bestObj = -1e100;\n        vector<int> bestAssign;\n\n        for (int rr = 0; rr < restarts; rr++) {\n            vector<int> assignPos = build_initial_assignment(rr);\n\n            // Precompute edge exp(beta * q) and exp(betaM * smax)\n            vector<double> edgeExpQ(E, 0.0), edgeExpM(E, 0.0);\n            double sumExpQ = 0.0, sumExpM = 0.0;\n            for (int ei = 0; ei < E; ei++) {\n                int u = edges[ei].first, v = edges[ei].second;\n                int a = assignPos[u], b = assignPos[v];\n                double q = edgeQuant(a, b);\n                double m = edgeSMax(a, b);\n                double eQ = exp(P.betaQ * q);\n                double eM = exp(P.betaM * m);\n                edgeExpQ[ei] = eQ; sumExpQ += eQ;\n                edgeExpM[ei] = eM; sumExpM += eM;\n            }\n\n            double currentObj = totalObjective(assignPos, edgeExpQ, sumExpQ, edgeExpM, sumExpM);\n\n            int iters = P.iters;\n            vector<char> mark(E, 0);\n            vector<int> changed; changed.reserve(16);\n\n            for (int it = 0; it < iters; it++) {\n                int aPos = rng.randint(0, N*N-1);\n                int bPos = rng.randint(0, N*N-1);\n                if (aPos == bPos) continue;\n                if (rr == 0) {\n                    // lock both anchor pairs\n                    if (aPos == anchor1Apos || aPos == anchor1Bpos || aPos == anchor2Apos || aPos == anchor2Bpos) continue;\n                    if (bPos == anchor1Apos || bPos == anchor1Bpos || bPos == anchor2Apos || bPos == anchor2Bpos) continue;\n                } else if (rr == 1) {\n                    // lock first anchor only\n                    if (aPos == anchor1Apos || aPos == anchor1Bpos) continue;\n                    if (bPos == anchor1Apos || bPos == anchor1Bpos) continue;\n                }\n\n                int ka = assignPos[aPos];\n                int kb = assignPos[bPos];\n\n                double delta = 0.0;\n                // Node term\n                delta += deg[aPos] * (nodeWeight[kb] - nodeWeight[ka]);\n                delta += deg[bPos] * (nodeWeight[ka] - nodeWeight[kb]);\n\n                // Pair spread and softmax updates for changed edges\n                double deltaPair = 0.0;\n                changed.clear();\n                for (int ei : edgeIdxByPos[aPos]) if (!mark[ei]) { mark[ei] = 1; changed.push_back(ei); }\n                for (int ei : edgeIdxByPos[bPos]) if (!mark[ei]) { mark[ei] = 1; changed.push_back(ei); }\n\n                double newSumExpQ = sumExpQ, newSumExpM = sumExpM;\n                for (int ei : changed) {\n                    int u = edges[ei].first, v = edges[ei].second;\n                    int su = assignPos[u], sv = assignPos[v];\n                    if (u == aPos) su = kb; else if (u == bPos) su = ka;\n                    if (v == aPos) sv = kb; else if (v == bPos) sv = ka;\n\n                    // Pair spread delta\n                    double oldPS = pairSpread(assignPos[u], assignPos[v]);\n                    double newPS = pairSpread(su, sv);\n                    deltaPair += newPS - oldPS;\n\n                    // Softmax updates\n                    double oldEQ = edgeExpQ[ei];\n                    double oldEM = edgeExpM[ei];\n                    double q = (double)pairMean[su][sv] + P.alpha * (double)pairSigma[su][sv];\n                    double m = (double)pairSMax[su][sv];\n                    double newEQ = exp(P.betaQ * q);\n                    double newEM = exp(P.betaM * m);\n                    newSumExpQ += (newEQ - oldEQ);\n                    newSumExpM += (newEM - oldEM);\n                }\n                for (int ei : changed) mark[ei] = 0;\n\n                delta += deltaPair;\n                if (newSumExpQ <= 0 || newSumExpM <= 0) continue;\n                double deltaSoft = P.muQ * (log(newSumExpQ) - log(sumExpQ))\n                                 + P.muM * (log(newSumExpM) - log(sumExpM));\n                double totalDelta = delta + deltaSoft;\n\n                if (totalDelta > 1e-12) {\n                    swap(assignPos[aPos], assignPos[bPos]);\n                    // Update edge arrays and sums\n                    for (int ei : changed) {\n                        int u = edges[ei].first, v = edges[ei].second;\n                        int a = assignPos[u], b = assignPos[v];\n                        double q = (double)pairMean[a][b] + P.alpha * (double)pairSigma[a][b];\n                        double m = (double)pairSMax[a][b];\n                        double eQ = exp(P.betaQ * q);\n                        double eM = exp(P.betaM * m);\n                        sumExpQ += (eQ - edgeExpQ[ei]);\n                        sumExpM += (eM - edgeExpM[ei]);\n                        edgeExpQ[ei] = eQ;\n                        edgeExpM[ei] = eM;\n                    }\n                    currentObj += totalDelta;\n                }\n            }\n\n            if (currentObj > bestObj) {\n                bestObj = currentObj;\n                bestAssign = assignPos;\n            }\n        }\n\n        // Output plan\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int pos = i * N + j;\n                cout << bestAssign[pos] << (j + 1 == N ? '\\n' : ' ');\n            }\n        }\n        cout.flush();\n\n        // Read next generation\n        for (int i = 0; i < SEED_COUNT; i++)\n            for (int j = 0; j < M; j++) cin >> X[i][j];\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int x, y; };\n\nstruct Hungarian {\n    // Square Hungarian algorithm, O(n^3), integer costs\n    static pair<long long, vector<int>> solve(const vector<vector<int>>& cost) {\n        int n = (int)cost.size();\n        const int INF = 1e9;\n        vector<int> u(n+1), v(n+1), p(n+1), way(n+1);\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            int j0 = 0;\n            vector<int> minv(n+1, INF);\n            vector<char> used(n+1, false);\n            do {\n                used[j0] = true;\n                int i0 = p[j0], delta = INF, j1 = 0;\n                for (int j = 1; j <= n; j++) if (!used[j]) {\n                    int cur = cost[i0-1][j-1] - u[i0] - v[j];\n                    if (cur < minv[j]) { minv[j] = cur; way[j] = j0; }\n                    if (minv[j] < delta) { delta = minv[j]; j1 = j; }\n                }\n                for (int j = 0; j <= n; j++) {\n                    if (used[j]) { u[p[j]] += delta; v[j] -= delta; }\n                    else minv[j] -= delta;\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n        vector<int> assignment(n, -1);\n        for (int j = 1; j <= n; j++) if (p[j] != 0) assignment[p[j]-1] = j-1;\n        long long value = -v[0];\n        return {value, assignment};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, V;\n    if (!(cin >> N >> M >> V)) return 0;\n    vector<string> ss(N), tt(N);\n    for (int i = 0; i < N; i++) cin >> ss[i];\n    for (int i = 0; i < N; i++) cin >> tt[i];\n\n    vector<vector<int>> occ(N, vector<int>(N, 0));\n    vector<Pos> sources, targets;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int s = ss[i][j] - '0';\n        int t = tt[i][j] - '0';\n        occ[i][j] = s;\n        if (s == 1 && t == 0) sources.push_back({i,j});\n        if (s == 0 && t == 1) targets.push_back({i,j});\n    }\n    int D = (int)sources.size();\n\n    // Simple arm: V' = 2, edge length 1\n    int Vp = 2;\n    const int DX[4] = {0, 1, 0, -1}; // 0=E,1=S,2=W,3=N\n    const int DY[4] = {1, 0, -1, 0};\n\n    auto rotdist = [&](int cur, int req) {\n        int d = (req - cur + 4) % 4;\n        return min(d, 4 - d);\n    };\n    auto enumerate_adj = [&](int bx, int by) -> vector<tuple<int,int,int>> {\n        vector<tuple<int,int,int>> res;\n        if (by - 1 >= 0) res.emplace_back(bx, by - 1, 0); // left -> face E\n        if (by + 1 < N) res.emplace_back(bx, by + 1, 2);  // right -> face W\n        if (bx - 1 >= 0) res.emplace_back(bx - 1, by, 1); // above -> face S\n        if (bx + 1 < N) res.emplace_back(bx + 1, by, 3);  // below -> face N\n        return res;\n    };\n    auto pureMoveCost = [&](int rx0, int ry0, int dir0, int ax, int ay, int adir) -> int {\n        int mv = abs(rx0 - ax) + abs(ry0 - ay);\n        int rr = rotdist(dir0, adir);\n        return max(mv, rr);\n    };\n    auto fusedCost = [&](int rx0, int ry0, int dir0, int ax, int ay, int adir, bool fuseP) -> int {\n        int mv = abs(rx0 - ax) + abs(ry0 - ay);\n        int rr = rotdist(dir0, adir);\n        int c = max(mv, rr);\n        if (fuseP && mv == 0 && rr == 0) return 1;\n        return c;\n    };\n\n    if ((int)targets.size() != D) {\n        // Fallback safe output\n        cout << 2 << \"\\n\";\n        cout << 0 << \" \" << 1 << \"\\n\";\n        cout << 0 << \" \" << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Precompute adjacency lists for all sources and all targets\n    vector<vector<tuple<int,int,int>>> srcAdj(D), tarAdj(D);\n    for (int i = 0; i < D; i++) srcAdj[i] = enumerate_adj(sources[i].x, sources[i].y);\n    for (int j = 0; j < D; j++) tarAdj[j] = enumerate_adj(targets[j].x, targets[j].y);\n    for (int i = 0; i < D; i++) if (srcAdj[i].empty()) {\n        // Should not happen, but safeguard\n        if (sources[i].y - 1 >= 0) srcAdj[i].emplace_back(sources[i].x, sources[i].y - 1, 0);\n        else srcAdj[i].emplace_back(sources[i].x, sources[i].y + 1, 2);\n    }\n    for (int j = 0; j < D; j++) if (tarAdj[j].empty()) {\n        if (targets[j].y - 1 >= 0) tarAdj[j].emplace_back(targets[j].x, targets[j].y - 1, 0);\n        else tarAdj[j].emplace_back(targets[j].x, targets[j].y + 1, 2);\n    }\n\n    // Hungarian assignment with adjacency-aware costs\n    vector<vector<int>> cost(D, vector<int>(D, 0));\n    for (int i = 0; i < D; i++) {\n        for (int j = 0; j < D; j++) {\n            int best = INT_MAX;\n            for (auto &sa : srcAdj[i]) {\n                int sx, sy, sd; tie(sx, sy, sd) = sa;\n                for (auto &ta : tarAdj[j]) {\n                    int tx, ty, td; tie(tx, ty, td) = ta;\n                    int c = pureMoveCost(sx, sy, sd, tx, ty, td);\n                    if (c < best) best = c;\n                }\n            }\n            cost[i][j] = (best == INT_MAX ? 0 : best);\n        }\n    }\n    vector<int> pairTo(D, -1);\n    if (D > 0) {\n        auto res = Hungarian::solve(cost);\n        pairTo = res.second;\n    }\n\n    // Build per-task adjacency lists after assignment\n    vector<vector<tuple<int,int,int>>> pickAdj(D), dropAdj(D);\n    for (int i = 0; i < D; i++) {\n        pickAdj[i] = srcAdj[i];\n        dropAdj[i] = tarAdj[pairTo[i]];\n    }\n\n    // Build inter-task linkCost using adjacency-aware transitions\n    vector<vector<int>> linkCost(D, vector<int>(D, 0));\n    for (int i = 0; i < D; i++) {\n        for (int j = 0; j < D; j++) {\n            if (i == j) { linkCost[i][j] = 0; continue; }\n            int best = INT_MAX;\n            for (auto &di : dropAdj[i]) {\n                int dx, dy, dd; tie(dx, dy, dd) = di;\n                for (auto &pj : pickAdj[j]) {\n                    int px, py, pd; tie(px, py, pd) = pj;\n                    int c = pureMoveCost(dx, dy, dd, px, py, pd);\n                    if (c < best) best = c;\n                }\n            }\n            linkCost[i][j] = (best == INT_MAX ? 0 : best);\n        }\n    }\n\n    // Initial order via nearest neighbor on linkCost starting from a promising node\n    vector<int> ord;\n    ord.reserve(D);\n    if (D > 0) {\n        vector<int> minOut(D, INT_MAX), minIn(D, INT_MAX);\n        for (int i = 0; i < D; i++) {\n            for (int j = 0; j < D; j++) if (i != j) {\n                minOut[i] = min(minOut[i], linkCost[i][j]);\n                minIn[i]  = min(minIn[i],  linkCost[j][i]);\n            }\n            if (minOut[i] == INT_MAX) minOut[i] = 0;\n            if (minIn[i]  == INT_MAX) minIn[i]  = 0;\n        }\n        int start = 0; int bestScore = INT_MAX, bestOut = INT_MAX;\n        for (int i = 0; i < D; i++) {\n            int score = minOut[i] - minIn[i];\n            if (score < bestScore || (score == bestScore && minOut[i] < bestOut)) {\n                bestScore = score; bestOut = minOut[i]; start = i;\n            }\n        }\n        vector<char> used(D, 0);\n        int cur = start; used[cur] = 1; ord.push_back(cur);\n        for (int k = 1; k < D; k++) {\n            int bestj = -1, bestd = INT_MAX;\n            for (int j = 0; j < D; j++) if (!used[j]) {\n                int dlink = linkCost[cur][j];\n                if (dlink < bestd) { bestd = dlink; bestj = j; }\n            }\n            if (bestj == -1) {\n                for (int j = 0; j < D; j++) if (!used[j]) { bestj = j; break; }\n            }\n            used[bestj] = 1; ord.push_back(bestj); cur = bestj;\n        }\n    }\n\n    // Single-node or-opt refinement, multiple passes\n    if (D >= 3) {\n        bool improved = true;\n        for (int pass = 0; pass < 6 && improved; pass++) {\n            improved = false;\n            for (int i = 0; i < D; i++) {\n                int a = ord[i];\n                long long delta_rem = 0;\n                if (D >= 2) {\n                    if (i == 0) {\n                        delta_rem -= linkCost[ord[0]][ord[1]];\n                    } else if (i == D-1) {\n                        delta_rem -= linkCost[ord[D-2]][ord[D-1]];\n                    } else {\n                        delta_rem -= linkCost[ord[i-1]][ord[i]];\n                        delta_rem -= linkCost[ord[i]][ord[i+1]];\n                        delta_rem += linkCost[ord[i-1]][ord[i+1]];\n                    }\n                }\n                auto idxAfterRemoval = [&](int p)->int { return (p < i) ? ord[p] : ord[p+1]; };\n                long long bestDelta = 0;\n                int bestPos = -1;\n                for (int p = 0; p <= D-1; p++) {\n                    if (p == i || p == i+1) continue;\n                    long long delta_ins = 0;\n                    if (p == 0) {\n                        int nxt = idxAfterRemoval(0);\n                        delta_ins += linkCost[a][nxt];\n                    } else if (p == D-1) {\n                        int prv = idxAfterRemoval(D-2);\n                        delta_ins += linkCost[prv][a];\n                    } else {\n                        int prv = idxAfterRemoval(p-1);\n                        int nxt = idxAfterRemoval(p);\n                        delta_ins -= linkCost[prv][nxt];\n                        delta_ins += linkCost[prv][a] + linkCost[a][nxt];\n                    }\n                    long long delta = delta_rem + delta_ins;\n                    if (delta < bestDelta) { bestDelta = delta; bestPos = p; }\n                }\n                if (bestPos != -1) {\n                    vector<int> tmp; tmp.reserve(D);\n                    for (int k = 0; k < D; k++) if (k != i) tmp.push_back(ord[k]);\n                    tmp.insert(tmp.begin() + bestPos, a);\n                    ord.swap(tmp);\n                    improved = true;\n                }\n            }\n        }\n    }\n\n    if (D == 0) {\n        // No operations needed\n        cout << Vp << \"\\n\";\n        cout << 0 << \" \" << 1 << \"\\n\";\n        cout << 0 << \" \" << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Choose first task and initial root position (minimizes first task + heuristic link to next)\n    int first = ord[0];\n    int pIdx0 = 0, dIdx0 = 0;\n    {\n        const auto &PA = pickAdj[first];\n        const auto &DA = dropAdj[first];\n        int nextIdx = (D >= 2 ? ord[1] : -1);\n        long long best = LLONG_MAX;\n        for (int pi = 0; pi < (int)PA.size(); pi++) {\n            int px, py, pdir; tie(px, py, pdir) = PA[pi];\n            int costPick = fusedCost(px, py, 0, px, py, pdir, true); // initial dir=0\n            for (int di = 0; di < (int)DA.size(); di++) {\n                int dx, dy, ddir; tie(dx, dy, ddir) = DA[di];\n                int costDrop = fusedCost(px, py, pdir, dx, dy, ddir, true);\n                long long link = 0;\n                if (nextIdx >= 0) {\n                    const auto &NPA = pickAdj[nextIdx];\n                    int bestLink = INT_MAX;\n                    for (auto &np : NPA) {\n                        int nx, ny, nd; tie(nx, ny, nd) = np;\n                        int lk = pureMoveCost(dx, dy, ddir, nx, ny, nd);\n                        bestLink = min(bestLink, lk);\n                    }\n                    if (bestLink == INT_MAX) bestLink = 0;\n                    link = bestLink;\n                }\n                long long tot = (long long)costPick + costDrop + link;\n                if (tot < best) { best = tot; pIdx0 = pi; dIdx0 = di; }\n            }\n        }\n    }\n\n    // Initial root position at chosen first pick adjacency, orientation east\n    int rx, ry, dir;\n    {\n        int px, py, pdir; tie(px, py, pdir) = pickAdj[first][pIdx0];\n        rx = px; ry = py; dir = 0;\n    }\n\n    // Output design and initial root position\n    cout << Vp << \"\\n\";\n    cout << 0 << \" \" << 1 << \"\\n\";\n    cout << rx << \" \" << ry << \"\\n\";\n\n    vector<string> ops; ops.reserve(100000);\n    bool holding = false;\n\n    auto push_turn = [&](char moveCh, char rotCh, bool P) {\n        string s(2*Vp, '.');\n        s[0] = moveCh;\n        s[1] = (rotCh == 'L' || rotCh == 'R') ? rotCh : '.';\n        s[2] = '.';\n        s[3] = (P ? 'P' : '.');\n\n        if (moveCh == 'U') rx -= 1;\n        else if (moveCh == 'D') rx += 1;\n        else if (moveCh == 'L') ry -= 1;\n        else if (moveCh == 'R') ry += 1;\n        rx = max(0, min(N-1, rx));\n        ry = max(0, min(N-1, ry));\n\n        if (rotCh == 'L') dir = (dir + 3) % 4;\n        else if (rotCh == 'R') dir = (dir + 1) % 4;\n\n        if (P) {\n            int fx = rx + DX[dir];\n            int fy = ry + DY[dir];\n            if (0 <= fx && fx < N && 0 <= fy && fy < N) {\n                if (!holding) {\n                    if (occ[fx][fy] == 1) { occ[fx][fy] = 0; holding = true; }\n                } else {\n                    if (occ[fx][fy] == 0) { occ[fx][fy] = 1; holding = false; }\n                }\n            }\n        }\n        ops.push_back(s);\n    };\n    auto rotate_step_char = [&](int cur, int req) -> char {\n        int d = (req - cur + 4) % 4;\n        if (d == 0) return '.';\n        if (d == 1) return 'R';\n        if (d == 3) return 'L';\n        return 'R'; // d==2\n    };\n    auto move_rotate_to = [&](int tx, int ty, int reqdir, bool fuseP) {\n        int dx = abs(rx - tx);\n        int dy = abs(ry - ty);\n        int rotNeed = rotdist(dir, reqdir);\n        int totMoves = dx + dy;\n        int rotTail = max(0, rotNeed - totMoves);\n        int totalSteps = totMoves + rotTail;\n\n        int stepIdx = 0;\n        while (rx != tx) {\n            char mv = (rx < tx ? 'D' : 'U');\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn(mv, rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000) return;\n        }\n        while (ry != ty) {\n            char mv = (ry < ty ? 'R' : 'L');\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn(mv, rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000) return;\n        }\n        while (dir != reqdir) {\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn('.', rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000) return;\n        }\n        if (fuseP && totalSteps == 0) {\n            push_turn('.', '.', true);\n        }\n    };\n\n    // Execute first task\n    {\n        int px, py, pdir; tie(px, py, pdir) = pickAdj[first][pIdx0];\n        move_rotate_to(px, py, pdir, true);\n        int dx, dy, ddir; tie(dx, dy, ddir) = dropAdj[first][dIdx0];\n        move_rotate_to(dx, dy, ddir, true);\n    }\n\n    // Remaining tasks in fixed order with look-ahead\n    for (int k = 1; k < D; k++) {\n        if ((int)ops.size() >= 100000) break;\n        int idx = ord[k];\n        int nextIdx = (k+1 < D ? ord[k+1] : -1);\n        const auto &PA = pickAdj[idx];\n        const auto &DA = dropAdj[idx];\n        const auto &NPA = (nextIdx >= 0 ? pickAdj[nextIdx] : vector<tuple<int,int,int>>());\n        long long best = LLONG_MAX;\n        int pickIdx = 0, dropIdx = 0;\n        for (int pi = 0; pi < (int)PA.size(); pi++) {\n            int px, py, pdir; tie(px, py, pdir) = PA[pi];\n            int costPick = fusedCost(rx, ry, dir, px, py, pdir, true);\n            for (int di = 0; di < (int)DA.size(); di++) {\n                int dx, dy, ddir; tie(dx, dy, ddir) = DA[di];\n                int costDrop = fusedCost(px, py, pdir, dx, dy, ddir, true);\n                if (nextIdx < 0 || NPA.empty()) {\n                    long long tot = (long long)costPick + costDrop;\n                    if (tot < best) { best = tot; pickIdx = pi; dropIdx = di; }\n                } else {\n                    for (auto &np : NPA) {\n                        int nx, ny, nd; tie(nx, ny, nd) = np;\n                        int link = pureMoveCost(dx, dy, ddir, nx, ny, nd);\n                        long long tot = (long long)costPick + costDrop + link;\n                        if (tot < best) { best = tot; pickIdx = pi; dropIdx = di; }\n                    }\n                }\n            }\n        }\n        int px, py, pdir; tie(px, py, pdir) = pickAdj[idx][pickIdx];\n        move_rotate_to(px, py, pdir, true);\n        int dx, dy, ddir; tie(dx, dy, ddir) = dropAdj[idx][dropIdx];\n        move_rotate_to(dx, dy, ddir, true);\n    }\n\n    for (auto &s : ops) cout << s << \"\\n\";\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int LIM = 100000;\nstatic const int PERIM_LIMIT = 400000;\n\nstruct Pt { int x, y, w; };\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nstruct Candidate {\n    vector<pair<int,int>> poly;\n    long long exactScore = LLONG_MIN;\n};\n\nstatic bool point_on_edge(const vector<pair<int,int>>& poly, int x, int y) {\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        int x1 = poly[i].first, y1 = poly[i].second;\n        int x2 = poly[(i+1)%m].first, y2 = poly[(i+1)%m].second;\n        if (x1 == x2) {\n            if (x == x1) {\n                int lo = min(y1, y2), hi = max(y1, y2);\n                if (lo <= y && y <= hi) return true;\n            }\n        } else if (y1 == y2) {\n            if (y == y1) {\n                int lo = min(x1, x2), hi = max(x1, x2);\n                if (lo <= x && x <= hi) return true;\n            }\n        }\n    }\n    return false;\n}\n\nstatic bool point_in_polygon(const vector<pair<int,int>>& poly, int x, int y) {\n    if (point_on_edge(poly, x, y)) return true;\n    bool inside = false;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        int x1 = poly[i].first, y1 = poly[i].second;\n        int x2 = poly[(i+1)%m].first, y2 = poly[(i+1)%m].second;\n        if (y1 == y2) continue;\n        int ymin = min(y1, y2), ymax = max(y1, y2);\n        if (y < ymin || y >= ymax) continue;\n        double xint;\n        if (x1 == x2) xint = x1;\n        else xint = x1 + (double)(x2 - x1) * (double)(y - y1) / (double)(y2 - y1);\n        if ((double)x < xint) inside = !inside;\n    }\n    return inside;\n}\n\nstatic long long exact_score_polygon(const vector<pair<int,int>>& poly, const vector<Pt>& pts) {\n    long long s = 0;\n    for (const auto& p : pts) if (point_in_polygon(poly, p.x, p.y)) s += p.w;\n    return s;\n}\n\nstatic long long polygon_perimeter(const vector<pair<int,int>>& poly) {\n    long long peri = 0;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        auto a = poly[i];\n        auto b = poly[(i+1)%m];\n        peri += llabs((long long)a.first - b.first) + llabs((long long)a.second - b.second);\n    }\n    return peri;\n}\n\n// Build grid weights\nstatic vector<vector<int>> build_grid_W(int G, const vector<Pt>& pts) {\n    vector<vector<int>> W(G, vector<int>(G, 0));\n    for (const auto& p : pts) {\n        int xi = (int)((long long)p.x * G / 100001); if (xi < 0) xi = 0; if (xi >= G) xi = G-1;\n        int yi = (int)((long long)p.y * G / 100001); if (yi < 0) yi = 0; if (yi >= G) yi = G-1;\n        W[yi][xi] += p.w;\n    }\n    return W;\n}\n\n// Grid lines: ceil(i*100001/G), capped to LIM\nstatic void build_grid_lines(int G, vector<int>& xs, vector<int>& ys) {\n    xs.resize(G+1); ys.resize(G+1);\n    for (int i = 0; i <= G; ++i) {\n        long long t = 1LL * i * 100001;\n        int v = (int)((t + G - 1) / G);\n        if (v > LIM) v = LIM;\n        xs[i] = v;\n        ys[i] = v;\n    }\n}\n\n// Coarse best rectangle (Kadane over W)\nstruct RectIdx { int L, R, B, T; };\nstatic RectIdx coarse_best_rect_from_W(const vector<vector<int>>& W) {\n    int H = (int)W.size();\n    if (H == 0) return {0,0,0,0};\n    int G = (int)W[0].size();\n    vector<long long> acc(G);\n    long long bestSum = LLONG_MIN;\n    RectIdx best{0,0,0,0};\n    for (int top = 0; top < H; ++top) {\n        fill(acc.begin(), acc.end(), 0);\n        for (int bot = top; bot < H; ++bot) {\n            for (int j = 0; j < G; ++j) acc[j] += W[bot][j];\n            long long s = 0, best1D = LLONG_MIN;\n            int start = 0, l = 0, r = -1;\n            for (int j = 0; j < G; ++j) {\n                if (s <= 0) { s = acc[j]; start = j; }\n                else s += acc[j];\n                if (best1D == LLONG_MIN || s > best1D) { best1D = s; l = start; r = j; }\n            }\n            if (best1D > bestSum) {\n                bestSum = best1D;\n                best = {l, r, top, bot};\n            }\n        }\n    }\n    return best;\n}\n\nstatic vector<pair<int,int>> rect_to_polygon(const RectIdx& r, const vector<int>& xs, const vector<int>& ys) {\n    int Lx = xs[r.L];\n    int Rx = xs[r.R+1] - 1; if (Rx < Lx) Rx = Lx;\n    int By = ys[r.B];\n    int Ty = ys[r.T+1] - 1; if (Ty < By) Ty = By;\n    vector<pair<int,int>> poly;\n    poly.emplace_back(Lx, By);\n    poly.emplace_back(Rx, By);\n    poly.emplace_back(Rx, Ty);\n    poly.emplace_back(Lx, Ty);\n    return poly;\n}\n\n// Region growth\nstruct RegionGrower {\n    int G;\n    vector<vector<int>> W;  // [j][i]\n    vector<int> xs, ys;\n    vector<int> wx, hy;\n    vector<vector<char>> inR;\n    vector<vector<unsigned char>> nmask;\n\n    RegionGrower(int G_, const vector<vector<int>>& W_, const vector<int>& xs_, const vector<int>& ys_)\n        : G(G_), W(W_), xs(xs_), ys(ys_) {\n        wx.resize(G); hy.resize(G);\n        for (int i = 0; i < G; ++i) {\n            wx[i] = xs[i+1] - xs[i]; if (wx[i] < 1) wx[i] = 1;\n            hy[i] = ys[i+1] - ys[i]; if (hy[i] < 1) hy[i] = 1;\n        }\n        inR.assign(G, vector<char>(G, 0));\n        nmask.assign(G, vector<unsigned char>(G, 0));\n    }\n\n    inline int delta_perim_for_cell(int i, int j, unsigned char mask) const {\n        int left = (mask & 1) ? 1 : 0;\n        int right = (mask & 2) ? 1 : 0;\n        int bottom = (mask & 4) ? 1 : 0;\n        int top = (mask & 8) ? 1 : 0;\n        int res = 2 * (wx[i] + hy[j]) - 2 * ( hy[j]*(left + right) + wx[i]*(bottom + top) );\n        return res;\n    }\n    inline bool inside_bounds(int i, int j) const { return 0 <= i && i < G && 0 <= j && j < G; }\n\n    void reset() {\n        for (int j = 0; j < G; ++j) {\n            fill(inR[j].begin(), inR[j].end(), 0);\n            fill(nmask[j].begin(), nmask[j].end(), 0);\n        }\n    }\n\n    struct GrowResult {\n        vector<vector<char>> inside;\n        long long approxScore = 0;\n        long long perim = 0;\n        bool valid = false;\n    };\n\n    struct PQEntry {\n        double key;\n        int i, j;\n        int ver;\n        bool operator<(const PQEntry& other) const { return key < other.key; } // largest first\n    };\n\n    // Add seed-based growth, then fill holes and prune negative leaves\n    GrowResult grow_from_seed(int si, int sj, int mode, double lambda, double time_limit_sec, Timer& tim) {\n        reset();\n        vector<vector<int>> ver(G, vector<int>(G, 0));\n        priority_queue<PQEntry> pq;\n        auto push_update = [&](int i, int j) {\n            if (inR[j][i]) return;\n            unsigned char mask = nmask[j][i];\n            if (mask == 0) return;\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                double gain = (double)sc;\n                // allow adding if sc>0 or if closing perimeter significantly\n                if (sc <= 0 && dper >= 0) return;\n                double key = (double)sc / (double)max(1, dper);\n                key += 1e-9 * sc;\n                pq.push({key, i, j, ++ver[j][i]});\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) return;\n                pq.push({gain, i, j, ++ver[j][i]});\n            }\n        };\n\n        long long perim = 0;\n\n        auto add_cell = [&](int ci, int cj) {\n            unsigned char mask = 0;\n            if (ci > 0 && inR[cj][ci-1]) mask |= 1;\n            if (ci+1 < G && inR[cj][ci+1]) mask |= 2;\n            if (cj > 0 && inR[cj-1][ci]) mask |= 4;\n            if (cj+1 < G && inR[cj+1][ci]) mask |= 8;\n            int dper = delta_perim_for_cell(ci, cj, mask);\n            perim += dper;\n            inR[cj][ci] = 1;\n            if (ci > 0 && !inR[cj][ci-1]) { nmask[cj][ci-1] |= 2; push_update(ci-1, cj); }\n            if (ci+1 < G && !inR[cj][ci+1]) { nmask[cj][ci+1] |= 1; push_update(ci+1, cj); }\n            if (cj > 0 && !inR[cj-1][ci]) { nmask[cj-1][ci] |= 8; push_update(ci, cj-1); }\n            if (cj+1 < G && !inR[cj+1][ci]) { nmask[cj+1][ci] |= 4; push_update(ci, cj+1); }\n        };\n\n        if (mode == 0 && W[sj][si] <= 0) {\n            GrowResult gr; gr.valid = false; return gr;\n        }\n        add_cell(si, sj);\n        if (perim > PERIM_LIMIT) { GrowResult gr; gr.valid = false; return gr; }\n\n        while (!pq.empty()) {\n            if (tim.elapsed() > time_limit_sec) break;\n            auto e = pq.top(); pq.pop();\n            int i = e.i, j = e.j;\n            if (inR[j][i]) continue;\n            if (e.ver != ver[j][i]) continue;\n            unsigned char mask = nmask[j][i];\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (!(sc > 0 || (dper < 0 && sc + 0.0 > -0.5))) continue;\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) continue;\n            }\n            if (perim + dper > PERIM_LIMIT) continue;\n            add_cell(i, j);\n        }\n\n        // Build inside by filling holes\n        auto inside = fill_holes(inR);\n        // Prune negative leaves\n        prune_negative_leaves(inside);\n\n        long long approxScore = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (inside[j][i]) approxScore += W[j][i];\n\n        GrowResult gr;\n        gr.inside = move(inside);\n        gr.approxScore = approxScore;\n        gr.perim = compute_perimeter(gr.inside);\n        gr.valid = true;\n        return gr;\n    }\n\n    // Continue growing from an existing mask\n    GrowResult grow_from_mask(vector<vector<char>> inside, int mode, double lambda, double time_limit_sec, Timer& tim) {\n        // Initialize inR and nmask from provided mask\n        for (int j = 0; j < G; ++j) {\n            for (int i = 0; i < G; ++i) {\n                inR[j][i] = inside[j][i] ? 1 : 0;\n                nmask[j][i] = 0;\n            }\n        }\n        vector<vector<int>> ver(G, vector<int>(G, 0));\n        priority_queue<PQEntry> pq;\n\n        auto set_frontier_for_cell = [&](int i, int j) {\n            if (!inR[j][i]) return;\n            if (i > 0 && !inR[j][i-1]) nmask[j][i-1] |= 2;\n            if (i+1 < G && !inR[j][i+1]) nmask[j][i+1] |= 1;\n            if (j > 0 && !inR[j-1][i]) nmask[j-1][i] |= 8;\n            if (j+1 < G && !inR[j+1][i]) nmask[j+1][i] |= 4;\n        };\n\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) set_frontier_for_cell(i,j);\n\n        auto push_update = [&](int i, int j) {\n            if (inR[j][i]) return;\n            unsigned char mask = nmask[j][i];\n            if (mask == 0) return;\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (!(sc > 0 || (dper < 0 && sc + 0.0 > -0.5))) return;\n                double key = (double)sc / (double)max(1, dper);\n                key += 1e-9 * sc;\n                pq.push({key, i, j, ++ver[j][i]});\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) return;\n                pq.push({gain, i, j, ++ver[j][i]});\n            }\n        };\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (!inR[j][i]) push_update(i,j);\n\n        long long perim = compute_perimeter(inR);\n        auto add_cell = [&](int ci, int cj) {\n            unsigned char mask = 0;\n            if (ci > 0 && inR[cj][ci-1]) mask |= 1;\n            if (ci+1 < G && inR[cj][ci+1]) mask |= 2;\n            if (cj > 0 && inR[cj-1][ci]) mask |= 4;\n            if (cj+1 < G && inR[cj+1][ci]) mask |= 8;\n            int dper = delta_perim_for_cell(ci, cj, mask);\n            perim += dper;\n            inR[cj][ci] = 1;\n            if (ci > 0 && !inR[cj][ci-1]) { nmask[cj][ci-1] |= 2; push_update(ci-1, cj); }\n            if (ci+1 < G && !inR[cj][ci+1]) { nmask[cj][ci+1] |= 1; push_update(ci+1, cj); }\n            if (cj > 0 && !inR[cj-1][ci]) { nmask[cj-1][ci] |= 8; push_update(ci, cj-1); }\n            if (cj+1 < G && !inR[cj+1][ci]) { nmask[cj+1][ci] |= 4; push_update(ci, cj+1); }\n        };\n\n        while (!pq.empty()) {\n            if (tim.elapsed() > time_limit_sec) break;\n            auto e = pq.top(); pq.pop();\n            int i = e.i, j = e.j;\n            if (inR[j][i]) continue;\n            if (e.ver != ver[j][i]) continue;\n            unsigned char mask = nmask[j][i];\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (!(sc > 0 || (dper < 0 && sc + 0.0 > -0.5))) continue;\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) continue;\n            }\n            if (perim + dper > PERIM_LIMIT) continue;\n            add_cell(i, j);\n        }\n\n        auto inside2 = fill_holes(inR);\n        prune_negative_leaves(inside2);\n\n        GrowResult gr;\n        gr.inside = move(inside2);\n        gr.approxScore = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (gr.inside[j][i]) gr.approxScore += W[j][i];\n        gr.perim = compute_perimeter(gr.inside);\n        gr.valid = true;\n        return gr;\n    }\n\n    // Compute perimeter of a mask\n    long long compute_perimeter(const vector<vector<char>>& mask) const {\n        long long per = 0;\n        for (int j = 0; j < G; ++j) {\n            for (int i = 0; i < G; ++i) {\n                if (!mask[j][i]) continue;\n                if (i == 0 || !mask[j][i-1]) per += hy[j];\n                if (i+1 == G || !mask[j][i+1]) per += hy[j];\n                if (j == 0 || !mask[j-1][i]) per += wx[i];\n                if (j+1 == G || !mask[j+1][i]) per += wx[i];\n            }\n        }\n        return per;\n    }\n\n    // Fill holes (outside reachable from border)\n    vector<vector<char>> fill_holes(const vector<vector<char>>& sel) const {\n        vector<vector<char>> visited(G, vector<char>(G, 0));\n        deque<pair<int,int>> dq;\n        auto push_border = [&](int i, int j) {\n            if (!inside_bounds(i,j)) return;\n            if (sel[j][i]) return;\n            if (visited[j][i]) return;\n            visited[j][i] = 1;\n            dq.emplace_back(i,j);\n        };\n        for (int i = 0; i < G; ++i) { push_border(i, 0); push_border(i, G-1); }\n        for (int j = 0; j < G; ++j) { push_border(0, j); push_border(G-1, j); }\n        while (!dq.empty()) {\n            auto [i, j] = dq.front(); dq.pop_front();\n            auto try_push = [&](int ni, int nj) {\n                if (!inside_bounds(ni,nj)) return;\n                if (sel[nj][ni]) return;\n                if (visited[nj][ni]) return;\n                visited[nj][ni] = 1;\n                dq.emplace_back(ni,nj);\n            };\n            try_push(i-1,j); try_push(i+1,j); try_push(i,j-1); try_push(i,j+1);\n        }\n        vector<vector<char>> inside(G, vector<char>(G, 0));\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) inside[j][i] = sel[j][i] || (!visited[j][i] && !sel[j][i]);\n        return inside;\n    }\n\n    // Prune negative leaves to clean spurs\n    void prune_negative_leaves(vector<vector<char>>& inside) const {\n        auto deg = [&](int i, int j)->int {\n            int d = 0;\n            if (i > 0 && inside[j][i-1]) ++d;\n            if (i+1 < G && inside[j][i+1]) ++d;\n            if (j > 0 && inside[j-1][i]) ++d;\n            if (j+1 < G && inside[j+1][i]) ++d;\n            return d;\n        };\n        deque<pair<int,int>> dq;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) {\n            if (!inside[j][i]) continue;\n            if (W[j][i] < 0 && deg(i,j) <= 1) dq.emplace_back(i,j);\n        }\n        int cntInside = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (inside[j][i]) ++cntInside;\n        while (!dq.empty()) {\n            auto [i,j] = dq.front(); dq.pop_front();\n            if (!inside[j][i]) continue;\n            if (W[j][i] >= 0) continue;\n            int d = deg(i,j);\n            if (d > 1) continue;\n            // avoid removing last cell\n            if (cntInside <= 1) break;\n            inside[j][i] = 0;\n            --cntInside;\n            // neighbors might become leaves now\n            if (i > 0 && inside[j][i-1] && W[j][i-1] < 0 && deg(i-1,j) <= 1) dq.emplace_back(i-1,j);\n            if (i+1 < G && inside[j][i+1] && W[j][i+1] < 0 && deg(i+1,j) <= 1) dq.emplace_back(i+1,j);\n            if (j > 0 && inside[j-1][i] && W[j-1][i] < 0 && deg(i,j-1) <= 1) dq.emplace_back(i,j-1);\n            if (j+1 < G && inside[j+1][i] && W[j+1][i] < 0 && deg(i,j+1) <= 1) dq.emplace_back(i,j+1);\n        }\n    }\n\n    // Convert inside mask to boundary polygon\n    vector<pair<int,int>> inside_to_polygon(const vector<vector<char>>& inside) const {\n        struct KeyHash { size_t operator()(const uint64_t& k) const noexcept { return std::hash<uint64_t>{}(k); } };\n        auto keyOf = [&](int x, int y)->uint64_t { return (uint64_t)((uint32_t)x) << 32 | (uint32_t)y; };\n        unordered_map<uint64_t, int, KeyHash> id;\n        vector<pair<int,int>> verts;\n        vector<vector<int>> adj;\n\n        auto get_id = [&](int x, int y)->int {\n            uint64_t key = keyOf(x, y);\n            auto it = id.find(key);\n            if (it != id.end()) return it->second;\n            int idx = (int)verts.size();\n            verts.emplace_back(x, y);\n            adj.emplace_back();\n            id.emplace(key, idx);\n            return idx;\n        };\n        auto add_edge = [&](int x1, int y1, int x2, int y2){\n            if (x1 == x2 && y1 == y2) return;\n            int a = get_id(x1, y1);\n            int b = get_id(x2, y2);\n            adj[a].push_back(b);\n            adj[b].push_back(a);\n        };\n\n        for (int j = 0; j < G; ++j) {\n            for (int i = 0; i < G; ++i) {\n                if (!inside[j][i]) continue;\n                int x0 = xs[i], x1 = xs[i+1];\n                int y0 = ys[j], y1 = ys[j+1];\n                if (i == 0 || !inside[j][i-1]) add_edge(x0, y0, x0, y1);\n                if (i+1 == G || !inside[j][i+1]) add_edge(x1, y0, x1, y1);\n                if (j == 0 || !inside[j-1][i]) add_edge(x0, y0, x1, y0);\n                if (j+1 == G || !inside[j+1][i]) add_edge(x0, y1, x1, y1);\n            }\n        }\n        if (verts.empty()) return {};\n        // find start vertex: minimal (y, x)\n        int start = 0;\n        for (int i = 1; i < (int)verts.size(); ++i) {\n            if (verts[i].second < verts[start].second ||\n                (verts[i].second == verts[start].second && verts[i].first < verts[start].first)) {\n                start = i;\n            }\n        }\n        // Traverse one cycle\n        vector<int> path;\n        int cur = start, prev = -1;\n        unordered_set<long long> usedEdge; usedEdge.reserve(adj.size()*2+1);\n        auto edgeKey = [&](int a, int b)->long long { if (a<b) return ((long long)a<<32)|b; else return ((long long)b<<32)|a; };\n        for (int step = 0; step < 400000; ++step) {\n            path.push_back(cur);\n            int next = -1;\n            for (int nb : adj[cur]) {\n                if (nb == prev) continue;\n                long long ek = edgeKey(cur, nb);\n                if (usedEdge.find(ek) != usedEdge.end()) continue;\n                next = nb; break;\n            }\n            if (next == -1) {\n                if (!adj[cur].empty()) {\n                    int nb = adj[cur][0];\n                    long long ek = edgeKey(cur, nb);\n                    if (usedEdge.find(ek) == usedEdge.end()) next = nb;\n                }\n            }\n            if (next == -1) break;\n            usedEdge.insert(edgeKey(cur, next));\n            prev = cur;\n            cur = next;\n            if (cur == start) break;\n        }\n        vector<pair<int,int>> poly;\n        for (int idv : path) poly.push_back(verts[idv]);\n        if (!poly.empty() && poly.front() == poly.back()) poly.pop_back();\n        // remove consecutive duplicates\n        vector<pair<int,int>> tmp;\n        for (auto &p : poly) { if (!tmp.empty() && tmp.back() == p) continue; tmp.push_back(p); }\n        poly.swap(tmp);\n        // simplify collinear\n        if (poly.size() >= 3) {\n            vector<pair<int,int>> simp;\n            int m = (int)poly.size();\n            for (int i = 0; i < m; ++i) {\n                auto p0 = poly[(i + m - 1) % m];\n                auto p1 = poly[i];\n                auto p2 = poly[(i + 1) % m];\n                bool col = ( (p0.first == p1.first && p1.first == p2.first) ||\n                             (p0.second == p1.second && p1.second == p2.second) );\n                if (!col) simp.push_back(p1);\n            }\n            poly.swap(simp);\n        }\n        return poly;\n    }\n};\n\n// Rectangle refinement baseline\nstruct Rect {\n    int L, R, B, T;\n    long long perim() const { return 2LL * (max(0, R - L) + max(0, T - B)); }\n    void ensure_min_size() {\n        L = max(L, 0); B = max(B, 0); R = min(R, LIM); T = min(T, LIM);\n        if (L >= R) { if (L > 0) L = R - 1; else R = L + 1; }\n        if (B >= T) { if (B > 0) B = T - 1; else T = B + 1; }\n        L = max(L, 0); B = max(B, 0); R = min(R, LIM); T = min(T, LIM);\n    }\n};\nstruct ColData { vector<int> xs; vector<vector<int>> ys; vector<vector<int>> pref; };\nstruct RowData { vector<int> ys; vector<vector<int>> xs; vector<vector<int>> pref; };\n\nstruct Refiner {\n    const ColData &col; const RowData &row;\n    Refiner(const ColData& c, const RowData& r): col(c), row(r) {}\n    inline int col_sum_idx(int xi, int B, int T) const {\n        if (xi < 0 || xi >= (int)col.xs.size()) return 0;\n        const auto &ysv = col.ys[xi]; const auto &pf = col.pref[xi];\n        auto itL = lower_bound(ysv.begin(), ysv.end(), B);\n        auto itR = upper_bound(ysv.begin(), ysv.end(), T);\n        int l = (int)(itL - ysv.begin()), r = (int)(itR - ysv.begin());\n        return pf[r] - pf[l];\n    }\n    inline int row_sum_idx(int yi, int L, int R) const {\n        if (yi < 0 || yi >= (int)row.ys.size()) return 0;\n        const auto &xsv = row.xs[yi]; const auto &pf = row.pref[yi];\n        auto itL = lower_bound(xsv.begin(), xsv.end(), L);\n        auto itR = upper_bound(xsv.begin(), xsv.end(), R);\n        int l = (int)(itL - xsv.begin()), r = (int)(itR - xsv.begin());\n        return pf[r] - pf[l];\n    }\n    long long rect_sum(Rect r) const {\n        auto itL = lower_bound(col.xs.begin(), col.xs.end(), r.L);\n        auto itR = upper_bound(col.xs.begin(), col.xs.end(), r.R);\n        long long s = 0;\n        for (auto it = itL; it != itR; ++it) {\n            int xi = (int)(it - col.xs.begin());\n            s += col_sum_idx(xi, r.B, r.T);\n        }\n        return s;\n    }\n    pair<long long,int> best_expand_left(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.L};\n        int kmax = (int)min<long long>(r.L, remain / 2); if (kmax <= 0) return {0, r.L};\n        int idx = (int)(lower_bound(col.xs.begin(), col.xs.end(), r.L) - col.xs.begin()) - 1;\n        if (idx < 0) return {0, r.L};\n        int xLower = r.L - kmax; long long best = 0, run = 0; int bestL = r.L;\n        for (int i = idx; i >= 0; --i) {\n            int x = col.xs[i]; if (x < xLower) break;\n            run += col_sum_idx(i, r.B, r.T);\n            if (run > best) { best = run; bestL = x; }\n        }\n        return {best, bestL};\n    }\n    pair<long long,int> best_shrink_left(const Rect& r) const {\n        if (r.L >= r.R) return {0, r.L};\n        int targetMax = r.R - 1;\n        int iL = (int)(lower_bound(col.xs.begin(), col.xs.end(), r.L) - col.xs.begin());\n        int iR = (int)(upper_bound(col.xs.begin(), col.xs.end(), targetMax) - col.xs.begin()) - 1;\n        if (iL > iR) return {0, r.L};\n        long long best = 0, run = 0; int bestL = r.L;\n        for (int i = iL; i <= iR; ++i) {\n            run += - (long long)col_sum_idx(i, r.B, r.T);\n            if (run > best) {\n                best = run;\n                int newL = col.xs[i] + 1; if (newL > targetMax) newL = targetMax;\n                bestL = newL;\n            }\n        }\n        return {best, bestL};\n    }\n    pair<long long,int> best_expand_right(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.R};\n        int kmax = (int)min<long long>(LIM - r.R, remain / 2); if (kmax <= 0) return {0, r.R};\n        int idx = (int)(upper_bound(col.xs.begin(), col.xs.end(), r.R) - col.xs.begin());\n        if (idx >= (int)col.xs.size()) return {0, r.R};\n        int xUpper = r.R + kmax; long long best = 0, run = 0; int bestR = r.R;\n        for (int i = idx; i < (int)col.xs.size(); ++i) {\n            int x = col.xs[i]; if (x > xUpper) break;\n            run += col_sum_idx(i, r.B, r.T);\n            if (run > best) { best = run; bestR = x; }\n        }\n        return {best, bestR};\n    }\n    pair<long long,int> best_shrink_right(const Rect& r) const {\n        if (r.L >= r.R) return {0, r.R};\n        int targetMin = r.L + 1;\n        int iL = (int)(lower_bound(col.xs.begin(), col.xs.end(), targetMin) - col.xs.begin());\n        int iR = (int)(upper_bound(col.xs.begin(), col.xs.end(), r.R) - col.xs.begin()) - 1;\n        if (iL > iR) return {0, r.R};\n        long long best = 0, run = 0; int bestR = r.R;\n        for (int i = iR; i >= iL; --i) {\n            run += - (long long)col_sum_idx(i, r.B, r.T);\n            if (run > best) {\n                best = run;\n                int newR = col.xs[i] - 1; if (newR < targetMin) newR = targetMin;\n                bestR = newR;\n            }\n        }\n        return {best, bestR};\n    }\n    pair<long long,int> best_expand_bottom(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.B};\n        int kmax = (int)min<long long>(r.B, remain / 2); if (kmax <= 0) return {0, r.B};\n        int idx = (int)(lower_bound(row.ys.begin(), row.ys.end(), r.B) - row.ys.begin()) - 1;\n        if (idx < 0) return {0, r.B};\n        int yLower = r.B - kmax; long long best = 0, run = 0; int bestB = r.B;\n        for (int i = idx; i >= 0; --i) {\n            int y = row.ys[i]; if (y < yLower) break;\n            run += row_sum_idx(i, r.L, r.R);\n            if (run > best) { best = run; bestB = y; }\n        }\n        return {best, bestB};\n    }\n    pair<long long,int> best_shrink_bottom(const Rect& r) const {\n        if (r.B >= r.T) return {0, r.B};\n        int targetMax = r.T - 1;\n        int iL = (int)(lower_bound(row.ys.begin(), row.ys.end(), r.B) - row.ys.begin());\n        int iR = (int)(upper_bound(row.ys.begin(), row.ys.end(), targetMax) - row.ys.begin()) - 1;\n        if (iL > iR) return {0, r.B};\n        long long best = 0, run = 0; int bestB = r.B;\n        for (int i = iL; i <= iR; ++i) {\n            run += - (long long)row_sum_idx(i, r.L, r.R);\n            if (run > best) {\n                best = run;\n                int newB = row.ys[i] + 1; if (newB > targetMax) newB = targetMax;\n                bestB = newB;\n            }\n        }\n        return {best, bestB};\n    }\n    pair<long long,int> best_expand_top(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.T};\n        int kmax = (int)min<long long>(LIM - r.T, remain / 2); if (kmax <= 0) return {0, r.T};\n        int idx = (int)(upper_bound(row.ys.begin(), row.ys.end(), r.T) - row.ys.begin());\n        if (idx >= (int)row.ys.size()) return {0, r.T};\n        int yUpper = r.T + kmax; long long best = 0, run = 0; int bestT = r.T;\n        for (int i = idx; i < (int)row.ys.size(); ++i) {\n            int y = row.ys[i]; if (y > yUpper) break;\n            run += row_sum_idx(i, r.L, r.R);\n            if (run > best) { best = run; bestT = y; }\n        }\n        return {best, bestT};\n    }\n    pair<long long,int> best_shrink_top(const Rect& r) const {\n        if (r.B >= r.T) return {0, r.T};\n        int targetMin = r.B + 1;\n        int iL = (int)(lower_bound(row.ys.begin(), row.ys.end(), targetMin) - row.ys.begin());\n        int iR = (int)(upper_bound(row.ys.begin(), row.ys.end(), r.T) - row.ys.begin()) - 1;\n        if (iL > iR) return {0, r.T};\n        long long best = 0, run = 0; int bestT = r.T;\n        for (int i = iR; i >= iL; --i) {\n            run += - (long long)row_sum_idx(i, r.L, r.R);\n            if (run > best) {\n                best = run;\n                int newT = row.ys[i] - 1; if (newT < targetMin) newT = targetMin;\n                bestT = newT;\n            }\n        }\n        return {best, bestT};\n    }\n\n    Rect refine(Rect r) const {\n        r.ensure_min_size();\n        long long curPerim = r.perim();\n        for (int it = 0; it < 200; ++it) {\n            array<long long, 8> delta{};\n            array<int, 8> newCoord{};\n            auto [d0, nl0] = best_expand_left(r, curPerim);\n            delta[0] = d0; newCoord[0] = nl0;\n            auto [d1, nl1] = best_shrink_left(r);\n            delta[1] = d1; newCoord[1] = nl1;\n            auto [d2, nr2] = best_expand_right(r, curPerim);\n            delta[2] = d2; newCoord[2] = nr2;\n            auto [d3, nr3] = best_shrink_right(r);\n            delta[3] = d3; newCoord[3] = nr3;\n            auto [d4, nb4] = best_expand_bottom(r, curPerim);\n            delta[4] = d4; newCoord[4] = nb4;\n            auto [d5, nb5] = best_shrink_bottom(r);\n            delta[5] = d5; newCoord[5] = nb5;\n            auto [d6, nt6] = best_expand_top(r, curPerim);\n            delta[6] = d6; newCoord[6] = nt6;\n            auto [d7, nt7] = best_shrink_top(r);\n            delta[7] = d7; newCoord[7] = nt7;\n            long long bestDelta = 0; int bestMove = -1;\n            for (int k = 0; k < 8; ++k) if (delta[k] > bestDelta) { bestDelta = delta[k]; bestMove = k; }\n            if (bestDelta <= 0) break;\n            if (bestMove == 0) { int oldL = r.L; r.L = newCoord[0]; curPerim += 2LL * (oldL - r.L); }\n            else if (bestMove == 1) { int oldL = r.L; r.L = newCoord[1]; curPerim -= 2LL * (r.L - oldL); }\n            else if (bestMove == 2) { int oldR = r.R; r.R = newCoord[2]; curPerim += 2LL * (r.R - oldR); }\n            else if (bestMove == 3) { int oldR = r.R; r.R = newCoord[3]; curPerim -= 2LL * (oldR - r.R); }\n            else if (bestMove == 4) { int oldB = r.B; r.B = newCoord[4]; curPerim += 2LL * (oldB - r.B); }\n            else if (bestMove == 5) { int oldB = r.B; r.B = newCoord[5]; curPerim -= 2LL * (r.B - oldB); }\n            else if (bestMove == 6) { int oldT = r.T; r.T = newCoord[6]; curPerim += 2LL * (r.T - oldT); }\n            else if (bestMove == 7) { int oldT = r.T; r.T = newCoord[7]; curPerim -= 2LL * (oldT - r.T); }\n            r.ensure_min_size();\n            if (curPerim > PERIM_LIMIT) {\n                while (r.perim() > PERIM_LIMIT && r.R - r.L > 1) --r.R;\n                while (r.perim() > PERIM_LIMIT && r.T - r.B > 1) --r.T;\n                curPerim = r.perim();\n            }\n        }\n        r.ensure_min_size();\n        return r;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<Pt> pts;\n    pts.reserve(2*N);\n    for (int i = 0; i < N; ++i) { int x,y; cin >> x >> y; pts.push_back({x,y,+1}); }\n    for (int i = 0; i < N; ++i) { int x,y; cin >> x >> y; pts.push_back({x,y,-1}); }\n\n    Timer tim;\n    const double TL = 1.98;\n\n    vector<Candidate> candidates;\n\n    // Rectangle refiner preprocessing\n    ColData col; RowData row;\n    {\n        vector<int> allX, allY;\n        allX.reserve(pts.size()); allY.reserve(pts.size());\n        for (auto &p : pts) { allX.push_back(p.x); allY.push_back(p.y); }\n        sort(allX.begin(), allX.end()); allX.erase(unique(allX.begin(), allX.end()), allX.end());\n        sort(allY.begin(), allY.end()); allY.erase(unique(allY.begin(), allY.end()), allY.end());\n        col.xs = allX; row.ys = allY;\n        col.ys.assign(col.xs.size(), {}); col.pref.assign(col.xs.size(), {});\n        row.xs.assign(row.ys.size(), {}); row.pref.assign(row.ys.size(), {});\n        vector<vector<pair<int,int>>> tempX(col.xs.size());\n        vector<vector<pair<int,int>>> tempY(row.ys.size());\n        for (const auto& p : pts) {\n            int xi = (int)(lower_bound(col.xs.begin(), col.xs.end(), p.x) - col.xs.begin());\n            int yi = (int)(lower_bound(row.ys.begin(), row.ys.end(), p.y) - row.ys.begin());\n            tempX[xi].emplace_back(p.y, p.w);\n            tempY[yi].emplace_back(p.x, p.w);\n        }\n        for (size_t i = 0; i < tempX.size(); ++i) {\n            auto &vec = tempX[i];\n            sort(vec.begin(), vec.end());\n            vector<int> ysMerged; vector<int> wsMerged;\n            ysMerged.reserve(vec.size()); wsMerged.reserve(vec.size());\n            for (size_t k = 0; k < vec.size();) {\n                int y = vec[k].first; int s = 0; size_t k2 = k;\n                while (k2 < vec.size() && vec[k2].first == y) { s += vec[k2].second; ++k2; }\n                ysMerged.push_back(y); wsMerged.push_back(s); k = k2;\n            }\n            col.ys[i] = move(ysMerged);\n            col.pref[i].assign(wsMerged.size()+1, 0);\n            for (size_t t = 0; t < wsMerged.size(); ++t) col.pref[i][t+1] = col.pref[i][t] + wsMerged[t];\n        }\n        for (size_t i = 0; i < tempY.size(); ++i) {\n            auto &vec = tempY[i];\n            sort(vec.begin(), vec.end());\n            vector<int> xsMerged; vector<int> wsMerged;\n            xsMerged.reserve(vec.size()); wsMerged.reserve(vec.size());\n            for (size_t k = 0; k < vec.size();) {\n                int x = vec[k].first; int s = 0; size_t k2 = k;\n                while (k2 < vec.size() && vec[k2].first == x) { s += vec[k2].second; ++k2; }\n                xsMerged.push_back(x); wsMerged.push_back(s); k = k2;\n            }\n            row.xs[i] = move(xsMerged);\n            row.pref[i].assign(wsMerged.size()+1, 0);\n            for (size_t t = 0; t < wsMerged.size(); ++t) row.pref[i][t+1] = row.pref[i][t] + wsMerged[t];\n        }\n    }\n    Refiner ref(col, row);\n\n    // Rectangle seeds from coarse grids with refinement\n    vector<int> Gs_rect = {64, 96, 128};\n    for (int G : Gs_rect) {\n        if (tim.elapsed() > TL * 0.55) break;\n        auto Wg = build_grid_W(G, pts);\n        auto rr = coarse_best_rect_from_W(Wg);\n        vector<int> xs, ys; build_grid_lines(G, xs, ys);\n        vector<pair<int,int>> poly = rect_to_polygon(rr, xs, ys);\n        Rect r{poly[0].first, poly[1].first, poly[0].second, poly[2].second};\n        r.ensure_min_size();\n        Rect refined = ref.refine(r);\n        vector<pair<int,int>> poly2 = {\n            {refined.L, refined.B}, {refined.R, refined.B}, {refined.R, refined.T}, {refined.L, refined.T}\n        };\n        if (polygon_perimeter(poly2) <= PERIM_LIMIT) {\n            Candidate cand; cand.poly = move(poly2);\n            cand.exactScore = exact_score_polygon(cand.poly, pts);\n            candidates.push_back(move(cand));\n        }\n    }\n\n    // Full area rectangle as always-valid fallback\n    {\n        vector<pair<int,int>> poly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n        Candidate cand; cand.poly = move(poly);\n        cand.exactScore = exact_score_polygon(cand.poly, pts);\n        candidates.push_back(move(cand));\n    }\n\n    // Multi-scale region growth with component seeds and pruning\n    struct GridCfg { int G; int maxSeeds; int minSep; vector<double> lambdas; };\n    vector<GridCfg> grids = {\n        {96, 6, 4, {0.0025, 0.005, 0.01}},\n        {128, 5, 4, {0.0025, 0.005}},\n        {160, 3, 4, {0.003, 0.006}},\n        {72, 4, 3, {0.005, 0.01}}\n    };\n\n    double growth_end_time = min(1.65, TL - 0.25); // leave time for polygon scoring and safety\n\n    for (auto cfg : grids) {\n        if (tim.elapsed() > growth_end_time) break;\n        int G = cfg.G;\n        auto Wg = build_grid_W(G, pts);\n        vector<int> xs, ys; build_grid_lines(G, xs, ys);\n        RegionGrower grower(G, Wg, xs, ys);\n\n        // seeds from top positive cells\n        struct Cell { int w, i, j; };\n        vector<Cell> cells;\n        cells.reserve(G*G);\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (Wg[j][i] > 0) cells.push_back({Wg[j][i], i, j});\n        sort(cells.begin(), cells.end(), [](const Cell& a, const Cell& b){\n            if (a.w != b.w) return a.w > b.w;\n            if (a.j != b.j) return a.j < b.j;\n            return a.i < b.i;\n        });\n        vector<pair<int,int>> seeds;\n\n        // seeds from positive components (max weight cell in component)\n        vector<vector<char>> vis(G, vector<char>(G, 0));\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) {\n            if (vis[j][i] || Wg[j][i] <= 0) continue;\n            int bestI = i, bestJ = j, bestW = Wg[j][i];\n            deque<pair<int,int>> dq; dq.emplace_back(i,j); vis[j][i] = 1;\n            while (!dq.empty()) {\n                auto [ci, cj] = dq.front(); dq.pop_front();\n                int cw = Wg[cj][ci];\n                if (cw > bestW) { bestW = cw; bestI = ci; bestJ = cj; }\n                auto try_push = [&](int ni, int nj) {\n                    if (ni<0||ni>=G||nj<0||nj>=G) return;\n                    if (vis[nj][ni]) return;\n                    if (Wg[nj][ni] <= 0) return;\n                    vis[nj][ni] = 1; dq.emplace_back(ni,nj);\n                };\n                try_push(ci-1,cj); try_push(ci+1,cj); try_push(ci,cj-1); try_push(ci,cj+1);\n            }\n            seeds.emplace_back(bestI, bestJ);\n        }\n\n        // merge with best cells, enforcing min separation and cap maxSeeds\n        for (const auto& c : cells) {\n            bool ok = true;\n            for (auto [si, sj] : seeds) if (abs(si - c.i) + abs(sj - c.j) < cfg.minSep) { ok = false; break; }\n            if (!ok) continue;\n            seeds.emplace_back(c.i, c.j);\n            if ((int)seeds.size() >= cfg.maxSeeds) break;\n        }\n        if (seeds.empty()) {\n            int bi=0,bj=0,bw=INT_MIN;\n            for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (Wg[j][i] > bw) { bw = Wg[j][i]; bi=i; bj=j; }\n            seeds.emplace_back(bi,bj);\n        }\n\n        // grow per seed/mode\n        vector<pair<long long, vector<pair<int,int>>>> local_polys; // for keeping best within this grid\n        long long bestLocalScore = LLONG_MIN;\n        vector<vector<char>> bestInside; bool haveBestInside = false;\n\n        double time_limit_sec = TL - 0.15;\n        for (auto [si, sj] : seeds) {\n            if (tim.elapsed() > growth_end_time) break;\n            // ratio-like\n            {\n                auto gr = grower.grow_from_seed(si, sj, 0, 0.0, time_limit_sec, tim);\n                if (gr.valid) {\n                    auto poly = grower.inside_to_polygon(gr.inside);\n                    if (!poly.empty()) {\n                        long long peri = polygon_perimeter(poly);\n                        if (peri <= PERIM_LIMIT && (int)poly.size() <= 1000) {\n                            long long sc = exact_score_polygon(poly, pts);\n                            candidates.push_back({poly, sc});\n                            local_polys.emplace_back(sc, poly);\n                            if (sc > bestLocalScore) { bestLocalScore = sc; bestInside = gr.inside; haveBestInside = true; }\n                        }\n                    }\n                }\n            }\n            for (double lam : cfg.lambdas) {\n                if (tim.elapsed() > growth_end_time) break;\n                auto gr = grower.grow_from_seed(si, sj, 1, lam, time_limit_sec, tim);\n                if (gr.valid) {\n                    auto poly = grower.inside_to_polygon(gr.inside);\n                    if (!poly.empty()) {\n                        long long peri = polygon_perimeter(poly);\n                        if (peri <= PERIM_LIMIT && (int)poly.size() <= 1000) {\n                            long long sc = exact_score_polygon(poly, pts);\n                            candidates.push_back({poly, sc});\n                            local_polys.emplace_back(sc, poly);\n                            if (sc > bestLocalScore) { bestLocalScore = sc; bestInside = gr.inside; haveBestInside = true; }\n                        }\n                    }\n                }\n            }\n        }\n\n        // Second stage: continue growing from the best inside of this grid (if time remains)\n        if (haveBestInside && tim.elapsed() < growth_end_time) {\n            // Try a couple of lambdas\n            vector<double> lam2 = {0.004, 0.007};\n            for (double lam : lam2) {\n                if (tim.elapsed() > growth_end_time) break;\n                auto gr2 = grower.grow_from_mask(bestInside, 1, lam, time_limit_sec, tim);\n                if (gr2.valid) {\n                    auto poly = grower.inside_to_polygon(gr2.inside);\n                    if (!poly.empty()) {\n                        long long peri = polygon_perimeter(poly);\n                        if (peri <= PERIM_LIMIT && (int)poly.size() <= 1000) {\n                            long long sc = exact_score_polygon(poly, pts);\n                            candidates.push_back({poly, sc});\n                            if (sc > bestLocalScore) {\n                                bestLocalScore = sc;\n                                bestInside = gr2.inside;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Select best candidate\n    long long bestScore = LLONG_MIN;\n    int bestIdx = -1;\n    for (int i = 0; i < (int)candidates.size(); ++i) {\n        long long sc = candidates[i].exactScore;\n        if (sc > bestScore) { bestScore = sc; bestIdx = i; }\n    }\n\n    vector<pair<int,int>> bestPoly;\n    if (bestIdx >= 0) bestPoly = candidates[bestIdx].poly;\n    else bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n\n    // Sanity: ensure constraints\n    if ((int)bestPoly.size() < 4) bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n    long long peri = polygon_perimeter(bestPoly);\n    if (peri > PERIM_LIMIT) {\n        for (int iter = 0; iter < 1000 && peri > PERIM_LIMIT; ++iter) {\n            int maxx = 0, maxy = 0;\n            for (auto &p : bestPoly) { maxx = max(maxx, p.first); maxy = max(maxy, p.second); }\n            for (auto &p : bestPoly) {\n                if (p.first == maxx && maxx > 0) --p.first;\n                if (p.second == maxy && maxy > 0) --p.second;\n            }\n            peri = polygon_perimeter(bestPoly);\n        }\n    }\n    if ((int)bestPoly.size() > 1000) {\n        // downsample conservatively (should be rare with our G)\n        vector<pair<int,int>> simp;\n        int step = (int)bestPoly.size() / 900 + 1;\n        for (int i = 0; i < (int)bestPoly.size(); i += step) simp.push_back(bestPoly[i]);\n        if (simp.front() != bestPoly.front()) simp.insert(simp.begin(), bestPoly.front());\n        bestPoly.swap(simp);\n        if (bestPoly.size() < 4) bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n    }\n\n    cout << bestPoly.size() << \"\\n\";\n    for (auto &p : bestPoly) cout << p.first << \" \" << p.second << \"\\n\";\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\n// 64-bit splitmix RNG\nstatic uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct Op {\n    int p;   // rectangle index\n    int r;   // rotation 0/1\n    char d;  // 'U' or 'L'\n    int b;   // base index or -1\n};\n\nstruct Column {\n    long long cw;   // column width (top width)\n    long long ch;   // accumulated height\n    int top_id;     // top rectangle id of this column\n    int last_id;    // last placed rectangle in this column\n};\n\nstruct Param {\n    double lamW;              // base weight for W increase\n    double lamH;              // base weight for H overflow\n    long long fudge;          // base stacking margin (>=0)\n    double fudgeFrac;         // additional margin as fraction of column width\n    double newColBias;        // base bias for opening new column (scaled by avgMin)\n    int lookK;                // lookahead count\n    double fitCountWeight;    // reward per future fit (scaled by avgMin)\n    double fitHeightWeight;   // reward per sum of future fitted heights (multiplied with lamH)\n    double dynAlpha;          // exponent for dynamic lam adjustment by W/H\n    double progBiasC;         // progress-dependent bias coefficient (scaled by avgMin)\n    double widthCapMul;       // soft width cap multiplier * avgMin\n    double widthCapPenalty;   // penalty coefficient for width exceeding soft cap\n    double minOpenFactor;     // factor for suffix quantile threshold for opening\n    double minOpenPenalty;    // penalty scale if cw below threshold (multiplied with lamW)\n    unsigned tieRand;         // seed for tie-breaking\n    string tag;               // label\n};\n\nstruct PlanResult {\n    vector<Op> ops;\n    long long W_est;\n    long long H_est;\n};\n\nstruct BuildCtx {\n    const vector<long long>& w;\n    const vector<long long>& h;\n    double avgMin;                  // typical instance scale\n    const vector<long long>& q70;   // suffix 70th percentile of min(w,h), length N+1 (q70[N]=0)\n};\n\n// Core builder (column-based) on given sizes\nstatic PlanResult build_columns_core(const BuildCtx& ctx, const Param& P) {\n    const auto& wp = ctx.w;\n    const auto& hp = ctx.h;\n    int N = (int)wp.size();\n\n    vector<Op> ops; ops.reserve(N);\n    vector<Column> cols; cols.reserve(N);\n\n    long long W = 0, H = 0;\n    int lastTopId = -1;\n    uint64_t rng = splitmix64((uint64_t)P.tieRand + 0x123456789abcdefULL);\n\n    auto future_fit_stats = [&](int iStart, long long capWidth, long long fudgeBase, double fudgeFrac)->pair<int, long long> {\n        long long cap = capWidth - (long long)llround(fudgeBase + fudgeFrac * (double)capWidth);\n        if (cap < 0) cap = 0;\n        int K = max(0, P.lookK);\n        if (K == 0) return {0, 0};\n        int end = min(N, iStart + K);\n        int cnt = 0;\n        long long sumH = 0;\n        for (int j = iStart; j < end; ++j) {\n            bool o0 = (wp[j] <= cap);\n            bool o1 = (hp[j] <= cap);\n            if (!o0 && !o1) continue;\n            ++cnt;\n            long long hmin = (o0 ? hp[j] : (long long)4e18);\n            if (o1) hmin = min(hmin, wp[j]);\n            if (hmin < (long long)4e18) sumH += hmin;\n        }\n        return {cnt, sumH};\n    };\n\n    for (int i = 0; i < N; ++i) {\n        long long w0 = wp[i], h0 = hp[i];\n        long long w1 = hp[i], h1 = wp[i];\n\n        // Dynamic weights by current aspect ratio\n        double Wr = max(1LL, W), Hr = max(1LL, H);\n        double ratio = Wr / Hr;\n        double wfac = (P.dynAlpha != 0.0 ? pow(ratio, P.dynAlpha) : 1.0);\n        double hfac = (P.dynAlpha != 0.0 ? pow(1.0 / ratio, P.dynAlpha) : 1.0);\n        double lamW_eff = max(0.0, P.lamW * wfac);\n        double lamH_eff = max(0.0, P.lamH * hfac);\n\n        // Progress-dependent bias\n        double prog = (N > 1 ? (double)i / (double)(N - 1) : 1.0);\n        double biasEff = P.newColBias + (prog - 0.5) * ctx.avgMin * P.progBiasC;\n\n        // Best stacking candidate\n        bool hasStack = false;\n        int bestCol = -1;\n        int bestRot = 0;\n        double bestCostStack = 1e300;\n        long long bestSlack = LLONG_MAX;   // prioritize minimal slack first\n        long long bestNewColH = LLONG_MAX; // then smaller resulting height\n\n        for (int j = 0; j < (int)cols.size(); ++j) {\n            long long effFudge = P.fudge + (long long)llround(P.fudgeFrac * (double)cols[j].cw);\n            long long cap = cols[j].cw - effFudge;\n            if (cap < 0) cap = 0;\n            bool fit0 = (w0 <= cap);\n            bool fit1 = (w1 <= cap);\n            if (!fit0 && !fit1) continue;\n\n            int rotSel; long long useW, useH;\n            if (fit0 && fit1) {\n                long long newH0 = cols[j].ch + h0;\n                long long newH1 = cols[j].ch + h1;\n                if (newH0 < newH1) { rotSel = 0; useW = w0; useH = h0; }\n                else if (newH1 < newH0) { rotSel = 1; useW = w1; useH = h1; }\n                else {\n                    if (w0 <= w1) { rotSel = 0; useW = w0; useH = h0; }\n                    else { rotSel = 1; useW = w1; useH = h1; }\n                }\n            } else if (fit0) { rotSel = 0; useW = w0; useH = h0; }\n            else { rotSel = 1; useW = w1; useH = h1; }\n\n            long long newColH = cols[j].ch + useH;\n            long long dH = (newColH > H ? (newColH - H) : 0LL);\n            double cost = lamH_eff * (double)dH;\n\n            long long slack = cols[j].cw - useW;\n            bool better = false;\n            if (!hasStack || cost < bestCostStack) better = true;\n            else if (fabs(cost - bestCostStack) < 1e-12) {\n                if (slack < bestSlack) better = true;\n                else if (slack == bestSlack) {\n                    if (newColH < bestNewColH) better = true;\n                    else if (newColH == bestNewColH) {\n                        rng = splitmix64(rng);\n                        if ((rng & 1ULL) == 0ULL) better = true;\n                    }\n                }\n            }\n\n            if (better) {\n                hasStack = true;\n                bestCol = j;\n                bestRot = rotSel;\n                bestCostStack = cost;\n                bestSlack = slack;\n                bestNewColH = newColH;\n            }\n        }\n\n        // Evaluate opening a new column (both rotations) with lookahead rewards and width soft cap\n        auto eval_newcol = [&](int rot)->tuple<double,long long,long long> {\n            long long cw = (rot==0? w0 : w1);\n            long long ch = (rot==0? h0 : h1);\n            long long dH = max(0LL, ch - H);\n            double cost = lamW_eff * (double)cw + lamH_eff * (double)dH + biasEff;\n\n            // Lookahead rewards: count and sum of fitted heights\n            auto st = future_fit_stats(i + 1, cw, P.fudge, P.fudgeFrac);\n            int cntFit = st.first;\n            long long sumHFit = st.second;\n            cost -= P.fitCountWeight * (double)cntFit;\n            cost -= lamH_eff * P.fitHeightWeight * (double)sumHFit;\n\n            // Suffix-quantile based penalty for too-narrow columns\n            long long thrQ = (i + 1 <= N ? ctx.q70[i + 1] : 0LL);\n            double thr = P.minOpenFactor * (double)thrQ;\n            if ((double)cw < thr) {\n                cost += lamW_eff * P.minOpenPenalty * (thr - (double)cw);\n            }\n\n            // Soft width cap penalty\n            double capW = P.widthCapMul * ctx.avgMin;\n            if ((double)cw > capW) {\n                cost += lamW_eff * P.widthCapPenalty * ((double)cw - capW);\n            }\n            return {cost, cw, ch};\n        };\n\n        auto [costNew0, cw0, ch0] = eval_newcol(0);\n        auto [costNew1, cw1, ch1] = eval_newcol(1);\n\n        double newColCost; long long newCW, newCH; int newRot;\n        if (costNew1 < costNew0 - 1e-12 || (fabs(costNew1 - costNew0) < 1e-12 && (cw1 < cw0 || (cw1 == cw0 && ch1 < ch0)))) {\n            newColCost = costNew1; newCW = cw1; newCH = ch1; newRot = 1;\n        } else {\n            newColCost = costNew0; newCW = cw0; newCH = ch0; newRot = 0;\n        }\n\n        if (hasStack && bestCostStack <= newColCost) {\n            // Stack into existing column\n            Op op;\n            op.p = i;\n            op.r = bestRot;\n            op.d = 'L';\n            op.b = cols[bestCol].last_id;\n            ops.push_back(op);\n\n            long long hAdd = (bestRot == 0 ? h0 : h1);\n            cols[bestCol].ch += hAdd;\n            cols[bestCol].last_id = i;\n            H = max(H, cols[bestCol].ch);\n        } else {\n            // Open a new column appended to the right\n            Op op;\n            op.p = i;\n            op.r = newRot;\n            op.d = 'U';\n            op.b = (lastTopId == -1 ? -1 : lastTopId);\n            ops.push_back(op);\n\n            Column c;\n            c.cw = newCW;\n            c.ch = newCH;\n            c.top_id = i;\n            c.last_id = i;\n            cols.push_back(c);\n\n            lastTopId = i;\n            W += newCW;\n            H = max(H, newCH);\n        }\n    }\n\n    return {ops, W, H};\n}\n\n// Wrapper to build either column-mode (normal) or row-mode (transposed)\nenum Mode { COLMODE = 0, ROWMODE = 1 };\n\nstatic PlanResult build_plan(const vector<long long>& w, const vector<long long>& h, double avgMin, const vector<long long>& q70, const Param& P, Mode mode) {\n    if (mode == COLMODE) {\n        BuildCtx ctx{w, h, avgMin, q70};\n        return build_columns_core(ctx, P);\n    } else {\n        // Transpose sizes\n        vector<long long> wt = h, ht = w;\n        BuildCtx ctxT{wt, ht, avgMin, q70}; // avgMin and q70 are computed from original; acceptable as scale signals\n        PlanResult rt = build_columns_core(ctxT, P);\n        // Map operations back: swap U<->L, r -> 1 - r\n        for (auto &op : rt.ops) {\n            op.r = 1 - op.r;\n            op.d = (op.d == 'U' ? 'L' : 'U');\n        }\n        swap(rt.W_est, rt.H_est);\n        return rt;\n    }\n}\n\n// Compute suffix quantile array Q[i] = quantile of ms[i..N-1], Q[N] = 0\nstatic vector<long long> compute_suffix_quantile(const vector<long long>& ms, double quant) {\n    int N = (int)ms.size();\n    vector<long long> Q(N + 1, 0);\n    for (int i = 0; i < N; ++i) {\n        vector<long long> v;\n        v.reserve(N - i);\n        for (int j = i; j < N; ++j) v.push_back(ms[j]);\n        sort(v.begin(), v.end());\n        int m = (int)v.size();\n        if (m > 0) {\n            int idx = (int)floor((m - 1) * quant + 1e-9);\n            if (idx < 0) idx = 0;\n            if (idx >= m) idx = m - 1;\n            Q[i] = v[idx];\n        } else Q[i] = 0;\n    }\n    Q[N] = 0;\n    return Q;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    long long sigma;\n    if (!(cin >> N >> T >> sigma)) return 0;\n    vector<long long> w(N), h(N);\n    for (int i = 0; i < N; ++i) cin >> w[i] >> h[i];\n\n    // Typical scale = average min side\n    double avgMin = 0.0;\n    vector<long long> ms(N);\n    for (int i = 0; i < N; ++i) {\n        ms[i] = min(w[i], h[i]);\n        avgMin += (double)ms[i];\n    }\n    avgMin /= max(1, N);\n\n    // Suffix quantile (70th percentile) for min side\n    vector<long long> q70 = compute_suffix_quantile(ms, 0.70);\n\n    // Parameter portfolio (safe, diverse; fudge >= 0)\n    struct Task { Param P; Mode mode; };\n    vector<Task> tasks;\n\n    auto clamp_fudge = [&](long long f)->long long {\n        if (f < 0) f = 0;\n        long long maxF = max(1LL, sigma);\n        if (f > maxF) f = maxF;\n        return f;\n    };\n\n    auto add_combo = [&](double lW, double lH, long long f, double fudgeFrac,\n                         double biasMul, int lookK,\n                         double fitCntMul, double fitHMul, double dynA, double progC,\n                         double widthCapMul, double widthCapPenalty,\n                         double minOpenFactor, double minOpenPenalty,\n                         const string& tag, Mode mode) {\n        Param P;\n        P.lamW = lW;\n        P.lamH = lH;\n        P.fudge = clamp_fudge(f);\n        P.fudgeFrac = max(0.0, fudgeFrac);\n        P.newColBias = biasMul * avgMin;        // scaled by avgMin\n        P.lookK = lookK;\n        P.fitCountWeight = max(0.0, fitCntMul) * avgMin;  // scaled by avgMin\n        P.fitHeightWeight = max(0.0, fitHMul);            // dimensionless, multiplied with lamH\n        P.dynAlpha = max(0.0, dynA);\n        P.progBiasC = max(0.0, progC);                    // multiplied by avgMin inside\n        P.widthCapMul = max(1.0, widthCapMul);            // soft cap multiplier on avgMin\n        P.widthCapPenalty = max(0.0, widthCapPenalty);    // penalty factor for over-cap width\n        P.minOpenFactor = min(max(0.5, minOpenFactor), 1.2);\n        P.minOpenPenalty = max(0.0, minOpenPenalty);\n        uint64_t seed = 0;\n        seed ^= (uint64_t)(lW * 1000 + 7) + ((uint64_t)(lH * 1000 + 13) << 1);\n        seed ^= (uint64_t)(P.fudge + 101) + ((uint64_t)(biasMul * 1000 + 17) << 2);\n        seed ^= ((uint64_t)lookK << 3) + ((uint64_t)(fitCntMul * 100 + 19) << 5);\n        seed ^= ((uint64_t)(fitHMul * 100 + 23) << 7);\n        seed ^= ((uint64_t)(dynA * 1000 + 29) << 9) ^ ((uint64_t)(progC * 1000 + 31) << 11);\n        seed ^= ((uint64_t)(widthCapMul * 1000 + 37) << 13) ^ ((uint64_t)(widthCapPenalty * 1000 + 41) << 15);\n        seed ^= ((uint64_t)(minOpenFactor * 1000 + 43) << 17) ^ ((uint64_t)(minOpenPenalty * 1000 + 47) << 19);\n        P.tieRand = (unsigned)splitmix64(seed);\n        P.tag = tag + (mode==COLMODE ? \"_col\" : \"_row\");\n        tasks.push_back({P, mode});\n    };\n\n    // Fudge levels\n    long long F0 = 0;\n    long long F1 = max(0LL, sigma / 8);\n    long long F2 = max(0LL, sigma / 4);\n    long long F3 = max(0LL, sigma / 2);\n\n    // Build tasks: both modes for each preset (prioritize safer first)\n    vector<long long> fudges = {F1, F0, F2};\n    for (auto f : fudges) {\n        // Balanced with adaptive margin and lookahead\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.0, 1.0, f, 0.02,  0.00, 8, 0.12, 0.05, 0.20, 0.40, 1.8, 0.15, 0.80, 0.20, \"bal_f\"+to_string(f), (Mode)m);\n        // Encourage stacking (narrow W)\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.5, 1.0, f, 0.02, +0.06, 6, 0.00, 0.00, 0.20, 0.40, 1.6, 0.20, 0.75, 0.15, \"W+_f\"+to_string(f), (Mode)m);\n        // Stronger W\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.8, 1.0, f, 0.02, +0.10, 6, 0.00, 0.00, 0.15, 0.40, 1.5, 0.25, 0.70, 0.15, \"W++_f\"+to_string(f), (Mode)m);\n        // Encourage new columns to control height\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.0, 1.4, f, 0.02, -0.05, 8, 0.14, 0.06, 0.25, 0.50, 2.0, 0.10, 0.85, 0.10, \"H+_f\"+to_string(f), (Mode)m);\n        // Stronger height-friendly\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.0, 1.8, f, 0.02, -0.10,10, 0.16, 0.07, 0.30, 0.60, 2.2, 0.08, 0.90, 0.10, \"H++_f\"+to_string(f), (Mode)m);\n        // Balanced with stronger lookahead\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.0, 1.0, f, 0.02, -0.03, 9, 0.15, 0.06, 0.25, 0.50, 1.9, 0.12, 0.80, 0.20, \"balFit_f\"+to_string(f), (Mode)m);\n    }\n    // Extra-safe with larger fudge\n    for (int m = 0; m < 2; ++m)\n        add_combo(1.2, 1.0, F3, 0.02, +0.06, 6, 0.00, 0.00, 0.20, 0.40, 1.6, 0.20, 0.75, 0.15, \"W+_f\"+to_string(F3), (Mode)m);\n    for (int m = 0; m < 2; ++m)\n        add_combo(1.0, 1.2, F3, 0.02, -0.04, 8, 0.10, 0.04, 0.25, 0.50, 2.0, 0.10, 0.85, 0.12, \"H+_f\"+to_string(F3), (Mode)m);\n\n    // Ensure first few tasks are diverse\n    int E = min((int)tasks.size(), T);\n\n    long long bestApproxScore = (1LL<<62);\n    Param bestParam{};\n    Mode bestMode = COLMODE;\n    bool bestSet = false;\n    long long lastWm = -1, lastHm = -1;\n\n    std::mt19937_64 rng(20250914);\n    std::uniform_real_distribution<double> ur(0.0, 1.0);\n\n    for (int t = 0; t < T; ++t) {\n        Param P;\n        Mode mode;\n        string tag;\n        if (t < E) {\n            P = tasks[t].P;\n            mode = tasks[t].mode;\n            tag = P.tag;\n        } else {\n            if (!bestSet) {\n                auto &task = tasks[t % E];\n                P = task.P;\n                mode = task.mode;\n                tag = \"fallback_\" + P.tag;\n            } else {\n                P = bestParam;\n                mode = bestMode;\n                // Rebalance using last W'/H'\n                if (lastWm > 0 && lastHm > 0) {\n                    double r = (double)lastWm / (double)lastHm;\n                    if (r > 1.2) {\n                        P.lamW *= 1.12; P.lamH *= 0.96;\n                        P.newColBias += 0.02 * avgMin;\n                        P.widthCapPenalty *= 1.10;\n                        P.minOpenPenalty *= 1.05;\n                    } else if (r < 1.0/1.2) {\n                        P.lamH *= 1.12; P.lamW *= 0.96;\n                        P.newColBias -= 0.02 * avgMin;\n                    }\n                }\n                // Jitter\n                double j1 = (ur(rng) - 0.5) * 0.25; // +-12.5%\n                double j2 = (ur(rng) - 0.5) * 0.25;\n                P.lamW = max(0.2, P.lamW * (1.0 + j1));\n                P.lamH = max(0.2, P.lamH * (1.0 + j2));\n                P.newColBias += (ur(rng) - 0.5) * (0.06 * avgMin);\n                P.fitCountWeight = max(0.0, P.fitCountWeight * (1.0 + (ur(rng) - 0.5) * 0.3));\n                P.fitHeightWeight = max(0.0, P.fitHeightWeight * (1.0 + (ur(rng) - 0.5) * 0.3));\n                P.dynAlpha = max(0.0, P.dynAlpha * (1.0 + (ur(rng) - 0.5) * 0.2));\n                P.progBiasC = max(0.0, P.progBiasC * (1.0 + (ur(rng) - 0.5) * 0.3));\n                P.widthCapMul = max(1.2, P.widthCapMul * (1.0 + (ur(rng) - 0.5) * 0.15));\n                P.widthCapPenalty = max(0.02, P.widthCapPenalty * (1.0 + (ur(rng) - 0.5) * 0.25));\n                P.minOpenFactor = min(1.1, max(0.6, P.minOpenFactor * (1.0 + (ur(rng) - 0.5) * 0.2)));\n                P.minOpenPenalty = max(0.0, P.minOpenPenalty * (1.0 + (ur(rng) - 0.5) * 0.25));\n                // Jitter fudge within [0, sigma] and fudgeFrac slightly\n                long long jfudge = (long long)((ur(rng) - 0.5) * (double)max(1LL, sigma/4)); // +-sigma/8\n                long long nf = P.fudge + jfudge;\n                if (nf < 0) nf = 0;\n                if (nf > max(1LL, sigma)) nf = max(1LL, sigma);\n                P.fudge = nf;\n                P.fudgeFrac = max(0.0, P.fudgeFrac * (1.0 + (ur(rng) - 0.5) * 0.3));\n\n                // Occasionally re-explore a baseline task and possibly flip mode\n                if (ur(rng) < 0.10) {\n                    int id = (int)(rng() % E);\n                    P = tasks[id].P;\n                    mode = tasks[id].mode;\n                    tag = \"reexplore_\" + P.tag;\n                } else {\n                    tag = string(\"exploit_\") + (mode==COLMODE ? \"col\" : \"row\");\n                }\n            }\n            uint64_t seed = splitmix64((uint64_t)rng());\n            P.tieRand = (unsigned)seed;\n        }\n\n        PlanResult res = build_plan(w, h, avgMin, q70, P, mode);\n\n        // Debug comment (optional)\n        cout << \"# t=\" << t\n             << \" mode=\" << (mode==COLMODE ? \"col\" : \"row\")\n             << \" W_est=\" << res.W_est << \" H_est=\" << res.H_est\n             << \" lamW=\" << fixed << setprecision(2) << P.lamW\n             << \" lamH=\" << P.lamH\n             << \" fudge=\" << P.fudge\n             << \" fFrac=\" << P.fudgeFrac\n             << \" bias=\" << P.newColBias\n             << \" lookK=\" << P.lookK\n             << \" fitCntW=\" << P.fitCountWeight\n             << \" fitHtW=\" << P.fitHeightWeight\n             << \" dynA=\" << P.dynAlpha\n             << \" progC=\" << P.progBiasC\n             << \" capMul=\" << P.widthCapMul\n             << \" capPen=\" << P.widthCapPenalty\n             << \" minOpenF=\" << P.minOpenFactor\n             << \" minOpenP=\" << P.minOpenPenalty\n             << \" tag=\" << tag << \"\\n\";\n\n        // Output operations\n        cout << res.ops.size() << \"\\n\";\n        for (auto &op : res.ops) {\n            cout << op.p << \" \" << op.r << \" \" << op.d << \" \" << op.b << \"\\n\";\n        }\n        cout.flush();\n\n        long long Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n        lastWm = Wm; lastHm = Hm;\n\n        long long approxScore = Wm + Hm; // all rectangles placed\n        if (approxScore < bestApproxScore) {\n            bestApproxScore = approxScore;\n            bestParam = P;\n            bestMode = mode;\n            bestSet = true;\n        }\n    }\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double ms() const {\n        return chrono::duration<double, milli>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nstatic const uint16_t INF16 = (uint16_t)30000;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    if (!(cin >> N >> M >> H)) return 0;\n    vector<int> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n    vector<vector<int>> g(N);\n    for (int i = 0; i < M; i++) {\n        int u, v; cin >> u >> v;\n        g[u].push_back(v);\n        g[v].push_back(u);\n    }\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n    Timer timer;\n\n    // 1) All-pairs shortest distances via BFS from each node (N=1000, M<=3000 -> OK)\n    vector<uint16_t> Dist((size_t)N * (size_t)N, INF16);\n    {\n        vector<int> q; q.reserve(N);\n        vector<int> dist(N);\n        for (int s = 0; s < N; s++) {\n            fill(dist.begin(), dist.end(), -1);\n            dist[s] = 0;\n            q.clear();\n            q.push_back(s);\n            for (size_t qi = 0; qi < q.size(); qi++) {\n                int u = q[qi];\n                for (int v : g[u]) if (dist[v] == -1) {\n                    dist[v] = dist[u] + 1;\n                    q.push_back(v);\n                }\n            }\n            uint16_t *row = &Dist[(size_t)s * N];\n            for (int v = 0; v < N; v++) row[v] = dist[v] >= 0 ? (uint16_t)dist[v] : INF16;\n        }\n    }\n\n    // Precompute within-H sets (for root selection tie-break)\n    vector<vector<int>> withinH(N);\n    for (int u = 0; u < N; u++) {\n        const uint16_t* Du = &Dist[(size_t)u * N];\n        for (int v = 0; v < N; v++) if (Du[v] <= (uint16_t)H) withinH[u].push_back(v);\n    }\n\n    // 2) Build a root set to ensure coverage within H using farthest-first, then prune\n    vector<int> roots;\n    vector<char> isRoot(N, 0);\n    vector<uint16_t> dR(N, INF16);\n\n    int s0 = int(min_element(A.begin(), A.end()) - A.begin()); // start from low beauty\n    roots.push_back(s0);\n    isRoot[s0] = 1;\n    {\n        const uint16_t* D0 = &Dist[(size_t)s0 * N];\n        for (int v = 0; v < N; v++) dR[v] = D0[v];\n    }\n\n    auto recompute_dR = [&]() {\n        fill(dR.begin(), dR.end(), INF16);\n        for (int r : roots) {\n            const uint16_t* Dr = &Dist[(size_t)r * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dr[v]);\n        }\n    };\n\n    while (true) {\n        uint16_t dmax = 0;\n        for (int v = 0; v < N; v++) if (dR[v] > dmax) dmax = dR[v];\n        if (dmax <= (uint16_t)H) break;\n\n        vector<int> far;\n        for (int v = 0; v < N; v++) if (dR[v] == dmax) far.push_back(v);\n\n        int bestCand = -1, bestCover = -1, bestA = INT_MAX;\n        for (int cand : far) {\n            int cover = 0;\n            for (int u : withinH[cand]) if (dR[u] > (uint16_t)H) cover++;\n            if (cover > bestCover || (cover == bestCover && A[cand] < bestA)) {\n                bestCover = cover; bestA = A[cand]; bestCand = cand;\n            }\n        }\n        if (bestCand == -1) bestCand = far[0];\n\n        if (!isRoot[bestCand]) {\n            roots.push_back(bestCand);\n            isRoot[bestCand] = 1;\n            const uint16_t* Dn = &Dist[(size_t)bestCand * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dn[v]);\n        } else {\n            int cand2 = -1;\n            for (int v = 0; v < N; v++) if (dR[v] > (uint16_t)H) { cand2 = v; break; }\n            if (cand2 == -1) break;\n            roots.push_back(cand2);\n            isRoot[cand2] = 1;\n            const uint16_t* Dn = &Dist[(size_t)cand2 * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dn[v]);\n        }\n    }\n\n    auto compute_min12 = [&](vector<uint16_t>& m1, vector<uint16_t>& m2, vector<int>& arg) {\n        m1.assign(N, INF16); m2.assign(N, INF16); arg.assign(N, -1);\n        for (int r : roots) {\n            const uint16_t* Dr = &Dist[(size_t)r * N];\n            for (int v = 0; v < N; v++) {\n                uint16_t d = Dr[v];\n                if (d < m1[v]) { m2[v] = m1[v]; m1[v] = d; arg[v] = r; }\n                else if (d < m2[v]) m2[v] = d;\n            }\n        }\n    };\n\n    // Prune redundant roots\n    {\n        vector<uint16_t> m1, m2; vector<int> arg;\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            compute_min12(m1, m2, arg);\n            for (int i = 0; i < (int)roots.size(); i++) {\n                int r = roots[i];\n                bool safe = true;\n                for (int v = 0; v < N; v++) if (arg[v] == r && m2[v] > (uint16_t)H) { safe = false; break; }\n                if (safe) {\n                    isRoot[r] = 0;\n                    roots.erase(roots.begin() + i);\n                    changed = true;\n                    break;\n                }\n            }\n        }\n        recompute_dR();\n    }\n\n    // 3) Build initial forest via multi-source BFS (depth cap H)\n    vector<int> parent(N, -1);\n    vector<uint16_t> depth(N, INF16);\n    deque<int> dq;\n    for (int r : roots) {\n        depth[r] = 0; parent[r] = -1; dq.push_back(r);\n    }\n    while (!dq.empty()) {\n        int u = dq.front(); dq.pop_front();\n        if (depth[u] >= (uint16_t)H) continue;\n        uint16_t nd = depth[u] + 1;\n        for (int v : g[u]) if (depth[v] == INF16) {\n            depth[v] = nd; parent[v] = u; dq.push_back(v);\n        }\n    }\n    for (int v = 0; v < N; v++) if (depth[v] == INF16) { depth[v] = 0; parent[v] = -1; }\n\n    // 4) Prepare dynamic tree structures\n    vector<vector<int>> children(N);\n    vector<int> posInParent(N, -1);\n    for (int v = 0; v < N; v++) if (parent[v] != -1) {\n        int p = parent[v];\n        posInParent[v] = (int)children[p].size();\n        children[p].push_back(v);\n    }\n\n    vector<int> tin(N, 0), tout(N, 0), order(N, -1), rootsNow;\n    vector<long long> subSum(N, 0);\n    vector<uint16_t> subMax(N, 0);\n\n    function<void(int,int&)> dfs = [&](int u, int &timerDfs) {\n        tin[u] = timerDfs;\n        order[timerDfs] = u;\n        timerDfs++;\n        long long s = A[u];\n        uint16_t mx = depth[u];\n        for (int w : children[u]) {\n            dfs(w, timerDfs);\n            s += subSum[w];\n            mx = max<uint16_t>(mx, subMax[w]);\n        }\n        subSum[u] = s;\n        subMax[u] = mx;\n        tout[u] = timerDfs;\n    };\n    auto recompute_tree_info = [&]() {\n        rootsNow.clear();\n        for (int v = 0; v < N; v++) if (parent[v] == -1) rootsNow.push_back(v);\n        int tval = 0;\n        for (int r : rootsNow) dfs(r, tval);\n    };\n    recompute_tree_info();\n\n    auto is_ancestor = [&](int u, int v) -> bool {\n        return tin[u] <= tin[v] && tout[v] <= tout[u];\n    };\n    auto remove_from_parent = [&](int u) {\n        int p = parent[u];\n        if (p == -1) return;\n        int idx = posInParent[u];\n        int last = children[p].back();\n        swap(children[p][idx], children[p].back());\n        children[p].pop_back();\n        posInParent[last] = idx;\n        posInParent[u] = -1;\n        parent[u] = -1;\n    };\n    auto add_to_parent = [&](int u, int p) {\n        parent[u] = p;\n        posInParent[u] = (int)children[p].size();\n        children[p].push_back(u);\n    };\n\n    struct Move {\n        int u, x;\n        int L, R; // euler interval of u's subtree [L, R)\n        int delta;\n        long long gain;\n    };\n\n    // 5) Batch deepening rounds with multiple candidate parents per node\n    const int TOPK = 3;\n    while (timer.ms() < 1950.0) {\n        vector<Move> cand;\n        cand.reserve(N * 2);\n        for (int u = 0; u < N; u++) {\n            if (subMax[u] >= (uint16_t)H) continue; // subtree already at cap\n            int du = depth[u];\n            // collect top-K candidates among neighbors\n            struct C { long long gain; int delta; int x; };\n            array<C, TOPK> top;\n            for (int k = 0; k < TOPK; k++) top[k] = C{0, 0, -1};\n            for (int x : g[u]) {\n                if (x == parent[u]) continue;\n                if (is_ancestor(u, x)) continue; // avoid cycle\n                int dx = depth[x];\n                int delta = dx + 1 - du;\n                if (delta <= 0) continue;\n                if ((int)subMax[u] + delta > H) continue;\n                long long gain = 1LL * delta * subSum[u];\n                // insert into top-K if better\n                int pos = -1;\n                for (int k = 0; k < TOPK; k++) {\n                    if (gain > top[k].gain) { pos = k; break; }\n                }\n                if (pos != -1) {\n                    for (int k = TOPK - 1; k > pos; k--) top[k] = top[k - 1];\n                    top[pos] = C{gain, delta, x};\n                }\n            }\n            for (int k = 0; k < TOPK; k++) {\n                if (top[k].x != -1 && top[k].gain > 0) {\n                    Move m;\n                    m.u = u; m.x = top[k].x; m.delta = top[k].delta; m.gain = top[k].gain;\n                    m.L = tin[u]; m.R = tout[u];\n                    cand.push_back(m);\n                }\n            }\n        }\n        if (cand.empty()) break;\n\n        sort(cand.begin(), cand.end(), [](const Move& a, const Move& b){\n            if (a.gain != b.gain) return a.gain > b.gain;\n            if (a.delta != b.delta) return a.delta > b.delta;\n            return a.u < b.u;\n        });\n\n        vector<Move> selected;\n        selected.reserve(cand.size());\n        vector<pair<int,int>> usedIntervals; usedIntervals.reserve(cand.size());\n        vector<int> usedParentTin; usedParentTin.reserve(cand.size());\n\n        // To avoid selecting two moves for the same subtree, we'll also track selected subtree roots\n        vector<char> usedSubtree(N, 0);\n\n        for (const auto &m : cand) {\n            if (usedSubtree[m.u]) continue; // already scheduled a move for this subtree\n            bool conflict = false;\n            for (size_t i = 0; i < usedIntervals.size(); i++) {\n                int L = usedIntervals[i].first, R = usedIntervals[i].second;\n                // disjoint subtrees\n                if (!(m.R <= L || R <= m.L)) { conflict = true; break; }\n                // new parent x inside any selected subtree\n                if (L <= tin[m.x] && tin[m.x] < R) { conflict = true; break; }\n            }\n            if (conflict) continue;\n            // reverse check: any selected parent x_sel inside this candidate subtree?\n            for (int tpx : usedParentTin) {\n                if (m.L <= tpx && tpx < m.R) { conflict = true; break; }\n            }\n            if (conflict) continue;\n\n            selected.push_back(m);\n            usedIntervals.emplace_back(m.L, m.R);\n            usedParentTin.push_back(tin[m.x]);\n            usedSubtree[m.u] = 1;\n        }\n\n        if (selected.empty()) break;\n\n        // Apply all selected moves based on current Euler order\n        for (const auto &m : selected) {\n            for (int i = m.L; i < m.R; i++) {\n                int w = order[i];\n                depth[w] = (uint16_t)(depth[w] + m.delta);\n            }\n        }\n        for (const auto &m : selected) {\n            int u = m.u, x = m.x;\n            remove_from_parent(u);\n            add_to_parent(u, x);\n        }\n\n        recompute_tree_info();\n\n        if (timer.ms() > 1990.0) break;\n    }\n\n    // 6) Final safety pass: ensure actual heights <= H, with reattachment instead of blind cuts\n    // Rebuild children from current parent (for traversal enumeration)\n    for (int v = 0; v < N; v++) { children[v].clear(); posInParent[v] = -1; }\n    for (int v = 0; v < N; v++) if (parent[v] != -1) {\n        int p = parent[v];\n        posInParent[v] = (int)children[p].size();\n        children[p].push_back(v);\n    }\n    // Recompute tin/tout once more to use for \"not in original subtree\" checks during safety\n    recompute_tree_info();\n\n    // Collect roots\n    vector<int> rootsFinal;\n    for (int v = 0; v < N; v++) if (parent[v] == -1) rootsFinal.push_back(v);\n\n    // Iterative DFS stack: for each node, carry the computed current height h along the potentially modified parent chain\n    struct Frame { int u; int it; int h; };\n    vector<Frame> st;\n    st.reserve(N);\n\n    // assignedDepth indicates which nodes already have a decided height in this pass\n    vector<int> assignedDepth(N, -1);\n\n    auto push_root = [&](int r) {\n        st.push_back({r, 0, 0});\n    };\n    for (int r : rootsFinal) push_root(r);\n\n    while (!st.empty()) {\n        Frame &fr = st.back();\n        int u = fr.u;\n        if (fr.it == 0) {\n            // On entry: adjust if over H by reattaching to a deep, already processed neighbor\n            int h = fr.h;\n            if (h > H) {\n                int bestY = -1, bestHy = -1;\n                for (int y : g[u]) {\n                    if (assignedDepth[y] == -1) continue; // only already processed nodes\n                    if (assignedDepth[y] > H - 1) continue;\n                    // Avoid cycles: y must not be in original subtree of u\n                    if (tin[u] <= tin[y] && tin[y] < tout[u]) continue;\n                    if (assignedDepth[y] > bestHy) {\n                        bestHy = assignedDepth[y];\n                        bestY = y;\n                    }\n                }\n                if (bestY != -1) {\n                    parent[u] = bestY;\n                    h = bestHy + 1;\n                } else {\n                    parent[u] = -1;\n                    h = 0;\n                }\n                fr.h = h;\n            }\n            assignedDepth[u] = fr.h;\n        }\n        if (fr.it < (int)children[u].size()) {\n            int v = children[u][fr.it++];\n            st.push_back({v, 0, fr.h + 1});\n        } else {\n            st.pop_back();\n        }\n    }\n\n    // Output final parents\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << parent[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Action {\n    char d;      // 'L','R','U','D'\n    int p;       // row/column index\n    int k;       // length (number of shifts each way)\n    int cost;    // 2*k\n    uint64_t mask; // bitmask of covered Oni (M <= 64; here M=40)\n};\n\nstatic inline char opposite(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\nstatic inline int ctz64(uint64_t x) { return __builtin_ctzll(x); }\n\npair<int,int> simulate(const vector<string>& init, const vector<pair<char,int>>& ops) {\n    int N = init.size();\n    vector<string> g = init;\n    int rem_oni = 0;\n    for (auto &row : g) for (char ch : row) if (ch == 'x') rem_oni++;\n    int removed_oni = 0, removed_fuku = 0;\n    for (auto [d,p] : ops) {\n        if (d == 'L') {\n            char out = g[p][0];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int j = 0; j < N-1; ++j) g[p][j] = g[p][j+1];\n            g[p][N-1] = '.';\n        } else if (d == 'R') {\n            char out = g[p][N-1];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\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            char out = g[0][p];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int i = 0; i < N-1; ++i) g[i][p] = g[i+1][p];\n            g[N-1][p] = '.';\n        } else { // 'D'\n            char out = g[N-1][p];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int i = N-1; i >= 1; --i) g[i][p] = g[i-1][p];\n            g[0][p] = '.';\n        }\n    }\n    int X = rem_oni - removed_oni;\n    int Y = removed_fuku;\n    return {X, Y};\n}\n\n// Build reduced candidate actions: only k at points where we \"pass a new Oni\".\n// Deduplicate identical masks (keep cheapest) and prune dominated actions (subset with >= cost).\nvector<Action> build_candidates_tight(const vector<string>& grid, const vector<pair<int,int>>& oni_pos,\n                                      const vector<vector<int>>& oni_id) {\n    int N = grid.size();\n    vector<Action> acts;\n    acts.reserve(400);\n\n    // Precompute Lsafe/Rsafe/Usafe/Dsafe based on Fukunokami positions\n    vector<int> Lsafe(N), Rsafe(N);\n    for (int r = 0; r < N; ++r) {\n        int firstF = N, lastF = -1;\n        for (int j = 0; j < N; ++j) if (grid[r][j] == 'o') {\n            firstF = min(firstF, j);\n            lastF = max(lastF, j);\n        }\n        Lsafe[r] = (firstF == N ? N : firstF);\n        Rsafe[r] = (lastF == -1 ? N : (N - 1 - lastF));\n    }\n    vector<int> Usafe(N), Dsafe(N);\n    for (int c = 0; c < N; ++c) {\n        int firstF = N, lastF = -1;\n        for (int i = 0; i < N; ++i) if (grid[i][c] == 'o') {\n            firstF = min(firstF, i);\n            lastF = max(lastF, i);\n        }\n        Usafe[c] = (firstF == N ? N : firstF);\n        Dsafe[c] = (lastF == -1 ? N : (N - 1 - lastF));\n    }\n\n    // Row-left actions\n    for (int r = 0; r < N; ++r) {\n        uint64_t mask = 0;\n        for (int j = 0; j < Lsafe[r]; ++j) {\n            int id = oni_id[r][j];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = j + 1;\n                Action a; a.d = 'L'; a.p = r; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n    // Row-right actions\n    for (int r = 0; r < N; ++r) {\n        uint64_t mask = 0;\n        for (int j = N-1; j >= N - Rsafe[r]; --j) {\n            int id = oni_id[r][j];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = N - j;\n                Action a; a.d = 'R'; a.p = r; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n    // Col-up actions\n    for (int c = 0; c < N; ++c) {\n        uint64_t mask = 0;\n        for (int i = 0; i < Usafe[c]; ++i) {\n            int id = oni_id[i][c];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = i + 1;\n                Action a; a.d = 'U'; a.p = c; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n    // Col-down actions\n    for (int c = 0; c < N; ++c) {\n        uint64_t mask = 0;\n        for (int i = N-1; i >= N - Dsafe[c]; --i) {\n            int id = oni_id[i][c];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = N - i;\n                Action a; a.d = 'D'; a.p = c; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n\n    // Deduplicate identical masks keeping minimal cost\n    unordered_map<uint64_t, int> bestIdx;\n    bestIdx.reserve(acts.size()*2);\n    vector<Action> filtered;\n    filtered.reserve(acts.size());\n    for (int i = 0; i < (int)acts.size(); ++i) {\n        auto it = bestIdx.find(acts[i].mask);\n        if (it == bestIdx.end()) {\n            bestIdx[acts[i].mask] = (int)filtered.size();\n            filtered.push_back(acts[i]);\n        } else {\n            int idx = it->second;\n            if (acts[i].cost < filtered[idx].cost) filtered[idx] = acts[i];\n        }\n    }\n\n    // Dominated action removal: if mask_i subset of mask_j and cost_i >= cost_j, drop i\n    int A = filtered.size();\n    vector<char> dominated(A, 0);\n    for (int i = 0; i < A; ++i) if (!dominated[i]) {\n        for (int j = 0; j < A; ++j) if (i != j && !dominated[i]) {\n            if ((filtered[i].mask & ~filtered[j].mask) == 0ULL) { // i \u2286 j\n                if (filtered[i].cost >= filtered[j].cost) dominated[i] = 1;\n            }\n        }\n    }\n    vector<Action> filtered2;\n    filtered2.reserve(A);\n    for (int i = 0; i < A; ++i) if (!dominated[i]) filtered2.push_back(filtered[i]);\n    return filtered2;\n}\n\nint selection_cost(const vector<int>& sel, const vector<Action>& acts) {\n    long long s = 0;\n    for (int idx : sel) s += acts[idx].cost;\n    if (s > INT_MAX) return INT_MAX;\n    return (int)s;\n}\n\nvector<int> prune_selection(const vector<int>& sel, const vector<Action>& acts, int M) {\n    if (sel.empty()) return sel;\n    vector<int> cnt(M, 0);\n    for (int idx : sel) {\n        uint64_t m = acts[idx].mask;\n        while (m) { int b = ctz64(m); cnt[b]++; m &= m - 1; }\n    }\n    vector<int> order = sel;\n    sort(order.begin(), order.end(), [&](int a, int b){\n        if (acts[a].cost != acts[b].cost) return acts[a].cost > acts[b].cost;\n        return a < b;\n    });\n    vector<char> alive(acts.size(), 0);\n    for (int idx : sel) alive[idx] = 1;\n\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        for (int idx : order) {\n            if (!alive[idx]) continue;\n            uint64_t m = acts[idx].mask;\n            bool can = true;\n            while (m) {\n                int b = ctz64(m);\n                if (cnt[b] <= 1) { can = false; break; }\n                m &= m - 1;\n            }\n            if (can) {\n                uint64_t mm = acts[idx].mask;\n                while (mm) { int b = ctz64(mm); cnt[b]--; mm &= mm - 1; }\n                alive[idx] = 0;\n                changed = true;\n            }\n        }\n    }\n    vector<int> res;\n    res.reserve(sel.size());\n    for (int idx : sel) if (alive[idx]) res.push_back(idx);\n    return res;\n}\n\n// Greedy selection with weights, per-action cost noise, and stochastic pick among top-K\nvector<int> greedy_select_weighted_noisy(const vector<Action>& acts, int M, const vector<double>& w,\n                                         std::mt19937& rng, double noise_beta = 0.12, int pickK = 3, double pickP2 = 0.15, double pickP3 = 0.05) {\n    int A = (int)acts.size();\n    vector<double> costEff(A);\n    uniform_real_distribution<double> urand(0.0, 1.0);\n    for (int i = 0; i < A; ++i) {\n        double noise = 1.0 + noise_beta * (urand(rng) * 2.0 - 1.0); // [1-beta, 1+beta]\n        noise = max(0.5, min(2.0, noise));\n        costEff[i] = acts[i].cost * noise;\n    }\n\n    vector<int> order(A);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    vector<int> rank(A);\n    for (int i = 0; i < A; ++i) rank[order[i]] = i;\n\n    uint64_t covered = 0;\n    // Restrict to bits that appear in acts\n    uint64_t unionMask = 0;\n    for (auto &a : acts) unionMask |= a.mask;\n\n    vector<int> sel;\n    sel.reserve(M);\n\n    auto allCovered = [&](){ return (covered & unionMask) == unionMask; };\n\n    while (!allCovered()) {\n        array<int, 3> topIdx = {-1, -1, -1};\n        array<double, 3> topRatio = {1e100, 1e100, 1e100};\n        array<int, 3> topCost = {INT_MAX, INT_MAX, INT_MAX};\n        array<int, 3> topRank = {INT_MAX, INT_MAX, INT_MAX};\n\n        for (int a = 0; a < A; ++a) {\n            uint64_t gmask = acts[a].mask & ~covered;\n            if (!gmask) continue;\n            double gain = 0.0;\n            uint64_t mm = gmask;\n            while (mm) { int b = ctz64(mm); gain += w[b]; mm &= mm - 1; }\n            if (gain <= 0.0) continue;\n            double ratio = costEff[a] / gain;\n            for (int k = 0; k < min(pickK, 3); ++k) {\n                if (ratio < topRatio[k] ||\n                    (ratio == topRatio[k] && (acts[a].cost < topCost[k] ||\n                                              (acts[a].cost == topCost[k] && rank[a] < topRank[k])))) {\n                    for (int t = min(pickK, 3)-1; t > k; --t) { topIdx[t] = topIdx[t-1]; topRatio[t] = topRatio[t-1]; topCost[t] = topCost[t-1]; topRank[t] = topRank[t-1]; }\n                    topIdx[k] = a; topRatio[k] = ratio; topCost[k] = acts[a].cost; topRank[k] = rank[a];\n                    break;\n                }\n            }\n        }\n        int chosen = -1;\n        if (topIdx[0] == -1) break;\n        double r = urand(rng);\n        if (pickK >= 3 && r < pickP3 && topIdx[2] != -1) chosen = topIdx[2];\n        else if (r < pickP2 && topIdx[1] != -1) chosen = topIdx[1];\n        else chosen = topIdx[0];\n\n        sel.push_back(chosen);\n        covered |= acts[chosen].mask;\n    }\n\n    sel = prune_selection(sel, acts, M);\n    return sel;\n}\n\nvector<int> compute_counts(const vector<int>& sel, const vector<Action>& acts, int M) {\n    vector<int> cnt(M, 0);\n    for (int idx : sel) {\n        uint64_t m = acts[idx].mask;\n        while (m) { int b = ctz64(m); cnt[b]++; m &= m - 1; }\n    }\n    return cnt;\n}\n\npair<vector<int>, int> greedy_repair(uint64_t remU, const vector<Action>& acts, const vector<char>& banned, const vector<double>& w) {\n    vector<int> add;\n    int addCost = 0;\n    uint64_t rem = remU;\n    while (rem) {\n        int best = -1;\n        double best_ratio = 1e100;\n        int best_cost = INT_MAX;\n        for (int a = 0; a < (int)acts.size(); ++a) {\n            if ((int)banned.size() == (int)acts.size() && banned[a]) continue;\n            uint64_t gm = acts[a].mask & rem;\n            if (!gm) continue;\n            double gain = 0.0;\n            uint64_t mm = gm;\n            while (mm) { int b = ctz64(mm); gain += w[b]; mm &= mm - 1; }\n            double ratio = acts[a].cost / gain;\n            if (ratio < best_ratio || (ratio == best_ratio && acts[a].cost < best_cost)) {\n                best = a; best_ratio = ratio; best_cost = acts[a].cost;\n            }\n        }\n        if (best == -1) return {{}, INT_MAX};\n        add.push_back(best);\n        addCost += acts[best].cost;\n        rem &= ~acts[best].mask;\n    }\n    return {add, addCost};\n}\n\n// Exact DP to cover a small set of Oni (Rem). Returns chosen action indices and cost, or INF if impossible.\npair<vector<int>, int> exact_cover_dp(uint64_t Rem,\n                                      const vector<Action>& acts,\n                                      const vector<vector<int>>& coverActs,\n                                      const vector<char>& banned,\n                                      int r_limit = 16,\n                                      int cand_limit = 60) {\n    if (Rem == 0ULL) return {{}, 0};\n    vector<int> bits;\n    uint64_t tmp = Rem;\n    while (tmp) { bits.push_back(ctz64(tmp)); tmp &= tmp - 1; }\n    int r = (int)bits.size();\n    if (r > r_limit) return {{}, INT_MAX};\n    int A = (int)acts.size();\n\n    vector<int> compIdx(64, -1);\n    for (int i = 0; i < r; ++i) compIdx[bits[i]] = i;\n    int FULL = (1 << r) - 1;\n\n    vector<char> used(A, 0);\n    vector<int> candIdx;\n    candIdx.reserve(256);\n    for (int b : bits) for (int a : coverActs[b]) {\n        if (!banned.empty() && banned[a]) continue;\n        if (!used[a]) { used[a] = 1; candIdx.push_back(a); }\n    }\n    if (candIdx.empty()) return {{}, INT_MAX};\n\n    struct Cand { int idx; int cost; int pmask; double ratio; };\n    vector<Cand> cands; cands.reserve(candIdx.size());\n    for (int ai : candIdx) {\n        uint64_t m = acts[ai].mask & Rem;\n        if (!m) continue;\n        int pm = 0;\n        while (m) { int b = ctz64(m); pm |= (1 << compIdx[b]); m &= m - 1; }\n        int pc = __builtin_popcount((unsigned)pm);\n        if (pc == 0) continue;\n        Cand c{ai, acts[ai].cost, pm, (double)acts[ai].cost / (double)pc};\n        cands.push_back(c);\n    }\n    if (cands.empty()) return {{}, INT_MAX};\n\n    // ensure essentials\n    vector<int> essential;\n    essential.reserve(r);\n    for (int i = 0; i < r; ++i) {\n        int best = -1, bestCost = INT_MAX;\n        int bitMask = (1 << i);\n        for (auto &c : cands) if (c.pmask & bitMask) {\n            if (c.cost < bestCost) { bestCost = c.cost; best = c.idx; }\n        }\n        if (best != -1) essential.push_back(best);\n    }\n\n    sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){\n        if (a.ratio != b.ratio) return a.ratio < b.ratio;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return a.idx < b.idx;\n    });\n    vector<int> finalIdx;\n    finalIdx.reserve(min((int)cands.size(), cand_limit) + (int)essential.size());\n    for (int i = 0; i < (int)cands.size() && (int)finalIdx.size() < cand_limit; ++i) finalIdx.push_back(cands[i].idx);\n    sort(finalIdx.begin(), finalIdx.end());\n    for (int e : essential) if (!binary_search(finalIdx.begin(), finalIdx.end(), e)) finalIdx.push_back(e);\n\n    struct FinalCand { int idx; int cost; int pmask; };\n    vector<FinalCand> fin;\n    fin.reserve(finalIdx.size());\n    for (int ai : finalIdx) {\n        uint64_t m = acts[ai].mask & Rem;\n        if (!m) continue;\n        int pm = 0;\n        while (m) { int b = ctz64(m); int ci = compIdx[b]; if (ci >= 0) pm |= (1 << ci); m &= m - 1; }\n        if (pm == 0) continue;\n        fin.push_back({ai, acts[ai].cost, pm});\n    }\n    if (fin.empty()) return {{}, INT_MAX};\n\n    int Smax = 1 << r;\n    const int INF = 1e9;\n    vector<int> dp(Smax, INF), parent(Smax, -1), which(Smax, -1);\n    dp[0] = 0;\n    for (auto &c : fin) {\n        int pm = c.pmask, cc = c.cost, ci = c.idx;\n        for (int S = 0; S < Smax; ++S) {\n            if (dp[S] == INF) continue;\n            int T = S | pm;\n            if (dp[S] + cc < dp[T]) {\n                dp[T] = dp[S] + cc;\n                parent[T] = S;\n                which[T] = ci;\n            }\n        }\n    }\n    if (dp[FULL] >= INF) return {{}, INT_MAX};\n    vector<int> picks;\n    int cur = FULL;\n    while (cur != 0) {\n        int wi = which[cur];\n        if (wi == -1) { picks.clear(); break; }\n        picks.push_back(wi);\n        cur = parent[cur];\n    }\n    if (picks.empty() && FULL != 0) return {{}, INT_MAX};\n    return {picks, dp[FULL]};\n}\n\n// Build cover lists: for each Oni id, which actions cover it\nvector<vector<int>> build_cover_lists(const vector<Action>& acts, int M) {\n    vector<vector<int>> cover(M);\n    for (int a = 0; a < (int)acts.size(); ++a) {\n        uint64_t m = acts[a].mask;\n        while (m) { int b = ctz64(m); cover[b].push_back(a); m &= m - 1; }\n    }\n    return cover;\n}\n\n// Local improvement using exact DP replacements; 'locked' actions are not removed.\nvoid local_improvement_dp_locked(vector<int>& sel, const vector<Action>& acts, int M,\n                                 const vector<vector<int>>& coverActs, std::mt19937& rng,\n                                 const vector<char>& locked,\n                                 double time_limit_ms = 100.0) {\n    auto t0 = chrono::high_resolution_clock::now();\n    auto time_ok = [&](){\n        auto t1 = chrono::high_resolution_clock::now();\n        double ms = chrono::duration<double, std::milli>(t1 - t0).count();\n        return ms < time_limit_ms;\n    };\n\n    int A = acts.size();\n    if (sel.empty()) return;\n    vector<int> cnt = compute_counts(sel, acts, M);\n    int bestCost = selection_cost(sel, acts);\n\n    // 1->k replacements\n    bool improved_global = true;\n    while (improved_global && time_ok()) {\n        improved_global = false;\n        vector<int> order = sel;\n        shuffle(order.begin(), order.end(), rng);\n        for (int sIdx : order) {\n            if (!time_ok()) break;\n            if (locked[sIdx]) continue;\n            uint64_t m = acts[sIdx].mask;\n            uint64_t uniqueMask = 0;\n            uint64_t mm = m;\n            while (mm) { int b = ctz64(mm); if (cnt[b] == 1) uniqueMask |= (1ULL << b); mm &= mm - 1; }\n            if (!uniqueMask) continue;\n            int r = __builtin_popcountll(uniqueMask);\n            vector<char> banned; // empty banned: allow any action (except we already have unique not covered by others)\n            vector<int> addList; int addCost = INT_MAX;\n            if (r <= 16) {\n                auto res = exact_cover_dp(uniqueMask, acts, coverActs, banned, 16, 80);\n                addList = res.first; addCost = res.second;\n            }\n            if (r > 16 || addCost == INT_MAX) {\n                vector<double> w(M, 1.0);\n                auto gr = greedy_repair(uniqueMask, acts, banned, w);\n                addList = gr.first; addCost = gr.second;\n            }\n            if (addCost >= acts[sIdx].cost) continue;\n            vector<int> newSel;\n            newSel.reserve(sel.size() - 1 + addList.size());\n            for (int id : sel) if (id != sIdx) newSel.push_back(id);\n            for (int id : addList) newSel.push_back(id);\n            newSel = prune_selection(newSel, acts, M);\n            int newCost = selection_cost(newSel, acts);\n            if (newCost < bestCost) {\n                sel.swap(newSel);\n                bestCost = newCost;\n                cnt = compute_counts(sel, acts, M);\n                improved_global = true;\n                break;\n            }\n        }\n    }\n\n    if (!time_ok()) return;\n\n    // 2->k replacements: random tries\n    int tries = 80;\n    while (tries-- > 0 && time_ok()) {\n        if ((int)sel.size() < 2) break;\n        int ia = rng() % sel.size();\n        int ib = rng() % sel.size();\n        if (ia == ib) continue;\n        int s1 = sel[ia], s2 = sel[ib];\n        if (locked[s1] || locked[s2]) continue;\n        // compute uncovered if removing s1,s2\n        vector<int> cnt2 = cnt;\n        uint64_t baseCovered = 0;\n        for (int id : sel) if (id != s1 && id != s2) baseCovered |= acts[id].mask;\n        uint64_t remU = (acts[s1].mask | acts[s2].mask) & ~baseCovered;\n        if (!remU) {\n            // removing both reduces cost\n            vector<int> newSel;\n            newSel.reserve(sel.size()-2);\n            for (int id : sel) if (id != s1 && id != s2) newSel.push_back(id);\n            newSel = prune_selection(newSel, acts, M);\n            int newCost = selection_cost(newSel, acts);\n            if (newCost < bestCost) {\n                sel.swap(newSel);\n                bestCost = newCost;\n                cnt = compute_counts(sel, acts, M);\n            }\n            continue;\n        }\n        int r = __builtin_popcountll(remU);\n        vector<char> banned; // allow any actions\n        vector<int> addList; int addCost = INT_MAX;\n        if (r <= 16) {\n            auto res = exact_cover_dp(remU, acts, coverActs, banned, 16, 100);\n            addList = res.first; addCost = res.second;\n        }\n        if (r > 16 || addCost == INT_MAX) {\n            vector<double> w(M, 1.0);\n            auto gr = greedy_repair(remU, acts, banned, w);\n            addList = gr.first; addCost = gr.second;\n        }\n        int removedCost = acts[s1].cost + acts[s2].cost;\n        if (addCost >= removedCost) continue;\n        vector<int> newSel;\n        newSel.reserve(sel.size() - 2 + addList.size());\n        for (int id : sel) if (id != s1 && id != s2) newSel.push_back(id);\n        for (int id : addList) newSel.push_back(id);\n        newSel = prune_selection(newSel, acts, M);\n        int newCost = selection_cost(newSel, acts);\n        if (newCost < bestCost) {\n            sel.swap(newSel);\n            bestCost = newCost;\n            cnt = compute_counts(sel, acts, M);\n        }\n    }\n}\n\n// Large Neighborhood Search (LNS): remove a small random set of non-locked actions and repair\nvoid lns_improve(vector<int>& sel, const vector<Action>& acts, int M,\n                 const vector<vector<int>>& coverActs, const vector<char>& locked,\n                 std::mt19937& rng, double time_limit_ms = 150.0) {\n    auto t0 = chrono::high_resolution_clock::now();\n    auto time_ok = [&](){\n        auto t1 = chrono::high_resolution_clock::now();\n        double ms = chrono::duration<double, std::milli>(t1 - t0).count();\n        return ms < time_limit_ms;\n    };\n\n    int bestCost = selection_cost(sel, acts);\n    if (sel.empty()) return;\n\n    uniform_real_distribution<double> urand(0.0, 1.0);\n\n    while (time_ok()) {\n        // choose group size\n        int gs;\n        double r = urand(rng);\n        if (r < 0.5) gs = 3;\n        else if (r < 0.85) gs = 2;\n        else gs = 4;\n        if (gs > (int)sel.size()) gs = sel.size();\n\n        // pick gs distinct non-locked actions\n        vector<int> idxs;\n        idxs.reserve(gs);\n        int attempts = 0;\n        while ((int)idxs.size() < gs && attempts < 50) {\n            int pos = rng() % sel.size();\n            int s = sel[pos];\n            if (locked[s]) { attempts++; continue; }\n            bool ok = true;\n            for (int x : idxs) if (x == s) { ok = false; break; }\n            if (ok) idxs.push_back(s);\n            attempts++;\n        }\n        if (idxs.empty()) break;\n\n        // compute uncovered by removing idxs\n        uint64_t baseCovered = 0, unionGroup = 0;\n        for (int id : sel) {\n            bool inGroup = false;\n            for (int g : idxs) if (id == g) { inGroup = true; break; }\n            if (!inGroup) baseCovered |= acts[id].mask;\n            else unionGroup |= acts[id].mask;\n        }\n        uint64_t remU = unionGroup & ~baseCovered;\n        if (!remU) {\n            // removal alone improves\n            vector<int> newSel;\n            newSel.reserve(sel.size() - (int)idxs.size());\n            for (int id : sel) {\n                bool inGroup = false;\n                for (int g : idxs) if (id == g) { inGroup = true; break; }\n                if (!inGroup) newSel.push_back(id);\n            }\n            newSel = prune_selection(newSel, acts, M);\n            int newCost = selection_cost(newSel, acts);\n            if (newCost < bestCost) {\n                sel.swap(newSel);\n                bestCost = newCost;\n            }\n            continue;\n        }\n\n        int rbits = __builtin_popcountll(remU);\n        vector<char> banned; // allow any\n        vector<int> addList; int addCost = INT_MAX;\n        if (rbits <= 18) {\n            auto res = exact_cover_dp(remU, acts, coverActs, banned, 18, 120);\n            addList = res.first; addCost = res.second;\n        }\n        if (rbits > 18 || addCost == INT_MAX) {\n            vector<double> w(M, 1.0);\n            auto gr = greedy_repair(remU, acts, banned, w);\n            addList = gr.first; addCost = gr.second;\n        }\n        int removedCost = 0;\n        for (int g : idxs) removedCost += acts[g].cost;\n        if (addCost >= removedCost) continue;\n\n        vector<int> newSel;\n        newSel.reserve(sel.size() - (int)idxs.size() + addList.size());\n        for (int id : sel) {\n            bool inGroup = false;\n            for (int g : idxs) if (id == g) { inGroup = true; break; }\n            if (!inGroup) newSel.push_back(id);\n        }\n        for (int id : addList) newSel.push_back(id);\n        newSel = prune_selection(newSel, acts, M);\n        int newCost = selection_cost(newSel, acts);\n        if (newCost < bestCost) {\n            sel.swap(newSel);\n            bestCost = newCost;\n        }\n    }\n}\n\n// Build baseline actions: per Oni minimal safe cycle\nvector<Action> build_baseline_actions(const vector<string>& grid,\n                                      const vector<pair<int,int>>& oni_pos) {\n    int N = grid.size();\n    vector<Action> acts;\n    acts.reserve(oni_pos.size());\n\n    vector<vector<int>> fuku_row_pref(N, vector<int>(N+1, 0));\n    vector<vector<int>> fuku_col_pref(N, vector<int>(N+1, 0));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            fuku_row_pref[i][j+1] = fuku_row_pref[i][j] + (grid[i][j] == 'o');\n            fuku_col_pref[j][i+1] = fuku_col_pref[j][i] + (grid[i][j] == 'o');\n        }\n    }\n    auto no_fuku_row = [&](int r, int l, int rgt) -> bool {\n        if (l > rgt) return true;\n        return (fuku_row_pref[r][rgt+1] - fuku_row_pref[r][l]) == 0;\n    };\n    auto no_fuku_col = [&](int c, int top, int bot) -> bool {\n        if (top > bot) return true;\n        return (fuku_col_pref[c][bot+1] - fuku_col_pref[c][top]) == 0;\n    };\n\n    for (auto [i, j] : oni_pos) {\n        vector<pair<int,pair<char,int>>> cand; // cost, (dir, k)\n        if (no_fuku_col(j, 0, i-1)) { int k = i + 1; cand.push_back({2*k, {'U', k}}); }\n        if (no_fuku_col(j, i+1, N-1)) { int k = N - i; cand.push_back({2*k, {'D', k}}); }\n        if (no_fuku_row(i, 0, j-1)) { int k = j + 1; cand.push_back({2*k, {'L', k}}); }\n        if (no_fuku_row(i, j+1, N-1)) { int k = N - j; cand.push_back({2*k, {'R', k}}); }\n        if (cand.empty()) continue;\n        auto best = min_element(cand.begin(), cand.end(),\n                                [](auto& a, auto& b){ return a.first < b.first; });\n        Action a; a.d = best->second.first; a.p = (a.d == 'L' || a.d == 'R') ? i : j; a.k = best->second.second; a.cost = best->first; a.mask = 0;\n        acts.push_back(a);\n    }\n    return acts;\n}\n\nvector<pair<char,int>> actions_to_ops(const vector<int>& sel, const vector<Action>& acts) {\n    vector<pair<char,int>> ops;\n    long long total = 0;\n    for (int idx : sel) total += acts[idx].cost;\n    ops.reserve((size_t)total);\n    for (int idx : sel) {\n        const auto& a = acts[idx];\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(a.d, a.p);\n        char od = opposite(a.d);\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(od, a.p);\n    }\n    return ops;\n}\nvector<pair<char,int>> actions_to_ops_direct(const vector<Action>& acts) {\n    vector<pair<char,int>> ops;\n    long long total = 0;\n    for (auto& a : acts) total += a.cost;\n    ops.reserve((size_t)total);\n    for (auto& a : acts) {\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(a.d, a.p);\n        char od = opposite(a.d);\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(od, a.p);\n    }\n    return ops;\n}\n\n// Kernelization: pick forced actions (Oni covered by exactly one action).\nstruct KernelResult {\n    vector<Action> reducedActs;\n    vector<int> forcedIdx; // indices in original 'acts'\n    uint64_t forcedCovered = 0;\n};\nKernelResult kernelize_forced(const vector<Action>& acts, int M) {\n    int A = acts.size();\n    vector<Action> work = acts; // will mutate masks\n    vector<char> forcedA(A, 0);\n    uint64_t forcedCovered = 0;\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        vector<vector<int>> cover(M);\n        for (int a = 0; a < A; ++a) if (!forcedA[a] && work[a].mask) {\n            uint64_t m = work[a].mask;\n            while (m) { int b = ctz64(m); cover[b].push_back(a); m &= m - 1; }\n        }\n        for (int b = 0; b < M; ++b) {\n            if (cover[b].empty()) continue;\n            if ((int)cover[b].size() == 1) {\n                int a = cover[b][0];\n                if (forcedA[a]) continue;\n                forcedA[a] = 1;\n                forcedCovered |= acts[a].mask; // use original mask\n                for (int i = 0; i < A; ++i) if (!forcedA[i] && work[i].mask) {\n                    work[i].mask &= ~acts[a].mask;\n                }\n                changed = true;\n            }\n        }\n    }\n    vector<Action> reduced;\n    reduced.reserve(A);\n    for (int i = 0; i < A; ++i) {\n        if (forcedA[i]) continue;\n        if (work[i].mask == 0) continue;\n        reduced.push_back(work[i]);\n    }\n    vector<int> forcedIdx;\n    forcedIdx.reserve(A);\n    for (int i = 0; i < A; ++i) if (forcedA[i]) forcedIdx.push_back(i);\n    return {reduced, forcedIdx, forcedCovered};\n}\n\n// Primal-dual style selector as another seed\nvector<int> primal_dual_select(const vector<Action>& acts, int M) {\n    int A = acts.size();\n    if (A == 0) return {};\n    vector<double> slack(A);\n    for (int i = 0; i < A; ++i) slack[i] = acts[i].cost;\n    vector<char> selected(A, 0);\n    uint64_t unionMask = 0;\n    for (auto &a : acts) unionMask |= a.mask;\n    uint64_t uncovered = unionMask;\n    auto cover = build_cover_lists(acts, M);\n\n    while (uncovered) {\n        // pick bit with smallest cover size\n        int bestBit = -1;\n        int bestDeg = INT_MAX;\n        uint64_t tmp = uncovered;\n        while (tmp) {\n            int b = ctz64(tmp);\n            int deg = 0;\n            for (int a : cover[b]) if (!selected[a]) deg++;\n            if (deg > 0 && deg < bestDeg) { bestDeg = deg; bestBit = b; }\n            tmp &= tmp - 1;\n        }\n        if (bestBit == -1) break;\n        int bestA = -1;\n        double bestSlack = 1e100;\n        for (int a : cover[bestBit]) if (!selected[a]) {\n            if (slack[a] < bestSlack) { bestSlack = slack[a]; bestA = a; }\n        }\n        if (bestA == -1) break;\n        if (bestSlack > 0) {\n            for (int a : cover[bestBit]) if (!selected[a]) slack[a] -= bestSlack;\n        }\n        selected[bestA] = 1;\n        uncovered &= ~acts[bestA].mask;\n    }\n    vector<int> sel;\n    for (int i = 0; i < A; ++i) if (selected[i]) sel.push_back(i);\n    sel = prune_selection(sel, acts, M);\n    return sel;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n\n    vector<pair<int,int>> oni_pos;\n    vector<vector<int>> oni_id(N, vector<int>(N, -1));\n    for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j)\n        if (grid[i][j] == 'x') {\n            int id = oni_pos.size();\n            oni_pos.emplace_back(i, j);\n            oni_id[i][j] = id;\n        }\n    int M = (int)oni_pos.size();\n\n    // Build candidates with pruning\n    vector<Action> actsAll = build_candidates_tight(grid, oni_pos, oni_id);\n\n    // Kernelization: forced picks\n    KernelResult ker = kernelize_forced(actsAll, M);\n    vector<Action> acts = ker.reducedActs;\n    vector<int> forcedIdxAll = ker.forcedIdx; // indices in actsAll\n\n    // Availability per Oni on reduced acts\n    vector<int> avail(M, 0);\n    for (auto &a : acts) {\n        uint64_t m = a.mask;\n        while (m) { int b = ctz64(m); avail[b]++; m &= m - 1; }\n    }\n\n    // Weight variants\n    vector<vector<double>> weightVariants;\n    {\n        vector<double> w0(M, 1.0), w1(M, 1.0), w2(M, 1.0), w3(M, 1.0);\n        for (int i = 0; i < M; ++i) {\n            int av = max(1, avail[i]);\n            w1[i] = 1.0 / sqrt((double)av);\n            w2[i] = 1.0 / (double)av;\n            w3[i] = (av <= 2 ? 3.0 : (av == 3 ? 2.0 : 1.0)); // scarcity boost\n        }\n        weightVariants.push_back(w0);\n        weightVariants.push_back(w1);\n        weightVariants.push_back(w2);\n        weightVariants.push_back(w3);\n    }\n\n    std::mt19937 rng(712367 + (uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Multiple weighted greedy restarts with noise and stochasticity\n    vector<int> bestSel2;\n    int bestCost2 = INT_MAX;\n    int restarts = 28;\n    for (int t = 0; t < restarts; ++t) {\n        const auto& w = weightVariants[t % weightVariants.size()];\n        vector<int> sel2 = greedy_select_weighted_noisy(acts, M, w, rng, 0.12, 3, 0.15, 0.05);\n        int cst2 = selection_cost(sel2, acts);\n        if (cst2 < bestCost2) { bestSel2 = move(sel2); bestCost2 = cst2; }\n    }\n    // Primal-dual seed\n    {\n        vector<int> sel2 = primal_dual_select(acts, M);\n        int cst2 = selection_cost(sel2, acts);\n        if (cst2 < bestCost2) { bestSel2 = move(sel2); bestCost2 = cst2; }\n    }\n\n    // Combine forced picks + selected from reduced acts into combined acts space\n    vector<Action> combinedActs;\n    combinedActs.reserve(forcedIdxAll.size() + acts.size());\n    // push forced actions with original masks\n    for (int idxAll : forcedIdxAll) combinedActs.push_back(actsAll[idxAll]);\n    // then remaining acts (already have forced bits removed)\n    for (auto &a : acts) combinedActs.push_back(a);\n\n    // Build initial combined selection indices\n    vector<int> selCombined;\n    selCombined.reserve(forcedIdxAll.size() + bestSel2.size());\n    for (int i = 0; i < (int)forcedIdxAll.size(); ++i) selCombined.push_back(i);\n    for (int i : bestSel2) selCombined.push_back((int)forcedIdxAll.size() + i);\n    // Prune globally\n    selCombined = prune_selection(selCombined, combinedActs, M);\n\n    // Local improvement with DP; lock forced picks\n    vector<char> locked(combinedActs.size(), 0);\n    for (int i = 0; i < (int)forcedIdxAll.size(); ++i) locked[i] = 1;\n    auto coverActs = build_cover_lists(combinedActs, M);\n    local_improvement_dp_locked(selCombined, combinedActs, M, coverActs, rng, locked, 120.0);\n\n    // LNS improvement\n    lns_improve(selCombined, combinedActs, M, coverActs, locked, rng, 200.0);\n\n    // Final prune\n    selCombined = prune_selection(selCombined, combinedActs, M);\n\n    // Produce greedy ops and validate strictly\n    auto opsGreedy = actions_to_ops(selCombined, combinedActs);\n    auto checkGreedy = simulate(grid, opsGreedy);\n    bool greedyValid = (checkGreedy.first == 0 && checkGreedy.second == 0);\n\n    // Baseline fallback (guaranteed safe)\n    vector<Action> baseActs = build_baseline_actions(grid, oni_pos);\n    auto opsBase = actions_to_ops_direct(baseActs);\n    auto checkBase = simulate(grid, opsBase);\n    bool baseValid = (checkBase.first == 0 && checkBase.second == 0);\n\n    vector<pair<char,int>> ops;\n    if (greedyValid && baseValid) {\n        ops = (opsGreedy.size() <= opsBase.size()) ? move(opsGreedy) : move(opsBase);\n    } else if (greedyValid) {\n        ops = move(opsGreedy);\n    } else if (baseValid) {\n        ops = move(opsBase);\n    } else {\n        ops = move(opsBase);\n    }\n\n    if ((int)ops.size() > 4*N*N) {\n        if (baseValid && (int)opsBase.size() <= 4*N*N) {\n            ops = move(opsBase);\n        } else if (greedyValid && (int)opsGreedy.size() <= 4*N*N) {\n            ops = move(opsGreedy);\n        } else {\n            ops.resize(4*N*N);\n        }\n    }\n\n    for (auto &op : ops) cout << op.first << ' ' << op.second << '\\n';\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double ms() const {\n        return chrono::duration<double, std::milli>(\n            chrono::high_resolution_clock::now() - st\n        ).count();\n    }\n};\n\nstruct Candidate {\n    vector<int> a, b;\n    long long E_full = (1LL<<62);\n    long long E_part = (1LL<<62);\n};\n\nstatic long long simulate_error_full(const vector<int>& a, const vector<int>& b,\n                                     int L, const vector<int>& T) {\n    int N = (int)a.size();\n    vector<int> t(N, 0);\n    int cur = 0;\n    for (int step = 0; step < L; ++step) {\n        t[cur] += 1;\n        if (t[cur] & 1) cur = a[cur];\n        else cur = b[cur];\n    }\n    long long E = 0;\n    for (int i = 0; i < N; ++i) {\n        E += llabs((long long)t[i] - (long long)T[i]);\n    }\n    return E;\n}\n\nstatic long long simulate_error_partial(const vector<int>& a, const vector<int>& b,\n                                        int Lpart, const vector<int>& Tpart) {\n    int N = (int)a.size();\n    vector<int> t(N, 0);\n    int cur = 0;\n    for (int step = 0; step < Lpart; ++step) {\n        t[cur] += 1;\n        if (t[cur] & 1) cur = a[cur];\n        else cur = b[cur];\n    }\n    long long E = 0;\n    for (int i = 0; i < N; ++i) {\n        E += llabs((long long)t[i] - (long long)Tpart[i]);\n    }\n    return E;\n}\n\n// Build a-edge from an order\nstatic void build_a_from_order(const vector<int>& order, vector<int>& a) {\n    int N = (int)order.size();\n    a.assign(N, 0);\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    }\n}\n\n// Compute residual target D[j] = 2*T[j] - T[prev(j)] for given order (no clamping)\nstatic void residuals_from_order(const vector<int>& order, const vector<int>& T, vector<long long>& D) {\n    int N = (int)order.size();\n    D.assign(N, 0);\n    for (int k = 0; k < N; ++k) {\n        int j = order[k];\n        int prev = order[(k-1+N)%N];\n        D[j] = 2LL * (long long)T[j] - (long long)T[prev];\n    }\n}\n\n// Snake order A: evens ascending then odds descending\nstatic vector<int> build_snake_order_A(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng); // random tie-breaking\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    vector<int> evenIdx, oddIdx;\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) evenIdx.push_back(ord[i]);\n        else oddIdx.push_back(ord[i]);\n    }\n    vector<int> order;\n    order.reserve(N);\n    for (int x : evenIdx) order.push_back(x);\n    for (int k = (int)oddIdx.size()-1; k >= 0; --k) order.push_back(oddIdx[k]);\n    return order;\n}\n\n// Snake order B: odds ascending then evens descending\nstatic vector<int> build_snake_order_B(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    vector<int> evenIdx, oddIdx;\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) evenIdx.push_back(ord[i]);\n        else oddIdx.push_back(ord[i]);\n    }\n    vector<int> order;\n    order.reserve(N);\n    for (int x : oddIdx) order.push_back(x);\n    for (int k = (int)evenIdx.size()-1; k >= 0; --k) order.push_back(evenIdx[k]);\n    return order;\n}\n\n// Pure ascending order cycle\nstatic vector<int> build_ascending_order(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    return ord;\n}\n\n// Alternating extremes: low, high, low2, high2, ...\nstatic vector<int> build_alternating_extremes(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    vector<int> order;\n    order.reserve(N);\n    int l = 0, r = N - 1;\n    bool takeLow = true;\n    while (l <= r) {\n        if (takeLow) order.push_back(ord[l++]);\n        else order.push_back(ord[r--]);\n        takeLow = !takeLow;\n    }\n    return order;\n}\n\n// Greedy ring insertion to minimize sum of c(prev, curr) where c = max(0, Tprev - 2*Tcurr)\nstatic long long edge_cost(int prev, int curr, const vector<int>& T) {\n    long long v = (long long)T[prev] - 2LL * (long long)T[curr];\n    return v > 0 ? v : 0;\n}\nstatic vector<int> build_insertion_order(const vector<int>& T, mt19937_64& rng, int seedMode = 0) {\n    int N = (int)T.size();\n    vector<int> nodes(N);\n    iota(nodes.begin(), nodes.end(), 0);\n    // pick initial two nodes\n    int u = 0, v = 1;\n    if (seedMode == 0) {\n        // choose u median by T\n        vector<int> idx = nodes;\n        stable_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        u = idx[N/2];\n    } else if (seedMode == 1) {\n        // choose u from upper quartile\n        vector<int> idx = nodes;\n        stable_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        u = idx[(3*N)/4];\n    } else {\n        // random u\n        u = (int)(rng() % N);\n    }\n    // choose v minimizing edge_cost(u,v)+edge_cost(v,u)\n    long long best = (1LL<<62);\n    for (int cand : nodes) if (cand != u) {\n        long long sc = edge_cost(u, cand, T) + edge_cost(cand, u, T);\n        if (sc < best) { best = sc; v = cand; }\n    }\n    vector<int> cycle;\n    cycle.push_back(u);\n    cycle.push_back(v);\n    vector<char> used(N, 0);\n    used[u] = used[v] = 1;\n    while ((int)cycle.size() < N) {\n        int x = -1;\n        long long bestDelta = (1LL<<62);\n        // try every unused node and every insertion arc\n        for (int cand : nodes) {\n            if (used[cand]) continue;\n            int m = (int)cycle.size();\n            for (int i = 0; i < m; ++i) {\n                int p = cycle[i];\n                int q = cycle[(i+1)%m];\n                long long delta = edge_cost(p, cand, T) + edge_cost(cand, q, T) - edge_cost(p, q, T);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    x = cand;\n                }\n            }\n        }\n        // insert x at best position\n        int bestPos = -1;\n        {\n            int m = (int)cycle.size();\n            for (int i = 0; i < m; ++i) {\n                int p = cycle[i];\n                int q = cycle[(i+1)%m];\n                long long delta = edge_cost(p, x, T) + edge_cost(x, q, T) - edge_cost(p, q, T);\n                if (delta == bestDelta) { bestPos = (i+1)%m; break; }\n            }\n        }\n        if (bestPos == -1) bestPos = (int)cycle.size(); // fallback\n        cycle.insert(cycle.begin() + bestPos, x);\n        used[x] = 1;\n    }\n    return cycle;\n}\n\n// Greedy assignment of b with residual r initialized to D\nstatic void greedy_assign_b(const vector<int>& T, vector<long long>& r,\n                            mt19937_64 &rng, vector<int>& b) {\n    int N = (int)T.size();\n    b.assign(N, 0);\n    vector<int> items(N);\n    iota(items.begin(), items.end(), 0);\n    shuffle(items.begin(), items.end(), rng);\n    stable_sort(items.begin(), items.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] > T[j];\n        return i < j;\n    });\n\n    for (int idx = 0; idx < N; ++idx) {\n        int i = items[idx];\n        long long w = T[i];\n        long long bestDelta = (1LL<<62);\n        vector<int> cands;\n        for (int j = 0; j < N; ++j) {\n            long long rj = r[j];\n            long long delta = llabs(rj - w) - llabs(rj);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                cands.clear();\n                cands.push_back(j);\n            } else if (delta == bestDelta) {\n                cands.push_back(j);\n            }\n        }\n        int j = cands[rng() % cands.size()];\n        b[i] = j;\n        r[j] -= w;\n    }\n}\n\n// Local improvement: move single items from oversupplied bins (r<0) to deficit bins (r>0)\nstatic void local_improve_moves(const vector<int>& T, vector<long long>& r,\n                                vector<int>& b, mt19937_64 &rng, int passes = 2) {\n    int N = (int)T.size();\n    vector<vector<int>> itemsOfBin(N);\n    itemsOfBin.assign(N, {});\n    for (int i = 0; i < N; ++i) itemsOfBin[b[i]].push_back(i);\n\n    for (int pass = 0; pass < passes; ++pass) {\n        vector<int> deficits, overs;\n        for (int j = 0; j < N; ++j) {\n            if (r[j] > 0) deficits.push_back(j);\n            else if (r[j] < 0) overs.push_back(j);\n        }\n        if (deficits.empty() || overs.empty()) break;\n        // fill larger deficits first\n        stable_sort(deficits.begin(), deficits.end(), [&](int x, int y){ return r[x] > r[y]; });\n        for (int k : deficits) {\n            long long rk = r[k];\n            long long bestGain = 0; // negative delta means improvement\n            int bestFromBin = -1;\n            int bestItem = -1;\n            for (int j : overs) {\n                if (itemsOfBin[j].empty()) continue;\n                long long rj = r[j];\n                for (int ii : itemsOfBin[j]) {\n                    long long w = T[ii];\n                    long long delta = llabs(rj + w) + llabs(rk - w) - (llabs(rj) + llabs(rk));\n                    if (delta < bestGain) {\n                        bestGain = delta;\n                        bestFromBin = j;\n                        bestItem = ii;\n                    }\n                }\n            }\n            if (bestItem != -1) {\n                int j = bestFromBin;\n                int ii = bestItem;\n                long long w = T[ii];\n                // apply move: remove from j, add to k\n                r[j] += w;\n                r[k] -= w;\n                // update bins\n                auto &vj = itemsOfBin[j];\n                for (int idx = 0; idx < (int)vj.size(); ++idx) {\n                    if (vj[idx] == ii) {\n                        vj[idx] = vj.back();\n                        vj.pop_back();\n                        break;\n                    }\n                }\n                itemsOfBin[k].push_back(ii);\n                b[ii] = k;\n            }\n        }\n    }\n}\n\n// Pair-swap local improvement on b\nstatic void local_swap_improve(const vector<int>& T, vector<long long>& r,\n                               vector<int>& b, mt19937_64 &rng, int tries = 220) {\n    int N = (int)T.size();\n    for (int t = 0; t < tries; ++t) {\n        int i1 = rng() % N;\n        int i2 = rng() % N;\n        if (i1 == i2) continue;\n        int j1 = b[i1];\n        int j2 = b[i2];\n        if (j1 == j2) continue;\n        long long w1 = T[i1], w2 = T[i2];\n        long long old = llabs(r[j1]) + llabs(r[j2]);\n        long long r1p = r[j1] + w1 - w2;\n        long long r2p = r[j2] + w2 - w1;\n        long long nw = llabs(r1p) + llabs(r2p);\n        if (nw < old) {\n            r[j1] = r1p;\n            r[j2] = r2p;\n            b[i1] = j2;\n            b[i2] = j1;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, L;\n    if (!(cin >> N >> L)) return 0;\n    vector<int> T(N);\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    Timer timer;\n    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    const double TIME_LIMIT_MS = 1950.0;\n\n    // Prepare partial target Tpart with rounding so that sum Tpart = Lpart\n    const int Lpart = min(L, 120000);\n    vector<int> Tpart(N, 0);\n    {\n        long long sumBase = 0;\n        struct Rem { long long r; int i; };\n        vector<Rem> rems;\n        rems.reserve(N);\n        for (int i = 0; i < N; ++i) {\n            long long num = 1LL * T[i] * Lpart;\n            int base = (int)(num / L);\n            long long rem = num - 1LL * base * L;\n            Tpart[i] = base;\n            sumBase += base;\n            rems.push_back({rem, i});\n        }\n        int need = Lpart - (int)sumBase;\n        stable_sort(rems.begin(), rems.end(), [&](const Rem& a, const Rem& b){\n            if (a.r != b.r) return a.r > b.r;\n            return a.i < b.i;\n        });\n        for (int k = 0; k < need; ++k) Tpart[rems[k].i] += 1;\n    }\n\n    // Build a variety of a-edge orders (and their reverses)\n    vector<vector<int>> orders;\n    orders.reserve(16);\n    auto add_with_reverse = [&](const vector<int>& ord) {\n        orders.push_back(ord);\n        vector<int> rev = ord;\n        reverse(rev.begin(), rev.end());\n        orders.push_back(rev);\n    };\n    add_with_reverse(build_snake_order_A(T, rng));\n    add_with_reverse(build_snake_order_B(T, rng));\n    add_with_reverse(build_ascending_order(T, rng));\n    add_with_reverse(build_alternating_extremes(T, rng));\n    add_with_reverse(build_insertion_order(T, rng, 0));\n    add_with_reverse(build_insertion_order(T, rng, 1));\n    add_with_reverse(build_insertion_order(T, rng, 2));\n\n    // Precompute a-edges and D for each order\n    struct AInfo { vector<int> a; vector<long long> D; };\n    vector<AInfo> ainfos;\n    ainfos.resize(orders.size());\n    for (size_t oi = 0; oi < orders.size(); ++oi) {\n        build_a_from_order(orders[oi], ainfos[oi].a);\n        residuals_from_order(orders[oi], T, ainfos[oi].D);\n    }\n\n    // Search parameters\n    const int TOP_PART = 10;            // keep top candidates by partial error\n    const double FINAL_SIM_BUDGET_MS = 300.0; // reserve time for full sims\n\n    vector<Candidate> topCandidates;\n\n    auto try_candidate = [&](const AInfo& ai) {\n        vector<long long> r = ai.D;\n        vector<int> b(N, 0);\n        greedy_assign_b(T, r, rng, b);\n        local_improve_moves(T, r, b, rng, 2);\n        local_swap_improve(T, r, b, rng, 240);\n\n        Candidate c;\n        c.a = ai.a;\n        c.b = b;\n        c.E_part = simulate_error_partial(c.a, c.b, Lpart, Tpart);\n\n        // maintain top list by partial error\n        if ((int)topCandidates.size() < TOP_PART) {\n            topCandidates.push_back(c);\n            sort(topCandidates.begin(), topCandidates.end(),\n                 [](const Candidate& x, const Candidate& y){ return x.E_part < y.E_part; });\n        } else if (c.E_part < topCandidates.back().E_part) {\n            topCandidates.back() = c;\n            sort(topCandidates.begin(), topCandidates.end(),\n                 [](const Candidate& x, const Candidate& y){ return x.E_part < y.E_part; });\n        }\n    };\n\n    // Main loop: try many b-assignments over the different a cycles\n    size_t oi = 0;\n    while (timer.ms() < TIME_LIMIT_MS - FINAL_SIM_BUDGET_MS) {\n        try_candidate(ainfos[oi]);\n        oi++;\n        if (oi >= ainfos.size()) oi = 0;\n    }\n\n    // Fallback if no candidates generated\n    if (topCandidates.empty()) {\n        vector<int> a(N), b(N);\n        iota(a.begin(), a.end(), 0);\n        for (int i = 0; i < N; ++i) b[i] = (i+1) % N;\n        for (int i = 0; i < N; ++i) cout << a[i] << \" \" << b[i] << \"\\n\";\n        return 0;\n    }\n\n    // Full simulation for top few\n    // Simulate as many as time allows, up to 8\n    int simulate_k = min(8, (int)topCandidates.size());\n    for (int i = 0; i < simulate_k; ++i) {\n        if (timer.ms() > TIME_LIMIT_MS) break;\n        topCandidates[i].E_full = simulate_error_full(topCandidates[i].a, topCandidates[i].b, L, T);\n    }\n    // Select best by full error if available, else by partial\n    Candidate best = topCandidates[0];\n    for (int i = 0; i < simulate_k; ++i) {\n        if (topCandidates[i].E_full < best.E_full) best = topCandidates[i];\n    }\n    if (best.E_full >= (1LL<<61)) {\n        best = *min_element(topCandidates.begin(), topCandidates.end(),\n                            [](const Candidate& x, const Candidate& y){\n                                return x.E_part < y.E_part;\n                            });\n    }\n\n    // Output best\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\n// DSU\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x ? x : p[x]=find(p[x]); }\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; sz[a]+=sz[b];\n        return true;\n    }\n};\n\n// Morton (Z-order) 15-bit interleave (coords <= 10000)\nstatic inline uint64_t morton_code(uint32_t x, uint32_t y) {\n    uint64_t code = 0;\n    for (int i = 0; i < 15; ++i) {\n        code |= (uint64_t)((x >> i) & 1u) << (2*i);\n        code |= (uint64_t)((y >> i) & 1u) << (2*i + 1);\n    }\n    return code;\n}\n\n// Hilbert order (bits=15)\nstatic inline uint64_t hilbert_index(uint32_t x, uint32_t y) {\n    const uint32_t n = 1u << 15;\n    uint64_t d = 0;\n    uint32_t rx, ry, s;\n    for (s = n >> 1; s > 0; s >>= 1) {\n        rx = (x & s) ? 1u : 0u;\n        ry = (y & s) ? 1u : 0u;\n        d += (uint64_t)s * (uint64_t)s * ((3u * rx) ^ ry);\n        if (ry == 0) {\n            if (rx == 1) {\n                x = (n - 1) - x;\n                y = (n - 1) - y;\n            }\n            uint32_t t = x; x = y; y = t;\n        }\n    }\n    return d;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, Q, L, W;\n    if (!(cin >> N >> M >> Q >> L >> W)) return 0;\n    vector<int> G(M);\n    for(int i=0;i<M;i++) cin >> G[i];\n    vector<int> lx(N), rx(N), ly(N), ry(N);\n    for(int i=0;i<N;i++){\n        cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n    }\n\n    // Centers and widths\n    vector<int> xc(N), yc(N), wx(N), wy(N);\n    for (int i = 0; i < N; ++i) {\n        xc[i] = (lx[i] + rx[i]) / 2;\n        yc[i] = (ly[i] + ry[i]) / 2;\n        wx[i] = rx[i] - lx[i];\n        wy[i] = ry[i] - ly[i];\n    }\n\n    // Variances and uncertainty\n    vector<double> varx(N), vary(N), diag(N);\n    for (int i = 0; i < N; ++i) {\n        varx[i] = (double)wx[i] * (double)wx[i] / 12.0;\n        vary[i] = (double)wy[i] * (double)wy[i] / 12.0;\n        diag[i] = hypot((double)wx[i], (double)wy[i]);\n    }\n\n    auto ed2 = [&](int u, int v)->double{\n        double dx = (double)xc[u] - (double)xc[v];\n        double dy = (double)yc[u] - (double)yc[v];\n        return dx*dx + dy*dy + varx[u] + varx[v] + vary[u] + vary[v];\n    };\n\n    // Build candidate orders: Morton, Hilbert, and Greedy NN (ed2)\n    vector<vector<int>> orders;\n\n    // Morton\n    {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        vector<uint64_t> code(N);\n        for (int i = 0; i < N; ++i) code[i] = morton_code((uint32_t)xc[i], (uint32_t)yc[i]);\n        sort(ord.begin(), ord.end(), [&](int a, int b){ return code[a] < code[b]; });\n        orders.push_back(move(ord));\n    }\n    // Hilbert\n    {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        vector<uint64_t> code(N);\n        for (int i = 0; i < N; ++i) code[i] = hilbert_index((uint32_t)xc[i], (uint32_t)yc[i]);\n        sort(ord.begin(), ord.end(), [&](int a, int b){ return code[a] < code[b]; });\n        orders.push_back(move(ord));\n    }\n    // Greedy Nearest-Neighbor (open path)\n    {\n        vector<int> ord;\n        ord.reserve(N);\n        vector<char> used(N, 0);\n        // start from smallest Hilbert code node\n        int start = 0;\n        {\n            uint64_t best = (uint64_t)-1;\n            for (int i = 0; i < N; ++i) {\n                uint64_t h = hilbert_index((uint32_t)xc[i], (uint32_t)yc[i]);\n                if (h < best) { best = h; start = i; }\n            }\n        }\n        int cur = start;\n        used[cur] = 1;\n        ord.push_back(cur);\n        for (int step = 1; step < N; ++step) {\n            int bestj = -1;\n            double bd = 1e300;\n            for (int j = 0; j < N; ++j) if (!used[j]) {\n                double d2 = ed2(cur, j);\n                if (d2 < bd) { bd = d2; bestj = j; }\n            }\n            if (bestj == -1) break;\n            used[bestj] = 1;\n            ord.push_back(bestj);\n            cur = bestj;\n        }\n        if ((int)ord.size() == N) orders.push_back(move(ord));\n    }\n\n    auto path_cost = [&](const vector<int>& ord)->double{\n        double s = 0.0;\n        for (int i = 0; i+1 < (int)ord.size(); ++i) s += ed2(ord[i], ord[i+1]);\n        return s;\n    };\n\n    // Pick best by neighbor sum\n    int bestOrdIdx = 0;\n    double bestPath = 1e300;\n    for (int i = 0; i < (int)orders.size(); ++i) {\n        double sc = path_cost(orders[i]);\n        if (sc < bestPath) {\n            bestPath = sc;\n            bestOrdIdx = i;\n        }\n    }\n    vector<int> ord = orders[bestOrdIdx];\n\n    // Windowed 2-opt on open path (few passes)\n    auto two_opt_improve = [&](vector<int>& path){\n        const int Nn = (int)path.size();\n        if (Nn < 4) return;\n        const int WINDOW = 60; // local window\n        const int PASSES = 2;\n        for (int pass = 0; pass < PASSES; ++pass) {\n            bool improved = false;\n            for (int i = 1; i <= Nn - 3; ++i) {\n                int jmax = min(Nn - 2, i + WINDOW);\n                for (int j = i + 1; j <= jmax; ++j) {\n                    int a = path[i-1];\n                    int b = path[i];\n                    int c = path[j];\n                    int d = path[j+1];\n                    double before = ed2(a,b) + ed2(c,d);\n                    double after  = ed2(a,c) + ed2(b,d);\n                    if (after + 1e-9 < before) {\n                        reverse(path.begin() + i, path.begin() + j + 1);\n                        improved = true;\n                        break;\n                    }\n                }\n                if (improved) continue;\n            }\n            if (!improved) break;\n        }\n    };\n    two_opt_improve(ord);\n\n    // Build group boundaries (fixed sizes)\n    vector<int> start(M+1, 0);\n    for (int k = 0; k < M; ++k) start[k+1] = start[k] + G[k];\n\n    // One-pass boundary smoothing: swap one element across boundary if improves expected MST cost\n    auto mst_cost_ed2 = [&](const vector<int>& nodes)->double{\n        int n = (int)nodes.size();\n        if (n <= 1) return 0.0;\n        vector<char> used(n, 0);\n        vector<double> best(n, 1e300);\n        best[0] = 0.0;\n        double cost = 0.0;\n        for (int it = 0; it < n; ++it) {\n            int v = -1;\n            double bv = 1e300;\n            for (int i = 0; i < n; ++i) if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n            if (v == -1) break;\n            used[v] = 1;\n            cost += (v==0 ? 0.0 : bv);\n            for (int u = 0; u < n; ++u) if (!used[u]) {\n                double w = ed2(nodes[v], nodes[u]);\n                if (w < best[u]) best[u] = w;\n            }\n        }\n        return cost;\n    };\n\n    auto group_nodes_by_ord = [&](int l, int r)->vector<int>{\n        vector<int> v;\n        v.reserve(r-l);\n        for (int i = l; i < r; ++i) v.push_back(ord[i]);\n        return v;\n    };\n\n    for (int k = 0; k+1 < M; ++k) {\n        if (G[k] == 0 || G[k+1] == 0) continue;\n        int posL = start[k+1] - 1;\n        int posR = start[k+1];\n        int left_id = ord[posL];\n        int right_id = ord[posR];\n\n        vector<int> grpL = group_nodes_by_ord(start[k], start[k+1]);\n        vector<int> grpR = group_nodes_by_ord(start[k+1], start[k+2]);\n        double before = mst_cost_ed2(grpL) + mst_cost_ed2(grpR);\n\n        grpL.back() = right_id;\n        grpR[0] = left_id;\n        double after = mst_cost_ed2(grpL) + mst_cost_ed2(grpR);\n\n        if (after + 1e-9 < before) {\n            swap(ord[posL], ord[posR]);\n        }\n    }\n\n    // Build groups from ord\n    vector<vector<int>> groups(M);\n    {\n        int ptr = 0;\n        for (int k = 0; k < M; ++k) {\n            groups[k].reserve(G[k]);\n            for (int t = 0; t < G[k]; ++t) groups[k].push_back(ord[ptr++]);\n        }\n    }\n\n    // Group uncertainty\n    vector<double> g_unc(M, 0.0);\n    for (int k = 0; k < M; ++k) {\n        double s = 0.0;\n        for (int id : groups[k]) s += diag[id];\n        g_unc[k] = (G[k] > 0 ? s / (double)G[k] : 0.0);\n    }\n\n    // Approx MST edges per group (expected distances)\n    auto mst_edges_ed2 = [&](const vector<int>& nodes)->vector<pair<int,int>>{\n        int n = (int)nodes.size();\n        vector<char> used(n, 0);\n        vector<double> best(n, 1e300);\n        vector<int> parent(n, -1);\n        if (n > 0) best[0] = 0.0;\n        vector<pair<int,int>> edges;\n        edges.reserve(max(0, n-1));\n        for (int it = 0; it < n; ++it) {\n            int v = -1;\n            double bv = 1e300;\n            for (int i = 0; i < n; ++i) if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n            if (v == -1) break;\n            used[v] = 1;\n            if (parent[v] != -1) edges.emplace_back(nodes[parent[v]], nodes[v]);\n            for (int u = 0; u < n; ++u) if (!used[u]) {\n                double w = ed2(nodes[v], nodes[u]);\n                if (w < best[u]) { best[u] = w; parent[u] = v; }\n            }\n        }\n        return edges;\n    };\n    vector<vector<pair<int,int>>> approxEdges(M);\n    for (int k = 0; k < M; ++k) {\n        approxEdges[k] = mst_edges_ed2(groups[k]);\n    }\n\n    // Query function\n    auto do_query = [&](const vector<int>& subset)->vector<pair<int,int>>{\n        int l = (int)subset.size();\n        cout << \"? \" << l;\n        for (int i = 0; i < l; ++i) cout << \" \" << subset[i];\n        cout << \"\\n\" << flush;\n        vector<pair<int,int>> res;\n        res.reserve(max(0, l-1));\n        for (int i = 0; i < l-1; ++i) {\n            int a,b; cin >> a >> b;\n            res.emplace_back(a,b);\n        }\n        return res;\n    };\n\n    int queries_used = 0;\n    vector<vector<pair<int,int>>> oracle_edges(M);\n\n    // Stage A: small groups 3..L\n    vector<int> small_groups;\n    for (int k = 0; k < M; ++k) if (G[k] >= 3 && G[k] <= L) small_groups.push_back(k);\n    sort(small_groups.begin(), small_groups.end(), [&](int a, int b){\n        if (G[a] != G[b]) return G[a] > G[b];\n        if (g_unc[a] != g_unc[b]) return g_unc[a] > g_unc[b];\n        return a < b;\n    });\n    for (int k : small_groups) {\n        if (queries_used >= Q) break;\n        auto res = do_query(groups[k]);\n        ++queries_used;\n        oracle_edges[k].insert(oracle_edges[k].end(), res.begin(), res.end());\n    }\n\n    // Stage B: large groups -> disjoint connected chunks (BFS on approx MST) with benefit scoring\n    struct Chunk {\n        int k;\n        vector<int> sub;\n        double benefit; // sum of variances on MST edges inside the chunk\n        bool operator<(Chunk const& other) const { return benefit > other.benefit; } // for sort desc\n    };\n    vector<Chunk> chunks_all;\n    vector<Chunk> chunks2; // size-2\n    vector<int> id2pos(N, -1);\n\n    for (int k = 0; k < M; ++k) {\n        if (G[k] <= L) continue;\n        const auto &grp = groups[k];\n        int sz = (int)grp.size();\n\n        for (int i = 0; i < sz; ++i) id2pos[grp[i]] = i;\n        vector<vector<int>> adj(sz);\n        for (auto &e : approxEdges[k]) {\n            int u = id2pos[e.first];\n            int v = id2pos[e.second];\n            if (u >= 0 && v >= 0) {\n                adj[u].push_back(v);\n                adj[v].push_back(u);\n            }\n        }\n\n        vector<char> used(sz, 0);\n        int remaining = sz;\n\n        auto pick_seed = [&]()->int{\n            for (int i = 0; i < sz; ++i) if (!used[i] && (int)adj[i].size() <= 1) return i;\n            for (int i = 0; i < sz; ++i) if (!used[i]) return i;\n            return -1;\n        };\n\n        vector<vector<int>> subs_local;\n        while (remaining > 0) {\n            int seed = pick_seed();\n            if (seed == -1) break;\n            deque<int> dq;\n            dq.push_back(seed);\n            vector<char> enq(sz, 0);\n            enq[seed] = 1;\n\n            vector<int> subset_local;\n            while (!dq.empty() && (int)subset_local.size() < L) {\n                int v = dq.front(); dq.pop_front();\n                if (used[v]) continue;\n                used[v] = 1;\n                subset_local.push_back(v);\n                --remaining;\n                for (int to : adj[v]) if (!used[to] && !enq[to]) {\n                    dq.push_back(to); enq[to] = 1;\n                }\n            }\n            if (!subset_local.empty()) subs_local.push_back(move(subset_local));\n            else break;\n        }\n\n        // Convert to city IDs and compute benefit\n        for (auto &loc : subs_local) {\n            vector<int> sub; sub.reserve(loc.size());\n            for (int idx : loc) sub.push_back(grp[idx]);\n            // Compute benefit on approx MST edges inside sub\n            vector<char> in(sz, 0);\n            for (int id : sub) in[id2pos[id]] = 1;\n            double ben = 0.0;\n            for (auto &e : approxEdges[k]) {\n                int u = id2pos[e.first], v = id2pos[e.second];\n                if (in[u] && in[v]) {\n                    ben += varx[e.first] + varx[e.second] + vary[e.first] + vary[e.second];\n                }\n            }\n            if ((int)sub.size() >= 3) chunks_all.push_back({k, move(sub), ben});\n            else if ((int)sub.size() == 2) chunks2.push_back({k, move(sub), ben});\n        }\n\n        for (int i = 0; i < sz; ++i) id2pos[grp[i]] = -1;\n    }\n\n    sort(chunks_all.begin(), chunks_all.end()); // by benefit desc\n    sort(chunks2.begin(), chunks2.end());\n\n    for (auto &ch : chunks_all) {\n        if (queries_used >= Q) break;\n        auto res = do_query(ch.sub);\n        ++queries_used;\n        oracle_edges[ch.k].insert(oracle_edges[ch.k].end(), res.begin(), res.end());\n    }\n    for (auto &ch : chunks2) {\n        if (queries_used >= Q) break;\n        auto res = do_query(ch.sub);\n        ++queries_used;\n        oracle_edges[ch.k].insert(oracle_edges[ch.k].end(), res.begin(), res.end());\n    }\n\n    // If any budget remains, query size-2 groups by uncertainty\n    if (queries_used < Q) {\n        vector<int> size2groups;\n        for (int k = 0; k < M; ++k) if (G[k] == 2) size2groups.push_back(k);\n        sort(size2groups.begin(), size2groups.end(), [&](int a, int b){\n            if (g_unc[a] != g_unc[b]) return g_unc[a] > g_unc[b];\n            return a < b;\n        });\n        for (int k : size2groups) {\n            if (queries_used >= Q) break;\n            auto res = do_query(groups[k]);\n            ++queries_used;\n            oracle_edges[k].insert(oracle_edges[k].end(), res.begin(), res.end());\n        }\n    }\n\n    // Output final answer\n    cout << \"!\" << \"\\n\";\n\n    // Build final edges per group\n    vector<int> pos(N, -1);\n    for (int k = 0; k < M; ++k) {\n        const auto &grp = groups[k];\n        int sz = (int)grp.size();\n\n        // Print city IDs for this group\n        for (int i = 0; i < sz; ++i) {\n            if (i) cout << \" \";\n            cout << grp[i];\n        }\n        cout << \"\\n\";\n\n        if (sz <= 1) continue;\n\n        for (int i = 0; i < sz; ++i) pos[grp[i]] = i;\n\n        // Force oracle edges first\n        vector<pair<int,int>> final_edges;\n        final_edges.reserve(max(0, sz-1));\n        DSU dsu(sz);\n\n        auto add_edge_if = [&](int u, int v){\n            int iu = pos[u], iv = pos[v];\n            if (iu < 0 || iv < 0) return;\n            if (dsu.unite(iu, iv)) final_edges.emplace_back(u, v);\n        };\n\n        {\n            unordered_set<long long> seen;\n            seen.reserve(oracle_edges[k].size()*2+1);\n            auto enc = [](int a, int b)->long long{\n                if (a > b) swap(a,b);\n                return ((long long)a<<32) ^ (long long)b;\n            };\n            for (auto &e : oracle_edges[k]) {\n                int a = e.first, b = e.second;\n                if (a == b) continue;\n                if (pos[a] == -1 || pos[b] == -1) continue;\n                long long key = enc(a,b);\n                if (seen.insert(key).second) {\n                    add_edge_if(a,b);\n                    if ((int)final_edges.size() == sz-1) break;\n                }\n            }\n        }\n\n        // Add approximate MST edges next\n        for (auto &e : approxEdges[k]) {\n            if ((int)final_edges.size() == sz-1) break;\n            add_edge_if(e.first, e.second);\n        }\n\n        // Fallback: connect remaining components greedily by expected distance\n        if ((int)final_edges.size() < sz-1) {\n            unordered_map<int, vector<int>> comp_nodes;\n            comp_nodes.reserve(sz*2+1);\n            for (int i = 0; i < sz; ++i) comp_nodes[dsu.find(i)].push_back(grp[i]);\n\n            while ((int)comp_nodes.size() > 1 && (int)final_edges.size() < sz-1) {\n                double bestW = 1e300;\n                int bu=-1, bv=-1;\n                vector<pair<int, vector<int>>> comps;\n                comps.reserve(comp_nodes.size());\n                for (auto &kv : comp_nodes) comps.push_back(kv);\n                for (size_t i = 0; i < comps.size(); ++i) {\n                    for (size_t j = i+1; j < comps.size(); ++j) {\n                        for (int u : comps[i].second) {\n                            for (int v : comps[j].second) {\n                                double w = ed2(u, v);\n                                if (w < bestW) { bestW = w; bu = u; bv = v; }\n                            }\n                        }\n                    }\n                }\n                if (bu != -1) {\n                    add_edge_if(bu, bv);\n                    comp_nodes.clear();\n                    for (int i = 0; i < sz; ++i) comp_nodes[dsu.find(i)].push_back(grp[i]);\n                } else break;\n            }\n        }\n\n        for (auto &e : final_edges) cout << e.first << \" \" << e.second << \"\\n\";\n\n        for (int i = 0; i < sz; ++i) pos[grp[i]] = -1;\n    }\n\n    cout.flush();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Directions: 0:U, 1:D, 2:L, 3:R\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\nstatic const char dch[4] = {'U', 'D', 'L', 'R'};\n\nstruct Step {\n    char a; // 'M','S','A'\n    char d; // 'U','D','L','R'\n};\n\nstruct BFSResult {\n    bool ok = false;\n    vector<Step> path; // Non-empty only when needPath=true\n    int dist = -1;\n};\n\nstruct GridEnv {\n    int N;\n    vector<uint8_t> G; // 0 free, 1 blocked\n    GridEnv() {}\n    GridEnv(int N_) : N(N_), G(N_*N_, 0) {}\n    inline bool inside(int i, int j) const { return (0 <= i && i < N && 0 <= j && j < N); }\n    inline int id(int i, int j) const { return i * N + j; }\n    inline pair<int,int> coord(int idx) const { return {idx / N, idx % N}; }\n};\n\nstatic inline int dir_from_to(pair<int,int> a, pair<int,int> b) {\n    int di2 = b.first - a.first;\n    int dj2 = b.second - a.second;\n    if (di2 == -1 && dj2 == 0) return 0; // U\n    if (di2 == 1 && dj2 == 0)  return 1; // D\n    if (di2 == 0 && dj2 == -1) return 2; // L\n    if (di2 == 0 && dj2 == 1)  return 3; // R\n    return -1;\n}\n\n// Build local mapping around target t = (ti,tj) for enhanced BFS\nstatic inline void build_local_bits(const GridEnv &env, int ti, int tj,\n                                    vector<int> &cellToBit, vector<pair<int,int>> &bitPos) {\n    int NN = env.N * env.N;\n    cellToBit.assign(NN, -1);\n    bitPos.clear();\n    auto add_bit = [&](int i, int j) {\n        cellToBit[env.id(i, j)] = (int)bitPos.size();\n        bitPos.emplace_back(i, j);\n    };\n    add_bit(ti, tj); // bit 0 is target itself\n    if (env.inside(ti - 1, tj)) add_bit(ti - 1, tj);\n    if (env.inside(ti + 1, tj)) add_bit(ti + 1, tj);\n    if (env.inside(ti, tj - 1)) add_bit(ti, tj - 1);\n    if (env.inside(ti, tj + 1)) add_bit(ti, tj + 1);\n}\n\n// Compute slide destination with local mask\nstatic inline pair<int,int> slide_with_mask(const GridEnv &env, int i, int j, int d,\n                                            const vector<int> &cellToBit, int mask) {\n    int ci = i, cj = j;\n    while (true) {\n        int ni = ci + di[d], nj = cj + dj[d];\n        if (!env.inside(ni, nj)) break;\n        int idx = env.id(ni, nj);\n        int b = cellToBit[idx];\n        bool blocked = (b != -1 ? ((mask >> b) & 1) : env.G[idx]);\n        if (blocked) break;\n        ci = ni; cj = nj;\n    }\n    return {ci, cj};\n}\n\n// Enhanced BFS: allows M, S, and A on the target and its four neighbors only (local mask).\n// Returns both distance and, optionally, the action path.\nstatic BFSResult bfs_enhanced(const GridEnv &env, pair<int,int> s, pair<int,int> t, bool needPath) {\n    int N = env.N;\n    int NN = N * N;\n    int si = s.first, sj = s.second;\n    int ti = t.first, tj = t.second;\n    int sId = env.id(si, sj);\n    int tId = env.id(ti, tj);\n\n    vector<int> cellToBit;\n    vector<pair<int,int>> bitPos;\n    build_local_bits(env, ti, tj, cellToBit, bitPos);\n    int K = (int)bitPos.size();\n    int MS = 1 << K;\n\n    auto is_blocked = [&](int idx, int mask) -> bool {\n        int b = cellToBit[idx];\n        if (b != -1) return (mask >> b) & 1;\n        return env.G[idx];\n    };\n\n    int initMask = 0;\n    for (int b = 0; b < K; ++b) {\n        auto [bi, bj] = bitPos[b];\n        if (env.G[env.id(bi, bj)]) initMask |= (1 << b);\n    }\n\n    int SZ = NN * MS;\n    vector<char> vis(SZ, 0);\n    vector<int> distArr(SZ, -1);\n\n    vector<int> par, how, hdir;\n    if (needPath) {\n        par.assign(SZ, -1);\n        how.assign(SZ, 0);\n        hdir.assign(SZ, 0);\n    }\n\n    auto enc = [&](int pos, int mask) { return pos * MS + mask; };\n    int start = enc(sId, initMask);\n    deque<int> q;\n    vis[start] = 1;\n    distArr[start] = 0;\n    q.push_back(start);\n    int goal = -1;\n\n    while (!q.empty()) {\n        int u = q.front(); q.pop_front();\n        int pos = u / MS;\n        int mask = u % MS;\n        if (pos == tId) { goal = u; break; }\n\n        auto [ui, uj] = env.coord(pos);\n\n        // Move\n        for (int d = 0; d < 4; ++d) {\n            int vi = ui + di[d], vj = uj + dj[d];\n            if (!env.inside(vi, vj)) continue;\n            int vpos = env.id(vi, vj);\n            if (is_blocked(vpos, mask)) continue;\n            int v = enc(vpos, mask);\n            if (!vis[v]) {\n                vis[v] = 1;\n                distArr[v] = distArr[u] + 1;\n                if (needPath) { par[v] = u; how[v] = 'M'; hdir[v] = dch[d]; }\n                q.push_back(v);\n            }\n        }\n        // Slide\n        for (int d = 0; d < 4; ++d) {\n            auto [vi, vj] = slide_with_mask(env, ui, uj, d, cellToBit, mask);\n            if (vi == ui && vj == uj) continue;\n            int vpos = env.id(vi, vj);\n            int v = enc(vpos, mask);\n            if (!vis[v]) {\n                vis[v] = 1;\n                distArr[v] = distArr[u] + 1;\n                if (needPath) { par[v] = u; how[v] = 'S'; hdir[v] = dch[d]; }\n                q.push_back(v);\n            }\n        }\n        // Alter on local cells\n        for (int d = 0; d < 4; ++d) {\n            int vi = ui + di[d], vj = uj + dj[d];\n            if (!env.inside(vi, vj)) continue;\n            int b = cellToBit[env.id(vi, vj)];\n            if (b == -1) continue;\n            int nmask = mask ^ (1 << b);\n            int v = enc(pos, nmask);\n            if (!vis[v]) {\n                vis[v] = 1;\n                distArr[v] = distArr[u] + 1;\n                if (needPath) { par[v] = u; how[v] = 'A'; hdir[v] = dch[d]; }\n                q.push_back(v);\n            }\n        }\n    }\n\n    if (goal == -1) {\n        return BFSResult{false, {}, -1};\n    }\n\n    int dist = distArr[goal];\n    if (!needPath) {\n        return BFSResult{true, {}, dist};\n    }\n\n    vector<Step> path;\n    int cur = goal;\n    while (cur != start) {\n        path.push_back(Step{(char)how[cur], (char)hdir[cur]});\n        cur = par[cur];\n    }\n    reverse(path.begin(), path.end());\n    return BFSResult{true, path, dist};\n}\n\nstatic inline int dist_enhanced(const GridEnv &env, pair<int,int> s, pair<int,int> t) {\n    auto res = bfs_enhanced(env, s, t, false);\n    if (!res.ok) return INT_MAX / 4;\n    return res.dist;\n}\n\nstatic inline BFSResult path_enhanced(const GridEnv &env, pair<int,int> s, pair<int,int> t) {\n    return bfs_enhanced(env, s, t, true);\n}\n\n// Apply a Step to the state: update position and grid (for Alter).\nstatic inline void apply_step(GridEnv &env, pair<int,int> &pos, const Step &st) {\n    int i = pos.first, j = pos.second;\n    int d = 0;\n    for (int k = 0; k < 4; ++k) if (dch[k] == st.d) { d = k; break; }\n    if (st.a == 'M') {\n        int ni = i + di[d], nj = j + dj[d];\n        pos = {ni, nj};\n    } else if (st.a == 'S') {\n        int ci = i, cj = j;\n        while (true) {\n            int ni = ci + di[d], nj = cj + dj[d];\n            if (!env.inside(ni, nj)) break;\n            if (env.G[env.id(ni, nj)]) break;\n            ci = ni; cj = nj;\n        }\n        pos = {ci, cj};\n    } else if (st.a == 'A') {\n        int ni = i + di[d], nj = j + dj[d];\n        if (env.inside(ni, nj)) {\n            int idx = env.id(ni, nj);\n            env.G[idx] ^= 1;\n        }\n    }\n}\n\nstatic inline void compute_top_rows_cols(const vector<pair<int,int>>& P, int startIdx, int N,\n                                         vector<int>& topRows, vector<int>& topCols) {\n    vector<int> rc(N, 0), cc(N, 0);\n    for (int i = startIdx; i < (int)P.size(); ++i) {\n        rc[P[i].first]++; cc[P[i].second]++;\n    }\n    vector<pair<int,int>> rv, cv;\n    rv.reserve(N); cv.reserve(N);\n    for (int r = 0; r < N; ++r) rv.emplace_back(rc[r], r);\n    for (int c = 0; c < N; ++c) cv.emplace_back(cc[c], c);\n    sort(rv.begin(), rv.end(), greater<>());\n    sort(cv.begin(), cv.end(), greater<>());\n    topRows.clear(); topCols.clear();\n    int need = 3; // top-3 rows/cols\n    for (int i = 0; i < (int)rv.size() && (int)topRows.size() < need; ++i) {\n        if (rv[i].first == 0) break;\n        topRows.push_back(rv[i].second);\n    }\n    for (int i = 0; i < (int)cv.size() && (int)topCols.size() < need; ++i) {\n        if (cv[i].first == 0) break;\n        topCols.push_back(cv[i].second);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    vector<pair<int,int>> P(M);\n    for (int k = 0; k < M; ++k) cin >> P[k].first >> P[k].second;\n\n    GridEnv env(N);\n    vector<Step> ans;\n    const long long cap = 2LL * N * M;\n\n    pair<int,int> cur = P[0];\n\n    int NN = N * N;\n\n    for (int k = 1; k < M; ++k) {\n        pair<int,int> target = P[k];\n        pair<int,int> next1 = (k + 1 < M ? P[k + 1] : make_pair(-1, -1));\n        pair<int,int> next2 = (k + 2 < M ? P[k + 2] : make_pair(-1, -1));\n        pair<int,int> next3 = (k + 3 < M ? P[k + 3] : make_pair(-1, -1));\n        pair<int,int> next4 = (k + 4 < M ? P[k + 4] : make_pair(-1, -1));\n\n        // Plan path for current leg\n        auto plan = path_enhanced(env, cur, target);\n        if (!plan.ok) {\n            plan = path_enhanced(env, cur, target);\n            if (!plan.ok) break;\n        }\n        vector<Step> path = plan.path;\n\n        // Baseline distances for upcoming legs under current env\n        int base1 = (k + 1 < M) ? dist_enhanced(env, target, next1) : 0;\n        int base2 = (k + 2 < M) ? dist_enhanced(env, next1, next2) : 0;\n        int base3 = (k + 3 < M) ? dist_enhanced(env, next2, next3) : 0;\n        int base4 = (k + 4 < M) ? dist_enhanced(env, next3, next4) : 0;\n\n        // Precompute neighbor-of-next flags for quick membership checks\n        vector<char> isNeigh1(NN, 0), isNeigh2(NN, 0), isNeigh3(NN, 0), isNeigh4(NN, 0);\n        if (k + 1 < M) {\n            int ti = next1.first, tj = next1.second;\n            for (int d = 0; d < 4; ++d) {\n                int ni = ti + di[d], nj = tj + dj[d];\n                if (env.inside(ni, nj)) isNeigh1[env.id(ni, nj)] = 1;\n            }\n        }\n        if (k + 2 < M) {\n            int ti = next2.first, tj = next2.second;\n            for (int d = 0; d < 4; ++d) {\n                int ni = ti + di[d], nj = tj + dj[d];\n                if (env.inside(ni, nj)) isNeigh2[env.id(ni, nj)] = 1;\n            }\n        }\n        if (k + 3 < M) {\n            int ti = next3.first, tj = next3.second;\n            for (int d = 0; d < 4; ++d) {\n                int ni = ti + di[d], nj = tj + dj[d];\n                if (env.inside(ni, nj)) isNeigh3[env.id(ni, nj)] = 1;\n            }\n        }\n        if (k + 4 < M) {\n            int ti = next4.first, tj = next4.second;\n            for (int d = 0; d < 4; ++d) {\n                int ni = ti + di[d], nj = tj + dj[d];\n                if (env.inside(ni, nj)) isNeigh4[env.id(ni, nj)] = 1;\n            }\n        }\n\n        // Build rail preferences: top rows/cols among remaining targets (k+1..M-1)\n        vector<int> topRows, topCols;\n        compute_top_rows_cols(P, k + 1, N, topRows, topCols);\n\n        // Execute path with opportunistic toggles\n        pair<int,int> pos = cur;\n        int i = 0;\n        int toggledCount = 0;\n        const int maxTogglesPerLeg = 4;\n\n        struct Cand {\n            int idx;\n            char dir;\n            int score;\n        };\n\n        auto try_opportunistic_toggle = [&](int &remLen, int &b1, int &b2, int &b3, int &b4) -> bool {\n            if (toggledCount >= maxTogglesPerLeg) return false;\n\n            // Build adjacent candidates with priority score\n            vector<Cand> cands;\n            for (int d = 0; d < 4; ++d) {\n                int ni = pos.first + di[d], nj = pos.second + dj[d];\n                if (!env.inside(ni, nj)) continue;\n                int idx = env.id(ni, nj);\n                int sc = 0;\n                if (k + 1 < M) {\n                    if (isNeigh1[idx]) sc += 9;\n                    if (ni == next1.first || nj == next1.second) sc += 4;\n                }\n                if (k + 2 < M) {\n                    if (isNeigh2[idx]) sc += 6;\n                    if (ni == next2.first || nj == next2.second) sc += 3;\n                }\n                if (k + 3 < M) {\n                    if (isNeigh3[idx]) sc += 4;\n                    if (ni == next3.first || nj == next3.second) sc += 2;\n                }\n                if (k + 4 < M) {\n                    if (isNeigh4[idx]) sc += 3;\n                    if (ni == next4.first || nj == next4.second) sc += 1;\n                }\n                bool onRail = false;\n                for (int r : topRows) if (ni == r) { onRail = true; break; }\n                if (!onRail) for (int c : topCols) if (nj == c) { onRail = true; break; }\n                if (onRail) sc += 2;\n\n                cands.push_back(Cand{idx, dch[d], sc});\n            }\n            // Dedup by idx and keep best score/dir\n            sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){\n                if (a.idx != b.idx) return a.idx < b.idx;\n                return a.score > b.score;\n            });\n            vector<Cand> uniq;\n            for (auto &c : cands) {\n                if (uniq.empty() || uniq.back().idx != c.idx) uniq.push_back(c);\n            }\n            // Sort by score desc, keep topK\n            sort(uniq.begin(), uniq.end(), [](const Cand& a, const Cand& b){\n                return a.score > b.score;\n            });\n            int topK = min(4, (int)uniq.size());\n            uniq.resize(topK);\n\n            int bestDelta = 0;\n            int bestType = 0; // 1 single, 2 pair\n            Cand bestA, bestB;\n\n            auto eval_state = [&](int tglCount) -> int {\n                int cur_new = dist_enhanced(env, pos, target);\n                if (cur_new >= INT_MAX / 8) return INT_MAX / 4;\n                int n1_new = (k + 1 < M) ? dist_enhanced(env, target, next1) : 0;\n                int n2_new = (k + 2 < M) ? dist_enhanced(env, next1, next2) : 0;\n                int n3_new = (k + 3 < M) ? dist_enhanced(env, next2, next3) : 0;\n                int n4_new = (k + 4 < M) ? dist_enhanced(env, next3, next4) : 0;\n                int delta = tglCount + (cur_new - remLen)\n                            + (n1_new - b1) + (n2_new - b2) + (n3_new - b3) + (n4_new - b4);\n                return delta;\n            };\n\n            // Evaluate singles\n            for (int a = 0; a < (int)uniq.size(); ++a) {\n                int idxA = uniq[a].idx;\n                env.G[idxA] ^= 1;\n                int delta = eval_state(1);\n                env.G[idxA] ^= 1;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestA = uniq[a];\n                }\n            }\n            // Evaluate pairs (only if we haven't toggled too much)\n            if (toggledCount <= maxTogglesPerLeg - 2 && (int)uniq.size() >= 2) {\n                for (int a = 0; a < (int)uniq.size(); ++a) {\n                    for (int b = a + 1; b < (int)uniq.size(); ++b) {\n                        int idxA = uniq[a].idx;\n                        int idxB = uniq[b].idx;\n                        if (idxA == idxB) continue;\n                        env.G[idxA] ^= 1;\n                        env.G[idxB] ^= 1;\n                        int delta = eval_state(2);\n                        env.G[idxA] ^= 1;\n                        env.G[idxB] ^= 1;\n                        if (delta < bestDelta) {\n                            bestDelta = delta;\n                            bestType = 2;\n                            bestA = uniq[a];\n                            bestB = uniq[b];\n                        }\n                    }\n                }\n            }\n\n            if (bestType != 0 && bestDelta < 0) {\n                if (bestType == 1) {\n                    if ((long long)ans.size() + 1LL > cap) return false;\n                    ans.push_back(Step{'A', bestA.dir});\n                    env.G[bestA.idx] ^= 1;\n                    toggledCount += 1;\n                } else {\n                    if ((long long)ans.size() + 2LL > cap) return false;\n                    ans.push_back(Step{'A', bestA.dir});\n                    env.G[bestA.idx] ^= 1;\n                    ans.push_back(Step{'A', bestB.dir});\n                    env.G[bestB.idx] ^= 1;\n                    toggledCount += 2;\n                }\n                // Replan remainder from current pos\n                auto repl = path_enhanced(env, pos, target);\n                if (repl.ok) {\n                    path = repl.path;\n                    i = 0;\n                    remLen = (int)path.size();\n                    // Recompute base distances under new env\n                    if (k + 1 < M) b1 = dist_enhanced(env, target, next1);\n                    if (k + 2 < M) b2 = dist_enhanced(env, next1, next2);\n                    if (k + 3 < M) b3 = dist_enhanced(env, next2, next3);\n                    if (k + 4 < M) b4 = dist_enhanced(env, next3, next4);\n                    return true;\n                } else {\n                    // Revert if replanning fails (unlikely)\n                    if (bestType == 1) {\n                        env.G[bestA.idx] ^= 1;\n                        ans.pop_back();\n                        toggledCount -= 1;\n                    } else {\n                        env.G[bestA.idx] ^= 1;\n                        env.G[bestB.idx] ^= 1;\n                        ans.pop_back();\n                        ans.pop_back();\n                        toggledCount -= 2;\n                    }\n                }\n            }\n            return false;\n        };\n\n        while (i < (int)path.size()) {\n            int remLen = (int)path.size() - i;\n            // Try an opportunistic toggle before executing next step\n            if (try_opportunistic_toggle(remLen, base1, base2, base3, base4)) {\n                continue; // toggled and replanned; evaluate again\n            }\n            // Execute next step\n            if ((long long)ans.size() + 1LL > cap) goto OUTPUT;\n            Step st = path[i];\n            ans.push_back(st);\n            apply_step(env, pos, st);\n            ++i;\n        }\n\n        // We are now at target\n        cur = target;\n\n        // Post-arrival toggles at target: evaluate all non-empty subsets of its neighbors\n        if (k + 1 < M) {\n            // Recompute base distances under current env (they may have changed in loop)\n            base1 = dist_enhanced(env, cur, next1);\n            base2 = (k + 2 < M) ? dist_enhanced(env, next1, next2) : 0;\n            base3 = (k + 3 < M) ? dist_enhanced(env, next2, next3) : 0;\n            base4 = (k + 4 < M) ? dist_enhanced(env, next3, next4) : 0;\n\n            // Gather neighbors of target with directions\n            vector<pair<int,char>> neigh; // (idx, dir)\n            for (int d = 0; d < 4; ++d) {\n                int ni = cur.first + di[d], nj = cur.second + dj[d];\n                if (env.inside(ni, nj)) {\n                    neigh.emplace_back(env.id(ni, nj), dch[d]);\n                }\n            }\n\n            int S = (int)neigh.size();\n            int bestDelta = 0;\n            int bestMask = 0; // bitmask over neighbors\n\n            // Evaluate all non-empty subsets (up to 15)\n            for (int mask = 1; mask < (1 << S); ++mask) {\n                // Apply subset\n                for (int b = 0; b < S; ++b) if (mask & (1 << b)) env.G[neigh[b].first] ^= 1;\n\n                int d1 = dist_enhanced(env, cur, next1);\n                int d2 = (k + 2 < M) ? dist_enhanced(env, next1, next2) : 0;\n                int d3 = (k + 3 < M) ? dist_enhanced(env, next2, next3) : 0;\n                int d4 = (k + 4 < M) ? dist_enhanced(env, next3, next4) : 0;\n\n                // Revert subset\n                for (int b = 0; b < S; ++b) if (mask & (1 << b)) env.G[neigh[b].first] ^= 1;\n\n                if (d1 >= INT_MAX / 8) continue;\n                int tglCount = __builtin_popcount((unsigned)mask);\n                int delta = tglCount + (d1 - base1) + (d2 - base2) + (d3 - base3) + (d4 - base4);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestMask = mask;\n                }\n            }\n\n            // Apply the best subset if beneficial and within cap\n            if (bestDelta < 0 && bestMask != 0) {\n                for (int b = 0; b < S; ++b) if (bestMask & (1 << b)) {\n                    if ((long long)ans.size() + 1LL > cap) goto OUTPUT;\n                    ans.push_back(Step{'A', neigh[b].second});\n                    env.G[neigh[b].first] ^= 1;\n                }\n            }\n        }\n    }\n\nOUTPUT:\n    for (auto &st : ans) {\n        cout << st.a << ' ' << st.d << '\\n';\n    }\n    return 0;\n}"},"16":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Rect { int a, b, c, d; }; // [a,c) x [b,d)\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Solver {\n    static constexpr int LIMIT_COORD = 10000;\n\n    int n;\n    vector<int> x, y, r;\n    vector<Rect> rects;\n\n    mt19937_64 rng;\n    Timer timer;\n    double time_limit;\n\n    Solver(int n_, vector<int> x_, vector<int> y_, vector<int> r_, double tl=4.85)\n        : n(n_), x(move(x_)), y(move(y_)), r(move(r_)), time_limit(tl) {\n        rects.resize(n);\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        seed ^= (uint64_t)(uintptr_t)this;\n        rng.seed(seed);\n    }\n\n    inline ll area_of(const Rect &rc) const { return (ll)(rc.c - rc.a) * (ll)(rc.d - rc.b); }\n    inline double score_si_ri(ll s, ll ri) const {\n        if (s <= 0) return 0.0;\n        ll mn = min(s, ri), mx = max(s, ri);\n        double t = (double)mn / (double)mx;\n        double d = 1.0 - t;\n        return 1.0 - d * d;\n    }\n    inline double score_i(int i) const { return score_si_ri(area_of(rects[i]), r[i]); }\n\n    inline void compute_allowed_expansions(int i, int &leftMax, int &rightMax, int &downMax, int &upMax) const {\n        const Rect &ri = rects[i];\n        int LBound = 0, RBound = LIMIT_COORD, DBound = 0, UBound = LIMIT_COORD;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect &rj = rects[j];\n            if (!(ri.d <= rj.b || rj.d <= ri.b)) {\n                if (rj.a >= ri.c) RBound = min(RBound, rj.a);\n                if (rj.c <= ri.a) LBound = max(LBound, rj.c);\n            }\n            if (!(ri.c <= rj.a || rj.c <= ri.a)) {\n                if (rj.b >= ri.d) UBound = min(UBound, rj.b);\n                if (rj.d <= ri.b) DBound = max(DBound, rj.d);\n            }\n        }\n        leftMax = max(0, ri.a - LBound);\n        rightMax = max(0, RBound - ri.c);\n        downMax = max(0, ri.b - DBound);\n        upMax = max(0, UBound - ri.d);\n    }\n\n    template <class T> inline T clampv(T v, T lo, T hi) const {\n        if (v < lo) return lo;\n        if (v > hi) return hi;\n        return v;\n    }\n\n    inline ll expand_horiz(int i, int delta, int leftMax, int rightMax) {\n        if (delta <= 0 || (leftMax + rightMax) <= 0) return 0;\n        Rect &ri = rects[i];\n        int h = ri.d - ri.b;\n        int maxDelta = min(delta, leftMax + rightMax);\n        int leftDist = x[i] - ri.a;\n        int rightDist = ri.c - x[i] - 1;\n        int diff = rightDist - leftDist;\n        int l = clampv((maxDelta + diff) / 2, 0, maxDelta);\n        l = min(l, leftMax);\n        int rTake = maxDelta - l;\n        if (rTake > rightMax) { rTake = rightMax; l = min(maxDelta - rTake, leftMax); }\n        if (l > 0) ri.a -= l;\n        if (rTake > 0) ri.c += rTake;\n        return (ll)h * (ll)(l + rTake);\n    }\n    inline ll expand_vert(int i, int delta, int downMax, int upMax) {\n        if (delta <= 0 || (downMax + upMax) <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int maxDelta = min(delta, downMax + upMax);\n        int downDist = y[i] - ri.b;\n        int upDist = ri.d - y[i] - 1;\n        int d = clampv((maxDelta + (downDist - upDist)) / 2, 0, maxDelta);\n        d = min(d, downMax);\n        int uTake = maxDelta - d;\n        if (uTake > upMax) { uTake = upMax; d = min(maxDelta - uTake, downMax); }\n        if (d > 0) ri.b -= d;\n        if (uTake > 0) ri.d += uTake;\n        return (ll)w * (ll)(d + uTake);\n    }\n    inline ll shrink_horiz(int i, int delta) {\n        if (delta <= 0) return 0;\n        Rect &ri = rects[i];\n        int h = ri.d - ri.b;\n        int shrinkLeftMax = x[i] - ri.a;\n        int shrinkRightMax = ri.c - (x[i] + 1);\n        int cap = shrinkLeftMax + shrinkRightMax;\n        if (cap <= 0) return 0;\n        int maxDelta = min(delta, cap);\n        int leftDist = x[i] - ri.a, rightDist = ri.c - x[i] - 1;\n        int l = clampv((maxDelta + (leftDist - rightDist)) / 2, 0, maxDelta);\n        l = min(l, shrinkLeftMax);\n        int rTake = maxDelta - l;\n        if (rTake > shrinkRightMax) { rTake = shrinkRightMax; l = min(maxDelta - rTake, shrinkLeftMax); }\n        if (l > 0) ri.a += l;\n        if (rTake > 0) ri.c -= rTake;\n        return (ll)h * (ll)(l + rTake);\n    }\n    inline ll shrink_vert(int i, int delta) {\n        if (delta <= 0) return 0;\n        Rect &ri = rects[i];\n        int w = ri.c - ri.a;\n        int shrinkDownMax = y[i] - ri.b;\n        int shrinkUpMax = ri.d - (y[i] + 1);\n        int cap = shrinkDownMax + shrinkUpMax;\n        if (cap <= 0) return 0;\n        int maxDelta = min(delta, cap);\n        int downDist = y[i] - ri.b, upDist = ri.d - y[i] - 1;\n        int d = clampv((maxDelta + (downDist - upDist)) / 2, 0, maxDelta);\n        d = min(d, shrinkDownMax);\n        int uTake = maxDelta - d;\n        if (uTake > shrinkUpMax) { uTake = shrinkUpMax; d = min(maxDelta - uTake, shrinkDownMax); }\n        if (d > 0) ri.b += d;\n        if (uTake > 0) ri.d -= uTake;\n        return (ll)w * (ll)(d + uTake);\n    }\n\n    static inline long long floordiv(long long a, long long b) {\n        if (b < 0) a = -a, b = -b;\n        if (a >= 0) return a / b;\n        else return - ((-a + b - 1) / b);\n    }\n\n    // Combined expand/shrink using true score gain\n    void combined_expand_plan(int i, ll s, ll target, int w, int h, int capW, int capH, int leftMax, int rightMax, int downMax, int upMax) {\n        if (capW + capH <= 0) return;\n        vector<int> candH;\n        auto pushH = [&](long long H) {\n            if (H < 0) H = 0;\n            if (H > capH) H = capH;\n            int hh = (int)H; if (hh < 0 || hh > capH) return;\n            for (int v : candH) if (v == hh) return;\n            candH.push_back(hh);\n        };\n        candH.reserve(12);\n        pushH(0); pushH(capH);\n        if (w > 0) { long long t = (target - s) / max(1, w);\n            pushH(t); pushH(t-1); pushH(t+1); pushH(t-2); pushH(t+2);\n        }\n        pushH(min(capH, max(0, (h < w ? (w - h) : 0))));\n        double base = score_si_ri(s, target);\n        double bestGain = 1e-15;\n        int bestDw = 0, bestDh = 0;\n        for (int Dh : candH) {\n            long long denom = (long long)h + (long long)Dh;\n            long long Dw0 = (denom > 0) ? floordiv((target - s) - (long long)w * Dh, denom) : 0;\n            for (long long dww : {Dw0 - 2, Dw0 - 1, Dw0, Dw0 + 1, Dw0 + 2}) {\n                int Dw = (int)clampv(dww, 0LL, (long long)capW);\n                long long added = (long long)h * Dw + (long long)w * Dh + (long long)Dw * Dh;\n                double gain = score_si_ri(s + added, target) - base;\n                if (gain > bestGain) { bestGain = gain; bestDw = Dw; bestDh = Dh; }\n            }\n        }\n        bool horizFirst = (w < h);\n        if (horizFirst && bestDw > 0) {\n            expand_horiz(i, bestDw, leftMax, rightMax);\n            int lM, rM, dM, uM; compute_allowed_expansions(i, lM, rM, dM, uM);\n            int Dh2 = min(bestDh, dM + uM); if (Dh2 > 0) expand_vert(i, Dh2, dM, uM);\n        } else if (!horizFirst && bestDh > 0) {\n            expand_vert(i, bestDh, downMax, upMax);\n            int lM, rM, dM, uM; compute_allowed_expansions(i, lM, rM, dM, uM);\n            int Dw2 = min(bestDw, lM + rM); if (Dw2 > 0) expand_horiz(i, Dw2, lM, rM);\n        } else {\n            if (bestDw > 0) expand_horiz(i, bestDw, leftMax, rightMax);\n            if (bestDh > 0) { int lM, rM, dM, uM; compute_allowed_expansions(i, lM, rM, dM, uM);\n                int Dh2 = min(bestDh, dM + uM); if (Dh2 > 0) expand_vert(i, Dh2, dM, uM);\n            }\n        }\n    }\n    void combined_shrink_plan(int i, ll s, ll target, int w, int h, int capW, int capH) {\n        if (capW + capH <= 0) return;\n        vector<int> candH;\n        auto pushH = [&](long long H) {\n            if (H < 0) H = 0; if (H > capH) H = capH;\n            int hh = (int)H; if (hh < 0 || hh > capH) return;\n            for (int v : candH) if (v == hh) return;\n            candH.push_back(hh);\n        };\n        candH.reserve(12);\n        pushH(0); pushH(capH);\n        if (w > 0) { long long t = (s - target) / max(1, w);\n            pushH(t); pushH(t-1); pushH(t+1); pushH(t-2); pushH(t+2);\n        }\n        pushH(min(capH, max(0, (h > w ? (h - w) : 0))));\n        double base = score_si_ri(s, target);\n        double bestGain = 1e-15; // positive gain\n        int bestDw = 0, bestDh = 0;\n        for (int Dh : candH) {\n            long long denom = (long long)h - (long long)Dh;\n            long long Dw0 = (denom > 0) ? floordiv((s - target) - (long long)w * Dh, denom) : 0;\n            for (long long dww : {Dw0 - 2, Dw0 - 1, Dw0, Dw0 + 1, Dw0 + 2}) {\n                int Dw = (int)clampv(dww, 0LL, (long long)capW);\n                long long dec = (long long)h * Dw + (long long)w * Dh - (long long)Dw * Dh;\n                dec = max(0LL, dec);\n                double gain = score_si_ri(s - dec, target) - base;\n                if (gain > bestGain) { bestGain = gain; bestDw = Dw; bestDh = Dh; }\n            }\n        }\n        bool shrinkHFirst = (w > h);\n        if (shrinkHFirst && bestDw > 0) { shrink_horiz(i, bestDw); if (bestDh > 0) shrink_vert(i, bestDh); }\n        else if (!shrinkHFirst && bestDh > 0) { shrink_vert(i, bestDh); if (bestDw > 0) shrink_horiz(i, bestDw); }\n        else { if (bestDw > 0) shrink_horiz(i, bestDw); if (bestDh > 0) shrink_vert(i, bestDh); }\n    }\n\n    bool adjust_one(int i) {\n        Rect &rc = rects[i]; bool changed = false;\n        for (int it = 0; it < 2; ++it) {\n            ll s = area_of(rc), target = r[i];\n            int w = rc.c - rc.a, h = rc.d - rc.b;\n            int leftMax, rightMax, downMax, upMax; compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n            if (s < target) {\n                combined_expand_plan(i, s, target, w, h, leftMax + rightMax, downMax + upMax, leftMax, rightMax, downMax, upMax); changed = true;\n                s = area_of(rects[i]);\n                if (s < target) {\n                    compute_allowed_expansions(i, leftMax, rightMax, downMax, upMax);\n                    int w2 = rects[i].c - rects[i].a, h2 = rects[i].d - rects[i].b;\n                    double base = score_si_ri(s, target);\n                    double bestGain = 1e-15; int mv = -1;\n                    if (leftMax > 0) { double gain = score_si_ri(s + h2, target) - base; if (gain > bestGain) { bestGain = gain; mv = 0; } }\n                    if (rightMax > 0) { double gain = score_si_ri(s + h2, target) - base; if (gain > bestGain) { bestGain = gain; mv = 1; } }\n                    if (downMax > 0) { double gain = score_si_ri(s + w2, target) - base; if (gain > bestGain) { bestGain = gain; mv = 2; } }\n                    if (upMax > 0) { double gain = score_si_ri(s + w2, target) - base; if (gain > bestGain) { bestGain = gain; mv = 3; } }\n                    if (mv == 0) rc.a--, changed = true;\n                    else if (mv == 1) rc.c++, changed = true;\n                    else if (mv == 2) rc.b--, changed = true;\n                    else if (mv == 3) rc.d++, changed = true;\n                }\n            } else if (s > target) {\n                int capW = (x[i] - rc.a) + (rc.c - (x[i] + 1)), capH = (y[i] - rc.b) + (rc.d - (y[i] + 1));\n                combined_shrink_plan(i, s, target, w, h, capW, capH); changed = true;\n                s = area_of(rects[i]);\n                if (s > target) {\n                    int sl = x[i] - rects[i].a, sr = rects[i].c - (x[i] + 1), sd = y[i] - rects[i].b, su = rects[i].d - (y[i] + 1);\n                    int w2 = rects[i].c - rects[i].a, h2 = rects[i].d - rects[i].b;\n                    double base = score_si_ri(s, target);\n                    double bestGain = 1e-15; int mv = -1;\n                    if (sl > 0) { double gain = score_si_ri(s - (ll)h2, target) - base; if (gain > bestGain) { bestGain = gain; mv = 0; } }\n                    if (sr > 0) { double gain = score_si_ri(s - (ll)h2, target) - base; if (gain > bestGain) { bestGain = gain; mv = 1; } }\n                    if (sd > 0) { double gain = score_si_ri(s - (ll)w2, target) - base; if (gain > bestGain) { bestGain = gain; mv = 2; } }\n                    if (su > 0) { double gain = score_si_ri(s - (ll)w2, target) - base; if (gain > bestGain) { bestGain = gain; mv = 3; } }\n                    if (mv == 0) rc.a++, changed = true;\n                    else if (mv == 1) rc.c--, changed = true;\n                    else if (mv == 2) rc.b++, changed = true;\n                    else if (mv == 3) rc.d--, changed = true;\n                }\n            } else break;\n            rc.a = clampv(rc.a, 0, LIMIT_COORD - 1); rc.c = clampv(rc.c, rc.a + 1, LIMIT_COORD);\n            rc.b = clampv(rc.b, 0, LIMIT_COORD - 1); rc.d = clampv(rc.d, rc.b + 1, LIMIT_COORD);\n            if (!(rc.a <= x[i] && x[i] < rc.c && rc.b <= y[i] && y[i] < rc.d)) {\n                rc.a = x[i]; rc.b = y[i]; rc.c = x[i] + 1; rc.d = y[i] + 1; changed = true;\n            }\n        }\n        return changed;\n    }\n\n    void initial_setup() { for (int i = 0; i < n; ++i) rects[i] = Rect{ x[i], y[i], x[i] + 1, y[i] + 1 }; }\n\n    struct PairItem { int i, j; bool vertical; };\n    void build_fullside_pairs(vector<PairItem>& pairs) const {\n        pairs.clear();\n        for (int i = 0; i < n; ++i) for (int j = i+1; j < n; ++j) {\n            const Rect &A = rects[i], &B = rects[j];\n            if (A.c == B.a && A.b == B.b && A.d == B.d) pairs.push_back({i, j, true});\n            else if (B.c == A.a && B.b == A.b && B.d == A.d) pairs.push_back({j, i, true});\n            if (A.d == B.b && A.a == B.a && A.c == B.c) pairs.push_back({i, j, false});\n            else if (B.d == A.b && B.a == A.a && B.c == A.c) pairs.push_back({j, i, false});\n        }\n    }\n\n    static inline bool overlapStrict(const Rect& A, const Rect& B) {\n        return (A.a < B.c && B.a < A.c && A.b < B.d && B.b < A.d);\n    }\n    inline bool containsSeed(const Rect& R, int xi, int yi) const {\n        return (R.a <= xi && xi < R.c && R.b <= yi && yi < R.d);\n    }\n    inline bool insideBounds(const Rect& R) const {\n        return (0 <= R.a && R.a < R.c && R.c <= LIMIT_COORD && 0 <= R.b && R.b < R.d && R.d <= LIMIT_COORD);\n    }\n    bool pair_update_legal(int i, int j, const Rect& Ri, const Rect& Rj) const {\n        if (!insideBounds(Ri) || !insideBounds(Rj)) return false;\n        if (!containsSeed(Ri, x[i], y[i]) || !containsSeed(Rj, x[j], y[j])) return false;\n        if (overlapStrict(Ri, Rj)) return false;\n        for (int k = 0; k < n; ++k) if (k != i && k != j) {\n            const Rect &Rk = rects[k];\n            if (overlapStrict(Ri, Rk) || overlapStrict(Rj, Rk)) return false;\n        }\n        return true;\n    }\n    bool single_update_legal(int i, const Rect& Ri) const {\n        if (!insideBounds(Ri)) return false;\n        if (!containsSeed(Ri, x[i], y[i])) return false;\n        for (int k = 0; k < n; ++k) if (k != i) if (overlapStrict(Ri, rects[k])) return false;\n        return true;\n    }\n\n    inline void best_slide_hillclimb(const Rect &L, const Rect &R, bool vertical, int idxL, int idxR, int &bestT, double &bestVal) const {\n        ll sL0 = (ll)(L.c - L.a) * (ll)(L.d - L.b), sR0 = (ll)(R.c - R.a) * (ll)(R.d - R.b);\n        int unit = vertical ? (L.d - L.b) : (L.c - L.a);\n        double base = score_si_ri(sL0, r[idxL]) + score_si_ri(sR0, r[idxR]);\n        if (unit <= 0) { bestT = 0; bestVal = base; return; }\n        int tmin, tmax;\n        if (vertical) { tmin = (x[idxL] + 1) - L.c; tmax = x[idxR] - R.a; }\n        else { tmin = (y[idxL] + 1) - L.d; tmax = y[idxR] - R.b; }\n        if (tmin > tmax) { bestT = 0; bestVal = base; return; }\n        auto valAt = [&](int t)->double{\n            ll sL = sL0 + (ll)unit * (ll)t, sR = sR0 - (ll)unit * (ll)t;\n            return score_si_ri(sL, r[idxL]) + score_si_ri(sR, r[idxR]);\n        };\n        int t = 0; double cur = valAt(0);\n        while (true) {\n            double vp = -1e-100, vm = -1e-100;\n            if (t < tmax) vp = valAt(t + 1);\n            if (t > tmin) vm = valAt(t - 1);\n            if (vp <= cur + 1e-15 && vm <= cur + 1e-15) break;\n            if (vp >= vm) { t += 1; cur = vp; } else { t -= 1; cur = vm; }\n        }\n        bestT = t; bestVal = cur;\n    }\n\n    bool slide_pairs_pass() {\n        vector<PairItem> pairs; build_fullside_pairs(pairs);\n        if (pairs.empty()) return false;\n        shuffle(pairs.begin(), pairs.end(), rng);\n        bool any = false;\n        for (const auto &pi : pairs) {\n            int i = pi.i, j = pi.j;\n            const Rect &ri = rects[i], &rj = rects[j];\n            double base = score_i(i) + score_i(j);\n            int bestT = 0; double bestVal = base;\n            best_slide_hillclimb(ri, rj, pi.vertical, i, j, bestT, bestVal);\n            if (bestVal > base + 1e-12 && bestT != 0) {\n                if (pi.vertical) { rects[i].c += bestT; rects[j].a += bestT; }\n                else { rects[i].d += bestT; rects[j].b += bestT; }\n                any = true;\n            }\n            if (timer.elapsed() > time_limit * 0.95) break;\n        }\n        return any;\n    }\n\n    inline int choose_B_for_H(int H, int BminC, int BmaxC, int DminC, int DmaxC, int yi, int yj) const {\n        int Blo = max(BminC, DminC - H), Bhi = min(BmaxC, DmaxC - H);\n        long long ycenter = ((long long)yi + (long long)yj + 1 - H) / 2;\n        return (int)clampv(ycenter, (long long)Blo, (long long)Bhi);\n    }\n    inline int choose_A_for_W(int W, int AminC, int AmaxC, int CminC, int CmaxC, int xi, int xj) const {\n        int Alo = max(AminC, CminC - W), Ahi = min(AmaxC, CmaxC - W);\n        long long xcenter = ((long long)xi + (long long)xj + 1 - W) / 2;\n        return (int)clampv(xcenter, (long long)Alo, (long long)Ahi);\n    }\n\n    bool align_general_pairs_pass() {\n        bool anyImproved = false;\n\n        // Vertical touching pairs\n        for (int i = 0; i < n; ++i) {\n            if (timer.elapsed() > time_limit * 0.92) break;\n            for (int j = i + 1; j < n; ++j) {\n                int idxL = -1, idxR = -1;\n                if (rects[i].c == rects[j].a) { idxL = i; idxR = j; }\n                else if (rects[j].c == rects[i].a) { idxL = j; idxR = i; }\n                else continue;\n                const Rect &Li = rects[idxL], &Rj = rects[idxR];\n                int lL, rL, dL, uL, lR, rR, dR, uR;\n                compute_allowed_expansions(idxL, lL, rL, dL, uL);\n                compute_allowed_expansions(idxR, lR, rR, dR, uR);\n\n                int bminL = Li.b - dL, bmaxL = y[idxL], dminL = y[idxL] + 1, dmaxL = Li.d + uL;\n                int bminR = Rj.b - dR, bmaxR = y[idxR], dminR = y[idxR] + 1, dmaxR = Rj.d + uR;\n                int BminC = max(bminL, bminR), BmaxC = min(bmaxL, bmaxR);\n                int DminC = max(dminL, dminR), DmaxC = min(dmaxL, dmaxR);\n\n                int Hmin = max(1, DminC - BmaxC), Hmax = DmaxC - BminC;\n                if (Hmin > Hmax) continue;\n\n                int wL = Li.c - Li.a, wR = Rj.c - Rj.a;\n                double base = score_i(idxL) + score_i(idxR);\n\n                vector<int> candH;\n                auto pushH = [&](long long H) {\n                    if (H < Hmin) H = Hmin; if (H > Hmax) H = Hmax;\n                    int h = (int)H; for (int v : candH) if (v == h) return; candH.push_back(h);\n                };\n                candH.reserve(14);\n                pushH(Hmin); pushH(Hmax);\n                pushH(Li.d - Li.b); pushH(Li.d - Li.b - 1); pushH(Li.d - Li.b + 1);\n                pushH(Rj.d - Rj.b); pushH(Rj.d - Rj.b - 1); pushH(Rj.d - Rj.b + 1);\n                if (wL > 0) { long long t = r[idxL] / max(1, wL); pushH(t); pushH(t-1); pushH(t+1); }\n                if (wR > 0) { long long t = r[idxR] / max(1, wR); pushH(t); pushH(t-1); pushH(t+1); }\n\n                double bestVal = base; int bestH = 0, bestT = 0, bestB = 0;\n                for (int H : candH) {\n                    int Blo = max(BminC, DminC - H), Bhi = min(BmaxC, DmaxC - H);\n                    if (Blo > Bhi) continue;\n                    int B = choose_B_for_H(H, BminC, BmaxC, DminC, DmaxC, y[idxL], y[idxR]);\n                    for (int trial = 0; trial < 3; ++trial) {\n                        int BB = (trial == 0 ? B : trial == 1 ? Blo : Bhi);\n                        Rect L2 = Li, R2 = Rj;\n                        L2.b = BB; L2.d = BB + H; R2.b = BB; R2.d = BB + H;\n                        if (!pair_update_legal(idxL, idxR, L2, R2)) continue;\n                        int tbest = 0; double valBestSlide;\n                        best_slide_hillclimb(L2, R2, true, idxL, idxR, tbest, valBestSlide);\n                        if (valBestSlide > bestVal + 1e-12) { bestVal = valBestSlide; bestH = H; bestT = tbest; bestB = BB; }\n                    }\n                }\n                if (bestVal > base + 1e-12) {\n                    rects[idxL].b = bestB; rects[idxL].d = bestB + bestH;\n                    rects[idxR].b = bestB; rects[idxR].d = bestB + bestH;\n                    rects[idxL].c += bestT; rects[idxR].a += bestT; anyImproved = true;\n                }\n            }\n        }\n\n        // Horizontal touching pairs\n        for (int i = 0; i < n; ++i) {\n            if (timer.elapsed() > time_limit * 0.94) break;\n            for (int j = i + 1; j < n; ++j) {\n                int idxB = -1, idxT = -1;\n                if (rects[i].d == rects[j].b) { idxB = i; idxT = j; }\n                else if (rects[j].d == rects[i].b) { idxB = j; idxT = i; }\n                else continue;\n                const Rect &Bi = rects[idxB], &Tj = rects[idxT];\n                int lB, rB, dB, uB, lT, rT, dT, uT;\n                compute_allowed_expansions(idxB, lB, rB, dB, uB);\n                compute_allowed_expansions(idxT, lT, rT, dT, uT);\n\n                int a_min_B = Bi.a - lB, a_max_B = x[idxB], c_min_B = x[idxB] + 1, c_max_B = Bi.c + rB;\n                int a_min_T = Tj.a - lT, a_max_T = x[idxT], c_min_T = x[idxT] + 1, c_max_T = Tj.c + rT;\n\n                int AminC = max(a_min_B, a_min_T), AmaxC = min(a_max_B, a_max_T);\n                int CminC = max(c_min_B, c_min_T), CmaxC = min(c_max_B, c_max_T);\n\n                int Wmin = max(1, CminC - AmaxC), Wmax = CmaxC - AminC;\n                if (Wmin > Wmax) continue;\n\n                int hB = Bi.d - Bi.b, hT = Tj.d - Tj.b;\n                double base = score_i(idxB) + score_i(idxT);\n\n                vector<int> candW;\n                auto pushW = [&](long long W) { if (W < Wmin) W = Wmin; if (W > Wmax) W = Wmax;\n                    int w = (int)W; for (int v : candW) if (v == w) return; candW.push_back(w); };\n                candW.reserve(14);\n                pushW(Wmin); pushW(Wmax);\n                pushW(Bi.c - Bi.a); pushW(Bi.c - Bi.a - 1); pushW(Bi.c - Bi.a + 1);\n                pushW(Tj.c - Tj.a); pushW(Tj.c - Tj.a - 1); pushW(Tj.c - Tj.a + 1);\n                if (hB > 0) { long long t = r[idxB] / max(1, hB); pushW(t); pushW(t-1); pushW(t+1); }\n                if (hT > 0) { long long t = r[idxT] / max(1, hT); pushW(t); pushW(t-1); pushW(t+1); }\n\n                double bestVal = base; int bestW = 0, bestT = 0, bestA = 0;\n                for (int W : candW) {\n                    int Alo = max(AminC, CminC - W), Ahi = min(AmaxC, CmaxC - W);\n                    if (Alo > Ahi) continue;\n                    int A = choose_A_for_W(W, AminC, AmaxC, CminC, CmaxC, x[idxB], x[idxT]);\n                    for (int trial = 0; trial < 3; ++trial) {\n                        int AA = (trial == 0 ? A : trial == 1 ? Alo : Ahi);\n                        Rect B2 = Bi, T2 = Tj;\n                        B2.a = AA; B2.c = AA + W; T2.a = AA; T2.c = AA + W;\n                        if (!pair_update_legal(idxB, idxT, B2, T2)) continue;\n                        int tbest = 0; double valBestSlide;\n                        best_slide_hillclimb(B2, T2, false, idxB, idxT, tbest, valBestSlide);\n                        if (valBestSlide > bestVal + 1e-12) { bestVal = valBestSlide; bestW = W; bestT = tbest; bestA = AA; }\n                    }\n                }\n                if (bestVal > base + 1e-12) {\n                    rects[idxB].a = bestA; rects[idxB].c = bestA + bestW;\n                    rects[idxT].a = bestA; rects[idxT].c = bestA + bestW;\n                    rects[idxB].d += bestT; rects[idxT].b += bestT; anyImproved = true;\n                }\n            }\n        }\n        return anyImproved;\n    }\n\n    bool shift_horizontal_center(int i) {\n        const Rect &ri = rects[i]; int w = ri.c - ri.a; if (w <= 0) return false;\n        int Alo = 0, Ahi = LIMIT_COORD - w;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect &rj = rects[j];\n            if (!(ri.d <= rj.b || rj.d <= ri.b)) {\n                if (rj.c <= ri.a) Alo = max(Alo, rj.c);\n                else if (rj.a >= ri.c) Ahi = min(Ahi, rj.a - w);\n            }\n        }\n        Alo = max(Alo, x[i] - (w - 1)); Ahi = min(Ahi, x[i]); if (Alo > Ahi) return false;\n        int a_new = clampv(x[i] - (w - 1) / 2, Alo, Ahi); if (a_new == ri.a) return false;\n        Rect Rn = ri; Rn.a = a_new; Rn.c = a_new + w; if (!single_update_legal(i, Rn)) return false; rects[i] = Rn; return true;\n    }\n    bool shift_horizontal_pack(int i) {\n        const Rect &ri = rects[i]; int w = ri.c - ri.a; if (w <= 0) return false;\n        int Alo = 0, Ahi = LIMIT_COORD - w;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect &rj = rects[j];\n            if (!(ri.d <= rj.b || rj.d <= ri.b)) {\n                if (rj.c <= ri.a) Alo = max(Alo, rj.c);\n                else if (rj.a >= ri.c) Ahi = min(Ahi, rj.a - w);\n            }\n        }\n        Alo = max(Alo, x[i] - (w - 1)); Ahi = min(Ahi, x[i]); if (Alo > Ahi) return false;\n        int moveR = Ahi - ri.a, moveL = ri.a - Alo; int a_new = (moveR > moveL) ? Ahi : Alo; if (a_new == ri.a) return false;\n        Rect Rn = ri; Rn.a = a_new; Rn.c = a_new + w; if (!single_update_legal(i, Rn)) return false; rects[i] = Rn; return true;\n    }\n    bool shift_vertical_center(int i) {\n        const Rect &ri = rects[i]; int h = ri.d - ri.b; if (h <= 0) return false;\n        int Blo = 0, Bhi = LIMIT_COORD - h;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect &rj = rects[j];\n            if (!(ri.c <= rj.a || rj.c <= ri.a)) {\n                if (rj.d <= ri.b) Blo = max(Blo, rj.d);\n                else if (rj.b >= ri.d) Bhi = min(Bhi, rj.b - h);\n            }\n        }\n        Blo = max(Blo, y[i] - (h - 1)); Bhi = min(Bhi, y[i]); if (Blo > Bhi) return false;\n        int b_new = clampv(y[i] - (h - 1) / 2, Blo, Bhi); if (b_new == ri.b) return false;\n        Rect Rn = ri; Rn.b = b_new; Rn.d = b_new + h; if (!single_update_legal(i, Rn)) return false; rects[i] = Rn; return true;\n    }\n    bool shift_vertical_pack(int i) {\n        const Rect &ri = rects[i]; int h = ri.d - ri.b; if (h <= 0) return false;\n        int Blo = 0, Bhi = LIMIT_COORD - h;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect &rj = rects[j];\n            if (!(ri.c <= rj.a || rj.c <= ri.a)) {\n                if (rj.d <= ri.b) Blo = max(Blo, rj.d);\n                else if (rj.b >= ri.d) Bhi = min(Bhi, rj.b - h);\n            }\n        }\n        Blo = max(Blo, y[i] - (h - 1)); Bhi = min(Bhi, y[i]); if (Blo > Bhi) return false;\n        int moveU = Bhi - ri.b, moveD = ri.b - Blo; int b_new = (moveU > moveD) ? Bhi : Blo; if (b_new == ri.b) return false;\n        Rect Rn = ri; Rn.b = b_new; Rn.d = b_new + h; if (!single_update_legal(i, Rn)) return false; rects[i] = Rn; return true;\n    }\n    bool shift_pass(bool packMode) {\n        vector<int> idx(n); iota(idx.begin(), idx.end(), 0); shuffle(idx.begin(), idx.end(), rng);\n        bool changed = false;\n        for (int k = 0; k < n; ++k) {\n            if ((k % 16 == 0) && timer.elapsed() > time_limit) break;\n            int i = idx[k];\n            bool ch = false;\n            if (packMode) { ch |= shift_horizontal_pack(i); ch |= shift_vertical_pack(i); }\n            else { ch |= shift_horizontal_center(i); ch |= shift_vertical_center(i); }\n            changed |= ch;\n        }\n        return changed;\n    }\n\n    void expand_pass_random() {\n        vector<int> idx(n); iota(idx.begin(), idx.end(), 0); shuffle(idx.begin(), idx.end(), rng);\n        for (int k = 0; k < n; ++k) { if ((k & 31) == 0 && timer.elapsed() > time_limit) return; adjust_one(idx[k]); }\n    }\n    void expand_pass_descR(const vector<int>& order) {\n        for (int id : order) { if (timer.elapsed() > time_limit) return; adjust_one(id); }\n    }\n\n    // New: gradient-priority ordering for expand pass\n    bool expand_pass_by_gap() {\n        struct Item { double pr; int idx; };\n        vector<Item> items; items.reserve(n);\n        for (int i = 0; i < n; ++i) {\n            ll s = area_of(rects[i]);\n            int w = rects[i].c - rects[i].a, h = rects[i].d - rects[i].b;\n            int lM, rM, dM, uM; compute_allowed_expansions(i, lM, rM, dM, uM);\n            double bestUnit = 0.0;\n            if (lM + rM > 0) bestUnit = max(bestUnit, (double)h);\n            if (dM + uM > 0) bestUnit = max(bestUnit, (double)w);\n            double dpabs = 0.0;\n            if (s < r[i]) {\n                dpabs = 2.0 * (double)(r[i] - s) / ((double)r[i] * (double)r[i]);\n            } else if (s > r[i]) {\n                double u = (double)r[i] / (double)s;\n                dpabs = 2.0 * u * (1.0 - u) / (double)s;\n            }\n            double pri = bestUnit * dpabs;\n            items.push_back({pri, i});\n        }\n        sort(items.begin(), items.end(), [&](const Item& A, const Item& B){\n            if (A.pr != B.pr) return A.pr > B.pr;\n            return A.idx < B.idx;\n        });\n        bool changed = false;\n        for (int k = 0; k < n; ++k) {\n            if ((k & 31) == 0 && timer.elapsed() > time_limit) break;\n            changed |= adjust_one(items[k].idx);\n        }\n        return changed;\n    }\n\n    // PAVA with bounds for Q = P - k (nondecreasing)\n    void pava_with_bounds(const vector<double>& T, const vector<double>& L, const vector<double>& U, vector<double>& Q) const {\n        struct Block { int l, r; double sumy; int w; double L, U, v; };\n        vector<Block> st;\n        int K = (int)T.size();\n        for (int i = 0; i < K; ++i) {\n            Block b{ i, i, T[i], 1, L[i], U[i], 0.0 };\n            b.v = min(max(b.sumy / b.w, b.L), b.U);\n            st.push_back(b);\n            while (st.size() >= 2) {\n                auto &b2 = st.back(); auto b1 = st[st.size()-2];\n                if (b1.v <= b2.v + 1e-12) break;\n                Block nb;\n                nb.l = b1.l; nb.r = b2.r;\n                nb.sumy = b1.sumy + b2.sumy; nb.w = b1.w + b2.w;\n                nb.L = max(b1.L, b2.L); nb.U = min(b1.U, b2.U);\n                nb.v = min(max(nb.sumy / nb.w, nb.L), nb.U);\n                st.pop_back(); st.pop_back(); st.push_back(nb);\n            }\n        }\n        Q.assign(K, 0.0);\n        for (auto &b : st) for (int i = b.l; i <= b.r; ++i) Q[i] = b.v;\n    }\n    bool round_prefix_integers(const vector<double>& Q, const vector<int>& L, const vector<int>& U, vector<int>& Pint) const {\n        int K = (int)Q.size(); Pint.assign(K, 0);\n        for (int k = 0; k < K; ++k) {\n            long long rr = llround(Q[k]);\n            Pint[k] = (int)clampv(rr, (long long)L[k], (long long)U[k]);\n        }\n        int k = 0;\n        while (k < K) {\n            if (k > 0 && Pint[k] < Pint[k-1]) {\n                if (Pint[k-1] <= U[k]) { Pint[k] = Pint[k-1]; k++; }\n                else {\n                    int t = k - 1;\n                    Pint[t] = U[k];\n                    while (t > 0 && Pint[t] < Pint[t-1]) { Pint[t-1] = Pint[t]; t--; }\n                    for (int j = 0; j <= k; ++j) Pint[j] = max(Pint[j], L[j]);\n                    k = 0;\n                }\n            } else {\n                Pint[k] = max(Pint[k], (k > 0 ? Pint[k-1] : Pint[k]));\n                if (Pint[k] > U[k]) {\n                    int t = k;\n                    Pint[t] = U[t];\n                    while (t > 0 && Pint[t] < Pint[t-1]) { Pint[t-1] = Pint[t]; t--; }\n                    for (int j = 0; j <= k; ++j) Pint[j] = max(Pint[j], L[j]);\n                    k = 0;\n                } else k++;\n            }\n        }\n        for (int i = 0; i < K; ++i) {\n            if (Pint[i] < L[i] || Pint[i] > U[i]) return false;\n            if (i > 0 && Pint[i] < Pint[i-1]) return false;\n        }\n        return true;\n    }\n\n    inline double vert_score_from_w(int idxRect, int w, int H) const {\n        return score_si_ri((ll)w * (ll)H, r[idxRect]);\n    }\n    inline double horiz_score_from_h(int idxRect, int h, int W) const {\n        return score_si_ri((ll)h * (ll)W, r[idxRect]);\n    }\n\n    void refine_vertical_chain(const vector<int>& idx, int H, int W, vector<int>& Pints, const vector<int>& Lower, const vector<int>& Upper) {\n        int m = (int)idx.size();\n        if (m < 2) return;\n        vector<int> w(m);\n        for (int k = 0; k <= m - 2; ++k) w[k] = Pints[k+1] - Pints[k];\n        w[m-1] = W - Pints[m-1];\n        vector<double> sc(m);\n        for (int k = 0; k < m; ++k) sc[k] = vert_score_from_w(idx[k], w[k], H);\n\n        int iter = 0;\n        while (true) {\n            if (++iter > 2000 || timer.elapsed() > time_limit * 0.99) break;\n            double bestDelta = 1e-12;\n            int bestK = -1, bestDir = 0;\n            for (int k = 1; k <= m - 1; ++k) {\n                if (Pints[k] < Upper[k] && w[k] >= 2) {\n                    double d = vert_score_from_w(idx[k-1], w[k-1] + 1, H) - sc[k-1]\n                             + vert_score_from_w(idx[k],     w[k]     - 1, H) - sc[k];\n                    if (d > bestDelta) { bestDelta = d; bestK = k; bestDir = +1; }\n                }\n                if (Pints[k] > Lower[k] && w[k-1] >= 2) {\n                    double d = vert_score_from_w(idx[k-1], w[k-1] - 1, H) - sc[k-1]\n                             + vert_score_from_w(idx[k],     w[k]     + 1, H) - sc[k];\n                    if (d > bestDelta) { bestDelta = d; bestK = k; bestDir = -1; }\n                }\n            }\n            if (bestK < 0) break;\n            Pints[bestK] += bestDir;\n            if (bestDir == +1) { w[bestK-1]++; w[bestK]--; }\n            else { w[bestK-1]--; w[bestK]++; }\n            sc[bestK-1] = vert_score_from_w(idx[bestK-1], w[bestK-1], H);\n            sc[bestK]   = vert_score_from_w(idx[bestK],   w[bestK],   H);\n        }\n    }\n\n    void refine_horizontal_chain(const vector<int>& idx, int W, int Htot, vector<int>& Pints, const vector<int>& Lower, const vector<int>& Upper) {\n        int m = (int)idx.size();\n        if (m < 2) return;\n        vector<int> h(m);\n        for (int k = 0; k <= m - 2; ++k) h[k] = Pints[k+1] - Pints[k];\n        h[m-1] = Htot - Pints[m-1];\n        vector<double> sc(m);\n        for (int k = 0; k < m; ++k) sc[k] = horiz_score_from_h(idx[k], h[k], W);\n\n        int iter = 0;\n        while (true) {\n            if (++iter > 2000 || timer.elapsed() > time_limit * 0.99) break;\n            double bestDelta = 1e-12;\n            int bestK = -1, bestDir = 0;\n            for (int k = 1; k <= m - 1; ++k) {\n                if (Pints[k] < Upper[k] && h[k] >= 2) {\n                    double d = horiz_score_from_h(idx[k-1], h[k-1] + 1, W) - sc[k-1]\n                             + horiz_score_from_h(idx[k],     h[k]     - 1, W) - sc[k];\n                    if (d > bestDelta) { bestDelta = d; bestK = k; bestDir = +1; }\n                }\n                if (Pints[k] > Lower[k] && h[k-1] >= 2) {\n                    double d = horiz_score_from_h(idx[k-1], h[k-1] - 1, W) - sc[k-1]\n                             + horiz_score_from_h(idx[k],     h[k]     + 1, W) - sc[k];\n                    if (d > bestDelta) { bestDelta = d; bestK = k; bestDir = -1; }\n                }\n            }\n            if (bestK < 0) break;\n            Pints[bestK] += bestDir;\n            if (bestDir == +1) { h[bestK-1]++; h[bestK]--; }\n            else { h[bestK-1]--; h[bestK]++; }\n            sc[bestK-1] = horiz_score_from_h(idx[bestK-1], h[bestK-1], W);\n            sc[bestK]   = horiz_score_from_h(idx[bestK],   h[bestK],   W);\n        }\n    }\n\n    bool optimize_vertical_chain(const vector<int>& chain) {\n        int m = (int)chain.size(); if (m < 2) return false;\n        int Lx = rects[chain.front()].a, Rx = rects[chain.back()].c;\n        int H = rects[chain.front()].d - rects[chain.front()].b; if (H <= 0) return false;\n        int W = Rx - Lx; if (W < m) return false;\n\n        double base = 0.0; for (int id : chain) base += score_i(id);\n\n        vector<int> idx = chain;\n        vector<long long> Ptarget(m, 0);\n        double S = 0.0;\n        for (int k = 1; k <= m - 1; ++k) {\n            S += (double)r[idx[k-1]] / (double)H;\n            long long Pt = llround(S);\n            long long maxPt = (long long)W - (long long)(m - k);\n            if (Pt > maxPt) Pt = maxPt;\n            if (Pt < (long long)k) Pt = k;\n            Ptarget[k] = Pt;\n        }\n        vector<int> Lower(m, 0), Upper(m, 0);\n        for (int k = 1; k <= m - 1; ++k) {\n            int Lk = max(k, x[idx[k-1]] - Lx + 1);\n            int Uk = min(W - (m - k), x[idx[k]] - Lx);\n            Lk = clampv(Lk, 0, W); Uk = clampv(Uk, 0, W);\n            if (Lk > Uk) return false;\n            Lower[k] = Lk; Upper[k] = Uk;\n        }\n        vector<double> T(m-1), Lb(m-1), Ub(m-1);\n        for (int k = 1; k <= m - 1; ++k) {\n            T[k-1] = (double)Ptarget[k] - (double)k;\n            Lb[k-1] = (double)Lower[k] - (double)k;\n            Ub[k-1] = (double)Upper[k] - (double)k;\n            if (Lb[k-1] > Ub[k-1]) return false;\n        }\n        vector<double> Q; pava_with_bounds(T, Lb, Ub, Q);\n\n        vector<int> Qint; vector<int> Lqi(m-1), Uqi(m-1);\n        for (int k = 1; k <= m - 1; ++k) { Lqi[k-1] = Lower[k] - k; Uqi[k-1] = Upper[k] - k; }\n        if (!round_prefix_integers(Q, Lqi, Uqi, Qint)) return false;\n        vector<int> Pints(m, 0); for (int k = 1; k <= m - 1; ++k) Pints[k] = Qint[k-1] + k;\n\n        refine_vertical_chain(idx, H, W, Pints, Lower, Upper);\n\n        vector<int> newW(m);\n        for (int k = 0; k <= m - 2; ++k) newW[k] = Pints[k+1] - Pints[k];\n        newW[m-1] = W - Pints[m-1];\n        for (int ww : newW) if (ww < 1) return false;\n\n        vector<Rect> newRects(m);\n        int curx = Lx; for (int k = 0; k < m; ++k) {\n            int id = idx[k]; Rect nr = rects[id]; nr.a = curx; nr.c = curx + newW[k]; curx = nr.c;\n            if (!(nr.a <= x[id] && x[id] < nr.c)) return false; newRects[k] = nr;\n        }\n        double after = 0.0; for (int k = 0; k < m; ++k) after += score_si_ri((ll)newW[k] * (ll)H, r[idx[k]]);\n        if (after > base + 1e-12) { for (int k = 0; k < m; ++k) rects[idx[k]] = newRects[k]; return true; }\n        return false;\n    }\n\n    bool optimize_vertical_chains() {\n        vector<int> ids(n); iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int i, int j){\n            const Rect &A = rects[i], &B = rects[j];\n            if (A.b != B.b) return A.b < B.b;\n            if (A.d != B.d) return A.d < B.d;\n            return A.a < B.a;\n        });\n        bool any = false; int i = 0;\n        while (i < n) {\n            if (timer.elapsed() > time_limit * 0.98) break;\n            int j = i; while (j < n && rects[ids[j]].b == rects[ids[i]].b && rects[ids[j]].d == rects[ids[i]].d) j++;\n            int k = i;\n            while (k < j) {\n                vector<int> chain; chain.push_back(ids[k]);\n                int t = k + 1;\n                while (t < j && rects[ids[t-1]].c == rects[ids[t]].a) { chain.push_back(ids[t]); t++; }\n                if ((int)chain.size() >= 2) { if (optimize_vertical_chain(chain)) any = true; }\n                k = t;\n            }\n            i = j;\n        }\n        return any;\n    }\n\n    bool optimize_horizontal_chain(const vector<int>& chain) {\n        int m = (int)chain.size(); if (m < 2) return false;\n        int By = rects[chain.front()].b, Ty = rects[chain.back()].d;\n        int W = rects[chain.front()].c - rects[chain.front()].a; if (W <= 0) return false;\n        int Htot = Ty - By; if (Htot < m) return false;\n\n        double base = 0.0; for (int id : chain) base += score_i(id);\n\n        vector<int> idx = chain;\n        vector<long long> Ptarget(m, 0);\n        double S = 0.0;\n        for (int k = 1; k <= m - 1; ++k) {\n            S += (double)r[idx[k-1]] / (double)W;\n            long long Pt = llround(S);\n            long long maxPt = (long long)Htot - (long long)(m - k);\n            if (Pt > maxPt) Pt = maxPt;\n            if (Pt < (long long)k) Pt = k;\n            Ptarget[k] = Pt;\n        }\n        vector<int> Lower(m, 0), Upper(m, 0);\n        for (int k = 1; k <= m - 1; ++k) {\n            int Lk = max(k, y[idx[k-1]] - By + 1);\n            int Uk = min(Htot - (m - k), y[idx[k]] - By);\n            Lk = clampv(Lk, 0, Htot); Uk = clampv(Uk, 0, Htot);\n            if (Lk > Uk) return false;\n            Lower[k] = Lk; Upper[k] = Uk;\n        }\n        vector<double> T(m-1), Lb(m-1), Ub(m-1);\n        for (int k = 1; k <= m - 1; ++k) {\n            T[k-1] = (double)Ptarget[k] - (double)k;\n            Lb[k-1] = (double)Lower[k] - (double)k;\n            Ub[k-1] = (double)Upper[k] - (double)k;\n            if (Lb[k-1] > Ub[k-1]) return false;\n        }\n        vector<double> Q; pava_with_bounds(T, Lb, Ub, Q);\n        vector<int> Qint; vector<int> Lqi(m-1), Uqi(m-1); for (int k = 1; k <= m - 1; ++k) { Lqi[k-1] = Lower[k] - k; Uqi[k-1] = Upper[k] - k; }\n        if (!round_prefix_integers(Q, Lqi, Uqi, Qint)) return false;\n        vector<int> Pints(m, 0); for (int k = 1; k <= m - 1; ++k) Pints[k] = Qint[k-1] + k;\n\n        refine_horizontal_chain(idx, W, Htot, Pints, Lower, Upper);\n\n        vector<int> newH(m);\n        for (int k = 0; k <= m - 2; ++k) newH[k] = Pints[k+1] - Pints[k];\n        newH[m-1] = Htot - Pints[m-1];\n        for (int hh : newH) if (hh < 1) return false;\n\n        vector<Rect> newRects(m);\n        int cury = By; for (int k = 0; k < m; ++k) {\n            int id = idx[k]; Rect nr = rects[id]; nr.b = cury; nr.d = cury + newH[k]; cury = nr.d;\n            if (!(nr.b <= y[id] && y[id] < nr.d)) return false; newRects[k] = nr;\n        }\n        double after = 0.0; for (int k = 0; k < m; ++k) after += score_si_ri((ll)newH[k] * (ll)W, r[idx[k]]);\n        if (after > base + 1e-12) { for (int k = 0; k < m; ++k) rects[idx[k]] = newRects[k]; return true; }\n        return false;\n    }\n\n    bool optimize_horizontal_chains() {\n        vector<int> ids(n); iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int i, int j){\n            const Rect &A = rects[i], &B = rects[j];\n            if (A.a != B.a) return A.a < B.a;\n            if (A.c != B.c) return A.c < B.c;\n            return A.b < B.b;\n        });\n        bool any = false; int i = 0;\n        while (i < n) {\n            if (timer.elapsed() > time_limit * 0.99) break;\n            int j = i; while (j < n && rects[ids[j]].a == rects[ids[i]].a && rects[ids[j]].c == rects[ids[i]].c) j++;\n            int k = i;\n            while (k < j) {\n                vector<int> chain; chain.push_back(ids[k]);\n                int t = k + 1;\n                while (t < j && rects[ids[t-1]].d == rects[ids[t]].b) { chain.push_back(ids[t]); t++; }\n                if ((int)chain.size() >= 2) { if (optimize_horizontal_chain(chain)) any = true; }\n                k = t;\n            }\n            i = j;\n        }\n        return any;\n    }\n\n    void solve() {\n        initial_setup();\n\n        vector<int> order(n); iota(order.begin(), order.end(), 0);\n        stable_sort(order.begin(), order.end(), [&](int a, int b){ return r[a] > r[b]; });\n\n        double t1 = time_limit * 0.26;\n        while (timer.elapsed() < t1) { expand_pass_descR(order); expand_pass_random(); }\n        expand_pass_by_gap();\n\n        double t_center = time_limit * 0.34;\n        while (timer.elapsed() < t_center) { bool ch = shift_pass(false); if (!ch) break; }\n\n        double t_align1 = time_limit * 0.58;\n        while (timer.elapsed() < t_align1) { bool imp = align_general_pairs_pass(); if (!imp) break; }\n\n        double t2 = time_limit * 0.78;\n        while (timer.elapsed() < t2) { bool improved = slide_pairs_pass(); if (!improved) break; }\n\n        optimize_vertical_chains();\n        optimize_horizontal_chains();\n\n        double t_align2 = time_limit * 0.88;\n        while (timer.elapsed() < t_align2) { bool imp = align_general_pairs_pass(); if (!imp) break; }\n\n        double t_pack = time_limit * 0.93;\n        while (timer.elapsed() < t_pack) { bool ch = shift_pass(true); if (!ch) break; }\n\n        double t_slide2 = time_limit * 0.97;\n        while (timer.elapsed() < t_slide2) { bool improved = slide_pairs_pass(); if (!improved) break; }\n\n        optimize_vertical_chains();\n        optimize_horizontal_chains();\n\n        while (timer.elapsed() < time_limit) {\n            bool ch1 = expand_pass_by_gap();\n            if (timer.elapsed() > time_limit) break;\n            bool ch2 = slide_pairs_pass();\n            if (timer.elapsed() > time_limit) break;\n            bool ch3 = optimize_vertical_chains();\n            if (timer.elapsed() > time_limit) break;\n            bool ch4 = optimize_horizontal_chains();\n            if (!(ch1 || ch2 || ch3 || ch4)) break;\n        }\n    }\n\n    void output() const {\n        for (int i = 0; i < n; ++i) {\n            const Rect &rc = rects[i];\n            cout << rc.a << ' ' << rc.b << ' ' << rc.c << ' ' << rc.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int n; if (!(cin >> n)) return 0;\n    vector<int> x(n), y(n), r(n);\n    for (int i = 0; i < n; ++i) cin >> x[i] >> y[i] >> r[i];\n    Solver solver(n, x, y, r, 4.85);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Fast RNG (xorshift)\nstruct XorShift64 {\n    uint64_t x;\n    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    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int randint(int l, int r) { // inclusive l..r\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Params {\n    double wP;        // weight for immediate p\n    double wDeg;      // weight for degree of next cell\n    double wPot;      // weight for precomputed potential\n    double wTwinPot;  // penalty weight for twin potential\n    double wTwinDeg;  // penalty weight for twin degree\n    double wLook;     // weight for 2-ply lookahead\n    double noise;     // random noise amplitude\n    int avoidDeadMinLen; // avoid moving into dead-end before this many steps if alternatives exist\n};\n\nstruct PathResult {\n    long long score;\n    string moves;\n    int lengthTiles; // number of tiles visited\n};\n\nstatic const int H = 50, W = 50, N = H * W;\n\ninline int id_of(int i, int j) { return i * W + j; }\n\ninline char direction_char(int u, int v) {\n    int ui = u / W, uj = u % W;\n    int vi = v / W, vj = v % W;\n    if (vi == ui - 1 && vj == uj) return 'U';\n    if (vi == ui + 1 && vj == uj) return 'D';\n    if (vi == ui && vj == uj - 1) return 'L';\n    if (vi == ui && vj == uj + 1) return 'R';\n    return 'U';\n}\n\ninline int move_to(int pos, char c) {\n    int i = pos / W, j = pos % W;\n    if (c == 'U') { if (i == 0) return -1; return id_of(i-1, j); }\n    if (c == 'D') { if (i == H-1) return -1; return id_of(i+1, j); }\n    if (c == 'L') { if (j == 0) return -1; return id_of(i, j-1); }\n    if (c == 'R') { if (j == W-1) return -1; return id_of(i, j+1); }\n    return -1;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto time_start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.95; // seconds\n\n    int si, sj;\n    if (!(cin >> si >> sj)) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    vector<int> tile(N), pval(N);\n    int maxTile = -1;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int t; cin >> t;\n            tile[id_of(i, j)] = t;\n            if (t > maxTile) maxTile = t;\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            int pv; cin >> pv;\n            pval[id_of(i, j)] = pv;\n        }\n    }\n\n    // Build tileCells and twin mapping\n    vector<vector<int>> tileCells(M);\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int id = id_of(i, j);\n            tileCells[tile[id]].push_back(id);\n        }\n    }\n    vector<int> twin(N, -1);\n    for (int t = 0; t < M; t++) {\n        if (tileCells[t].size() == 2) {\n            int a = tileCells[t][0];\n            int b = tileCells[t][1];\n            twin[a] = b;\n            twin[b] = a;\n        }\n    }\n\n    // Build neighbor list: edges only across different tiles\n    vector<vector<int>> NB(N);\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = id_of(i, j);\n            if (i-1 >= 0) { int v = id_of(i-1, j); if (tile[u] != tile[v]) NB[u].push_back(v); }\n            if (i+1 <  H) { int v = id_of(i+1, j); if (tile[u] != tile[v]) NB[u].push_back(v); }\n            if (j-1 >= 0) { int v = id_of(i, j-1); if (tile[u] != tile[v]) NB[u].push_back(v); }\n            if (j+1 <  W) { int v = id_of(i, j+1); if (tile[u] != tile[v]) NB[u].push_back(v); }\n        }\n    }\n\n    // Precompute static potentials: BFS to depth 3 on allowed graph, with decays for p\n    vector<double> pot(N, 0.0);\n    {\n        static const double w1 = 1.0, w2 = 0.6, w3 = 0.3;\n        vector<char> seen(N, 0);\n        vector<int> frontier, nextf;\n        frontier.reserve(64);\n        nextf.reserve(128);\n\n        for (int s = 0; s < N; s++) {\n            fill(seen.begin(), seen.end(), 0);\n            seen[s] = 1;\n            double sum = 0.0;\n\n            frontier.clear();\n            for (int v : NB[s]) if (!seen[v]) { seen[v] = 1; frontier.push_back(v); sum += w1 * pval[v]; }\n\n            // depth 2\n            nextf.clear();\n            for (int v : frontier) {\n                for (int u : NB[v]) if (!seen[u]) { seen[u] = 1; nextf.push_back(u); sum += w2 * pval[u]; }\n            }\n            // depth 3\n            frontier.swap(nextf);\n            nextf.clear();\n            for (int v : frontier) {\n                for (int u : NB[v]) if (!seen[u]) { seen[u] = 1; nextf.push_back(u); sum += w3 * pval[u]; }\n            }\n\n            pot[s] = sum;\n        }\n    }\n\n    // RNG seed from input to diversify per test\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)si + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    seed ^= (uint64_t)sj + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2);\n    XorShift64 rng(seed);\n\n    auto dynamicDeg = [&](int cell, const vector<char>& tileUsed, int extraTile1 = -1, int extraTile2 = -1) -> int {\n        int cnt = 0;\n        for (int w : NB[cell]) {\n            int tt = tile[w];\n            if (tileUsed[tt]) continue;\n            if (tt == extraTile1 || tt == extraTile2) continue;\n            cnt++;\n        }\n        return cnt;\n    };\n\n    // Direction char mapping is global function\n\n    // Parameter presets (with minor jitter in runs)\n    vector<Params> presets;\n    presets.push_back(Params{1.00, 1.50, 0.050, 0.040, 0.30, 0.40, 1.5, 500});\n    presets.push_back(Params{1.20, 0.80, 0.080, 0.050, 0.20, 0.50, 1.2, 300});\n    presets.push_back(Params{1.00, 1.00, 0.060, 0.040, 0.25, 0.35, 1.5, 700});\n    presets.push_back(Params{1.00, 0.80, 0.030, 0.020, 0.20, 0.60, 1.0, 400});\n    presets.push_back(Params{1.00, 0.50, 0.100, 0.070, 0.15, 0.60, 1.2, 800});\n    presets.push_back(Params{1.40, 0.60, 0.040, 0.030, 0.20, 0.30, 1.5, 200});\n    presets.push_back(Params{1.00, 1.20, 0.070, 0.060, 0.25, 0.45, 1.0, 600});\n\n    auto build_path = [&](const Params& baseParam) -> PathResult {\n        // Slight random variation per run\n        Params P = baseParam;\n        auto jitter = [&](double v, double f=0.15) {\n            double m = 1.0 + (rng.next_double() * 2.0 - 1.0) * f;\n            return v * m;\n        };\n        P.wP       = jitter(P.wP,       0.10);\n        P.wDeg     = jitter(P.wDeg,     0.20);\n        P.wPot     = jitter(P.wPot,     0.25);\n        P.wTwinPot = jitter(P.wTwinPot, 0.25);\n        P.wTwinDeg = jitter(P.wTwinDeg, 0.20);\n        P.wLook    = jitter(P.wLook,    0.25);\n        P.noise    = jitter(P.noise,    0.40);\n        int avoidLimit = P.avoidDeadMinLen;\n\n        vector<char> tileUsed(M, 0);\n        int start = id_of(si, sj);\n        tileUsed[tile[start]] = 1;\n\n        long long score = pval[start];\n        int pos = start;\n        string moves;\n        moves.reserve(2000);\n\n        // We'll build until stuck\n        for (int step = 0; ; step++) {\n            // List candidate neighbors whose tile not yet visited\n            vector<int> cand;\n            cand.reserve(4);\n            for (int v : NB[pos]) {\n                int t = tile[v];\n                if (!tileUsed[t]) cand.push_back(v);\n            }\n            if (cand.empty()) break;\n\n            // Precompute degAfter for candidates and check for any non-dead options\n            vector<int> degAfter(cand.size(), 0);\n            bool hasNonDead = false;\n            for (size_t i = 0; i < cand.size(); i++) {\n                degAfter[i] = dynamicDeg(cand[i], tileUsed);\n                if (degAfter[i] > 0) hasNonDead = true;\n            }\n\n            double bestVal = -1e100;\n            int bestV = -1;\n\n            for (size_t idx = 0; idx < cand.size(); idx++) {\n                int v = cand[idx];\n                if (step < avoidLimit && hasNonDead && degAfter[idx] == 0) {\n                    // avoid entering a dead end early if alternatives exist\n                    continue;\n                }\n                double val = 0.0;\n\n                // immediate gain and local features\n                val += P.wP * pval[v];\n                val += P.wPot * pot[v];\n\n                // degree after stepping into v (available next moves)\n                val += P.wDeg * degAfter[idx];\n\n                // penalty for blocking via twin\n                int tv = twin[v];\n                if (tv != -1) {\n                    // twin degree and potential (approximate loss)\n                    int dTwin = dynamicDeg(tv, tileUsed);\n                    val -= P.wTwinDeg * dTwin;\n                    val -= P.wTwinPot * pot[tv];\n                }\n\n                // 2-ply lookahead: best child of v\n                if (degAfter[idx] > 0 && P.wLook > 1e-9) {\n                    double best2 = -1e100;\n                    for (int w : NB[v]) {\n                        int tw = tile[w];\n                        if (tileUsed[tw]) continue;\n                        // deg after moving to w, with v's tile considered newly visited\n                        int deg2 = dynamicDeg(w, tileUsed, tile[v]);\n                        double val2 = 0.0;\n                        val2 += P.wP * pval[w];\n                        val2 += P.wPot * pot[w];\n                        val2 += P.wDeg * deg2;\n                        int t2 = twin[w];\n                        if (t2 != -1) {\n                            int dtwin2 = dynamicDeg(t2, tileUsed, tile[v]);\n                            val2 -= P.wTwinDeg * dtwin2;\n                            val2 -= P.wTwinPot * pot[t2];\n                        }\n                        if (val2 > best2) best2 = val2;\n                    }\n                    if (best2 > -1e90) val += P.wLook * best2;\n                }\n\n                // noise\n                val += (rng.next_double() * 2.0 - 1.0) * P.noise;\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestV = v;\n                }\n            }\n\n            if (bestV == -1) {\n                // If all candidates were dead-ends and we avoided them, but we must choose one; pick the best ignoring avoid\n                bestVal = -1e100;\n                for (int v : cand) {\n                    double val = P.wP * pval[v] + P.wPot * pot[v] + (rng.next_double() * 2.0 - 1.0) * P.noise;\n                    if (val > bestVal) bestVal = val, bestV = v;\n                }\n                if (bestV == -1) break;\n            }\n\n            // Take the move\n            tileUsed[tile[bestV]] = 1;\n            score += pval[bestV];\n            moves.push_back(direction_char(pos, bestV));\n            pos = bestV;\n        }\n\n        PathResult res;\n        res.score = score;\n        res.moves = moves;\n        res.lengthTiles = (int)moves.size() + 1;\n        return res;\n    };\n\n    auto build_path_with_forced = [&](const Params& baseParam, const string& forced) -> PathResult {\n        // Same as build_path, but apply a forced prefix path before greedy\n        Params P = baseParam;\n        auto jitter = [&](double v, double f=0.15) {\n            double m = 1.0 + (rng.next_double() * 2.0 - 1.0) * f;\n            return v * m;\n        };\n        P.wP       = jitter(P.wP,       0.10);\n        P.wDeg     = jitter(P.wDeg,     0.20);\n        P.wPot     = jitter(P.wPot,     0.25);\n        P.wTwinPot = jitter(P.wTwinPot, 0.25);\n        P.wTwinDeg = jitter(P.wTwinDeg, 0.20);\n        P.wLook    = jitter(P.wLook,    0.25);\n        P.noise    = jitter(P.noise,    0.40);\n        int avoidLimit = P.avoidDeadMinLen;\n\n        vector<char> tileUsed(M, 0);\n        int pos = id_of(si, sj);\n        tileUsed[tile[pos]] = 1;\n        long long score = pval[pos];\n        string moves;\n        moves.reserve(2048);\n\n        // Apply forced prefix\n        for (char c : forced) {\n            int npos = move_to(pos, c);\n            if (npos < 0) break;\n            if (tile[pos] == tile[npos]) break;\n            int tt = tile[npos];\n            if (tileUsed[tt]) break;\n            tileUsed[tt] = 1;\n            score += pval[npos];\n            moves.push_back(c);\n            pos = npos;\n        }\n\n        // Continue greedy\n        for (int step = (int)moves.size(); ; step++) {\n            vector<int> cand;\n            for (int v : NB[pos]) {\n                int t = tile[v];\n                if (!tileUsed[t]) cand.push_back(v);\n            }\n            if (cand.empty()) break;\n\n            vector<int> degAfter(cand.size(), 0);\n            bool hasNonDead = false;\n            for (size_t i = 0; i < cand.size(); i++) {\n                degAfter[i] = dynamicDeg(cand[i], tileUsed);\n                if (degAfter[i] > 0) hasNonDead = true;\n            }\n\n            double bestVal = -1e100;\n            int bestV = -1;\n            for (size_t idx = 0; idx < cand.size(); idx++) {\n                int v = cand[idx];\n                if (step < avoidLimit && hasNonDead && degAfter[idx] == 0) continue;\n                double val = 0.0;\n                val += P.wP * pval[v];\n                val += P.wPot * pot[v];\n                val += P.wDeg * degAfter[idx];\n                int tv = twin[v];\n                if (tv != -1) {\n                    int dTwin = dynamicDeg(tv, tileUsed);\n                    val -= P.wTwinDeg * dTwin;\n                    val -= P.wTwinPot * pot[tv];\n                }\n                if (degAfter[idx] > 0 && P.wLook > 1e-9) {\n                    double best2 = -1e100;\n                    for (int w : NB[v]) {\n                        int tw = tile[w];\n                        if (tileUsed[tw]) continue;\n                        int deg2 = dynamicDeg(w, tileUsed, tile[v]);\n                        double val2 = 0.0;\n                        val2 += P.wP * pval[w];\n                        val2 += P.wPot * pot[w];\n                        val2 += P.wDeg * deg2;\n                        int t2 = twin[w];\n                        if (t2 != -1) {\n                            int dtwin2 = dynamicDeg(t2, tileUsed, tile[v]);\n                            val2 -= P.wTwinDeg * dtwin2;\n                            val2 -= P.wTwinPot * pot[t2];\n                        }\n                        if (val2 > best2) best2 = val2;\n                    }\n                    if (best2 > -1e90) val += P.wLook * best2;\n                }\n                val += (rng.next_double() * 2.0 - 1.0) * P.noise;\n                if (val > bestVal) bestVal = val, bestV = v;\n            }\n\n            if (bestV == -1) {\n                double bestFallback = -1e100;\n                for (int v : cand) {\n                    double val = P.wP * pval[v] + P.wPot * pot[v] + (rng.next_double() * 2.0 - 1.0) * P.noise;\n                    if (val > bestFallback) bestFallback = val, bestV = v;\n                }\n                if (bestV == -1) break;\n            }\n\n            tileUsed[tile[bestV]] = 1;\n            score += pval[bestV];\n            moves.push_back(direction_char(pos, bestV));\n            pos = bestV;\n        }\n\n        return PathResult{score, moves, (int)moves.size() + 1};\n    };\n\n    auto beam_prefix = [&](int maxDepth, int beamWidth, const Params& P) -> string {\n        struct BNode {\n            int pos;\n            long long g;\n            string path;\n            vector<char> used;\n            double pri;\n        };\n        int start = id_of(si, sj);\n        BNode root;\n        root.pos = start;\n        root.g = pval[start];\n        root.path.clear();\n        root.used.assign(M, 0);\n        root.used[tile[start]] = 1;\n        root.pri = root.g + 0.05 * pot[start] + 0.8 * (double)dynamicDeg(start, root.used);\n        vector<BNode> cur, nxt;\n        cur.reserve(beamWidth);\n        nxt.reserve(beamWidth * 4);\n        cur.push_back(std::move(root));\n\n        const double aPot = max(0.03, P.wPot * 0.8);\n        const double bDeg = max(0.5, P.wDeg * 0.5);\n        const double deadPenalty = 1e6;\n\n        for (int d = 0; d < maxDepth; d++) {\n            nxt.clear();\n            for (const auto& nd : cur) {\n                int u = nd.pos;\n                for (int v : NB[u]) {\n                    int tv = tile[v];\n                    if (nd.used[tv]) continue;\n                    BNode ch;\n                    ch.pos = v;\n                    ch.g = nd.g + pval[v];\n                    ch.path = nd.path;\n                    ch.path.push_back(direction_char(u, v));\n                    ch.used = nd.used;\n                    ch.used[tv] = 1;\n                    int degv = dynamicDeg(v, ch.used);\n                    ch.pri = ch.g + aPot * pot[v] + bDeg * degv;\n                    if (degv == 0 && d + 1 < maxDepth) ch.pri -= deadPenalty; // avoid early dead-ends\n                    nxt.push_back(std::move(ch));\n                }\n            }\n            if (nxt.empty()) break;\n            if ((int)nxt.size() > beamWidth) {\n                nth_element(nxt.begin(), nxt.begin() + beamWidth, nxt.end(),\n                            [](const BNode& a, const BNode& b){ return a.pri > b.pri; });\n                nxt.resize(beamWidth);\n            }\n            // sort to make next layer deterministic enough\n            sort(nxt.begin(), nxt.end(), [](const BNode& a, const BNode& b){ return a.pri > b.pri; });\n            cur.swap(nxt);\n        }\n\n        // pick best by g + tiny pot to break ties\n        if (cur.empty()) return string();\n        int besti = 0;\n        double bestScore = cur[0].g + 0.02 * pot[cur[0].pos];\n        for (int i = 1; i < (int)cur.size(); i++) {\n            double s = cur[i].g + 0.02 * pot[cur[i].pos];\n            if (s > bestScore) { bestScore = s; besti = i; }\n        }\n        return cur[besti].path;\n    };\n\n    // Run multiple randomized attempts within time limit\n    long long bestScore = -1;\n    string bestMoves;\n    int runs = 0;\n\n    // One beam-planned run first (prefix only), then normal restarts\n    {\n        Params P = presets[0]; // balanced for beam heuristic weights\n        string forced = beam_prefix(12, 24, P);\n        PathResult r = build_path_with_forced(presets[0], forced);\n        bestScore = r.score;\n        bestMoves = r.moves;\n        runs++;\n    }\n    {\n        Params P = presets[0];\n        PathResult r = build_path(P);\n        if (r.score > bestScore) { bestScore = r.score; bestMoves = r.moves; }\n        runs++;\n    }\n\n    while (true) {\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - time_start).count();\n        if (elapsed > TIME_LIMIT) break;\n\n        // Pick a preset randomly\n        Params baseP = presets[rng.randint(0, (int)presets.size()-1)];\n\n        // Mildly adapt avoidDeadMinLen with elapsed (later runs may allow more dead-ends to grab value)\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        if (progress > 0.6) {\n            baseP.avoidDeadMinLen = max(0, baseP.avoidDeadMinLen - (int)((progress - 0.6) * 800));\n        }\n\n        PathResult r = build_path(baseP);\n        if (r.score > bestScore) {\n            bestScore = r.score;\n            bestMoves = r.moves;\n        }\n        runs++;\n    }\n\n    // Output best path\n    cout << bestMoves << '\\n';\n\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int H = 30;\n    static constexpr int W = 30;\n    static constexpr int N = H * W;\n    // true generation range\n    static constexpr double WMIN = 1000.0;\n    static constexpr double WMAX = 9000.0;\n    // per-edge deviation clamp\n    static constexpr double DEV_CLAMP = 3000.0;\n\n    // base parameters: row-segment for horizontals, col-segment for verticals\n    // Hseg[i][s] for s=0..2: j in [0..9], [10..19], [20..28]\n    // Vseg[j][s] for s=0..2: i in [0..9], [10..19], [20..28]\n    array<array<double, 3>, H> Hseg;\n    array<array<double, 3>, W> Vseg;\n\n    // per-edge deviations\n    double dev_h[H][W-1];\n    double dev_v[H-1][W];\n\n    // query counter\n    int qid;\n\n    Solver() {\n        // initialize bases to center of allowed range\n        double init = 5000.0;\n        for (int i = 0; i < H; i++) Hseg[i] = {init, init, init};\n        for (int j = 0; j < W; j++) Vseg[j] = {init, init, init};\n        for (int i = 0; i < H; i++) for (int j = 0; j < W-1; j++) dev_h[i][j] = 0.0;\n        for (int i = 0; i < H-1; i++) for (int j = 0; j < W; j++) dev_v[i][j] = 0.0;\n        qid = 0;\n    }\n\n    static inline int segH_from_j(int j) {\n        if (j < 10) return 0;\n        if (j < 20) return 1;\n        return 2; // 20..28\n    }\n    static inline int segV_from_i(int i) {\n        if (i < 10) return 0;\n        if (i < 20) return 1;\n        return 2; // 20..28\n    }\n\n    inline double wh(int i, int j) const { // horizontal edge (i,j)-(i,j+1), j in [0..28]\n        int s = segH_from_j(j);\n        double x = Hseg[i][s] + dev_h[i][j];\n        if (x < WMIN) x = WMIN;\n        if (x > WMAX) x = WMAX;\n        return x;\n    }\n    inline double wv(int i, int j) const { // vertical edge (i,j)-(i+1,j), i in [0..28]\n        int s = segV_from_i(i);\n        double x = Vseg[j][s] + dev_v[i][j];\n        if (x < WMIN) x = WMIN;\n        if (x > WMAX) x = WMAX;\n        return x;\n    }\n\n    struct Node {\n        double d;\n        int i, j;\n        bool operator<(const Node& other) const {\n            return d > other.d; // for min-heap\n        }\n    };\n\n    // compute shortest path under current estimates using Dijkstra\n    string compute_path(int si, int sj, int ti, int tj, double &pred_len) {\n        static double dist[H][W];\n        static int pi[H][W], pj[H][W];\n        static char pdir[H][W];\n\n        for (int i = 0; i < H; i++) {\n            for (int j = 0; j < W; j++) {\n                dist[i][j] = numeric_limits<double>::infinity();\n                pi[i][j] = pj[i][j] = -1;\n                pdir[i][j] = 0;\n            }\n        }\n\n        priority_queue<Node> pq;\n        dist[si][sj] = 0.0;\n        pq.push({0.0, si, sj});\n\n        while (!pq.empty()) {\n            Node cur = pq.top(); pq.pop();\n            int i = cur.i, j = cur.j;\n            if (cur.d != dist[i][j]) continue;\n            if (i == ti && j == tj) break;\n\n            // neighbors: U,D,L,R\n            if (i > 0) {\n                double w = wv(i-1, j);\n                double nd = cur.d + w;\n                if (nd < dist[i-1][j]) {\n                    dist[i-1][j] = nd;\n                    pi[i-1][j] = i; pj[i-1][j] = j; pdir[i-1][j] = 'U';\n                    pq.push({nd, i-1, j});\n                }\n            }\n            if (i+1 < H) {\n                double w = wv(i, j);\n                double nd = cur.d + w;\n                if (nd < dist[i+1][j]) {\n                    dist[i+1][j] = nd;\n                    pi[i+1][j] = i; pj[i+1][j] = j; pdir[i+1][j] = 'D';\n                    pq.push({nd, i+1, j});\n                }\n            }\n            if (j > 0) {\n                double w = wh(i, j-1);\n                double nd = cur.d + w;\n                if (nd < dist[i][j-1]) {\n                    dist[i][j-1] = nd;\n                    pi[i][j-1] = i; pj[i][j-1] = j; pdir[i][j-1] = 'L';\n                    pq.push({nd, i, j-1});\n                }\n            }\n            if (j+1 < W) {\n                double w = wh(i, j);\n                double nd = cur.d + w;\n                if (nd < dist[i][j+1]) {\n                    dist[i][j+1] = nd;\n                    pi[i][j+1] = i; pj[i][j+1] = j; pdir[i][j+1] = 'R';\n                    pq.push({nd, i, j+1});\n                }\n            }\n        }\n\n        // reconstruct path\n        string rev;\n        int ci = ti, cj = tj;\n        while (!(ci == si && cj == sj)) {\n            char c = pdir[ci][cj];\n            rev.push_back(c);\n            int ni = pi[ci][cj], nj = pj[ci][cj];\n            ci = ni; cj = nj;\n        }\n        reverse(rev.begin(), rev.end());\n        pred_len = dist[ti][tj];\n        return rev;\n    }\n\n    struct EdgeUse {\n        bool isH; // true: horizontal; false: vertical\n        int i, j; // for horizontal: edge (i,j)-(i,j+1), j in [0..28]; for vertical: (i,j)-(i+1,j), i in [0..28]\n    };\n\n    // parse path into edges, compute predicted length and feature counts\n    void parse_path_and_features(int si, int sj, const string &path,\n                                 vector<EdgeUse> &edges,\n                                 vector<array<int,3>> &countHseg, // size H: counts per segment\n                                 vector<array<int,3>> &countVseg, // size W: counts per segment\n                                 double &S_pred) {\n        edges.clear();\n        countHseg.assign(H, {0,0,0});\n        countVseg.assign(W, {0,0,0});\n        int i = si, j = sj;\n        S_pred = 0.0;\n\n        for (char c : path) {\n            if (c == 'U') {\n                // use vertical edge (i-1,j)\n                int ei = i - 1, ej = j;\n                edges.push_back({false, ei, ej});\n                int s = segV_from_i(ei);\n                countVseg[ej][s] += 1;\n                double w = wv(ei, ej);\n                S_pred += w;\n                i -= 1;\n            } else if (c == 'D') {\n                int ei = i, ej = j;\n                edges.push_back({false, ei, ej});\n                int s = segV_from_i(ei);\n                countVseg[ej][s] += 1;\n                double w = wv(ei, ej);\n                S_pred += w;\n                i += 1;\n            } else if (c == 'L') {\n                int ei = i, ej = j - 1;\n                edges.push_back({true, ei, ej});\n                int s = segH_from_j(ej);\n                countHseg[ei][s] += 1;\n                double w = wh(ei, ej);\n                S_pred += w;\n                j -= 1;\n            } else if (c == 'R') {\n                int ei = i, ej = j;\n                edges.push_back({true, ei, ej});\n                int s = segH_from_j(ej);\n                countHseg[ei][s] += 1;\n                double w = wh(ei, ej);\n                S_pred += w;\n                j += 1;\n            }\n        }\n    }\n\n    // Update parameters using normalized LMS; devs receive larger share\n    void update_from_observation(int si, int sj, const string &path, long long y) {\n        vector<EdgeUse> edges;\n        vector<array<int,3>> countH; // per row segments\n        vector<array<int,3>> countV; // per col segments\n        double S_pred = 0.0;\n        parse_path_and_features(si, sj, path, edges, countH, countV, S_pred);\n\n        // Error\n        double delta = (double)y - S_pred;\n        int L = (int)edges.size();\n\n        // Compute norms for base features\n        double n_base = 0.0;\n        for (int i = 0; i < H; i++) {\n            for (int s = 0; s < 3; s++) {\n                int c = countH[i][s];\n                if (c) n_base += (double)c * (double)c;\n            }\n        }\n        for (int j = 0; j < W; j++) {\n            for (int s = 0; s < 3; s++) {\n                int c = countV[j][s];\n                if (c) n_base += (double)c * (double)c;\n            }\n        }\n        if (n_base < 1e-9) n_base = 0.0;\n\n        // Learning rates schedule\n        double t = (double)qid / 1000.0; // 0 ... ~1\n        // linearly decrease learning rates over time\n        double eta_dev = (1.0 - t) * 0.75 + t * 0.35;   // from 0.75 to 0.35\n        double eta_base = (1.0 - t) * 0.24 + t * 0.10;  // from 0.24 to 0.10\n        double lambda = 1.0;\n\n        // compute step sizes\n        double alpha_dev = 0.0;\n        if (L > 0) alpha_dev = eta_dev * delta / ( (double)L + lambda );\n\n        double alpha_base = 0.0;\n        if (n_base > 0.0) alpha_base = eta_base * delta / ( n_base + lambda );\n\n        // Update base parameters\n        if (alpha_base != 0.0) {\n            for (int i = 0; i < H; i++) {\n                for (int s = 0; s < 3; s++) {\n                    int c = countH[i][s];\n                    if (c) {\n                        Hseg[i][s] += alpha_base * c;\n                        if (Hseg[i][s] < WMIN) Hseg[i][s] = WMIN;\n                        else if (Hseg[i][s] > WMAX) Hseg[i][s] = WMAX;\n                    }\n                }\n            }\n            for (int j = 0; j < W; j++) {\n                for (int s = 0; s < 3; s++) {\n                    int c = countV[j][s];\n                    if (c) {\n                        Vseg[j][s] += alpha_base * c;\n                        if (Vseg[j][s] < WMIN) Vseg[j][s] = WMIN;\n                        else if (Vseg[j][s] > WMAX) Vseg[j][s] = WMAX;\n                    }\n                }\n            }\n        }\n\n        // Update per-edge deviations\n        if (alpha_dev != 0.0) {\n            for (const auto &e : edges) {\n                if (e.isH) {\n                    dev_h[e.i][e.j] += alpha_dev;\n                    if (dev_h[e.i][e.j] < -DEV_CLAMP) dev_h[e.i][e.j] = -DEV_CLAMP;\n                    else if (dev_h[e.i][e.j] > DEV_CLAMP) dev_h[e.i][e.j] = DEV_CLAMP;\n                } else {\n                    dev_v[e.i][e.j] += alpha_dev;\n                    if (dev_v[e.i][e.j] < -DEV_CLAMP) dev_v[e.i][e.j] = -DEV_CLAMP;\n                    else if (dev_v[e.i][e.j] > DEV_CLAMP) dev_v[e.i][e.j] = DEV_CLAMP;\n                }\n            }\n        }\n\n        // Small deviation decay towards 0 to regularize\n        double decay = (1.0 - t) * 0.0007 + t * 0.0018; // from ~7e-4 to ~1.8e-3\n        if (decay > 0.0) {\n            double mul = 1.0 - decay;\n            for (int i = 0; i < H; i++) {\n                for (int j = 0; j < W-1; j++) {\n                    dev_h[i][j] *= mul;\n                }\n            }\n            for (int i = 0; i < H-1; i++) {\n                for (int j = 0; j < W; j++) {\n                    dev_v[i][j] *= mul;\n                }\n            }\n        }\n\n        qid++;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int k = 0; k < 1000; k++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) {\n            return 0; // input ended unexpectedly\n        }\n\n        double pred_len = 0.0;\n        string path = solver.compute_path(si, sj, ti, tj, pred_len);\n\n        // Output path and flush\n        cout << path << '\\n' << flush;\n\n        long long observed_len;\n        if (!(cin >> observed_len)) {\n            return 0; // interactive judge ended\n        }\n\n        // Update model\n        solver.update_from_observation(si, sj, path, observed_len);\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\nusing namespace std;\n\n// Timer\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\n// Xorshift RNG\nstruct XorShift64 {\n    uint64_t x;\n    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    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n    inline double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n};\n\n// Problem constants\nstatic const int N_FIX = 20;\nstatic const int LMIN = 2;\nstatic const int LMAX = 12;\nstatic const int LCOUNT = LMAX - LMIN + 1;\n\nusing u64 = uint64_t;\nusing FlatMap = boost::unordered_flat_map<u64,int>;\n\nstatic inline u64 pack_key_str(const string& s) {\n    u64 k = 0;\n    for (char ch : s) k = (k << 3) | (u64)(ch - 'A');\n    return k;\n}\n\n// AC automaton for alphabet size 8\nstruct ACNode {\n    int next[8];\n    int fail;\n    vector<int> out; // list of uids (merged via fail)\n    ACNode() {\n        memset(next, -1, sizeof(next));\n        fail = 0;\n    }\n};\nstruct AhoCorasick {\n    vector<ACNode> nodes;\n    AhoCorasick() { nodes.reserve(4096); nodes.push_back(ACNode()); }\n\n    void add(const vector<uint8_t>& s, int uid) {\n        int v = 0;\n        for (uint8_t c : s) {\n            if (nodes[v].next[c] == -1) {\n                nodes[v].next[c] = (int)nodes.size();\n                nodes.push_back(ACNode());\n            }\n            v = nodes[v].next[c];\n        }\n        nodes[v].out.push_back(uid);\n    }\n\n    void build() {\n        queue<int> q;\n        for (int c = 0; c < 8; ++c) {\n            int u = nodes[0].next[c];\n            if (u != -1) {\n                nodes[u].fail = 0;\n                q.push(u);\n            } else {\n                nodes[0].next[c] = 0;\n            }\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int f = nodes[v].fail;\n            if (!nodes[f].out.empty()) {\n                auto &ov = nodes[v].out;\n                const auto &of = nodes[f].out;\n                ov.insert(ov.end(), of.begin(), of.end());\n            }\n            for (int c = 0; c < 8; ++c) {\n                int u = nodes[v].next[c];\n                if (u != -1) {\n                    nodes[u].fail = nodes[f].next[c];\n                    q.push(u);\n                } else {\n                    nodes[v].next[c] = nodes[f].next[c];\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    vector<string> inputS(M);\n    for (int i = 0; i < M; ++i) cin >> inputS[i];\n\n    Timer timer;\n    const double TIME_LIMIT = 2.95;\n\n    // Build unique strings (lenIdx, key) -> uid\n    struct UKeyHasher {\n        size_t operator()(const pair<int,u64>& p) const {\n            return std::hash<u64>()((p.second << 4) ^ (u64)p.first);\n        }\n    };\n    struct UKeyEq {\n        bool operator()(const pair<int,u64>& a, const pair<int,u64>& b) const {\n            return a.first == b.first && a.second == b.second;\n        }\n    };\n    boost::unordered_flat_map<pair<int,u64>, int, UKeyHasher, UKeyEq> uniqMap;\n    uniqMap.reserve(M*2);\n\n    struct Unique {\n        int len;\n        u64 key;\n        int weight;\n        vector<uint8_t> codes;\n    };\n    vector<Unique> uniqs; uniqs.reserve(M);\n\n    for (int i = 0; i < M; ++i) {\n        const string &s = inputS[i];\n        int L = (int)s.size();\n        int li = L - LMIN;\n        u64 key = pack_key_str(s);\n        auto pr = make_pair(li, key);\n        auto it = uniqMap.find(pr);\n        if (it == uniqMap.end()) {\n            int uid = (int)uniqs.size();\n            uniqMap.emplace(pr, uid);\n            Unique u;\n            u.len = L;\n            u.key = key;\n            u.weight = 1;\n            u.codes.resize(L);\n            for (int j = 0; j < L; ++j) u.codes[j] = (uint8_t)(s[j] - 'A');\n            uniqs.push_back(std::move(u));\n        } else {\n            uniqs[it->second].weight += 1;\n        }\n    }\n    int K = (int)uniqs.size();\n\n    // Per-length key->uid maps\n    array<FlatMap, LCOUNT> key2uid;\n    for (int li = 0; li < LCOUNT; ++li) key2uid[li].reserve(max(8, K / LCOUNT * 2));\n    for (int uid = 0; uid < K; ++uid) {\n        int li = uniqs[uid].len - LMIN;\n        key2uid[li].emplace(uniqs[uid].key, uid);\n    }\n\n    // Precompute bit shifts\n    int shiftAmt[LCOUNT][LMAX];\n    for (int li = 0; li < LCOUNT; ++li) {\n        int L = LMIN + li;\n        for (int t = 0; t < L; ++t) shiftAmt[li][t] = 3 * (L - 1 - t);\n    }\n\n    // Grid initialization: random\n    XorShift64 rng(123456789);\n    uint8_t g[N_FIX][N_FIX];\n    for (int i = 0; i < N_FIX; ++i) for (int j = 0; j < N_FIX; ++j) g[i][j] = (uint8_t)rng.next_int(0,7);\n\n    // windowsKey/Uid for lines: [li][line 0..39][start 0..19]\n    u64 windowsKey[LCOUNT][2*N_FIX][N_FIX];\n    int  windowsUid[LCOUNT][2*N_FIX][N_FIX];\n    for (int li = 0; li < LCOUNT; ++li)\n        for (int ln = 0; ln < 2*N_FIX; ++ln)\n            for (int s = 0; s < N_FIX; ++s) {\n                windowsKey[li][ln][s] = 0;\n                windowsUid[li][ln][s] = -1;\n            }\n\n    vector<int> occCount(K, 0);\n    vector<char> present(K, 0);\n    long long scoreC = 0;\n\n    // Initialize windows and occCount\n    for (int li = 0; li < LCOUNT; ++li) {\n        int L = LMIN + li;\n        for (int ln = 0; ln < 2*N_FIX; ++ln) {\n            for (int s = 0; s < N_FIX; ++s) {\n                u64 key = 0;\n                if (ln < N_FIX) {\n                    int i = ln;\n                    for (int r = 0; r < L; ++r) {\n                        int idx = s + r;\n                        if (idx >= N_FIX) idx -= N_FIX;\n                        key = (key << 3) | (u64)g[i][idx];\n                    }\n                } else {\n                    int j = ln - N_FIX;\n                    for (int r = 0; r < L; ++r) {\n                        int idx = s + r;\n                        if (idx >= N_FIX) idx -= N_FIX;\n                        key = (key << 3) | (u64)g[idx][j];\n                    }\n                }\n                windowsKey[li][ln][s] = key;\n                auto it = key2uid[li].find(key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    windowsUid[li][ln][s] = uid;\n                    if (occCount[uid] == 0) {\n                        scoreC += uniqs[uid].weight;\n                        present[uid] = 1;\n                    }\n                    occCount[uid] += 1;\n                } else {\n                    windowsUid[li][ln][s] = -1;\n                }\n            }\n        }\n    }\n\n    // Stamping structures for evaluating deltas\n    vector<int> deltaOcc(K, 0);\n    vector<int> lastStamp(K, -1);\n    vector<int> touched; touched.reserve(4096);\n    int stamp = 0;\n\n    // Aggregate masks for block paste row/col evaluation\n    static u64 aggMask[LCOUNT][N_FIX];\n    static int maskStamp[LCOUNT][N_FIX];\n    int aggStamp = 1; // start from 1 so 0 means \"never\"\n\n    // Common accumulator for a single change on given line at pos, with ocxor\n    auto accumulate_single_change = [&](int line, int pos, int ocxor_) {\n        for (int li = 0; li < LCOUNT; ++li) {\n            int Lw = LMIN + li;\n            for (int t = 0; t < Lw; ++t) {\n                int s = pos - t;\n                if (s < 0) s += N_FIX;\n                int old_uid = windowsUid[li][line][s];\n                if (old_uid >= 0) {\n                    if (lastStamp[old_uid] != stamp) {\n                        lastStamp[old_uid] = stamp;\n                        deltaOcc[old_uid] = 0;\n                        touched.push_back(old_uid);\n                    }\n                    deltaOcc[old_uid] -= 1;\n                }\n                u64 old_key = windowsKey[li][line][s];\n                u64 new_key = old_key ^ ((u64)ocxor_ << shiftAmt[li][t]);\n                auto it = key2uid[li].find(new_key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    if (lastStamp[uid] != stamp) {\n                        lastStamp[uid] = stamp;\n                        deltaOcc[uid] = 0;\n                        touched.push_back(uid);\n                    }\n                    deltaOcc[uid] += 1;\n                }\n            }\n        }\n    };\n\n    // Update windows and counts for a single change\n    auto update_line_single = [&](int line, int pos, int ocxor_) {\n        for (int li = 0; li < LCOUNT; ++li) {\n            int Lw = LMIN + li;\n            for (int t = 0; t < Lw; ++t) {\n                int s = pos - t;\n                if (s < 0) s += N_FIX;\n                int old_uid = windowsUid[li][line][s];\n                u64 old_key = windowsKey[li][line][s];\n                u64 new_key = old_key ^ ((u64)ocxor_ << shiftAmt[li][t]);\n                auto it = key2uid[li].find(new_key);\n                int new_uid = (it == key2uid[li].end() ? -1 : it->second);\n\n                if (old_uid >= 0) {\n                    occCount[old_uid] -= 1;\n                    if (occCount[old_uid] == 0) {\n                        scoreC -= uniqs[old_uid].weight;\n                        present[old_uid] = 0;\n                    }\n                }\n                if (new_uid >= 0) {\n                    if (occCount[new_uid] == 0) {\n                        scoreC += uniqs[new_uid].weight;\n                        present[new_uid] = 1;\n                    }\n                    occCount[new_uid] += 1;\n                }\n\n                windowsKey[li][line][s] = new_key;\n                windowsUid[li][line][s] = new_uid;\n            }\n        }\n    };\n\n    auto eval_delta_for_letter = [&](int i, int j, uint8_t newCode) -> long long {\n        uint8_t oldCode = g[i][j];\n        if (newCode == oldCode) return 0;\n        int ocxor = (int)(oldCode ^ newCode);\n\n        ++stamp;\n        touched.clear();\n\n        // row and column\n        accumulate_single_change(i, j, ocxor);\n        accumulate_single_change(N_FIX + j, i, ocxor);\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto eval_delta_letter_lineonly = [&](int line, int pos, uint8_t oldCode, uint8_t newCode) -> long long {\n        if (newCode == oldCode) return 0;\n        int ocxor = (int)(oldCode ^ newCode);\n        ++stamp;\n        touched.clear();\n        accumulate_single_change(line, pos, ocxor);\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto apply_letter = [&](int i, int j, uint8_t newCode) {\n        uint8_t oldCode = g[i][j];\n        if (newCode == oldCode) return;\n        int ocxor = (int)(oldCode ^ newCode);\n\n        // update row windows\n        update_line_single(i, j, ocxor);\n        // update column windows\n        update_line_single(N_FIX + j, i, ocxor);\n\n        // update grid\n        g[i][j] = newCode;\n    };\n\n    // Aggregate evaluation for multiple changes on the same line\n    auto eval_delta_paste_line_aggregate = [&](int line, const vector<pair<int,int>>& posXor) {\n        ++aggStamp;\n        for (auto &px : posXor) {\n            int pos = px.first;\n            int ocxor = px.second;\n            if (ocxor == 0) continue;\n            for (int li = 0; li < LCOUNT; ++li) {\n                int Lw = LMIN + li;\n                for (int t = 0; t < Lw; ++t) {\n                    int s = pos - t;\n                    if (s < 0) s += N_FIX;\n                    if (maskStamp[li][s] != aggStamp) {\n                        maskStamp[li][s] = aggStamp;\n                        aggMask[li][s] = 0;\n                    }\n                    aggMask[li][s] ^= ((u64)ocxor << shiftAmt[li][t]);\n                }\n            }\n        }\n        for (int li = 0; li < LCOUNT; ++li) {\n            for (int s = 0; s < N_FIX; ++s) {\n                if (maskStamp[li][s] != aggStamp) continue;\n                u64 m = aggMask[li][s];\n                if (m == 0) continue;\n                int old_uid = windowsUid[li][line][s];\n                if (old_uid >= 0) {\n                    if (lastStamp[old_uid] != stamp) {\n                        lastStamp[old_uid] = stamp;\n                        deltaOcc[old_uid] = 0;\n                        touched.push_back(old_uid);\n                    }\n                    deltaOcc[old_uid] -= 1;\n                }\n                u64 old_key = windowsKey[li][line][s];\n                u64 new_key = old_key ^ m;\n                auto it = key2uid[li].find(new_key);\n                if (it != key2uid[li].end()) {\n                    int uid = it->second;\n                    if (lastStamp[uid] != stamp) {\n                        lastStamp[uid] = stamp;\n                        deltaOcc[uid] = 0;\n                        touched.push_back(uid);\n                    }\n                    deltaOcc[uid] += 1;\n                }\n            }\n        }\n    };\n\n    // Exact evaluation for pasting an entire row/column (codes.size() == 20)\n    auto eval_delta_paste_row_full = [&](int i, const vector<uint8_t>& codes) -> long long {\n        vector<pair<int,int>> rowPosXor; rowPosXor.reserve(N_FIX);\n        vector<tuple<int,int,int>> colTriples; colTriples.reserve(N_FIX);\n        for (int j = 0; j < N_FIX; ++j) {\n            int ocxor = g[i][j] ^ codes[j];\n            if (ocxor == 0) continue;\n            rowPosXor.emplace_back(j, ocxor);\n            colTriples.emplace_back(N_FIX + j, i, ocxor);\n        }\n        if (rowPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        // row aggregate\n        eval_delta_paste_line_aggregate(i, rowPosXor);\n\n        // columns single\n        for (auto &tp : colTriples) {\n            int line = get<0>(tp), pos = get<1>(tp), ocxor = get<2>(tp);\n            accumulate_single_change(line, pos, ocxor);\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto eval_delta_paste_col_full = [&](int j, const vector<uint8_t>& codes) -> long long {\n        vector<pair<int,int>> colPosXor; colPosXor.reserve(N_FIX);\n        vector<tuple<int,int,int>> rowTriples; rowTriples.reserve(N_FIX);\n        for (int i = 0; i < N_FIX; ++i) {\n            int ocxor = g[i][j] ^ codes[i];\n            if (ocxor == 0) continue;\n            colPosXor.emplace_back(i, ocxor);\n            rowTriples.emplace_back(i, j, ocxor);\n        }\n        if (colPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        // column aggregate\n        eval_delta_paste_line_aggregate(N_FIX + j, colPosXor);\n\n        // rows single\n        for (auto &tp : rowTriples) {\n            int line = get<0>(tp), pos = get<1>(tp), ocxor = get<2>(tp);\n            accumulate_single_change(line, pos, ocxor);\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto eval_delta_paste_row_seg = [&](int i, int start, const vector<uint8_t>& codes) -> long long {\n        vector<pair<int,int>> rowPosXor; rowPosXor.reserve((int)codes.size());\n        vector<tuple<int,int,int>> colTriples; colTriples.reserve((int)codes.size());\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int j = start + p; if (j >= N_FIX) j -= N_FIX;\n            int ocxor = g[i][j] ^ codes[p];\n            if (ocxor == 0) continue;\n            rowPosXor.emplace_back(j, ocxor);\n            colTriples.emplace_back(N_FIX + j, i, ocxor);\n        }\n        if (rowPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        eval_delta_paste_line_aggregate(i, rowPosXor);\n        for (auto &tp : colTriples) {\n            int line = get<0>(tp), pos = get<1>(tp), ocxor = get<2>(tp);\n            accumulate_single_change(line, pos, ocxor);\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto eval_delta_paste_col_seg = [&](int j, int start, const vector<uint8_t>& codes) -> long long {\n        vector<pair<int,int>> colPosXor; colPosXor.reserve((int)codes.size());\n        vector<tuple<int,int,int>> rowTriples; rowTriples.reserve((int)codes.size());\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int i = start + p; if (i >= N_FIX) i -= N_FIX;\n            int ocxor = g[i][j] ^ codes[p];\n            if (ocxor == 0) continue;\n            colPosXor.emplace_back(i, ocxor);\n            rowTriples.emplace_back(i, j, ocxor);\n        }\n        if (colPosXor.empty()) return 0;\n\n        ++stamp;\n        touched.clear();\n\n        eval_delta_paste_line_aggregate(N_FIX + j, colPosXor);\n        for (auto &tp : rowTriples) {\n            int line = get<0>(tp), pos = get<1>(tp), ocxor = get<2>(tp);\n            accumulate_single_change(line, pos, ocxor);\n        }\n\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n\n    auto apply_paste_row_full = [&](int i, const vector<uint8_t>& codes) {\n        for (int j = 0; j < N_FIX; ++j) {\n            if (g[i][j] != codes[j]) apply_letter(i, j, codes[j]);\n        }\n    };\n    auto apply_paste_col_full = [&](int j, const vector<uint8_t>& codes) {\n        for (int i = 0; i < N_FIX; ++i) {\n            if (g[i][j] != codes[i]) apply_letter(i, j, codes[i]);\n        }\n    };\n    auto apply_paste_row_seg = [&](int i, int start, const vector<uint8_t>& codes) {\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int j = start + p; if (j >= N_FIX) j -= N_FIX;\n            if (g[i][j] != codes[p]) apply_letter(i, j, codes[p]);\n        }\n    };\n    auto apply_paste_col_seg = [&](int j, int start, const vector<uint8_t>& codes) {\n        for (int p = 0; p < (int)codes.size(); ++p) {\n            int i = start + p; if (i >= N_FIX) i -= N_FIX;\n            if (g[i][j] != codes[p]) apply_letter(i, j, codes[p]);\n        }\n    };\n\n    // Rotation evaluation and application\n    auto eval_delta_rotate_row = [&](int i, int sft) -> long long {\n        if (sft % N_FIX == 0) return 0;\n        ++stamp;\n        touched.clear();\n        for (int j = 0; j < N_FIX; ++j) {\n            int j2 = j - sft; if (j2 < 0) j2 += N_FIX;\n            int ocxor = g[i][j] ^ g[i][j2];\n            if (ocxor) {\n                accumulate_single_change(N_FIX + j, i, ocxor);\n            }\n        }\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n    auto apply_rotate_row = [&](int i, int sft) {\n        if (sft % N_FIX == 0) return;\n        uint8_t newRow[N_FIX];\n        for (int j = 0; j < N_FIX; ++j) {\n            int j2 = j - sft; if (j2 < 0) j2 += N_FIX;\n            newRow[j] = g[i][j2];\n        }\n        for (int j = 0; j < N_FIX; ++j) {\n            uint8_t oldC = g[i][j];\n            uint8_t newC = newRow[j];\n            if (oldC != newC) {\n                int ocxor = (int)(oldC ^ newC);\n                update_line_single(N_FIX + j, i, ocxor);\n                g[i][j] = newC;\n            }\n        }\n        // rotate row windows arrays without changing occCount\n        for (int li = 0; li < LCOUNT; ++li) {\n            u64 tmpK[N_FIX];\n            int tmpU[N_FIX];\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                int from = s0 - sft; if (from < 0) from += N_FIX;\n                tmpK[s0] = windowsKey[li][i][from];\n                tmpU[s0] = windowsUid[li][i][from];\n            }\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                windowsKey[li][i][s0] = tmpK[s0];\n                windowsUid[li][i][s0] = tmpU[s0];\n            }\n        }\n    };\n\n    auto eval_delta_rotate_col = [&](int j, int sft) -> long long {\n        if (sft % N_FIX == 0) return 0;\n        ++stamp;\n        touched.clear();\n        for (int i = 0; i < N_FIX; ++i) {\n            int i2 = i - sft; if (i2 < 0) i2 += N_FIX;\n            int ocxor = g[i][j] ^ g[i2][j];\n            if (ocxor) {\n                accumulate_single_change(i, j, ocxor);\n            }\n        }\n        long long deltaScore = 0;\n        for (int uid : touched) {\n            int before = occCount[uid];\n            int after = before + deltaOcc[uid];\n            if (before == 0 && after > 0) deltaScore += uniqs[uid].weight;\n            else if (before > 0 && after == 0) deltaScore -= uniqs[uid].weight;\n        }\n        return deltaScore;\n    };\n    auto apply_rotate_col = [&](int j, int sft) {\n        if (sft % N_FIX == 0) return;\n        uint8_t newCol[N_FIX];\n        for (int i = 0; i < N_FIX; ++i) {\n            int i2 = i - sft; if (i2 < 0) i2 += N_FIX;\n            newCol[i] = g[i2][j];\n        }\n        for (int i = 0; i < N_FIX; ++i) {\n            uint8_t oldC = g[i][j];\n            uint8_t newC = newCol[i];\n            if (oldC != newC) {\n                int ocxor = (int)(oldC ^ newC);\n                update_line_single(i, j, ocxor);\n                g[i][j] = newC;\n            }\n        }\n        // rotate column windows arrays without changing occCount\n        for (int li = 0; li < LCOUNT; ++li) {\n            u64 tmpK[N_FIX];\n            int tmpU[N_FIX];\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                int from = s0 - sft; if (from < 0) from += N_FIX;\n                tmpK[s0] = windowsKey[li][N_FIX + j][from];\n                tmpU[s0] = windowsUid[li][N_FIX + j][from];\n            }\n            for (int s0 = 0; s0 < N_FIX; ++s0) {\n                windowsKey[li][N_FIX + j][s0] = tmpK[s0];\n                windowsUid[li][N_FIX + j][s0] = tmpU[s0];\n            }\n        }\n    };\n\n    long long bestScore = scoreC;\n    uint8_t bestGrid[N_FIX][N_FIX];\n    memcpy(bestGrid, g, sizeof(g));\n\n    // Build AC automaton with all unique strings\n    AhoCorasick ac;\n    for (int uid = 0; uid < K; ++uid) ac.add(uniqs[uid].codes, uid);\n    ac.build();\n    int S = (int)ac.nodes.size();\n\n    // Buffers for DP per line\n    vector<int> outW(S, 0), dp(S, 0), ndp(S, 0);\n    vector<uint8_t> choice((size_t)N_FIX * S);\n\n    auto ac_build_best_line = [&](vector<uint8_t>& out) {\n        for (int v = 0; v < S; ++v) {\n            int sum = 0;\n            const auto &ov = ac.nodes[v].out;\n            for (int uid : ov) if (!present[uid]) sum += uniqs[uid].weight;\n            outW[v] = sum;\n        }\n        fill(dp.begin(), dp.end(), 0);\n        for (int pos = N_FIX - 1; pos >= 0; --pos) {\n            for (int v = 0; v < S; ++v) {\n                int bestVal = INT_MIN;\n                uint8_t bestC = 0;\n                for (int c = 0; c < 8; ++c) {\n                    int u = ac.nodes[v].next[c];\n                    int val = outW[u] + dp[u];\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestC = (uint8_t)c;\n                    }\n                }\n                ndp[v] = bestVal;\n                choice[(size_t)pos * S + v] = bestC;\n            }\n            dp.swap(ndp);\n        }\n        out.resize(N_FIX);\n        int v = 0;\n        for (int pos = 0; pos < N_FIX; ++pos) {\n            uint8_t c = choice[(size_t)pos * S + v];\n            out[pos] = c;\n            v = ac.nodes[v].next[c];\n        }\n    };\n\n    // Precompute weight-sorted uid list for block-paste targeting\n    vector<int> weightSorted(K);\n    iota(weightSorted.begin(), weightSorted.end(), 0);\n    sort(weightSorted.begin(), weightSorted.end(), [&](int a, int b){\n        if (uniqs[a].weight != uniqs[b].weight) return uniqs[a].weight > uniqs[b].weight;\n        return uniqs[a].len > uniqs[b].len;\n    });\n\n    auto pick_absent_uid = [&]() -> int {\n        int topK = min(K, 512);\n        for (int t = 0; t < 20; ++t) {\n            int idx = rng.next_int(0, topK-1);\n            int uid = weightSorted[idx];\n            if (!present[uid]) return uid;\n        }\n        for (int idx = 0; idx < K; ++idx) {\n            int uid = weightSorted[idx];\n            if (!present[uid]) return uid;\n        }\n        return rng.next_int(0, K-1);\n    };\n\n    // Stage 0: AC-guided line synthesis with best rotation\n    double T_AC = min(0.75, TIME_LIMIT * 0.26);\n    vector<int> lines(2*N_FIX);\n    iota(lines.begin(), lines.end(), 0);\n    while (timer.elapsed() < T_AC) {\n        shuffle(lines.begin(), lines.end(), std::mt19937(1234567 ^ (unsigned)rng.next_u32()));\n        bool anyApplied = false;\n        bool needRebuild = true;\n        vector<uint8_t> baseLine;\n        for (int idx = 0; idx < (int)lines.size(); ++idx) {\n            if (timer.elapsed() >= T_AC) break;\n            int ln = lines[idx];\n            if (needRebuild) {\n                ac_build_best_line(baseLine);\n                needRebuild = false;\n            }\n            // try all rotations for this line\n            long long bestDelta = LLONG_MIN;\n            int bestRot = 0;\n            vector<uint8_t> rotated(20);\n            if (ln < N_FIX) {\n                // row\n                for (int rot = 0; rot < N_FIX; ++rot) {\n                    for (int j = 0; j < N_FIX; ++j) rotated[j] = baseLine[(j + rot) % N_FIX];\n                    long long d = eval_delta_paste_row_full(ln, rotated);\n                    if (d > bestDelta) {\n                        bestDelta = d;\n                        bestRot = rot;\n                    }\n                }\n                if (bestDelta > 0) {\n                    for (int j = 0; j < N_FIX; ++j) rotated[j] = baseLine[(j + bestRot) % N_FIX];\n                    apply_paste_row_full(ln, rotated);\n                    anyApplied = true;\n                    needRebuild = true;\n                    if (scoreC > bestScore) {\n                        bestScore = scoreC;\n                        memcpy(bestGrid, g, sizeof(g));\n                    }\n                }\n            } else {\n                int j = ln - N_FIX;\n                for (int rot = 0; rot < N_FIX; ++rot) {\n                    for (int i = 0; i < N_FIX; ++i) rotated[i] = baseLine[(i + rot) % N_FIX];\n                    long long d = eval_delta_paste_col_full(j, rotated);\n                    if (d > bestDelta) {\n                        bestDelta = d;\n                        bestRot = rot;\n                    }\n                }\n                if (bestDelta > 0) {\n                    for (int i = 0; i < N_FIX; ++i) rotated[i] = baseLine[(i + bestRot) % N_FIX];\n                    apply_paste_col_full(j, rotated);\n                    anyApplied = true;\n                    needRebuild = true;\n                    if (scoreC > bestScore) {\n                        bestScore = scoreC;\n                        memcpy(bestGrid, g, sizeof(g));\n                    }\n                }\n            }\n        }\n        if (!anyApplied) break;\n    }\n\n    // Stage 0.25: Context-aware AC DP on a few lines with perpendicular letter gains (tight budget)\n    auto ac_build_best_line_with_gain = [&](const vector<array<int,8>>& letterGain, vector<uint8_t>& out) {\n        // compute outW by absent patterns\n        for (int v = 0; v < S; ++v) {\n            int sum = 0;\n            const auto &ov = ac.nodes[v].out;\n            for (int uid : ov) if (!present[uid]) sum += uniqs[uid].weight;\n            outW[v] = sum;\n        }\n        fill(dp.begin(), dp.end(), 0);\n        for (int pos = N_FIX - 1; pos >= 0; --pos) {\n            const auto &lg = letterGain[pos];\n            for (int v = 0; v < S; ++v) {\n                int bestVal = INT_MIN;\n                uint8_t bestC = 0;\n                for (int c = 0; c < 8; ++c) {\n                    int u = ac.nodes[v].next[c];\n                    int val = outW[u] + dp[u] + lg[c];\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestC = (uint8_t)c;\n                    }\n                }\n                ndp[v] = bestVal;\n                choice[(size_t)pos * S + v] = bestC;\n            }\n            dp.swap(ndp);\n        }\n        out.resize(N_FIX);\n        int v = 0;\n        for (int pos = 0; pos < N_FIX; ++pos) {\n            uint8_t c = choice[(size_t)pos * S + v];\n            out[pos] = c;\n            v = ac.nodes[v].next[c];\n        }\n    };\n\n    double T_CA = TIME_LIMIT * 0.06; // small budget\n    if (timer.elapsed() < T_CA) {\n        vector<int> order(2*N_FIX);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), std::mt19937(987654321 ^ (unsigned)rng.next_u32()));\n        int trials = 10; // try a few lines\n        for (int t = 0; t < trials && t < (int)order.size(); ++t) {\n            if (timer.elapsed() >= T_CA) break;\n            int ln = order[t];\n            if (ln < N_FIX) {\n                int i = ln;\n                vector<array<int,8>> gain(N_FIX);\n                for (int j = 0; j < N_FIX; ++j) {\n                    uint8_t oldC = g[i][j];\n                    for (int c = 0; c < 8; ++c) {\n                        if (c == oldC) { gain[j][c] = 0; continue; }\n                        gain[j][c] = (int)eval_delta_letter_lineonly(N_FIX + j, i, oldC, (uint8_t)c);\n                    }\n                }\n                vector<uint8_t> cand;\n                ac_build_best_line_with_gain(gain, cand);\n                long long d = eval_delta_paste_row_full(i, cand);\n                if (d > 0) {\n                    apply_paste_row_full(i, cand);\n                    if (scoreC > bestScore) {\n                        bestScore = scoreC;\n                        memcpy(bestGrid, g, sizeof(g));\n                    }\n                }\n            } else {\n                int j = ln - N_FIX;\n                vector<array<int,8>> gain(N_FIX);\n                for (int i = 0; i < N_FIX; ++i) {\n                    uint8_t oldC = g[i][j];\n                    for (int c = 0; c < 8; ++c) {\n                        if (c == oldC) { gain[i][c] = 0; continue; }\n                        gain[i][c] = (int)eval_delta_letter_lineonly(i, j, oldC, (uint8_t)c);\n                    }\n                }\n                vector<uint8_t> cand;\n                ac_build_best_line_with_gain(gain, cand);\n                long long d = eval_delta_paste_col_full(j, cand);\n                if (d > 0) {\n                    apply_paste_col_full(j, cand);\n                    if (scoreC > bestScore) {\n                        bestScore = scoreC;\n                        memcpy(bestGrid, g, sizeof(g));\n                    }\n                }\n            }\n        }\n    }\n\n    // Stage 0.5: Iterative rotation pass (rows then columns)\n    auto rotation_pass_iterative = [&]() {\n        bool improved_any = true;\n        while (improved_any && timer.elapsed() < TIME_LIMIT * 0.9) {\n            improved_any = false;\n            // Rows\n            for (int i = 0; i < N_FIX; ++i) {\n                if (timer.elapsed() > TIME_LIMIT * 0.88) break;\n                long long bestD = 0;\n                int bestSft = 0;\n                for (int sft = 1; sft < N_FIX; ++sft) {\n                    long long d = eval_delta_rotate_row(i, sft);\n                    if (d > bestD) { bestD = d; bestSft = sft; }\n                }\n                if (bestD > 0) {\n                    apply_rotate_row(i, bestSft);\n                    improved_any = true;\n                    if (scoreC > bestScore) {\n                        bestScore = scoreC;\n                        memcpy(bestGrid, g, sizeof(g));\n                    }\n                }\n            }\n            // Columns\n            for (int j = 0; j < N_FIX; ++j) {\n                if (timer.elapsed() > TIME_LIMIT * 0.90) break;\n                long long bestD = 0;\n                int bestSft = 0;\n                for (int sft = 1; sft < N_FIX; ++sft) {\n                    long long d = eval_delta_rotate_col(j, sft);\n                    if (d > bestD) { bestD = d; bestSft = sft; }\n                }\n                if (bestD > 0) {\n                    apply_rotate_col(j, bestSft);\n                    improved_any = true;\n                    if (scoreC > bestScore) {\n                        bestScore = scoreC;\n                        memcpy(bestGrid, g, sizeof(g));\n                    }\n                }\n            }\n        }\n    };\n    rotation_pass_iterative();\n\n    // Guided candidate selection for block paste\n    struct Cand {\n        bool isRow;\n        int line;\n        int start;\n        int mism;\n    };\n    struct CmpMax {\n        bool operator()(const Cand& a, const Cand& b) const {\n            return a.mism < b.mism; // for max-heap\n        }\n    };\n\n    auto guided_candidates_for_uid = [&](int uid, vector<Cand>& out, int KTOP) {\n        out.clear();\n        priority_queue<Cand, vector<Cand>, CmpMax> heap;\n        const auto &codes = uniqs[uid].codes;\n        int L = (int)codes.size();\n        // rows\n        for (int i = 0; i < N_FIX; ++i) {\n            for (int s = 0; s < N_FIX; ++s) {\n                int mism = 0;\n                for (int p = 0; p < L; ++p) {\n                    int j = s + p; if (j >= N_FIX) j -= N_FIX;\n                    mism += (g[i][j] != codes[p]);\n                }\n                if ((int)heap.size() < KTOP) heap.push({true, i, s, mism});\n                else if (mism < heap.top().mism) { heap.pop(); heap.push({true, i, s, mism}); }\n            }\n        }\n        // columns\n        for (int j = 0; j < N_FIX; ++j) {\n            for (int s = 0; s < N_FIX; ++s) {\n                int mism = 0;\n                for (int p = 0; p < L; ++p) {\n                    int i = s + p; if (i >= N_FIX) i -= N_FIX;\n                    mism += (g[i][j] != codes[p]);\n                }\n                if ((int)heap.size() < KTOP) heap.push({false, j, s, mism});\n                else if (mism < heap.top().mism) { heap.pop(); heap.push({false, j, s, mism}); }\n            }\n        }\n        out.reserve(heap.size());\n        while (!heap.empty()) { out.push_back(heap.top()); heap.pop(); }\n        sort(out.begin(), out.end(), [](const Cand& a, const Cand& b){ return a.mism < b.mism; });\n    };\n\n    // Stage 1: Block paste hill-climbing (focus absent), mix guided and random\n    double T_BLOCK = TIME_LIMIT * 0.82;\n    int iterBlock = 0;\n    vector<Cand> cands; cands.reserve(16);\n    while (timer.elapsed() < T_BLOCK) {\n        ++iterBlock;\n        bool guided = (iterBlock % 2 == 0); // guided every 2nd iteration\n        int uid = pick_absent_uid();\n        const auto &codes = uniqs[uid].codes;\n\n        long long bestDelta = LLONG_MIN;\n        bool bestIsRow = true;\n        int bestLine = 0, bestStart = 0;\n\n        if (guided) {\n            guided_candidates_for_uid(uid, cands, 12);\n            for (const auto& cd : cands) {\n                long long d = cd.isRow ? eval_delta_paste_row_seg(cd.line, cd.start, codes)\n                                       : eval_delta_paste_col_seg(cd.line, cd.start, codes);\n                if (d > bestDelta) {\n                    bestDelta = d;\n                    bestIsRow = cd.isRow;\n                    bestLine = cd.line;\n                    bestStart = cd.start;\n                }\n            }\n        } else {\n            int tries = 12;\n            for (int t = 0; t < tries; ++t) {\n                bool isRow = (rng.next_u32() & 1) == 0;\n                int line = rng.next_int(0, N_FIX-1);\n                int start = rng.next_int(0, N_FIX-1);\n                long long d = isRow ? eval_delta_paste_row_seg(line, start, codes)\n                                    : eval_delta_paste_col_seg(line, start, codes);\n                if (d > bestDelta) {\n                    bestDelta = d;\n                    bestIsRow = isRow;\n                    bestLine = line;\n                    bestStart = start;\n                }\n            }\n        }\n\n        if (bestDelta > 0) {\n            if (bestIsRow) apply_paste_row_seg(bestLine, bestStart, codes);\n            else apply_paste_col_seg(bestLine, bestStart, codes);\n            if (scoreC > bestScore) {\n                bestScore = scoreC;\n                memcpy(bestGrid, g, sizeof(g));\n            }\n        }\n    }\n\n    // Optional second rotation pass (iterative)\n    if (timer.elapsed() < TIME_LIMIT * 0.92) rotation_pass_iterative();\n\n    // Stage 2: SA fine-tuning with single-letter moves\n    double T0 = 1.0, T1 = 0.01;\n    while (timer.elapsed() < TIME_LIMIT) {\n        int i = rng.next_int(0, N_FIX-1);\n        int j = rng.next_int(0, N_FIX-1);\n        uint8_t oldCode = g[i][j];\n\n        long long bestDelta = LLONG_MIN;\n        uint8_t bestCode = oldCode;\n        for (uint8_t nc = 0; nc < 8; ++nc) {\n            if (nc == oldCode) continue;\n            long long delta = eval_delta_for_letter(i, j, nc);\n            if (delta > bestDelta) {\n                bestDelta = delta;\n                bestCode = nc;\n            }\n        }\n\n        double t = timer.elapsed() / TIME_LIMIT;\n        if (t > 1.0) break;\n        double T = T0 + (T1 - T0) * t;\n\n        bool accept = false;\n        if (bestDelta >= 0) accept = true;\n        else {\n            double prob = exp((double)bestDelta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n        if (accept && bestCode != oldCode) {\n            apply_letter(i, j, bestCode);\n            if (scoreC > bestScore) {\n                bestScore = scoreC;\n                memcpy(bestGrid, g, sizeof(g));\n            }\n        }\n    }\n\n    // Output best grid\n    for (int i = 0; i < N_FIX; ++i) {\n        string out; out.resize(N_FIX);\n        for (int j = 0; j < N_FIX; ++j) out[j] = char('A' + bestGrid[i][j]);\n        cout << out << '\\n';\n    }\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist;\n    vector<int> matchL, matchR;\n\n    HopcroftKarp(int nL_, int nR_) : nL(nL_), nR(nR_), g(nL_), dist(nL_), matchL(nL_, -1), matchR(nR_, -1) {}\n\n    void add_edge(int u, int v) { g[u].push_back(v); }\n\n    bool bfs() {\n        queue<int> q;\n        for (int i = 0; i < nL; ++i) {\n            if (matchL[i] == -1) {\n                dist[i] = 0;\n                q.push(i);\n            } else dist[i] = -1;\n        }\n        bool found = false;\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    bool dfs(int u) {\n        for (int v : g[u]) {\n            int u2 = matchR[v];\n            if (u2 == -1 || (dist[u2] == dist[u] + 1 && dfs(u2))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int max_matching() {\n        int res = 0;\n        while (bfs()) {\n            for (int i = 0; i < nL; ++i) {\n                if (matchL[i] == -1) if (dfs(i)) ++res;\n            }\n        }\n        return res;\n    }\n\n    pair<vector<char>, vector<char>> min_vertex_cover() {\n        // Compute Z: vertices reachable from unmatched left vertices via alternating paths\n        vector<char> visL(nL, 0), visR(nR, 0);\n        queue<int> q;\n        for (int u = 0; u < nL; ++u) if (matchL[u] == -1) {\n            visL[u] = 1;\n            q.push(u);\n        }\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                if (matchL[u] != v) { // unmatched edge\n                    if (!visR[v]) {\n                        visR[v] = 1;\n                        int u2 = matchR[v];\n                        if (u2 != -1 && !visL[u2]) {\n                            visL[u2] = 1;\n                            q.push(u2);\n                        }\n                    }\n                }\n            }\n        }\n        vector<char> coverL(nL, 0), coverR(nR, 0);\n        for (int u = 0; u < nL; ++u) if (!visL[u]) coverL[u] = 1;\n        for (int v = 0; v < nR; ++v) if (visR[v]) coverR[v] = 1;\n        return {coverL, coverR};\n    }\n};\n\nstruct NodePQ {\n    int d, u;\n    bool operator<(const NodePQ& o) const { return d > o.d; }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, si, sj;\n    if (!(cin >> N >> si >> sj)) return 0;\n    vector<string> c(N);\n    for (int i = 0; i < N; ++i) cin >> c[i];\n\n    const int H = N, W = N;\n    auto id = [&](int i, int j){ return i*W + j; };\n    const int M = H*W;\n\n    vector<char> isRoad(M, 0);\n    vector<int> w(M, -1);\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        if (c[i][j] != '#') {\n            int u = id(i,j);\n            isRoad[u] = 1;\n            w[u] = c[i][j] - '0';\n        }\n    }\n\n    // Build row segments\n    vector<int> rowSegId(M, -1), colSegId(M, -1);\n    vector<int> rowPos(M, -1), colPos(M, -1);\n    vector<vector<int>> rowSegCells;\n    for (int i = 0; i < H; ++i) {\n        int j = 0;\n        while (j < W) {\n            if (isRoad[id(i,j)] && (j == 0 || !isRoad[id(i, j-1)])) {\n                int j2 = j;\n                int segId = (int)rowSegCells.size();\n                rowSegCells.emplace_back();\n                while (j2 < W && isRoad[id(i,j2)]) {\n                    int u = id(i,j2);\n                    rowSegId[u] = segId;\n                    rowPos[u] = (int)rowSegCells.back().size();\n                    rowSegCells.back().push_back(u);\n                    ++j2;\n                }\n                j = j2;\n            } else ++j;\n        }\n    }\n    // Build column segments\n    vector<vector<int>> colSegCells;\n    for (int j = 0; j < W; ++j) {\n        int i = 0;\n        while (i < H) {\n            if (isRoad[id(i,j)] && (i == 0 || !isRoad[id(i-1, j)])) {\n                int i2 = i;\n                int segId = (int)colSegCells.size();\n                colSegCells.emplace_back();\n                while (i2 < H && isRoad[id(i2,j)]) {\n                    int u = id(i2,j);\n                    colSegId[u] = segId;\n                    colPos[u] = (int)colSegCells.back().size();\n                    colSegCells.back().push_back(u);\n                    ++i2;\n                }\n                i = i2;\n            } else ++i;\n        }\n    }\n    int nR = (int)rowSegCells.size();\n    int nC = (int)colSegCells.size();\n\n    // Build bipartite graph: row segs -> col segs via edges for each road cell\n    HopcroftKarp hk(nR, nC);\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        int u = id(i,j);\n        if (!isRoad[u]) continue;\n        int r = rowSegId[u], cc = colSegId[u];\n        if (r >= 0 && cc >= 0) hk.add_edge(r, cc);\n    }\n    hk.max_matching();\n    auto [chooseRow_char, chooseCol_char] = hk.min_vertex_cover();\n    vector<char> chooseRow = chooseRow_char, chooseCol = chooseCol_char;\n\n    // Coverage states for chosen segments only\n    vector<char> coveredRow(nR, 0), coveredCol(nC, 0);\n    long long remain = 0;\n    for (int r = 0; r < nR; ++r) if (chooseRow[r]) ++remain;\n    for (int cc = 0; cc < nC; ++cc) if (chooseCol[cc]) ++remain;\n\n    // Prefix sums for along-segment costs\n    vector<vector<int>> rowPref(nR), colPref(nC);\n    for (int r = 0; r < nR; ++r) {\n        int L = (int)rowSegCells[r].size();\n        rowPref[r].resize(L);\n        for (int k = 0; k < L; ++k) {\n            int u = rowSegCells[r][k];\n            rowPref[r][k] = w[u] + (k ? rowPref[r][k-1] : 0);\n        }\n    }\n    for (int cc = 0; cc < nC; ++cc) {\n        int L = (int)colSegCells[cc].size();\n        colPref[cc].resize(L);\n        for (int k = 0; k < L; ++k) {\n            int u = colSegCells[cc][k];\n            colPref[cc][k] = w[u] + (k ? colPref[cc][k-1] : 0);\n        }\n    }\n    auto rowCost = [&](int seg, int p, int q)->int {\n        if (q >= p) return rowPref[seg][q] - rowPref[seg][p];\n        else return rowPref[seg][p-1] - (q > 0 ? rowPref[seg][q-1] : 0);\n    };\n    auto colCost = [&](int seg, int p, int q)->int {\n        if (q >= p) return colPref[seg][q] - colPref[seg][p];\n        else return colPref[seg][p-1] - (q > 0 ? colPref[seg][q-1] : 0);\n    };\n\n    int start = id(si, sj);\n    int cur = start;\n    string ans;\n\n    auto mark_covered_at_cell = [&](int u)->int {\n        int added = 0;\n        int r = rowSegId[u], cc = colSegId[u];\n        if (r >= 0 && chooseRow[r] && !coveredRow[r]) { coveredRow[r] = 1; --remain; ++added; }\n        if (cc >= 0 && chooseCol[cc] && !coveredCol[cc]) { coveredCol[cc] = 1; --remain; ++added; }\n        return added;\n    };\n    mark_covered_at_cell(cur);\n\n    const int INF = 1e9;\n    vector<int> dist(M, INF), prv(M, -1);\n    vector<char> prvDir(M, 0);\n\n    auto reconstruct_and_apply = [&](int s, int t){\n        if (s == t) return;\n        vector<char> moves;\n        int x = t;\n        while (x != s && x != -1) {\n            moves.push_back(prvDir[x]);\n            x = prv[x];\n        }\n        if (x != s) return;\n        reverse(moves.begin(), moves.end());\n        int ci = cur / W, cj = cur % W;\n        for (char mv : moves) {\n            if (mv == 'U') --ci;\n            else if (mv == 'D') ++ci;\n            else if (mv == 'L') --cj;\n            else if (mv == 'R') ++cj;\n            int nid = id(ci, cj);\n            mark_covered_at_cell(nid);\n            ans.push_back(mv);\n        }\n        cur = id(ci, cj);\n    };\n\n    auto dijkstra_to_single = [&](int target){\n        fill(dist.begin(), dist.end(), INF);\n        fill(prv.begin(), prv.end(), -1);\n        fill(prvDir.begin(), prvDir.end(), 0);\n        priority_queue<NodePQ> pq;\n        dist[cur] = 0;\n        pq.push({0, cur});\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (u == target) break;\n            int ui = u / W, uj = u % W;\n            if (ui-1 >= 0) {\n                int v = id(ui-1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'U'; pq.push({nd, v});\n                    }\n                }\n            }\n            if (ui+1 < H) {\n                int v = id(ui+1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'D'; pq.push({nd, v});\n                    }\n                }\n            }\n            if (uj-1 >= 0) {\n                int v = id(ui, uj-1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'L'; pq.push({nd, v});\n                    }\n                }\n            }\n            if (uj+1 < W) {\n                int v = id(ui, uj+1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) {\n                        dist[v] = nd; prv[v] = u; prvDir[v] = 'R'; pq.push({nd, v});\n                    }\n                }\n            }\n        }\n    };\n\n    auto dijkstra_next_target = [&]()->int {\n        const int LOOKAHEAD_MARGIN = 30;\n        fill(dist.begin(), dist.end(), INF);\n        fill(prv.begin(), prv.end(), -1);\n        fill(prvDir.begin(), prvDir.end(), 0);\n        priority_queue<NodePQ> pq;\n        dist[cur] = 0;\n        pq.push({0, cur});\n\n        auto is_union_target = [&](int u)->bool {\n            int r = rowSegId[u], cc = colSegId[u];\n            if (r >= 0 && chooseRow[r] && !coveredRow[r]) return true;\n            if (cc >= 0 && chooseCol[cc] && !coveredCol[cc]) return true;\n            return false;\n        };\n        auto is_inter_target = [&](int u)->bool {\n            int r = rowSegId[u], cc = colSegId[u];\n            bool t1 = (r >= 0 && chooseRow[r] && !coveredRow[r]);\n            bool t2 = (cc >= 0 && chooseCol[cc] && !coveredCol[cc]);\n            return t1 && t2;\n        };\n\n        int bestUnion = -1, bestUnionDist = INF;\n        int bestInter = -1, bestInterDist = INF;\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (bestInter != -1 && d >= bestInterDist) break;\n            if (bestUnion != -1 && d > bestUnionDist + LOOKAHEAD_MARGIN) break;\n\n            if (is_union_target(u)) {\n                if (d < bestUnionDist) {\n                    bestUnionDist = d;\n                    bestUnion = u;\n                }\n                if (is_inter_target(u)) {\n                    if (d < bestInterDist) {\n                        bestInterDist = d;\n                        bestInter = u;\n                    }\n                }\n            }\n\n            int ui = u / W, uj = u % W;\n            if (ui-1 >= 0) {\n                int v = id(ui-1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'U'; pq.push({nd, v}); }\n                }\n            }\n            if (ui+1 < H) {\n                int v = id(ui+1, uj);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'D'; pq.push({nd, v}); }\n                }\n            }\n            if (uj-1 >= 0) {\n                int v = id(ui, uj-1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'L'; pq.push({nd, v}); }\n                }\n            }\n            if (uj+1 < W) {\n                int v = id(ui, uj+1);\n                if (isRoad[v]) {\n                    int nd = d + w[v];\n                    if (nd < dist[v]) { dist[v] = nd; prv[v] = u; prvDir[v] = 'R'; pq.push({nd, v}); }\n                }\n            }\n        }\n        if (bestInter != -1) return bestInter;\n        if (bestUnion != -1) return bestUnion;\n        return cur; // fallback\n    };\n\n    auto local_sweep = [&](){\n        // Conservative sweeping to catch nearby MVC intersections\n        const int STEP_LIMIT = 40;   // max cost per single extension\n        const int TOTAL_LIMIT = 120; // total budget per call\n        int spent = 0;\n\n        while (remain > 0 && spent < TOTAL_LIMIT) {\n            int u = cur;\n            int r = rowSegId[u], cc = colSegId[u];\n            int rp = (r >= 0 ? rowPos[u] : -1);\n            int cp = (cc >= 0 ? colPos[u] : -1);\n\n            int bestRowPos = -1, bestRowCost = INT_MAX;\n            if (r >= 0) {\n                // search left for nearest uncovered chosen col segment\n                for (int q = rp - 1; q >= 0; --q) {\n                    int v = rowSegCells[r][q];\n                    int c2 = colSegId[v];\n                    if (c2 >= 0 && chooseCol[c2] && !coveredCol[c2]) {\n                        bestRowPos = q;\n                        bestRowCost = rowCost(r, rp, q);\n                        break;\n                    }\n                }\n                // search right\n                int L = (int)rowSegCells[r].size();\n                for (int q = rp + 1; q < L; ++q) {\n                    int v = rowSegCells[r][q];\n                    int c2 = colSegId[v];\n                    if (c2 >= 0 && chooseCol[c2] && !coveredCol[c2]) {\n                        int cost = rowCost(r, rp, q);\n                        if (cost < bestRowCost) { bestRowCost = cost; bestRowPos = q; }\n                        break;\n                    }\n                }\n            }\n\n            int bestColPos = -1, bestColCost = INT_MAX;\n            if (cc >= 0) {\n                // up\n                for (int q = cp - 1; q >= 0; --q) {\n                    int v = colSegCells[cc][q];\n                    int r2 = rowSegId[v];\n                    if (r2 >= 0 && chooseRow[r2] && !coveredRow[r2]) {\n                        bestColPos = q;\n                        bestColCost = colCost(cc, cp, q);\n                        break;\n                    }\n                }\n                // down\n                int L = (int)colSegCells[cc].size();\n                for (int q = cp + 1; q < L; ++q) {\n                    int v = colSegCells[cc][q];\n                    int r2 = rowSegId[v];\n                    if (r2 >= 0 && chooseRow[r2] && !coveredRow[r2]) {\n                        int cost = colCost(cc, cp, q);\n                        if (cost < bestColCost) { bestColCost = cost; bestColPos = q; }\n                        break;\n                    }\n                }\n            }\n\n            bool doRow = false, doCol = false;\n            int extCost = INT_MAX;\n            if (bestRowPos != -1) { doRow = true; extCost = bestRowCost; }\n            if (bestColPos != -1 && bestColCost < extCost) { doRow = false; doCol = true; extCost = bestColCost; }\n\n            if (extCost == INT_MAX || extCost > STEP_LIMIT || spent + extCost > TOTAL_LIMIT) break;\n\n            if (doRow) {\n                int targetPos = bestRowPos;\n                int ci = cur / W, cj = cur % W;\n                int diff = targetPos - rp;\n                char mv = (diff > 0 ? 'R' : 'L');\n                int steps = abs(diff);\n                for (int t = 0; t < steps; ++t) {\n                    if (mv == 'R') ++cj; else --cj;\n                    int nid = id(ci, cj);\n                    mark_covered_at_cell(nid);\n                    ans.push_back(mv);\n                }\n                cur = id(ci, cj);\n                spent += extCost;\n            } else if (doCol) {\n                int targetPos = bestColPos;\n                int ci = cur / W, cj = cur % W;\n                int diff = targetPos - cp;\n                char mv = (diff > 0 ? 'D' : 'U');\n                int steps = abs(diff);\n                for (int t = 0; t < steps; ++t) {\n                    if (mv == 'D') ++ci; else --ci;\n                    int nid = id(ci, cj);\n                    mark_covered_at_cell(nid);\n                    ans.push_back(mv);\n                }\n                cur = id(ci, cj);\n                spent += extCost;\n            } else {\n                break;\n            }\n        }\n    };\n\n    // Main loop\n    while (remain > 0) {\n        int dest = dijkstra_next_target();\n        if (dest == cur) {\n            // fallback: pick any target explicitly by full dijkstra\n            dijkstra_to_single(cur); // init dist/prv from current\n            int bestD = INF; dest = -1;\n            for (int u = 0; u < M; ++u) if (isRoad[u]) {\n                int r = rowSegId[u], cc = colSegId[u];\n                bool need = (r >= 0 && chooseRow[r] && !coveredRow[r]) || (cc >= 0 && chooseCol[cc] && !coveredCol[cc]);\n                if (need && dist[u] < bestD) { bestD = dist[u]; dest = u; }\n            }\n            if (dest == -1) break;\n        } else {\n            // Already have dist/prv/prvDir from the multi-target search\n        }\n        reconstruct_and_apply(cur, dest);\n        // local sweep to grab nearby MVC segments at low extra cost\n        local_sweep();\n    }\n\n    // Return to start\n    if (cur != start) {\n        dijkstra_to_single(start);\n        reconstruct_and_apply(cur, start);\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Fast RNG for small init noise\nstruct FastRNG {\n    uint64_t x;\n    FastRNG(uint64_t seed=88172645463393265ull) : x(seed) {}\n    uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    double drand() { return (next() >> 11) * (1.0/9007199254740992.0); } // [0,1)\n    double uni(double a, double b){ return a + (b-a)*drand(); }\n};\n\n// Hungarian algorithm (min-cost assignment) on an n x n matrix\nstruct Hungarian {\n    static pair<double, vector<int>> solve(const vector<vector<double>>& a) {\n        int n = (int)a.size();\n        const double INF = 1e100;\n        vector<double> u(n+1, 0), v(n+1, 0);\n        vector<int> p(n+1, 0), way(n+1, 0);\n        for (int i = 1; i <= n; ++i) {\n            p[0] = i;\n            int j0 = 0;\n            vector<double> minv(n+1, INF);\n            vector<char> used(n+1, false);\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                double delta = INF;\n                for (int j = 1; j <= n; ++j) if (!used[j]) {\n                    double cur = a[i0-1][j-1] - u[i0] - v[j];\n                    if (cur < minv[j]) { minv[j] = cur; way[j] = j0; }\n                    if (minv[j] < delta) { delta = minv[j]; j1 = j; }\n                }\n                for (int j = 0; j <= n; ++j) {\n                    if (used[j]) { u[p[j]] += delta; v[j] -= delta; }\n                    else { minv[j] -= delta; }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n        vector<int> assignment(n, -1);\n        for (int j = 1; j <= n; ++j) if (p[j]) assignment[p[j]-1] = j-1;\n        double value = -v[0];\n        return {value, assignment};\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K, R;\n    if(!(cin >> N >> M >> K >> R)) return 0;\n\n    vector<vector<int>> D(N, vector<int>(K));\n    vector<double> sumD(N, 0.0), meanD(K, 0.0);\n    for(int i=0;i<N;i++){\n        double s=0.0;\n        for(int k=0;k<K;k++){\n            cin >> D[i][k];\n            s += D[i][k];\n            meanD[k] += D[i][k];\n        }\n        sumD[i] = s;\n    }\n    for(int k=0;k<K;k++) meanD[k] /= N;\n\n    vector<vector<int>> G(N);\n    vector<int> indeg(N, 0);\n    for(int e=0;e<R;e++){\n        int u,v; cin >> u >> v; --u; --v;\n        G[u].push_back(v);\n        indeg[v]++;\n    }\n\n    // Longest path depth (DAG with u<v)\n    vector<int> dp(N, 1), outdeg(N);\n    for(int i=N-1;i>=0;--i){\n        int best=0;\n        for(int v: G[i]) best = max(best, dp[v]);\n        dp[i] = 1 + best;\n        outdeg[i] = (int)G[i].size();\n    }\n    int dpMax = *max_element(dp.begin(), dp.end()); if(dpMax<=0) dpMax=1;\n    double sumDmax = *max_element(sumD.begin(), sumD.end()); if(sumDmax<=0) sumDmax=1.0;\n    int outMax = *max_element(outdeg.begin(), outdeg.end()); if(outMax<=0) outMax=1;\n\n    // Base priority (normalized)\n    vector<double> basePri(N);\n    const double wDepth = 1.0;\n    const double wOut = 0.3;\n    const double wDiff = 0.2;\n    for(int i=0;i<N;i++){\n        double nd = (double)dp[i] / dpMax;\n        double no = (double)outdeg[i] / outMax;\n        double nf = sumD[i] / sumDmax;\n        basePri[i] = wDepth*nd + wOut*no + wDiff*nf;\n    }\n\n    // Ready tracking (dynamic)\n    vector<char> in_ready(N, 0), started(N, 0), done(N, 0);\n    vector<int> readySince(N, 0);\n    vector<int> readyList; readyList.reserve(N);\n    for(int i=0;i<N;i++){\n        if(indeg[i] == 0){\n            in_ready[i] = 1;\n            readySince[i] = 0; // available from day 1\n            readyList.push_back(i);\n        }\n    }\n\n    // Worker state\n    vector<int> workerTask(M, -1);\n    vector<int> workerStart(M, 0);\n    vector<double> wAtAssign(M, 0.0); // predicted w (sum ReLU) at assignment time\n\n    // Skill estimates and lower bounds\n    FastRNG rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    vector<vector<double>> S(M, vector<double>(K, 0.0));\n    vector<vector<double>> sLB(M, vector<double>(K, 0.0));\n    for(int j=0;j<M;j++){\n        for(int k=0;k<K;k++){\n            double val = meanD[k] * 1.6 + rng.uni(-0.5, 0.5);\n            if(val < 0) val = 0;\n            S[j][k] = val;\n            sLB[j][k] = 0.0;\n        }\n    }\n    vector<int> obsCnt(M, 0);\n\n    // Per-task r_i estimate (residual)\n    vector<double> sumR(N, 0.0);\n    vector<int> cntR(N, 0);\n\n    // Time model helpers\n    auto expected_time_from_w = [&](double w)->double{\n        if (w <= 1e-12) return 1.0;\n        double sum = 0.0;\n        for(int r=-3;r<=3;r++){\n            double val = w + r;\n            if(val < 1.0) val = 1.0;\n            sum += val;\n        }\n        return sum / 7.0;\n    };\n    auto dEt_dw = [&](double w)->double{\n        int cnt=0;\n        for(int r=-3;r<=3;r++){\n            if (w + r > 1.0) cnt++;\n        }\n        return cnt / 7.0;\n    };\n\n    // Softplus smoothing for SGD\n    const double beta = 0.35;\n    const double invbeta = 1.0 / beta;\n    auto softplus_sum = [&](const vector<int>& dvec, const vector<double>& svec)->double{\n        double res=0.0;\n        for(int k=0;k<K;k++){\n            double x = dvec[k] - svec[k];\n            double bx = beta * x;\n            if (bx > 30.0) res += x;\n            else if (bx < -30.0) { /* ~0 */ }\n            else res += log1p(exp(bx)) * invbeta;\n        }\n        return res;\n    };\n    auto sigmoid_beta = [&](double x)->double{\n        double bx = beta * x;\n        if (bx >= 0) {\n            double e = exp(-bx);\n            return 1.0 / (1.0 + e);\n        } else {\n            double e = exp(bx);\n            return e / (1.0 + e);\n        }\n    };\n\n    // Predict expected time using clamped skills with lower bounds and per-task r-hat blending\n    const double Smax = 120.0;\n    auto compute_w = [&](int i, int j)->double{\n        double w=0.0;\n        for(int k=0;k<K;k++){\n            double sj = S[j][k];\n            if (sj < sLB[j][k]) sj = sLB[j][k];\n            double z = (double)D[i][k] - sj;\n            if (z > 0) w += z;\n        }\n        return w;\n    };\n    auto predict_time = [&](int i, int j)->double{\n        double w = compute_w(i,j);\n        if (w <= 1e-12) return 1.0;\n        if (cntR[i] <= 0){\n            return expected_time_from_w(w);\n        } else {\n            double rhat = sumR[i] / max(1, cntR[i]);\n            if (rhat < -3.0) rhat = -3.0;\n            if (rhat > 3.0) rhat = 3.0;\n            double t_det = max(1.0, w + rhat);\n            double t_exp = expected_time_from_w(w);\n            double gamma = (double)cntR[i] / ((double)cntR[i] + 3.0); // blend\n            return gamma * t_det + (1.0 - gamma) * t_exp;\n        }\n    };\n    auto ub_time = [&](int i, int j)->double{\n        // Upper bound on time using lower bounds on skills\n        double wUB = 0.0;\n        for(int k=0;k<K;k++){\n            double z = (double)D[i][k] - sLB[j][k];\n            if (z > 0) wUB += z;\n        }\n        return expected_time_from_w(wUB);\n    };\n\n    // SGD update\n    const double baseLR = 0.5;\n    auto update_skill = [&](int j, int i, int t){\n        vector<double> Sc(S[j]);\n        for(int k=0;k<K;k++) if(Sc[k] < sLB[j][k]) Sc[k] = sLB[j][k];\n        double wsoft = softplus_sum(D[i], Sc);\n        double pred = (wsoft < 0.05 ? 1.0 : expected_time_from_w(wsoft));\n        double target = max(1, t);\n        double err = pred - target;\n        double gE = dEt_dw(wsoft);\n\n        double lr = baseLR / sqrt((double)obsCnt[j] + 1.0);\n        if (t <= 1) lr *= 0.2;\n        else if (t >= 5) lr *= 1.1;\n\n        if (err > 8) err = 8;\n        if (err < -8) err = -8;\n\n        double scale = lr * gE;\n        if (scale <= 0) { obsCnt[j]++; return; }\n\n        for(int k=0;k<K;k++){\n            double s_curr = S[j][k];\n            if (s_curr < sLB[j][k]) s_curr = sLB[j][k];\n            double g = sigmoid_beta((double)D[i][k] - s_curr); // d wsoft / d s_k = -g\n            double ns = s_curr + scale * err * g;\n            if (ns < sLB[j][k]) ns = sLB[j][k];\n            if (ns < 0) ns = 0;\n            if (ns > Smax) ns = Smax;\n            S[j][k] = ns;\n        }\n        obsCnt[j]++;\n    };\n\n    // Parameters for dynamic pool and matching\n    const double ageCoef = 0.25;   // age bonus added to basePri\n    const int ageCap = 8;          // days to saturate age bonus\n    const double priWeight = 0.40; // priority weight in cost\n\n    // Risk penalties\n    const double riskCoef = 0.40;     // uncertainty penalty coefficient\n    const double riskUBCoef = 0.25;   // extra penalty from sLB-based UB\n\n    // Convex time cost and t=1 exploration\n    const double timeAlpha = 1.10;     // convexity for time cost\n    const double t1Bonus = 0.33;       // base bonus for predicted t ~ 1\n    const double t1ExploreCoef = 0.18; // extra bonus proportional to worker uncertainty\n    const double t1SureBonus = 0.45;   // strong bonus if sLB guarantees t=1\n\n    // Risk-aware idling\n    const double idleBase = 2.6;   // base idle cost\n    const double idleUncert = 0.9; // added when worker is uncertain\n\n    int day = 0;\n    vector<double> scoreBuf(N, -1.0);\n    vector<char> inPool(N, 0);\n\n    while(true){\n        day++;\n\n        // Collect free workers\n        vector<int> freeWorkers;\n        freeWorkers.reserve(M);\n        for(int j=0;j<M;j++) if(workerTask[j] == -1) freeWorkers.push_back(j);\n\n        vector<pair<int,int>> assignments; // (worker, task)\n\n        if(!freeWorkers.empty()){\n            // Build full candidate list with dynamic scores (base + age + moderate unlock)\n            vector<pair<double,int>> cand; cand.reserve(readyList.size());\n            for(int idx=0; idx<(int)readyList.size(); ++idx){\n                int i = readyList[idx];\n                if(i < 0) continue;\n                if(!in_ready[i]) continue;\n                if(started[i] || done[i]) continue;\n                int age = max(0, day - max(1, readySince[i]));\n                double ageBoost = ageCoef * (double)(min(age, ageCap)) / (double)ageCap;\n                // dynamic unlock: count children with indeg == 1 currently\n                int unlockCnt = 0;\n                for(int v: G[i]) if (indeg[v] == 1) unlockCnt++;\n                double unlockCoef = 0.25; // moderate\n                double unlockBoost = unlockCoef * min(1.0, unlockCnt / 3.0);\n                double score = basePri[i] + ageBoost + unlockBoost;\n                cand.emplace_back(score, i);\n                scoreBuf[i] = score;\n            }\n\n            int readyCnt = (int)cand.size();\n            if(readyCnt > 0){\n                int F = (int)freeWorkers.size();\n\n                // Base pool by score\n                int baseTarget = min(readyCnt, max(F * 10, 20));\n                baseTarget = min(baseTarget, 60); // cap\n                if (baseTarget < readyCnt){\n                    nth_element(cand.begin(), cand.begin() + baseTarget, cand.end(),\n                                [](const pair<double,int>& a, const pair<double,int>& b){\n                                    return a.first > b.first;\n                                });\n                } else {\n                    baseTarget = readyCnt;\n                }\n\n                // Reset inPool marks\n                for(int ii=0; ii<(int)readyList.size(); ++ii){\n                    int id = readyList[ii];\n                    if (id>=0) inPool[id] = 0;\n                }\n\n                vector<int> pool; pool.reserve(90);\n                vector<double> poolScore; poolScore.reserve(90);\n                for(int i=0;i<baseTarget;i++){\n                    int id = cand[i].second;\n                    pool.push_back(id);\n                    poolScore.push_back(cand[i].first);\n                    inPool[id] = 1;\n                }\n\n                // Augment pool with worker-centric picks from the rest\n                int unionCap = 80; // final pool cap\n                int addPerWorker = 3;\n                if ((int)pool.size() < unionCap){\n                    vector<pair<double,int>> rest;\n                    rest.reserve(readyCnt - baseTarget);\n                    for(int i=baseTarget;i<readyCnt;i++) rest.push_back(cand[i]);\n\n                    const double INF_MET = 1e100;\n                    vector<double> bestMetric(N, INF_MET);\n                    vector<int> metList; metList.reserve(readyCnt - baseTarget);\n\n                    for(int fi=0; fi<F; ++fi){\n                        int j = freeWorkers[fi];\n                        // top-k by predicted time among rest\n                        vector<pair<double,int>> topk; topk.reserve(addPerWorker+2);\n                        for(auto &rp : rest){\n                            int ti = rp.second;\n                            double tpred = predict_time(ti, j);\n                            if ((int)topk.size() < addPerWorker){\n                                topk.emplace_back(tpred, ti);\n                                if ((int)topk.size() == addPerWorker){\n                                    sort(topk.begin(), topk.end(),\n                                         [](const auto& A, const auto& B){ return A.first < B.first; });\n                                }\n                            } else if (tpred < topk.back().first){\n                                topk.back() = {tpred, ti};\n                                for (int x = (int)topk.size()-1; x>0 && topk[x].first < topk[x-1].first; --x)\n                                    swap(topk[x], topk[x-1]);\n                            }\n                        }\n                        for(auto &p : topk){\n                            int ti = p.second;\n                            if (inPool[ti]) continue;\n                            double metric = p.first - priWeight * scoreBuf[ti];\n                            if (bestMetric[ti] == INF_MET){\n                                bestMetric[ti] = metric;\n                                metList.push_back(ti);\n                            } else if (metric < bestMetric[ti]){\n                                bestMetric[ti] = metric;\n                            }\n                        }\n                    }\n                    sort(metList.begin(), metList.end(), [&](int a, int b){\n                        return bestMetric[a] < bestMetric[b];\n                    });\n                    for(int idx=0; idx<(int)metList.size() && (int)pool.size() < unionCap; ++idx){\n                        int ti = metList[idx];\n                        if (!inPool[ti]){\n                            pool.push_back(ti);\n                            poolScore.push_back(scoreBuf[ti]);\n                            inPool[ti] = 1;\n                        }\n                    }\n                }\n\n                int P = (int)pool.size();\n                if (P > 0){\n                    // Build cost matrix for Hungarian\n                    int n = max(F, P);\n                    const double BIG = 1e6;\n                    vector<vector<double>> cost(n, vector<double>(n, BIG));\n\n                    // Early-phase scaling for risk and exploration\n                    double earlyFactor = 0.0;\n                    if (day <= 6) earlyFactor = (6 - (day - 1)) / 6.0; // 1.0 -> 0.0 over days 1..6\n                    double riskCoefEff = riskCoef * (1.0 + 0.3 * earlyFactor);\n                    double riskUBCoefEff = riskUBCoef * (1.0 + 0.4 * earlyFactor);\n                    double t1ExploreEff = t1ExploreCoef * (1.0 + 0.8 * earlyFactor);\n\n                    for(int fi=0; fi<F; ++fi){\n                        int j = freeWorkers[fi];\n                        double uncert = 1.0 / sqrt((double)obsCnt[j] + 1.0);\n                        double idleCost = idleBase + idleUncert * uncert;\n                        for(int pi=0; pi<P; ++pi){\n                            int ti = pool[pi];\n                            double tpred = predict_time(ti, j);\n                            double tUB = ub_time(ti, j);\n                            // Convex time cost\n                            double cTime = pow(max(1e-9, tpred), timeAlpha);\n                            // 1-day preference and exploration bonus\n                            if (tpred <= 1.02) {\n                                cTime -= t1Bonus;\n                                cTime -= t1ExploreEff * uncert;\n                            }\n                            // Strong bonus if guaranteed 1 day by sLB\n                            if (tUB <= 1.02) cTime -= t1SureBonus;\n\n                            // Risk penalties\n                            double nf = sumD[ti] / sumDmax;\n                            double nd = (double)dp[ti] / dpMax;\n                            double risk = riskCoefEff * uncert * (0.6*nf + 0.4*nd);\n                            double ubExcess = max(0.0, tUB - 1.0);\n                            double riskUB = riskUBCoefEff * uncert * (ubExcess / 6.0);\n                            double c = cTime + risk + riskUB - priWeight * poolScore[pi];\n                            cost[fi][pi] = c;\n                        }\n                        for(int ccol=P; ccol<n; ++ccol) cost[fi][ccol] = idleCost; // dummy task (idle)\n                    }\n                    for(int r=F; r<n; ++r){\n                        for(int c=0;c<n;c++) cost[r][c] = 0.0; // dummy workers\n                    }\n\n                    auto res = Hungarian::solve(cost);\n                    vector<int> assignCols = res.second;\n\n                    vector<char> taskTaken(P, 0), workerTaken(F, 0);\n                    for(int fi=0; fi<F; ++fi){\n                        int col = assignCols[fi];\n                        if(col >= 0 && col < P){\n                            int j = freeWorkers[fi];\n                            int ti = pool[col];\n                            assignments.emplace_back(j, ti);\n                            workerTaken[fi] = 1;\n                            taskTaken[col] = 1;\n                        }\n                    }\n                    // Mark assigned tasks as no longer ready\n                    for(int pi=0; pi<P; ++pi){\n                        if(taskTaken[pi]){\n                            int ti = pool[pi];\n                            in_ready[ti] = 0;\n                        }\n                    }\n                }\n\n                // cleanup score buffer for next day (only clear used indices)\n                for(auto &p : cand) scoreBuf[p.second] = -1.0;\n            }\n        }\n\n        // Emit output\n        cout << assignments.size();\n        for(auto &p: assignments){\n            int j = p.first;\n            int i = p.second;\n            cout << \" \" << (j+1) << \" \" << (i+1);\n            workerTask[j] = i;\n            workerStart[j] = day;\n            started[i] = 1;\n            // record w at assignment time for r_i residual update\n            wAtAssign[j] = compute_w(i, j);\n        }\n        cout << '\\n';\n        cout.flush();\n\n        // Read feedback\n        int ncomp;\n        if(!(cin >> ncomp)) return 0;\n        if(ncomp == -1){\n            return 0;\n        }\n        vector<int> fins(ncomp);\n        for(int idx=0; idx<ncomp; ++idx){\n            int fj; cin >> fj; --fj;\n            fins[idx] = fj;\n        }\n        sort(fins.begin(), fins.end());\n        fins.erase(unique(fins.begin(), fins.end()), fins.end());\n\n        // Process completions\n        for(int fj : fins){\n            int i = workerTask[fj];\n            if(i < 0) continue; // safety\n            int t = day - workerStart[fj] + 1;\n\n            // Update per-task r_i estimate using w at assignment time\n            double waw = wAtAssign[fj];\n            if (waw > 0.0){\n                double ref = max(1.0, waw);\n                double r_obs = (double)t - ref;\n                if (r_obs < -3.0) r_obs = -3.0;\n                if (r_obs >  3.0) r_obs =  3.0;\n                // Update running average\n                sumR[i] += r_obs;\n                cntR[i] += 1;\n            }\n\n            // Skill update\n            update_skill(fj, i, t);\n            // Hard lower bounds only for t=1: exact s >= d\n            if (t <= 1){\n                for(int k=0;k<K;k++){\n                    if (sLB[fj][k] < D[i][k]) sLB[fj][k] = D[i][k];\n                    if (S[fj][k] < sLB[fj][k]) S[fj][k] = sLB[fj][k];\n                }\n            }\n\n            workerTask[fj] = -1;\n            wAtAssign[fj] = 0.0;\n            done[i] = 1;\n\n            // Unlock children for next day\n            for(int v: G[i]){\n                indeg[v]--;\n                if(indeg[v] == 0 && !started[v] && !done[v] && !in_ready[v]){\n                    in_ready[v] = 1;\n                    readySince[v] = day; // ready for next day\n                    readyList.push_back(v);\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 88172645463393265ull) { x = seed; }\n    inline uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int randint(int l, int r) { // inclusive\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    inline double drand() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstatic inline int manhattan(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\nstruct Order {\n    int id; // 0-based original index\n    int ax, ay, cx, cy; // pickup (a,b), drop (c,d)\n};\n\nstruct Event {\n    int oid; // 0..M-1 (index in selected array)\n    bool is_pick; // true: pickup, false: drop\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 1000;\n    const int M = 50;\n    const int OFFICE_X = 400;\n    const int OFFICE_Y = 400;\n\n    auto global_start = chrono::high_resolution_clock::now();\n    auto elapsed_sec = [&]() -> double {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - global_start).count();\n    };\n    const double GLOBAL_TL = 1.95;\n\n    vector<Order> all(N);\n    for (int i = 0; i < N; ++i) {\n        int a,b,c,d;\n        if (!(cin >> a >> b >> c >> d)) return 0;\n        all[i] = {i, a, b, c, d};\n    }\n\n    RNG rng(chrono::high_resolution_clock::now().time_since_epoch().count() * 11995408973635179863ull);\n\n    auto s_cost = [&](const Order& o)->long long {\n        long long s = 0;\n        s += manhattan(OFFICE_X, OFFICE_Y, o.ax, o.ay);\n        s += manhattan(o.ax, o.ay, o.cx, o.cy);\n        s += manhattan(o.cx, o.cy, OFFICE_X, OFFICE_Y);\n        return s;\n    };\n\n    // Rank orders by surrogate cost\n    vector<long long> sc(N);\n    vector<pair<long long,int>> score_idx;\n    score_idx.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        sc[i] = s_cost(all[i]);\n        score_idx.emplace_back(sc[i], i);\n    }\n    sort(score_idx.begin(), score_idx.end());\n\n    // Candidate pool and per-step subset size\n    const int P = min(250, N);   // pool from top s_cost\n    const int PER_STEP = 72;     // sampled per insertion step\n    const int TOPK_MAX = 6;      // maximum K for arrays\n    const int topK = 4;          // top-K pickup positions to try per candidate\n\n    vector<int> pool;\n    pool.reserve(P);\n    for (int i = 0; i < P; ++i) pool.push_back(score_idx[i].second);\n\n    // Selection + initial route via fast pair insertion\n    vector<int> selected_orig_ids; selected_orig_ids.reserve(M);\n    vector<Event> seq; seq.reserve(2*M);\n    // coords for selected orders (by internal oid)\n    vector<int> px(M), py(M), dx(M), dy(M);\n\n    auto get_seq_coord = [&](const vector<Event>& s, int idx)->pair<int,int> {\n        const Event &e = s[idx];\n        return e.is_pick ? pair<int,int>{px[e.oid], py[e.oid]} : pair<int,int>{dx[e.oid], dy[e.oid]};\n    };\n\n    auto best_insert_pair_into_current_fast = [&](const vector<Event>& s, const pair<int,int>& pC, const pair<int,int>& dC,\n                                                  int topK_local, long long &bestDelta, int &bestI, int &bestJ) {\n        int L = (int)s.size();\n        long long bestVal[TOPK_MAX]; int bestIdx[TOPK_MAX];\n        for (int t = 0; t < TOPK_MAX; ++t) { bestVal[t] = (long long)4e18; bestIdx[t] = 0; }\n        for (int i = 0; i <= L; ++i) {\n            pair<int,int> prevI = (i == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_seq_coord(s, i - 1);\n            pair<int,int> nextI = (i == L) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_seq_coord(s, i);\n            long long delta_pick = (long long)manhattan(prevI.first, prevI.second, pC.first, pC.second)\n                                 + (long long)manhattan(pC.first, pC.second, nextI.first, nextI.second)\n                                 - (long long)manhattan(prevI.first, prevI.second, nextI.first, nextI.second);\n            if (delta_pick < bestVal[topK_local-1]) {\n                bestVal[topK_local-1] = delta_pick; bestIdx[topK_local-1] = i;\n                for (int t = topK_local-1; t > 0 && bestVal[t] < bestVal[t-1]; --t) {\n                    swap(bestVal[t], bestVal[t-1]);\n                    swap(bestIdx[t], bestIdx[t-1]);\n                }\n            }\n        }\n        bestDelta = (long long)4e18; bestI = 0; bestJ = 1;\n        for (int t = 0; t < topK_local; ++t) {\n            int i = bestIdx[t];\n            long long delta_pick = bestVal[t];\n            auto coord_after_pick = [&](int pos)->pair<int,int> {\n                if (pos == i) return pC;\n                if (pos < i) return get_seq_coord(s, pos);\n                return get_seq_coord(s, pos - 1);\n            };\n            for (int j = i + 1; j <= L + 1; ++j) {\n                pair<int,int> prevJ = coord_after_pick(j - 1);\n                pair<int,int> nextJ = (j == L + 1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : coord_after_pick(j);\n                long long delta_drop = (long long)manhattan(prevJ.first, prevJ.second, dC.first, dC.second)\n                                     + (long long)manhattan(dC.first, dC.second, nextJ.first, nextJ.second)\n                                     - (long long)manhattan(prevJ.first, prevJ.second, nextJ.first, nextJ.second);\n                long long tot = delta_pick + delta_drop;\n                if (tot < bestDelta) {\n                    bestDelta = tot;\n                    bestI = i; bestJ = j;\n                }\n            }\n        }\n    };\n\n    vector<char> used_pool(N, 0);\n    for (int k = 0; k < M; ++k) {\n        // Build list of available pool ids\n        vector<int> avail;\n        avail.reserve(P);\n        for (int id : pool) if (!used_pool[id]) avail.push_back(id);\n        // Sample up to PER_STEP candidates uniformly without replacement\n        vector<int> cand;\n        int need = min(PER_STEP, (int)avail.size());\n        cand.reserve(need);\n        if ((int)avail.size() <= need) {\n            cand = avail;\n        } else {\n            // partial shuffle\n            for (int i = 0; i < (int)avail.size(); ++i) {\n                int j = rng.randint(i, (int)avail.size() - 1);\n                swap(avail[i], avail[j]);\n            }\n            for (int i = 0; i < need; ++i) cand.push_back(avail[i]);\n        }\n\n        long long bestDelta = (long long)4e18;\n        int bestIdx = -1;\n        int insI = 0, insJ = 1;\n        for (int id : cand) {\n            pair<int,int> pC = {all[id].ax, all[id].ay};\n            pair<int,int> dC = {all[id].cx, all[id].cy};\n            long long bD; int bi, bj;\n            best_insert_pair_into_current_fast(seq, pC, dC, topK, bD, bi, bj);\n            if (bD < bestDelta || (bD == bestDelta && sc[id] < sc[(bestIdx==-1)?id:bestIdx])) {\n                bestDelta = bD;\n                bestIdx = id;\n                insI = bi; insJ = bj;\n            }\n        }\n        // Insert chosen pair\n        int oid = k;\n        selected_orig_ids.push_back(bestIdx);\n        used_pool[bestIdx] = 1;\n        px[oid] = all[bestIdx].ax; py[oid] = all[bestIdx].ay;\n        dx[oid] = all[bestIdx].cx; dy[oid] = all[bestIdx].cy;\n        Event ep{oid, true}, ed{oid, false};\n        seq.insert(seq.begin() + insI, ep);\n        seq.insert(seq.begin() + insJ, ed);\n    }\n\n    // Improvement and SA setup\n\n    auto coord_of_event = [&](const Event &e) -> pair<int,int> {\n        return e.is_pick ? pair<int,int>{px[e.oid], py[e.oid]} : pair<int,int>{dx[e.oid], dy[e.oid]};\n    };\n    auto route_cost = [&](const vector<Event> &s)->long long {\n        long long t = 0;\n        int lx = OFFICE_X, ly = OFFICE_Y;\n        for (auto &e : s) {\n            auto [nx, ny] = coord_of_event(e);\n            t += manhattan(lx, ly, nx, ny);\n            lx = nx; ly = ny;\n        }\n        t += manhattan(lx, ly, OFFICE_X, OFFICE_Y);\n        return t;\n    };\n\n    int L = (int)seq.size(); // 2*M\n    vector<int> posPick(M, -1), posDel(M, -1);\n    auto recompute_positions = [&](){\n        fill(posPick.begin(), posPick.end(), -1);\n        fill(posDel.begin(), posDel.end(), -1);\n        for (int i = 0; i < (int)seq.size(); ++i) {\n            if (seq[i].is_pick) posPick[seq[i].oid] = i;\n            else posDel[seq[i].oid] = i;\n        }\n        L = (int)seq.size();\n    };\n    recompute_positions();\n\n    auto get_coord_by_index = [&](int idx)->pair<int,int>{\n        const Event &e = seq[idx];\n        return e.is_pick ? pair<int,int>{px[e.oid], py[e.oid]} : pair<int,int>{dx[e.oid], dy[e.oid]};\n    };\n\n    // Single-event relocation delta\n    auto delta_move_single = [&](int p, int q)->long long {\n        const Event &ev = seq[p];\n        int oid = ev.oid;\n        if (ev.is_pick) {\n            int pos_del_prime = posDel[oid] - 1; // after removal\n            if (q > pos_del_prime) return (long long)4e18; // invalid\n        } else {\n            int pos_pick_prime = posPick[oid];\n            if (q <= pos_pick_prime) return (long long)4e18; // invalid\n        }\n        auto curr = get_coord_by_index(p);\n        pair<int,int> prevc = (p == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p-1);\n        pair<int,int> nextc = (p == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p+1);\n        long long delta = 0;\n        delta += (long long)manhattan(prevc.first, prevc.second, nextc.first, nextc.second)\n               - (long long)manhattan(prevc.first, prevc.second, curr.first, curr.second)\n               - (long long)manhattan(curr.first, curr.second, nextc.first, nextc.second);\n\n        pair<int,int> prev2, next2;\n        if (q == 0) prev2 = {OFFICE_X, OFFICE_Y};\n        else {\n            int j1 = q - 1;\n            int orig1 = (j1 < p ? j1 : j1 + 1);\n            prev2 = get_coord_by_index(orig1);\n        }\n        if (q == L-1) next2 = {OFFICE_X, OFFICE_Y};\n        else {\n            int orig2 = (q < p ? q : q + 1);\n            next2 = get_coord_by_index(orig2);\n        }\n        delta += (long long)manhattan(prev2.first, prev2.second, curr.first, curr.second)\n               + (long long)manhattan(curr.first, curr.second, next2.first, next2.second)\n               - (long long)manhattan(prev2.first, prev2.second, next2.first, next2.second);\n\n        return delta;\n    };\n\n    auto apply_move_single = [&](int p, int q) {\n        Event ev = seq[p];\n        seq.erase(seq.begin() + p);\n        seq.insert(seq.begin() + q, ev);\n        recompute_positions();\n    };\n\n    // Helpers for pair removal mapping\n    auto get_after_removals_coord = [&](int p1, int p2, int k)->pair<int,int>{\n        int orig;\n        if (k < p1) orig = k;\n        else if (k < p2 - 1) orig = k + 1;\n        else orig = k + 2;\n        return get_coord_by_index(orig);\n    };\n    auto get_after_removals_and_pick_coord = [&](int p1, int p2, int i, const pair<int,int>& pickCoord, int k)->pair<int,int>{\n        if (k == i) return pickCoord;\n        if (k < i) return get_after_removals_coord(p1, p2, k);\n        return get_after_removals_coord(p1, p2, k - 1);\n    };\n\n    // Pair relocation delta (remove both, insert at i<j)\n    auto delta_move_pair = [&](int oid, int i, int j)->long long {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        if (!(0 <= p1 && p1 < p2 && p2 < L)) return (long long)4e18;\n        int L2 = L - 2;\n        if (i < 0 || i > L2) return (long long)4e18;\n        if (j <= i || j > L2 + 1) return (long long)4e18;\n\n        auto curr1 = get_coord_by_index(p1);\n        pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n        long long delta = 0;\n        delta += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n               - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n               - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n\n        auto curr2 = get_coord_by_index(p2);\n        pair<int,int> prev2prime, next2prime;\n        if (p2 == p1 + 1) {\n            prev2prime = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        } else {\n            prev2prime = get_coord_by_index(p2 - 1);\n        }\n        next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n        delta += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n               - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n               - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n\n        // Insertion\n        auto pC = pair<int,int>{px[oid], py[oid]};\n        auto dC = pair<int,int>{dx[oid], dy[oid]};\n        pair<int,int> prevI = (i == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i - 1);\n        pair<int,int> nextI = (i == L2) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i);\n        delta += (long long)manhattan(prevI.first, prevI.second, pC.first, pC.second)\n               + (long long)manhattan(pC.first, pC.second, nextI.first, nextI.second)\n               - (long long)manhattan(prevI.first, prevI.second, nextI.first, nextI.second);\n\n        pair<int,int> prevJ = (j == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j - 1);\n        pair<int,int> nextJ = (j == L2 + 1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j);\n        delta += (long long)manhattan(prevJ.first, prevJ.second, dC.first, dC.second)\n               + (long long)manhattan(dC.first, dC.second, nextJ.first, nextJ.second)\n               - (long long)manhattan(prevJ.first, prevJ.second, nextJ.first, nextJ.second);\n\n        return delta;\n    };\n\n    auto apply_move_pair = [&](int oid, int i, int j) {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        seq.erase(seq.begin() + p2);\n        seq.erase(seq.begin() + p1);\n        Event ep{oid, true}, ed{oid, false};\n        seq.insert(seq.begin() + i, ep);\n        seq.insert(seq.begin() + j, ed);\n        recompute_positions();\n    };\n\n    // Fast best insertion after removal (top-K pickup positions)\n    auto best_insertion_after_removal_fast = [&](int p1, int p2, const pair<int,int>& pC, const pair<int,int>& dC, int topK_local,\n                                                 long long &bestDelta, int &bestI, int &bestJ) {\n        int L2 = L - 2;\n        long long bestVal[TOPK_MAX]; int bestIdx[TOPK_MAX];\n        for (int t = 0; t < TOPK_MAX; ++t) { bestVal[t] = (long long)4e18; bestIdx[t] = 0; }\n        for (int i = 0; i <= L2; ++i) {\n            pair<int,int> prevI = (i == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i - 1);\n            pair<int,int> nextI = (i == L2) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_coord(p1, p2, i);\n            long long delta_pick = (long long)manhattan(prevI.first, prevI.second, pC.first, pC.second)\n                                 + (long long)manhattan(pC.first, pC.second, nextI.first, nextI.second)\n                                 - (long long)manhattan(prevI.first, prevI.second, nextI.first, nextI.second);\n            if (delta_pick < bestVal[topK_local-1]) {\n                bestVal[topK_local-1] = delta_pick; bestIdx[topK_local-1] = i;\n                for (int t = topK_local-1; t > 0 && bestVal[t] < bestVal[t-1]; --t) {\n                    swap(bestVal[t], bestVal[t-1]);\n                    swap(bestIdx[t], bestIdx[t-1]);\n                }\n            }\n        }\n        bestDelta = (long long)4e18; bestI = 0; bestJ = 1;\n        for (int t = 0; t < topK_local; ++t) {\n            int i = bestIdx[t];\n            long long delta_pick = bestVal[t];\n            for (int j = i + 1; j <= L2 + 1; ++j) {\n                pair<int,int> prevJ = (j == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j - 1);\n                pair<int,int> nextJ = (j == L2 + 1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_after_removals_and_pick_coord(p1, p2, i, pC, j);\n                long long delta_drop = (long long)manhattan(prevJ.first, prevJ.second, dC.first, dC.second)\n                                     + (long long)manhattan(dC.first, dC.second, nextJ.first, nextJ.second)\n                                     - (long long)manhattan(prevJ.first, prevJ.second, nextJ.first, nextJ.second);\n                long long tot = delta_pick + delta_drop;\n                if (tot < bestDelta) {\n                    bestDelta = tot;\n                    bestI = i; bestJ = j;\n                }\n            }\n        }\n    };\n\n    auto delta_pair_best_fast = [&](int oid, long long &bestDelta, int &bi, int &bj) -> long long {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        // removal delta\n        auto curr1 = get_coord_by_index(p1);\n        pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n        long long delta_rem = 0;\n        delta_rem += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n                   - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n                   - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n        auto curr2 = get_coord_by_index(p2);\n        pair<int,int> prev2prime = (p2 == p1 + 1) ? ((p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1))\n                                                  : get_coord_by_index(p2 - 1);\n        pair<int,int> next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n        delta_rem += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n                   - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n                   - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n\n        long long bestIns; int iBest, jBest;\n        best_insertion_after_removal_fast(p1, p2, {px[oid], py[oid]}, {dx[oid], dy[oid]}, topK, bestIns, iBest, jBest);\n        bestDelta = delta_rem + bestIns;\n        bi = iBest; bj = jBest;\n        return bestDelta;\n    };\n\n    // Small order-replacement stage: replace selected order with an outside candidate if it strictly improves route\n    vector<char> in_selected(N, 0);\n    for (int i = 0; i < M; ++i) in_selected[selected_orig_ids[i]] = 1;\n    // Build outside candidate list from top of score ranking\n    vector<int> cand_out;\n    int P2 = min(400, N);\n    cand_out.reserve(P2);\n    for (int i = 0; i < P2; ++i) {\n        int id = score_idx[i].second;\n        if (!in_selected[id]) cand_out.push_back(id);\n    }\n\n    auto removal_delta_for_oid = [&](int oid)->long long {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        auto curr1 = get_coord_by_index(p1);\n        pair<int,int> prev1 = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        pair<int,int> next1 = (p1 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1+1);\n        long long delta = 0;\n        delta += (long long)manhattan(prev1.first, prev1.second, next1.first, next1.second)\n               - (long long)manhattan(prev1.first, prev1.second, curr1.first, curr1.second)\n               - (long long)manhattan(curr1.first, curr1.second, next1.first, next1.second);\n        auto curr2 = get_coord_by_index(p2);\n        pair<int,int> prev2prime, next2prime;\n        if (p2 == p1 + 1) {\n            prev2prime = (p1 == 0) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p1-1);\n        } else {\n            prev2prime = get_coord_by_index(p2 - 1);\n        }\n        next2prime = (p2 == L-1) ? pair<int,int>{OFFICE_X, OFFICE_Y} : get_coord_by_index(p2 + 1);\n        delta += (long long)manhattan(prev2prime.first, prev2prime.second, next2prime.first, next2prime.second)\n               - (long long)manhattan(prev2prime.first, prev2prime.second, curr2.first, curr2.second)\n               - (long long)manhattan(curr2.first, curr2.second, next2prime.first, next2prime.second);\n        return delta;\n    };\n\n    auto apply_replace_order = [&](int oid, int new_orig_id, int insI, int insJ) {\n        int p1 = posPick[oid];\n        int p2 = posDel[oid];\n        // remove old\n        seq.erase(seq.begin() + p2);\n        seq.erase(seq.begin() + p1);\n        // update coords and mapping\n        selected_orig_ids[oid] = new_orig_id;\n        px[oid] = all[new_orig_id].ax; py[oid] = all[new_orig_id].ay;\n        dx[oid] = all[new_orig_id].cx; dy[oid] = all[new_orig_id].cy;\n        // insert new\n        Event ep{oid, true}, ed{oid, false};\n        seq.insert(seq.begin() + insI, ep);\n        seq.insert(seq.begin() + insJ, ed);\n        recompute_positions();\n    };\n\n    double replace_budget = 0.25; // seconds\n    double replace_end = elapsed_sec() + replace_budget;\n    if (!cand_out.empty()) {\n        while (elapsed_sec() < replace_end) {\n            int oid = rng.randint(0, M - 1);\n            if (cand_out.empty()) break;\n            // pick a random candidate not selected\n            int idx = rng.randint(0, (int)cand_out.size() - 1);\n            int new_id = cand_out[idx];\n            if (in_selected[new_id]) {\n                // refresh cand_out lazily\n                cand_out.clear();\n                for (int i = 0; i < P2; ++i) {\n                    int id = score_idx[i].second;\n                    if (!in_selected[id]) cand_out.push_back(id);\n                }\n                if (cand_out.empty()) break;\n                continue;\n            }\n            long long delta_rem = removal_delta_for_oid(oid);\n            int p1 = posPick[oid];\n            int p2 = posDel[oid];\n            long long bestIns; int bi, bj;\n            pair<int,int> newP{all[new_id].ax, all[new_id].ay};\n            pair<int,int> newD{all[new_id].cx, all[new_id].cy};\n            best_insertion_after_removal_fast(p1, p2, newP, newD, topK, bestIns, bi, bj);\n            long long delta_tot = delta_rem + bestIns;\n            if (delta_tot < 0) {\n                int old_orig = selected_orig_ids[oid];\n                in_selected[old_orig] = 0;\n                in_selected[new_id] = 1;\n                apply_replace_order(oid, new_id, bi, bj);\n                // refresh cand_out maybe (optional)\n            }\n        }\n    }\n\n    // Quick local improvement: one pass of fast best pair relocations\n    for (int oid = 0; oid < M; ++oid) {\n        long long bestDelta; int bi, bj;\n        long long d = delta_pair_best_fast(oid, bestDelta, bi, bj);\n        if (d < 0) apply_move_pair(oid, bi, bj);\n    }\n\n    // Extra cheap local improvement: best single-event relocation for each pickup and delivery\n    auto single_improve_pass = [&](){\n        bool improved = false;\n        // deliveries\n        for (int oid = 0; oid < M; ++oid) {\n            int p = posDel[oid];\n            long long bestD = 0;\n            int bestQ = p;\n            for (int q = 0; q <= L - 1; ++q) if (q != p) {\n                long long d = delta_move_single(p, q);\n                if (d == (long long)4e18) continue;\n                if (q > posPick[oid]) { // valid delivered after its pick\n                    if (bestQ == p || d < bestD) { bestD = d; bestQ = q; }\n                }\n            }\n            if (bestQ != p && bestD < 0) {\n                apply_move_single(p, bestQ);\n                improved = true;\n            }\n        }\n        // pickups\n        for (int oid = 0; oid < M; ++oid) {\n            int p = posPick[oid];\n            long long bestD = 0;\n            int bestQ = p;\n            for (int q = 0; q <= L - 1; ++q) if (q != p) {\n                long long d = delta_move_single(p, q);\n                if (d == (long long)4e18) continue;\n                if (q <= posDel[oid] - 1) { // pickup before its delivery\n                    if (bestQ == p || d < bestD) { bestD = d; bestQ = q; }\n                }\n            }\n            if (bestQ != p && bestD < 0) {\n                apply_move_single(p, bestQ);\n                improved = true;\n            }\n        }\n        return improved;\n    };\n    for (int t = 0; t < 2; ++t) {\n        if (!single_improve_pass()) break;\n    }\n\n    // SA setup\n    long long cur_cost = route_cost(seq);\n    long long best_cost = cur_cost;\n    vector<Event> best_seq = seq;\n\n    const double T0 = 180.0;\n    const double T1 = 1.0;\n\n    // Lambda to get coord at index or office if out of bounds\n    auto coordAtIdxOrOfficeLocal = [&](int idx)->pair<int,int> {\n        if (idx < 0 || idx >= L) return pair<int,int>{OFFICE_X, OFFICE_Y};\n        return get_coord_by_index(idx);\n    };\n\n    // Swap move: try swapping nodes at positions p<q with precedence checks; O(1) delta\n    auto delta_swap_nodes = [&](int p, int q)->long long {\n        if (p == q) return (long long)4e18;\n        if (p > q) swap(p, q);\n        const Event &Aev = seq[p];\n        const Event &Bev = seq[q];\n\n        // validity checks for precedence after swap\n        if (Aev.is_pick && Bev.is_pick) {\n            if (!(posDel[Aev.oid] > q && posDel[Bev.oid] > p)) return (long long)4e18;\n        } else if (!Aev.is_pick && !Bev.is_pick) {\n            if (!(posPick[Aev.oid] < q && posPick[Bev.oid] < p)) return (long long)4e18;\n        } else if (Aev.is_pick && !Bev.is_pick) {\n            if (!(q < posDel[Aev.oid] && posPick[Bev.oid] < p)) return (long long)4e18;\n        } else { // A is drop, B is pick\n            if (!(p < posDel[Bev.oid] && posPick[Aev.oid] < q)) return (long long)4e18;\n        }\n\n        auto A = get_coord_by_index(p);\n        auto B = get_coord_by_index(q);\n        auto up = coordAtIdxOrOfficeLocal(p-1);\n        auto ap = coordAtIdxOrOfficeLocal(p+1);\n        auto vq = coordAtIdxOrOfficeLocal(q-1);\n        auto bq = coordAtIdxOrOfficeLocal(q+1);\n\n        long long oldSum = 0, newSum = 0;\n        if (q == p + 1) {\n            // adjacent\n            oldSum += manhattan(up.first, up.second, A.first, A.second);\n            oldSum += manhattan(A.first, A.second, B.first, B.second);\n            oldSum += manhattan(B.first, B.second, bq.first, bq.second);\n\n            newSum += manhattan(up.first, up.second, B.first, B.second);\n            newSum += manhattan(B.first, B.second, A.first, A.second);\n            newSum += manhattan(A.first, A.second, bq.first, bq.second);\n        } else {\n            oldSum += manhattan(up.first, up.second, A.first, A.second);\n            oldSum += manhattan(A.first, A.second, ap.first, ap.second);\n            oldSum += manhattan(vq.first, vq.second, B.first, B.second);\n            oldSum += manhattan(B.first, B.second, bq.first, bq.second);\n\n            newSum += manhattan(up.first, up.second, B.first, B.second);\n            newSum += manhattan(B.first, B.second, ap.first, ap.second);\n            newSum += manhattan(vq.first, vq.second, A.first, A.second);\n            newSum += manhattan(A.first, A.second, bq.first, bq.second);\n        }\n        return newSum - oldSum;\n    };\n\n    auto apply_swap_nodes = [&](int p, int q) {\n        if (p == q) return;\n        if (p > q) swap(p, q);\n        Event A = seq[p], B = seq[q];\n        swap(seq[p], seq[q]);\n        if (A.is_pick) posPick[A.oid] = q; else posDel[A.oid] = q;\n        if (B.is_pick) posPick[B.oid] = p; else posDel[B.oid] = p;\n        // L unchanged\n    };\n\n    int iter = 0;\n    double last_check = 0.0;\n    while (true) {\n        if ((iter & 1023) == 0) {\n            double t = elapsed_sec();\n            if (t > GLOBAL_TL) break;\n            last_check = t;\n        }\n        ++iter;\n        double tfrac = min(1.0, last_check / GLOBAL_TL);\n        double temp = T0 + (T1 - T0) * tfrac;\n\n        int moveType = rng.randint(0, 99);\n        bool accepted = false;\n        long long d = 0;\n\n        if (moveType < 30) {\n            // Single-event relocation\n            int p = rng.randint(0, L - 1);\n            int Lp = L - 1;\n            if (Lp <= 0) continue;\n            int q = rng.randint(0, Lp);\n            if (q == p) continue;\n            d = delta_move_single(p, q);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_single(p, q);\n                cur_cost += d;\n                accepted = true;\n            }\n        } else if (moveType < 80) {\n            // Random pair relocation\n            int oid = rng.randint(0, M - 1);\n            if (L < 4) continue;\n            int i = rng.randint(0, L - 2);\n            int j = rng.randint(i + 1, L - 1);\n            d = delta_move_pair(oid, i, j);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_pair(oid, i, j);\n                cur_cost += d;\n                accepted = true;\n            }\n        } else if (moveType < 98) {\n            // Node swap\n            int p = rng.randint(0, L - 1);\n            int q = rng.randint(0, L - 1);\n            if (p == q) continue;\n            d = delta_swap_nodes(p, q);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_swap_nodes(p, q);\n                cur_cost += d;\n                accepted = true;\n            }\n        } else {\n            // Rare fast best pair relocation\n            int oid = rng.randint(0, M - 1);\n            long long bestDelta; int bi, bj;\n            d = delta_pair_best_fast(oid, bestDelta, bi, bj);\n            if (d == (long long)4e18) continue;\n            if (d <= 0 || exp(-(double)d / temp) > rng.drand()) {\n                apply_move_pair(oid, bi, bj);\n                cur_cost += d;\n                accepted = true;\n            }\n        }\n\n        if (accepted && cur_cost < best_cost) {\n            best_cost = cur_cost;\n            best_seq = seq;\n        }\n    }\n\n    // Apply final cheap improvement pass on the best sequence and keep it\n    seq = best_seq;\n    recompute_positions();\n    auto single_improve_pass2 = [&](){\n        bool improved = false;\n        for (int oid = 0; oid < M; ++oid) {\n            int p = posDel[oid];\n            long long bestD = 0; int bestQ = p;\n            for (int q = 0; q <= L - 1; ++q) if (q != p) {\n                long long d = delta_move_single(p, q);\n                if (d == (long long)4e18) continue;\n                if (q > posPick[oid]) { if (bestQ == p || d < bestD) { bestD = d; bestQ = q; } }\n            }\n            if (bestQ != p && bestD < 0) { apply_move_single(p, bestQ); improved = true; }\n        }\n        for (int oid = 0; oid < M; ++oid) {\n            int p = posPick[oid];\n            long long bestD = 0; int bestQ = p;\n            for (int q = 0; q <= L - 1; ++q) if (q != p) {\n                long long d = delta_move_single(p, q);\n                if (d == (long long)4e18) continue;\n                if (q <= posDel[oid] - 1) { if (bestQ == p || d < bestD) { bestD = d; bestQ = q; } }\n            }\n            if (bestQ != p && bestD < 0) { apply_move_single(p, bestQ); improved = true; }\n        }\n        return improved;\n    };\n    for (int t = 0; t < 2; ++t) {\n        if (!single_improve_pass2()) break;\n    }\n\n    // Output\n    cout << M;\n    for (int i = 0; i < M; ++i) cout << ' ' << (selected_orig_ids[i] + 1);\n    cout << '\\n';\n\n    int n = 2*M + 2;\n    cout << n << ' ' << OFFICE_X << ' ' << OFFICE_Y;\n    for (int i = 0; i < (int)seq.size(); ++i) {\n        auto [x, y] = coord_of_event(seq[i]);\n        cout << ' ' << x << ' ' << y;\n    }\n    cout << ' ' << OFFICE_X << ' ' << OFFICE_Y << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\n#include <boost/dynamic_bitset.hpp>\nusing namespace std;\n\n// Fixed sizes\nstatic constexpr int N = 400;\nstatic constexpr int M = 5 * (N - 1);\n\nstruct Edge {\n    int u, v;\n    int d;              // rounded Euclidean distance\n    int level = 6;      // 1..5 if chosen in k-th spanning tree (from complete graph), else 6\n};\n\n// DSU with cut-edge bitsets per component: inc[C] is XOR of per-vertex incident edges in C\nstruct DSU {\n    vector<int> parent, sz;\n    vector<boost::dynamic_bitset<unsigned long long>> inc; // cut edges per component\n    DSU(int n, int m_bits) : parent(n), sz(n,1), inc(n, boost::dynamic_bitset<unsigned long long>(m_bits)) {\n        iota(parent.begin(), parent.end(), 0);\n    }\n    int find(int x){\n        while(parent[x]!=x){\n            parent[x]=parent[parent[x]];\n            x=parent[x];\n        }\n        return x;\n    }\n    int unite(int a, int b){\n        a=find(a); b=find(b);\n        if(a==b) return a;\n        if(sz[a] < sz[b]) swap(a,b);\n        inc[a] ^= inc[b]; // exact cut update\n        parent[b] = a;\n        sz[a] += sz[b];\n        return a;\n    }\n};\n\n// Count up to cap set bits strictly after pos\nstatic inline int count_suffix_capped(const boost::dynamic_bitset<unsigned long long>& bs, int pos, int cap) {\n    int c = 0;\n    auto idx = bs.find_next(pos);\n    while (idx != boost::dynamic_bitset<unsigned long long>::npos) {\n        ++c;\n        if (c >= cap) break;\n        idx = bs.find_next(idx);\n    }\n    return c;\n}\n\n// Quick check if there exists a set bit strictly after pos\nstatic inline bool has_future(const boost::dynamic_bitset<unsigned long long>& bs, int pos) {\n    auto idx = bs.find_next(pos);\n    return idx != boost::dynamic_bitset<unsigned long long>::npos;\n}\n\nstatic inline int round_int(double x) {\n    return (int)llround(x);\n}\n\n// Assign levels 1..5 by computing 5 MSTs on the complete geometric graph (weights = d)\n// and mapping them back to edges in E.\nstatic void assign_levels_from_complete_graph(const vector<int>& x, const vector<int>& y, vector<Edge>& edges) {\n    struct FEdge { int u, v, d; int idx; };\n    vector<FEdge> all;\n    all.reserve(N*(N-1)/2);\n    for (int u = 0; u < N; ++u) {\n        for (int v = u+1; v < N; ++v) {\n            long long dx = x[u] - x[v];\n            long long dy = y[u] - y[v];\n            int d = round_int(sqrt((double)dx*dx + (double)dy*dy));\n            if (d <= 0) d = 1;\n            all.push_back({u,v,d,(int)all.size()});\n        }\n    }\n    stable_sort(all.begin(), all.end(), [](const FEdge& a, const FEdge& b){\n        if (a.d != b.d) return a.d < b.d;\n        if (a.u != b.u) return a.u < b.u;\n        return a.v < b.v;\n    });\n\n    vector<char> removed(all.size(), 0);\n    auto key = [](int u, int v)->uint64_t { return ((uint64_t)u << 20) | (uint64_t)v; };\n    unordered_map<uint64_t,int> level_of_pair;\n    level_of_pair.reserve(M*2);\n    level_of_pair.max_load_factor(0.7f);\n\n    for (int lev = 1; lev <= 5; ++lev) {\n        vector<int> par(N), rnk(N,0);\n        iota(par.begin(), par.end(), 0);\n        function<int(int)> fnd = [&](int a){ return par[a]==a ? a : par[a]=fnd(par[a]); };\n        auto uni = [&](int a, int b)->bool {\n            a=fnd(a); b=fnd(b);\n            if (a==b) return false;\n            if (rnk[a] < rnk[b]) swap(a,b);\n            par[b] = a;\n            if (rnk[a]==rnk[b]) rnk[a]++;\n            return true;\n        };\n        int picked = 0;\n        for (size_t i = 0; i < all.size(); ++i) {\n            if (removed[i]) continue;\n            const auto& fe = all[i];\n            if (uni(fe.u, fe.v)) {\n                removed[i] = 1;\n                level_of_pair[key(fe.u, fe.v)] = lev;\n                ++picked;\n                if (picked == N-1) break;\n            }\n        }\n    }\n\n    for (auto &e : edges) {\n        uint64_t k = key(e.u, e.v);\n        auto it = level_of_pair.find(k);\n        if (it != level_of_pair.end()) e.level = it->second;\n        else e.level = 6;\n    }\n}\n\n// Temporary DSU for connectivity check among current components using only future edges\nstruct TempDSU {\n    vector<int> par;\n    int comps;\n    explicit TempDSU(int n=0) { init(n); }\n    void init(int n) {\n        par.resize(n);\n        iota(par.begin(), par.end(), 0);\n        comps = n;\n    }\n    int find(int a){\n        while(par[a]!=a){ par[a]=par[par[a]]; a=par[a]; }\n        return a;\n    }\n    bool unite(int a, int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        par[b]=a;\n        --comps;\n        return true;\n    }\n};\n\n// Check if rejecting current edge keeps the \"future graph\" connected:\n// Nodes = current DSU components; Edges = edges with index > i connecting different components.\nstatic bool future_connected_after_reject(int i, DSU& dsu, const vector<Edge>& edges) {\n    static vector<int> root_idx;\n    root_idx.assign(N, -1);\n    int K = 0;\n    for (int v = 0; v < N; v++) {\n        if (dsu.parent[v] == v) { // v is a root\n            root_idx[v] = K++;\n        }\n    }\n    if (K <= 1) return true;\n\n    TempDSU tmp(K);\n\n    for (int j = i + 1; j < M; j++) {\n        int ru = dsu.find(edges[j].u);\n        int rv = dsu.find(edges[j].v);\n        if (ru == rv) continue;\n        int iu = root_idx[ru];\n        int iv = root_idx[rv];\n        if (iu < 0 || iv < 0) continue; // safety\n        if (tmp.unite(iu, iv) && tmp.comps == 1) {\n            return true; // connected\n        }\n    }\n    return tmp.comps == 1;\n}\n\n// Deterministic PRNG for perturbed MSTs\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed=88172645463393265ULL): x(seed) {}\n    uint64_t next() {\n        uint64_t y = x;\n        y ^= y << 7;\n        y ^= y >> 9;\n        return x = y;\n    }\n    double next_double() {\n        return (next() >> 11) * (1.0 / (1ULL << 53));\n    }\n    double uniform(double a, double b) { return a + (b - a) * next_double(); }\n};\n\n// Build multiple perturbed MSTs on E (weights near d) to compute frequency\nstatic vector<int> mst_frequency(const vector<Edge>& edges, int rounds, double sigma) {\n    vector<int> freq(M, 0);\n    vector<int> idx(M);\n    vector<double> w(M);\n    XorShift64 rng(2025813ULL); // deterministic\n\n    for (int r = 0; r < rounds; r++) {\n        for (int i = 0; i < M; i++) {\n            double noise = rng.uniform(-sigma, sigma);\n            w[i] = edges[i].d * (1.0 + noise);\n            idx[i] = i;\n        }\n        sort(idx.begin(), idx.end(), [&](int a, int b){\n            if (w[a] != w[b]) return w[a] < w[b];\n            return a < b;\n        });\n        // DSU\n        vector<int> par(N), rnk(N,0);\n        iota(par.begin(), par.end(), 0);\n        function<int(int)> fnd = [&](int x){ return par[x]==x ? x : par[x]=fnd(par[x]); };\n        auto uni = [&](int a, int b)->bool {\n            a=fnd(a); b=fnd(b);\n            if(a==b) return false;\n            if(rnk[a]<rnk[b]) swap(a,b);\n            par[b]=a;\n            if(rnk[a]==rnk[b]) rnk[a]++;\n            return true;\n        };\n        int picked = 0;\n        for (int id : idx) {\n            if (uni(edges[id].u, edges[id].v)) {\n                freq[id]++;\n                picked++;\n                if (picked == N-1) break;\n            }\n        }\n    }\n    return freq;\n}\n\n// Expected-MST inclusion test for current edge i with length l:\n// Contract current accepted edges (DSU components). Consider remaining edges j>i with weight 2*d_j.\n// Process all with 2*d_j < l; if after that, endpoints of edge i are still in different components,\n// then edge i would be included by the expected MST -> return true.\nstatic bool expected_mst_includes_edge(int i, int l, DSU& dsu, const vector<Edge>& edges, const vector<int>& orderBy2d) {\n    static vector<int> root_idx;\n    root_idx.assign(N, -1);\n    int K = 0;\n    for (int v = 0; v < N; v++) {\n        if (dsu.parent[v] == v) {\n            root_idx[v] = K++;\n        }\n    }\n    if (K <= 1) return false;\n\n    vector<int> par(K);\n    iota(par.begin(), par.end(), 0);\n    function<int(int)> fnd = [&](int a){ while(par[a]!=a){ par[a]=par[par[a]]; a=par[a]; } return a; };\n    auto uni = [&](int a, int b){ a=fnd(a); b=fnd(b); if(a==b) return false; par[b]=a; return true; };\n\n    const int ru = dsu.find(edges[i].u);\n    const int rv = dsu.find(edges[i].v);\n    const int iu = root_idx[ru];\n    const int iv = root_idx[rv];\n\n    for (int eid : orderBy2d) {\n        if (eid <= i) continue;\n        int w2 = 2 * edges[eid].d;\n        if (w2 >= l) break;\n        int r1 = dsu.find(edges[eid].u);\n        int r2 = dsu.find(edges[eid].v);\n        if (r1 == r2) continue;\n        int a = root_idx[r1], b = root_idx[r2];\n        if (a < 0 || b < 0) continue;\n        uni(a, b);\n    }\n    return fnd(iu) != fnd(iv);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Read coordinates\n    vector<int> x(N), y(N);\n    for (int i = 0; i < N; i++) {\n        if (!(cin >> x[i] >> y[i])) {\n            return 0;\n        }\n    }\n\n    // Read edges and compute distances\n    vector<Edge> edges(M);\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        edges[i].u = u;\n        edges[i].v = v;\n        long long dx = x[u] - x[v];\n        long long dy = y[u] - y[v];\n        double dist = sqrt((double)dx * dx + (double)dy * dy);\n        int d = round_int(dist);\n        if (d <= 0) d = 1;\n        edges[i].d = d;\n    }\n\n    // Assign 5 spanning tree levels using complete graph MSTs (mirrors generator)\n    assign_levels_from_complete_graph(x, y, edges);\n\n    // MST frequency over perturbed weights (on E)\n    const int FREQ_ROUNDS = 16;\n    const double FREQ_SIGMA = 0.03;\n    vector<int> freq = mst_frequency(edges, FREQ_ROUNDS, FREQ_SIGMA);\n\n    // Distance quantiles for small/large d adjustments\n    vector<int> all_d; all_d.reserve(M);\n    for (auto &e : edges) all_d.push_back(e.d);\n    vector<int> tmp = all_d;\n    nth_element(tmp.begin(), tmp.begin() + M/4, tmp.end());\n    int q25 = tmp[M/4];\n    tmp = all_d;\n    nth_element(tmp.begin(), tmp.begin() + (3*M)/4, tmp.end());\n    int q75 = tmp[(3*M)/4];\n\n    // Pre-sort edges by 2*d ascending for expected-MST scan\n    vector<int> orderBy2d(M);\n    iota(orderBy2d.begin(), orderBy2d.end(), 0);\n    stable_sort(orderBy2d.begin(), orderBy2d.end(), [&](int a, int b){\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n\n    // DSU with cut-bitsets\n    DSU dsu(N, M);\n    for (int i = 0; i < M; i++) {\n        dsu.inc[edges[i].u].set(i);\n        dsu.inc[edges[i].v].set(i);\n    }\n\n    // Heuristic parameters (tuned moderately)\n    static const double levelAdd[7] = {0.0, 0.26, 0.18, 0.12, 0.07, 0.03, 0.0}; // index 1..5 used\n    const double smallDAdd    = 0.04;\n    const double largeDPen    = 0.05;\n    const double tRelaxCoeff  = 0.07;  // mild relaxation over time\n    const int    kCapCount    = 256;\n    const double freqScale    = 0.010; // per-round contribution (max ~0.16)\n\n    auto k_small_bonus = [](int kmin)->double{\n        if (kmin <= 1) return 0.18;\n        if (kmin == 2) return 0.15;\n        if (kmin == 3) return 0.08;\n        if (kmin == 4) return 0.04;\n        return 0.0;\n    };\n\n    boost::dynamic_bitset<unsigned long long> pairBS(M);\n\n    // Interactive loop\n    for (int i = 0; i < M; i++) {\n        int l;\n        if (!(cin >> l)) return 0;\n\n        const Edge &e = edges[i];\n        int ru = dsu.find(e.u);\n        int rv = dsu.find(e.v);\n\n        int decision = 0;\n\n        if (ru == rv) {\n            // Reject to avoid cycle\n            decision = 0;\n        } else {\n            // Safety first: if rejecting disconnects future contracted graph, accept\n            bool must_accept = false;\n            if (!has_future(dsu.inc[ru], i) || !has_future(dsu.inc[rv], i)) {\n                must_accept = true;\n            } else if (!future_connected_after_reject(i, dsu, edges)) {\n                must_accept = true;\n            }\n\n            if (must_accept) {\n                decision = 1;\n                dsu.unite(ru, rv);\n            } else {\n                // Expected-MST inclusion test: if expected MST (unknown edges weight 2d) would include this edge, accept\n                bool exp_includes = expected_mst_includes_edge(i, l, dsu, edges, orderBy2d);\n                if (exp_includes) {\n                    decision = 1;\n                    dsu.unite(ru, rv);\n                } else {\n                    // Scarcity-aware threshold\n                    int k1 = count_suffix_capped(dsu.inc[ru], i, kCapCount);\n                    int k2 = count_suffix_capped(dsu.inc[rv], i, kCapCount);\n                    int kmin = min(k1, k2);\n\n                    double r = (double)l / (double)e.d;\n                    double thr = 1.0 + 2.0 / (double)(kmin + 1);\n\n                    // Pair-specific future alternatives between ru and rv\n                    pairBS = dsu.inc[ru];\n                    pairBS &= dsu.inc[rv];\n                    int kpair = 0;\n                    int dminpair = INT_MAX;\n                    auto idxb = pairBS.find_next(i);\n                    while (idxb != boost::dynamic_bitset<unsigned long long>::npos) {\n                        ++kpair;\n                        int eid = (int)idxb;\n                        dminpair = min(dminpair, edges[eid].d);\n                        idxb = pairBS.find_next(idxb);\n                    }\n                    if (kpair > 0 && dminpair < INT_MAX) {\n                        double pairFactor = (double)dminpair / (double)e.d;\n                        if (pairFactor < 0.75) pairFactor = 0.75;\n                        if (pairFactor > 1.20) pairFactor = 1.20;\n                        thr *= pairFactor;\n                    }\n\n                    // Offline/geometry adjustments\n                    if (e.level >= 1 && e.level <= 5) thr += levelAdd[e.level];\n                    if (e.d <= q25) thr += smallDAdd;\n                    else if (e.d >= q75) thr -= largeDPen;\n\n                    // MST frequency bonus\n                    thr += freq[i] * freqScale;\n\n                    // Small extra help for small k\n                    thr += k_small_bonus(kmin);\n\n                    // Mild relaxation over time\n                    double t = (double)i / (double)M;\n                    thr += tRelaxCoeff * t;\n\n                    if (thr < 1.0) thr = 1.0;\n                    if (thr > 3.0) thr = 3.0;\n\n                    if (r <= thr) {\n                        decision = 1;\n                        dsu.unite(ru, rv);\n                    } else {\n                        decision = 0;\n                    }\n                }\n            }\n        }\n\n        cout << decision << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pet { int x, y, t; };\n\nstruct Plan {\n    bool active = false;\n    bool sealed = false;\n    int L = 0; // number of interior cells\n    vector<pair<int,int>> cells; // interior cells in a straight line\n    vector<pair<int,int>> boundary; // boundary target cells\n    vector<int> adjIdx; // which interior cell a boundary belongs to\n    vector<char> done; // boundary cell is already blocked or OOB\n    int pos = 0; // index in cells where human currently is\n    int idle_turns = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int H = 30, W = 30;\n    auto inb = [&](int x, int y)->bool { return 0 <= x && x < H && 0 <= y && y < W; };\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<Pet> pets(N);\n    for (int i = 0; i < N; i++) {\n        int px, py, pt; cin >> px >> py >> pt;\n        pets[i] = {px-1, py-1, pt};\n    }\n    int M; cin >> M;\n    vector<int> hx(M), hy(M);\n    for (int i = 0; i < M; i++) {\n        int x, y; cin >> x >> y;\n        hx[i] = x-1; hy[i] = y-1;\n    }\n\n    vector<vector<char>> blocked(H, vector<char>(W, 0));\n    vector<vector<int>> pet_here(H, vector<int>(W, 0));\n    vector<vector<int>> human_here(H, vector<int>(W, 0));\n\n    auto rebuild_human_here = [&]() {\n        for (int i = 0; i < H; i++) fill(human_here[i].begin(), human_here[i].end(), 0);\n        for (int i = 0; i < M; i++) human_here[hx[i]][hy[i]]++;\n    };\n    auto rebuild_pet_here = [&]() {\n        for (int i = 0; i < H; i++) fill(pet_here[i].begin(), pet_here[i].end(), 0);\n        for (int i = 0; i < N; i++) pet_here[pets[i].x][pets[i].y]++;\n    };\n\n    rebuild_human_here();\n    rebuild_pet_here();\n\n    const int dx4[4] = {-1, 0, 1, 0};\n    const int dy4[4] = {0, 1, 0, -1};\n    const char blockChar[4] = {'u','r','d','l'};\n    const char moveChar[4]  = {'U','R','D','L'};\n\n    // Preferred direction order for fallback 1-cell closure\n    vector<array<int,4>> prefDir(M);\n    for (int i = 0; i < M; i++) {\n        int topDist = hx[i];\n        int bottomDist = (H-1) - hx[i];\n        int leftDist = hy[i];\n        int rightDist = (W-1) - hy[i];\n        int firstV = (topDist <= bottomDist ? 0 : 2);   // up or down\n        int firstH = (leftDist <= rightDist ? 3 : 1);   // left or right\n        int otherV = firstV ^ 2;\n        int otherH = firstH ^ 2;\n        prefDir[i] = { firstV, firstH, otherV, otherH };\n    }\n\n    vector<char> fully_closed(M, 0); // closed with either 1/2/3/...-cell chamber\n    vector<Plan> plan(M);\n\n    // movement modes: 0 none, 1 moving to nearest wall, 2 moving along wall to chosen site\n    vector<int> moveMode(M, 0);\n    vector<int> siteTX(M, -1), siteTY(M, -1);\n\n    auto count_open_neighbors = [&](int x, int y)->int {\n        int c = 0;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (!blocked[nx][ny]) c++;\n        }\n        return c;\n    };\n\n    auto can_block_rule = [&](int tx, int ty)->bool {\n        if (!inb(tx, ty)) return false;\n        if (blocked[tx][ty]) return false;\n        if (human_here[tx][ty] > 0) return false;\n        if (pet_here[tx][ty] > 0) return false;\n        for (int k = 0; k < 4; k++) {\n            int ax = tx + dx4[k], ay = ty + dy4[k];\n            if (!inb(ax, ay)) continue;\n            if (pet_here[ax][ay] > 0) return false;\n        }\n        return true;\n    };\n\n    auto onWall = [&](int x, int y)->bool {\n        return (x == 0 || x == H-1 || y == 0 || y == W-1);\n    };\n\n    auto minDistToPet = [&](int tx, int ty)->int {\n        int best = INT_MAX;\n        for (const auto &p : pets) {\n            int dist = abs(tx - p.x) + abs(ty - p.y);\n            if (dist < best) best = dist;\n        }\n        return best;\n    };\n\n    auto dynamic_slack = [&](int time_left)->int {\n        if (time_left >= 200) return 40;\n        if (time_left >= 120) return 35;\n        if (time_left >= 80) return 30;\n        return 25;\n    };\n\n    // Build centered straight-line corridor plan of length L with time budget constraint\n    auto build_centered_plan = [&](int i, int L, int time_left)->bool {\n        int cx = hx[i], cy = hy[i];\n        int best_score = -1;\n        long long best_dist_sum = -1;\n        vector<pair<int,int>> best_cells;\n        vector<pair<int,int>> best_boundary;\n        vector<int> best_adjIdx;\n\n        bool atTop = (hx[i] == 0), atBottom = (hx[i] == H-1), atLeft = (hy[i] == 0), atRight = (hy[i] == W-1);\n\n        for (int axis = 0; axis < 2; axis++) {\n            int axis_bias = 0;\n            if ((axis == 0 && (atTop || atBottom)) || (axis == 1 && (atLeft || atRight))) axis_bias = 5;\n\n            for (int left = 0; left <= L-1; left++) {\n                int right = (L-1) - left;\n                vector<pair<int,int>> cells;\n                bool ok = true;\n                if (axis == 0) {\n                    int l = cy - left, r = cy + right;\n                    if (l < 0 || r >= W) continue;\n                    for (int y = l; y <= r; y++) {\n                        if (blocked[cx][y]) { ok = false; break; }\n                        cells.emplace_back(cx, y);\n                    }\n                } else {\n                    int u = cx - left, d = cx + right;\n                    if (u < 0 || d >= H) continue;\n                    for (int x = u; x <= d; x++) {\n                        if (blocked[x][cy]) { ok = false; break; }\n                        cells.emplace_back(x, cy);\n                    }\n                }\n                if (!ok) continue;\n\n                // skip if pet inside now\n                bool petInsideNow = false;\n                for (auto &q : cells) if (pet_here[q.first][q.second] > 0) { petInsideNow = true; break; }\n                if (petInsideNow) continue;\n\n                vector<pair<int,int>> boundary;\n                vector<int> adjIdx;\n                auto add_unique = [&](int tx, int ty, int idx) {\n                    for (size_t p = 0; p < boundary.size(); p++) {\n                        if (boundary[p].first == tx && boundary[p].second == ty) return;\n                    }\n                    boundary.emplace_back(tx, ty);\n                    adjIdx.push_back(idx);\n                };\n                for (int idx = 0; idx < (int)cells.size(); idx++) {\n                    int x = cells[idx].first, y = cells[idx].second;\n                    for (int d = 0; d < 4; d++) {\n                        int nx = x + dx4[d], ny = y + dy4[d];\n                        bool isInterior = false;\n                        for (auto &q : cells) {\n                            if (q.first == nx && q.second == ny) { isInterior = true; break; }\n                        }\n                        if (isInterior) continue;\n                        add_unique(nx, ny, idx);\n                    }\n                }\n                int done_count = 0;\n                int remain_count = 0;\n                long long dist_sum = 0;\n                for (auto &b : boundary) {\n                    int tx = b.first, ty = b.second;\n                    bool done = (!inb(tx, ty) || blocked[tx][ty]);\n                    if (done) done_count++;\n                    else remain_count++;\n                    int md = inb(tx, ty) ? minDistToPet(tx, ty) : 100;\n                    dist_sum += md;\n                }\n\n                int slack = dynamic_slack(time_left);\n                if (remain_count > max(0, time_left - slack)) continue;\n\n                int score = done_count * 100 + axis_bias;\n                if (score > best_score || (score == best_score && dist_sum > best_dist_sum)) {\n                    best_score = score;\n                    best_dist_sum = dist_sum;\n                    best_cells = cells;\n                    best_boundary = boundary;\n                    best_adjIdx = adjIdx;\n                }\n            }\n        }\n\n        if (best_score < 0) return false;\n\n        plan[i].active = true;\n        plan[i].sealed = false;\n        plan[i].L = L;\n        plan[i].cells = best_cells;\n        plan[i].boundary = best_boundary;\n        plan[i].adjIdx = best_adjIdx;\n        plan[i].done.assign(plan[i].boundary.size(), 0);\n        plan[i].idle_turns = 0;\n\n        for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n            int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n            if (!inb(tx, ty) || blocked[tx][ty]) plan[i].done[k] = 1;\n        }\n        int found = -1;\n        for (int idx = 0; idx < plan[i].L; idx++) {\n            if (plan[i].cells[idx].first == cx && plan[i].cells[idx].second == cy) { found = idx; break; }\n        }\n        plan[i].pos = (found == -1 ? 0 : found);\n        return true;\n    };\n\n    // Evaluate best site along a wall for a human, returns true if a site chosen\n    auto choose_wall_site = [&](int i, int time_left)->bool {\n        int x = hx[i], y = hy[i];\n        bool top = (x == 0), bottom = (x == H-1), left = (y == 0), right = (y == W-1);\n        if (!(top || bottom || left || right)) return false;\n\n        vector<int> Lcands_scan = {18, 16, 14, 12, 10, 8, 6};\n        int bestScore = INT_MIN;\n        long long bestDist = LLONG_MAX;\n        int bestTX = -1, bestTY = -1;\n\n        if (top || bottom) {\n            for (int ty = 0; ty < W; ty++) {\n                int travel = abs(ty - y);\n                int tleft = time_left - travel;\n                if (tleft <= 0) continue;\n                // Simple heuristic: try to build a plan hypothetically at (x, ty) and get a score\n                int localBest = INT_MIN;\n                long long localDistSum = -1;\n                for (int L : Lcands_scan) {\n                    // simulate boundary counts at this anchor without modifying state\n                    int cx = x, cy = ty;\n                    int best_score_inner = -1;\n                    long long best_sum_inner = -1;\n                    for (int axis = 0; axis < 2; axis++) {\n                        int axis_bias = 5; // already on wall, both axes small bias\n                        for (int leftCnt = 0; leftCnt <= L-1; leftCnt++) {\n                            int rightCnt = (L-1) - leftCnt;\n                            vector<pair<int,int>> cells;\n                            bool ok = true;\n                            if (axis == 0) {\n                                int l = cy - leftCnt, r = cy + rightCnt;\n                                if (l < 0 || r >= W) continue;\n                                for (int yy = l; yy <= r; yy++) {\n                                    if (blocked[cx][yy]) { ok = false; break; }\n                                    cells.emplace_back(cx, yy);\n                                }\n                            } else {\n                                int u = cx - leftCnt, d = cx + rightCnt;\n                                if (u < 0 || d >= H) continue;\n                                for (int xx = u; xx <= d; xx++) {\n                                    if (blocked[xx][cy]) { ok = false; break; }\n                                    cells.emplace_back(xx, cy);\n                                }\n                            }\n                            if (!ok) continue;\n                            bool petInsideNow = false;\n                            for (auto &q : cells) if (pet_here[q.first][q.second] > 0) { petInsideNow = true; break; }\n                            if (petInsideNow) continue;\n\n                            vector<pair<int,int>> boundary;\n                            vector<int> adjIdx;\n                            auto add_unique = [&](int tx, int ty2, int idx) {\n                                for (auto &b : boundary) if (b.first == tx && b.second == ty2) return;\n                                boundary.emplace_back(tx, ty2);\n                                adjIdx.push_back(idx);\n                            };\n                            for (int idx = 0; idx < (int)cells.size(); idx++) {\n                                int xx = cells[idx].first, yy = cells[idx].second;\n                                for (int d = 0; d < 4; d++) {\n                                    int nx2 = xx + dx4[d], ny2 = yy + dy4[d];\n                                    bool isInt = false;\n                                    for (auto &q : cells) if (q.first == nx2 && q.second == ny2) { isInt = true; break; }\n                                    if (isInt) continue;\n                                    add_unique(nx2, ny2, idx);\n                                }\n                            }\n                            int done_count = 0;\n                            int remain_count = 0;\n                            long long dist_sum = 0;\n                            for (auto &b : boundary) {\n                                int tx = b.first, ty2 = b.second;\n                                bool done = (!inb(tx, ty2) || blocked[tx][ty2]);\n                                if (done) done_count++;\n                                else remain_count++;\n                                int md = inb(tx, ty2) ? minDistToPet(tx, ty2) : 100;\n                                dist_sum += md;\n                            }\n                            int slack = dynamic_slack(tleft);\n                            if (remain_count > max(0, tleft - slack)) continue;\n                            int score = done_count * 100 + axis_bias;\n                            if (score > best_score_inner || (score == best_score_inner && dist_sum > best_sum_inner)) {\n                                best_score_inner = score;\n                                best_sum_inner = dist_sum;\n                            }\n                        }\n                    }\n                    if (best_score_inner > localBest || (best_score_inner == localBest && best_sum_inner > localDistSum)) {\n                        localBest = best_score_inner;\n                        localDistSum = best_sum_inner;\n                    }\n                }\n                if (localBest == INT_MIN) continue;\n                if (localBest > bestScore || (localBest == bestScore && travel < bestDist)) {\n                    bestScore = localBest;\n                    bestDist = travel;\n                    bestTX = x; bestTY = ty;\n                }\n            }\n        } else { // left or right wall\n            for (int tx = 0; tx < H; tx++) {\n                int travel = abs(tx - x);\n                int tleft = time_left - travel;\n                if (tleft <= 0) continue;\n                int localBest = INT_MIN;\n                long long localDistSum = -1;\n                for (int L : vector<int>{18,16,14,12,10,8,6}) {\n                    int cx = tx, cy = y;\n                    int best_score_inner = -1;\n                    long long best_sum_inner = -1;\n                    for (int axis = 0; axis < 2; axis++) {\n                        int axis_bias = 5;\n                        for (int leftCnt = 0; leftCnt <= L-1; leftCnt++) {\n                            int rightCnt = (L-1) - leftCnt;\n                            vector<pair<int,int>> cells;\n                            bool ok = true;\n                            if (axis == 0) {\n                                int l = cy - leftCnt, r = cy + rightCnt;\n                                if (l < 0 || r >= W) continue;\n                                for (int yy = l; yy <= r; yy++) {\n                                    if (blocked[cx][yy]) { ok = false; break; }\n                                    cells.emplace_back(cx, yy);\n                                }\n                            } else {\n                                int u = cx - leftCnt, d = cx + rightCnt;\n                                if (u < 0 || d >= H) continue;\n                                for (int xx = u; xx <= d; xx++) {\n                                    if (blocked[xx][cy]) { ok = false; break; }\n                                    cells.emplace_back(xx, cy);\n                                }\n                            }\n                            if (!ok) continue;\n                            bool petInsideNow = false;\n                            for (auto &q : cells) if (pet_here[q.first][q.second] > 0) { petInsideNow = true; break; }\n                            if (petInsideNow) continue;\n\n                            vector<pair<int,int>> boundary;\n                            vector<int> adjIdx;\n                            auto add_unique = [&](int tx2, int ty2, int idx) {\n                                for (auto &b : boundary) if (b.first == tx2 && b.second == ty2) return;\n                                boundary.emplace_back(tx2, ty2);\n                                adjIdx.push_back(idx);\n                            };\n                            for (int idx = 0; idx < (int)cells.size(); idx++) {\n                                int xx = cells[idx].first, yy = cells[idx].second;\n                                for (int d = 0; d < 4; d++) {\n                                    int nx2 = xx + dx4[d], ny2 = yy + dy4[d];\n                                    bool isInt = false;\n                                    for (auto &q : cells) if (q.first == nx2 && q.second == ny2) { isInt = true; break; }\n                                    if (isInt) continue;\n                                    add_unique(nx2, ny2, idx);\n                                }\n                            }\n                            int done_count = 0;\n                            int remain_count = 0;\n                            long long dist_sum = 0;\n                            for (auto &b : boundary) {\n                                int tx2 = b.first, ty2 = b.second;\n                                bool done = (!inb(tx2, ty2) || blocked[tx2][ty2]);\n                                if (done) done_count++;\n                                else remain_count++;\n                                int md = inb(tx2, ty2) ? minDistToPet(tx2, ty2) : 100;\n                                dist_sum += md;\n                            }\n                            int slack = dynamic_slack(tleft);\n                            if (remain_count > max(0, tleft - slack)) continue;\n                            int score = done_count * 100 + axis_bias;\n                            if (score > best_score_inner || (score == best_score_inner && dist_sum > best_sum_inner)) {\n                                best_score_inner = score;\n                                best_sum_inner = dist_sum;\n                            }\n                        }\n                    }\n                    if (best_score_inner > localBest || (best_score_inner == localBest && best_sum_inner > localDistSum)) {\n                        localBest = best_score_inner;\n                        localDistSum = best_sum_inner;\n                    }\n                }\n                if (localBest == INT_MIN) continue;\n                if (localBest > bestScore || (localBest == bestScore && travel < bestDist)) {\n                    bestScore = localBest;\n                    bestDist = travel;\n                    bestTX = tx; bestTY = y;\n                }\n            }\n        }\n\n        if (bestTX == -1) return false;\n        siteTX[i] = bestTX;\n        siteTY[i] = bestTY;\n        moveMode[i] = 2; // moving along wall to site\n        return true;\n    };\n\n    // Fallback 1-cell action\n    auto fallback_one_cell_action = [&](int i, const vector<vector<int>>& reserved)->char {\n        if (fully_closed[i]) return '.';\n        int x = hx[i], y = hy[i];\n        int openN = 0;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (!blocked[nx][ny]) openN++;\n        }\n        if (openN == 0) {\n            fully_closed[i] = 1;\n            return '.';\n        }\n        bool petOnMyCell = (pet_here[x][y] > 0);\n        if (openN == 1 && petOnMyCell) {\n            return '.';\n        }\n        for (int order = 0; order < 4; order++) {\n            int d = prefDir[i][order];\n            int nx = x + dx4[d], ny = y + dy4[d];\n            if (!inb(nx, ny)) continue;\n            if (blocked[nx][ny]) continue;\n            if (reserved[nx][ny] > 0) continue; // avoid blocking others' interior\n            if (can_block_rule(nx, ny)) {\n                return blockChar[d];\n            }\n        }\n        return '.';\n    };\n\n    const int panic_turn = 260;\n    vector<int> Lcands_long = {24, 22, 20, 18, 16, 14, 12, 10, 9, 8, 7, 6, 5, 4, 3, 2};\n    vector<int> Lcands_panic = {6, 5, 4, 3, 2};\n\n    for (int turn = 0; turn < 300; turn++) {\n        int time_left = 300 - turn;\n\n        // Sync plan pos; handle movement modes; assign sites when reaching wall\n        for (int i = 0; i < M; i++) {\n            if (fully_closed[i]) { moveMode[i] = 0; continue; }\n\n            if (turn >= panic_turn) {\n                plan[i].active = false;\n                moveMode[i] = 0;\n            }\n\n            if (plan[i].active) {\n                int found = -1;\n                for (int idx = 0; idx < plan[i].L; idx++) {\n                    if (hx[i] == plan[i].cells[idx].first && hy[i] == plan[i].cells[idx].second) { found = idx; break; }\n                }\n                if (found == -1) {\n                    plan[i].active = false;\n                } else {\n                    plan[i].pos = found;\n                }\n            }\n\n            bool atWall = onWall(hx[i], hy[i]);\n\n            if (!plan[i].active && turn < panic_turn) {\n                if (!atWall) {\n                    if (moveMode[i] == 0) moveMode[i] = 1; // move to nearest wall\n                } else {\n                    // at wall\n                    if (moveMode[i] != 2) {\n                        // choose a site along the wall\n                        siteTX[i] = hx[i];\n                        siteTY[i] = hy[i];\n                        bool ok = choose_wall_site(i, time_left);\n                        if (!ok) {\n                            moveMode[i] = 0; // build here\n                        }\n                    }\n                }\n            }\n        }\n\n        // Build reserved grid from active plans\n        vector<vector<int>> reserved(H, vector<int>(W, 0));\n        for (int i = 0; i < M; i++) {\n            if (!plan[i].active) continue;\n            for (auto &c : plan[i].cells) {\n                int x = c.first, y = c.second;\n                if (inb(x, y)) reserved[x][y]++;\n            }\n        }\n\n        string actions(M, '.');\n        vector<char> is_move(M, 0);\n        vector<int> move_dir(M, -1);\n\n        // Tentative actions\n        for (int i = 0; i < M; i++) {\n            if (fully_closed[i]) { actions[i] = '.'; continue; }\n\n            // Panic: try small plans else fallback\n            if (turn >= panic_turn) {\n                if (!plan[i].active) {\n                    bool built = false;\n                    for (int L : Lcands_panic) {\n                        if (build_centered_plan(i, L, time_left)) { built = true; break; }\n                    }\n                    if (!built) {\n                        actions[i] = fallback_one_cell_action(i, reserved);\n                        continue;\n                    }\n                }\n            }\n\n            if (moveMode[i] == 1) {\n                // Move towards nearest wall; prefer farther from pets\n                int x = hx[i], y = hy[i];\n                int dTop = x, dBottom = (H-1)-x, dLeft = y, dRight = (W-1)-y;\n                int minv = min(min(dTop, dBottom), min(dLeft, dRight));\n                vector<int> cand;\n                if (dTop == minv) cand.push_back(0);\n                if (dLeft == minv) cand.push_back(3);\n                if (dBottom == minv) cand.push_back(2);\n                if (dRight == minv) cand.push_back(1);\n                int chosen_dir = -1;\n                int bestDist = -1;\n                for (int d : cand) {\n                    int nx = x + dx4[d], ny = y + dy4[d];\n                    if (!inb(nx, ny)) continue;\n                    if (blocked[nx][ny]) continue;\n                    int md = minDistToPet(nx, ny);\n                    if (md > bestDist) { bestDist = md; chosen_dir = d; }\n                }\n                if (chosen_dir != -1) {\n                    actions[i] = moveChar[chosen_dir];\n                    is_move[i] = 1;\n                    move_dir[i] = chosen_dir;\n                } else {\n                    actions[i] = '.';\n                }\n                continue;\n            } else if (moveMode[i] == 2) {\n                // Move along wall toward site\n                int x = hx[i], y = hy[i];\n                int tx = siteTX[i], ty = siteTY[i];\n                if (x == tx && y == ty) {\n                    moveMode[i] = 0; // arrived; build this turn\n                } else {\n                    int dd = -1;\n                    if (x == 0 || x == H-1) {\n                        // move horizontally\n                        if (ty < y) dd = 3; // left\n                        else if (ty > y) dd = 1; // right\n                    } else {\n                        // y==0 or y==W-1: move vertically\n                        if (tx < x) dd = 0; // up\n                        else if (tx > x) dd = 2; // down\n                    }\n                    if (dd != -1) {\n                        int nx = x + dx4[dd], ny = y + dy4[dd];\n                        if (inb(nx, ny) && !blocked[nx][ny]) {\n                            actions[i] = moveChar[dd];\n                            is_move[i] = 1;\n                            move_dir[i] = dd;\n                        } else {\n                            actions[i] = '.';\n                        }\n                        continue;\n                    }\n                }\n            }\n\n            if (!plan[i].active && turn < panic_turn) {\n                // Build plan at current cell using time budget\n                bool built = false;\n                for (int L : Lcands_long) {\n                    if (build_centered_plan(i, L, time_left)) { built = true; break; }\n                }\n                if (!built) {\n                    actions[i] = fallback_one_cell_action(i, reserved);\n                    continue;\n                }\n            }\n\n            if (!plan[i].active) {\n                actions[i] = fallback_one_cell_action(i, reserved);\n                continue;\n            }\n\n            // Update boundary done flags\n            for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                if (!inb(tx, ty) || blocked[tx][ty]) plan[i].done[k] = 1;\n            }\n            // If any interior cell got blocked, abort plan\n            bool interior_broken = false;\n            for (int idx = 0; idx < plan[i].L; idx++) {\n                int cx = plan[i].cells[idx].first, cy = plan[i].cells[idx].second;\n                if (!inb(cx, cy) || blocked[cx][cy]) { interior_broken = true; break; }\n            }\n            if (interior_broken) {\n                plan[i].active = false;\n                actions[i] = fallback_one_cell_action(i, reserved);\n                continue;\n            }\n\n            int remain_now = 0;\n            for (char f : plan[i].done) if (!f) remain_now++;\n\n            // Time-based degrade: if too big for remaining time, rebuild smaller\n            if (remain_now > max(0, time_left - dynamic_slack(time_left) - 10)) {\n                plan[i].active = false;\n                bool atWall = onWall(hx[i], hy[i]);\n                if (atWall && turn < panic_turn) {\n                    for (int L : Lcands_long) {\n                        if (L < plan[i].L) {\n                            if (build_centered_plan(i, L, time_left)) break;\n                        }\n                    }\n                } else if (turn >= panic_turn) {\n                    for (int L : Lcands_panic) {\n                        if (build_centered_plan(i, L, time_left)) break;\n                    }\n                }\n                if (!plan[i].active) {\n                    actions[i] = fallback_one_cell_action(i, reserved);\n                    continue;\n                }\n                remain_now = 0;\n                for (char f : plan[i].done) if (!f) remain_now++;\n            }\n\n            if (remain_now == 0) {\n                plan[i].sealed = true;\n                fully_closed[i] = 1;\n                actions[i] = '.';\n                continue;\n            }\n\n            // Determine if pet is inside the chamber\n            bool petInside = false;\n            for (int idx = 0; idx < plan[i].L; idx++) {\n                if (pet_here[plan[i].cells[idx].first][plan[i].cells[idx].second] > 0) { petInside = true; break; }\n            }\n\n            int cx = plan[i].cells[plan[i].pos].first;\n            int cy = plan[i].cells[plan[i].pos].second;\n\n            // Try to block from current pos; choose safest candidate; also avoid reserved\n            int chosen_dir = -1;\n            int bestDist = -1;\n            for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                if (plan[i].done[k]) continue;\n                if (plan[i].adjIdx[k] != plan[i].pos) continue;\n                int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                if (!inb(tx, ty)) continue;\n                if (remain_now == 1 && petInside) continue;\n                if (reserved[tx][ty] > 0) continue; // avoid blocking other's interior\n                if (!can_block_rule(tx, ty)) continue;\n                int dd = -1;\n                for (int d = 0; d < 4; d++) {\n                    if (cx + dx4[d] == tx && cy + dy4[d] == ty) { dd = d; break; }\n                }\n                if (dd == -1) continue;\n                int md = minDistToPet(tx, ty);\n                if (md > bestDist) {\n                    bestDist = md;\n                    chosen_dir = dd;\n                }\n            }\n\n            if (chosen_dir != -1) {\n                actions[i] = blockChar[chosen_dir];\n                continue;\n            } else {\n                // Move along corridor toward a spot that has a candidate boundary\n                int target_idx = -1;\n                int target_bestDist = -1;\n                for (int idx = 0; idx < plan[i].L; idx++) {\n                    if (idx == plan[i].pos) continue;\n                    int localBest = -1;\n                    for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                        if (plan[i].done[k]) continue;\n                        if (plan[i].adjIdx[k] != idx) continue;\n                        int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                        if (!inb(tx, ty)) continue;\n                        if (remain_now == 1 && petInside) continue;\n                        if (reserved[tx][ty] > 0) continue;\n                        if (!can_block_rule(tx, ty)) continue;\n                        int md = minDistToPet(tx, ty);\n                        if (md > localBest) localBest = md;\n                    }\n                    if (localBest > target_bestDist) {\n                        target_bestDist = localBest;\n                        target_idx = idx;\n                    }\n                }\n                if (target_idx != -1) {\n                    int next_idx = plan[i].pos + ((target_idx > plan[i].pos) ? 1 : -1);\n                    int nx = plan[i].cells[next_idx].first;\n                    int ny = plan[i].cells[next_idx].second;\n                    if (inb(nx, ny) && !blocked[nx][ny]) {\n                        int dd = -1;\n                        for (int d = 0; d < 4; d++) {\n                            if (hx[i] + dx4[d] == nx && hy[i] + dy4[d] == ny) { dd = d; break; }\n                        }\n                        if (dd != -1) {\n                            actions[i] = moveChar[dd];\n                            is_move[i] = 1;\n                            move_dir[i] = dd;\n                        } else {\n                            actions[i] = '.';\n                        }\n                    } else {\n                        actions[i] = '.';\n                    }\n                } else {\n                    actions[i] = '.';\n                }\n            }\n        }\n\n        // Phase-2: prevent moving into a cell that becomes blocked by anyone this turn\n        vector<vector<char>> blocked_this_turn(H, vector<char>(W, 0));\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'u' || c == 'r' || c == 'd' || c == 'l') {\n                int d = (c=='u'?0:(c=='r'?1:(c=='d'?2:3)));\n                int tx = hx[i] + dx4[d], ty = hy[i] + dy4[d];\n                if (inb(tx, ty)) blocked_this_turn[tx][ty] = 1;\n            }\n        }\n        vector<char> canceled(M, 0);\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'U' || c == 'R' || c == 'D' || c == 'L') {\n                int d = (c=='U'?0:(c=='R'?1:(c=='D'?2:3)));\n                int nx = hx[i] + dx4[d], ny = hy[i] + dy4[d];\n                if (inb(nx, ny) && blocked_this_turn[nx][ny]) {\n                    actions[i] = '.';\n                    canceled[i] = 1;\n                }\n            }\n        }\n        // Adjust idle/degrade after final actions\n        for (int i = 0; i < M; i++) {\n            if (!plan[i].active || fully_closed[i]) continue;\n            if (actions[i] == '.') plan[i].idle_turns++;\n            else plan[i].idle_turns = 0;\n            int threshold;\n            if (plan[i].L >= 20) threshold = 85;\n            else if (plan[i].L >= 16) threshold = 80;\n            else if (plan[i].L >= 12) threshold = 70;\n            else if (plan[i].L >= 8) threshold = 60;\n            else if (plan[i].L >= 6) threshold = 55;\n            else if (plan[i].L >= 4) threshold = 50;\n            else threshold = 45;\n\n            if (plan[i].idle_turns >= threshold) {\n                plan[i].active = false;\n                if (onWall(hx[i], hy[i]) && turn < panic_turn) {\n                    for (int L : Lcands_long) {\n                        if (L < plan[i].L) {\n                            if (build_centered_plan(i, L, time_left)) break;\n                        }\n                    }\n                }\n            }\n        }\n\n        // Output final actions and flush\n        cout << actions << '\\n' << flush;\n\n        // Apply blocks and moves locally\n        for (int i = 0; i < M; i++) {\n            char c = actions[i];\n            if (c == 'u' || c == 'r' || c == 'd' || c == 'l') {\n                int d = (c=='u'?0:(c=='r'?1:(c=='d'?2:3)));\n                int tx = hx[i] + dx4[d], ty = hy[i] + dy4[d];\n                if (inb(tx, ty)) blocked[tx][ty] = 1;\n            } else if (c == 'U' || c == 'R' || c == 'D' || c == 'L') {\n                int d = (c=='U'?0:(c=='R'?1:(c=='D'?2:3)));\n                int nx = hx[i] + dx4[d], ny = hy[i] + dy4[d];\n                if (inb(nx, ny) && !blocked[nx][ny]) {\n                    hx[i] = nx; hy[i] = ny;\n                }\n            }\n        }\n\n        // Read pet moves\n        for (int i = 0; i < N; i++) {\n            string s; cin >> s;\n            if (s == \".\") continue;\n            for (char mv : s) {\n                if (mv == 'U') pets[i].x -= 1;\n                else if (mv == 'D') pets[i].x += 1;\n                else if (mv == 'L') pets[i].y -= 1;\n                else if (mv == 'R') pets[i].y += 1;\n            }\n        }\n\n        // Rebuild occupancy for next turn\n        rebuild_pet_here();\n        rebuild_human_here();\n\n        // Update modes and closure status\n        for (int i = 0; i < M; i++) {\n            if (fully_closed[i]) continue;\n            // Arrived to wall?\n            if (moveMode[i] == 1 && onWall(hx[i], hy[i])) {\n                moveMode[i] = 0; // will pick site next turn\n            }\n            if (moveMode[i] == 2 && hx[i] == siteTX[i] && hy[i] == siteTY[i]) {\n                moveMode[i] = 0; // arrived; build next turn\n            }\n\n            if (plan[i].active) {\n                int remain = 0;\n                for (size_t k = 0; k < plan[i].boundary.size(); k++) {\n                    int tx = plan[i].boundary[k].first, ty = plan[i].boundary[k].second;\n                    if (!inb(tx, ty) || blocked[tx][ty]) plan[i].done[k] = 1;\n                    if (!plan[i].done[k]) remain++;\n                }\n                if (remain == 0) {\n                    plan[i].sealed = true;\n                    fully_closed[i] = 1;\n                }\n                int found = -1;\n                for (int idx = 0; idx < plan[i].L; idx++) {\n                    if (hx[i] == plan[i].cells[idx].first && hy[i] == plan[i].cells[idx].second) { found = idx; break; }\n                }\n                if (found != -1) plan[i].pos = found;\n                else plan[i].active = false;\n            } else {\n                if (count_open_neighbors(hx[i], hy[i]) == 0) {\n                    fully_closed[i] = 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static auto st = std::chrono::steady_clock::now();\n    auto cur = std::chrono::steady_clock::now();\n    return std::chrono::duration<double>(cur - st).count();\n}\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int randint(int l, int r) {\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    int si, sj, ti, tj;\n    double p;\n    if (!(cin >> si >> sj >> ti >> tj >> p)) return 0;\n    vector<string> h(20);\n    for (int i = 0; i < 20; i++) cin >> h[i];\n    vector<string> v(19);\n    for (int i = 0; i < 19; i++) cin >> v[i];\n\n    const int H = 20, W = 20, N = H * W;\n    auto id = [&](int r, int c) { return r * W + c; };\n    int s_id = id(si, sj);\n    int t_id = id(ti, tj);\n\n    if (s_id == t_id) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift rng(seed ^ 0x9e3779b97f4a7c15ULL);\n\n    // Directions\n    const char DIRC[4] = {'U','D','L','R'};\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n\n    const double q = 1.0 - p;\n\n    // dest transitions\n    static int dest[400][4];\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = id(i, j);\n            dest[u][0] = (i > 0 && v[i-1][j] == '0') ? id(i-1, j) : -1;\n            dest[u][1] = (i < H-1 && v[i][j] == '0') ? id(i+1, j) : -1;\n            dest[u][2] = (j > 0 && h[i][j-1] == '0') ? id(i, j-1) : -1;\n            dest[u][3] = (j < W-1 && h[i][j] == '0') ? id(i, j+1) : -1;\n        }\n    }\n\n    // right-transition weights\n    static double self_w_right[4][400], other_w_right[4][400];\n    static int other_idx_right[4][400];\n    for (int d = 0; d < 4; d++) {\n        for (int u = 0; u < N; u++) {\n            if (u == t_id) {\n                self_w_right[d][u] = 1.0;\n                other_w_right[d][u] = 0.0;\n                other_idx_right[d][u] = u;\n            } else {\n                int y = dest[u][d];\n                if (y >= 0) {\n                    self_w_right[d][u] = p;\n                    other_w_right[d][u] = q;\n                    other_idx_right[d][u] = y;\n                } else {\n                    self_w_right[d][u] = 1.0;\n                    other_w_right[d][u] = 0.0;\n                    other_idx_right[d][u] = u;\n                }\n            }\n        }\n    }\n\n    const int L0 = 200;\n\n    // Transition ops\n    auto apply_right = [&](int dir, const double* vin, double* vout) {\n        for (int i = 0; i < N; i++) vout[i] = 0.0;\n        const double* sw = self_w_right[dir];\n        const double* ow = other_w_right[dir];\n        const int* oi = other_idx_right[dir];\n        for (int u = 0; u < N; u++) {\n            double val = vin[u];\n            if (val == 0.0) continue;\n            vout[u] += sw[u] * val;\n            double owu = ow[u];\n            if (owu != 0.0) vout[oi[u]] += owu * val;\n        }\n    };\n    auto apply_right_and_dot = [&](int dir, const double* vin, double* vout, const double* gvec)->double {\n        double sum = 0.0;\n        for (int i = 0; i < N; i++) vout[i] = 0.0;\n        const double* sw = self_w_right[dir];\n        const double* ow = other_w_right[dir];\n        const int* oi = other_idx_right[dir];\n        for (int u = 0; u < N; u++) {\n            double val = vin[u];\n            if (val == 0.0) continue;\n            double self_add = sw[u] * val;\n            vout[u] += self_add;\n            sum += gvec[u] * self_add;\n            double owu = ow[u];\n            if (owu != 0.0) {\n                int j = oi[u];\n                double add = owu * val;\n                vout[j] += add;\n                sum += gvec[j] * add;\n            }\n        }\n        return sum;\n    };\n    auto apply_left = [&](int dir, const double* gcur, double* gprev) {\n        const double* sw = self_w_right[dir];\n        const double* ow = other_w_right[dir];\n        const int* oi = other_idx_right[dir];\n        for (int u = 0; u < N; u++) {\n            double s = sw[u] * gcur[u];\n            double owu = ow[u];\n            if (owu != 0.0) s += owu * gcur[oi[u]];\n            gprev[u] = s;\n        }\n    };\n\n    // BFS shortest path by direction order\n    auto bfs_path = [&](array<int,4> order)->vector<int> {\n        vector<int> par(N, -1), pdir(N, -1);\n        deque<int> dq;\n        dq.push_back(s_id);\n        par[s_id] = s_id;\n        while (!dq.empty() && par[t_id] == -1) {\n            int u = dq.front(); dq.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int d = order[k];\n                int vtx = dest[u][d];\n                if (vtx == -1) continue;\n                if (par[vtx] != -1) continue;\n                par[vtx] = u; pdir[vtx] = d;\n                dq.push_back(vtx);\n            }\n        }\n        vector<int> dirs;\n        if (par[t_id] != -1) {\n            int cur = t_id;\n            while (cur != s_id) { dirs.push_back(pdir[cur]); cur = par[cur]; }\n            reverse(dirs.begin(), dirs.end());\n        }\n        return dirs;\n    };\n\n    // Build sequences\n    auto build_seq_from_path_variant = [&](const vector<int>& path, int dup_k, bool reinforce)->vector<int>{\n        vector<int> seq; seq.reserve(L0);\n        vector<int> base = path;\n        if (base.empty()) {\n            int cr = si, cc = sj;\n            for (int steps = 0; steps < 400 && !(cr == ti && cc == tj); steps++) {\n                int bestd = 0, bestdist = INT_MAX;\n                for (int d = 0; d < 4; d++) {\n                    int nr = cr + dr[d], nc = cc + dc[d];\n                    if (nr < 0 || nr >= H || nc < 0 || nc >= W) continue;\n                    if (dest[id(cr,cc)][d] == -1) continue;\n                    int md = abs(nr - ti) + abs(nc - tj);\n                    if (md < bestdist) { bestdist = md; bestd = d; }\n                }\n                base.push_back(bestd); cr += dr[bestd]; cc += dc[bestd];\n            }\n        }\n        int prev = -1;\n        vector<int> expanded;\n        for (int d : base) {\n            if (reinforce && prev != -1 && prev != d) expanded.push_back(prev);\n            for (int r = 0; r < dup_k; r++) expanded.push_back(d);\n            if (dup_k == 0) expanded.push_back(d);\n            prev = d;\n        }\n        if (expanded.empty()) expanded.push_back(3);\n        while ((int)seq.size() < L0) {\n            for (int d : expanded) { seq.push_back(d); if ((int)seq.size() >= L0) break; }\n        }\n        return seq;\n    };\n    auto build_seq_from_path_cornerboost = [&](const vector<int>& path, int dup_k, bool reinforce, int boost_next)->vector<int>{\n        vector<int> seq; seq.reserve(L0);\n        vector<int> base = path;\n        if (base.empty()) {\n            int cr = si, cc = sj;\n            for (int steps = 0; steps < 400 && !(cr == ti && cc == tj); steps++) {\n                int bestd = 0, bestdist = INT_MAX;\n                for (int d = 0; d < 4; d++) {\n                    int nr = cr + dr[d], nc = cc + dc[d];\n                    if (nr < 0 || nr >= H || nc < 0 || nc >= W) continue;\n                    if (dest[id(cr,cc)][d] == -1) continue;\n                    int md = abs(nr - ti) + abs(nc - tj);\n                    if (md < bestdist) { bestdist = md; bestd = d; }\n                }\n                base.push_back(bestd); cr += dr[bestd]; cc += dc[bestd];\n            }\n        }\n        int prev = -1;\n        for (int i = 0; i < (int)base.size(); i++) {\n            int d = base[i];\n            bool is_turn_start = (i == 0) || (base[i-1] != d);\n            if (reinforce && prev != -1 && prev != d) { if ((int)seq.size() < L0) seq.push_back(prev); }\n            int reps = dup_k + (is_turn_start ? boost_next : 0); if (reps < 1) reps = 1;\n            for (int r = 0; r < reps && (int)seq.size() < L0; r++) seq.push_back(d);\n            prev = d;\n        }\n        if (seq.empty()) seq.push_back(3);\n        if ((int)seq.size() < L0) {\n            vector<int> tiled = seq;\n            while ((int)seq.size() < L0) { for (int d : tiled) { seq.push_back(d); if ((int)seq.size() >= L0) break; } }\n        }\n        return seq;\n    };\n    auto build_seq_toT_then_orbit_with = [&](const vector<int>& path, int dup_k, bool reinforce, const vector<int>& orbit_template, bool cornerboost, int boost_next)->vector<int>{\n        vector<int> seq; seq.reserve(L0);\n        vector<int> base = path;\n        if (base.empty()) {\n            int cr = si, cc = sj;\n            for (int steps = 0; steps < 400 && !(cr == ti && cc == tj); steps++) {\n                int bestd = 0, bestdist = INT_MAX;\n                for (int d = 0; d < 4; d++) {\n                    int nr = cr + dr[d], nc = cc + dc[d];\n                    if (nr < 0 || nr >= H || nc < 0 || nc >= W) continue;\n                    if (dest[id(cr,cc)][d] == -1) continue;\n                    int md = abs(nr - ti) + abs(nc - tj);\n                    if (md < bestdist) { bestdist = md; bestd = d; }\n                }\n                base.push_back(bestd); cr += dr[bestd]; cc += dc[bestd];\n            }\n        }\n        int prev = -1;\n        for (int i = 0; i < (int)base.size(); i++) {\n            int d = base[i];\n            bool is_turn_start = (i == 0) || (base[i-1] != d);\n            if (reinforce && prev != -1 && prev != d) { if ((int)seq.size() < L0) seq.push_back(prev); }\n            int reps = dup_k + (cornerboost && is_turn_start ? boost_next : 0); if (reps < 1) reps = 1;\n            for (int r = 0; r < reps && (int)seq.size() < L0; r++) seq.push_back(d);\n            prev = d;\n        }\n        vector<int> orbit;\n        for (int d : orbit_template) {\n            int reps = max(1, dup_k);\n            for (int r = 0; r < reps; r++) orbit.push_back(d);\n        }\n        if (orbit.empty()) orbit.push_back(3);\n        while ((int)seq.size() < L0) { for (int d : orbit) { seq.push_back(d); if ((int)seq.size() >= L0) break; } }\n        return seq;\n    };\n\n    auto compute_orbits = [&]()->vector<vector<int>> {\n        vector<int> push;\n        if (ti > 0 && v[ti-1][tj] == '0') push.push_back(1);\n        if (ti < H-1 && v[ti][tj] == '0') push.push_back(0);\n        if (tj > 0 && h[ti][tj-1] == '0') push.push_back(3);\n        if (tj < W-1 && h[ti][tj] == '0') push.push_back(2);\n        if (push.empty()) push = {0,1,2,3};\n        vector<vector<int>> res;\n        res.push_back(push);\n        vector<int> rev = push; reverse(rev.begin(), rev.end()); if (rev != push) res.push_back(rev);\n        if ((int)push.size() >= 3) { vector<int> rot = push; rotate(rot.begin(), rot.begin()+1, rot.end()); if (rot != push && rot != rev) res.push_back(rot); }\n        return res;\n    };\n\n    // Buffers\n    vector<array<double,400>> g(L0);\n    vector<array<double,400>> Fwd(L0+1);\n    array<double,400> gtmp, vcur, vtmp, vbest;\n\n    auto compute_backward_g_len = [&](const vector<int>& seq, int Len){\n        for (int i = 0; i < N; i++) g[Len-1][i] = 0.0;\n        g[Len-1][t_id] = double(401 - Len);\n        for (int t = Len - 2; t >= 0; t--) {\n            for (int i = 0; i < N; i++) g[t][i] = 0.0;\n            g[t][t_id] = 1.0;\n            int dn = seq[t+1];\n            apply_left(dn, g[t+1].data(), gtmp.data());\n            for (int i = 0; i < N; i++) g[t][i] += gtmp[i];\n        }\n    };\n    auto compute_forward_F_len = [&](const vector<int>& seq, int Len){\n        for (int i = 0; i < N; i++) Fwd[0][i] = 0.0;\n        Fwd[0][s_id] = 1.0;\n        for (int t = 0; t < Len; t++) apply_right(seq[t], Fwd[t].data(), Fwd[t+1].data());\n    };\n    auto find_saturation = [&](const vector<int>& seq, int Len, double thr)->int {\n        compute_forward_F_len(seq, Len);\n        for (int t = 0; t <= Len; t++) if (Fwd[t][t_id] >= thr) return t;\n        return Len;\n    };\n    auto evaluate_best_prefix = [&](const vector<int>& seq)->pair<double,int>{\n        for (int i = 0; i < N; i++) vcur[i] = 0.0; vcur[s_id] = 1.0;\n        double sum_prev = 0.0;\n        double best_score = -1e300; int best_len = 1;\n        for (int t = 0; t < L0; t++) {\n            apply_right(seq[t], vcur.data(), vtmp.data());\n            for (int i = 0; i < N; i++) vcur[i] = vtmp[i];\n            double Ft = vcur[t_id]; int Lcur = t+1;\n            double score = sum_prev + (401.0 - Lcur) * Ft;\n            if (score > best_score) { best_score = score; best_len = Lcur; }\n            sum_prev += Ft;\n        }\n        return {best_score, best_len};\n    };\n\n    const double eps = 1e-12;\n\n    auto forward_single_pass = [&](vector<int>& seq, int Len, double TL, double t0)->bool {\n        compute_backward_g_len(seq, Len);\n        for (int i = 0; i < N; i++) vcur[i] = 0.0; vcur[s_id] = 1.0;\n        bool changed = false;\n        for (int t = 0; t < Len; t++) {\n            int old_dir = seq[t]; double best_val = -1e300; int best_dir = old_dir;\n            for (int d = 0; d < 4; d++) {\n                double val = apply_right_and_dot(d, vcur.data(), vtmp.data(), g[t].data());\n                if (val > best_val + eps || (fabs(val - best_val) <= eps && d == old_dir)) {\n                    best_val = val; best_dir = d; for (int i = 0; i < N; i++) vbest[i] = vtmp[i];\n                }\n            }\n            if (best_dir != old_dir) { changed = true; seq[t] = best_dir; }\n            for (int i = 0; i < N; i++) vcur[i] = vbest[i];\n            if ((t & 31) == 0 && now_sec() - t0 > TL) break;\n        }\n        return changed;\n    };\n    auto backward_single_pass = [&](vector<int>& seq, int Len, double TL, double t0)->bool {\n        compute_forward_F_len(seq, Len);\n        array<double,400> g_at; for (int i = 0; i < N; i++) g_at[i] = 0.0; g_at[t_id] = double(401 - Len);\n        bool changed = false;\n        for (int t = Len - 1; t >= 0; --t) {\n            int old_dir = seq[t]; int best_dir = old_dir; double best_val = -1e300;\n            for (int d = 0; d < 4; d++) {\n                double val = apply_right_and_dot(d, Fwd[t].data(), vtmp.data(), g_at.data());\n                if (val > best_val + eps || (fabs(val - best_val) <= eps && d == old_dir)) { best_val = val; best_dir = d; }\n            }\n            if (best_dir != old_dir) { changed = true; seq[t] = best_dir; }\n            if (t > 0) {\n                apply_left(seq[t], g_at.data(), gtmp.data());\n                for (int i = 0; i < N; i++) g_at[i] = gtmp[i];\n                g_at[t_id] += 1.0;\n            }\n            if (((Len - 1 - t) & 31) == 0 && now_sec() - t0 > TL) break;\n        }\n        return changed;\n    };\n    auto forward_pair_pass = [&](vector<int>& seq, int Len, int limitT, double TL, double t0)->bool {\n        compute_backward_g_len(seq, Len);\n        for (int i = 0; i < N; i++) vcur[i] = 0.0; vcur[s_id] = 1.0;\n        bool changed = false;\n        array<array<double,400>,4> X, GB;\n        int t = 0, lim = min(Len, max(0, limitT));\n        while (t < lim) {\n            if ((t & 15) == 0 && now_sec() - t0 > TL) break;\n            if (t == lim - 1) {\n                int old_dir = seq[t]; int best_dir = old_dir; double best_val = -1e300;\n                for (int d = 0; d < 4; d++) {\n                    double val = apply_right_and_dot(d, vcur.data(), vtmp.data(), g[t].data());\n                    if (val > best_val + eps || (fabs(val - best_val) <= eps && d == old_dir)) { best_val = val; best_dir = d; for (int i = 0; i < N; i++) vbest[i] = vtmp[i]; }\n                }\n                if (best_dir != old_dir) { changed = true; seq[t] = best_dir; }\n                for (int i = 0; i < N; i++) vcur[i] = vbest[i];\n                t++; continue;\n            }\n            for (int a = 0; a < 4; a++) apply_right(a, vcur.data(), X[a].data());\n            for (int b = 0; b < 4; b++) { apply_left(b, g[t+1].data(), GB[b].data()); GB[b][t_id] += 1.0; }\n            int old_a = seq[t], old_b = seq[t+1], best_a = old_a, best_b = old_b; double best_val = -1e300;\n            for (int a = 0; a < 4; a++) {\n                const double* xa = X[a].data();\n                for (int b = 0; b < 4; b++) {\n                    const double* gb = GB[b].data(); double val = 0.0;\n                    for (int i = 0; i < N; i++) val += xa[i] * gb[i];\n                    bool tie_keep = (a == old_a && b == old_b);\n                    if (val > best_val + eps || (fabs(val - best_val) <= eps && tie_keep)) { best_val = val; best_a = a; best_b = b; }\n                }\n            }\n            if (best_a != old_a || best_b != old_b) changed = true;\n            seq[t] = best_a; seq[t+1] = best_b;\n            const double* v1 = X[best_a].data(); apply_right(best_b, v1, vtmp.data());\n            for (int i = 0; i < N; i++) vcur[i] = vtmp[i];\n            t += 2;\n        }\n        return changed;\n    };\n    auto forward_triple_pass = [&](vector<int>& seq, int Len, int limitT, double TL, double t0)->bool {\n        compute_backward_g_len(seq, Len);\n        for (int i = 0; i < N; i++) vcur[i] = 0.0; vcur[s_id] = 1.0;\n        bool changed = false;\n        array<array<double,400>,4> X, Hc, GB2c;\n        int t = 0, lim = min(Len, max(0, limitT));\n        while (t < lim) {\n            if ((t & 7) == 0 && now_sec() - t0 > TL) break;\n            int remain = lim - t;\n            if (remain >= 3) {\n                for (int a = 0; a < 4; a++) apply_right(a, vcur.data(), X[a].data());\n                for (int c = 0; c < 4; c++) { apply_left(c, g[t+2].data(), Hc[c].data()); Hc[c][t_id] += 1.0; }\n                int old_a = seq[t], old_b = seq[t+1], old_c = seq[t+2];\n                int best_a = old_a, best_b = old_b, best_c = old_c; double best_val = -1e300;\n                for (int b = 0; b < 4; b++) {\n                    for (int c = 0; c < 4; c++) apply_left(b, Hc[c].data(), GB2c[c].data());\n                    for (int a = 0; a < 4; a++) {\n                        const double* xa = X[a].data();\n                        for (int c = 0; c < 4; c++) {\n                            const double* gb = GB2c[c].data(); double val = xa[t_id];\n                            for (int i = 0; i < N; i++) val += xa[i] * gb[i];\n                            bool tie_keep = (a == old_a && b == old_b && c == old_c);\n                            if (val > best_val + eps || (fabs(val - best_val) <= eps && tie_keep)) { best_val = val; best_a = a; best_b = b; best_c = c; }\n                        }\n                    }\n                }\n                if (best_a != old_a || best_b != old_b || best_c != old_c) changed = true;\n                seq[t] = best_a; seq[t+1] = best_b; seq[t+2] = best_c;\n                const double* v1 = X[best_a].data(); apply_right(best_b, v1, vtmp.data());\n                array<double,400> v2 = vtmp; apply_right(best_c, v2.data(), vtmp.data());\n                for (int i = 0; i < N; i++) vcur[i] = vtmp[i];\n                t += 3;\n            } else {\n                for (; t < lim; t++) {\n                    int old_dir = seq[t]; int best_dir = old_dir; double best_val = -1e300;\n                    for (int d = 0; d < 4; d++) {\n                        double val = apply_right_and_dot(d, vcur.data(), vtmp.data(), g[t].data());\n                        if (val > best_val + eps || (fabs(val - best_val) <= eps && d == old_dir)) { best_val = val; best_dir = d; for (int i = 0; i < N; i++) vbest[i] = vtmp[i]; }\n                    }\n                    if (best_dir != old_dir) { changed = true; seq[t] = best_dir; }\n                    for (int i = 0; i < N; i++) vcur[i] = vbest[i];\n                }\n            }\n        }\n        return changed;\n    };\n    auto forward_quad_pass = [&](vector<int>& seq, int Len, int limitT, double TL, double t0)->bool {\n        compute_backward_g_len(seq, Len);\n        for (int i = 0; i < N; i++) vcur[i] = 0.0; vcur[s_id] = 1.0;\n        bool changed = false;\n        array<array<double,400>,4> X, E3;\n        array<double,400> tmp;\n        int lim = min(Len, max(0, limitT));\n        for (int t = 0; t + 3 < lim; t += 4) {\n            if ((t & 7) == 0 && now_sec() - t0 > TL) break;\n            for (int a = 0; a < 4; a++) apply_right(a, vcur.data(), X[a].data());\n            for (int d = 0; d < 4; d++) { apply_left(d, g[t+3].data(), E3[d].data()); E3[d][t_id] += 1.0; }\n            int old_a = seq[t], old_b = seq[t+1], old_c = seq[t+2], old_d = seq[t+3];\n            int best_a = old_a, best_b = old_b, best_c = old_c, best_d = old_d; double best_val = -1e300;\n            for (int d = 0; d < 4; d++) {\n                array<array<double,400>,4> E2c;\n                for (int c = 0; c < 4; c++) { apply_left(c, E3[d].data(), E2c[c].data()); E2c[c][t_id] += 1.0; }\n                for (int c = 0; c < 4; c++) {\n                    for (int b = 0; b < 4; b++) {\n                        apply_left(b, E2c[c].data(), tmp.data()); tmp[t_id] += 1.0;\n                        for (int a = 0; a < 4; a++) {\n                            const double* xa = X[a].data(); double val = 0.0;\n                            for (int i = 0; i < N; i++) val += xa[i] * tmp[i];\n                            bool tie_keep = (a == old_a && b == old_b && c == old_c && d == old_d);\n                            if (val > best_val + eps || (fabs(val - best_val) <= eps && tie_keep)) { best_val = val; best_a = a; best_b = b; best_c = c; best_d = d; }\n                        }\n                    }\n                }\n            }\n            if (best_a != old_a || best_b != old_b || best_c != old_c || best_d != old_d) changed = true;\n            seq[t] = best_a; seq[t+1] = best_b; seq[t+2] = best_c; seq[t+3] = best_d;\n            array<double,400> v1, v2, v3;\n            apply_right(best_a, vcur.data(), v1.data());\n            apply_right(best_b, v1.data(), v2.data());\n            apply_right(best_c, v2.data(), v3.data());\n            apply_right(best_d, v3.data(), vcur.data());\n        }\n        return changed;\n    };\n\n    // Initial seeds\n    vector<array<int,4>> orders;\n    array<int,4> base = {0,1,2,3};\n    orders.push_back({0,1,2,3});\n    orders.push_back({1,0,3,2});\n    orders.push_back({2,3,0,1});\n    orders.push_back({3,2,1,0});\n    for (int k = 0; k < 4; k++) { array<int,4> ord = base; for (int i = 3; i > 0; --i) { int j = rng.randint(0, i); swap(ord[i], ord[j]); } orders.push_back(ord); }\n\n    auto compute_k_target = [&](int Lsp)->int{\n        if (Lsp <= 0) return 1;\n        double target = 0.85;\n        double step_goal = pow(target, 1.0 / max(1, Lsp));\n        double rhs = 1.0 - step_goal;\n        if (rhs <= 0.0 || p <= 0.0) return 1;\n        double kreal = log(rhs) / log(p);\n        int k = (int)ceil(kreal);\n        return max(1, min(6, k));\n    };\n    int k_nominal = (int)ceil(1.0 / (1.0 - p));\n\n    struct Candidate { vector<int> seq; double score; int len; };\n    vector<Candidate> pool;\n    vector<vector<int>> orbit_templates = compute_orbits();\n\n    for (int oi = 0; oi < (int)orders.size(); oi++) {\n        vector<int> path = bfs_path(orders[oi]); int Lsp = (int)path.size();\n        vector<int> dup_ks;\n        auto addk = [&](int k){ k = max(1, min(6, k)); if (find(dup_ks.begin(), dup_ks.end(), k) == dup_ks.end()) dup_ks.push_back(k); };\n        addk(1); addk(k_nominal); addk(k_nominal + 1); int kt = compute_k_target(Lsp); addk(kt); addk(kt + 1);\n\n        for (int rf = 0; rf < 2; rf++) {\n            bool reinforce = (rf == 1);\n            for (int k : dup_ks) {\n                {\n                    vector<int> seq = build_seq_from_path_variant(path, k, reinforce);\n                    auto [sc, ln] = evaluate_best_prefix(seq);\n                    pool.push_back({move(seq), sc, ln});\n                }\n                {\n                    vector<int> seq = build_seq_from_path_cornerboost(path, k, reinforce, 1);\n                    auto [sc, ln] = evaluate_best_prefix(seq);\n                    pool.push_back({move(seq), sc, ln});\n                }\n                for (const auto& orb : orbit_templates) {\n                    vector<int> seq = build_seq_toT_then_orbit_with(path, k, reinforce, orb, false, 0);\n                    auto [sc, ln] = evaluate_best_prefix(seq);\n                    pool.push_back({move(seq), sc, ln});\n                    vector<int> seq2 = build_seq_toT_then_orbit_with(path, k, reinforce, orb, true, 1);\n                    auto [sc2, ln2] = evaluate_best_prefix(seq2);\n                    pool.push_back({move(seq2), sc2, ln2});\n                }\n            }\n        }\n        if ((int)pool.size() > 28) break;\n    }\n    sort(pool.begin(), pool.end(), [&](const Candidate& a, const Candidate& b){ return a.score > b.score; });\n    if ((int)pool.size() > 14) pool.resize(14);\n\n    const double TL = 1.95; double t0 = now_sec();\n\n    double global_best_score = -1e300; int global_best_len = L0; vector<int> global_best_seq;\n\n    // Improve candidates\n    for (auto &cand : pool) {\n        if (now_sec() - t0 >= TL) break;\n        vector<int> seq = cand.seq;\n        auto [local_best_score, local_best_len] = evaluate_best_prefix(seq);\n        vector<int> local_best_seq = seq;\n\n        int iter = 0;\n        while (now_sec() - t0 < TL) {\n            int sat = find_saturation(seq, L0, 0.999);\n            int quad_lim   = min(L0, sat + 24);\n            int triple_lim = min(L0, sat + 32);\n            int pair_lim   = min(L0, sat + 56);\n\n            bool changed_any = false;\n            changed_any |= forward_quad_pass(seq, L0, quad_lim, TL, t0); if (now_sec() - t0 >= TL) break;\n            changed_any |= forward_triple_pass(seq, L0, triple_lim, TL, t0); if (now_sec() - t0 >= TL) break;\n            changed_any |= forward_pair_pass(seq, L0, pair_lim, TL, t0); if (now_sec() - t0 >= TL) break;\n            changed_any |= backward_single_pass(seq, L0, TL, t0); if (now_sec() - t0 >= TL) break;\n            changed_any |= forward_single_pass(seq, L0, TL, t0); if (now_sec() - t0 >= TL) break;\n\n            auto [sc, ln] = evaluate_best_prefix(seq);\n            if (sc > local_best_score + 1e-9) { local_best_score = sc; local_best_len = ln; local_best_seq = seq; }\n\n            iter++; if (!changed_any || iter >= 6) break;\n        }\n\n        if (local_best_score > global_best_score + 1e-9) {\n            global_best_score = local_best_score; global_best_len = local_best_len; global_best_seq = local_best_seq;\n        }\n    }\n\n    // Perturbation\n    int perturb_trials = 0;\n    while (now_sec() - t0 < TL && perturb_trials < 5 && !global_best_seq.empty()) {\n        perturb_trials++;\n        vector<int> seq = global_best_seq;\n        int K = 6 + rng.randint(0, 8);\n        for (int k = 0; k < K; k++) { int tpos = rng.randint(0, L0 - 1); int ndir = rng.randint(0, 3); seq[tpos] = ndir; }\n        auto [local_best_score, local_best_len] = evaluate_best_prefix(seq);\n        vector<int> local_best_seq = seq;\n\n        int iter = 0;\n        while (now_sec() - t0 < TL) {\n            int sat = find_saturation(seq, L0, 0.999);\n            int quad_lim   = min(L0, sat + 24);\n            int triple_lim = min(L0, sat + 32);\n            int pair_lim   = min(L0, sat + 56);\n\n            bool changed_any = false;\n            changed_any |= forward_quad_pass(seq, L0, quad_lim, TL, t0); if (now_sec() - t0 >= TL) break;\n            changed_any |= forward_triple_pass(seq, L0, triple_lim, TL, t0); if (now_sec() - t0 >= TL) break;\n            changed_any |= forward_pair_pass(seq, L0, pair_lim, TL, t0); if (now_sec() - t0 >= TL) break;\n            changed_any |= backward_single_pass(seq, L0, TL, t0); if (now_sec() - t0 >= TL) break;\n            changed_any |= forward_single_pass(seq, L0, TL, t0); if (now_sec() - t0 >= TL) break;\n\n            auto [sc, ln] = evaluate_best_prefix(seq);\n            if (sc > local_best_score + 1e-9) { local_best_score = sc; local_best_len = ln; local_best_seq = seq; }\n\n            iter++; if (!changed_any || iter >= 5) break;\n        }\n\n        if (local_best_score > global_best_score + 1e-9) {\n            global_best_score = local_best_score; global_best_len = local_best_len; global_best_seq = local_best_seq;\n        }\n    }\n\n    // Final refinement under best length if time remains\n    if (!global_best_seq.empty() && now_sec() - t0 < TL - 0.08) {\n        int Len = global_best_len;\n        for (int it = 0; it < 2 && now_sec() - t0 < TL - 0.02; it++) {\n            forward_quad_pass(global_best_seq, Len, Len, TL, t0);\n            forward_triple_pass(global_best_seq, Len, Len, TL, t0);\n            forward_pair_pass(global_best_seq, Len, Len, TL, t0);\n            backward_single_pass(global_best_seq, Len, TL, t0);\n            forward_single_pass(global_best_seq, Len, TL, t0);\n            auto [sc, ln] = evaluate_best_prefix(global_best_seq);\n            if (sc > global_best_score + 1e-9) { global_best_score = sc; global_best_len = ln; Len = ln; }\n        }\n    }\n\n    if (global_best_seq.empty()) {\n        vector<int> path = bfs_path({0,1,2,3});\n        auto fallback = build_seq_from_path_variant(path, 1, false);\n        global_best_seq = fallback;\n        auto [scb, lnb] = evaluate_best_prefix(global_best_seq);\n        global_best_len = lnb;\n    }\n\n    // Output best prefix\n    string out; int out_len = max(1, min(global_best_len, L0));\n    out.reserve(out_len);\n    for (int i = 0; i < out_len; i++) out.push_back(DIRC[global_best_seq[i]]);\n    cout << out << \"\\n\";\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const { return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count(); }\n};\n\n// RNG\nstruct XorShift {\n    uint64_t x;\n    XorShift() { x = 88172645463393265ull; }\n    void reseed(uint64_t s) {\n        if (s == 0) s = 88172645463393265ull;\n        x = s ^ (s << 13) ^ (s >> 7) ^ (s << 17);\n        if (x == 0) x = 88172645463393265ull;\n    }\n    inline uint64_t next() { x ^= x << 7; x ^= x << 13; x ^= x >> 9; return x; }\n    inline uint32_t next_u32() { return (uint32_t)next(); }\n    inline int randint(int l, int r) { return l + (int)(next_u32() % (uint32_t)(r - l + 1)); }\n    inline double rand01() { return (next_u32() & 0xFFFFFF) / double(0x1000000); }\n} rng;\n\n// Directions: 0=left,1=up,2=right,3=down\nstatic const int di[4] = {0,-1,0,1};\nstatic const int dj[4] = {-1,0,1,0};\n\n// to[t][d]\nstatic const int TO[8][4] = {\n    {1, 0, -1, -1},\n    {3, -1, -1, 0},\n    {-1, -1, 3, 2},\n    {-1, 2, 1, -1},\n    {1, 0, 3, 2},\n    {3, 2, 1, 0},\n    {2, -1, 0, -1},\n    {-1, 3, -1, 1},\n};\n\nstatic bool PRES[8][4];\nstatic int OUT_COUNT_TO[8][4];\nstatic bool EXIST_OUT[8][4];\n\ninline int rotate_t(int t, int r) {\n    if (t < 4) return (t + r) & 3;\n    if (t < 6) return (r & 1) ? 9 - t : t; // 4<->5\n    return (r & 1) ? 13 - t : t;           // 6<->7\n}\n\nstatic inline int state_id(int i, int j, int d) {\n    return ((i * 30 + j) << 2) | d;\n}\n\nstruct LoopEval {\n    long long L1=0, L2=0;\n    long long sumCycles=0;\n    int cycleCount=0;\n    long long product() const { return (L2==0 ? 0LL : L1*L2); }\n};\n\nLoopEval evaluate_loops(const array<array<int,30>,30>& eff) {\n    const int N=30, M=30, TOT=N*M*4;\n    static int next_state[30*30*4];\n    static unsigned char allowed[30*30*4];\n    for (int i=0;i<N;i++){\n        for (int j=0;j<M;j++){\n            int t = eff[i][j];\n            for (int d=0; d<4; d++){\n                int idx = state_id(i,j,d);\n                int d2 = TO[t][d];\n                if (d2 == -1) { allowed[idx]=0; next_state[idx]=-1; continue; }\n                allowed[idx]=1;\n                int i2 = i + di[d2], j2 = j + dj[d2];\n                if (i2<0||i2>=N||j2<0||j2>=M) next_state[idx]=-1;\n                else {\n                    int t2=eff[i2][j2];\n                    int d_rev=(d2+2)&3;\n                    next_state[idx] = (TO[t2][d_rev]==-1)? -1 : state_id(i2,j2,d_rev);\n                }\n            }\n        }\n    }\n    static unsigned char visited[30*30*4];\n    static int seen_pass[30*30*4];\n    static int seen_pos[30*30*4];\n    memset(visited,0,sizeof(visited));\n    int pass_id=1;\n    long long best1=0,best2=0,sumC=0;\n    int cntC=0;\n    int stack_arr[30*30*4];\n    for (int v0=0; v0<TOT; v0++){\n        if (!allowed[v0] || visited[v0]) continue;\n        int v=v0, top=0;\n        ++pass_id;\n        while (true){\n            if (v<0 || !allowed[v] || next_state[v]==-1) { while(top) visited[stack_arr[--top]]=1; break; }\n            if (visited[v]) { while(top) visited[stack_arr[--top]]=1; break; }\n            if (seen_pass[v] == pass_id){\n                int cycle_len = top - seen_pos[v];\n                long long L=cycle_len;\n                sumC += L; cntC++;\n                if (L>best1){ best2=best1; best1=L; }\n                else if (L>best2){ best2=L; }\n                while(top) visited[stack_arr[--top]]=1;\n                break;\n            }\n            seen_pass[v]=pass_id;\n            seen_pos[v]=top;\n            stack_arr[top++]=v;\n            v = next_state[v];\n        }\n    }\n    LoopEval le; le.L1=best1; le.L2=best2; le.sumCycles=sumC; le.cycleCount=cntC;\n    return le;\n}\n\nstruct LoopEvalSets {\n    LoopEval le;\n    array<unsigned char,900> in1{}, in2{};\n};\nLoopEvalSets evaluate_loops_with_sets(const array<array<int,30>,30>& eff){\n    const int N=30,M=30,TOT=N*M*4;\n    static int next_state[30*30*4];\n    static unsigned char allowed[30*30*4];\n    for(int i=0;i<N;i++){\n        for(int j=0;j<M;j++){\n            int t=eff[i][j];\n            for(int d=0; d<4; d++){\n                int idx=state_id(i,j,d);\n                int d2=TO[t][d];\n                if(d2==-1){ allowed[idx]=0; next_state[idx]=-1; continue; }\n                allowed[idx]=1;\n                int i2=i+di[d2], j2=j+dj[d2];\n                if(i2<0||i2>=N||j2<0||j2>=M) next_state[idx]=-1;\n                else {\n                    int t2=eff[i2][j2];\n                    int d_rev=(d2+2)&3;\n                    next_state[idx] = (TO[t2][d_rev]==-1)? -1 : state_id(i2,j2,d_rev);\n                }\n            }\n        }\n    }\n    static unsigned char visited[30*30*4];\n    static int seen_pass[30*30*4];\n    static int seen_pos[30*30*4];\n    memset(visited,0,sizeof(visited));\n    int pass_id=1;\n    long long best1=0,best2=0,sumC=0;\n    int cntC=0;\n    int stack_arr[30*30*4];\n    array<unsigned char,900> in1{}; array<unsigned char,900> in2{}; array<unsigned char,900> temp{};\n    for(int v0=0; v0<TOT; v0++){\n        if(!allowed[v0] || visited[v0]) continue;\n        int v=v0, top=0;\n        ++pass_id;\n        while(true){\n            if(v<0 || !allowed[v] || next_state[v]==-1){ while(top) visited[stack_arr[--top]]=1; break; }\n            if(visited[v]){ while(top) visited[stack_arr[--top]]=1; break; }\n            if(seen_pass[v]==pass_id){\n                int start=seen_pos[v];\n                int cycle_len=top-start;\n                long long L=cycle_len;\n                sumC += L; cntC++;\n                bool beats1 = (L>best1);\n                bool beats2 = (!beats1 && L>best2);\n                if(beats1||beats2){\n                    temp.fill(0);\n                    for(int k=start;k<top;k++){\n                        int tile = stack_arr[k] >> 2;\n                        temp[tile]=1;\n                    }\n                    if(beats1){ best2=best1; in2=in1; best1=L; in1=temp; }\n                    else { best2=L; in2=temp; }\n                }\n                while(top) visited[stack_arr[--top]]=1;\n                break;\n            }\n            seen_pass[v]=pass_id;\n            seen_pos[v]=top;\n            stack_arr[top++]=v;\n            v=next_state[v];\n        }\n    }\n    LoopEvalSets les; les.le.L1=best1; les.le.L2=best2; les.le.sumCycles=sumC; les.le.cycleCount=cntC; les.in1=in1; les.in2=in2;\n    return les;\n}\n\n// S2 surrogate\nstruct Score2 {\n    int N=30,M=30;\n    inline int count_outgoing(const array<array<int,30>,30>& eff, int i, int j, int t) const {\n        int s=0;\n        for(int d=0; d<4; d++){\n            int d2=TO[t][d];\n            if(d2==-1) continue;\n            int i2=i+di[d2], j2=j+dj[d2];\n            if(i2<0||i2>=N||j2<0||j2>=M) continue;\n            int t2=eff[i2][j2]; int d_rev=(d2+2)&3;\n            if(TO[t2][d_rev]!=-1) s++;\n        }\n        return s;\n    }\n    long long compute_all(const array<array<int,30>,30>& eff) const {\n        long long s=0;\n        for(int i=0;i<N;i++) for(int j=0;j<M;j++) s += count_outgoing(eff,i,j,eff[i][j]);\n        return s;\n    }\n    long long delta_change(const array<array<int,30>,30>& eff, int i, int j, int curT, int newT) const {\n        long long delta = 0;\n        delta += count_outgoing(eff,i,j,newT) - count_outgoing(eff,i,j,curT);\n        if (j-1>=0){ int tL=eff[i][j-1]; int c=OUT_COUNT_TO[tL][2]; delta += c * ((PRES[newT][0]?1:0) - (PRES[curT][0]?1:0)); }\n        if (j+1< M){ int tR=eff[i][j+1]; int c=OUT_COUNT_TO[tR][0]; delta += c * ((PRES[newT][2]?1:0) - (PRES[curT][2]?1:0)); }\n        if (i-1>=0){ int tU=eff[i-1][j]; int c=OUT_COUNT_TO[tU][3]; delta += c * ((PRES[newT][1]?1:0) - (PRES[curT][1]?1:0)); }\n        if (i+1< N){ int tD=eff[i+1][j]; int c=OUT_COUNT_TO[tD][1]; delta += c * ((PRES[newT][3]?1:0) - (PRES[curT][3]?1:0)); }\n        return delta;\n    }\n};\n\nstatic int boundary_friendly_rotation(int base_t, int i, int j){\n    const int N=30,M=30;\n    int bestR=0,bestBad=1e9;\n    for(int r=0;r<4;r++){\n        int tt=rotate_t(base_t,r);\n        int bad=0;\n        if(i==0 && PRES[tt][1]) bad++;\n        if(i==N-1 && PRES[tt][3]) bad++;\n        if(j==0 && PRES[tt][0]) bad++;\n        if(j==M-1 && PRES[tt][2]) bad++;\n        if(bad<bestBad){ bestBad=bad; bestR=r; }\n    }\n    return bestR;\n}\n\ninline int count_invalid_exits(const array<array<int,30>,30>& eff, int i, int j){\n    const int N=30,M=30;\n    int t=eff[i][j];\n    int bad=0;\n    for(int d=0; d<4; d++){\n        int d2=TO[t][d];\n        if(d2==-1) continue;\n        int i2=i+di[d2], j2=j+dj[d2];\n        if(i2<0||i2>=N||j2<0||j2>=M){ bad++; continue; }\n        int t2=eff[i2][j2]; int d_rev=(d2+2)&3;\n        if(TO[t2][d_rev]==-1) bad++;\n    }\n    return bad;\n}\n\nvoid improve_blocks_2x2(array<array<int,30>,30>& eff, array<array<int,30>,30>& rot,\n                        const array<array<int,30>,30>& base, Score2& scorer2,\n                        long long& S2, double end_time, Timer& timer){\n    const int N=30,M=30;\n    vector<pair<int,int>> blocks;\n    blocks.reserve((N-1)*(M-1));\n    for(int i=0;i<N-1;i++) for(int j=0;j<M-1;j++) blocks.emplace_back(i,j);\n    shuffle(blocks.begin(), blocks.end(), std::mt19937(rng.next_u32()));\n    for(auto &p: blocks){\n        if(timer.elapsed()>end_time) break;\n        int si=p.first, sj=p.second;\n        for(int sweep=0;sweep<2;sweep++){\n            bool improved=false;\n            for(int k=0;k<4;k++){\n                int i=si+(k>>1), j=sj+(k&1);\n                int base_t=base[i][j];\n                int curR=rot[i][j], curT=eff[i][j];\n                long long bestDelta=0; int bestR=curR;\n                for(int r=0;r<4;r++){\n                    if(r==curR) continue;\n                    int newT=rotate_t(base_t,r);\n                    long long delta=scorer2.delta_change(eff,i,j,curT,newT);\n                    if(delta>bestDelta){ bestDelta=delta; bestR=r; }\n                }\n                if(bestR!=curR){\n                    int newT=rotate_t(base_t,bestR);\n                    S2 += scorer2.delta_change(eff,i,j,curT,newT);\n                    rot[i][j]=bestR; eff[i][j]=newT; improved=true;\n                }\n            }\n            if(!improved) break;\n        }\n    }\n}\n\n// Build a \"near\" set: tiles in set or 4-neighbors of any tile in set\nstatic void build_near_set(const array<unsigned char,900>& inSet, array<unsigned char,900>& nearSet){\n    nearSet.fill(0);\n    for (int i=0;i<30;i++){\n        for (int j=0;j<30;j++){\n            int idx = i*30 + j;\n            if (inSet[idx]) {\n                nearSet[idx] = 1;\n                if (j-1>=0) nearSet[i*30 + (j-1)] = 1;\n                if (j+1<30) nearSet[i*30 + (j+1)] = 1;\n                if (i-1>=0) nearSet[(i-1)*30 + j] = 1;\n                if (i+1<30) nearSet[(i+1)*30 + j] = 1;\n            }\n        }\n    }\n}\n\n// Tournament helper with avoid and prefer sets\npair<int,int> pick_tile_biased(const array<array<int,30>,30>& effCur, int K, bool allow_random,\n                               const unsigned char* avoidSet=nullptr, double avoidProb=0.0,\n                               const unsigned char* preferSet=nullptr, int preferBoost=0){\n    const int N=30,M=30;\n    for(int attempt=0; attempt<8; ++attempt){\n        int bi=-1,bj=-1,bbest=-INT_MAX;\n        if(allow_random && rng.rand01()<0.1){\n            bi=rng.randint(0,N-1); bj=rng.randint(0,M-1);\n        } else {\n            for(int k=0;k<K;k++){\n                int ci=rng.randint(0,N-1), cj=rng.randint(0,M-1);\n                int score = count_invalid_exits(effCur,ci,cj);\n                if (preferSet && preferSet[ci*30 + cj]) score += preferBoost;\n                if (score > bbest || (score == bbest && rng.rand01() < 0.5)) {\n                    bbest = score; bi = ci; bj = cj;\n                }\n            }\n        }\n        if (!avoidSet) return {bi,bj};\n        int tile = bi*30 + bj;\n        if (!(avoidSet[tile] && rng.rand01() < avoidProb)) return {bi,bj};\n    }\n    return {rng.randint(0,29), rng.randint(0,29)};\n}\n\n// Final precise 2x2 block enumeration under true objective (small number of blocks)\nvoid refine_blocks_true(array<array<int,30>,30>& bestRot, array<array<int,30>,30>& bestEff, const array<array<int,30>,30>& base,\n                        const unsigned char* avoidSet, double time_end, Timer& timer, int maxBlocks=4) {\n    const int N=30,M=30;\n    struct Cand { int score; int i,j; };\n    vector<Cand> cands; cands.reserve((N-1)*(M-1));\n    for (int i=0;i<N-1;i++){\n        for (int j=0;j<M-1;j++){\n            int sc=0;\n            for (int dii=0; dii<2; dii++) for (int djj=0; djj<2; djj++){\n                sc += count_invalid_exits(bestEff, i+dii, j+djj);\n            }\n            bool touchL1=false;\n            if (avoidSet){\n                for (int dii=0; dii<2; dii++) for (int djj=0; djj<2; djj++){\n                    if (avoidSet[(i+dii)*30 + (j+djj)]) { touchL1=true; break; }\n                }\n            }\n            if (touchL1) sc -= 100;\n            cands.push_back({sc,i,j});\n        }\n    }\n    sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){ return a.score > b.score; });\n    int tried=0;\n    long long baseProd = evaluate_loops(bestEff).product();\n    for (auto &cd : cands) {\n        if (tried >= maxBlocks) break;\n        if (timer.elapsed() > time_end) break;\n        int si=cd.i, sj=cd.j;\n        int t[4]; int coords[4][2] = {{si,sj},{si,sj+1},{si+1,sj},{si+1,sj+1}};\n        for (int k=0;k<4;k++){ int i=coords[k][0], j=coords[k][1]; t[k] = base[i][j]; }\n        long long bestProdLocal = baseProd;\n        int bestRs[4] = {bestRot[si][sj], bestRot[si][sj+1], bestRot[si+1][sj], bestRot[si+1][sj+1]};\n        for (int r0=0;r0<4;r0++){\n            for (int r1=0;r1<4;r1++){\n                for (int r2=0;r2<4;r2++){\n                    for (int r3=0;r3<4;r3++){\n                        int rs[4]={r0,r1,r2,r3};\n                        array<array<int,30>,30> eff2 = bestEff;\n                        for (int k=0;k<4;k++){\n                            int i=coords[k][0], j=coords[k][1];\n                            eff2[i][j] = rotate_t(t[k], rs[k]);\n                        }\n                        long long prod = evaluate_loops(eff2).product();\n                        if (prod > bestProdLocal) {\n                            bestProdLocal = prod;\n                            for (int k=0;k<4;k++) bestRs[k]=rs[k];\n                        }\n                        if (timer.elapsed() > time_end) break;\n                    }\n                    if (timer.elapsed() > time_end) break;\n                }\n                if (timer.elapsed() > time_end) break;\n            }\n            if (timer.elapsed() > time_end) break;\n        }\n        if (bestProdLocal > baseProd) {\n            for (int k=0;k<4;k++){\n                int i=coords[k][0], j=coords[k][1];\n                bestRot[i][j] = bestRs[k];\n                bestEff[i][j] = rotate_t(t[k], bestRs[k]);\n            }\n            baseProd = bestProdLocal;\n        }\n        tried++;\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        for(int d=0; d<4; d++){\n            PRES[t][d]=(TO[t][d]!=-1);\n        }\n        for(int dir=0; dir<4; dir++){\n            int c=0; for(int d=0; d<4; d++) if(TO[t][d]==dir) c++;\n            OUT_COUNT_TO[t][dir]=c; EXIST_OUT[t][dir]=(c>0);\n        }\n    }\n\n    const int N=30,M=30;\n    array<array<int,30>,30> base{};\n    for(int i=0;i<N;i++){\n        string s; if(!(cin>>s)) return 0;\n        for(int j=0;j<M;j++) base[i][j]=s[j]-'0';\n    }\n\n    // deterministic seed\n    {\n        uint64_t h=1469598103934665603ull;\n        for(int i=0;i<N;i++) for(int j=0;j<M;j++){ h ^= (uint64_t)base[i][j]; h *= 1099511628211ull; }\n        rng.reseed(h);\n    }\n\n    Timer timer;\n    const double TIME_LIMIT=1.98;\n\n    auto run_pipeline = [&](array<array<int,30>,30>& bestRot, array<array<int,30>,30>& bestEff, long long& bestProduct,\n                            double timeBudget, int init_mode){\n        double deadline = min(timer.elapsed()+timeBudget, TIME_LIMIT-0.01);\n\n        array<array<int,30>,30> rot{}, eff{};\n\n        // Initialization\n        for(int i=0;i<N;i++){\n            for(int j=0;j<M;j++){\n                int t0=base[i][j];\n                int rr=0;\n                if(init_mode==2){\n                    rr = rng.randint(0,3);\n                } else {\n                    rr = boundary_friendly_rotation(t0,i,j);\n                    if(init_mode==1 && t0>=6){\n                        bool wantHoriz=((i+j)&1)==0;\n                        int want = wantHoriz?6:7;\n                        int r0 = (t0==want?0:1);\n                        rr = r0;\n                    } else {\n                        if(rng.rand01()<0.4) rr = (rr + rng.randint(0,3)) & 3;\n                    }\n                }\n                rot[i][j]=rr; eff[i][j]=rotate_t(t0,rr);\n            }\n        }\n\n        Score2 scorer2;\n        long long S2 = scorer2.compute_all(eff);\n\n        double total = max(0.0, deadline - timer.elapsed());\n        if(total<=0) return;\n\n        // Stage durations (more SA)\n        double dur_s2 = total * 0.18;\n        double dur_block = total * 0.04;\n        double dur_sa1 = total * 0.58;\n        double dur_sa2 = total * 0.16;\n        double dur_refine = total * 0.02;\n        double dur_tail = total * 0.02;\n\n        // Stage 1: S2 descent\n        {\n            double t_end = min(deadline, timer.elapsed()+dur_s2);\n            vector<pair<int,int>> order; order.reserve(N*M);\n            for(int i=0;i<N;i++) for(int j=0;j<M;j++) order.emplace_back(i,j);\n            while(timer.elapsed()<t_end){\n                shuffle(order.begin(), order.end(), std::mt19937(rng.next_u32()));\n                bool improved=false;\n                for(auto &p: order){\n                    int i=p.first, j=p.second;\n                    int base_t=base[i][j], curR=rot[i][j], curT=eff[i][j];\n                    long long bestDelta=0; int bestR=curR;\n                    for(int r=0;r<4;r++){\n                        if(r==curR) continue;\n                        int newT=rotate_t(base_t,r);\n                        long long delta=scorer2.delta_change(eff,i,j,curT,newT);\n                        if(delta>bestDelta || (delta==bestDelta && rng.rand01()<0.1)){ bestDelta=delta; bestR=r; }\n                    }\n                    if(bestR!=curR){\n                        int newT=rotate_t(base_t,bestR);\n                        S2 += scorer2.delta_change(eff,i,j,curT,newT);\n                        rot[i][j]=bestR; eff[i][j]=newT; improved=true;\n                    }\n                    if(timer.elapsed()>=t_end) break;\n                }\n                if(!improved) break;\n            }\n            // Straight toggle pass\n            for(int i=0;i<N;i++){\n                for(int j=0;j<M;j++){\n                    int t0=base[i][j], curR=rot[i][j], curT=eff[i][j];\n                    if(t0>=6){\n                        int newR=(curR^1)&3; int newT=rotate_t(t0,newR);\n                        long long delta=scorer2.delta_change(eff,i,j,curT,newT);\n                        if(delta>0){ S2+=delta; rot[i][j]=newR; eff[i][j]=newT; }\n                    }\n                }\n            }\n        }\n\n        // Stage 1.5: 2x2 block\n        {\n            double t_end = min(deadline, timer.elapsed()+dur_block);\n            improve_blocks_2x2(eff,rot,base,scorer2,S2,t_end,timer);\n        }\n\n        // Initial eval\n        LoopEvalSets les0=evaluate_loops_with_sets(eff);\n        long long curBestProduct=les0.le.product();\n        if(curBestProduct>bestProduct){ bestProduct=curBestProduct; bestRot=rot; bestEff=eff; }\n\n        auto shapedF = [&](const LoopEval& le,double a,double b,double c)->double{\n            return (double)le.product() + a*(double)min(le.L1,le.L2) + b*(double)(le.L1+le.L2) - c*(double)le.cycleCount;\n        };\n\n        // SA Phase 1\n        {\n            double t_start=timer.elapsed();\n            double t_end=min(deadline, t_start+dur_sa1);\n            if(t_end - t_start > 1e-6){\n                auto currRot=rot; auto currEff=eff;\n                long long S2cur=S2;\n                LoopEval leCur=les0.le;\n                double currF = shapedF(leCur,3.0,0.2,1.0); // stronger fragmentation penalty early\n                double startT=6.0, endT=0.04;\n\n                while(true){\n                    double now=timer.elapsed(); if(now>=t_end) break;\n                    double progress=(now - t_start)/(t_end - t_start); if(progress<0) progress=0; if(progress>1) progress=1;\n                    double T = startT + (endT - startT)*progress;\n                    double a=3.0*(1.0 - progress), b=0.2*(1.0 - progress), c=1.0*(1.0 - progress);\n\n                    double r=rng.rand01(); bool moved=false;\n\n                    if(r<0.25){\n                        auto pr=pick_tile_biased(currEff,6,true,nullptr,0.0,nullptr,0);\n                        int i1=pr.first, j1=pr.second;\n                        int tt1=currEff[i1][j1];\n                        int cand[4], cnt=0;\n                        for(int d=0; d<4; d++){\n                            int d2=TO[tt1][d];\n                            if(d2==-1) continue;\n                            int i2=i1+di[d2], j2=j1+dj[d2];\n                            if(i2<0||i2>=N||j2<0||j2>=M) continue;\n                            int tt2=currEff[i2][j2]; int d_rev=(d2+2)&3;\n                            if(TO[tt2][d_rev]==-1) cand[cnt++]=d2;\n                        }\n                        if(cnt>0){\n                            int d2=cand[rng.randint(0,cnt-1)];\n                            int i2=i1+di[d2], j2=j1+dj[d2];\n                            int t2=base[i2][j2], oldR2=currRot[i2][j2], oldT2=currEff[i2][j2];\n                            int d_rev=(d2+2)&3;\n                            int bestR2=-1; long long bestDeltaS2=LLONG_MIN;\n                            for(int r2=0;r2<4;r2++){\n                                int nt2=rotate_t(t2,r2);\n                                if(TO[nt2][d_rev]==-1) continue;\n                                long long delta=scorer2.delta_change(currEff,i2,j2,oldT2,nt2);\n                                if(delta>bestDeltaS2){ bestDeltaS2=delta; bestR2=r2; }\n                            }\n                            if(bestR2!=-1){\n                                if(bestDeltaS2<-2 && rng.rand01()<0.9){\n                                    // skip\n                                } else {\n                                    int newR2=bestR2, newT2=rotate_t(t2,newR2);\n                                    currRot[i2][j2]=newR2; currEff[i2][j2]=newT2;\n                                    LoopEval le=evaluate_loops(currEff);\n                                    double newF=shapedF(le,a,b,c);\n                                    double diff=newF - currF;\n                                    bool accept = diff>=0 || rng.rand01()<exp(diff/max(1.0,T));\n                                    if(accept){\n                                        currF=newF; leCur=le;\n                                        S2cur += scorer2.delta_change(currEff,i2,j2,oldT2,newT2);\n                                        long long prod=le.product();\n                                        if(prod>bestProduct){ bestProduct=prod; bestRot=currRot; bestEff=currEff; }\n                                    } else {\n                                        int t1=base[i1][j1], oldR1=currRot[i1][j1], oldT1=currEff[i1][j1];\n                                        long long bestPair=LLONG_MIN; int bestR1p=-1,bestR2p=-1;\n                                        for(int r1=0;r1<4;r1++){\n                                            int nt1=rotate_t(t1,r1); if(!EXIST_OUT[nt1][d2]) continue;\n                                            long long d1=scorer2.delta_change(currEff,i1,j1,oldT1,nt1);\n                                            currEff[i1][j1]=nt1;\n                                            for(int r2=0;r2<4;r2++){\n                                                int nt2=rotate_t(t2,r2);\n                                                if(TO[nt2][d_rev]==-1) continue;\n                                                long long d2s=scorer2.delta_change(currEff,i2,j2,oldT2,nt2);\n                                                long long dsum=d1+d2s;\n                                                if(dsum>bestPair){ bestPair=dsum; bestR1p=r1; bestR2p=r2; }\n                                            }\n                                            currEff[i1][j1]=oldT1;\n                                        }\n                                        if(bestR1p!=-1 && !(bestPair<-2 && rng.rand01()<0.9)){\n                                            int newR1=bestR1p, newR2b=bestR2p;\n                                            int newT1=rotate_t(t1,newR1), newT2b=rotate_t(t2,newR2b);\n                                            currRot[i1][j1]=newR1; currEff[i1][j1]=newT1;\n                                            currRot[i2][j2]=newR2b; currEff[i2][j2]=newT2b;\n                                            LoopEval le2=evaluate_loops(currEff);\n                                            double newF2=shapedF(le2,a,b,c);\n                                            double diff2=newF2 - currF;\n                                            bool accept2 = diff2>=0 || rng.rand01()<exp(diff2/max(1.0,T));\n                                            if(accept2){\n                                                currF=newF2; leCur=le2;\n                                                S2cur += scorer2.delta_change(currEff,i1,j1,oldT1,newT1);\n                                                S2cur += scorer2.delta_change(currEff,i2,j2,oldT2,newT2b);\n                                                long long prod=le2.product();\n                                                if(prod>bestProduct){ bestProduct=prod; bestRot=currRot; bestEff=currEff; }\n                                            } else {\n                                                currRot[i1][j1]=oldR1; currEff[i1][j1]=oldT1;\n                                                currRot[i2][j2]=oldR2; currEff[i2][j2]=oldT2;\n                                            }\n                                        } else {\n                                            currRot[i2][j2]=oldR2; currEff[i2][j2]=oldT2;\n                                        }\n                                    }\n                                    moved=true;\n                                }\n                            }\n                        }\n                    } else if (r<0.5){\n                        auto pr=pick_tile_biased(currEff,6,true,nullptr,0.0,nullptr,0);\n                        int i1=pr.first,j1=pr.second;\n                        int dir=rng.randint(0,3);\n                        int i2=i1+di[dir], j2=j1+dj[dir];\n                        if(i2>=0&&i2<N&&j2>=0&&j2<M){\n                            int t1=base[i1][j1], t2=base[i2][j2];\n                            int oldR1=currRot[i1][j1], oldR2=currRot[i2][j2];\n                            int newR1=(oldR1 + rng.randint(1,3)) & 3;\n                            int newR2=(oldR2 + rng.randint(1,3)) & 3;\n                            if(newR1==oldR1) newR1=(newR1+1)&3;\n                            if(newR2==oldR2) newR2=(newR2+1)&3;\n                            int oldT1=currEff[i1][j1], oldT2=currEff[i2][j2];\n                            int newT1=rotate_t(t1,newR1), newT2=rotate_t(t2,newR2);\n                            long long d1=scorer2.delta_change(currEff,i1,j1,oldT1,newT1);\n                            currEff[i1][j1]=newT1;\n                            long long d2=scorer2.delta_change(currEff,i2,j2,oldT2,newT2);\n                            currEff[i1][j1]=oldT1;\n                            long long s2delta=d1+d2;\n                            if(s2delta<-2 && rng.rand01()<0.9){\n                                // skip\n                            } else {\n                                currRot[i1][j1]=newR1; currEff[i1][j1]=newT1;\n                                currRot[i2][j2]=newR2; currEff[i2][j2]=newT2;\n                                LoopEval le=evaluate_loops(currEff);\n                                double newF=shapedF(le,a,b,c);\n                                double diff=newF - currF;\n                                bool accept = diff>=0 || rng.rand01()<exp(diff/max(1.0,T));\n                                if(accept){\n                                    currF=newF; leCur=le;\n                                    S2cur += scorer2.delta_change(currEff,i1,j1,oldT1,newT1);\n                                    S2cur += scorer2.delta_change(currEff,i2,j2,oldT2,newT2);\n                                    long long prod=le.product();\n                                    if(prod>bestProduct){ bestProduct=prod; bestRot=currRot; bestEff=currEff; }\n                                } else {\n                                    currRot[i1][j1]=oldR1; currEff[i1][j1]=oldT1;\n                                    currRot[i2][j2]=oldR2; currEff[i2][j2]=oldT2;\n                                }\n                                moved=true;\n                            }\n                        }\n                    }\n\n                    if(!moved){\n                        auto pr=pick_tile_biased(currEff,6,true,nullptr,0.0,nullptr,0);\n                        int i=pr.first,j=pr.second;\n                        int tbase=base[i][j], oldR=currRot[i][j];\n                        int newR=(oldR + rng.randint(1,3)) & 3; if(newR==oldR) newR=(newR+1)&3;\n                        int oldT=currEff[i][j], newT=rotate_t(tbase,newR);\n                        long long s2delta=scorer2.delta_change(currEff,i,j,oldT,newT);\n                        if(s2delta<-1 && rng.rand01()<0.9) continue;\n                        currRot[i][j]=newR; currEff[i][j]=newT;\n                        LoopEval le=evaluate_loops(currEff);\n                        double newF=shapedF(le,a,b,c);\n                        double diff=newF - currF;\n                        bool accept = diff>=0 || rng.rand01()<exp(diff/max(1.0,T));\n                        if(accept){\n                            currF=newF; leCur=le;\n                            S2cur += scorer2.delta_change(currEff,i,j,oldT,newT);\n                            long long prod=le.product();\n                            if(prod>bestProduct){ bestProduct=prod; bestRot=currRot; bestEff=currEff; }\n                        } else {\n                            currRot[i][j]=oldR; currEff[i][j]=oldT;\n                        }\n                    }\n                }\n                rot=bestRot; eff=bestEff;\n            }\n        }\n\n        // SA Phase 2: L2-focused with bias near L2, soft-freeze L1\n        {\n            double t_start=timer.elapsed();\n            double t_end=min(deadline, t_start+dur_sa2);\n            if(t_end - t_start > 1e-6){\n                LoopEvalSets les=evaluate_loops_with_sets(eff);\n                auto currRot=rot; auto currEff=eff;\n                long long S2cur=scorer2.compute_all(currEff);\n                LoopEval leCur=les.le;\n                double currF=(double)leCur.product();\n                const unsigned char* avoidSet=les.in1.data();\n                array<unsigned char,900> near2; build_near_set(les.in2, near2);\n                double startT=4.0,endT=0.02;\n\n                while(true){\n                    double now=timer.elapsed(); if(now>=t_end) break;\n                    double progress=(now - t_start)/(t_end - t_start); if(progress<0) progress=0; if(progress>1) progress=1;\n                    double T=startT + (endT - startT)*progress;\n                    double a=2.0*(1.0 - progress), b=0.1*(1.0 - progress), c=0.5*(1.0 - progress);\n                    double avoidProb=0.95;\n\n                    double r=rng.rand01(); bool moved=false;\n\n                    if(r<0.25){\n                        auto pr=pick_tile_biased(currEff,6,true,avoidSet,avoidProb, near2.data(), 1000);\n                        int i1=pr.first,j1=pr.second;\n                        int tt1=currEff[i1][j1];\n                        int cand[4],cnt=0;\n                        for(int d=0; d<4; d++){\n                            int d2=TO[tt1][d];\n                            if(d2==-1) continue;\n                            int i2=i1+di[d2], j2=j1+dj[d2];\n                            if(i2<0||i2>=N||j2<0||j2>=M) continue;\n                            int tt2=currEff[i2][j2]; int d_rev=(d2+2)&3;\n                            if(TO[tt2][d_rev]==-1) cand[cnt++]=d2;\n                        }\n                        if(cnt>0){\n                            int d2=cand[rng.randint(0,cnt-1)];\n                            int i2=i1+di[d2], j2=j1+dj[d2];\n                            int t2=base[i2][j2], oldR2=currRot[i2][j2], oldT2=currEff[i2][j2];\n                            int d_rev=(d2+2)&3;\n                            int bestR2=-1; long long bestDeltaS2=LLONG_MIN;\n                            for(int r2=0;r2<4;r2++){\n                                int nt2=rotate_t(t2,r2);\n                                if(TO[nt2][d_rev]==-1) continue;\n                                long long delta=scorer2.delta_change(currEff,i2,j2,oldT2,nt2);\n                                if(delta>bestDeltaS2){ bestDeltaS2=delta; bestR2=r2; }\n                            }\n                            if(bestR2!=-1){\n                                if(bestDeltaS2<-2 && rng.rand01()<0.9){\n                                    // skip\n                                } else {\n                                    int newR2=bestR2, newT2=rotate_t(t2,newR2);\n                                    currRot[i2][j2]=newR2; currEff[i2][j2]=newT2;\n                                    LoopEval le=evaluate_loops(currEff);\n                                    double newF=(double)le.product()+a*(double)min(le.L1,le.L2)+b*(double)(le.L1+le.L2)-c*(double)le.cycleCount;\n                                    double diff=newF - currF;\n                                    bool accept = diff>=0 || rng.rand01()<exp(diff/max(1.0,T));\n                                    if(accept){\n                                        currF=newF; leCur=le;\n                                        S2cur += scorer2.delta_change(currEff,i2,j2,oldT2,newT2);\n                                        long long prod=le.product();\n                                        if(prod>bestProduct){ bestProduct=prod; bestRot=currRot; bestEff=currEff; }\n                                    } else {\n                                        currRot[i2][j2]=oldR2; currEff[i2][j2]=oldT2;\n                                    }\n                                    moved=true;\n                                }\n                            }\n                        }\n                    } else if (r<0.5){\n                        auto pr=pick_tile_biased(currEff,6,true,avoidSet,avoidProb, near2.data(), 1000);\n                        int i1=pr.first,j1=pr.second;\n                        int dir=rng.randint(0,3);\n                        int i2=i1+di[dir], j2=j1+dj[dir];\n                        if(i2>=0&&i2<N&&j2>=0&&j2<M){\n                            int t1=base[i1][j1], t2=base[i2][j2];\n                            int oldR1=currRot[i1][j1], oldR2=currRot[i2][j2];\n                            int newR1=(oldR1 + rng.randint(1,3)) & 3;\n                            int newR2=(oldR2 + rng.randint(1,3)) & 3;\n                            if(newR1==oldR1) newR1=(newR1+1)&3;\n                            if(newR2==oldR2) newR2=(newR2+1)&3;\n                            int oldT1=currEff[i1][j1], oldT2=currEff[i2][j2];\n                            int newT1=rotate_t(t1,newR1), newT2=rotate_t(t2,newR2);\n                            long long d1=scorer2.delta_change(currEff,i1,j1,oldT1,newT1);\n                            currEff[i1][j1]=newT1;\n                            long long d2=scorer2.delta_change(currEff,i2,j2,oldT2,newT2);\n                            currEff[i1][j1]=oldT1;\n                            long long s2delta=d1+d2;\n                            if(s2delta<-2 && rng.rand01()<0.9){\n                                // skip\n                            } else {\n                                currRot[i1][j1]=newR1; currEff[i1][j1]=newT1;\n                                currRot[i2][j2]=newR2; currEff[i2][j2]=newT2;\n                                LoopEval le=evaluate_loops(currEff);\n                                double newF=(double)le.product()+a*(double)min(le.L1,le.L2)+b*(double)(le.L1+le.L2)-c*(double)le.cycleCount;\n                                double diff=newF - currF;\n                                bool accept = diff>=0 || rng.rand01()<exp(diff/max(1.0,T));\n                                if(accept){\n                                    currF=newF; leCur=le;\n                                    S2cur += scorer2.delta_change(currEff,i1,j1,oldT1,newT1);\n                                    S2cur += scorer2.delta_change(currEff,i2,j2,oldT2,newT2);\n                                    long long prod=le.product();\n                                    if(prod>bestProduct){ bestProduct=prod; bestRot=currRot; bestEff=currEff; }\n                                } else {\n                                    currRot[i1][j1]=oldR1; currEff[i1][j1]=oldT1;\n                                    currRot[i2][j2]=oldR2; currEff[i2][j2]=oldT2;\n                                }\n                                moved=true;\n                            }\n                        }\n                    }\n\n                    if(!moved){\n                        auto pr=pick_tile_biased(currEff,6,true,avoidSet,avoidProb, near2.data(), 1000);\n                        int i=pr.first,j=pr.second;\n                        int tbase=base[i][j], oldR=currRot[i][j];\n                        int newR=(oldR + rng.randint(1,3)) & 3; if(newR==oldR) newR=(newR+1)&3;\n                        int oldT=currEff[i][j], newT=rotate_t(tbase,newR);\n                        long long s2delta=scorer2.delta_change(currEff,i,j,oldT,newT);\n                        if(s2delta<-1 && rng.rand01()<0.9) continue;\n                        currRot[i][j]=newR; currEff[i][j]=newT;\n                        LoopEval le=evaluate_loops(currEff);\n                        double newF=(double)le.product()+a*(double)min(le.L1,le.L2)+b*(double)(le.L1+le.L2)-c*(double)le.cycleCount;\n                        double diff=newF - currF;\n                        bool accept = diff>=0 || rng.rand01()<exp(diff/max(1.0,T));\n                        if(accept){\n                            currF=newF; leCur=le;\n                            S2cur += scorer2.delta_change(currEff,i,j,oldT,newT);\n                            long long prod=le.product();\n                            if(prod>bestProduct){ bestProduct=prod; bestRot=currRot; bestEff=currEff; }\n                        } else {\n                            currRot[i][j]=oldR; currEff[i][j]=oldT;\n                        }\n                    }\n                }\n                rot=bestRot; eff=bestEff;\n            }\n        }\n\n        // 2x2 brute-force refine under true objective\n        {\n            double t_end = min(deadline, timer.elapsed()+dur_refine);\n            LoopEvalSets les = evaluate_loops_with_sets(eff);\n            refine_blocks_true(bestRot, bestEff, base, les.in1.data(), t_end, timer, 4);\n        }\n\n        // Greedy tail\n        {\n            double t_end=min(deadline, timer.elapsed()+dur_tail);\n            auto currRot=bestRot; auto currEff=bestEff;\n            long long currSc=evaluate_loops(currEff).product();\n            while(timer.elapsed()<t_end){\n                int bi=-1,bj=-1,bbad=-1;\n                const int K=4;\n                for(int k=0;k<K;k++){\n                    int ci=rng.randint(0,N-1), cj=rng.randint(0,M-1);\n                    int bad=count_invalid_exits(currEff,ci,cj);\n                    if(bad>bbad || (bad==bbad && rng.rand01()<0.5)){ bbad=bad; bi=ci; bj=cj; }\n                }\n                if(bi<0){ bi=rng.randint(0,N-1); bj=rng.randint(0,M-1); }\n                int i=bi,j=bj;\n                int base_t=base[i][j], curR=currRot[i][j], bestR=curR, bestT2=currEff[i][j];\n                long long bestLocal=currSc;\n                for(int r=0;r<4;r++){\n                    if(r==curR) continue;\n                    int newT=rotate_t(base_t,r);\n                    auto saveT=currEff[i][j]; currEff[i][j]=newT;\n                    long long sc=evaluate_loops(currEff).product();\n                    if(sc>bestLocal){ bestLocal=sc; bestR=r; bestT2=newT; }\n                    currEff[i][j]=saveT;\n                }\n                if(bestLocal>currSc){\n                    currSc=bestLocal; currRot[i][j]=bestR; currEff[i][j]=bestT2;\n                    if(currSc>bestProduct){ bestProduct=currSc; bestRot=currRot; bestEff=currEff; }\n                }\n            }\n        }\n    };\n\n    array<array<int,30>,30> bestRot{}, bestEff{};\n    long long bestProduct=-1;\n\n    double totalBudget = TIME_LIMIT - 0.03;\n    // Two pipelines: 60% and 40%\n    double tb1 = totalBudget * 0.60;\n    double tb2 = totalBudget - tb1;\n\n    run_pipeline(bestRot,bestEff,bestProduct,tb1,0); // standard init\n    rng.reseed(rng.next() ^ 0x9E3779B97F4A7C15ull);\n    run_pipeline(bestRot,bestEff,bestProduct,tb2,1); // checkerboard straights\n\n    // Output\n    string out; out.reserve(N*M);\n    for(int i=0;i<N;i++) for(int j=0;j<M;j++) out.push_back(char('0'+bestRot[i][j]));\n    cout<<out<<\"\\n\";\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\n// High resolution timer\nstatic inline double now_sec() {\n    using clk = chrono::high_resolution_clock;\n    return chrono::duration<double>(clk::now().time_since_epoch()).count();\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n_) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        p.resize(n);\n        sz.assign(n, 0);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Eval {\n    int largestTree = 0;\n    int largestCC = 0;\n    int cyclesInLargestCC = 0;\n    int totalEdges = 0;\n    int loops2x2 = 0;\n    int cyclesTotal = 0;\n    int treePotential = 0; // largestCC - cyclesInLargestCC\n};\n\nstruct ScoreKey {\n    int largestTree;\n    int treePotential;\n    int negCyclesTotal;\n    int largestCC;\n    int negCyclesInLargestCC;\n    int totalEdges;\n    int negLoops2x2;\n    int novelty;             // mild tie-breaker\n    uint32_t tieRand;\n};\n\nstatic inline bool better_key(const ScoreKey& a, const ScoreKey& b) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.treePotential != b.treePotential) return a.treePotential > b.treePotential;\n    if (a.negCyclesTotal != b.negCyclesTotal) return a.negCyclesTotal > b.negCyclesTotal;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.negCyclesInLargestCC != b.negCyclesInLargestCC) return a.negCyclesInLargestCC > b.negCyclesInLargestCC;\n    if (a.totalEdges != b.totalEdges) return a.totalEdges > b.totalEdges;\n    if (a.negLoops2x2 != b.negLoops2x2) return a.negLoops2x2 > b.negLoops2x2;\n    if (a.novelty != b.novelty) return a.novelty > b.novelty;\n    return a.tieRand < b.tieRand;\n}\n\nstatic inline int hexchar_to_int(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    if ('a' <= c && c <= 'f') return 10 + (c - 'a');\n    if ('A' <= c && c <= 'F') return 10 + (c - 'A');\n    return 0;\n}\n\nstruct Board {\n    int N;\n    vector<int> a; // size N*N, 0 is empty\n    int zr, zc;\n\n    inline bool in_bounds(int r, int c) const {\n        return (0 <= r && r < N && 0 <= c && c < N);\n    }\n};\n\nstruct Evaluator {\n    int N, n2;\n    DSU dsu;\n    vector<char> occ;\n    vector<int> deg;\n    vector<int> compDegSum;\n\n    Evaluator() {}\n    Evaluator(int N_) { init(N_); }\n    void init(int N_) {\n        N = N_; n2 = N*N;\n        dsu.init(n2);\n        occ.assign(n2, 0);\n        deg.assign(n2, 0);\n        compDegSum.assign(n2, 0);\n    }\n\n    Eval evaluate(const Board& B) {\n        const int L = 1, U = 2, R = 4, D = 8;\n        fill(occ.begin(), occ.end(), 0);\n        fill(deg.begin(), deg.end(), 0);\n        iota(dsu.p.begin(), dsu.p.end(), 0);\n        fill(dsu.sz.begin(), dsu.sz.end(), 0);\n\n        for (int i = 0; i < N; ++i) {\n            int base = i * N;\n            for (int j = 0; j < N; ++j) {\n                int id = base + j;\n                if (B.a[id] != 0) {\n                    occ[id] = 1;\n                    dsu.sz[id] = 1;\n                }\n            }\n        }\n\n        int totalEdges = 0;\n        // Vertical\n        for (int i = 0; i < N-1; ++i) {\n            int base = i * N, base2 = (i+1)*N;\n            for (int j = 0; j < N; ++j) {\n                int id1 = base + j, id2 = base2 + j;\n                int m1 = B.a[id1], m2 = B.a[id2];\n                if ((m1 & D) && (m2 & U)) {\n                    totalEdges++;\n                    deg[id1]++; deg[id2]++;\n                    if (occ[id1] && occ[id2]) dsu.unite(id1, id2);\n                }\n            }\n        }\n        // Horizontal\n        for (int i = 0; i < N; ++i) {\n            int base = i * N;\n            for (int j = 0; j < N-1; ++j) {\n                int id1 = base + j, id2 = base + (j+1);\n                int m1 = B.a[id1], m2 = B.a[id2];\n                if ((m1 & R) && (m2 & L)) {\n                    totalEdges++;\n                    deg[id1]++; deg[id2]++;\n                    if (occ[id1] && occ[id2]) dsu.unite(id1, id2);\n                }\n            }\n        }\n\n        int loops2x2 = 0;\n        for (int i = 0; i < N-1; ++i) {\n            int base = i * N, base2 = (i+1)*N;\n            for (int j = 0; j < N-1; ++j) {\n                int id00 = base + j, id01 = base + (j+1);\n                int id10 = base2 + j, id11 = base2 + (j+1);\n                int m00 = B.a[id00], m01 = B.a[id01], m10 = B.a[id10], m11 = B.a[id11];\n                bool v1 = (m00 & 8) && (m10 & 2);\n                bool v2 = (m01 & 8) && (m11 & 2);\n                bool h1 = (m00 & 4) && (m01 & 1);\n                bool h2 = (m10 & 4) && (m11 & 1);\n                if (v1 && v2 && h1 && h2) loops2x2++;\n            }\n        }\n\n        fill(compDegSum.begin(), compDegSum.end(), 0);\n        for (int id = 0; id < n2; ++id) {\n            if (!occ[id]) continue;\n            int r = dsu.find(id);\n            compDegSum[r] += deg[id];\n        }\n\n        int largestCC = 0;\n        int largestTree = 0;\n        int cyclesInLargestCC = 0;\n        int cyclesTotal = 0;\n\n        vector<char> seen(n2, 0);\n        for (int id = 0; id < n2; ++id) {\n            if (!occ[id]) continue;\n            int r = dsu.find(id);\n            if (seen[r]) continue;\n            seen[r] = 1;\n            int V = dsu.sz[r];\n            int E = compDegSum[r] / 2;\n            int cyc = E - (V - 1);\n            if (V > largestCC) {\n                largestCC = V;\n                cyclesInLargestCC = max(0, cyc);\n            } else if (V == largestCC) {\n                cyclesInLargestCC = min(cyclesInLargestCC, max(0, cyc));\n            }\n            if (E == V - 1) {\n                if (V > largestTree) largestTree = V;\n            }\n            if (cyc > 0) cyclesTotal += cyc;\n        }\n\n        Eval ev;\n        ev.largestTree = largestTree;\n        ev.largestCC = largestCC;\n        ev.cyclesInLargestCC = cyclesInLargestCC;\n        ev.totalEdges = totalEdges;\n        ev.loops2x2 = loops2x2;\n        ev.cyclesTotal = cyclesTotal;\n        ev.treePotential = largestCC - cyclesInLargestCC;\n        return ev;\n    }\n};\n\nstatic inline ScoreKey make_key(const Eval& ev, std::mt19937& rng, int novelty) {\n    ScoreKey k;\n    k.largestTree = ev.largestTree;\n    k.treePotential = ev.treePotential;\n    k.negCyclesTotal = -ev.cyclesTotal;\n    k.largestCC = ev.largestCC;\n    k.negCyclesInLargestCC = -ev.cyclesInLargestCC;\n    k.totalEdges = ev.totalEdges;\n    k.negLoops2x2 = -ev.loops2x2;\n    k.novelty = novelty;\n    k.tieRand = rng();\n    return k;\n}\n\nstruct LocalHeu {\n    int deltaEdges;\n    int deltaLoops;\n    int bridges;     // new edges to different components (start-of-step DSU)\n    int sameComp;    // new edges within same component\n};\n\nstruct Searcher {\n    int N;\n    Evaluator &evaluator;\n    Board &B;\n    std::mt19937 &rng;\n    unordered_set<uint64_t> *visited; // executed states (for novelty)\n    vector<uint64_t> zob; // zobrist pos*16 + tile\n    uint64_t curHash;\n\n    static constexpr int dr[4] = {-1, +1, 0, 0};\n    static constexpr int dc[4] = {0, 0, -1, +1};\n    static constexpr int opp[4] = {1, 0, 3, 2};\n    static constexpr char mvch[4] = {'U','D','L','R'};\n\n    vector<int> curPath, bestPath;\n    vector<uint64_t> hashStack; // path hashes for cycle pruning\n\n    int wEdge = 3, wLoop = 2;\n    int wBridge = 3, wCycle = 2;\n\n    vector<int> compId0; // start-of-step component id (-1 for empty)\n\n    Searcher(int N_, Evaluator &ev, Board &b, std::mt19937 &r, unordered_set<uint64_t>* visited_)\n        : N(N_), evaluator(ev), B(b), rng(r), visited(visited_) {\n        curPath.reserve(16);\n        bestPath.reserve(16);\n        hashStack.reserve(16);\n        std::uniform_int_distribution<uint64_t> dist64(0, std::numeric_limits<uint64_t>::max());\n        zob.resize(N*N*16);\n        for (auto &x : zob) x = dist64(rng);\n        curHash = 0;\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j) {\n                int id = i*N + j;\n                int v = B.a[id] & 15;\n                curHash ^= zob[id*16 + v];\n            }\n        compId0.assign(N*N, -1);\n    }\n\n    inline void setLocalWeights(int wE, int wL, int wBr, int wCy) { wEdge = wE; wLoop = wL; wBridge = wBr; wCycle = wCy; }\n    inline void setCompIds(const vector<int>& cid) { compId0 = cid; }\n\n    inline bool in_bounds(int r, int c) const { return 0 <= r && r < N && 0 <= c && c < N; }\n\n    inline bool applyMove(int dir) {\n        int zr = B.zr, zc = B.zc;\n        int nr = zr + dr[dir], nc = zc + dc[dir];\n        if (!in_bounds(nr, nc)) return false;\n        int zidx = zr * N + zc, nidx = nr * N + nc;\n        int valn = B.a[nidx];\n        curHash ^= zob[zidx*16 + 0];\n        curHash ^= zob[nidx*16 + (valn & 15)];\n        curHash ^= zob[zidx*16 + (valn & 15)];\n        curHash ^= zob[nidx*16 + 0];\n        swap(B.a[zidx], B.a[nidx]);\n        B.zr = nr; B.zc = nc;\n        return true;\n    }\n    inline void undoMove(int dir) { applyMove(opp[dir]); }\n\n    int incidentEdgesAt(const Board& BB, int r, int c) const {\n        int id = r * N + c, m = BB.a[id];\n        if (m == 0) return 0;\n        int cnt = 0;\n        if (r-1 >= 0) { int m2 = BB.a[(r-1)*N + c]; if ((m & 2) && (m2 & 8)) cnt++; }\n        if (r+1 < N) { int m2 = BB.a[(r+1)*N + c]; if ((m & 8) && (m2 & 2)) cnt++; }\n        if (c-1 >= 0) { int m2 = BB.a[r*N + (c-1)]; if ((m & 1) && (m2 & 4)) cnt++; }\n        if (c+1 < N) { int m2 = BB.a[r*N + (c+1)]; if ((m & 4) && (m2 & 1)) cnt++; }\n        return cnt;\n    }\n    bool isLoop2x2At(const Board& BB, int i, int j) const {\n        if (i < 0 || j < 0 || i+1 >= N || j+1 >= N) return false;\n        int id00 = i*N + j, id01 = i*N + (j+1), id10 = (i+1)*N + j, id11 = (i+1)*N + (j+1);\n        int m00 = BB.a[id00], m01 = BB.a[id01], m10 = BB.a[id10], m11 = BB.a[id11];\n        bool v1 = (m00 & 8) && (m10 & 2), v2 = (m01 & 8) && (m11 & 2);\n        bool h1 = (m00 & 4) && (m01 & 1), h2 = (m10 & 4) && (m11 & 1);\n        return v1 && v2 && h1 && h2;\n    }\n\n    LocalHeu local_delta_for_dir(int dir) {\n        LocalHeu h{0, 0, 0, 0};\n        int zr = B.zr, zc = B.zc;\n        int nr = zr + dr[dir], nc = zc + dc[dir];\n        if (!in_bounds(nr, nc)) return h;\n\n        int preEdges = incidentEdgesAt(B, zr, zc) + incidentEdgesAt(B, nr, nc);\n\n        pair<int,int> buf[8]; int bsz = 0;\n        auto push_unique = [&](int r, int c){\n            if (r < 0 || c < 0 || r+1 >= N || c+1 >= N) return;\n            for (int i = 0; i < bsz; ++i) if (buf[i].first == r && buf[i].second == c) return;\n            buf[bsz++] = {r, c};\n        };\n        push_unique(zr, zc); push_unique(zr-1, zc); push_unique(zr, zc-1); push_unique(zr-1, zc-1);\n        push_unique(nr, nc); push_unique(nr-1, nc); push_unique(nr, nc-1); push_unique(nr-1, nc-1);\n\n        int preLoops = 0;\n        for (int i = 0; i < bsz; ++i) if (isLoop2x2At(B, buf[i].first, buf[i].second)) preLoops++;\n\n        int nidx = nr * N + nc;\n        int movedComp = (nidx >= 0 && nidx < (int)compId0.size()) ? compId0[nidx] : -1;\n\n        applyMove(dir);\n\n        int postEdges = incidentEdgesAt(B, zr, zc) + incidentEdgesAt(B, nr, nc);\n        int postLoops = 0;\n        for (int i = 0; i < bsz; ++i) if (isLoop2x2At(B, buf[i].first, buf[i].second)) postLoops++;\n\n        // Bridging vs same-comp at (zr,zc)\n        int idNew = zr * N + zc;\n        int mNew = B.a[idNew];\n        // Up\n        if (zr-1 >= 0) {\n            int nid = (zr-1)*N + zc;\n            int m2 = B.a[nid];\n            if ((mNew & 2) && (m2 & 8)) {\n                int c2 = (nid >= 0 && nid < (int)compId0.size()) ? compId0[nid] : -1;\n                if (movedComp != -1 && c2 != -1) {\n                    if (movedComp != c2) h.bridges++; else h.sameComp++;\n                }\n            }\n        }\n        // Down\n        if (zr+1 < N) {\n            int nid = (zr+1)*N + zc;\n            int m2 = B.a[nid];\n            if ((mNew & 8) && (m2 & 2)) {\n                int c2 = (nid >= 0 && nid < (int)compId0.size()) ? compId0[nid] : -1;\n                if (movedComp != -1 && c2 != -1) {\n                    if (movedComp != c2) h.bridges++; else h.sameComp++;\n                }\n            }\n        }\n        // Left\n        if (zc-1 >= 0) {\n            int nid = zr*N + (zc-1);\n            int m2 = B.a[nid];\n            if ((mNew & 1) && (m2 & 4)) {\n                int c2 = (nid >= 0 && nid < (int)compId0.size()) ? compId0[nid] : -1;\n                if (movedComp != -1 && c2 != -1) {\n                    if (movedComp != c2) h.bridges++; else h.sameComp++;\n                }\n            }\n        }\n        // Right\n        if (zc+1 < N) {\n            int nid = zr*N + (zc+1);\n            int m2 = B.a[nid];\n            if ((mNew & 4) && (m2 & 1)) {\n                int c2 = (nid >= 0 && nid < (int)compId0.size()) ? compId0[nid] : -1;\n                if (movedComp != -1 && c2 != -1) {\n                    if (movedComp != c2) h.bridges++; else h.sameComp++;\n                }\n            }\n        }\n\n        undoMove(dir);\n\n        h.deltaEdges = postEdges - preEdges;\n        h.deltaLoops = postLoops - preLoops;\n        return h;\n    }\n\n    inline int localScore(const LocalHeu& h) const {\n        return wEdge * h.deltaEdges - wLoop * h.deltaLoops + wBridge * h.bridges - wCycle * h.sameComp;\n    }\n\n    void dfs(int depth, int maxD, int lastDir, ScoreKey& bestKey, double endTime, bool& timeUp) {\n        if (now_sec() > endTime) { timeUp = true; return; }\n\n        for (uint64_t h : hashStack) if (h == curHash) return; // path cycle prune\n        hashStack.push_back(curHash);\n\n        if (depth == maxD) {\n            Eval ev = evaluator.evaluate(B);\n            int novelty = (visited && visited->find(curHash) == visited->end()) ? 1 : 0;\n            ScoreKey key = make_key(ev, rng, novelty);\n            if (better_key(key, bestKey)) { bestKey = key; bestPath = curPath; }\n            hashStack.pop_back();\n            return;\n        }\n\n        vector<int> cand;\n        cand.reserve(4);\n        if (depth == 0) {\n            vector<int> legal, nonRev;\n            for (int dir = 0; dir < 4; ++dir) {\n                int nr = B.zr + dr[dir], nc = B.zc + dc[dir];\n                if (!in_bounds(nr, nc)) continue;\n                legal.push_back(dir);\n                if (lastDir == -1 || dir != opp[lastDir]) nonRev.push_back(dir);\n            }\n            if (!nonRev.empty() && (int)nonRev.size() >= 2) cand = nonRev;\n            else cand = legal;\n        } else {\n            for (int dir = 0; dir < 4; ++dir) {\n                if (lastDir != -1 && dir == opp[lastDir]) continue;\n                int nr = B.zr + dr[dir], nc = B.zc + dc[dir];\n                if (!in_bounds(nr, nc)) continue;\n                cand.push_back(dir);\n            }\n        }\n        if (cand.empty()) { hashStack.pop_back(); return; }\n\n        if (depth == 0) {\n            // Root-level ordering by full evaluation\n            struct Cand { ScoreKey key; int dir; };\n            vector<Cand> ord;\n            ord.reserve(cand.size());\n            for (int dir : cand) {\n                applyMove(dir);\n                Eval ev = evaluator.evaluate(B);\n                int novelty = (visited && visited->find(curHash) == visited->end()) ? 1 : 0;\n                ScoreKey key = make_key(ev, rng, novelty);\n                ord.push_back({key, dir});\n                undoMove(dir);\n            }\n            sort(ord.begin(), ord.end(), [&](const Cand& A, const Cand& B){ return better_key(A.key, B.key); });\n            for (auto &c : ord) {\n                int dir = c.dir;\n                if (!applyMove(dir)) continue;\n                curPath.push_back(dir);\n                dfs(depth+1, maxD, dir, bestKey, endTime, timeUp);\n                curPath.pop_back();\n                undoMove(dir);\n                if (timeUp) { hashStack.pop_back(); return; }\n            }\n        } else {\n            // Deeper: local heuristic ordering\n            vector<pair<int,int>> ord; ord.reserve(cand.size()); // (score, dir)\n            for (int dir : cand) {\n                LocalHeu h = local_delta_for_dir(dir);\n                int noise = (int)(rng() & 1);\n                ord.push_back({localScore(h) * 2 + noise, dir});\n            }\n            sort(ord.begin(), ord.end(), [&](const auto& A, const auto& B){\n                if (A.first != B.first) return A.first > B.first;\n                return A.second < B.second;\n            });\n            for (auto &p : ord) {\n                int dir = p.second;\n                if (!applyMove(dir)) continue;\n                curPath.push_back(dir);\n                dfs(depth+1, maxD, dir, bestKey, endTime, timeUp);\n                curPath.pop_back();\n                undoMove(dir);\n                if (timeUp) { hashStack.pop_back(); return; }\n            }\n        }\n\n        hashStack.pop_back();\n    }\n\n    int choose_move_with_budget(int maxDepth, double budget_sec, int lastGlobalDir, ScoreKey& outKey) {\n        curPath.clear(); bestPath.clear(); hashStack.clear();\n        ScoreKey bestKey = {-1, -1, INT_MIN, -1, INT_MIN, -1, INT_MIN, -1, 0};\n        bool timeUp = false;\n        double endTime = now_sec() + budget_sec;\n        dfs(0, maxDepth, lastGlobalDir, bestKey, endTime, timeUp);\n        outKey = bestKey;\n        if (!bestPath.empty()) return bestPath[0];\n        return -1;\n    }\n\n    // Randomized rollout fallback: simulate short sequences guided by local heuristic\n    int choose_move_rollout(int lastGlobalDir, double rollBudgetSec, int rolloutLen) {\n        double endTime = now_sec() + rollBudgetSec;\n        ScoreKey bestKey = {-1, -1, INT_MIN, -1, INT_MIN, -1, INT_MIN, -1, 0};\n        vector<int> bestPathSim;\n\n        while (now_sec() < endTime) {\n            vector<int> pathSim;\n            pathSim.reserve(rolloutLen);\n            int lastDir = lastGlobalDir;\n\n            // simulate rolloutLen moves\n            for (int d = 0; d < rolloutLen; ++d) {\n                // build legal moves\n                array<int,4> legal;\n                int ln = 0;\n                for (int dir = 0; dir < 4; ++dir) {\n                    if (lastDir != -1 && dir == opp[lastDir]) continue;\n                    int nr = B.zr + dr[dir], nc = B.zc + dc[dir];\n                    if (!in_bounds(nr, nc)) continue;\n                    legal[ln++] = dir;\n                }\n                if (ln == 0) break;\n\n                // score moves locally\n                vector<pair<int,int>> ord; ord.reserve(ln);\n                for (int i = 0; i < ln; ++i) {\n                    int dir = legal[i];\n                    LocalHeu h = local_delta_for_dir(dir);\n                    int sc = localScore(h);\n                    ord.push_back({sc, dir});\n                }\n                sort(ord.begin(), ord.end(), [&](const auto& A, const auto& B){\n                    if (A.first != B.first) return A.first > B.first;\n                    return A.second < B.second;\n                });\n\n                // epsilon-greedy pick among top 2\n                int pickDir = ord[0].second;\n                if (ord.size() >= 2) {\n                    if ((rng() & 1023) < 200) pickDir = ord[1].second; // ~20% choose second-best\n                }\n\n                if (!applyMove(pickDir)) break;\n                pathSim.push_back(pickDir);\n                lastDir = pickDir;\n            }\n\n            // evaluate\n            Eval ev = evaluator.evaluate(B);\n            int novelty = (visited && visited->find(curHash) == visited->end()) ? 1 : 0;\n            ScoreKey key = make_key(ev, rng, novelty);\n            if (better_key(key, bestKey) && !pathSim.empty()) {\n                bestKey = key;\n                bestPathSim = pathSim;\n            }\n\n            // undo\n            for (int i = (int)pathSim.size()-1; i >= 0; --i) undoMove(pathSim[i]);\n        }\n\n        if (!bestPathSim.empty()) return bestPathSim[0];\n        return -1;\n    }\n\n    int choose_move_local(int lastGlobalDir) {\n        int bestDir = -1, bestScore = INT_MIN;\n        array<int,4> legal; int ln = 0;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nr = B.zr + dr[dir], nc = B.zc + dc[dir];\n            if (!in_bounds(nr, nc)) continue;\n            legal[ln++] = dir;\n        }\n        if (ln == 0) return -1;\n        bool hasNonReverse = false;\n        for (int i = 0; i < ln; ++i) if (lastGlobalDir == -1 || legal[i] != opp[lastGlobalDir]) hasNonReverse = true;\n        for (int i = 0; i < ln; ++i) {\n            int dir = legal[i];\n            if (hasNonReverse && lastGlobalDir != -1 && dir == opp[lastGlobalDir]) continue;\n            LocalHeu h = local_delta_for_dir(dir);\n            int sc = localScore(h);\n            if (sc > bestScore) { bestScore = sc; bestDir = dir; }\n        }\n        if (bestDir == -1) bestDir = legal[0];\n        return bestDir;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    if (!(cin >> N >> T)) return 0;\n    vector<string> ts(N);\n    for (int i = 0; i < N; ++i) cin >> ts[i];\n\n    Board B; B.N = N; B.a.assign(N*N, 0); B.zr = -1; B.zc = -1;\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j) {\n            int v = hexchar_to_int(ts[i][j]);\n            B.a[i*N + j] = v;\n            if (v == 0) { B.zr = i; B.zc = j; }\n        }\n\n    Evaluator evaluator(N);\n\n    string ans; ans.reserve(T);\n\n    std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    static const int dr[4] = {-1, +1, 0, 0};\n    static const int dc[4] = {0, 0, -1, +1};\n    static const char mvch[4] = {'U', 'D', 'L', 'R'};\n    static const int opp[4] = {1, 0, 3, 2};\n\n    double t_start = now_sec();\n    const double TIME_LIMIT = 2.90;\n    const double SAFETY_MARGIN = 0.05;\n\n    Eval ev0 = evaluator.evaluate(B);\n    if (ev0.largestTree == N*N - 1) { cout << \"\" << '\\n'; return 0; }\n\n    unordered_set<uint64_t> visited; visited.reserve(4096);\n    Searcher searcher(N, evaluator, B, rng, &visited);\n    visited.insert(searcher.curHash);\n\n    int lastDirGlobal = -1;\n\n    int bestLargestTree = ev0.largestTree;\n    int stagnation = 0;\n\n    for (int step = 0; step < T; ++step) {\n        double elapsed = now_sec() - t_start;\n        double timeLeft = TIME_LIMIT - elapsed - SAFETY_MARGIN;\n        if (timeLeft <= 0.0) break;\n\n        Eval evCur = evaluator.evaluate(B);\n        // Build comp ids at start-of-step for bridge heuristic\n        vector<int> compId0(B.N*B.N, -1);\n        for (int id = 0; id < B.N*B.N; ++id) {\n            if (evaluator.occ[id]) compId0[id] = evaluator.dsu.find(id);\n        }\n        searcher.setCompIds(compId0);\n\n        double remainSteps = double(T - step);\n        double budget = (remainSteps > 0 ? timeLeft / remainSteps : 0.0);\n        double minBudget = 0.00025, maxBudget = 0.0026;\n        if (budget < minBudget) budget = minBudget;\n        if (budget > maxBudget) budget = maxBudget;\n\n        if (evCur.largestTree > bestLargestTree) { bestLargestTree = evCur.largestTree; stagnation = 0; }\n        else stagnation++;\n\n        double factor = 1.0;\n        if (stagnation > 60) factor = 1.2;\n        if (stagnation > 120) factor = 1.4;\n        budget *= factor; if (budget > maxBudget * 1.4) budget = maxBudget * 1.4;\n\n        int wE = 3, wL = 2, wBr = 3, wCy = 2;\n        int totalTiles = N*N - 1;\n        if (evCur.largestTree < totalTiles / 3) { wE = 4; wBr = 4; wCy = 1; }\n        if (evCur.cyclesTotal >= N) { wL = 4; wCy = max(wCy, 3); }\n        else if (evCur.cyclesTotal >= N/2) { wL = max(wL, 3); }\n        searcher.setLocalWeights(wE, wL, wBr, wCy);\n\n        int maxDepth;\n        if (N <= 7) {\n            if (budget > 0.0020) maxDepth = 5;\n            else if (budget > 0.0012) maxDepth = 4;\n            else maxDepth = 3;\n        } else {\n            if (budget > 0.0018) maxDepth = 4;\n            else maxDepth = 3;\n        }\n        if (factor > 1.0 && maxDepth < 5 && N <= 7) maxDepth++;\n\n        ScoreKey outKey;\n        int chosenDir = searcher.choose_move_with_budget(maxDepth, budget * 0.8, lastDirGlobal, outKey);\n\n        // If DFS found no path or no improvement and we stagnate, try rollout fallback\n        if ((chosenDir == -1 || outKey.largestTree <= evCur.largestTree) && stagnation > 80 && budget > 0.0010) {\n            int rollLen = (N <= 7 ? 7 : 6);\n            int rd = searcher.choose_move_rollout(lastDirGlobal, budget * 0.8, rollLen);\n            if (rd != -1) chosenDir = rd;\n        }\n\n        if (chosenDir == -1) {\n            if (budget <= 0.00035) {\n                chosenDir = searcher.choose_move_local(lastDirGlobal);\n            } else {\n                double t0 = now_sec();\n                double greedyBudget = budget * 0.8;\n                ScoreKey bestKey = {-1, -1, INT_MIN, -1, INT_MIN, -1, INT_MIN, -1, 0};\n                int bestDir = -1;\n\n                array<int,4> legal; int ln = 0;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int nr = B.zr + dr[dir], nc = B.zc + dc[dir];\n                    if (0 <= nr && nr < N && 0 <= nc && nc < N) legal[ln++] = dir;\n                }\n                if (ln == 0) break;\n                bool hasNonReverse = false;\n                for (int i = 0; i < ln; ++i) if (lastDirGlobal == -1 || legal[i] != opp[lastDirGlobal]) hasNonReverse = true;\n\n                for (int i = 0; i < ln; ++i) {\n                    int dir = legal[i];\n                    if (hasNonReverse && lastDirGlobal != -1 && dir == opp[lastDirGlobal]) continue;\n                    searcher.applyMove(dir);\n                    Eval ev = evaluator.evaluate(B);\n                    int novelty = (visited.find(searcher.curHash) == visited.end()) ? 1 : 0;\n                    ScoreKey key = make_key(ev, rng, novelty);\n                    if (better_key(key, bestKey)) { bestKey = key; bestDir = dir; }\n                    searcher.undoMove(dir);\n                    if (now_sec() - t0 > greedyBudget) break;\n                }\n                if (bestDir != -1) chosenDir = bestDir;\n                else chosenDir = searcher.choose_move_local(lastDirGlobal);\n            }\n        }\n\n        if (chosenDir == -1) break;\n\n        searcher.applyMove(chosenDir);\n        ans.push_back(mvch[chosenDir]);\n        lastDirGlobal = chosenDir;\n\n        visited.insert(searcher.curHash);\n\n        Eval ev = evaluator.evaluate(B);\n        if (ev.largestTree == N*N - 1) break;\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\nstruct Normal { long long nx, ny; };\n\nstruct WeightSpec {\n    int mode;      // 0: uniform; 1: symmetric center-heavy (r<1); 2: monotonic (r<1)\n    long double r; // ratio parameter (unused for uniform)\n};\n\nstatic inline long long now_us() {\n    using namespace std::chrono;\n    return duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();\n}\n\n// Build weights\nstatic vector<long double> make_weights(int m, const WeightSpec& ws) {\n    vector<long double> w(max(m, 1), 1.0L);\n    if (m <= 0) return w;\n    if (ws.mode == 0) {\n        for (int i = 0; i < m; ++i) w[i] = 1.0L;\n    } else if (ws.mode == 1) {\n        long double mid = (m - 1) * 0.5L;\n        for (int i = 0; i < m; ++i) {\n            long double d = fabsl((long double)i - mid);\n            w[i] = pow(ws.r, d);\n        }\n    } else if (ws.mode == 2) {\n        long double v = 1.0L;\n        for (int i = 0; i < m; ++i) {\n            w[i] = v;\n            v *= ws.r;\n        }\n    } else {\n        for (int i = 0; i < m; ++i) w[i] = 1.0L;\n    }\n    long double s = 0;\n    for (auto &x : w) s += x;\n    if (s > 0) for (auto &x : w) x /= s;\n    return w;\n}\n\n// Largest Remainder Method\nstatic vector<int> targets_from_weights(const vector<long double>& w, int N) {\n    int m = (int)w.size();\n    vector<int> tgt(m, 0);\n    vector<pair<long double,int>> frac; frac.reserve(m);\n    long double sum_floor = 0;\n    for (int i = 0; i < m; ++i) {\n        long double val = (long double)N * w[i];\n        int f = (int)floor(val);\n        tgt[i] = f;\n        sum_floor += f;\n        frac.emplace_back(val - f, i);\n    }\n    int rem = N - (int)sum_floor;\n    if (rem > 0) {\n        sort(frac.begin(), frac.end(), [](const auto& a, const auto& b){ return a.first > b.first; });\n        for (int k = 0; k < rem && k < m; ++k) {\n            tgt[frac[k].second]++;\n        }\n    }\n    return tgt;\n}\n\n// Safe j positions where integer cut is possible between arr[j] and arr[j+1], with sentinels -1 and N-1\nstatic vector<int> build_safe_indices(const vector<long long>& arr) {\n    int N = (int)arr.size();\n    vector<int> safe;\n    safe.reserve(N + 2);\n    safe.push_back(-1);\n    for (int j = 0; j + 1 < N; ++j) {\n        if (arr[j+1] - arr[j] >= 2) {\n            safe.push_back(j);\n        }\n    }\n    safe.push_back(N - 1);\n    return safe;\n}\n\nstatic int choose_nearest_safe(const vector<int>& safe, int t, int min_j) {\n    int lo = 0, hi = (int)safe.size();\n    while (lo < hi) {\n        int mid = (lo + hi) >> 1;\n        if (safe[mid] < t) lo = mid + 1;\n        else hi = mid;\n    }\n    long long bestDist = (1LL<<60);\n    int best = -1;\n    for (int k = lo - 1; k <= lo; ++k) {\n        if (k < 0 || k >= (int)safe.size()) continue;\n        int cand = safe[k];\n        if (cand < min_j) continue;\n        long long dist = llabs((long long)cand - (long long)t);\n        if (dist < bestDist) {\n            bestDist = dist;\n            best = cand;\n        }\n    }\n    if (best == -1) {\n        int idx = lower_bound(safe.begin(), safe.end(), min_j) - safe.begin();\n        if (idx >= (int)safe.size()) idx = (int)safe.size() - 1;\n        best = safe[idx];\n    }\n    return best;\n}\n\n// Plan boundary j-values (in terms of index into arr_sorted: cut between j and j+1) given per-segment counts\nstatic vector<int> plan_boundaries_from_targets(const vector<long long>& arr_sorted, const vector<int>& inc) {\n    int N = (int)arr_sorted.size();\n    int L = (int)inc.size();\n    vector<int> safe = build_safe_indices(arr_sorted);\n    vector<int> js; js.reserve(L);\n    int pos = 0;\n    for (int i = 0; i < L; ++i) {\n        int c = inc[i];\n        if (pos >= N) {\n            js.push_back(N - 1); // far right\n            continue;\n        }\n        if (c <= 0) {\n            js.push_back(-1); // far left\n            continue;\n        }\n        int desired = pos + c - 1;\n        desired = max(desired, pos - 1);\n        desired = min(desired, N - 1);\n        int j = choose_nearest_safe(safe, desired, pos - 1);\n        js.push_back(j);\n        if (j >= pos - 1) pos = max(pos, j + 1);\n    }\n    sort(js.begin(), js.end()); // monotone sequence\n    return js;\n}\n\nstruct Projected {\n    vector<long long> u, v;         // raw projections\n    vector<pair<long long,int>> up, vp; // value,id sorted\n    vector<long long> uSorted, vSorted;\n    vector<int> ru, rv;             // ranks in sorted arrays\n    vector<int> safeU, safeV;       // safe j lists\n};\n\nstatic void build_projection(const vector<Point>& pts, const Normal& nx, const Normal& ny, Projected& P) {\n    int N = (int)pts.size();\n    P.u.resize(N); P.v.resize(N);\n    for (int i = 0; i < N; ++i) {\n        P.u[i] = nx.nx * (long long)pts[i].x + nx.ny * (long long)pts[i].y;\n        P.v[i] = ny.nx * (long long)pts[i].x + ny.ny * (long long)pts[i].y;\n    }\n    P.up.resize(N); P.vp.resize(N);\n    for (int i = 0; i < N; ++i) {\n        P.up[i] = {P.u[i], i};\n        P.vp[i] = {P.v[i], i};\n    }\n    stable_sort(P.up.begin(), P.up.end());\n    stable_sort(P.vp.begin(), P.vp.end());\n    P.uSorted.resize(N);\n    P.vSorted.resize(N);\n    P.ru.assign(N, 0);\n    P.rv.assign(N, 0);\n    for (int i = 0; i < N; ++i) {\n        P.uSorted[i] = P.up[i].first;\n        P.vSorted[i] = P.vp[i].first;\n        P.ru[P.up[i].second] = i;\n        P.rv[P.vp[i].second] = i;\n    }\n    // Build safe indices\n    P.safeU = build_safe_indices(P.uSorted);\n    P.safeV = build_safe_indices(P.vSorted);\n}\n\nstatic long long evaluate_score_from_boundaries(const vector<int>& jx, const vector<int>& jy,\n                                                const Projected& P,\n                                                const array<int,11>& a) {\n    int V = (int)jx.size();\n    int H = (int)jy.size();\n    int C = V + 1;\n    int R = H + 1;\n    vector<int> counts(C * R, 0);\n    // For each point, get ci = # {j in jx | j <= ru-1} and ri similar\n    for (size_t i = 0; i < P.u.size(); ++i) {\n        int ru = P.ru[i];\n        int rv = P.rv[i];\n        int ci = int(upper_bound(jx.begin(), jx.end(), ru - 1) - jx.begin());\n        int ri = int(upper_bound(jy.begin(), jy.end(), rv - 1) - jy.begin());\n        counts[ri * C + ci] += 1;\n    }\n    array<int,11> b{}; // b[1..10]\n    for (int val : counts) {\n        if (val >= 1 && val <= 10) b[val]++;\n    }\n    long long s = 0;\n    for (int d = 1; d <= 10; ++d) s += min(a[d], b[d]);\n    return s;\n}\n\nstatic long long extgcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) { x = (a >= 0 ? 1 : -1); y = 0; return llabs(a); }\n    long long x1, y1;\n    long long g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\n// Convert boundary j list to integer constants T for the line equation nx*x + ny*y = T\nstatic vector<long long> constants_from_boundaries(const vector<int>& jlist, const vector<long long>& arrSorted) {\n    int N = (int)arrSorted.size();\n    long long minV = arrSorted.front();\n    long long maxV = arrSorted.back();\n    vector<int> js = jlist;\n    sort(js.begin(), js.end());\n    vector<long long> T; T.reserve(js.size());\n    int leftExtra = 0, rightExtra = 0;\n    for (int j : js) {\n        if (j <= -1) {\n            T.push_back(minV - 1 - leftExtra);\n            leftExtra++;\n        } else if (j >= N - 1) {\n            T.push_back(maxV + 1 + rightExtra);\n            rightExtra++;\n        } else {\n            T.push_back(arrSorted[j] + 1);\n        }\n    }\n    return T;\n}\n\nstatic pair<pair<long long,long long>, pair<long long,long long>> line_endpoints(const Normal& n, long long T) {\n    long long nx = n.nx, ny = n.ny;\n    long long x0, y0;\n    long long g = extgcd(nx, ny, x0, y0);\n    if (g < 0) { g = -g; x0 = -x0; y0 = -y0; }\n    long long mul = T / g;\n    long long px = x0 * mul;\n    long long py = y0 * mul;\n    long long dx = -ny;\n    long long dy = nx;\n    long long px2 = px + dx, py2 = py + dy;\n    return {{px, py}, {px2, py2}};\n}\n\nstruct Candidate {\n    Normal nx, ny;\n    vector<int> jx, jy; // boundary j-values\n    long long score;\n};\n\n// Generate orientation pairs (coprime small normals)\nstatic vector<pair<Normal,Normal>> generate_orientations() {\n    vector<pair<Normal,Normal>> O;\n    auto add = [&](long long ax, long long ay, long long bx, long long by) {\n        if (std::gcd(llabs(ax), llabs(ay)) != 1) return;\n        if (std::gcd(llabs(bx), llabs(by)) != 1) return;\n        // Non-collinear\n        if (ax * by - ay * bx == 0) return;\n        O.push_back({{ax, ay}, {bx, by}});\n    };\n    add(1,0,  0,1);\n    add(1,1,  1,-1);\n    add(2,1,  1,2);\n    add(3,1,  1,3);\n    add(3,2,  2,3);\n    add(4,1,  1,4);\n    add(2,1,  1,-2);\n    add(5,2,  2,5);\n    return O;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    long long start_us = now_us();\n    const long long TIME_LIMIT_US = 2900000; // 2.9s\n    const long long SEARCH_BUDGET_US = 1700000; // ~1.7s for global search\n    const long long LOCAL_BUDGET_US = 1000000;  // ~1.0s for local search (rest is slack)\n\n    int N, K;\n    if (!(cin >> N >> K)) return 0;\n    array<int,11> a{}; for (int d = 1; d <= 10; ++d) cin >> a[d];\n    vector<Point> pts(N); for (int i = 0; i < N; ++i) cin >> pts[i].x >> pts[i].y;\n\n    // Orientation candidates\n    vector<pair<Normal,Normal>> orientations = generate_orientations();\n\n    // Budgeted k values and V/H ratios\n    vector<int> kList;\n    for (int x : {50, 70, 90, 100}) if (x <= K) kList.push_back(x);\n    if (kList.empty()) kList.push_back(min(K, 50));\n    vector<long double> alphaList = {0.35L, 0.45L, 0.55L, 0.65L};\n\n    // Weight options\n    vector<WeightSpec> weightOptions = {\n        {0, 1.0L},   // uniform\n        {1, 0.95L},  // symmetric mild\n        {1, 0.90L},  // symmetric medium\n        {1, 0.85L},  // symmetric strong\n        {2, 0.95L},  // monotonic mild\n        {2, 0.90L},  // monotonic medium\n        {2, 0.80L},  // monotonic strong\n    };\n\n    mt19937_64 rng(123456789); // deterministic for stability\n\n    Candidate best; best.score = -1;\n\n    // Global search\n    for (auto &orn : orientations) {\n        if (now_us() - start_us > SEARCH_BUDGET_US) break;\n\n        Projected P;\n        build_projection(pts, orn.first, orn.second, P);\n\n        for (int kUse : kList) {\n            if (now_us() - start_us > SEARCH_BUDGET_US) break;\n\n            for (long double alpha : alphaList) {\n                if (now_us() - start_us > SEARCH_BUDGET_US) break;\n\n                int V = (int)llround(alpha * kUse);\n                V = max(1, min(V, kUse - 1));\n                int H = kUse - V;\n                int C = V + 1, R = H + 1;\n\n                for (const auto &wc : weightOptions) {\n                    if (now_us() - start_us > SEARCH_BUDGET_US) break;\n                    vector<long double> wcol = make_weights(C, wc);\n                    vector<int> colCounts = targets_from_weights(wcol, N);\n                    vector<int> colInc(colCounts.begin(), colCounts.end() - 1);\n\n                    for (const auto &wr : weightOptions) {\n                        if (now_us() - start_us > SEARCH_BUDGET_US) break;\n                        vector<long double> wrow = make_weights(R, wr);\n                        vector<int> rowCounts = targets_from_weights(wrow, N);\n                        vector<int> rowInc(rowCounts.begin(), rowCounts.end() - 1);\n\n                        vector<int> jx = plan_boundaries_from_targets(P.uSorted, colInc);\n                        vector<int> jy = plan_boundaries_from_targets(P.vSorted, rowInc);\n\n                        long long sc = evaluate_score_from_boundaries(jx, jy, P, a);\n                        if (sc > best.score) {\n                            best.score = sc;\n                            best.nx = orn.first;\n                            best.ny = orn.second;\n                            best.jx = move(jx);\n                            best.jy = move(jy);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Local improvement (hill-climbing) on the best grid\n    if (best.score < 0) {\n        // Fallback: no cuts\n        cout << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Prepare projection for best orientation\n    Projected Pbest;\n    build_projection(pts, best.nx, best.ny, Pbest);\n\n    // Convert j-values to indices in safe arrays for quick move steps\n    auto to_safe_indices = [&](const vector<int>& jlist, const vector<int>& safe) {\n        vector<int> sidx(jlist.size());\n        for (size_t i = 0; i < jlist.size(); ++i) {\n            int j = jlist[i];\n            int idx = int(lower_bound(safe.begin(), safe.end(), j) - safe.begin());\n            if (idx == (int)safe.size() || safe[idx] != j) {\n                // due to sorting, j should be in safe; handle extremes anyway\n                // adjust to nearest\n                if (idx > 0) --idx;\n            }\n            // ensure exact match\n            if (safe[idx] != j) {\n                // fallback search small window\n                int k1 = idx;\n                if (k1+1 < (int)safe.size() && safe[k1+1] == j) idx = k1+1;\n                else if (k1 > 0 && safe[k1-1] == j) idx = k1-1;\n            }\n            sidx[i] = idx;\n        }\n        sort(sidx.begin(), sidx.end());\n        return sidx;\n    };\n\n    auto sx = to_safe_indices(best.jx, Pbest.safeU);\n    auto sy = to_safe_indices(best.jy, Pbest.safeV);\n\n    auto rebuild_j_from_s = [&](const vector<int>& sidx, const vector<int>& safe) {\n        vector<int> jv; jv.reserve(sidx.size());\n        for (int si : sidx) jv.push_back(safe[si]);\n        // jv must be nondecreasing if sidx is nondecreasing\n        return jv;\n    };\n\n    auto evaluate_s = [&](const vector<int>& sx, const vector<int>& sy) {\n        vector<int> jx = rebuild_j_from_s(sx, Pbest.safeU);\n        vector<int> jy = rebuild_j_from_s(sy, Pbest.safeV);\n        return evaluate_score_from_boundaries(jx, jy, Pbest, a);\n    };\n\n    long long currentScore = evaluate_s(sx, sy);\n    if (currentScore != best.score) {\n        // in rare cases due to rounding differences; sync\n        best.score = currentScore;\n    }\n\n    uniform_int_distribution<int> coin(0, 1);\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    auto try_move_line = [&](bool vertical, int idx, int dir, int step)->bool{\n        if (vertical) {\n            if (sx.empty()) return false;\n            int V = (int)sx.size();\n            if (idx < 0 || idx >= V) return false;\n            int new_val = sx[idx] + dir * step;\n            int lo = (idx == 0 ? sx[idx] : sx[idx-1]);\n            int hi = (idx == V-1 ? sx[idx] : sx[idx+1]);\n            if (dir < 0) {\n                new_val = max(new_val, lo);\n            } else {\n                new_val = min(new_val, hi);\n            }\n            if (new_val == sx[idx]) return false;\n\n            int old = sx[idx];\n            sx[idx] = new_val;\n            long long sc = evaluate_s(sx, sy);\n            if (sc > currentScore) {\n                currentScore = sc;\n                return true;\n            } else {\n                sx[idx] = old;\n                return false;\n            }\n        } else {\n            if (sy.empty()) return false;\n            int H = (int)sy.size();\n            if (idx < 0 || idx >= H) return false;\n            int new_val = sy[idx] + dir * step;\n            int lo = (idx == 0 ? sy[idx] : sy[idx-1]);\n            int hi = (idx == H-1 ? sy[idx] : sy[idx+1]);\n            if (dir < 0) new_val = max(new_val, lo);\n            else new_val = min(new_val, hi);\n            if (new_val == sy[idx]) return false;\n\n            int old = sy[idx];\n            sy[idx] = new_val;\n            long long sc = evaluate_s(sx, sy);\n            if (sc > currentScore) {\n                currentScore = sc;\n                return true;\n            } else {\n                sy[idx] = old;\n                return false;\n            }\n        }\n    };\n\n    // Hill-climb loop within time budget\n    while (now_us() - start_us < SEARCH_BUDGET_US + LOCAL_BUDGET_US) {\n        bool vertical = coin(rng);\n        if ((vertical && sx.empty()) || (!vertical && sy.empty())) vertical = !vertical;\n        int idx = 0;\n        int step = 1;\n        if (vertical) {\n            if (sx.empty()) break;\n            uniform_int_distribution<int> pick(0, (int)sx.size() - 1);\n            idx = pick(rng);\n        } else {\n            if (sy.empty()) break;\n            uniform_int_distribution<int> pick(0, (int)sy.size() - 1);\n            idx = pick(rng);\n        }\n        double r = uni01(rng);\n        if (r < 0.15) step = 2;\n        else if (r < 0.20) step = 3;\n        int dir = (coin(rng) ? 1 : -1);\n        try_move_line(vertical, idx, dir, step);\n    }\n\n    // Rebuild final j lists and compute T constants for output\n    vector<int> finalJx = rebuild_j_from_s(sx, Pbest.safeU);\n    vector<int> finalJy = rebuild_j_from_s(sy, Pbest.safeV);\n    vector<long long> Tx = constants_from_boundaries(finalJx, Pbest.uSorted);\n    vector<long long> Ty = constants_from_boundaries(finalJy, Pbest.vSorted);\n\n    // Output lines\n    int V = (int)Tx.size();\n    int H = (int)Ty.size();\n    cout << (V + H) << \"\\n\";\n    // Family X\n    for (int i = 0; i < V; ++i) {\n        auto ep = line_endpoints(best.nx, Tx[i]);\n        auto [p, q] = ep;\n        cout << p.first << \" \" << p.second << \" \" << q.first << \" \" << q.second << \"\\n\";\n    }\n    // Family Y\n    for (int j = 0; j < H; ++j) {\n        auto ep = line_endpoints(best.ny, Ty[j]);\n        auto [p, q] = ep;\n        cout << p.first << \" \" << p.second << \" \" << q.first << \" \" << q.second << \"\\n\";\n    }\n\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Operation {\n    int x1,y1,x2,y2,x3,y3,x4,y4;\n};\n\nstruct Params {\n    long long fanCoef;             // fan-out coefficient\n    double   expCoefBase;          // base expansion bonus per margin unit\n    double   expCoefFactor;        // factor on (1 - areaRatio)\n    long long rotBiasInitial;      // initial bias for rotated rectangles\n    int      rotBiasDecayOps;      // decay horizon (ops)\n    double   axisInsideCoefBase;   // axis inside-perimeter penalty base\n    double   axisInsideCoefFactor; // axis inside-perimeter penalty factor\n    double   rotInsideCoefBase;    // rotated inside-perimeter penalty base\n    double   rotInsideCoefFactor;  // rotated inside-perimeter penalty factor\n    int      noiseAmp;             // random noise amplitude added to score\n    uint64_t seedSalt;             // seed salt per variant\n};\n\nstruct Solver {\n    int N, M;\n    int c; // center coordinate (N-1)/2\n    vector<uint8_t> occ; // occupancy grid N*N\n\n    // used unit segments\n    vector<uint8_t> usedH;  // horizontal: size N*(N-1), seg (x,y)-(x+1,y)\n    vector<uint8_t> usedV;  // vertical:   size (N-1)*N, seg (x,y)-(x,y+1)\n    vector<uint8_t> usedD1; // diag +1:    size (N-1)*(N-1), (x,y)-(x+1,y+1)\n    vector<uint8_t> usedD2; // diag -1:    size (N-1)*(N-1), (x,y)-(x+1,y-1) mapped by y-1\n\n    vector<pair<int,int>> points; // all dots (initial + added)\n    vector<Operation> ops;\n\n    // line indices for fast 45\u00b0 generation\n    vector<vector<pair<int,int>>> diagPlus;  // size 2N-1, id = (x - y) + (N-1)\n    vector<vector<pair<int,int>>> diagMinus; // size 2N-1, id = (x + y)\n\n    // row/column indices for axis generation\n    vector<vector<int>> rowXs; // rowXs[y] = list of x such that (x,y) occupied\n    vector<vector<int>> colYs; // colYs[x] = list of y such that (x,y) occupied\n\n    // dedup sets\n    unordered_set<uint64_t> seenAxis;\n    unordered_set<uint64_t> seenRot;\n\n    // bounding box of current occupied points\n    int minX, maxX, minY, maxY;\n\n    // committed ops count (for phase-dependent bias)\n    int opsCount = 0;\n\n    // sum of weights of all points (initial + added)\n    long long totalWeight = 0;\n\n    // parameters\n    Params P;\n\n    // RNG for noise\n    uint64_t rng_state = 0;\n\n    inline uint32_t rng_u32() {\n        uint64_t x = rng_state;\n        x ^= x << 7;\n        x ^= x >> 9;\n        rng_state = x;\n        return (uint32_t)(x & 0xffffffffu);\n    }\n    inline int rng_noise(int amp) { // uniform in [-amp, amp]\n        if (amp <= 0) return 0;\n        uint32_t r = rng_u32();\n        return (int)( (int) (r % (2u*amp+1u)) ) - amp;\n    }\n\n    inline int idx(int x, int y) const { return y*N + x; }\n    inline bool isInside(int x, int y) const { return (0 <= x && x < N && 0 <= y && y < N); }\n\n    inline int idxH(int x, int y) const { return y*(N-1) + x; } // x in [0..N-2], y in [0..N-1]\n    inline int idxV(int x, int y) const { return y*N + x; }     // x in [0..N-1], y in [0..N-2]\n    inline int idxD1_fromPoints(int x0, int y0, int x1, int y1) const {\n        int x = min(x0, x1);\n        int y = min(y0, y1);\n        return y*(N-1) + x;\n    }\n    inline int idxD2_fromPoints(int x0, int y0, int x1, int y1) const {\n        int x = min(x0, x1);\n        int y = max(y0, y1); // y in [1..N-1]\n        return (y-1)*(N-1) + x;\n    }\n\n    inline int weight(int x, int y) const {\n        int dx = x - c;\n        int dy = y - c;\n        return dx*dx + dy*dy + 1;\n    }\n\n    struct Candidate {\n        // type 0: axis-aligned rectangle\n        // type 1: rotated 45\u00b0 rectangle (sides parallel to y=x and y=-x)\n        int type;\n        int p1x, p1y; // new dot\n        // scoring\n        long long w;           // weight(p1)\n        int perim;             // perimeter measured in unit segments\n        long long score;       // priority key: higher is better\n\n        // axis fields\n        int xL, xR, yB, yT;\n        int insideLen; // total unit segments lying inside current bbox at push-time (axis or rotated)\n\n        // rot45 fields: store three existing corners A,B,C (D=p1)\n        int ax, ay, bx, by, cx, cy;\n    };\n\n    struct CandCmp {\n        bool operator()(const Candidate& a, const Candidate& b) const {\n            if (a.score != b.score) return a.score < b.score; // max-heap by score\n            if (a.w != b.w) return a.w < b.w; // then by raw weight\n            int aa;\n            if (a.type==0) aa = (a.xR - a.xL) + (a.yT - a.yB);\n            else {\n                int d1 = abs(a.bx - a.ax);\n                int d2 = abs(a.cx - a.ax);\n                aa = d1 + d2;\n            }\n            int bb;\n            if (b.type==0) bb = (b.xR - b.xL) + (b.yT - b.yB);\n            else {\n                int d1 = abs(b.bx - b.ax);\n                int d2 = abs(b.cx - b.ax);\n                bb = d1 + d2;\n            }\n            if (aa != bb) return aa < bb;\n            if (a.p1x != b.p1x) return a.p1x < b.p1x;\n            return a.p1y < b.p1y;\n        }\n    };\n\n    priority_queue<Candidate, vector<Candidate>, CandCmp> pq;\n\n    Solver(int N_, int M_, const vector<pair<int,int>>& initPts, const Params& Pin, uint64_t seedBase)\n        : N(N_), M(M_), P(Pin) {\n        c = (N - 1) / 2;\n        occ.assign(N*N, 0);\n        usedH.assign(N*(N-1), 0);\n        usedV.assign((N-1)*N, 0);\n        usedD1.assign((N-1)*(N-1), 0);\n        usedD2.assign((N-1)*(N-1), 0);\n        diagPlus.assign(2*N-1, {});\n        diagMinus.assign(2*N-1, {});\n        rowXs.assign(N, {});\n        colYs.assign(N, {});\n        seenAxis.reserve(1<<20);\n        seenRot.reserve(1<<20);\n        minX = 1e9; maxX = -1e9; minY = 1e9; maxY = -1e9;\n\n        points.reserve(N*N);\n        for (auto &p : initPts) {\n            int x = p.first, y = p.second;\n            points.emplace_back(x,y);\n            occ[idx(x,y)] = 1;\n            totalWeight += weight(x,y);\n        }\n\n        rng_state = seedBase ^ P.seedSalt;\n    }\n\n    inline int diagPlusId(int x, int y) const { return (x - y) + (N - 1); }\n    inline int diagMinusId(int x, int y) const { return (x + y); }\n\n    inline double bboxAreaRatio() const {\n        if (minX > maxX) return 1.0;\n        long long w = (maxX - minX + 1);\n        long long h = (maxY - minY + 1);\n        double area = double(w) * double(h);\n        return area / double(N * N);\n    }\n\n    // non-const to allow RNG noise\n    inline long long computePriority(int px, int py, int perim, long long w, int type, int insideLen) {\n        long long base = (long long)w * 100000LL / (perim + 4);\n\n        int rowD = (py>=0 && py<N) ? (int)rowXs[py].size() : 0;\n        int colD = (px>=0 && px<N) ? (int)colYs[px].size() : 0;\n        int degPlus = (int)diagPlus[diagPlusId(px,py)].size();\n        int degMinus = (int)diagMinus[diagMinusId(px,py)].size();\n        long long fan = (long long)rowD * colD + (long long)degPlus * degMinus;\n        long long fanTerm = P.fanCoef * fan;\n\n        double ar = bboxAreaRatio();\n        long long expCoef = (long long)(P.expCoefBase * (1.0 + P.expCoefFactor * (1.0 - ar)));\n        int margin = 0;\n        if (minX <= maxX) {\n            margin = max(margin, (px < minX) ? (minX - px) : 0);\n            margin = max(margin, (px > maxX) ? (px - maxX) : 0);\n            margin = max(margin, (py < minY) ? (minY - py) : 0);\n            margin = max(margin, (py > maxY) ? (py - maxY) : 0);\n        }\n        long long expandTerm = (long long)margin * expCoef;\n\n        long long rotBias = 0;\n        if (type == 1 && P.rotBiasDecayOps > 0) {\n            int rem = max(0, P.rotBiasDecayOps - opsCount);\n            rotBias = (P.rotBiasInitial * (long long)rem) / P.rotBiasDecayOps;\n        }\n\n        long long insidePenalty = 0;\n        if (insideLen > 0 && minX <= maxX) {\n            double arFactor = (1.0 + 0.5 * (1.0 - ar));\n            if (type == 0) {\n                long long penCoef = (long long)(P.axisInsideCoefBase * arFactor);\n                insidePenalty = penCoef * (long long)insideLen;\n            } else {\n                long long penCoef = (long long)(P.rotInsideCoefBase * arFactor);\n                insidePenalty = penCoef * (long long)insideLen;\n            }\n        }\n\n        long long score = base + fanTerm + expandTerm + rotBias - insidePenalty;\n        score += rng_noise(P.noiseAmp);\n        return score;\n    }\n\n    static inline uint64_t axisKey(int xL, int yB, int xR, int yT) {\n        return ( (uint64_t)(uint8_t)xL << 24 ) |\n               ( (uint64_t)(uint8_t)yB << 16 ) |\n               ( (uint64_t)(uint8_t)xR << 8  ) |\n               ( (uint64_t)(uint8_t)yT );\n    }\n    inline uint64_t rotKeyFromABC(int ax, int ay, int bx, int by, int cx, int cy) const {\n        int d1 = ax - ay;\n        int d2 = cx - cy;\n        if (d1 > d2) swap(d1, d2);\n        int s1 = ax + ay;\n        int s2 = bx + by;\n        if (s1 > s2) swap(s1, s2);\n        int sd1 = d1 + (N - 1);\n        int sd2 = d2 + (N - 1);\n        return ( (uint64_t)(uint8_t)sd1 << 24 ) |\n               ( (uint64_t)(uint8_t)sd2 << 16 ) |\n               ( (uint64_t)(uint8_t)s1  << 8  ) |\n               ( (uint64_t)(uint8_t)s2 );\n    }\n\n    bool validateAxis(const Candidate& cd) const {\n        if (!isInside(cd.p1x, cd.p1y)) return false;\n        if (occ[idx(cd.p1x, cd.p1y)]) return false;\n\n        int cx[4] = {cd.xL, cd.xR, cd.xR, cd.xL};\n        int cy[4] = {cd.yB, cd.yB, cd.yT, cd.yT};\n        int cntExist = 0;\n        for (int i=0;i<4;i++) {\n            int x = cx[i], y = cy[i];\n            if (x==cd.p1x && y==cd.p1y) continue;\n            if (!isInside(x,y)) return false;\n            if (!occ[idx(x,y)]) return false;\n            cntExist++;\n        }\n        if (cntExist != 3) return false;\n\n        for (int x = cd.xL+1; x <= cd.xR-1; ++x) {\n            if (occ[idx(x, cd.yB)]) return false;\n            if (occ[idx(x, cd.yT)]) return false;\n        }\n        for (int y = cd.yB+1; y <= cd.yT-1; ++y) {\n            if (occ[idx(cd.xL, y)]) return false;\n            if (occ[idx(cd.xR, y)]) return false;\n        }\n\n        for (int x = cd.xL; x <= cd.xR-1; ++x) {\n            if (usedH[idxH(x, cd.yB)]) return false;\n            if (usedH[idxH(x, cd.yT)]) return false;\n        }\n        for (int y = cd.yB; y <= cd.yT-1; ++y) {\n            if (usedV[idxV(cd.xL, y)]) return false;\n            if (usedV[idxV(cd.xR, y)]) return false;\n        }\n        return true;\n    }\n\n    bool validateRot45(const Candidate& cd) const {\n        int ax=cd.ax, ay=cd.ay, bx=cd.bx, by=cd.by, cx=cd.cx, cy=cd.cy;\n        int dx=cd.p1x, dy=cd.p1y;\n\n        if (!isInside(dx,dy) || occ[idx(dx,dy)]) return false;\n        if (!isInside(ax,ay) || !isInside(bx,by) || !isInside(cx,cy)) return false;\n        if (!occ[idx(ax,ay)] || !occ[idx(bx,by)] || !occ[idx(cx,cy)]) return false;\n\n        if (abs(bx - ax) != abs(by - ay)) return false;\n        if (abs(cx - ax) != abs(cy - ay)) return false;\n        int d1 = abs(bx - ax);\n        int d2 = abs(cx - ax);\n        if (d1 == 0 || d2 == 0) return false;\n\n        if (!(dx == bx + cx - ax && dy == by + cy - ay)) return false;\n\n        int s1x = (bx > ax) ? 1 : -1;\n        int s1y = (by > ay) ? 1 : -1;\n        int s2x = (cx > ax) ? 1 : -1;\n        int s2y = (cy > ay) ? 1 : -1;\n\n        for (int t=1; t<=d1-1; ++t) {\n            if (occ[idx(ax + s1x*t, ay + s1y*t)]) return false;\n        }\n        for (int t=1; t<=d2-1; ++t) {\n            if (occ[idx(ax + s2x*t, ay + s2y*t)]) return false;\n        }\n        for (int t=1; t<=d2-1; ++t) {\n            if (occ[idx(bx + s2x*t, by + s2y*t)]) return false;\n        }\n        int ns1x = -s1x, ns1y = -s1y;\n        for (int t=1; t<=d1-1; ++t) {\n            if (occ[idx(dx + ns1x*t, dy + ns1y*t)]) return false;\n        }\n\n        for (int t=0; t<=d1-1; ++t) {\n            int x0 = ax + s1x*t, y0 = ay + s1y*t;\n            int x1 = ax + s1x*(t+1), y1 = ay + s1y*(t+1);\n            if (usedD1[idxD1_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n        for (int t=0; t<=d2-1; ++t) {\n            int x0 = bx + s2x*t, y0 = by + s2y*t;\n            int x1 = bx + s2x*(t+1), y1 = by + s2y*(t+1);\n            if (usedD2[idxD2_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n        for (int t=0; t<=d1-1; ++t) {\n            int x0 = dx + ns1x*t, y0 = dy + ns1y*t;\n            int x1 = dx + ns1x*(t+1), y1 = dy + ns1y*(t+1);\n            if (usedD1[idxD1_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n        for (int t=0; t<=d2-1; ++t) {\n            int x0 = cx - s2x*t, y0 = cy - s2y*t;\n            int x1 = cx - s2x*(t+1), y1 = cy - s2y*(t+1);\n            if (usedD2[idxD2_fromPoints(x0,y0,x1,y1)]) return false;\n        }\n\n        return true;\n    }\n\n    bool validate(const Candidate& cd) const {\n        if (cd.type == 0) return validateAxis(cd);\n        else return validateRot45(cd);\n    }\n\n    void markUsedSegments(const Candidate& cd) {\n        if (cd.type == 0) {\n            for (int x = cd.xL; x <= cd.xR-1; ++x) {\n                usedH[idxH(x, cd.yB)] = 1;\n                usedH[idxH(x, cd.yT)] = 1;\n            }\n            for (int y = cd.yB; y <= cd.yT-1; ++y) {\n                usedV[idxV(cd.xL, y)] = 1;\n                usedV[idxV(cd.xR, y)] = 1;\n            }\n        } else {\n            int ax=cd.ax, ay=cd.ay, bx=cd.bx, by=cd.by, cx=cd.cx, cy=cd.cy;\n            int dx=cd.p1x, dy=cd.p1y;\n            int s1x = (bx > ax) ? 1 : -1;\n            int s1y = (by > ay) ? 1 : -1;\n            int s2x = (cx > ax) ? 1 : -1;\n            int s2y = (cy > ay) ? 1 : -1;\n            int ns1x = -s1x, ns1y = -s1y;\n            int d1 = abs(bx - ax);\n            int d2 = abs(cx - ax);\n\n            for (int t=0; t<=d1-1; ++t) {\n                int x0 = ax + s1x*t, y0 = ay + s1y*t;\n                int x1 = ax + s1x*(t+1), y1 = ay + s1y*(t+1);\n                usedD1[idxD1_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n            for (int t=0; t<=d2-1; ++t) {\n                int x0 = bx + s2x*t, y0 = by + s2y*t;\n                int x1 = bx + s2x*(t+1), y1 = by + s2y*(t+1);\n                usedD2[idxD2_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n            for (int t=0; t<=d1-1; ++t) {\n                int x0 = dx + ns1x*t, y0 = dy + ns1y*t;\n                int x1 = dx + ns1x*(t+1), y1 = dy + ns1y*(t+1);\n                usedD1[idxD1_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n            for (int t=0; t<=d2-1; ++t) {\n                int x0 = cx - s2x*t, y0 = cy - s2y*t;\n                int x1 = cx - s2x*(t+1), y1 = cy - s2y*(t+1);\n                usedD2[idxD2_fromPoints(x0,y0,x1,y1)] = 1;\n            }\n        }\n    }\n\n    void emitOperation(const Candidate& cd) {\n        Operation op;\n        if (cd.type == 0) {\n            int LLx = cd.xL, LLy = cd.yB;\n            int LRx = cd.xR, LRy = cd.yB;\n            int URx = cd.xR, URy = cd.yT;\n            int ULx = cd.xL, ULy = cd.yT;\n            array<pair<int,int>,4> seq = {{{LLx,LLy},{LRx,LRy},{URx,URy},{ULx,ULy}}};\n            int pos = 0;\n            for (int i=0;i<4;i++) if (seq[i].first==cd.p1x && seq[i].second==cd.p1y) { pos=i; break; }\n            auto get = [&](int k)->pair<int,int> { return seq[(pos + k) % 4]; };\n            auto p1 = get(0);\n            auto p2 = get(1);\n            auto p3 = get(2);\n            auto p4 = get(3);\n            op = {p1.first,p1.second,p2.first,p2.second,p3.first,p3.second,p4.first,p4.second};\n        } else {\n            int ax=cd.ax, ay=cd.ay, bx=cd.bx, by=cd.by, cx=cd.cx, cy=cd.cy;\n            int dx=cd.p1x, dy=cd.p1y;\n            op = {dx,dy, cx,cy, ax,ay, bx,by};\n        }\n        ops.push_back(op);\n    }\n\n    inline int axisInsideLen(int xL, int yB, int xR, int yT) const {\n        if (minX > maxX) return 0;\n        int inside = 0;\n        if (yB >= minY && yB <= maxY) {\n            int L = max(xL, minX);\n            int R = min(xR, maxX);\n            if (R > L) inside += (R - L);\n        }\n        if (yT >= minY && yT <= maxY) {\n            int L = max(xL, minX);\n            int R = min(xR, maxX);\n            if (R > L) inside += (R - L);\n        }\n        if (xL >= minX && xL <= maxX) {\n            int B = max(yB, minY);\n            int T = min(yT, maxY);\n            if (T > B) inside += (T - B);\n        }\n        if (xR >= minX && xR <= maxX) {\n            int B = max(yB, minY);\n            int T = min(yT, maxY);\n            if (T > B) inside += (T - B);\n        }\n        return inside;\n    }\n\n    inline int diagInsideSegs(int x0, int y0, int sx, int sy, int len) const {\n        if (minX > maxX) return 0;\n        int tLowX, tHighX, tLowY, tHighY;\n        if (sx == 1) { tLowX = minX - x0; tHighX = maxX - x0; }\n        else         { tLowX = x0 - maxX; tHighX = x0 - minX; }\n        if (sy == 1) { tLowY = minY - y0; tHighY = maxY - y0; }\n        else         { tLowY = y0 - maxY; tHighY = y0 - minY; }\n        int L = max({0, tLowX, tLowY});\n        int R = min({len, tHighX, tHighY});\n        int cnt = R - L;\n        if (cnt < 0) cnt = 0;\n        return cnt;\n    }\n\n    inline int rotInsideLen(int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy) const {\n        int d1 = abs(bx - ax);\n        int d2 = abs(cx - ax);\n        int s1x = (bx > ax) ? 1 : -1;\n        int s1y = (by > ay) ? 1 : -1;\n        int s2x = (cx > ax) ? 1 : -1;\n        int s2y = (cy > ay) ? 1 : -1;\n        int ns1x = -s1x, ns1y = -s1y;\n        int inside = 0;\n        inside += diagInsideSegs(ax, ay, s1x, s1y, d1);\n        inside += diagInsideSegs(bx, by, s2x, s2y, d2);\n        inside += diagInsideSegs(dx, dy, ns1x, ns1y, d1);\n        inside += diagInsideSegs(cx, cy, -s2x, -s2y, d2);\n        return inside;\n    }\n\n    void pushAxisCandidateFromPair(int x1, int y1, int x2, int y2) {\n        if (x1 == x2 || y1 == y2) return;\n        int xL = min(x1, x2), xR = max(x1, x2);\n        int yB = min(y1, y2), yT = max(y1, y2);\n        int c1x = x1, c1y = y2;\n        int c2x = x2, c2y = y1;\n        bool occ1 = occ[idx(c1x, c1y)];\n        bool occ2 = occ[idx(c2x, c2y)];\n        if (occ1 == occ2) return;\n\n        uint64_t key = axisKey(xL, yB, xR, yT);\n        if (seenAxis.find(key) != seenAxis.end()) return;\n\n        Candidate cd;\n        cd.type = 0;\n        if (!occ1) { cd.p1x = c1x; cd.p1y = c1y; }\n        else       { cd.p1x = c2x; cd.p1y = c2y; }\n        cd.xL = xL; cd.xR = xR; cd.yB = yB; cd.yT = yT;\n        cd.w = weight(cd.p1x, cd.p1y);\n        cd.perim = 2 * ((xR - xL) + (yT - yB));\n        cd.insideLen = axisInsideLen(xL, yB, xR, yT);\n        cd.score = computePriority(cd.p1x, cd.p1y, cd.perim, cd.w, cd.type, cd.insideLen);\n        if (validate(cd)) {\n            pq.push(cd);\n            seenAxis.insert(key);\n        }\n    }\n\n    void pushRot45CandidateFromPivotABC(int ax, int ay, int bx, int by, int cx, int cy) {\n        int dx = bx + cx - ax;\n        int dy = by + cy - ay;\n        if (!isInside(dx,dy)) return;\n        if (occ[idx(dx,dy)]) return;\n\n        uint64_t key = rotKeyFromABC(ax,ay,bx,by,cx,cy);\n        if (seenRot.find(key) != seenRot.end()) return;\n\n        Candidate cd;\n        cd.type = 1;\n        cd.ax = ax; cd.ay = ay; cd.bx = bx; cd.by = by; cd.cx = cx; cd.cy = cy;\n        cd.p1x = dx; cd.p1y = dy;\n        cd.w = weight(dx,dy);\n\n        int d1 = abs(bx - ax);\n        int d2 = abs(cx - ax);\n        if (d1 == 0 || d2 == 0) return;\n        cd.perim = 2*(d1 + d2);\n        cd.insideLen = rotInsideLen(ax, ay, bx, by, cx, cy, dx, dy);\n        cd.score = computePriority(cd.p1x, cd.p1y, cd.perim, cd.w, cd.type, cd.insideLen);\n\n        if (validate(cd)) {\n            pq.push(cd);\n            seenRot.insert(key);\n        }\n    }\n\n    void generateRot45FromPivot(int ax, int ay) {\n        int idp = diagPlusId(ax, ay);\n        int idm = diagMinusId(ax, ay);\n        auto &Blist = diagPlus[idp];\n        auto &Clist = diagMinus[idm];\n        if (Blist.size() <= 1 || Clist.size() <= 1) return;\n\n        for (auto &B : Blist) {\n            int bx = B.first, by = B.second;\n            if (bx == ax && by == ay) continue;\n            for (auto &C : Clist) {\n                int cx = C.first, cy = C.second;\n                if (cx == ax && cy == ay) continue;\n                pushRot45CandidateFromPivotABC(ax, ay, bx, by, cx, cy);\n            }\n        }\n    }\n\n    void generateRot45WithNewAsB(int nx, int ny) {\n        int idp = diagPlusId(nx, ny);\n        auto &AList = diagPlus[idp];\n        for (auto &A : AList) {\n            int ax = A.first, ay = A.second;\n            if (ax == nx && ay == ny) continue;\n            auto &Clist = diagMinus[diagMinusId(ax, ay)];\n            if (Clist.empty()) continue;\n            for (auto &C : Clist) {\n                int cx = C.first, cy = C.second;\n                if (cx == ax && cy == ay) continue;\n                pushRot45CandidateFromPivotABC(ax, ay, nx, ny, cx, cy);\n            }\n        }\n    }\n\n    void generateRot45WithNewAsC(int nx, int ny) {\n        int idm = diagMinusId(nx, ny);\n        auto &AList = diagMinus[idm];\n        for (auto &A : AList) {\n            int ax = A.first, ay = A.second;\n            if (ax == nx && ay == ny) continue;\n            auto &Blist = diagPlus[diagPlusId(ax, ay)];\n            if (Blist.empty()) continue;\n            for (auto &B : Blist) {\n                int bx = B.first, by = B.second;\n                if (bx == ax && by == ay) continue;\n                pushRot45CandidateFromPivotABC(ax, ay, bx, by, nx, ny);\n            }\n        }\n    }\n\n    void generateAxisWithNewAsOffDiag(int nx, int ny) {\n        auto &colList = colYs[nx];\n        auto &rowList = rowXs[ny];\n        if (colList.empty() || rowList.empty()) return;\n\n        for (int yA : colList) {\n            if (yA == ny) continue;\n            for (int xB : rowList) {\n                if (xB == nx) continue;\n                if (occ[idx(xB, yA)]) continue;\n                pushAxisCandidateFromPair(nx, yA, xB, ny);\n            }\n        }\n    }\n\n    void initialCandidates() {\n        for (auto &p : points) {\n            int x = p.first, y = p.second;\n            diagPlus[diagPlusId(x,y)].emplace_back(x,y);\n            diagMinus[diagMinusId(x,y)].emplace_back(x,y);\n            rowXs[y].push_back(x);\n            colYs[x].push_back(y);\n            minX = min(minX, x);\n            maxX = max(maxX, x);\n            minY = min(minY, y);\n            maxY = max(maxY, y);\n        }\n\n        int Pn = (int)points.size();\n        for (int i=0;i<Pn;i++) {\n            auto [x1,y1] = points[i];\n            for (int j=i+1;j<Pn;j++) {\n                auto [x2,y2] = points[j];\n                pushAxisCandidateFromPair(x1,y1,x2,y2);\n            }\n        }\n        for (auto &p : points) {\n            generateRot45FromPivot(p.first, p.second);\n        }\n    }\n\n    void generateFromNewPointAxisDiagPairs(int nx, int ny) {\n        int Pn = (int)points.size() - 1;\n        for (int i=0;i<Pn;i++) {\n            int x2 = points[i].first;\n            int y2 = points[i].second;\n            if (nx != x2 && ny != y2) {\n                pushAxisCandidateFromPair(nx,ny,x2,y2);\n            }\n        }\n    }\n\n    void addPointToLines(int x, int y) {\n        diagPlus[diagPlusId(x,y)].emplace_back(x,y);\n        diagMinus[diagMinusId(x,y)].emplace_back(x,y);\n        rowXs[y].push_back(x);\n        colYs[x].push_back(y);\n        if (minX > maxX) {\n            minX = maxX = x;\n            minY = maxY = y;\n        } else {\n            minX = min(minX, x);\n            maxX = max(maxX, x);\n            minY = min(minY, y);\n            maxY = max(maxY, y);\n        }\n    }\n\n    void solve(double timeLimitSec) {\n        initialCandidates();\n        auto start = chrono::steady_clock::now();\n        while (!pq.empty()) {\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - start).count();\n            if (elapsed > timeLimitSec) break;\n\n            Candidate cd = pq.top(); pq.pop();\n            if (!validate(cd)) continue;\n\n            occ[idx(cd.p1x, cd.p1y)] = 1;\n            points.emplace_back(cd.p1x, cd.p1y);\n            addPointToLines(cd.p1x, cd.p1y);\n            markUsedSegments(cd);\n            emitOperation(cd);\n            opsCount++;\n            totalWeight += cd.w;\n\n            generateFromNewPointAxisDiagPairs(cd.p1x, cd.p1y);\n            generateAxisWithNewAsOffDiag(cd.p1x, cd.p1y);\n\n            generateRot45FromPivot(cd.p1x, cd.p1y);\n            generateRot45WithNewAsB(cd.p1x, cd.p1y);\n            generateRot45WithNewAsC(cd.p1x, cd.p1y);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    vector<pair<int,int>> initPts;\n    initPts.reserve(M);\n    uint64_t inputHash = 1469598103934665603ULL; // FNV offset basis\n    for (int i=0;i<M;i++) {\n        int x,y; cin >> x >> y;\n        initPts.emplace_back(x,y);\n        inputHash ^= (uint64_t)(x + 0x9e3779b97f4a7c15ULL * (y+1));\n        inputHash *= 1099511628211ULL; // FNV prime\n    }\n    inputHash ^= (uint64_t)(N * 10007 + M * 1000003);\n\n    // Parameter sets\n    Params PA;\n    PA.fanCoef = 15;\n    PA.expCoefBase = 9000.0;\n    PA.expCoefFactor = 0.6;\n    PA.rotBiasInitial = 40000;\n    PA.rotBiasDecayOps = 600;\n    PA.axisInsideCoefBase = 5500.0;\n    PA.axisInsideCoefFactor = 0.5;\n    PA.rotInsideCoefBase  = 2300.0;\n    PA.rotInsideCoefFactor= 0.5;\n    PA.noiseAmp = 1500;\n    PA.seedSalt = 0x12345678abcdef01ULL;\n\n    Params PB = PA;\n    PB.fanCoef = 12;\n    PB.expCoefBase = 14000.0;\n    PB.expCoefFactor = 1.0;\n    PB.rotBiasInitial = 50000;\n    PB.rotBiasDecayOps = 800;\n    PB.axisInsideCoefBase = 5000.0;\n    PB.rotInsideCoefBase  = 1800.0;\n    PB.noiseAmp = 2500;\n    PB.seedSalt = 0x0fedcba987654321ULL;\n\n    Params PC = PA; // aggressive outward\n    PC.fanCoef = 10;\n    PC.expCoefBase = 18000.0;\n    PC.expCoefFactor = 1.4;\n    PC.rotBiasInitial = 30000;\n    PC.rotBiasDecayOps = 500;\n    PC.axisInsideCoefBase = 6000.0;\n    PC.rotInsideCoefBase  = 2200.0;\n    PC.noiseAmp = 3000;\n    PC.seedSalt = 0x9e3779b97f4a7c15ULL;\n\n    const double TOTAL_LIMIT = 4.85; // margin under 5.0\n    auto globalStart = chrono::steady_clock::now();\n\n    auto elapsedSec = [&](){\n        return chrono::duration<double>(chrono::steady_clock::now() - globalStart).count();\n    };\n\n    double remain = TOTAL_LIMIT;\n\n    // Run A\n    double budgetA = min(remain, TOTAL_LIMIT / 2.0);\n    Solver solA(N, M, initPts, PA, inputHash);\n    solA.solve(budgetA);\n    remain = TOTAL_LIMIT - elapsedSec();\n    if (remain < 0.0) remain = 0.0;\n\n    // Run B\n    double budgetB = remain * 0.7; // keep some for C if possible\n    Solver solB(N, M, initPts, PB, inputHash ^ 0xdeadbeefcafebabeULL);\n    if (budgetB > 0.05) solB.solve(budgetB);\n    remain = TOTAL_LIMIT - elapsedSec();\n    if (remain < 0.0) remain = 0.0;\n\n    // Run C if time remains\n    Solver solC(N, M, initPts, PC, inputHash ^ 0x3141592653589793ULL);\n    if (remain > 0.08) solC.solve(remain);\n\n    Solver* best = &solA;\n    if (solB.totalWeight > best->totalWeight) best = &solB;\n    if (solC.totalWeight > best->totalWeight) best = &solC;\n\n    cout << best->ops.size() << '\\n';\n    for (auto &op : best->ops) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << ' '\n             << op.x3 << ' ' << op.y3 << ' ' << op.x4 << ' ' << op.y4 << '\\n';\n    }\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    void reset(int m){ n=m; p.resize(n); sz.assign(n,1); iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\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; sz[a]+=sz[b];\n        return true;\n    }\n};\n\nstruct Simulator {\n    static const int H = 10;\n    static const int W = 10;\n    array<array<int,W>,H> board;\n\n    Simulator() { for (int r=0;r<H;r++) for (int c=0;c<W;c++) board[r][c]=0; }\n\n    pair<int,int> emptyIndexToRC(int p) const {\n        int cnt=0;\n        for (int r=0;r<H;r++){\n            for (int c=0;c<W;c++){\n                if (board[r][c]==0){\n                    ++cnt;\n                    if (cnt==p) return {r,c};\n                }\n            }\n        }\n        return {-1,-1};\n    }\n\n    struct SimResult {\n        array<array<int,W>,H> b;\n        int new_r, new_c;\n    };\n\n    // dir: 0=F,1=B,2=L,3=R\n    SimResult simulateTilt(const array<array<int,W>,H>& inputBoard, int dir, int src_r, int src_c) const {\n        SimResult res;\n        for (int r=0;r<H;r++) for (int c=0;c<W;c++) res.b[r][c]=0;\n\n        if (dir == 0) { // F (up)\n            int cnt = 0;\n            for (int r=0; r<=src_r; ++r) if (inputBoard[r][src_c]!=0) ++cnt;\n            res.new_r = cnt-1; res.new_c = src_c;\n            for (int c=0;c<W;c++){\n                int to=0;\n                for (int r=0;r<H;r++){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[to++][c] = v;\n                }\n            }\n        } else if (dir == 1) { // B (down)\n            int cnt = 0;\n            for (int r=src_r; r<H; ++r) if (inputBoard[r][src_c]!=0) ++cnt;\n            res.new_r = H-1-(cnt-1); res.new_c = src_c;\n            for (int c=0;c<W;c++){\n                int to=H-1;\n                for (int r=H-1;r>=0;r--){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[to--][c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            int cnt = 0;\n            for (int c=0; c<=src_c; ++c) if (inputBoard[src_r][c]!=0) ++cnt;\n            res.new_r = src_r; res.new_c = cnt-1;\n            for (int r=0;r<H;r++){\n                int to=0;\n                for (int c=0;c<W;c++){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[r][to++] = v;\n                }\n            }\n        } else { // R\n            int cnt = 0;\n            for (int c=src_c; c<W; ++c) if (inputBoard[src_r][c]!=0) ++cnt;\n            res.new_r = src_r; res.new_c = W-1-(cnt-1);\n            for (int r=0;r<H;r++){\n                int to=W-1;\n                for (int c=W-1;c>=0;c--){\n                    int v = inputBoard[r][c];\n                    if (v) res.b[r][to--] = v;\n                }\n            }\n        }\n        return res;\n    }\n};\n\nstatic const int H = Simulator::H;\nstatic const int W = Simulator::W;\n\ninline int id(int r,int c){ return r*W + c; }\n\nstruct BoardStats {\n    long long sumSq;\n    long long sameAdj;\n    long long crossAdj;\n};\n\nBoardStats computeStats(const array<array<int,W>,H>& b) {\n    DSU dsu(H*W);\n    long long sameAdj = 0, crossAdj = 0;\n    for (int r=0;r<H;r++){\n        for (int c=0;c<W;c++){\n            int v = b[r][c];\n            if (!v) continue;\n            if (r+1<H) {\n                int u = b[r+1][c];\n                if (u) {\n                    if (u==v) { sameAdj++; dsu.unite(id(r,c), id(r+1,c)); }\n                    else crossAdj++;\n                }\n            }\n            if (c+1<W) {\n                int u = b[r][c+1];\n                if (u) {\n                    if (u==v) { sameAdj++; dsu.unite(id(r,c), id(r,c+1)); }\n                    else crossAdj++;\n                }\n            }\n        }\n    }\n    vector<int> cnt(H*W,0);\n    for (int r=0;r<H;r++) for (int c=0;c<W;c++) if (b[r][c]!=0) cnt[dsu.find(id(r,c))]++;\n    long long sumSq = 0;\n    for (int i=0;i<H*W;i++) if (cnt[i]>0) sumSq += 1LL*cnt[i]*cnt[i];\n    return {sumSq, sameAdj, crossAdj};\n}\n\nlong long totalMovementDistance(const array<array<int,W>,H>& b0, int dir) {\n    long long mv=0;\n    if (dir==0){ // F\n        for (int c=0;c<W;c++){\n            vector<int> rows; rows.reserve(H);\n            for (int r=0;r<H;r++) if (b0[r][c]!=0) rows.push_back(r);\n            for (int i=0;i<(int)rows.size();i++) mv += rows[i] - i;\n        }\n    } else if (dir==1){ // B\n        for (int c=0;c<W;c++){\n            vector<int> rows; rows.reserve(H);\n            for (int r=0;r<H;r++) if (b0[r][c]!=0) rows.push_back(r);\n            int k=(int)rows.size();\n            for (int i=0;i<k;i++){\n                int newr = H - k + i;\n                mv += newr - rows[i];\n            }\n        }\n    } else if (dir==2){ // L\n        for (int r=0;r<H;r++){\n            vector<int> cols; cols.reserve(W);\n            for (int c=0;c<W;c++) if (b0[r][c]!=0) cols.push_back(c);\n            for (int j=0;j<(int)cols.size();j++) mv += cols[j] - j;\n        }\n    } else { // R\n        for (int r=0;r<H;r++){\n            vector<int> cols; cols.reserve(W);\n            for (int c=0;c<W;c++) if (b0[r][c]!=0) cols.push_back(c);\n            int k=(int)cols.size();\n            for (int j=0;j<k;j++){\n                int newc = W - k + j;\n                mv += newc - cols[j];\n            }\n        }\n    }\n    return mv;\n}\n\nstatic inline vector<int> sampleIdx(int M, int K, std::mt19937& rng){\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    for (int i=0;i<K;i++){\n        uniform_int_distribution<int> dist(i, M-1);\n        int j = dist(rng);\n        swap(idx[i], idx[j]);\n    }\n    idx.resize(K);\n    return idx;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> f(100);\n    for (int i=0;i<100;i++){\n        if(!(cin>>f[i])) return 0;\n    }\n\n    Simulator sim;\n\n    array<pair<int,int>,4> corners = { pair<int,int>{0,0}, {0,9}, {9,0}, {9,9} };\n    int distToCorner[4][H][W];\n    for (int k=0;k<4;k++){\n        auto [tr,tc] = corners[k];\n        for (int r=0;r<H;r++) for (int c=0;c<W;c++) distToCorner[k][r][c] = abs(r-tr)+abs(c-tc);\n    }\n\n    vector<array<int,4>> mappings;\n    array<int,4> perm = {0,1,2,3};\n    sort(perm.begin(), perm.end());\n    do{\n        array<int,4> m = {0, perm[0], perm[1], perm[2]};\n        mappings.push_back(m);\n    }while(next_permutation(perm.begin(), perm.end()));\n\n    array<int,4> currentMap = {0,0,1,2};\n\n    static const int dr4[4] = {-1,1,0,0};\n    static const int dc4[4] = {0,0,-1,1};\n\n    std::mt19937 rng(123456789);\n    int prevDir = -1;\n\n    // Precompute remaining counts per step\n    int remAll[101][4]; // remAll[t][color]\n    memset(remAll, 0, sizeof(remAll));\n    int cntRem[4]={0,0,0,0};\n    for (int i=99;i>=0;i--){\n        cntRem[f[i]]++;\n        for (int c=1;c<=3;c++) remAll[i][c] = cntRem[c];\n    }\n\n    for (int t=0;t<100;t++){\n        int p; if(!(cin>>p)) return 0;\n        auto [r,c] = sim.emptyIndexToRC(p);\n        auto board0 = sim.board;\n        int color = f[t];\n        board0[r][c] = color;\n\n        double progress = (t<=99 ? (double)t/99.0 : 1.0);\n\n        // Immediate evaluation weights\n        double w_comp       = 10.0 + 22.0*progress;\n        double w_compDelta  = 2.0 + 6.0*progress;\n        double w_adjDelta   = 1.0 + 4.0*progress;\n        double w_sumDist    = 0.24 - 0.14*progress;\n\n        double w_crossAbs   = 0.18 + 0.36*progress;\n        double w_crossDelta = 0.08 + 0.26*progress;\n\n        double w_newAbs     = 0.55*(1.0-progress) + 0.08;\n        double w_newDelta   = 1.4*(1.0 - 0.28*progress);\n\n        double w_adjNewSame = 1.9 + 1.0*progress;\n        double w_adjNewDiff = 0.3;\n\n        double w_move       = 0.015 + 0.05*progress;\n        double noChangeBias = 0.5 + 3.5*progress;\n        double axisBonus    = (prevDir==-1?0.0:(0.3 + 0.8*progress));\n        double repeatBonus  = (prevDir==-1?0.0:(0.1 + 0.4*progress));\n\n        // Direction-to-corner alignment biases\n        double w_dirBias    = 0.06*(1.0 - 0.5*progress);\n        double w_newDirBias = 0.25*(1.0 - 0.5*progress);\n\n        // Mapping handling\n        double mapConsistencyBonus = 0.2;\n        double mapPenalty = 12.0 + 100.0*progress;     // for final mapping decision\n        double immSwitchPenalty = 3.0 + 25.0*progress; // small immediate penalty if best distance implies switching\n        int freezeT = 80;\n        double changeMargin = (80.0 + 200.0*progress);\n\n        // Next-candy lookahead\n        int nextColor = (t+1<100 ? f[t+1] : 0);\n        int emptiesNow = 100 - (t+1);\n        int sampleK = min(32, max(12, emptiesNow/4));\n        double look_cross_w = 4.0 + 2.0*progress;\n        double look_move_w = 0.02 + 0.04*progress;\n\n        // Future-candy-aware empty-space shaping (early only)\n        int rem1 = (t+1<=100 ? remAll[t+1][1] : 0);\n        int rem2 = (t+1<=100 ? remAll[t+1][2] : 0);\n        int rem3 = (t+1<=100 ? remAll[t+1][3] : 0);\n        double w_prepFuture = 0.06*(1.0 - progress);\n\n        BoardStats beforeStats = computeStats(board0);\n        long long sumSq0 = beforeStats.sumSq;\n        long long adjBefore = beforeStats.sameAdj;\n        long long crossBefore = beforeStats.crossAdj;\n\n        array<Simulator::SimResult,4> ress;\n        array<BoardStats,4> statsAfter;\n        array<long long,4> moveDist;\n        array<int,4> adjNewSame;\n        array<int,4> adjNewDiff;\n        array<char,4> isSameBoard;\n        long long S[4][4][4]; memset(S, 0, sizeof(S)); // dir, color, corner\n        long long E_empty[4][4]; memset(E_empty, 0, sizeof(E_empty));\n        int emptyCnt[4] = {0,0,0,0};\n\n        // Count colors on board0\n        int cntColor[4]={0,0,0,0};\n        for (int rr=0; rr<H; rr++) for (int cc=0; cc<W; cc++){\n            int v=board0[rr][cc]; if(v) cntColor[v]++;\n        }\n\n        for (int d=0; d<4; d++){\n            ress[d] = sim.simulateTilt(board0, d, r, c);\n            statsAfter[d] = computeStats(ress[d].b);\n            moveDist[d] = totalMovementDistance(board0, d);\n\n            bool equalBoard = true;\n            for (int rr=0; rr<H && equalBoard; rr++){\n                for (int cc=0; cc<W; cc++){\n                    if (board0[rr][cc] != ress[d].b[rr][cc]) { equalBoard=false; break; }\n                }\n            }\n            isSameBoard[d] = equalBoard;\n\n            int nr = ress[d].new_r, nc = ress[d].new_c;\n            int same=0, diff=0;\n            for (int k=0;k<4;k++){\n                int rr = nr + dr4[k], cc = nc + dc4[k];\n                if (0<=rr && rr<H && 0<=cc && cc<W){\n                    int v = ress[d].b[rr][cc];\n                    if (!v) continue;\n                    if (v == color) same++;\n                    else diff++;\n                }\n            }\n            adjNewSame[d] = same;\n            adjNewDiff[d] = diff;\n\n            for (int rr=0; rr<H; rr++){\n                for (int cc=0; cc<W; cc++){\n                    int v = ress[d].b[rr][cc];\n                    if (v == 0) {\n                        for (int k=0;k<4;k++){\n                            E_empty[d][k] += distToCorner[k][rr][cc];\n                        }\n                        emptyCnt[d]++;\n                    } else {\n                        for (int k=0;k<4;k++){\n                            S[d][v][k] += distToCorner[k][rr][cc];\n                        }\n                    }\n                }\n            }\n        }\n\n        int cornerIdxCur = currentMap[color];\n        int newDistBeforeCur = distToCorner[cornerIdxCur][r][c];\n\n        auto cornerMatchesDir = [&](int cornerIdx, int dir)->bool{\n            if (dir==0) return (cornerIdx==0 || cornerIdx==1);\n            if (dir==1) return (cornerIdx==2 || cornerIdx==3);\n            if (dir==2) return (cornerIdx==0 || cornerIdx==2);\n            return (cornerIdx==1 || cornerIdx==3);\n        };\n\n        array<double,4> immScore{};\n        double bestImmScore = -1e100;\n        int bestImmDir = 0;\n        for (int d=0; d<4; d++){\n            long long sumDistStay = S[d][1][ currentMap[1] ] + S[d][2][ currentMap[2] ] + S[d][3][ currentMap[3] ];\n            long long bestSumDist = sumDistStay;\n            bool usesAlt = false;\n            for (const auto& cmap : mappings) {\n                if (cmap == currentMap) continue;\n                long long sd = S[d][1][cmap[1]] + S[d][2][cmap[2]] + S[d][3][cmap[3]];\n                if (sd < bestSumDist) {\n                    bestSumDist = sd;\n                    usesAlt = true;\n                }\n            }\n\n            int newDistAfterCur = distToCorner[currentMap[color]][ress[d].new_r][ress[d].new_c];\n\n            double score = 0.0;\n            score += w_comp * (double)statsAfter[d].sumSq;\n            score += w_compDelta * (double)(statsAfter[d].sumSq - sumSq0);\n            score += w_adjDelta * (double)(statsAfter[d].sameAdj - adjBefore);\n            score -= w_crossAbs * (double)statsAfter[d].crossAdj;\n            score -= w_crossDelta * (double)(statsAfter[d].crossAdj - crossBefore);\n            score -= w_sumDist * (double)bestSumDist;\n            if (usesAlt) score -= immSwitchPenalty;\n\n            score -= w_newAbs * (double)newDistAfterCur;\n            score += w_newDelta * (double)(newDistBeforeCur - newDistAfterCur);\n            score += w_adjNewSame * (double)adjNewSame[d];\n            score -= w_adjNewDiff * (double)adjNewDiff[d];\n\n            if (emptyCnt[d] > 0) {\n                double avg1 = (double)E_empty[d][ currentMap[1] ] / (double)emptyCnt[d];\n                double avg2 = (double)E_empty[d][ currentMap[2] ] / (double)emptyCnt[d];\n                double avg3 = (double)E_empty[d][ currentMap[3] ] / (double)emptyCnt[d];\n                double prepRem = rem1*avg1 + rem2*avg2 + rem3*avg3;\n                score -= w_prepFuture * prepRem;\n            }\n\n            score -= w_move * (double)moveDist[d];\n\n            if (isSameBoard[d]) score += noChangeBias;\n            if (prevDir != -1) {\n                bool sameAxis = ((prevDir<2 && d<2) || (prevDir>=2 && d>=2));\n                if (sameAxis) score += axisBonus;\n                if (prevDir == d) score += repeatBonus;\n            }\n\n            int benefCnt = 0;\n            for (int col=1; col<=3; col++) if (cornerMatchesDir(currentMap[col], d)) benefCnt += cntColor[col];\n            if (benefCnt > 0) score += w_dirBias * benefCnt;\n            if (cornerMatchesDir(currentMap[color], d)) score += w_newDirBias;\n\n            score += mapConsistencyBonus;\n\n            immScore[d] = score;\n            if (score > bestImmScore) {\n                bestImmScore = score;\n                bestImmDir = d;\n            }\n        }\n\n        // 1-step lookahead (mapping-independent)\n        array<double,4> exp2{};\n        if (nextColor && emptiesNow > 0) {\n            for (int d0=0; d0<4; d0++){\n                const auto& B1 = ress[d0].b;\n                vector<pair<int,int>> empties;\n                empties.reserve(H*W);\n                for (int rr=0; rr<H; rr++) for (int cc=0; cc<W; cc++) if (B1[rr][cc]==0) empties.emplace_back(rr,cc);\n                int M = (int)empties.size();\n                if (M == 0) { exp2[d0] = (double)statsAfter[d0].sumSq; continue; }\n                int K = min(M, sampleK);\n                auto idx = sampleIdx(M, K, rng);\n                double accum = 0.0;\n                for (int s=0; s<K; s++){\n                    int rr = empties[idx[s]].first;\n                    int cc = empties[idx[s]].second;\n                    auto board1plus = B1;\n                    board1plus[rr][cc] = nextColor;\n                    double best2 = -1e100;\n                    for (int d1=0; d1<4; d1++){\n                        auto res2 = sim.simulateTilt(board1plus, d1, rr, cc);\n                        BoardStats st2 = computeStats(res2.b);\n                        double mv2 = totalMovementDistance(board1plus, d1);\n                        double val = (double)st2.sumSq\n                                     - look_cross_w * (double)st2.crossAdj\n                                     - look_move_w * mv2;\n                        if (val > best2) best2 = val;\n                    }\n                    accum += best2;\n                }\n                exp2[d0] = accum / (double)K;\n            }\n        } else {\n            for (int d0=0; d0<4; d0++) exp2[d0] = (double)statsAfter[d0].sumSq;\n        }\n\n        // optional 2-step lookahead refinement for early game on top 2 dirs\n        int nextNextColor = (t+2<100 ? f[t+2] : 0);\n        if (t < 30 && nextColor && nextNextColor) {\n            // pick top 2 by exp2\n            array<int,4> ord = {0,1,2,3};\n            sort(ord.begin(), ord.end(), [&](int a,int b){ return exp2[a] > exp2[b]; });\n            int numRefine = 2;\n            int K1 = 10; // first placement samples\n            int K2 = 6;  // next-next placement samples\n            double blend = 0.5; // blend immediate second-step and third-step estimates\n            for (int idxDir=0; idxDir<numRefine; idxDir++){\n                int d0 = ord[idxDir];\n                const auto& B1 = ress[d0].b;\n                vector<pair<int,int>> empties1;\n                empties1.reserve(H*W);\n                for (int rr=0; rr<H; rr++) for (int cc=0; cc<W; cc++) if (B1[rr][cc]==0) empties1.emplace_back(rr,cc);\n                int M1 = (int)empties1.size();\n                if (M1 == 0) continue;\n                int KK1 = min(M1, K1);\n                auto idx1 = sampleIdx(M1, KK1, rng);\n                double accum1 = 0.0;\n                for (int s1=0; s1<KK1; s1++){\n                    int r1 = empties1[idx1[s1]].first;\n                    int c1 = empties1[idx1[s1]].second;\n                    auto board1plus = B1;\n                    board1plus[r1][c1] = nextColor;\n                    double best2Val = -1e100;\n                    for (int d1=0; d1<4; d1++){\n                        auto res2 = sim.simulateTilt(board1plus, d1, r1, c1);\n                        BoardStats st2 = computeStats(res2.b);\n                        double mv2 = totalMovementDistance(board1plus, d1);\n                        double val2 = (double)st2.sumSq\n                                      - look_cross_w * (double)st2.crossAdj\n                                      - look_move_w * mv2;\n                        // third step\n                        vector<pair<int,int>> empties2;\n                        for (int rr=0; rr<H; rr++) for (int cc=0; cc<W; cc++) if (res2.b[rr][cc]==0) empties2.emplace_back(rr,cc);\n                        double avgBest3 = val2;\n                        if (!empties2.empty()){\n                            int M2 = (int)empties2.size();\n                            int KK2 = min(M2, K2);\n                            auto idx2 = sampleIdx(M2, KK2, rng);\n                            double acc3 = 0.0;\n                            for (int s2=0; s2<KK2; s2++){\n                                int r2 = empties2[idx2[s2]].first;\n                                int c2 = empties2[idx2[s2]].second;\n                                auto board2plus = res2.b;\n                                board2plus[r2][c2] = nextNextColor;\n                                double best3 = -1e100;\n                                for (int d2=0; d2<4; d2++){\n                                    auto res3 = sim.simulateTilt(board2plus, d2, r2, c2);\n                                    BoardStats st3 = computeStats(res3.b);\n                                    double mv3 = totalMovementDistance(board2plus, d2);\n                                    double v3 = (double)st3.sumSq\n                                                - look_cross_w * (double)st3.crossAdj\n                                                - look_move_w * mv3;\n                                    if (v3 > best3) best3 = v3;\n                                }\n                                acc3 += best3;\n                            }\n                            avgBest3 = acc3 / (double)KK2;\n                        }\n                        double blended = (1.0 - blend) * val2 + blend * avgBest3;\n                        if (blended > best2Val) best2Val = blended;\n                    }\n                    accum1 += best2Val;\n                }\n                double exp3 = accum1 / (double)KK1;\n                // refine exp2 for this direction\n                exp2[d0] = 0.5*exp2[d0] + 0.5*exp3;\n            }\n        }\n\n        int lhDir = 0;\n        double bestExp2 = -1e100;\n        for (int d=0; d<4; d++){\n            if (exp2[d] > bestExp2) { bestExp2 = exp2[d]; lhDir = d; }\n        }\n\n        double tol = 0.025 * fabs(bestImmScore) + 40.0;\n        int chosenDir = lhDir;\n        if (immScore[lhDir] + tol < bestImmScore) {\n            chosenDir = bestImmDir;\n        }\n\n        // Mapping decision for chosenDir\n        long long Sfinal[4][4]; memset(Sfinal, 0, sizeof(Sfinal));\n        const auto& Bfinal = ress[chosenDir].b;\n        for (int rr=0; rr<H; rr++){\n            for (int cc=0; cc<W; cc++){\n                int v = Bfinal[rr][cc];\n                if (v == 0) continue;\n                for (int k=0;k<4;k++){\n                    Sfinal[v][k] += distToCorner[k][rr][cc];\n                }\n            }\n        }\n\n        auto mappingScore = [&](const array<int,4>& cmap, bool isCurrent)->double{\n            long long sumDist = Sfinal[1][cmap[1]] + Sfinal[2][cmap[2]] + Sfinal[3][cmap[3]];\n            int newDistAfter = distToCorner[cmap[color]][ress[chosenDir].new_r][ress[chosenDir].new_c];\n            int newDistBefore = distToCorner[cmap[color]][r][c];\n            double sc = 0.0;\n            sc += w_comp * (double)statsAfter[chosenDir].sumSq;\n            sc += w_compDelta * (double)(statsAfter[chosenDir].sumSq - sumSq0);\n            sc += w_adjDelta * (double)(statsAfter[chosenDir].sameAdj - adjBefore);\n            sc -= w_crossAbs * (double)statsAfter[chosenDir].crossAdj;\n            sc -= w_crossDelta * (double)(statsAfter[chosenDir].crossAdj - crossBefore);\n            sc -= w_sumDist * (double)sumDist;\n\n            sc -= w_newAbs * (double)newDistAfter;\n            sc += w_newDelta * (double)(newDistBefore - newDistAfter);\n            sc += w_adjNewSame * (double)adjNewSame[chosenDir];\n            sc -= w_adjNewDiff * (double)adjNewDiff[chosenDir];\n\n            sc -= w_move * (double)moveDist[chosenDir];\n            if (isCurrent) sc += mapConsistencyBonus;\n            return sc;\n        };\n\n        double scoreCurrentMap = mappingScore(currentMap, true);\n        double bestMapScore = scoreCurrentMap;\n        array<int,4> bestMap = currentMap;\n        for (const auto& cmap : mappings) {\n            if (cmap == currentMap) continue;\n            double sc = mappingScore(cmap, false) - mapPenalty;\n            if (sc > bestMapScore) {\n                bestMapScore = sc;\n                bestMap = cmap;\n            }\n        }\n        if (t >= freezeT && bestMap != currentMap) {\n            if (bestMapScore < scoreCurrentMap + changeMargin) {\n                bestMap = currentMap;\n                bestMapScore = scoreCurrentMap;\n            }\n        }\n\n        if (t < 99) {\n            static const char dirs[4] = {'F','B','L','R'};\n            cout << dirs[chosenDir] << '\\n' << flush;\n        }\n\n        sim.board = ress[chosenDir].b;\n        currentMap = bestMap;\n        prevDir = chosenDir;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Utility\nstatic inline int ceil_log2_int(int x) {\n    int l = 0; int v = 1;\n    while (v < x) { v <<= 1; l++; }\n    return l;\n}\n\n// Build an R x A binary matrix alpha with column sums t[a]\nstatic vector<vector<int>> build_alpha(int R, int A, const vector<int>& t, mt19937_64 &rng) {\n    vector<vector<int>> alpha(max(R,1), vector<int>(A, 0));\n    vector<int> rowSum(max(R,1), 0);\n    // Greedy fill balancing row sums\n    for (int a = 0; a < A; ++a) {\n        int need = t[a];\n        vector<int> idx(R);\n        iota(idx.begin(), idx.end(), 0);\n        stable_sort(idx.begin(), idx.end(), [&](int r1, int r2){\n            if (rowSum[r1] != rowSum[r2]) return rowSum[r1] < rowSum[r2];\n            return r1 < r2;\n        });\n        for (int k = 0; k < need && k < R; ++k) {\n            int r = idx[k];\n            alpha[r][a] = 1;\n            rowSum[r]++;\n        }\n    }\n    // Small local improvement\n    auto min_pairwise_dist = [&]() {\n        if (R <= 1) return A;\n        int mind = INT_MAX;\n        for (int i = 0; i < R; ++i) for (int j = i+1; j < R; ++j) {\n            int d = 0; for (int a = 0; a < A; ++a) if (alpha[i][a] != alpha[j][a]) d++;\n            mind = min(mind, d);\n        }\n        if (mind == INT_MAX) mind = 0;\n        return mind;\n    };\n    int currentMinD = min_pairwise_dist();\n    auto penalty = [&](const vector<int>& rs) {\n        int p = 0; int target = A/2;\n        for (int r = 0; r < max(R,1); ++r) {\n            int d = abs(rs[r] - target);\n            p += d*d;\n        }\n        return p;\n    };\n    int oldPen = penalty(rowSum);\n    uniform_int_distribution<int> distA(0, max(0, A-1)), distR(0, max(0, R-1));\n    for (int iter = 0; iter < 2000; ++iter) {\n        if (A <= 0 || R <= 1) break;\n        int a = distA(rng);\n        int r1 = distR(rng), r2 = distR(rng);\n        if (r1 == r2) continue;\n        if (alpha[r1][a] == alpha[r2][a]) continue;\n        alpha[r1][a] ^= 1; alpha[r2][a] ^= 1;\n        int newMinD = min_pairwise_dist();\n        vector<int> rowSumNew = rowSum;\n        rowSumNew[r1] += (alpha[r1][a] ? 1 : -1);\n        rowSumNew[r2] += (alpha[r2][a] ? 1 : -1);\n        int newPen = penalty(rowSumNew);\n        bool accept = false;\n        if (newMinD > currentMinD) accept = true;\n        else if (newMinD == currentMinD && newPen <= oldPen) accept = true;\n        if (accept) { currentMinD = newMinD; rowSum = rowSumNew; oldPen = newPen; }\n        else { alpha[r1][a] ^= 1; alpha[r2][a] ^= 1; }\n    }\n    if (R == 0) alpha.clear();\n    return alpha;\n}\n\n// Generate M distinct codewords of length R with large pairwise Hamming distances.\nstatic vector<unsigned int> generate_codewords(int M, int R, mt19937_64 &rng) {\n    vector<unsigned int> codes;\n    if (R <= 0) { codes.assign(M, 0u); return codes; }\n    int total = 1 << R;\n    vector<unsigned int> cand; cand.reserve(total);\n    int band = max(0, R/4);\n    while (true) {\n        cand.clear();\n        for (int x = 0; x < total; ++x) {\n            int w = __builtin_popcount((unsigned)x);\n            if (abs(w - R/2) <= band) cand.push_back((unsigned)x);\n        }\n        if ((int)cand.size() >= M || band >= R) break;\n        band++;\n    }\n    if ((int)cand.size() < M) {\n        cand.clear(); cand.reserve(total);\n        for (int x = 0; x < total; ++x) cand.push_back((unsigned)x);\n    }\n    shuffle(cand.begin(), cand.end(), rng);\n    vector<unsigned int> picked; picked.reserve(M);\n    picked.push_back(cand[0]);\n    vector<int> mindist(cand.size(), R+1);\n    for (size_t i = 0; i < cand.size(); ++i) mindist[i] = __builtin_popcount((unsigned)(cand[i] ^ picked[0]));\n    while ((int)picked.size() < M) {\n        int bestIdx = -1, bestScore = -1;\n        for (size_t i = 0; i < cand.size(); ++i) {\n            int d = mindist[i];\n            if (d > bestScore) { bestScore = d; bestIdx = (int)i; }\n        }\n        if (bestIdx == -1) break;\n        unsigned int chosen = cand[bestIdx];\n        picked.push_back(chosen);\n        for (size_t i = 0; i < cand.size(); ++i) {\n            int d = __builtin_popcount((unsigned)(cand[i] ^ chosen));\n            if (d < mindist[i]) mindist[i] = d;\n        }\n        mindist[bestIdx] = -1;\n    }\n    while ((int)picked.size() < M) picked.push_back(cand[picked.size() % cand.size()]);\n    return picked;\n}\n\n// Hungarian algorithm (minimization)\nstatic pair<long long, vector<int>> hungarian(const vector<vector<long long>>& a) {\n    int n = (int)a.size(), m = (int)a[0].size();\n    int N = max(n, m);\n    vector<vector<long long>> c(N, vector<long long>(N, 0));\n    for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) c[i][j] = a[i][j];\n    const long long INF = (1LL<<60);\n    vector<long long> u(N+1), v(N+1), minv(N+1);\n    vector<int> p(N+1), way(N+1);\n    for (int i = 1; i <= N; ++i) {\n        p[0] = i; int j0 = 0; vector<char> used(N+1, false);\n        fill(minv.begin(), minv.end(), INF);\n        do {\n            used[j0] = true; int i0 = p[j0], j1 = 0; long long delta = INF;\n            for (int j = 1; j <= N; ++j) if (!used[j]) {\n                long long cur = c[i0-1][j-1] - u[i0] - v[j];\n                if (cur < minv[j]) { minv[j] = cur; way[j] = j0; }\n                if (minv[j] < delta) { delta = minv[j]; j1 = j; }\n            }\n            for (int j = 0; j <= N; ++j) {\n                if (used[j]) { u[p[j]] += delta; v[j] -= delta; }\n                else minv[j] -= delta;\n            }\n            j0 = j1;\n        } while (p[j0] != 0);\n        do { int j1 = way[j0]; p[j0] = p[j1]; j0 = j1; } while (j0);\n    }\n    vector<int> assign(n, -1);\n    for (int j = 1; j <= N; ++j) if (p[j] <= n && j <= m) assign[p[j]-1] = j - 1;\n    long long val = -v[0];\n    return {val, assign};\n}\n\n// Min-Cost Flow\nstruct MinCostFlow {\n    struct Edge { int to, rev, cap; int cost; };\n    int N;\n    vector<vector<Edge>> G;\n    void init(int n){ N=n; G.assign(n, {}); }\n    void addEdge(int s, int t, int cap, int cost){\n        Edge a{t, (int)G[t].size(), cap, cost};\n        Edge b{s, (int)G[s].size(), 0, -cost};\n        G[s].push_back(a); G[t].push_back(b);\n    }\n    pair<int,long long> minCostMaxFlow(int s, int t, int maxf){\n        const long long INF = (1LL<<60);\n        vector<long long> dist(N), pot(N);\n        vector<int> pv(N), pe(N);\n        int flow = 0; long long cost = 0;\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INF);\n            dist[s] = 0;\n            using P = pair<long long,int>;\n            priority_queue<P, vector<P>, greater<P>> pq;\n            pq.emplace(0, s);\n            while (!pq.empty()) {\n                auto [d,u]=pq.top(); pq.pop();\n                if (d != dist[u]) continue;\n                for (int i = 0; i < (int)G[u].size(); ++i) {\n                    const Edge &e = G[u][i];\n                    if (e.cap <= 0) continue;\n                    long long nd = d + e.cost + pot[u] - pot[e.to];\n                    if (nd < dist[e.to]) { dist[e.to] = nd; pv[e.to] = u; pe[e.to] = i; pq.emplace(nd, e.to); }\n                }\n            }\n            if (dist[t] == INF) break;\n            for (int i = 0; i < N; ++i) if (dist[i] < INF) pot[i] += dist[i];\n            int addf = maxf - flow;\n            for (int v = t; v != s; v = pv[v]) addf = min(addf, G[pv[v]][pe[v]].cap);\n            for (int v = t; v != s; v = pv[v]) { Edge &e = G[pv[v]][pe[v]]; e.cap -= addf; G[v][e.rev].cap += addf; }\n            flow += addf; cost += (long long)addf * pot[t];\n        }\n        return {flow, cost};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M; double eps;\n    if (!(cin >> M >> eps)) return 0;\n    mt19937_64 rng(123456789);\n\n    int Lbits = max(1, ceil_log2_int(M));\n    int extra;\n    if (eps <= 0.12) extra = 0;\n    else if (eps <= 0.22) extra = 1;\n    else if (eps <= 0.30) extra = 2;\n    else extra = 3;\n    int R = Lbits + extra;\n    if ((1 << R) < M) R = Lbits;\n\n    int g;\n    if (eps <= 0.01) g = 5;\n    else if (eps <= 0.03) g = 6;\n    else if (eps <= 0.06) g = 7;\n    else if (eps <= 0.12) g = 8;\n    else if (eps <= 0.20) g = 9;\n    else g = 10;\n\n    int A = R + 1;\n    vector<int> t(A);\n    for (int a = 0; a < A; ++a) t[a] = a;\n    auto alpha = build_alpha(R, A, t, rng);\n\n    vector<int> rowSum(max(R,1), 0);\n    for (int r = 0; r < R; ++r) for (int a = 0; a < A; ++a) rowSum[r] += alpha[r][a];\n    int rowSumMax = 0;\n    for (int r = 0; r < R; ++r) rowSumMax = max(rowSumMax, rowSum[r]);\n\n    int margin;\n    if (eps <= 0.04) margin = 1;\n    else if (eps <= 0.10) margin = 2;\n    else if (eps <= 0.20) margin = 3;\n    else if (eps <= 0.30) margin = 4;\n    else margin = 5;\n\n    auto rebuild_alpha = [&](int R_new, int A_new){\n        R = R_new; A = A_new; t.resize(A);\n        if (A <= 1) { for (int a = 0; a < A; ++a) t[a] = 0; }\n        else { for (int a = 0; a < A; ++a) { t[a] = (int)llround((double)a * (double)R / (double)(A-1)); t[a] = max(0, min(R, t[a])); } }\n        alpha = build_alpha(R, A, t, rng);\n        rowSum.assign(max(R,1), 0); for (int r = 0; r < R; ++r) for (int a = 0; a < A; ++a) rowSum[r] += alpha[r][a];\n        rowSumMax = 0; for (int r = 0; r < R; ++r) rowSumMax = max(rowSumMax, rowSum[r]);\n    };\n\n    int U = 0;\n    while (true) {\n        int N0 = A + R * g;\n        if (N0 > 100) {\n            if (g > 4) { g--; continue; }\n            if (R > Lbits) { rebuild_alpha(R-1, R-1+1); continue; }\n            break;\n        }\n        int clusterMaxDeg = (R > 0 ? rowSumMax : 0) + (g - 1);\n        int Utarget = max(0, clusterMaxDeg + margin - (A - 1));\n        if (N0 + Utarget <= 100) { U = Utarget; break; }\n        else {\n            if (g > 4) { g--; continue; }\n            if (R > Lbits) { rebuild_alpha(R-1, R-1+1); continue; }\n            U = max(0, 100 - N0);\n            break;\n        }\n    }\n\n    int N = A + U + R * g;\n    int T = N * (N - 1) / 2;\n\n    vector<int> offset(N+1, 0);\n    for (int i = 1; i <= N; ++i) offset[i] = offset[i-1] + (N - i);\n    auto idx = [&](int i, int j) -> int {\n        if (i > j) swap(i, j);\n        return offset[i] + (j - i - 1);\n    };\n\n    auto cluster_start = [&](int r) { return A + U + r * g; };\n    auto cluster_end   = [&](int r) { return A + U + (r + 1) * g - 1; };\n\n    string base(T, '0');\n    for (int i = 0; i < A; ++i) for (int j = i + 1; j < A; ++j) base[idx(i, j)] = '1';\n    for (int a = 0; a < A; ++a) for (int p = A; p < A + U; ++p) base[idx(a, p)] = '1';\n    for (int r = 0; r < R; ++r) {\n        int s = cluster_start(r), e = cluster_end(r);\n        for (int a = 0; a < A; ++a) if (alpha[r][a]) for (int v = s; v <= e; ++v) base[idx(a, v)] = '1';\n    }\n    vector<vector<int>> clusterEdgePos(R);\n    for (int r = 0; r < R; ++r) {\n        int s = cluster_start(r), e = cluster_end(r);\n        for (int u = s; u <= e; ++u) for (int v = u + 1; v <= e; ++v) clusterEdgePos[r].push_back(idx(u, v));\n    }\n\n    auto codewords = generate_codewords(M, R, rng);\n\n    cout << N << \"\\n\";\n    cout.flush();\n    for (int k = 0; k < M; ++k) {\n        string out = base;\n        unsigned int cw = (R > 0 ? codewords[k] : 0u);\n        for (int r = 0; r < R; ++r) {\n            int bit = (cw >> r) & 1u;\n            if (bit) { for (int pos : clusterEdgePos[r]) out[pos] = '1'; }\n            else { for (int pos : clusterEdgePos[r]) out[pos] = '0'; }\n        }\n        cout << out << \"\\n\";\n    }\n    cout.flush();\n\n    double log_p1 = log(max(1e-12, 1.0 - eps));\n    double log_q1 = log(max(1e-12, eps));\n    double log_p0 = log(max(1e-12, eps));\n    double log_q0 = log(max(1e-12, 1.0 - eps));\n\n    auto build_adj = [&](const string& H, vector<vector<char>>& adj, vector<int>& deg){\n        int pos2 = 0;\n        int n = (int)deg.size();\n        for (int i = 0; i < n; ++i) { deg[i] = 0; for (int j = 0; j < n; ++j) adj[i][j] = 0; }\n        for (int i = 0; i < n; ++i) for (int j = i+1; j < n; ++j) {\n            char c = H[pos2++]; if (c == '1') { adj[i][j] = adj[j][i] = 1; deg[i]++; deg[j]++; }\n        }\n    };\n\n    struct AssignRes { vector<vector<int>> clusterVerts; vector<double> rowWeight; vector<int> x; vector<int> pairCount; };\n\n    auto compute_row_stats = [&](const vector<vector<char>>& adj, const vector<int>& anchors_ordered, const vector<vector<int>>& clusterVerts) -> AssignRes {\n        vector<double> rowWeight(R, 1.0);\n        vector<int> x(R, 0), pairCount(R, 0);\n        vector<int> isAnchorIndex(N, -1);\n        for (int a = 0; a < A; ++a) isAnchorIndex[anchors_ordered[a]] = a;\n        vector<int> nonAnchors; for (int v = 0; v < N; ++v) if (isAnchorIndex[v] < 0) nonAnchors.push_back(v);\n        vector<vector<int>> distToRow(N, vector<int>(max(R,1), 0));\n        for (int v : nonAnchors) for (int r = 0; r < R; ++r) {\n            int d = 0; for (int a = 0; a < A; ++a) { int av = anchors_ordered[a]; int bit = alpha[r][a]; if ((int)adj[v][av] != bit) d++; }\n            distToRow[v][r] = d;\n        }\n        for (int r = 0; r < R; ++r) {\n            auto &vec = clusterVerts[r];\n            int gi = (int)vec.size();\n            pairCount[r] = gi * (gi - 1) / 2;\n            double sumMatch = 0.0, sumMargin = 0.0;\n            for (int v : vec) {\n                int d_best = 0; for (int a = 0; a < A; ++a) { int av = anchors_ordered[a]; int bit = alpha[r][a]; if ((int)adj[v][av] != bit) d_best++; }\n                int d2 = INT_MAX; for (int rr = 0; rr < R; ++rr) if (rr != r) d2 = min(d2, distToRow[v][rr]);\n                double match = (double)(A - d_best) / (double)A;\n                double margin = max(0, d2 - d_best);\n                sumMatch += match; sumMargin += margin;\n            }\n            double avgMatch = (gi > 0 ? sumMatch / gi : 1.0);\n            double avgMargin = (gi > 0 ? sumMargin / gi : 0.0);\n            double w = 0.5 + avgMatch; w += 0.05 * min(2.0, avgMargin);\n            if (w < 0.5) w = 0.5; if (w > 1.6) w = 1.6; rowWeight[r] = w;\n\n            int cnt = 0; for (int i = 0; i < gi; ++i) for (int j = i + 1; j < gi; ++j) if (adj[vec[i]][vec[j]]) cnt++; x[r] = cnt;\n        }\n        return AssignRes{clusterVerts, rowWeight, x, pairCount};\n    };\n\n    auto decode_from_assign = [&](const AssignRes& ar) -> pair<int,double> {\n        int bestS_unw = 0; double bestLL_unw = -1e300;\n        for (int s = 0; s < M; ++s) {\n            unsigned int cw = (R > 0 ? codewords[s] : 0u); double ll = 0.0;\n            for (int r = 0; r < R; ++r) { int bit = (cw >> r) & 1u; int xi = ar.x[r], ni = ar.pairCount[r];\n                if (bit) ll += xi * log_p1 + (ni - xi) * log_q1; else ll += xi * log_p0 + (ni - xi) * log_q0;\n            }\n            if (ll > bestLL_unw) { bestLL_unw = ll; bestS_unw = s; }\n        }\n        int bestS_w = 0; double bestLL_w = -1e300;\n        for (int s = 0; s < M; ++s) {\n            unsigned int cw = (R > 0 ? codewords[s] : 0u); double ll = 0.0;\n            for (int r = 0; r < R; ++r) { int bit = (cw >> r) & 1u; int xi = ar.x[r], ni = ar.pairCount[r]; double w = ar.rowWeight[r];\n                if (bit) ll += w * (xi * log_p1 + (ni - xi) * log_q1); else ll += w * (xi * log_p0 + (ni - xi) * log_q0);\n            }\n            if (ll > bestLL_w) { bestLL_w = ll; bestS_w = s; }\n        }\n        auto eval_unw = [&](int s)->double{\n            unsigned int cw = (R > 0 ? codewords[s] : 0u); double ll = 0.0;\n            for (int r = 0; r < R; ++r) { int bit = (cw >> r) & 1u; int xi = ar.x[r], ni = ar.pairCount[r];\n                if (bit) ll += xi * log_p1 + (ni - xi) * log_q1; else ll += xi * log_p0 + (ni - xi) * log_q0;\n            } return ll;\n        };\n        double ll_unw_for_unw = bestLL_unw, ll_unw_for_w = eval_unw(bestS_w);\n        if (ll_unw_for_w > ll_unw_for_unw) return {bestS_w, ll_unw_for_w};\n        else return {bestS_unw, ll_unw_for_unw};\n    };\n\n    auto assign_greedy_allowed = [&](const vector<vector<char>>& adj, const vector<int>& anchors_ordered, const vector<char>& allowed){\n        vector<int> isAnchorIndex(N, -1); for (int a = 0; a < A; ++a) isAnchorIndex[anchors_ordered[a]] = a;\n        vector<int> allowedVerts, allNonAnchors;\n        for (int v = 0; v < N; ++v) if (isAnchorIndex[v] < 0) { allNonAnchors.push_back(v); if (allowed[v]) allowedVerts.push_back(v); }\n        bool sufficient = ((int)allowedVerts.size() >= R * g);\n        const vector<int>& pool = sufficient ? allowedVerts : allNonAnchors;\n        vector<vector<int>> distToRow(N, vector<int>(max(R,1), 0));\n        vector<int> bestRow(N, -1), bestD(N, 0), secondD(N, 0);\n        for (int v : pool) {\n            int d1 = INT_MAX, d2 = INT_MAX, r1 = -1;\n            for (int r = 0; r < R; ++r) {\n                int d = 0; for (int a = 0; a < A; ++a) { int av = anchors_ordered[a]; int bit = alpha[r][a]; if ((int)adj[v][av] != bit) d++; }\n                distToRow[v][r] = d; if (d < d1) { d2 = d1; d1 = d; r1 = r; } else if (d < d2) d2 = d;\n            }\n            bestRow[v] = r1; bestD[v] = d1; secondD[v] = d2;\n        }\n        vector<vector<pair<int,int>>> primary(R); vector<vector<tuple<int,int,int>>> secondary(R);\n        for (int r = 0; r < R; ++r) { primary[r].reserve(pool.size()); secondary[r].reserve(pool.size()); }\n        for (int v : pool) { int r1 = bestRow[v]; primary[r1].push_back({bestD[v], v}); }\n        for (int v : pool) {\n            int r1 = bestRow[v];\n            for (int r = 0; r < R; ++r) if (r != r1) { int gap = distToRow[v][r] - bestD[v]; secondary[r].emplace_back(gap, distToRow[v][r], v); }\n        }\n        for (int r = 0; r < R; ++r) { sort(primary[r].begin(), primary[r].end()); sort(secondary[r].begin(), secondary[r].end()); }\n\n        vector<vector<int>> clusterVerts(R); vector<char> used(N, 0);\n        for (int r = 0; r < R; ++r) for (auto &pr : primary[r]) {\n            if ((int)clusterVerts[r].size() >= g) break; int v = pr.second; if (!used[v]) { clusterVerts[r].push_back(v); used[v] = 1; }\n        }\n        for (int r = 0; r < R; ++r) if ((int)clusterVerts[r].size() < g) for (auto &tp : secondary[r]) {\n            if ((int)clusterVerts[r].size() >= g) break; int v = get<2>(tp); if (!used[v]) { clusterVerts[r].push_back(v); used[v] = 1; }\n        }\n        if (sufficient) for (int r = 0; r < R; ++r) if ((int)clusterVerts[r].size() < g) {\n            for (int v : allNonAnchors) if (!used[v]) { clusterVerts[r].push_back(v); used[v] = 1; if ((int)clusterVerts[r].size() >= g) break; }\n        }\n        for (int r = 0; r < R; ++r) if ((int)clusterVerts[r].size() > g) clusterVerts[r].resize(g);\n\n        // refinement swaps\n        for (int r1 = 0; r1 < R; ++r1) for (int r2 = r1+1; r2 < R; ++r2) {\n            for (int i1 = 0; i1 < (int)clusterVerts[r1].size(); ++i1) {\n                int v1 = clusterVerts[r1][i1];\n                int d11 = 0, d12 = 0;\n                for (int a = 0; a < A; ++a) { int av = anchors_ordered[a]; int b1 = alpha[r1][a], b2 = alpha[r2][a]; d11 += ((int)adj[v1][av] != b1); d12 += ((int)adj[v1][av] != b2); }\n                for (int i2 = 0; i2 < (int)clusterVerts[r2].size(); ++i2) {\n                    int v2 = clusterVerts[r2][i2];\n                    int d22 = 0, d21 = 0;\n                    for (int a = 0; a < A; ++a) { int av = anchors_ordered[a]; int b1 = alpha[r1][a], b2 = alpha[r2][a]; d22 += ((int)adj[v2][av] != b2); d21 += ((int)adj[v2][av] != b1); }\n                    int delta = (d11 + d22) - (d12 + d21);\n                    if (delta > 0) { swap(clusterVerts[r1][i1], clusterVerts[r2][i2]); d11 = d12; }\n                }\n            }\n        }\n        return compute_row_stats(adj, anchors_ordered, clusterVerts);\n    };\n\n    auto assign_mcf_allowed = [&](const vector<vector<char>>& adj, const vector<int>& anchors_ordered, const vector<char>& allowed){\n        vector<int> isAnchorIndex(N, -1); for (int a = 0; a < A; ++a) isAnchorIndex[anchors_ordered[a]] = a;\n        vector<int> allowedVerts, allNonAnchors;\n        for (int v = 0; v < N; ++v) if (isAnchorIndex[v] < 0) { allNonAnchors.push_back(v); if (allowed[v]) allowedVerts.push_back(v); }\n        bool sufficient = ((int)allowedVerts.size() >= R * g);\n        const vector<int>& pool = sufficient ? allowedVerts : allNonAnchors;\n        vector<array<int, 32>> distToRow(N);\n        for (int v : pool) for (int r = 0; r < R; ++r) {\n            int d = 0; for (int a = 0; a < A; ++a) { int av = anchors_ordered[a]; int bit = alpha[r][a]; if ((int)adj[v][av] != bit) d++; }\n            distToRow[v][r] = d;\n        }\n        int SRC = 0; int Vn = 1 + (int)pool.size() + R + 1; int SNK = Vn - 1;\n        MinCostFlow mcf; mcf.init(Vn);\n        for (int i = 0; i < (int)pool.size(); ++i) mcf.addEdge(SRC, 1 + i, 1, 0);\n        for (int r = 0; r < R; ++r) mcf.addEdge(1 + (int)pool.size() + r, SNK, g, 0);\n        for (int i = 0; i < (int)pool.size(); ++i) {\n            int v = pool[i];\n            for (int r = 0; r < R; ++r) mcf.addEdge(1 + i, 1 + (int)pool.size() + r, 1, distToRow[v][r]);\n        }\n        mcf.minCostMaxFlow(SRC, SNK, R * g);\n        vector<vector<int>> clusterVerts(R);\n        for (int i = 0; i < (int)pool.size(); ++i) {\n            int from = 1 + i;\n            for (auto &e : mcf.G[from]) {\n                int to = e.to;\n                if (to >= 1 + (int)pool.size() && to < 1 + (int)pool.size() + R) {\n                    int row = to - (1 + (int)pool.size());\n                    if (mcf.G[to][e.rev].cap > 0) clusterVerts[row].push_back(pool[i]);\n                }\n            }\n        }\n        vector<char> used(N, 0);\n        for (int r = 0; r < R; ++r) for (int v : clusterVerts[r]) used[v] = 1;\n        if (sufficient) for (int r = 0; r < R; ++r) while ((int)clusterVerts[r].size() < g) {\n            bool found = false; for (int v : allowedVerts) if (!used[v]) { clusterVerts[r].push_back(v); used[v] = 1; found = true; break; }\n            if (!found) break;\n        }\n        for (int r = 0; r < R; ++r) while ((int)clusterVerts[r].size() < g) {\n            bool found = false; for (int v : allNonAnchors) if (!used[v]) { clusterVerts[r].push_back(v); used[v] = 1; found = true; break; }\n            if (!found) break;\n        }\n        for (int r = 0; r < R; ++r) if ((int)clusterVerts[r].size() > g) clusterVerts[r].resize(g);\n        return compute_row_stats(adj, anchors_ordered, clusterVerts);\n    };\n\n    auto refine_order_by_clusters = [&](const vector<vector<char>>& adj, const vector<int>& anchors_ordered, const AssignRes& ar)->vector<int>{\n        vector<vector<long long>> cost(A, vector<long long>(A, 0));\n        for (int ai = 0; ai < A; ++ai) {\n            int av = anchors_ordered[ai];\n            for (int j = 0; j < A; ++j) {\n                long long c = 0;\n                for (int r = 0; r < R; ++r) {\n                    int gi = (int)ar.clusterVerts[r].size();\n                    int y = 0; for (int v : ar.clusterVerts[r]) if (adj[av][v]) y++;\n                    int mis = alpha[r][j] ? (gi - y) : y;\n                    long long w = (long long)llround(ar.rowWeight[r] * 100.0);\n                    c += w * mis;\n                }\n                cost[ai][j] = c;\n            }\n        }\n        auto res = hungarian(cost);\n        vector<int> ord(A, -1); vector<char> seen(N, 0);\n        bool ok = true;\n        for (int ai = 0; ai < A; ++ai) {\n            int col = res.second[ai];\n            if (col < 0 || col >= A) { ok = false; break; }\n            int v = anchors_ordered[ai];\n            if (seen[v]) { ok = false; break; }\n            seen[v] = 1; ord[col] = v;\n        }\n        for (int j = 0; j < A; ++j) if (ord[j] < 0) ok = false;\n        if (!ok) return anchors_ordered;\n        return ord;\n    };\n\n    // Bit-aware MCF refinement with weighted cost terms and row bit reliability\n    auto assign_mcf_bitaware = [&](const vector<vector<char>>& adj, const vector<int>& anchors_ordered, const vector<char>& allowed, const AssignRes& refAr, unsigned int cwBits){\n        const auto& refClusters = refAr.clusterVerts;\n        vector<int> isAnchorIndex(N, -1); for (int a = 0; a < A; ++a) isAnchorIndex[anchors_ordered[a]] = a;\n        vector<int> allowedVerts, allNonAnchors; allowedVerts.reserve(N - A); allNonAnchors.reserve(N - A);\n        for (int v = 0; v < N; ++v) if (isAnchorIndex[v] < 0) { allNonAnchors.push_back(v); if (allowed[v]) allowedVerts.push_back(v); }\n        bool sufficient = ((int)allowedVerts.size() >= R * g);\n        const vector<int>& pool = sufficient ? allowedVerts : allNonAnchors;\n\n        // Precompute anchor mismatch distance\n        vector<array<int, 32>> distToRow(N);\n        for (int v : pool) for (int r = 0; r < R; ++r) {\n            int d = 0; for (int a = 0; a < A; ++a) { int av = anchors_ordered[a]; int bit = alpha[r][a]; if ((int)adj[v][av] != bit) d++; } distToRow[v][r] = d;\n        }\n        // Precompute edges to ref clusters\n        vector<array<int, 32>> edgesToRef(N);\n        vector<int> refSize(R, 0);\n        for (int r = 0; r < R; ++r) {\n            refSize[r] = (int)refClusters[r].size();\n            for (int v : pool) {\n                int y = 0; for (int u : refClusters[r]) if (adj[v][u]) y++;\n                edgesToRef[v][r] = y;\n            }\n        }\n        // Row bit reliability weight based on |2x - n|/n\n        vector<double> bitWeight(R, 1.0);\n        for (int r = 0; r < R; ++r) {\n            int n = refAr.pairCount[r];\n            int x = refAr.x[r];\n            if (n > 0) {\n                double conf = fabs(2.0 * x - n) / (double)n; // in [0,1]\n                bitWeight[r] = 0.7 + 0.8 * conf; // in [0.7, 1.5]\n            } else bitWeight[r] = 1.0;\n        }\n        // Weights for cost combination (increase edge weight with eps)\n        double wA = 1.0;\n        double wE = (eps <= 0.12 ? 1.0 : (eps <= 0.22 ? 1.2 : (eps <= 0.30 ? 1.4 : 1.6)));\n\n        int SRC = 0; int Vn = 1 + (int)pool.size() + R + 1; int SNK = Vn - 1;\n        MinCostFlow mcf; mcf.init(Vn);\n        for (int i = 0; i < (int)pool.size(); ++i) mcf.addEdge(SRC, 1 + i, 1, 0);\n        for (int r = 0; r < R; ++r) mcf.addEdge(1 + (int)pool.size() + r, SNK, g, 0);\n        for (int i = 0; i < (int)pool.size(); ++i) {\n            int v = pool[i];\n            for (int r = 0; r < R; ++r) {\n                int bit = (cwBits >> r) & 1u;\n                int y = edgesToRef[v][r]; int gi = refSize[r];\n                int costEdges = bit ? (gi - y) : y;\n                int costAnchor = distToRow[v][r];\n                int cost = (int)llround(wA * costAnchor + wE * bitWeight[r] * costEdges);\n                mcf.addEdge(1 + i, 1 + (int)pool.size() + r, 1, cost);\n            }\n        }\n        mcf.minCostMaxFlow(SRC, SNK, R * g);\n        vector<vector<int>> clusterVerts(R);\n        for (int i = 0; i < (int)pool.size(); ++i) {\n            int from = 1 + i;\n            for (auto &e : mcf.G[from]) {\n                int to = e.to;\n                if (to >= 1 + (int)pool.size() && to < 1 + (int)pool.size() + R) {\n                    int row = to - (1 + (int)pool.size());\n                    if (mcf.G[to][e.rev].cap > 0) clusterVerts[row].push_back(pool[i]);\n                }\n            }\n        }\n        vector<char> used(N, 0);\n        for (int r = 0; r < R; ++r) for (int v : clusterVerts[r]) used[v] = 1;\n        if (sufficient) for (int r = 0; r < R; ++r) while ((int)clusterVerts[r].size() < g) {\n            bool found = false; for (int v : allowedVerts) if (!used[v]) { clusterVerts[r].push_back(v); used[v] = 1; found = true; break; }\n            if (!found) break;\n        }\n        for (int r = 0; r < R; ++r) while ((int)clusterVerts[r].size() < g) {\n            bool found = false; for (int v : allNonAnchors) if (!used[v]) { clusterVerts[r].push_back(v); used[v] = 1; found = true; break; }\n            if (!found) break;\n        }\n        for (int r = 0; r < R; ++r) if ((int)clusterVerts[r].size() > g) clusterVerts[r].resize(g);\n        return compute_row_stats(adj, anchors_ordered, clusterVerts);\n    };\n\n    // Per-query buffers\n    vector<vector<char>> adj(N, vector<char>(N, 0)); vector<int> deg(N, 0);\n\n    for (int q = 0; q < 100; ++q) {\n        string H; cin >> H; build_adj(H, adj, deg);\n\n        // Anchors: top A by degree\n        vector<int> ord(N); iota(ord.begin(), ord.end(), 0);\n        nth_element(ord.begin(), ord.begin() + A, ord.end(), [&](int x, int y){ return deg[x] > deg[y]; });\n        vector<int> anchors(ord.begin(), ord.begin() + A);\n        vector<char> inA(N, 0); for (int v : anchors) inA[v] = 1;\n\n        // Estimate pads among non-anchors\n        vector<pair<int,int>> nonA_counts; nonA_counts.reserve(N - A);\n        for (int v = 0; v < N; ++v) if (!inA[v]) { int c = 0; for (int u : anchors) if (adj[v][u]) c++; nonA_counts.emplace_back(c, v); }\n        sort(nonA_counts.begin(), nonA_counts.end(), greater<>());\n        vector<char> isPadEst(N, 0); for (int i = 0; i < (int)nonA_counts.size() && i < U; ++i) isPadEst[nonA_counts[i].second] = 1;\n\n        // Allowed mask: exclude top-K pad candidates adaptively, but keep >= R*g vertices\n        int desiredBlock = (eps >= 0.26 ? U : (eps >= 0.18 ? max(0, U - 1) : 0));\n        int block = desiredBlock;\n        while (block > 0) {\n            int allowedCount = (int)nonA_counts.size() - block;\n            if (allowedCount >= R * g) break;\n            block--;\n        }\n        vector<char> allowed(N, 1);\n        for (int i = 0; i < block && i < (int)nonA_counts.size(); ++i) allowed[nonA_counts[i].second] = 0;\n        for (int v : anchors) allowed[v] = 1;\n\n        // External degree variants\n        vector<int> degExt(A, 0), degClustOnly(A, 0);\n        for (int i = 0; i < A; ++i) {\n            int v = anchors[i], c1 = 0, c2 = 0;\n            for (int u = 0; u < N; ++u) if (!inA[u] && adj[v][u]) c1++;\n            for (int u = 0; u < N; ++u) if (!inA[u] && isPadEst[u] == 0 && adj[v][u]) c2++;\n            degExt[i] = c1; degClustOnly[i] = c2;\n        }\n\n        // Candidate anchor orderings\n        vector<vector<int>> orderings;\n        { vector<int> o = anchors;\n          sort(o.begin(), o.end(), [&](int x, int y){ if (deg[x] != deg[y]) return deg[x] < deg[y]; return x < y; });\n          orderings.push_back(o); reverse(o.begin(), o.end()); orderings.push_back(o); }\n        { vector<pair<int,int>> tmp; for (int i = 0; i < A; ++i) tmp.emplace_back(degExt[i], anchors[i]);\n          sort(tmp.begin(), tmp.end()); vector<int> o; for (auto &p : tmp) o.push_back(p.second);\n          orderings.push_back(o); reverse(o.begin(), o.end()); orderings.push_back(o); }\n        { vector<pair<int,int>> tmp; for (int i = 0; i < A; ++i) tmp.emplace_back(degClustOnly[i], anchors[i]);\n          sort(tmp.begin(), tmp.end()); vector<int> o; for (auto &p : tmp) o.push_back(p.second);\n          orderings.push_back(o); reverse(o.begin(), o.end()); orderings.push_back(o); }\n        { vector<vector<long long>> cost(A, vector<long long>(A, 0));\n          for (int i = 0; i < A; ++i) for (int j = 0; j < A; ++j) cost[i][j] = llabs((long long)degClustOnly[i] - (long long)g * t[j]);\n          auto resH = hungarian(cost); vector<int> o(A, -1); vector<char> used(N, 0); bool ok = true;\n          for (int i = 0; i < A; ++i) { int col = resH.second[i]; if (col < 0 || col >= A) { ok = false; break; } int v = anchors[i]; if (used[v]) { ok = false; break; } used[v] = 1; o[col] = v; }\n          for (int j = 0; j < A; ++j) if (o[j] < 0) ok = false; if (ok) orderings.push_back(o); }\n\n        // Evaluate candidates by greedy decoding; keep top 2\n        struct CandRes { double ll; int idx; AssignRes ar; int pred; vector<int> ord; };\n        vector<CandRes> candRes; candRes.reserve(orderings.size());\n        for (int i = 0; i < (int)orderings.size(); ++i) {\n            auto ar = assign_greedy_allowed(adj, orderings[i], allowed);\n            auto res = decode_from_assign(ar);\n            candRes.push_back({res.second, i, move(ar), res.first, orderings[i]});\n        }\n        sort(candRes.begin(), candRes.end(), [](const CandRes& a, const CandRes& b){ return a.ll > b.ll; });\n\n        // Adjacent-swap refinement on best\n        vector<int> bestOrder = candRes[0].ord;\n        if ((int)bestOrder.size() >= 3) {\n            for (int i = 0; i < (int)bestOrder.size() - 1; ++i) {\n                swap(bestOrder[i], bestOrder[i+1]);\n                auto arTmp = assign_greedy_allowed(adj, bestOrder, allowed);\n                auto resTmp = decode_from_assign(arTmp);\n                if (resTmp.second > candRes[0].ll) { candRes[0].ll = resTmp.second; candRes[0].ar = move(arTmp); candRes[0].pred = resTmp.first; candRes[0].ord = bestOrder; }\n                else swap(bestOrder[i], bestOrder[i+1]);\n            }\n        }\n        // Cluster-driven Hungarian refinement on best and second-best\n        { auto ord2 = refine_order_by_clusters(adj, candRes[0].ord, candRes[0].ar);\n          auto ar2 = assign_greedy_allowed(adj, ord2, allowed); auto res2 = decode_from_assign(ar2);\n          if (res2.second > candRes[0].ll) { candRes[0].ll = res2.second; candRes[0].ar = move(ar2); candRes[0].pred = res2.first; candRes[0].ord = move(ord2); } }\n        int Kgreedy = min(2, (int)candRes.size());\n        if (Kgreedy >= 2) {\n            auto ord2 = refine_order_by_clusters(adj, candRes[1].ord, candRes[1].ar);\n            auto ar2 = assign_greedy_allowed(adj, ord2, allowed); auto res2 = decode_from_assign(ar2);\n            if (res2.second > candRes[1].ll) { candRes[1].ll = res2.second; candRes[1].ar = move(ar2); candRes[1].pred = res2.first; candRes[1].ord = move(ord2); }\n        }\n\n        // MCF and EM-like refinement on top K orderings (K adaptive)\n        int K = (eps > 0.24 ? min(3, (int)candRes.size()) : min(2, (int)candRes.size()));\n        int finalS = candRes[0].pred; double finalLL = candRes[0].ll;\n        vector<int> finalOrder = candRes[0].ord; AssignRes finalAssign = candRes[0].ar;\n\n        for (int k = 0; k < K; ++k) {\n            // MCF assignment\n            auto arMCF = assign_mcf_allowed(adj, candRes[k].ord, allowed);\n            auto resMCF = decode_from_assign(arMCF);\n            AssignRes bestAr = arMCF; vector<int> bestOrd = candRes[k].ord; int bestPredS = resMCF.first; double bestLL = resMCF.second;\n\n            // Refine order by clusters from MCF assignment and re-run MCF\n            auto ordR = refine_order_by_clusters(adj, candRes[k].ord, arMCF);\n            auto arMCF2 = assign_mcf_allowed(adj, ordR, allowed);\n            auto resMCF2 = decode_from_assign(arMCF2);\n            if (resMCF2.second > bestLL) { bestLL = resMCF2.second; bestPredS = resMCF2.first; bestOrd = ordR; bestAr = arMCF2; }\n\n            // Bit-aware MCF refinement (with row bit reliability)\n            if (R > 0) {\n                unsigned int cwBits = codewords[bestPredS];\n                auto arBA = assign_mcf_bitaware(adj, bestOrd, allowed, bestAr, cwBits);\n                auto resBA = decode_from_assign(arBA);\n                if (resBA.second > bestLL) { bestLL = resBA.second; bestPredS = resBA.first; }\n            }\n\n            if (bestLL > finalLL) { finalLL = bestLL; finalS = bestPredS; finalOrder = bestOrd; finalAssign = bestAr; }\n        }\n\n        cout << finalS << \"\\n\";\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Edge { int u, v; ll w; };\nstruct AdjEdge { int to, id; ll w; };\n\nconst ll INFLL = (ll)4e18;\n\nint N, M, D, K;\nvector<Edge> edges;\nvector<vector<AdjEdge>> adj;\nvector<int> Xcoord, Ycoord;\n\n// Morton Z-order for tie-breaking\nstatic inline uint64_t part1by1(uint32_t x) {\n    uint64_t v = x & 0x0000ffffu;\n    v = (v | (v << 8)) & 0x00FF00FFu;\n    v = (v | (v << 4)) & 0x0F0F0F0Fu;\n    v = (v | (v << 2)) & 0x33333333u;\n    v = (v | (v << 1)) & 0x55555555u;\n    return v;\n}\nstatic inline uint64_t morton2D_32(uint32_t x, uint32_t y) {\n    return (part1by1(y) << 1) | part1by1(x);\n}\n\n// Dijkstra from s to t while ignoring one banned edge (early exit on t), output parentEdge\nll dijkstra_exclude_with_parent(int s, int t, int banned_edge_id, vector<ll>& dist, vector<int>& parentEdge) {\n    dist.assign(N, INFLL);\n    parentEdge.assign(N, -1);\n    vector<char> vis(N, 0);\n    struct Node { ll d; int v; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n    dist[s] = 0;\n    pq.push({0, s});\n    while (!pq.empty()) {\n        auto [dcur, u] = pq.top(); pq.pop();\n        if (vis[u]) continue;\n        vis[u] = 1;\n        if (u == t) break;\n        for (const auto& ae : adj[u]) {\n            if (ae.id == banned_edge_id) continue;\n            int v = ae.to;\n            ll nd = dcur + ae.w;\n            if (dist[v] > nd) {\n                dist[v] = nd;\n                parentEdge[v] = ae.id;\n                pq.push({nd, v});\n            }\n        }\n    }\n    return dist[t];\n}\n\n// Dijkstra SPT from src (full graph) -> dist, parentEdge\nvoid dijkstra_tree(int src, vector<ll>& dist, vector<int>& parentEdge) {\n    dist.assign(N, INFLL);\n    parentEdge.assign(N, -1);\n    vector<char> vis(N, 0);\n    struct Node { ll d; int v; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.d > b.d; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n    dist[src] = 0;\n    pq.push({0, src});\n    while (!pq.empty()) {\n        auto [dcur, u] = pq.top(); pq.pop();\n        if (vis[u]) continue;\n        vis[u] = 1;\n        for (const auto& ae : adj[u]) {\n            int v = ae.to;\n            ll nd = dcur + ae.w;\n            if (dist[v] > nd) {\n                dist[v] = nd;\n                parentEdge[v] = ae.id;\n                pq.push({nd, v});\n            }\n        }\n    }\n}\n\n// Components of complement graph for a day (exclude edges scheduled on that day)\nvoid compute_components_for_day(int day, const vector<int>& assign, vector<int>& compId, int& compCount) {\n    compId.assign(N, -1);\n    compCount = 0;\n    deque<int> dq;\n    for (int i = 0; i < N; i++) {\n        if (compId[i] != -1) continue;\n        compId[i] = compCount;\n        dq.push_back(i);\n        while (!dq.empty()) {\n            int u = dq.front(); dq.pop_front();\n            for (const auto& ae : adj[u]) {\n                if (assign[ae.id] == day) continue; // removed that day\n                int v = ae.to;\n                if (compId[v] == -1) {\n                    compId[v] = compCount;\n                    dq.push_back(v);\n                }\n            }\n        }\n        compCount++;\n    }\n}\n\n// Tarjan bridges on complement graph for a day (edges with assign != day)\nvoid compute_bridges_for_day(int day, const vector<int>& assign, vector<char>& isBridge) {\n    isBridge.assign(M, false);\n    vector<int> tin(N, -1), low(N, -1);\n    int timer = 0;\n    function<void(int,int)> dfs = [&](int u, int peid) {\n        tin[u] = low[u] = timer++;\n        for (const auto& ae : adj[u]) {\n            int id = ae.id;\n            if (assign[id] == day) continue; // absent that day\n            if (id == peid) continue;\n            int v = ae.to;\n            if (tin[v] == -1) {\n                dfs(v, id);\n                low[u] = min(low[u], low[v]);\n                if (low[v] > tin[u]) isBridge[id] = true;\n            } else {\n                low[u] = min(low[u], tin[v]);\n            }\n        }\n    };\n    for (int i = 0; i < N; i++) if (tin[i] == -1) dfs(i, -1);\n}\nvoid precompute_bridges_all_days(const vector<int>& assign, vector<vector<char>>& isBridgeDays) {\n    isBridgeDays.assign(D, vector<char>(M, false));\n    for (int d = 0; d < D; d++) compute_bridges_for_day(d, assign, isBridgeDays[d]);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> D >> K;\n    edges.resize(M);\n    for (int i = 0; i < M; i++) {\n        int u, v; ll w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[i] = {u, v, w};\n    }\n    Xcoord.resize(N);\n    Ycoord.resize(N);\n    for (int i = 0; i < N; i++) cin >> Xcoord[i] >> Ycoord[i];\n\n    adj.assign(N, {});\n    for (int i = 0; i < M; i++) {\n        auto &e = edges[i];\n        adj[e.u].push_back({e.v, i, e.w});\n        adj[e.v].push_back({e.u, i, e.w});\n    }\n\n    auto time_start = chrono::steady_clock::now();\n    const double T_budget = 5.75;\n\n    // 1) Per-edge importance and bypass paths (bitsets)\n    int Wbits = (M + 63) >> 6;\n    vector<vector<uint64_t>> backupBits(M, vector<uint64_t>(Wbits, 0ULL));\n    vector<ll> importance(M, 0);\n    vector<ll> distTmp;\n    vector<int> parentEdge;\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        ll alt = dijkstra_exclude_with_parent(u, v, i, distTmp, parentEdge);\n        if (alt >= INFLL/2) {\n            importance[i] = (ll)1e9;\n        } else {\n            ll imp = alt - edges[i].w;\n            if (imp < 0) imp = 0;\n            importance[i] = imp;\n            // reconstruct path from v to u via parentEdge\n            int cur = v;\n            int safety = 0;\n            while (cur != u && safety <= N) {\n                int pe = parentEdge[cur];\n                if (pe < 0) break; // safety\n                backupBits[i][pe >> 6] |= (1ULL << (pe & 63));\n                int a = edges[pe].u, b = edges[pe].v;\n                cur = (a == cur ? b : a);\n                ++safety;\n            }\n        }\n    }\n\n    // 2) Edge usage via S shortest path trees with subtree sizes\n    vector<int> usage(M, 0);\n    vector<int> deg(N, 0);\n    for (int u = 0; u < N; u++) deg[u] = (int)adj[u].size();\n    vector<int> vid(N);\n    iota(vid.begin(), vid.end(), 0);\n    sort(vid.begin(), vid.end(), [&](int a, int b){\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        return a < b;\n    });\n    int SCount = min(48, max(24, N / 20));\n    vector<int> sources;\n    int n1 = min((int)vid.size(), SCount / 2);\n    for (int i = 0; i < n1; i++) sources.push_back(vid[i]);\n    for (int i = 0; (int)sources.size() < SCount && i < SCount * 3; i++) {\n        int id = (int)((1LL * i * N) / SCount);\n        if (id >= N) id = N - 1;\n        sources.push_back(id);\n        sort(sources.begin(), sources.end());\n        sources.erase(unique(sources.begin(), sources.end()), sources.end());\n    }\n    for (int i = 0; (int)sources.size() < SCount && i < N; i++) {\n        sources.push_back(i);\n        sort(sources.begin(), sources.end());\n        sources.erase(unique(sources.begin(), sources.end()), sources.end());\n    }\n    if ((int)sources.size() > SCount) sources.resize(SCount);\n\n    vector<ll> distFull;\n    vector<int> parentEdgeFull;\n    vector<int> orderNodes(N), parentVertex(N), subtree(N);\n    for (int s : sources) {\n        dijkstra_tree(s, distFull, parentEdgeFull);\n        for (int v = 0; v < N; v++) {\n            int pe = parentEdgeFull[v];\n            if (pe < 0) parentVertex[v] = -1;\n            else {\n                int a = edges[pe].u, b = edges[pe].v;\n                parentVertex[v] = (a == v ? b : a);\n            }\n        }\n        iota(orderNodes.begin(), orderNodes.end(), 0);\n        sort(orderNodes.begin(), orderNodes.end(), [&](int a, int b){\n            return distFull[a] > distFull[b];\n        });\n        for (int v = 0; v < N; v++) subtree[v] = 1;\n        for (int v : orderNodes) {\n            int p = parentVertex[v];\n            if (p >= 0) {\n                int pe = parentEdgeFull[v];\n                usage[pe] += subtree[v];\n                subtree[p] += subtree[v];\n            }\n        }\n    }\n    int maxUsage = 0;\n    for (int i = 0; i < M; i++) maxUsage = max(maxUsage, usage[i]);\n\n    // 3) Heavy metric\n    const double alphaUsage = 2.0;\n    vector<double> heavy(M, 0.0);\n    for (int i = 0; i < M; i++) {\n        double uNorm = (maxUsage > 0 ? (double)usage[i] / (double)maxUsage : 0.0);\n        heavy[i] = (double)importance[i] * (1.0 + alphaUsage * uNorm);\n    }\n\n    // Spatial key\n    vector<uint64_t> zkey(M);\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        int mx = (Xcoord[u] + Xcoord[v]) >> 1;\n        int my = (Ycoord[u] + Ycoord[v]) >> 1;\n        zkey[i] = morton2D_32((uint32_t)mx, (uint32_t)my);\n    }\n\n    // Grid partition\n    const int GW = 20, GH = 20;\n    const int strideX = (1001 + GW - 1) / GW;\n    const int strideY = (1001 + GH - 1) / GH;\n    auto cell_of_point = [&](int x, int y) -> int {\n        int cx = x / strideX; if (cx >= GW) cx = GW - 1;\n        int cy = y / strideY; if (cy >= GH) cy = GH - 1;\n        return cy * GW + cx;\n    };\n    vector<int> edgeCell(M);\n    for (int i = 0; i < M; i++) {\n        int u = edges[i].u, v = edges[i].v;\n        int mx = (Xcoord[u] + Xcoord[v]) >> 1;\n        int my = (Ycoord[u] + Ycoord[v]) >> 1;\n        edgeCell[i] = cell_of_point(mx, my);\n    }\n    const int nCells = GW * GH;\n\n    // Edge order: heavy desc then spatial key asc\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    stable_sort(order.begin(), order.end(), [&](int a, int b){\n        if (heavy[a] != heavy[b]) return heavy[a] > heavy[b];\n        if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n        return a < b;\n    });\n\n    // Assignment state\n    vector<int> assign(M, -1);\n    vector<vector<int>> dayEdges(D);\n    vector<int> daySize(D, 0);\n\n    vector<vector<double>> PV(N, vector<double>(D, 0.0));    // per-vertex/day heavy sum\n    vector<vector<double>> PC(nCells, vector<double>(D, 0.0)); // per-cell/day heavy sum\n    vector<double> daySum(D, 0.0);                           // per-day heavy sum\n    vector<vector<int>> cnt(N, vector<int>(D, 0));           // incident edges count per vertex/day\n\n    // Bypass interaction penalty state\n    vector<vector<uint64_t>> Rbits(D, vector<uint64_t>(Wbits, 0ULL)); // set of edges scheduled on day d\n    vector<vector<double>> sumHeavyBack(D, vector<double>(M, 0.0));   // sum heavy[g] for g in day d s.t. e in backup[g]\n\n    // Objective weights\n    const long double lamV = 1.0L;   // per-vertex heavy sum^2\n    const long double lamC = 0.25L;  // per-cell heavy sum^2\n    const long double lamD = 0.02L;  // per-day heavy sum^2\n    const long double lamB = 1.30L;  // bypass interaction\n    const long double lamDeg = 0.08L; // per-vertex incident-count^2\n    const long double lamN = 0.010L;  // per-day count^2\n\n    auto sqDelta = [&](double s, double dw) -> long double {\n        long double ss = (long double)s;\n        long double ddw = (long double)dw;\n        return (ss + ddw) * (ss + ddw) - ss * ss;\n    };\n    auto overlapCount = [&](int e, int d) -> int {\n        int c = 0;\n        const auto &be = backupBits[e];\n        const auto &Rd = Rbits[d];\n        for (int w = 0; w < Wbits; w++) {\n            uint64_t x = be[w] & Rd[w];\n            c += __builtin_popcountll(x);\n        }\n        return c;\n    };\n\n    auto add_delta = [&](int e, int d) -> long double {\n        int u = edges[e].u, v = edges[e].v;\n        int c = edgeCell[e];\n        double w = heavy[e];\n        long double delta = 0.0L;\n        // quadratic parts (heavy)\n        delta += lamV * ( sqDelta(PV[u][d], w) + sqDelta(PV[v][d], w) );\n        delta += lamC * ( sqDelta(PC[c][d], w) );\n        delta += lamD * ( sqDelta(daySum[d], w) );\n        // degree concentration counts\n        delta += lamDeg * ( (long double)(2*cnt[u][d] + 1) + (long double)(2*cnt[v][d] + 1) );\n        // day size balance\n        delta += lamN * ( (long double)(2*daySize[d] + 1) );\n        // bypass penalty\n        int ov = overlapCount(e, d);\n        delta += lamB * ( (long double)w * (long double)ov + (long double)sumHeavyBack[d][e] );\n        return delta;\n    };\n    auto remove_delta = [&](int e, int d) -> long double {\n        int u = edges[e].u, v = edges[e].v;\n        int c = edgeCell[e];\n        double w = heavy[e];\n        long double delta = 0.0L;\n        // quadratic parts (heavy)\n        delta += lamV * ( sqDelta(PV[u][d], -w) + sqDelta(PV[v][d], -w) );\n        delta += lamC * ( sqDelta(PC[c][d], -w) );\n        delta += lamD * ( sqDelta(daySum[d], -w) );\n        // degree concentration counts\n        delta += lamDeg * ( (long double)(-2*cnt[u][d] + 1) + (long double)(-2*cnt[v][d] + 1) );\n        // day size balance\n        delta += lamN * ( (long double)(-2*daySize[d] + 1) );\n        // bypass penalty\n        int ov = overlapCount(e, d);\n        delta += lamB * ( -(long double)w * (long double)ov - (long double)sumHeavyBack[d][e] );\n        return delta;\n    };\n\n    // Greedy assignment (respect K)\n    for (int idx = 0; idx < M; idx++) {\n        int e = order[idx];\n        int u = edges[e].u, v = edges[e].v;\n\n        int best_d = -1;\n        int best_conf = INT_MAX;\n        long double best_incr = 1e300L;\n        int best_size = INT_MAX;\n\n        for (int d = 0; d < D; d++) {\n            if (daySize[d] >= K) continue;\n            int conf = cnt[u][d] + cnt[v][d];\n            long double incr = add_delta(e, d);\n            if (conf < best_conf ||\n                (conf == best_conf && (incr < best_incr - 1e-12L ||\n                                       (fabsl(incr - best_incr) <= 1e-12L && daySize[d] < best_size)))) {\n                best_conf = conf;\n                best_incr = incr;\n                best_size = daySize[d];\n                best_d = d;\n            }\n        }\n        if (best_d == -1) best_d = 0;\n\n        // apply\n        assign[e] = best_d;\n        dayEdges[best_d].push_back(e);\n        // update counts\n        cnt[u][best_d]++; cnt[v][best_d]++;\n        int c = edgeCell[e];\n        double w = heavy[e];\n        PV[u][best_d] += w; PV[v][best_d] += w;\n        PC[c][best_d] += w;\n        daySum[best_d] += w;\n        // update day size and bypass state\n        Rbits[best_d][e >> 6] |= (1ULL << (e & 63));\n        for (int widx = 0; widx < Wbits; widx++) {\n            uint64_t bits = backupBits[e][widx];\n            while (bits) {\n                uint64_t b = bits & -bits;\n                int j = (widx << 6) + __builtin_ctzll(bits);\n                if (j < M) sumHeavyBack[best_d][j] += w;\n                bits ^= b;\n            }\n        }\n        daySize[best_d]++;\n    }\n\n    // posInDay\n    vector<int> posInDay(M, -1);\n    for (int d = 0; d < D; d++) for (int i = 0; i < (int)dayEdges[d].size(); i++) posInDay[dayEdges[d][i]] = i;\n\n    // Connectivity enforcement helpers\n    vector<vector<char>> isBridgeDays;\n    precompute_bridges_all_days(assign, isBridgeDays);\n\n    auto applyMove = [&](int e, int dFrom, int dTo) {\n        if (dFrom == dTo) return;\n        int u = edges[e].u, v = edges[e].v;\n        int c = edgeCell[e];\n        double w = heavy[e];\n\n        // remove from dFrom structures\n        {\n            int p = posInDay[e];\n            int last = dayEdges[dFrom].back();\n            dayEdges[dFrom][p] = last;\n            posInDay[last] = p;\n            dayEdges[dFrom].pop_back();\n            daySize[dFrom]--;\n        }\n        // update stats for removal\n        cnt[u][dFrom]--; cnt[v][dFrom]--;\n        PV[u][dFrom] -= w; PV[v][dFrom] -= w;\n        PC[c][dFrom] -= w;\n        daySum[dFrom] -= w;\n        // Rbits clear\n        Rbits[dFrom][e >> 6] &= ~(1ULL << (e & 63));\n        // sumHeavyBack subtract for backup[e]\n        for (int widx = 0; widx < Wbits; widx++) {\n            uint64_t bits = backupBits[e][widx];\n            while (bits) {\n                uint64_t b = bits & -bits;\n                int j = (widx << 6) + __builtin_ctzll(bits);\n                if (j < M) sumHeavyBack[dFrom][j] -= w;\n                bits ^= b;\n            }\n        }\n\n        // add to dTo\n        posInDay[e] = (int)dayEdges[dTo].size();\n        dayEdges[dTo].push_back(e);\n\n        cnt[u][dTo]++; cnt[v][dTo]++;\n        PV[u][dTo] += w; PV[v][dTo] += w;\n        PC[c][dTo] += w;\n        daySum[dTo] += w;\n        Rbits[dTo][e >> 6] |= (1ULL << (e & 63));\n        for (int widx = 0; widx < Wbits; widx++) {\n            uint64_t bits = backupBits[e][widx];\n            while (bits) {\n                uint64_t b = bits & -bits;\n                int j = (widx << 6) + __builtin_ctzll(bits);\n                if (j < M) sumHeavyBack[dTo][j] += w;\n                bits ^= b;\n            }\n        }\n        daySize[dTo]++;\n        assign[e] = dTo;\n\n        // Update bridges for the two days\n        compute_bridges_for_day(dFrom, assign, isBridgeDays[dFrom]);\n        compute_bridges_for_day(dTo, assign, isBridgeDays[dTo]);\n    };\n\n    auto applySwap = [&](int e1, int d1, int e2, int d2) {\n        if (d1 == d2) return;\n        // Remove e1 from d1\n        int u1 = edges[e1].u, v1 = edges[e1].v, c1 = edgeCell[e1];\n        double w1 = heavy[e1];\n        {\n            int p = posInDay[e1];\n            int last = dayEdges[d1].back();\n            dayEdges[d1][p] = last;\n            posInDay[last] = p;\n            dayEdges[d1].pop_back();\n            daySize[d1]--;\n            cnt[u1][d1]--; cnt[v1][d1]--;\n            PV[u1][d1] -= w1; PV[v1][d1] -= w1;\n            PC[c1][d1] -= w1;\n            daySum[d1] -= w1;\n            Rbits[d1][e1 >> 6] &= ~(1ULL << (e1 & 63));\n            for (int widx = 0; widx < Wbits; widx++) {\n                uint64_t bits = backupBits[e1][widx];\n                while (bits) {\n                    uint64_t b = bits & -bits;\n                    int j = (widx << 6) + __builtin_ctzll(bits);\n                    if (j < M) sumHeavyBack[d1][j] -= w1;\n                    bits ^= b;\n                }\n            }\n        }\n        // Remove e2 from d2\n        int u2 = edges[e2].u, v2 = edges[e2].v, c2 = edgeCell[e2];\n        double w2 = heavy[e2];\n        {\n            int p = posInDay[e2];\n            int last = dayEdges[d2].back();\n            dayEdges[d2][p] = last;\n            posInDay[last] = p;\n            dayEdges[d2].pop_back();\n            daySize[d2]--;\n            cnt[u2][d2]--; cnt[v2][d2]--;\n            PV[u2][d2] -= w2; PV[v2][d2] -= w2;\n            PC[c2][d2] -= w2;\n            daySum[d2] -= w2;\n            Rbits[d2][e2 >> 6] &= ~(1ULL << (e2 & 63));\n            for (int widx = 0; widx < Wbits; widx++) {\n                uint64_t bits = backupBits[e2][widx];\n                while (bits) {\n                    uint64_t b = bits & -bits;\n                    int j = (widx << 6) + __builtin_ctzll(bits);\n                    if (j < M) sumHeavyBack[d2][j] -= w2;\n                    bits ^= b;\n                }\n            }\n        }\n        // Add e1 to d2\n        posInDay[e1] = (int)dayEdges[d2].size();\n        dayEdges[d2].push_back(e1);\n        daySize[d2]++;\n        cnt[u1][d2]++; cnt[v1][d2]++;\n        PV[u1][d2] += w1; PV[v1][d2] += w1;\n        PC[c1][d2] += w1;\n        daySum[d2] += w1;\n        Rbits[d2][e1 >> 6] |= (1ULL << (e1 & 63));\n        for (int widx = 0; widx < Wbits; widx++) {\n            uint64_t bits = backupBits[e1][widx];\n            while (bits) {\n                uint64_t b = bits & -bits;\n                int j = (widx << 6) + __builtin_ctzll(bits);\n                if (j < M) sumHeavyBack[d2][j] += w1;\n                bits ^= b;\n            }\n        }\n        // Add e2 to d1\n        posInDay[e2] = (int)dayEdges[d1].size();\n        dayEdges[d1].push_back(e2);\n        daySize[d1]++;\n        cnt[u2][d1]++; cnt[v2][d1]++;\n        PV[u2][d1] += w2; PV[v2][d1] += w2;\n        PC[c2][d1] += w2;\n        daySum[d1] += w2;\n        Rbits[d1][e2 >> 6] |= (1ULL << (e2 & 63));\n        for (int widx = 0; widx < Wbits; widx++) {\n            uint64_t bits = backupBits[e2][widx];\n            while (bits) {\n                uint64_t b = bits & -bits;\n                int j = (widx << 6) + __builtin_ctzll(bits);\n                if (j < M) sumHeavyBack[d1][j] += w2;\n                bits ^= b;\n            }\n        }\n        assign[e1] = d2;\n        assign[e2] = d1;\n\n        // Update bridges for the two days\n        compute_bridges_for_day(d1, assign, isBridgeDays[d1]);\n        compute_bridges_for_day(d2, assign, isBridgeDays[d2]);\n    };\n\n    // Connectivity enforcement: fix disconnected days\n    int maxPass = 4;\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool changedAny = false;\n        for (int d = 0; d < D; d++) {\n            vector<int> compId;\n            int compCount = 0;\n            compute_components_for_day(d, assign, compId, compCount);\n            if (compCount <= 1) continue;\n\n            vector<int> crossEdges;\n            for (int e : dayEdges[d]) {\n                int u = edges[e].u, v = edges[e].v;\n                if (compId[u] != compId[v]) crossEdges.push_back(e);\n            }\n            if (crossEdges.empty()) continue;\n\n            sort(crossEdges.begin(), crossEdges.end(), [&](int a, int b){\n                if (heavy[a] != heavy[b]) return heavy[a] > heavy[b];\n                return a < b;\n            });\n\n            struct DSU {\n                vector<int> p, r;\n                int comps;\n                DSU(int n=0){ if(n) init(n); }\n                void init(int n){ p.resize(n); r.assign(n,0); iota(p.begin(),p.end(),0); comps=n; }\n                int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n                bool unite(int a,int b){\n                    a=find(a); b=find(b);\n                    if(a==b) return false;\n                    if(r[a]<r[b]) swap(a,b);\n                    p[b]=a;\n                    if(r[a]==r[b]) r[a]++;\n                    comps--;\n                    return true;\n                }\n            } dsu(compCount);\n\n            for (int e : crossEdges) {\n                int cu = dsu.find(compId[edges[e].u]);\n                int cv = dsu.find(compId[edges[e].v]);\n                if (cu == cv) continue;\n\n                int bestSafe = -1, bestAny = -1;\n                long double bestSafeDelta = 1e300L, bestAnyDelta = 1e300L;\n                for (int tday = 0; tday < D; tday++) {\n                    if (tday == d) continue;\n                    if (daySize[tday] >= K) continue;\n                    bool safe = !isBridgeDays[tday][e];\n                    long double delta = add_delta(e, tday); // removal from d helps, ignore here\n                    if (safe) {\n                        if (delta < bestSafeDelta) { bestSafeDelta = delta; bestSafe = tday; }\n                    } else {\n                        if (delta < bestAnyDelta) { bestAnyDelta = delta; bestAny = tday; }\n                    }\n                }\n                int tday = (bestSafe != -1 ? bestSafe : bestAny);\n                if (tday == -1) continue;\n                applyMove(e, d, tday);\n                dsu.unite(cu, cv);\n                changedAny = true;\n                if (dsu.comps == 1) break;\n            }\n        }\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - time_start).count();\n        if (elapsed > T_budget) break;\n        if (!changedAny) break;\n    }\n\n    // Bypass-relief pass: move edges with highest heavy*overlap first\n    {\n        vector<pair<double,int>> bad;\n        bad.reserve(M);\n        for (int e = 0; e < M; e++) {\n            int d = assign[e];\n            int ov = overlapCount(e, d);\n            if (ov > 0) bad.emplace_back(heavy[e] * (double)ov, e);\n        }\n        sort(bad.begin(), bad.end(), [&](const auto& A, const auto& B){\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        int limit = min<int>(200, (int)bad.size());\n        for (int i = 0; i < limit; i++) {\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - time_start).count();\n            if (elapsed > T_budget) break;\n            int e = bad[i].second;\n            int dFrom = assign[e];\n            long double bestDelta = -1e-12L;\n            int bestTo = -1;\n            for (int dTo = 0; dTo < D; dTo++) {\n                if (dTo == dFrom) continue;\n                if (daySize[dTo] >= K) continue;\n                if (isBridgeDays[dTo][e]) continue;\n                long double delta = remove_delta(e, dFrom) + add_delta(e, dTo);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestTo = dTo;\n                }\n            }\n            if (bestTo != -1) {\n                applyMove(e, dFrom, bestTo);\n            }\n        }\n    }\n\n    // Targeted synergy-driven swap pass (helps when best day is full)\n    {\n        vector<pair<double,int>> bad;\n        bad.reserve(M);\n        for (int e = 0; e < M; e++) {\n            int d = assign[e];\n            int ov = overlapCount(e, d);\n            if (ov > 0) bad.emplace_back(heavy[e] * (double)ov, e);\n        }\n        sort(bad.begin(), bad.end(), [&](const auto& A, const auto& B){\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        int limit = min<int>(150, (int)bad.size());\n        mt19937 rng(1234567);\n        for (int i = 0; i < limit; i++) {\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - time_start).count();\n            if (elapsed > T_budget) break;\n            int e = bad[i].second;\n            int dFrom = assign[e];\n\n            // Try to find best destination day (including swap if full)\n            long double bestDelta = -1e-12L;\n            int bestTo = -1, bestE2 = -1;\n\n            for (int dTo = 0; dTo < D; dTo++) {\n                if (dTo == dFrom) continue;\n\n                if (daySize[dTo] < K) {\n                    if (isBridgeDays[dTo][e]) continue;\n                    long double delta = remove_delta(e, dFrom) + add_delta(e, dTo);\n                    if (delta < bestDelta) { bestDelta = delta; bestTo = dTo; bestE2 = -1; }\n                } else {\n                    // Try swap with a few candidates in dTo\n                    // Skip if adding e would disconnect dTo in current state\n                    if (isBridgeDays[dTo][e]) continue;\n                    int trials = min<int>(12, (int)dayEdges[dTo].size());\n                    for (int t = 0; t < trials; t++) {\n                        int e2 = dayEdges[dTo][ rng() % dayEdges[dTo].size() ];\n                        if (isBridgeDays[dFrom][e2]) continue; // adding e2 to dFrom should be safe\n                        long double delta = remove_delta(e, dFrom) + add_delta(e, dTo)\n                                          + remove_delta(e2, dTo) + add_delta(e2, dFrom);\n                        if (delta < bestDelta) { bestDelta = delta; bestTo = dTo; bestE2 = e2; }\n                    }\n                }\n            }\n            if (bestTo != -1) {\n                if (bestE2 == -1) applyMove(e, dFrom, bestTo);\n                else applySwap(e, dFrom, bestE2, bestTo);\n            }\n        }\n    }\n\n    // Deterministic improvement pass: try best target day for each edge (one pass)\n    {\n        vector<int> idxs(M);\n        iota(idxs.begin(), idxs.end(), 0);\n        sort(idxs.begin(), idxs.end(), [&](int a, int b){\n            if (heavy[a] != heavy[b]) return heavy[a] > heavy[b];\n            return a < b;\n        });\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - time_start).count();\n        for (int k = 0; k < M; k++) {\n            if ((k & 255) == 0) {\n                now = chrono::steady_clock::now();\n                elapsed = chrono::duration<double>(now - time_start).count();\n                if (elapsed > T_budget) break;\n            }\n            int e = idxs[k];\n            int dFrom = assign[e];\n            long double bestDelta = -1e-12L;\n            int bestTo = -1;\n            for (int dTo = 0; dTo < D; dTo++) {\n                if (dTo == dFrom) continue;\n                if (daySize[dTo] >= K) continue;\n                if (isBridgeDays[dTo][e]) continue;\n                long double delta = remove_delta(e, dFrom) + add_delta(e, dTo);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestTo = dTo;\n                }\n            }\n            if (bestTo != -1) {\n                applyMove(e, dFrom, bestTo);\n            }\n        }\n    }\n\n    // Small random local search if time remains\n    auto now = chrono::steady_clock::now();\n    double elapsed = chrono::duration<double>(now - time_start).count();\n    double time_left = T_budget - elapsed;\n    if (time_left > 0.10) {\n        mt19937 rng(890123);\n        uniform_int_distribution<int> dayDist(0, D-1);\n        uniform_int_distribution<int> edgeDist(0, M-1);\n\n        int attemptsMove = 15000;\n        int attemptsSwap = 15000;\n\n        // 1-move attempts (connectivity-safe)\n        for (int it = 0; it < attemptsMove; it++) {\n            if ((it & 1023) == 0) {\n                now = chrono::steady_clock::now();\n                elapsed = chrono::duration<double>(now - time_start).count();\n                if (elapsed > T_budget) break;\n            }\n            int e = edgeDist(rng);\n            int dFrom = assign[e];\n            if (dFrom < 0) continue;\n            int bestTo = -1;\n            long double bestDelta = -1e-12L;\n            for (int dTo = 0; dTo < D; dTo++) {\n                if (dTo == dFrom) continue;\n                if (daySize[dTo] >= K) continue;\n                if (isBridgeDays[dTo][e]) continue; // adding e to dTo would disconnect\n                long double delta = remove_delta(e, dFrom) + add_delta(e, dTo);\n                if (delta < bestDelta) { bestDelta = delta; bestTo = dTo; }\n            }\n            if (bestTo != -1) {\n                applyMove(e, dFrom, bestTo);\n            }\n        }\n\n        // 2-swap attempts (connectivity-safe)\n        for (int it = 0; it < attemptsSwap; it++) {\n            if ((it & 1023) == 0) {\n                now = chrono::steady_clock::now();\n                elapsed = chrono::duration<double>(now - time_start).count();\n                if (elapsed > T_budget) break;\n            }\n            int d1 = dayDist(rng), d2 = dayDist(rng);\n            if (d1 == d2) continue;\n            if (dayEdges[d1].empty() || dayEdges[d2].empty()) continue;\n\n            int e1 = dayEdges[d1][ (int)(rng() % dayEdges[d1].size()) ];\n            int e2 = dayEdges[d2][ (int)(rng() % dayEdges[d2].size()) ];\n            if (e1 == e2) continue;\n            if (isBridgeDays[d2][e1]) continue;\n            if (isBridgeDays[d1][e2]) continue;\n\n            long double delta = remove_delta(e1, d1) + add_delta(e1, d2)\n                              + remove_delta(e2, d2) + add_delta(e2, d1);\n            if (delta < -1e-12L) {\n                applySwap(e1, d1, e2, d2);\n            }\n        }\n    }\n\n    // Output\n    for (int i = 0; i < M; i++) {\n        if (i) cout << ' ';\n        cout << (assign[i] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline int idx3(int D, int x, int y, int z) { return x * D * D + y * D + z; }\n\n// Hopcroft-Karp for bipartite matching (left: 0..nL-1, right: 0..nR-1)\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> adj;\n    vector<int> dist, matchL, matchR;\n    HopcroftKarp(int nL=0, int nR=0): nL(nL), nR(nR), adj(nL) {}\n    void init(int _nL, int _nR){ nL=_nL; nR=_nR; adj.assign(nL,{}); }\n    void addEdge(int u, int v){ adj[u].push_back(v); }\n    bool bfs(){\n        dist.assign(nL, -1);\n        queue<int> q;\n        for(int u=0; u<nL; ++u) if(matchL[u]==-1){ dist[u]=0; q.push(u); }\n        bool found=false;\n        while(!q.empty()){\n            int u=q.front(); q.pop();\n            for(int v: adj[u]){\n                int w=matchR[v];\n                if(w>=0){\n                    if(dist[w]<0){ dist[w]=dist[u]+1; q.push(w); }\n                }else found=true;\n            }\n        }\n        return found;\n    }\n    bool dfs(int u){\n        for(int v: adj[u]){\n            int w=matchR[v];\n            if(w<0 || (dist[w]==dist[u]+1 && dfs(w))){\n                matchL[u]=v; matchR[v]=u; return true;\n            }\n        }\n        dist[u]=-1; return false;\n    }\n    int maxMatching(vector<int>* outL=nullptr, vector<int>* outR=nullptr){\n        matchL.assign(nL, -1); matchR.assign(nR, -1);\n        int m=0;\n        while(bfs()){\n            for(int u=0; u<nL; ++u) if(matchL[u]==-1) if(dfs(u)) ++m;\n        }\n        if(outL) *outL = matchL;\n        if(outR) *outR = matchR;\n        return m;\n    }\n};\n\nstruct MinArrangement {\n    int D;\n    vector<char> present; // size D^3\n    long long volume=0;\n};\n\n// Randomized minimal arrangement builder with vertical run-length preference\nMinArrangement build_min_arrangement_random_weighted(const vector<string>& fz, const vector<string>& rz, int D, uint32_t seed, int lenWeight){\n    MinArrangement arr; arr.D=D; int N=D*D*D;\n    arr.present.assign(N, 0);\n    vector<vector<int>> prevLen(D, vector<int>(D, 0)); // run length up to z-1\n    vector<vector<char>> prevOcc(D, vector<char>(D, 0));\n\n    uint32_t rng_state = seed ? seed : 123456789u;\n    auto rng=[&]()->uint32_t{ rng_state^=rng_state<<13; rng_state^=rng_state>>17; rng_state^=rng_state<<5; return rng_state; };\n\n    for(int z=0; z<D; ++z){\n        vector<int> A,B;\n        for(int x=0;x<D;++x) if(fz[z][x]=='1') A.push_back(x);\n        for(int y=0;y<D;++y) if(rz[z][y]=='1') B.push_back(y);\n        int Nx=A.size(), Ny=B.size();\n        if(Nx==0 || Ny==0) continue;\n\n        if(Nx>=Ny){\n            HopcroftKarp hk(Ny, Nx);\n            for(int j=0;j<Ny;++j){\n                int y=B[j];\n                for(int i=0;i<Nx;++i){\n                    int x=A[i];\n                    if(prevOcc[x][y]) hk.addEdge(j,i);\n                }\n            }\n            vector<int> mY, mX; hk.maxMatching(&mY, &mX);\n            vector<int> xToY(Nx,-1), loadY(Ny,0);\n            vector<char> usedX(Nx,0), yCov(Ny,0);\n            for(int j=0;j<Ny;++j) if(mY[j]!=-1){\n                xToY[mY[j]]=j; usedX[mY[j]]=1; yCov[j]=1; loadY[j]++;\n            }\n            vector<int> prefX(Nx,0);\n            for(int i=0;i<Nx;++i){\n                int x=A[i], cnt=0;\n                for(int j=0;j<Ny;++j) if(prevOcc[x][B[j]]) cnt++;\n                prefX[i]=cnt;\n            }\n            for(int j=0;j<Ny;++j) if(!yCov[j]){\n                int pick=-1, best=INT_MAX;\n                for(int i=0;i<Nx;++i) if(!usedX[i]){\n                    int sc=prefX[i]*10 + int(rng()&7u);\n                    if(sc<best){ best=sc; pick=i; }\n                }\n                if(pick==-1){ for(int i=0;i<Nx;++i) if(xToY[i]!=-1){ pick=i; break; } if(pick==-1) pick=0; }\n                xToY[pick]=j; usedX[pick]=1; yCov[j]=1; loadY[j]++;\n            }\n            vector<vector<int>> xsPerY(Ny);\n            for(int i=0;i<Nx;++i) if(xToY[i]!=-1) xsPerY[xToY[i]].push_back(i);\n            for(int i=0;i<Nx;++i) if(!usedX[i]){\n                int x=A[i], bestY=0, bestSc=INT_MIN;\n                for(int j=0;j<Ny;++j){\n                    int y=B[j];\n                    int sc = 0;\n                    sc += 100 * (prevOcc[x][y] ? 1 : 0);\n                    sc += lenWeight * prevLen[x][y];\n                    for(int xi: xsPerY[j]) if(abs(A[xi]-x)==1){ sc += 10; break; }\n                    sc -= loadY[j];\n                    sc += int(rng()&3u);\n                    if(sc>bestSc){ bestSc=sc; bestY=j; }\n                }\n                xToY[i]=bestY; loadY[bestY]++; xsPerY[bestY].push_back(i);\n            }\n            for(int i=0;i<Nx;++i){\n                int x=A[i], y=B[xToY[i]];\n                arr.present[idx3(D,x,y,z)] = 1; arr.volume++;\n            }\n        }else{\n            HopcroftKarp hk(Nx, Ny);\n            for(int i=0;i<Nx;++i){\n                int x=A[i];\n                for(int j=0;j<Ny;++j){\n                    int y=B[j];\n                    if(prevOcc[x][y]) hk.addEdge(i,j);\n                }\n            }\n            vector<int> mX, mY; hk.maxMatching(&mX, &mY);\n            vector<int> yToX(Ny,-1), loadX(Nx,0);\n            vector<char> usedY(Ny,0);\n            vector<vector<int>> ysPerX(Nx);\n            for(int i=0;i<Nx;++i) if(mX[i]!=-1){\n                int j=mX[i]; yToX[j]=i; usedY[j]=1; loadX[i]++; ysPerX[i].push_back(j);\n            }\n            vector<int> prefY(Ny,0);\n            for(int j=0;j<Ny;++j){\n                int y=B[j], cnt=0;\n                for(int i=0;i<Nx;++i) if(prevOcc[A[i]][y]) cnt++;\n                prefY[j]=cnt;\n            }\n            for(int i=0;i<Nx;++i) if(mX[i]==-1){\n                int pick=-1, best=INT_MAX;\n                for(int j=0;j<Ny;++j) if(!usedY[j]){\n                    int sc=prefY[j]*10 + int((rng()&7u));\n                    if(sc<best){ best=sc; pick=j; }\n                }\n                if(pick==-1){ for(int j=0;j<Ny;++j) if(!usedY[j]){ pick=j; break; } if(pick==-1) pick=0; }\n                yToX[pick]=i; usedY[pick]=1; loadX[i]++; ysPerX[i].push_back(pick);\n            }\n            for(int j=0;j<Ny;++j) if(!usedY[j]){\n                int y=B[j], bestI=0, bestSc=INT_MIN;\n                for(int i=0;i<Nx;++i){\n                    int x=A[i];\n                    int sc=0;\n                    sc += 100 * (prevOcc[x][y] ? 1 : 0);\n                    sc += lenWeight * prevLen[x][y];\n                    for(int yj: ysPerX[i]) if(abs(B[yj]-y)==1){ sc += 10; break; }\n                    sc -= loadX[i];\n                    sc += int(rng()&3u);\n                    if(sc>bestSc){ bestSc=sc; bestI=i; }\n                }\n                yToX[j]=bestI; usedY[j]=1; loadX[bestI]++; ysPerX[bestI].push_back(j);\n            }\n            for(int j=0;j<Ny;++j){\n                int i=yToX[j]; int x=A[i], y=B[j];\n                arr.present[idx3(D,x,y,z)] = 1; arr.volume++;\n            }\n        }\n        vector<vector<int>> nextLen(D, vector<int>(D, 0));\n        for(int x=0;x<D;++x) for(int y=0;y<D;++y){\n            if(arr.present[idx3(D,x,y,z)]){\n                prevOcc[x][y]=1;\n                nextLen[x][y]=prevLen[x][y]+1;\n            }else{\n                prevOcc[x][y]=0;\n                nextLen[x][y]=0;\n            }\n        }\n        prevLen.swap(nextLen);\n    }\n    return arr;\n}\n\n// DP per layer maximizing vertical continuity with lookahead\nMinArrangement build_min_arrangement_dp(const vector<string>& fz, const vector<string>& rz, int D, int Wprev, int Wnext, int Wnext2) {\n    MinArrangement arr;\n    arr.D = D;\n    int N = D * D * D;\n    arr.present.assign(N, 0);\n    arr.volume = 0;\n\n    vector<vector<char>> prevOcc(D, vector<char>(D, 0));\n    const int NEG_INF = -1e9;\n\n    for (int z = 0; z < D; ++z) {\n        vector<int> A, B;\n        for (int x = 0; x < D; ++x) if (fz[z][x] == '1') A.push_back(x);\n        for (int y = 0; y < D; ++y) if (rz[z][y] == '1') B.push_back(y);\n        int Nx = (int)A.size();\n        int Ny = (int)B.size();\n        if (Nx == 0 || Ny == 0) continue;\n\n        auto nextAllowed = [&](int x, int y)->int{\n            if (z + 1 >= D) return 0;\n            return (fz[z+1][x]=='1' && rz[z+1][y]=='1') ? 1 : 0;\n        };\n        auto next2Allowed = [&](int x, int y)->int{\n            if (z + 2 >= D) return 0;\n            return (fz[z+2][x]=='1' && rz[z+2][y]=='1') ? 1 : 0;\n        };\n\n        if (Nx >= Ny) {\n            int S = 1 << Ny;\n            vector<int> dp(S, NEG_INF), ndp(S, NEG_INF);\n            vector<int> parY((Nx + 1) * S, -1);\n            vector<int> parMask((Nx + 1) * S, -1);\n            auto at = [&](int i, int mask)->int{ return i * S + mask; };\n            dp[0]=0;\n            for(int i=0;i<Nx;++i){\n                fill(ndp.begin(), ndp.end(), NEG_INF);\n                int x = A[i];\n                for(int mask=0; mask<S; ++mask){\n                    int cur=dp[mask]; if(cur<=NEG_INF/2) continue;\n                    for(int j=0;j<Ny;++j){\n                        int y=B[j];\n                        int w=0;\n                        if(prevOcc[x][y]) w+=Wprev;\n                        if(nextAllowed(x,y)) w+=Wnext;\n                        if(next2Allowed(x,y)) w+=Wnext2;\n                        int nmask=mask | (1<<j);\n                        int val=cur+w;\n                        if(val > ndp[nmask]){\n                            ndp[nmask]=val;\n                            parY[at(i+1,nmask)] = j;\n                            parMask[at(i+1,nmask)] = mask;\n                        }\n                    }\n                }\n                dp.swap(ndp);\n            }\n            int full=(1<<Ny)-1;\n            int mask=full;\n            vector<int> y_of_x(Nx,0);\n            for(int i=Nx;i>=1;--i){\n                int j=parY[at(i,mask)];\n                if(j<0) j=(i-1)%Ny;\n                y_of_x[i-1]=j;\n                int pm=parMask[at(i,mask)];\n                if(pm>=0) mask=pm;\n            }\n            for(int i=0;i<Nx;++i){\n                int x=A[i], y=B[y_of_x[i]];\n                arr.present[idx3(D,x,y,z)] = 1; arr.volume++;\n            }\n        } else {\n            int S = 1 << Nx;\n            vector<int> dp(S, NEG_INF), ndp(S, NEG_INF);\n            vector<int> parX((Ny + 1) * S, -1);\n            vector<int> parMask((Ny + 1) * S, -1);\n            auto at = [&](int j, int mask)->int{ return j * S + mask; };\n            dp[0]=0;\n            for(int j=0;j<Ny;++j){\n                fill(ndp.begin(), ndp.end(), NEG_INF);\n                int y=B[j];\n                for(int mask=0; mask<S; ++mask){\n                    int cur=dp[mask]; if(cur<=NEG_INF/2) continue;\n                    for(int i=0;i<Nx;++i){\n                        int x=A[i];\n                        int w=0;\n                        if(prevOcc[x][y]) w+=Wprev;\n                        if(nextAllowed(x,y)) w+=Wnext;\n                        if(next2Allowed(x,y)) w+=Wnext2;\n                        int nmask=mask | (1<<i);\n                        int val=cur+w;\n                        if(val > ndp[nmask]){\n                            ndp[nmask]=val;\n                            parX[at(j+1,nmask)] = i;\n                            parMask[at(j+1,nmask)] = mask;\n                        }\n                    }\n                }\n                dp.swap(ndp);\n            }\n            int full=(1<<Nx)-1;\n            int mask=full;\n            vector<int> x_of_y(Ny,0);\n            for(int j=Ny;j>=1;--j){\n                int i=parX[at(j,mask)];\n                if(i<0) i=(j-1)%Nx;\n                x_of_y[j-1]=i;\n                int pm=parMask[at(j,mask)];\n                if(pm>=0) mask=pm;\n            }\n            for(int j=0;j<Ny;++j){\n                int x=A[x_of_y[j]], y=B[j];\n                arr.present[idx3(D,x,y,z)] = 1; arr.volume++;\n            }\n        }\n        for(int x=0;x<D;++x) for(int y=0;y<D;++y) prevOcc[x][y]=0;\n        for(int x=0;x<D;++x) for(int y=0;y<D;++y) if(arr.present[idx3(D,x,y,z)]) prevOcc[x][y]=1;\n    }\n    return arr;\n}\n\nstruct Run { int x,y,z0,len; };\n\nstatic vector<Run> extract_runs(const MinArrangement& arr){\n    int D=arr.D; vector<Run> runs;\n    for(int x=0;x<D;++x) for(int y=0;y<D;++y){\n        int z=0;\n        while(z<D){\n            while(z<D && !arr.present[idx3(D,x,y,z)]) ++z;\n            if(z>=D) break;\n            int z0=z;\n            while(z<D && arr.present[idx3(D,x,y,z)]) ++z;\n            int len=z-z0;\n            if(len>0) runs.push_back({x,y,z0,len});\n        }\n    }\n    return runs;\n}\n\nstruct PairingScore { double penalty; long long shared; };\n\n// Greedy pairing by length across both run multisets\nstatic PairingScore evaluate_pairing(const vector<Run>& r1, const vector<Run>& r2){\n    struct Node{int len,id;};\n    struct Cmp{ bool operator()(const Node&a,const Node&b)const{\n        if(a.len!=b.len) return a.len<b.len; return a.id>b.id;\n    }};\n    priority_queue<Node, vector<Node>, Cmp> pq1, pq2;\n    for(int i=0;i<(int)r1.size();++i) if(r1[i].len>0) pq1.push({r1[i].len,i});\n    for(int j=0;j<(int)r2.size();++j) if(r2[j].len>0) pq2.push({r2[j].len,j});\n    double pen=0.0; long long shared=0;\n    while(!pq1.empty() && !pq2.empty()){\n        auto a=pq1.top(); pq1.pop();\n        auto b=pq2.top(); pq2.pop();\n        int L=min(a.len,b.len);\n        pen += 1.0 / (double)L;\n        shared += L;\n        a.len -= L; b.len -= L;\n        if(a.len>0) pq1.push(a);\n        if(b.len>0) pq2.push(b);\n    }\n    return {pen, shared};\n}\n\nstruct AssignResult {\n    int D, N;\n    vector<int> b1, b2;\n    int nblocks;\n    int sharedK;\n    vector<Run> sharedRun1, sharedRun2; // IDs 1..sharedK correspond to these runs\n};\n\nstatic AssignResult assign_blocks_from_runs_with_meta(\n    const vector<Run>& r1, const vector<Run>& r2, int D\n){\n    AssignResult res;\n    res.D = D; res.N = D*D*D;\n    res.b1.assign(res.N, 0);\n    res.b2.assign(res.N, 0);\n    res.nblocks = 0;\n    res.sharedK = 0;\n    res.sharedRun1.clear(); res.sharedRun2.clear();\n\n    struct Node{int len,id;};\n    struct Cmp{ bool operator()(const Node&a,const Node&b)const{\n        if(a.len!=b.len) return a.len<b.len; return a.id>b.id;\n    }};\n    priority_queue<Node, vector<Node>, Cmp> pq1, pq2;\n    int n1=r1.size(), n2=r2.size();\n    vector<int> rem1(n1), rem2(n2), off1(n1,0), off2(n2,0);\n    for(int i=0;i<n1;++i){ rem1[i]=r1[i].len; if(rem1[i]>0) pq1.push({rem1[i],i}); }\n    for(int j=0;j<n2;++j){ rem2[j]=r2[j].len; if(rem2[j]>0) pq2.push({rem2[j],j}); }\n\n    // Shared sticks\n    while(!pq1.empty() && !pq2.empty()){\n        auto a=pq1.top(); pq1.pop();\n        auto b=pq2.top(); pq2.pop();\n        int i=a.id, j=b.id;\n        int L=min(rem1[i], rem2[j]);\n        int id=++res.nblocks;\n        for(int t=0;t<L;++t){\n            int z=r1[i].z0+off1[i]+t;\n            res.b1[idx3(D, r1[i].x, r1[i].y, z)] = id;\n        }\n        for(int t=0;t<L;++t){\n            int z=r2[j].z0+off2[j]+t;\n            res.b2[idx3(D, r2[j].x, r2[j].y, z)] = id;\n        }\n        res.sharedRun1.push_back({r1[i].x, r1[i].y, r1[i].z0+off1[i], L});\n        res.sharedRun2.push_back({r2[j].x, r2[j].y, r2[j].z0+off2[j], L});\n        res.sharedK++;\n\n        rem1[i]-=L; off1[i]+=L;\n        rem2[j]-=L; off2[j]+=L;\n        if(rem1[i]>0) pq1.push({rem1[i],i});\n        if(rem2[j]>0) pq2.push({rem2[j],j});\n    }\n    // Remaining arrangement-only sticks in A1\n    for(int i=0;i<n1;++i) if(rem1[i]>0){\n        int id=++res.nblocks;\n        for(int t=0;t<rem1[i];++t){\n            int z=r1[i].z0+off1[i]+t;\n            res.b1[idx3(D, r1[i].x, r1[i].y, z)] = id;\n        }\n    }\n    // Remaining arrangement-only sticks in A2\n    for(int j=0;j<n2;++j) if(rem2[j]>0){\n        int id=++res.nblocks;\n        for(int t=0;t<rem2[j];++t){\n            int z=r2[j].z0+off2[j]+t;\n            res.b2[idx3(D, r2[j].x, r2[j].y, z)] = id;\n        }\n    }\n    return res;\n}\n\nstatic bool validate_arr(int D, const vector<string>& fz, const vector<string>& rz, const vector<int>& b){\n    auto occ=[&](int x,int y,int z)->bool{ return b[idx3(D,x,y,z)]!=0; };\n    for(int z=0; z<D; ++z){\n        for(int x=0;x<D;++x) if(fz[z][x]=='1'){\n            bool ok=false; for(int y=0;y<D;++y) if(occ(x,y,z)){ ok=true; break; }\n            if(!ok) return false;\n        }\n        for(int y=0;y<D;++y) if(rz[z][y]=='1'){\n            bool ok=false; for(int x=0;x<D;++x) if(occ(x,y,z)){ ok=true; break; }\n            if(!ok) return false;\n        }\n    }\n    return true;\n}\n\n// Domino fallback: build minimal arrangement (DP) then max 3D matching\nstatic vector<int> domino_arrangement(const vector<string>& fz, const vector<string>& rz, int D){\n    MinArrangement A = build_min_arrangement_dp(fz, rz, D, 1000, 20, 5);\n    int N=D*D*D;\n    vector<int> leftId(N,-1), rightId(N,-1), leftPos, rightPos;\n    int nL=0,nR=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 p=idx3(D,x,y,z); if(!A.present[p]) continue;\n        if(((x+y+z)&1)==0){ leftId[p]=nL++; leftPos.push_back(p); }\n        else{ rightId[p]=nR++; rightPos.push_back(p); }\n    }\n    HopcroftKarp hk(nL,nR); hk.adj.assign(nL,{});\n    const int dx[6]={1,-1,0,0,0,0};\n    const int dy[6]={0,0,1,-1,0,0};\n    const int dz[6]={0,0,0,0,1,-1};\n    for(int u=0;u<nL;++u){\n        int p=leftPos[u], x=p/(D*D), y=(p/D)%D, z=p%D;\n        for(int d=0; d<6; ++d){\n            int nx=x+dx[d], ny=y+dy[d], nz=z+dz[d];\n            if(nx<0||nx>=D||ny<0||ny>=D||nz<0||nz>=D) continue;\n            int q=idx3(D,nx,ny,nz);\n            if(!A.present[q]) continue;\n            int v=rightId[q]; if(v!=-1) hk.addEdge(u,v);\n        }\n    }\n    vector<int> mL, mR; hk.maxMatching(&mL, &mR);\n    vector<int> B(N,0); vector<char> used(N,0);\n    int nb=0;\n    for(int u=0;u<nL;++u){\n        int v=mL[u]; if(v!=-1){\n            int id=++nb; int p=leftPos[u], q=rightPos[v];\n            B[p]=id; B[q]=id; used[p]=used[q]=1;\n        }\n    }\n    for(int p=0;p<N;++p) if(!used[p] && A.present[p]){ int id=++nb; B[p]=id; }\n    return B;\n}\n\n// DSU for merging IDs\nstruct DSU {\n    vector<int> p;\n    DSU() {}\n    DSU(int n){ init(n); }\n    void init(int n){ p.resize(n); iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x? x : p[x]=find(p[x]); }\n    void unite(int a, int b){ a=find(a); b=find(b); if(a!=b) p[b]=a; }\n};\n\n// Check if positions form a contiguous line along x or y\nstatic bool isContiguousLine(const vector<pair<int,int>>& pos, int D){\n    int s = (int)pos.size();\n    if (s < 2) return false;\n    bool sameX = true, sameY = true;\n    int x0 = pos[0].first, y0 = pos[0].second;\n    for (auto &pr : pos) {\n        if (pr.first != x0) sameX = false;\n        if (pr.second != y0) sameY = false;\n    }\n    if (sameY) {\n        int mn = INT_MAX, mx = INT_MIN;\n        vector<char> seen(D, 0);\n        for (auto &pr : pos) {\n            int x = pr.first;\n            if (seen[x]) return false;\n            seen[x] = 1;\n            mn = min(mn, x);\n            mx = max(mx, x);\n        }\n        return (mx - mn + 1 == s);\n    } else if (sameX) {\n        int mn = INT_MAX, mx = INT_MIN;\n        vector<char> seen(D, 0);\n        for (auto &pr : pos) {\n            int y = pr.second;\n            if (seen[y]) return false;\n            seen[y] = 1;\n            mn = min(mn, y);\n            mx = max(mx, y);\n        }\n        return (mx - mn + 1 == s);\n    }\n    return false;\n}\n\n// Align shared pairs: permute A2 segments within each length group to match z0 and locality\nstatic void align_shared_pairs(struct AssignResult& res){\n    int K = res.sharedK;\n    if (K <= 1) return;\n    int D = res.D;\n    unordered_map<int, vector<int>> byLen;\n    byLen.reserve(K*2);\n    for (int id = 1; id <= K; ++id) {\n        byLen[ res.sharedRun1[id-1].len ].push_back(id);\n    }\n    vector<int> mapId(K+1); // map A1 id -> A2 id\n    iota(mapId.begin(), mapId.end(), 0);\n\n    auto morton = [D](int x, int y)->int{\n        return y * D + x;\n    };\n\n    for (auto &kv : byLen) {\n        auto &ids = kv.second;\n        int n = (int)ids.size();\n        if (n <= 1) continue;\n\n        struct Elem { int id; int x1,y1,z01; int x2,y2,z02; };\n        vector<Elem> elems; elems.reserve(n);\n        for (int id : ids) {\n            auto &r1 = res.sharedRun1[id-1];\n            auto &r2 = res.sharedRun2[id-1];\n            elems.push_back({id, r1.x, r1.y, r1.z0, r2.x, r2.y, r2.z0});\n        }\n\n        unordered_map<int, vector<int>> z1, z2;\n        z1.reserve(n*2); z2.reserve(n*2);\n        for (int i = 0; i < n; ++i) {\n            z1[ elems[i].z01 ].push_back(i);\n            z2[ elems[i].z02 ].push_back(i);\n        }\n\n        vector<int> used1(n, 0), used2(n, 0);\n        vector<pair<int,int>> pairs; pairs.reserve(n);\n\n        for (auto &kvz : z1) {\n            int z = kvz.first;\n            auto it = z2.find(z);\n            if (it == z2.end()) continue;\n            auto &v1 = kvz.second;\n            auto &v2 = it->second;\n            sort(v1.begin(), v1.end(), [&](int a, int b){\n                return morton(elems[a].x1, elems[a].y1) < morton(elems[b].x1, elems[b].y1);\n            });\n            sort(v2.begin(), v2.end(), [&](int a, int b){\n                return morton(elems[a].x2, elems[a].y2) < morton(elems[b].x2, elems[b].y2);\n            });\n            int k = min((int)v1.size(), (int)v2.size());\n            for (int t = 0; t < k; ++t) {\n                int i = v1[t], j = v2[t];\n                if (used1[i] || used2[j]) continue;\n                used1[i] = used2[j] = 1;\n                pairs.emplace_back(i, j);\n            }\n        }\n\n        vector<int> rem1, rem2;\n        rem1.reserve(n); rem2.reserve(n);\n        for (int i = 0; i < n; ++i) if (!used1[i]) rem1.push_back(i);\n        for (int j = 0; j < n; ++j) if (!used2[j]) rem2.push_back(j);\n        sort(rem1.begin(), rem1.end(), [&](int a, int b){\n            return morton(elems[a].x1, elems[a].y1) < morton(elems[b].x1, elems[b].y1);\n        });\n        sort(rem2.begin(), rem2.end(), [&](int a, int b){\n            return morton(elems[a].x2, elems[a].y2) < morton(elems[b].x2, elems[b].y2);\n        });\n        int k2 = min((int)rem1.size(), (int)rem2.size());\n        for (int t = 0; t < k2; ++t) {\n            pairs.emplace_back(rem1[t], rem2[t]);\n        }\n\n        for (auto &pr : pairs) {\n            int idA = elems[pr.first].id;\n            int idB = elems[pr.second].id;\n            mapId[idA] = idB;\n        }\n    }\n\n    vector<int> invMap(K+1, 0);\n    for (int i = 1; i <= K; ++i) invMap[ mapId[i] ] = i;\n\n    for (int p = 0; p < res.N; ++p) {\n        int id = res.b2[p];\n        if (id >= 1 && id <= K) {\n            res.b2[p] = invMap[id];\n        }\n    }\n    vector<Run> newRun2(K);\n    for (int i = 1; i <= K; ++i) {\n        newRun2[i-1] = res.sharedRun2[ mapId[i] - 1 ];\n    }\n    res.sharedRun2.swap(newRun2);\n}\n\n// Merge rectangles first, then lines, among shared sticks\nstatic void merge_shared_rectangles(struct AssignResult& res){\n    int D = res.D, N = res.N;\n    int K = res.sharedK;\n    if (K <= 1) return;\n\n    struct Pos { int x,y,z0,len; };\n    vector<Pos> p1(K+1), p2(K+1);\n    for (int id = 1; id <= K; ++id) {\n        auto r1 = res.sharedRun1[id-1];\n        auto r2 = res.sharedRun2[id-1];\n        p1[id] = {r1.x, r1.y, r1.z0, r1.len};\n        p2[id] = {r2.x, r2.y, r2.z0, r2.len};\n    }\n\n    struct Key { int len,z01,z02; };\n    struct KeyHash {\n        size_t operator()(const Key& k) const noexcept {\n            return (size_t)k.len * 10000u + (size_t)k.z01 * 100u + (size_t)k.z02;\n        }\n    };\n    struct KeyEq { bool operator()(const Key& a, const Key& b) const noexcept {\n        return a.len==b.len && a.z01==b.z01 && a.z02==b.z02;\n    }};\n\n    unordered_map<Key, vector<int>, KeyHash, KeyEq> groups;\n    groups.reserve(K*2);\n    for (int id = 1; id <= K; ++id) {\n        Key key{p1[id].len, p1[id].z0, p2[id].z0};\n        groups[key].push_back(id);\n    }\n\n    DSU dsu(res.nblocks + 1);\n\n    for (auto &kv : groups) {\n        auto &ids = kv.second;\n        vector<int> grid1(D*D, 0), grid2(D*D, 0);\n        for (int id : ids) {\n            grid1[p1[id].x*D + p1[id].y] = id;\n            grid2[p2[id].x*D + p2[id].y] = id;\n        }\n        vector<char> usedRect(K+1, 0);\n\n        auto try_rectangle_from = [&](int sx, int sy, vector<int>& rectIDs) -> bool {\n            int id0 = grid1[sx*D + sy];\n            if (id0 == 0 || usedRect[id0]) return false;\n            int maxRows = 0;\n            for (int dy = 0; sy + dy < D; ++dy) {\n                int id = grid1[sx*D + (sy + dy)];\n                if (id == 0 || usedRect[id]) break;\n                maxRows++;\n            }\n            if (maxRows <= 0) return false;\n            vector<int> rowLen(maxRows, 0);\n            for (int dy = 0; dy < maxRows; ++dy) {\n                int y = sy + dy;\n                int len = 0;\n                for (int x = sx; x < D; ++x) {\n                    int id = grid1[x*D + y];\n                    if (id == 0 || usedRect[id]) break;\n                    ++len;\n                }\n                rowLen[dy] = len;\n            }\n            bool found = false; int bestArea=0,bestW=0,bestH=0;\n            for (int h = 1; h <= maxRows; ++h) {\n                int w = rowLen[0];\n                for (int t = 1; t < h; ++t) w = min(w, rowLen[t]);\n                if (w <= 0) break;\n                int area = w * h;\n                if (area < 2) continue;\n                vector<int> cand; cand.reserve(area);\n                for (int dy = 0; dy < h; ++dy)\n                    for (int dx = 0; dx < w; ++dx)\n                        cand.push_back(grid1[(sx+dx)*D + (sy+dy)]);\n                int minx=INT_MAX,miny=INT_MAX,maxx=INT_MIN,maxy=INT_MIN;\n                for (int id : cand) {\n                    minx = min(minx, p2[id].x);\n                    maxx = max(maxx, p2[id].x);\n                    miny = min(miny, p2[id].y);\n                    maxy = max(maxy, p2[id].y);\n                }\n                int w2 = maxx - minx + 1;\n                int h2 = maxy - miny + 1;\n                if (w2 * h2 != (int)cand.size()) continue;\n                unordered_set<int> mark; mark.reserve(cand.size()*2);\n                for (int id : cand) mark.insert(id);\n                bool ok = true;\n                for (int yy = miny; yy <= maxy && ok; ++yy) {\n                    for (int xx = minx; xx <= maxx; ++xx) {\n                        int id = grid2[xx*D + yy];\n                        if (id == 0 || !mark.count(id)) { ok=false; break; }\n                    }\n                }\n                if (!ok) continue;\n                if (area > bestArea) { bestArea=area; bestW=w; bestH=h; found=true; }\n            }\n            if (!found) return false;\n            rectIDs.clear();\n            for (int dy = 0; dy < bestH; ++dy)\n                for (int dx = 0; dx < bestW; ++dx)\n                    rectIDs.push_back(grid1[(sx+dx)*D + (sy+dy)]);\n            return true;\n        };\n\n        // Greedy rectangle merging\n        for (int y = 0; y < D; ++y) {\n            for (int x = 0; x < D; ++x) {\n                int id = grid1[x*D + y];\n                if (id == 0 || usedRect[id]) continue;\n                vector<int> rectIDs;\n                if (try_rectangle_from(x, y, rectIDs)) {\n                    if ((int)rectIDs.size() >= 2) {\n                        int keep = rectIDs[0];\n                        for (int i = 1; i < (int)rectIDs.size(); ++i) dsu.unite(keep, rectIDs[i]);\n                        for (int id2 : rectIDs) usedRect[id2] = 1;\n                    } else {\n                        usedRect[id] = 1;\n                    }\n                }\n            }\n        }\n\n        // Line merging leftover\n        vector<int> leftIDs;\n        for (int id : ids) if (!usedRect[id]) leftIDs.push_back(id);\n        if (leftIDs.empty()) continue;\n\n        vector<char> usedLine(K+1, 0);\n        vector<int> grid1L(D*D, 0);\n        for (int id : leftIDs) grid1L[p1[id].x*D + p1[id].y] = id;\n\n        auto collect_line = [&](int seed, int dx, int dy) -> vector<int> {\n            vector<int> line;\n            if (usedLine[seed]) return line;\n            vector<int> forward;\n            int x = p1[seed].x, y = p1[seed].y;\n            while (true) {\n                int nx = x + dx, ny = y + dy;\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D) break;\n                int nid = grid1L[nx*D + ny];\n                if (nid == 0 || usedLine[nid]) break;\n                forward.push_back(nid);\n                x = nx; y = ny;\n            }\n            vector<int> backward;\n            x = p1[seed].x; y = p1[seed].y;\n            while (true) {\n                int nx = x - dx, ny = y - dy;\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D) break;\n                int nid = grid1L[nx*D + ny];\n                if (nid == 0 || usedLine[nid]) break;\n                backward.push_back(nid);\n                x = nx; y = ny;\n            }\n            for (int i = (int)backward.size() - 1; i >= 0; --i) line.push_back(backward[i]);\n            line.push_back(seed);\n            for (int v : forward) line.push_back(v);\n            return line;\n        };\n\n        auto split_by_arr2 = [&](const vector<int>& line) -> vector<vector<int>> {\n            vector<vector<int>> segs;\n            int n = (int)line.size();\n            int s = 0;\n            while (s < n) {\n                int bestE = -1;\n                vector<pair<int,int>> pos;\n                pos.reserve(n - s);\n                for (int e = s; e < n; ++e) {\n                    pos.emplace_back(p2[line[e]].x, p2[line[e]].y);\n                    if ((int)pos.size() >= 2) {\n                        if (isContiguousLine(pos, D)) bestE = e;\n                    }\n                }\n                if (bestE >= s + 1) {\n                    vector<int> seg(line.begin() + s, line.begin() + bestE + 1);\n                    segs.push_back(move(seg));\n                    s = bestE + 1;\n                } else {\n                    s++;\n                }\n            }\n            return segs;\n        };\n\n        for (int id : leftIDs) {\n            if (usedLine[id]) continue;\n            vector<vector<int>> bestSegs;\n            int bestSum = 0;\n            for (int dcase = 0; dcase < 2; ++dcase) {\n                int dx = (dcase == 0) ? 1 : 0;\n                int dy = (dcase == 0) ? 0 : 1;\n                vector<int> line = collect_line(id, dx, dy);\n                if (line.empty()) continue;\n                auto segs = split_by_arr2(line);\n                int sum = 0;\n                for (auto &sg : segs) sum += (int)sg.size();\n                if (sum > bestSum) {\n                    bestSum = sum;\n                    bestSegs = move(segs);\n                }\n            }\n            for (auto &sg : bestSegs) {\n                if ((int)sg.size() >= 2) {\n                    int keep = sg[0];\n                    for (int j = 1; j < (int)sg.size(); ++j) dsu.unite(keep, sg[j]);\n                    for (int v : sg) usedLine[v] = 1;\n                }\n            }\n        }\n    }\n\n    // Apply DSU and compress IDs\n    for (int p = 0; p < N; ++p) {\n        if (res.b1[p] > 0) res.b1[p] = dsu.find(res.b1[p]);\n        if (res.b2[p] > 0) res.b2[p] = dsu.find(res.b2[p]);\n    }\n    vector<char> present(res.nblocks + 1, 0);\n    for (int p = 0; p < N; ++p) { int id = res.b1[p]; if (id > 0) present[id] = 1; }\n    for (int p = 0; p < N; ++p) { int id = res.b2[p]; if (id > 0) present[id] = 1; }\n    vector<int> remap(res.nblocks + 1, 0);\n    int nid = 0;\n    for (int id = 1; id <= res.nblocks; ++id) {\n        if (present[id]) remap[id] = ++nid;\n    }\n    for (int p = 0; p < N; ++p) {\n        int id = res.b1[p]; if (id > 0) res.b1[p] = remap[id];\n    }\n    for (int p = 0; p < N; ++p) {\n        int id = res.b2[p]; if (id > 0) res.b2[p] = remap[id];\n    }\n    res.nblocks = nid;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D; if(!(cin>>D)) return 0;\n    vector<string> f[2], r[2];\n    for(int t=0;t<2;++t){\n        f[t].resize(D); for(int i=0;i<D;++i) cin>>f[t][i];\n        r[t].resize(D); for(int i=0;i<D;++i) cin >> r[t][i];\n    }\n\n    auto start = chrono::steady_clock::now();\n    const double timeLimit = 3.2; // extended seconds for candidate search (within 6s)\n    double elapsed = 0.0;\n\n    // DP candidates (various lookaheads)\n    struct Cand { MinArrangement A; vector<Run> runs; };\n    vector<tuple<int,int,int>> dpParams = {\n        {1000, 0, 0},\n        {1000, 20, 5},\n        {1000, 50, 10},\n        {1000, 150, 30},\n        {1500, 80, 20},\n        {2000, 120, 30}\n    };\n    vector<Cand> cand1, cand2;\n    cand1.reserve(dpParams.size());\n    cand2.reserve(dpParams.size());\n    for(auto [Wp, Wn, Wn2] : dpParams){\n        Cand c1, c2;\n        c1.A = build_min_arrangement_dp(f[0], r[0], D, Wp, Wn, Wn2);\n        c1.runs = extract_runs(c1.A);\n        cand1.push_back(move(c1));\n        c2.A = build_min_arrangement_dp(f[1], r[1], D, Wp, Wn, Wn2);\n        c2.runs = extract_runs(c2.A);\n        cand2.push_back(move(c2));\n    }\n\n    double bestPen = 1e100;\n    MinArrangement bestA1, bestA2;\n    vector<Run> bestR1, bestR2;\n\n    // Initialize best from DP cross combinations\n    for(auto& c1 : cand1) for(auto& c2 : cand2){\n        auto ps = evaluate_pairing(c1.runs, c2.runs);\n        if(ps.penalty < bestPen){\n            bestPen = ps.penalty;\n            bestA1 = c1.A; bestR1 = c1.runs;\n            bestA2 = c2.A; bestR2 = c2.runs;\n        }\n    }\n\n    // Randomized candidates with different run-length weights\n    uint32_t baseSeed = 146527u;\n    vector<int> lenWeights = {0, 2, 5, 10, 15, 20, 30, 40};\n    int iter = 0;\n    while(true){\n        uint32_t s1 = baseSeed + 10007u*(iter+1);\n        uint32_t s2 = baseSeed ^ (0x9E3779B9u * (iter + 137u));\n        int lw1 = lenWeights[iter % (int)lenWeights.size()];\n        int lw2 = lenWeights[(iter*3 + 1) % (int)lenWeights.size()];\n        MinArrangement A1 = build_min_arrangement_random_weighted(f[0], r[0], D, s1, lw1);\n        MinArrangement A2 = build_min_arrangement_random_weighted(f[1], r[1], D, s2, lw2);\n        auto runs1 = extract_runs(A1);\n        auto runs2 = extract_runs(A2);\n        auto ps = evaluate_pairing(runs1, runs2);\n        if(ps.penalty < bestPen){\n            bestPen = ps.penalty;\n            bestA1 = move(A1); bestR1 = move(runs1);\n            bestA2 = move(A2); bestR2 = move(runs2);\n        }\n        ++iter;\n        if((iter & 3)==0){\n            auto now = chrono::steady_clock::now();\n            elapsed = chrono::duration<double>(now - start).count();\n            if(elapsed > timeLimit) break;\n        }\n        if(iter > 4000) break; // safety cap\n    }\n\n    // Assign sticks to block IDs with metadata for shared sticks\n    AssignResult res = assign_blocks_from_runs_with_meta(bestR1, bestR2, D);\n\n    // Align shared pairs to maximize identical z0 and locality, then merge rectangles/lines\n    align_shared_pairs(res);\n    merge_shared_rectangles(res);\n\n    // Validate; fallback to domino-based plan if invalid (very rare)\n    bool ok1 = validate_arr(D, f[0], r[0], res.b1);\n    bool ok2 = validate_arr(D, f[1], r[1], res.b2);\n    if(!(ok1 && ok2)){\n        vector<int> B1 = domino_arrangement(f[0], r[0], D);\n        vector<int> B2 = domino_arrangement(f[1], r[1], D);\n        int N = D*D*D;\n        int id = 0;\n        for(int p=0;p<N;++p) if(B1[p]!=0) B1[p] = ++id;\n        for(int p=0;p<N;++p) if(B2[p]!=0) B2[p] = ++id;\n        cout << id << \"\\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 p=idx3(D,x,y,z);\n            cout << B1[p] << ((x==D-1&&y==D-1&&z==D-1)?'\\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            int p=idx3(D,x,y,z);\n            cout << B2[p] << ((x==D-1&&y==D-1&&z==D-1)?'\\n':' ');\n        }\n        return 0;\n    }\n\n    // Output final\n    cout << res.nblocks << \"\\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 p=idx3(D,x,y,z);\n        cout << res.b1[p] << ((x==D-1&&y==D-1&&z==D-1)?'\\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        int p=idx3(D,x,y,z);\n        cout << res.b2[p] << ((x==D-1&&y==D-1&&z==D-1)?'\\n':' ');\n    }\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge { int u, v; long long w; };\n\nstruct Solution {\n    vector<int> P;           // size N\n    vector<char> edgeOn;     // size M\n    long long edgeSum = 0;\n    long long pSum = 0;\n    long long S = (1LL<<62);\n};\n\nstatic inline int sqrt_ceil_ll(long long x) {\n    if (x <= 0) return 0;\n    long double dx = (long double)x;\n    long long r = (long long)floor(sqrt(dx) + 1e-12L);\n    while ((r+1) * (r+1) <= x) ++r;\n    while (r * r > x) --r;\n    if (r * r == x) return (int)r;\n    return (int)(r + 1);\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, r;\n    DSU(int n=0):n(n),p(n),r(n,0){ iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n    bool unite(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, M, K;\n    if(!(cin>>N>>M>>K)) return 0;\n    vector<long long> xs(N), ys(N);\n    for(int i=0;i<N;i++){ cin>>xs[i]>>ys[i]; }\n    vector<Edge> edges(M);\n    for(int j=0;j<M;j++){\n        int u,v; long long w;\n        cin>>u>>v>>w; --u; --v;\n        edges[j] = {u,v,w};\n    }\n    vector<long long> ax(K), ay(K);\n    for(int k=0;k<K;k++){ cin>>ax[k]>>ay[k]; }\n\n    // adjacency\n    vector<vector<pair<int,int>>> adj(N);\n    for(int e=0;e<M;e++){\n        int u=edges[e].u, v=edges[e].v;\n        adj[u].push_back({v,e});\n        adj[v].push_back({u,e});\n    }\n\n    // Precompute distances station-resident and coverage sets\n    const long long R2 = 5000LL*5000LL;\n    vector<vector<int>> covList(N);\n    vector<vector<uint64_t>> covBits(N);\n    int B = (K + 63) >> 6;\n    uint64_t lastMask = (K%64 == 0) ? ~0ULL : ((1ULL << (K%64)) - 1ULL);\n    vector<vector<int>> d2sr(N, vector<int>(K, 0));\n    vector<vector<int>> nearStationsForResid(K);\n    for(int i=0;i<N;i++){\n        covBits[i].assign(B, 0ULL);\n        for(int k=0;k<K;k++){\n            long long dx = xs[i] - ax[k];\n            long long dy = ys[i] - ay[k];\n            long long d2 = dx*dx + dy*dy;\n            if (d2 > INT_MAX) d2 = INT_MAX;\n            d2sr[i][k] = (int)d2;\n            if(d2 <= R2){\n                covList[i].push_back(k);\n                nearStationsForResid[k].push_back(i);\n                int blk = k >> 6, off = k & 63;\n                covBits[i][blk] |= (1ULL << off);\n            }\n        }\n    }\n\n    // Precompute nearest stations by Euclidean distance (for terminal swap)\n    vector<vector<int>> nearStationsEuclid(N);\n    for(int i=0;i<N;i++){\n        vector<pair<long long,int>> tmp;\n        tmp.reserve(N);\n        for(int j=0;j<N;j++){\n            long long dx=xs[i]-xs[j], dy=ys[i]-ys[j];\n            tmp.emplace_back(dx*dx+dy*dy, j);\n        }\n        sort(tmp.begin(), tmp.end());\n        nearStationsEuclid[i].reserve(N);\n        for(auto &p: tmp) nearStationsEuclid[i].push_back(p.second);\n    }\n\n    // All-pairs shortest paths (Dijkstra from each node)\n    const long long INF = (1LL<<60);\n    vector<vector<long long>> distW(N, vector<long long>(N, INF));\n    vector<vector<int>> prevV(N, vector<int>(N, -1));\n    vector<vector<int>> prevE(N, vector<int>(N, -1));\n    auto dijkstra_from = [&](int s){\n        auto &d = distW[s];\n        auto &pv = prevV[s];\n        auto &pe = prevE[s];\n        fill(d.begin(), d.end(), INF);\n        fill(pv.begin(), pv.end(), -1);\n        fill(pe.begin(), pe.end(), -1);\n        d[s] = 0;\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        pq.push({0, s});\n        while(!pq.empty()){\n            auto [cd,u] = pq.top(); pq.pop();\n            if(cd != d[u]) continue;\n            for(auto [v,eid] : adj[u]){\n                long long nd = cd + edges[eid].w;\n                if(nd < d[v]){\n                    d[v] = nd;\n                    pv[v] = u;\n                    pe[v] = eid;\n                    pq.push({nd, v});\n                }\n            }\n        }\n    };\n    for(int i=0;i<N;i++) dijkstra_from(i);\n\n    // SPT from root 0\n    vector<int> parentSPT(N, -1);\n    vector<int> parentEdgeSPT(N, -1);\n    for(int v=0; v<N; v++){\n        parentSPT[v] = prevV[0][v];\n        parentEdgeSPT[v] = prevE[0][v];\n    }\n\n    auto build_inV = [&](const vector<char>& edgeOn)->vector<char>{\n        vector<char> inV(N, 0);\n        queue<int> q;\n        inV[0] = 1; q.push(0);\n        while(!q.empty()){\n            int u=q.front(); q.pop();\n            for(auto [v,eid]: adj[u]){\n                if(edgeOn[eid] && !inV[v]){\n                    inV[v]=1; q.push(v);\n                }\n            }\n        }\n        return inV;\n    };\n\n    auto count_covered_bits = [&](const vector<char>& inV)->int{\n        vector<uint64_t> uni(B, 0ULL);\n        for(int i=0;i<N;i++){\n            if(!inV[i]) continue;\n            for(int b=0;b<B;b++) uni[b] |= covBits[i][b];\n        }\n        long long cnt = 0;\n        for(int b=0;b<B;b++){\n            uint64_t mask = (b==B-1 ? lastMask : ~0ULL);\n            cnt += __builtin_popcountll(uni[b] & mask);\n        }\n        return (int)cnt;\n    };\n\n    auto prune_unused_leaves = [&](vector<char>& edgeOn, const vector<int>& P){\n        vector<vector<int>> inc(N);\n        for(int e=0;e<M;e++){\n            if(edgeOn[e]){\n                int u=edges[e].u, v=edges[e].v;\n                inc[u].push_back(e);\n                inc[v].push_back(e);\n            }\n        }\n        vector<int> deg(N,0);\n        for(int i=0;i<N;i++){\n            for(int e: inc[i]) if(edgeOn[e]) deg[i]++;\n        }\n        deque<int> dq;\n        for(int i=0;i<N;i++){\n            if(i==0) continue;\n            if(deg[i]==1 && P[i]==0) dq.push_back(i);\n        }\n        vector<char> rm(N,0);\n        while(!dq.empty()){\n            int v = dq.front(); dq.pop_front();\n            if(rm[v]) continue;\n            if(deg[v]!=1 || P[v]!=0) continue;\n            int euniq=-1, u=-1;\n            for(int eid: inc[v]){\n                if(edgeOn[eid]){\n                    euniq=eid;\n                    u = (edges[eid].u==v? edges[eid].v : edges[eid].u);\n                    break;\n                }\n            }\n            if(euniq==-1) continue;\n            edgeOn[euniq]=0;\n            deg[v]--; deg[u]--;\n            rm[v]=1;\n            if(u!=0 && deg[u]==1 && P[u]==0) dq.push_back(u);\n        }\n    };\n\n    struct FastEval {\n        vector<char> inV;\n        vector<int> bestTo;   // size K\n        vector<int> bestD2;   // size K\n        vector<int> P;\n        long long pSum=0, edgeSum=0, S=0;\n        bool allCovered=false;\n    };\n\n    auto fast_evaluate = [&](const vector<char>& edgeOn){\n        FastEval fe;\n        fe.edgeSum = 0;\n        for(int e=0;e<M;e++) if(edgeOn[e]) fe.edgeSum += edges[e].w;\n        fe.inV = build_inV(edgeOn);\n        int covered = count_covered_bits(fe.inV);\n        fe.allCovered = (covered == K);\n        fe.bestTo.assign(K, -1);\n        fe.bestD2.assign(K, INT_MAX);\n        for(int k=0;k<K;k++){\n            int besti=-1, bestd2 = INT_MAX;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                int d2 = d2sr[i][k];\n                if(d2 < bestd2){\n                    bestd2 = d2; besti = i;\n                }\n            }\n            fe.bestTo[k] = besti;\n            fe.bestD2[k] = bestd2;\n        }\n        vector<long long> maxD2(N, 0);\n        for(int k=0;k<K;k++){\n            int i = fe.bestTo[k];\n            if(i<0) continue;\n            long long d2 = fe.bestD2[k];\n            if(d2 > maxD2[i]) maxD2[i] = d2;\n        }\n        fe.P.assign(N, 0);\n        fe.pSum = 0;\n        for(int i=0;i<N;i++){\n            if(!fe.inV[i]) { fe.P[i]=0; continue; }\n            int rad = sqrt_ceil_ll(maxD2[i]);\n            if(rad>5000) rad=5000;\n            fe.P[i]=rad;\n            fe.pSum += 1LL*rad*rad;\n        }\n        fe.S = fe.edgeSum + fe.pSum;\n        return fe;\n    };\n\n    struct FullEval {\n        Solution sol;\n        vector<char> inV;\n        vector<int> assignTo; // K -> i\n    };\n\n    auto optimize_assignment = [&](const vector<char>& edgeOn){\n        FullEval fe;\n        fe.inV = build_inV(edgeOn);\n        fe.assignTo.assign(K, -1);\n        vector<vector<int>> assigned(N);\n        vector<multiset<int>> dsets(N);\n        vector<long long> maxD2(N, 0);\n        for(int k=0;k<K;k++){\n            int besti=-1, bestd2=INT_MAX;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                int d2 = d2sr[i][k];\n                if(d2 < bestd2){ bestd2=d2; besti=i; }\n            }\n            fe.assignTo[k]=besti;\n            if(besti>=0){\n                assigned[besti].push_back(k);\n                dsets[besti].insert(bestd2);\n                if(bestd2 > maxD2[besti]) maxD2[besti] = bestd2;\n            }\n        }\n        vector<int> P(N,0);\n        vector<int> rad2(N,0);\n        for(int i=0;i<N;i++){\n            if(!fe.inV[i]) { P[i]=0; rad2[i]=0; continue; }\n            int rad = sqrt_ceil_ll(maxD2[i]);\n            if(rad>5000) rad=5000;\n            P[i]=rad;\n            rad2[i]=rad*rad;\n        }\n\n        auto recompute_max_after_removal = [&](int i, int d2val)->long long{\n            if(dsets[i].empty()) return 0;\n            auto it = dsets[i].find(d2val);\n            if(it == dsets[i].end()){\n                return (long long)(*dsets[i].rbegin());\n            }\n            dsets[i].erase(it);\n            long long res = dsets[i].empty() ? 0 : (long long)(*dsets[i].rbegin());\n            dsets[i].insert(d2val);\n            return res;\n        };\n\n        // Step A: move unique farthest to a station that already covers it\n        bool changedA = true;\n        int guardA = 0;\n        while(changedA && guardA < 2*N){\n            changedA = false; guardA++;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                if(dsets[i].empty()) continue;\n                int dmax = *prev(dsets[i].end());\n                int cntMax = (int)dsets[i].count(dmax);\n                if(cntMax != 1) continue;\n                int r = -1;\n                for(int idx : assigned[i]){\n                    if(d2sr[i][idx] == dmax){ r = idx; break; }\n                }\n                if(r==-1) continue;\n                int jbest = -1;\n                for(int j : nearStationsForResid[r]){\n                    if(!fe.inV[j] || j==i) continue;\n                    if(rad2[j] >= d2sr[j][r]){ jbest = j; break; }\n                }\n                if(jbest==-1) continue;\n                dsets[i].erase(dsets[i].find(dmax));\n                auto itv = find(assigned[i].begin(), assigned[i].end(), r);\n                if(itv != assigned[i].end()) assigned[i].erase(itv);\n                assigned[jbest].push_back(r);\n                dsets[jbest].insert(d2sr[jbest][r]);\n                fe.assignTo[r] = jbest;\n                long long newMaxI = dsets[i].empty() ? 0 : (long long)(*dsets[i].rbegin());\n                int newPi = sqrt_ceil_ll(newMaxI); if(newPi>5000) newPi=5000;\n                P[i] = newPi; rad2[i] = newPi*newPi;\n                changedA = true;\n            }\n        }\n\n        // Step B: move an outlier to reduce total pSum (within 5000 only)\n        bool improved = true;\n        int iter = 0;\n        while(improved && iter < 300){\n            improved = false; iter++;\n            long long bestDelta = 0;\n            int bi=-1, bj=-1, br=-1;\n            for(int i=0;i<N;i++){\n                if(!fe.inV[i]) continue;\n                if(dsets[i].empty()) continue;\n                int dmax = *prev(dsets[i].end());\n                int r = -1;\n                for(int idx : assigned[i]){\n                    if(d2sr[i][idx] == dmax){ r = idx; break; }\n                }\n                if(r==-1) continue;\n                long long newMaxI_d2 = recompute_max_after_removal(i, dmax);\n                int newPi = sqrt_ceil_ll(newMaxI_d2); if(newPi>5000) newPi=5000;\n                int newPi_sq = newPi*newPi;\n                int curPi_sq = rad2[i];\n                for(int j : nearStationsForResid[r]){\n                    if(!fe.inV[j] || j==i) continue;\n                    long long curMaxJ_d2 = dsets[j].empty() ? 0 : (long long)(*dsets[j].rbegin());\n                    long long newMaxJ_d2 = max(curMaxJ_d2, (long long)d2sr[j][r]);\n                    int newPj = sqrt_ceil_ll(newMaxJ_d2);\n                    if(newPj>5000) newPj=5000;\n                    int newPj_sq = newPj*newPj;\n                    long long curPj_sq = rad2[j];\n                    long long delta = (long long)newPi_sq + newPj_sq - curPi_sq - curPj_sq;\n                    if(delta < bestDelta){\n                        bestDelta = delta;\n                        bi = i; bj = j; br = r;\n                    }\n                }\n            }\n            if(bestDelta < 0 && bi>=0){\n                int i = bi, j = bj, r = br;\n                int dmax = d2sr[i][r];\n                auto itf = dsets[i].find(dmax);\n                if(itf != dsets[i].end()) dsets[i].erase(itf);\n                auto itv = find(assigned[i].begin(), assigned[i].end(), r);\n                if(itv != assigned[i].end()) assigned[i].erase(itv);\n                dsets[j].insert(d2sr[j][r]);\n                assigned[j].push_back(r);\n                fe.assignTo[r] = j;\n                long long newMaxI_d2 = dsets[i].empty() ? 0 : (long long)(*dsets[i].rbegin());\n                int newPi2 = sqrt_ceil_ll(newMaxI_d2); if(newPi2>5000) newPi2=5000;\n                P[i] = newPi2; rad2[i] = newPi2*newPi2;\n                long long newMaxJ_d2 = (long long)(*dsets[j].rbegin());\n                int newPj2 = sqrt_ceil_ll(newMaxJ_d2); if(newPj2>5000) newPj2=5000;\n                P[j] = newPj2; rad2[j] = newPj2*newPj2;\n                improved = true;\n            }\n        }\n\n        long long pSum = 0;\n        for(int i=0;i<N;i++) pSum += 1LL*P[i]*P[i];\n        long long edgeSum = 0;\n        for(int e=0;e<M;e++) if(edgeOn[e]) edgeSum += edges[e].w;\n        fe.sol.P = P;\n        fe.sol.edgeOn = edgeOn;\n        fe.sol.pSum = pSum;\n        fe.sol.edgeSum = edgeSum;\n        fe.sol.S = pSum + edgeSum;\n        return fe;\n    };\n\n    // Build metric MST for terminals (Steinerization backbone)\n    auto build_tree_for_terminals = [&](const vector<int>& T)->vector<char>{\n        int TS = (int)T.size();\n        vector<char> edgeOn(M, 0);\n        if(TS <= 1) return edgeOn;\n        vector<char> used(TS,0);\n        vector<long long> low(TS, INF);\n        vector<int> par(TS,-1);\n        used[0]=1;\n        for(int i=1;i<TS;i++){ low[i]=distW[T[0]][T[i]]; par[i]=0; }\n        vector<pair<int,int>> mstPairs; mstPairs.reserve(TS-1);\n        for(int it=0; it<TS-1; it++){\n            int v=-1; long long best=INF;\n            for(int j=0;j<TS;j++){\n                if(!used[j] && low[j] < best){\n                    best=low[j]; v=j;\n                }\n            }\n            if(v==-1) break;\n            used[v]=1;\n            mstPairs.emplace_back(T[par[v]], T[v]);\n            for(int j=0;j<TS;j++){\n                if(!used[j]){\n                    long long nd = distW[T[v]][T[j]];\n                    if(nd < low[j]){ low[j]=nd; par[j]=v; }\n                }\n            }\n        }\n        for(auto [u,v] : mstPairs){\n            int cur = v;\n            while(cur != u){\n                int eid = prevE[u][cur];\n                if(eid<0) break;\n                edgeOn[eid]=1;\n                cur = prevV[u][cur];\n                if(cur<0) break;\n            }\n        }\n        vector<int> unionEdges;\n        for(int e=0;e<M;e++) if(edgeOn[e]) unionEdges.push_back(e);\n        sort(unionEdges.begin(), unionEdges.end(), [&](int a,int b){ return edges[a].w < edges[b].w; });\n        DSU dsu(N);\n        vector<char> edgeOn2(M,0);\n        for(int e: unionEdges){\n            int u=edges[e].u, v=edges[e].v;\n            if(dsu.unite(u,v)) edgeOn2[e]=1;\n        }\n        vector<char> isTerm(N,0);\n        for(int v: T) isTerm[v]=1;\n        vector<vector<int>> inc(N);\n        for(int e=0;e<M;e++){\n            if(!edgeOn2[e]) continue;\n            int u=edges[e].u, v=edges[e].v;\n            inc[u].push_back(e);\n            inc[v].push_back(e);\n        }\n        vector<int> deg(N,0);\n        for(int i=0;i<N;i++){\n            for(int e: inc[i]) if(edgeOn2[e]) deg[i]++;\n        }\n        deque<int> dq;\n        for(int i=0;i<N;i++) if(deg[i]==1 && !isTerm[i]) dq.push_back(i);\n        vector<char> rm(N,0);\n        while(!dq.empty()){\n            int v=dq.front(); dq.pop_front();\n            if(rm[v]) continue;\n            if(deg[v]!=1 || isTerm[v]) continue;\n            int euniq=-1, u=-1;\n            for(int eid: inc[v]) if(edgeOn2[eid]){ euniq=eid; u=(edges[eid].u==v? edges[eid].v : edges[eid].u); break; }\n            if(euniq==-1) continue;\n            edgeOn2[euniq]=0; deg[v]--; deg[u]--; rm[v]=1;\n            if(deg[u]==1 && !isTerm[u]) dq.push_back(u);\n        }\n        return edgeOn2;\n    };\n\n    auto steinerize_from_P = [&](const Solution& sol)->Solution{\n        vector<int> T;\n        T.push_back(0);\n        for(int i=0;i<N;i++) if(sol.P[i] > 0 && i!=0) T.push_back(i);\n        vector<char> edgeOn = build_tree_for_terminals(T);\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        return full2.sol;\n    };\n\n    // Shrink radii pass (safe)\n    auto shrink_radii = [&](Solution& s){\n        vector<char> inV = build_inV(s.edgeOn);\n        bool changed = true;\n        int iter=0;\n        while(changed && iter<3){\n            iter++;\n            changed = false;\n            vector<int> coverCnt(K, 0);\n            for(int i=0;i<N;i++){\n                if(!inV[i] || s.P[i]==0) continue;\n                long long rad2 = 1LL*s.P[i]*s.P[i];\n                for(int k: covList[i]){\n                    if((long long)d2sr[i][k] <= rad2) coverCnt[k]++;\n                }\n            }\n            for(int i=0;i<N;i++){\n                if(!inV[i] || s.P[i]==0) continue;\n                long long need2 = 0;\n                long long rad2 = 1LL*s.P[i]*s.P[i];\n                for(int k: covList[i]){\n                    int d2 = d2sr[i][k];\n                    if((long long)d2 <= rad2 && coverCnt[k]==1){\n                        if((long long)d2 > need2) need2 = d2;\n                    }\n                }\n                int newP = sqrt_ceil_ll(need2);\n                if(newP < s.P[i]){\n                    s.P[i] = newP;\n                    changed = true;\n                }\n            }\n        }\n        s.pSum = 0;\n        for(int i=0;i<N;i++) s.pSum += 1LL*s.P[i]*s.P[i];\n        s.edgeSum = 0;\n        for(int e=0;e<M;e++) if(s.edgeOn[e]) s.edgeSum += edges[e].w;\n        s.S = s.pSum + s.edgeSum;\n    };\n\n    // Initializers\n    auto build_solution_setcover_dyn = [&](){\n        vector<char> selected(N, 0);\n        vector<char> uncovered(K, 1);\n        int remaining = K;\n        vector<long long> minConnectCost(N, INF);\n        for(int i=0;i<N;i++) minConnectCost[i] = distW[0][i];\n        selected[0] = 1;\n        while(remaining > 0){\n            int besti = -1;\n            long long bestScore = LLONG_MIN/4;\n            int bestc = -1;\n            for(int i=0;i<N;i++){\n                if(selected[i]) continue;\n                int cnt = 0;\n                for(int k: covList[i]) if(uncovered[k]) cnt++;\n                if(cnt == 0) continue;\n                long long score = 1'000'000LL * cnt - minConnectCost[i];\n                if(score > bestScore || (score == bestScore && cnt > bestc)){\n                    bestScore = score; bestc = cnt; besti = i;\n                }\n            }\n            if(besti==-1){\n                int bi=-1, bc=-1;\n                for(int i=0;i<N;i++){\n                    if(selected[i]) continue;\n                    int cnt=0; for(int k: covList[i]) if(uncovered[k]) cnt++;\n                    if(cnt>bc){bc=cnt; bi=i;}\n                }\n                if(bi==-1) break;\n                besti=bi;\n            }\n            selected[besti]=1;\n            for(int k : covList[besti]) if(uncovered[k]){ uncovered[k]=0; remaining--; }\n            for(int i=0;i<N;i++){\n                if(distW[besti][i] < minConnectCost[i]) minConnectCost[i] = distW[besti][i];\n            }\n        }\n        vector<int> coverCnt(K, 0);\n        for(int i=0;i<N;i++) if(selected[i]) for(int k: covList[i]) coverCnt[k]++;\n        bool ch = true; int safe=0;\n        while(ch && safe++<N){\n            ch=false;\n            for(int i=0;i<N;i++){\n                if(!selected[i] || i==0) continue;\n                bool canRem=true;\n                for(int k: covList[i]) if(coverCnt[k]<=1){canRem=false;break;}\n                if(canRem){ selected[i]=0; for(int k: covList[i]) coverCnt[k]--; ch=true; }\n            }\n        }\n        vector<int> T; T.push_back(0);\n        for(int i=0;i<N;i++) if(selected[i] && i!=0) T.push_back(i);\n        vector<char> edgeOn = build_tree_for_terminals(T);\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        Solution res = full2.sol;\n        shrink_radii(res);\n        return res;\n    };\n\n    auto build_solution_setcover_simple = [&](){\n        vector<char> selected(N, 0);\n        vector<char> uncovered(K, 1);\n        int remaining = K;\n        vector<long long> dRoot(N);\n        for(int i=0;i<N;i++) dRoot[i] = distW[0][i];\n        while(remaining > 0){\n            int besti = -1, bestc = -1;\n            long long tieRoot = (1LL<<60);\n            for(int i=0;i<N;i++){\n                if(selected[i]) continue;\n                int cnt = 0;\n                for(int k: covList[i]) if(uncovered[k]) cnt++;\n                if(cnt > bestc || (cnt==bestc && dRoot[i] < tieRoot)){\n                    bestc = cnt; tieRoot = dRoot[i]; besti = i;\n                }\n            }\n            if(besti==-1 || bestc<=0) break;\n            selected[besti]=1;\n            for(int k : covList[besti]) if(uncovered[k]){ uncovered[k]=0; remaining--; }\n        }\n        vector<int> coverCnt(K, 0);\n        for(int i=0;i<N;i++) if(selected[i]) for(int k: covList[i]) coverCnt[k]++;\n        bool ch = true; int safe=0;\n        while(ch && safe++<N){\n            ch=false;\n            for(int i=0;i<N;i++){\n                if(!selected[i]) continue;\n                bool canRem=true;\n                for(int k: covList[i]) if(coverCnt[k]<=1){canRem=false;break;}\n                if(canRem){ selected[i]=0; for(int k: covList[i]) coverCnt[k]--; ch=true; }\n            }\n        }\n        vector<int> T; T.push_back(0);\n        for(int i=0;i<N;i++) if(selected[i] && i!=0) T.push_back(i);\n        vector<char> edgeOn = build_tree_for_terminals(T);\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        Solution res = full2.sol;\n        shrink_radii(res);\n        return res;\n    };\n\n    auto build_solution_spt = [&](){\n        vector<char> inV(N, 0);\n        vector<char> edgeOn(M, 0);\n        inV[0]=1;\n        vector<uint64_t> covered(B, 0ULL);\n        for(int b=0;b<B;b++) covered[b] |= covBits[0][b];\n        auto allCovered = [&](){\n            for(int b=0;b<B;b++){\n                uint64_t mask = (b==B-1? lastMask : ~0ULL);\n                if( (covered[b] & mask) != mask) return false;\n            }\n            return true;\n        };\n        vector<uint64_t> tmp(B);\n        while(!allCovered()){\n            int bestV = -1;\n            long long bestGain = -1;\n            long long bestIncW = (1LL<<60);\n            for(int v=0; v<N; v++){\n                if(inV[v]) continue;\n                for(int b=0;b<B;b++) tmp[b]=0ULL;\n                long long incW=0;\n                int cur=v; bool any=false;\n                while(cur!=-1 && !inV[cur]){\n                    for(int b=0;b<B;b++) tmp[b] |= covBits[cur][b];\n                    int pe = parentEdgeSPT[cur];\n                    if(pe>=0) incW += edges[pe].w;\n                    cur = parentSPT[cur];\n                    any=true;\n                }\n                if(!any) continue;\n                long long gain=0;\n                for(int b=0;b<B;b++){\n                    uint64_t mask = (b==B-1? lastMask : ~0ULL);\n                    uint64_t nc = (~covered[b]) & mask;\n                    uint64_t add = tmp[b] & nc;\n                    gain += __builtin_popcountll(add);\n                }\n                if(gain > bestGain || (gain==bestGain && incW < bestIncW)){\n                    bestGain=gain; bestIncW=incW; bestV=v;\n                }\n            }\n            if(bestV==-1) break;\n            for(int b=0;b<B;b++) tmp[b]=0ULL;\n            int cur=bestV;\n            while(cur!=-1 && !inV[cur]){\n                for(int b=0;b<B;b++) tmp[b] |= covBits[cur][b];\n                int pe = parentEdgeSPT[cur];\n                if(pe>=0) edgeOn[pe]=1;\n                inV[cur]=1;\n                cur = parentSPT[cur];\n            }\n            for(int b=0;b<B;b++) covered[b] |= tmp[b];\n        }\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        Solution res = full2.sol;\n        shrink_radii(res);\n        return res;\n    };\n\n    // Local searches\n    auto removal_pass = [&](Solution cur)->Solution{\n        vector<char> edgeOn = cur.edgeOn;\n        auto fe = fast_evaluate(edgeOn);\n        long long curS = fe.S;\n        vector<int> onEdges;\n        for(int e=0;e<M;e++) if(edgeOn[e]) onEdges.push_back(e);\n        sort(onEdges.begin(), onEdges.end(), [&](int a,int b){ return edges[a].w > edges[b].w; });\n        bool improved=true;\n        int rounds=0;\n        while(improved && rounds<2){\n            improved=false; rounds++;\n            for(int e : onEdges){\n                if(!edgeOn[e]) continue;\n                edgeOn[e]=0;\n                vector<char> inV = build_inV(edgeOn);\n                int covered = count_covered_bits(inV);\n                if(covered < K){\n                    edgeOn[e]=1;\n                    continue;\n                }\n                auto fe2 = fast_evaluate(edgeOn);\n                if(fe2.S <= curS){\n                    fe = fe2;\n                    curS = fe2.S;\n                    improved=true;\n                }else{\n                    edgeOn[e]=1;\n                }\n            }\n        }\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        Solution res = full2.sol;\n        shrink_radii(res);\n        return res;\n    };\n\n    auto addition_pass = [&](Solution cur)->Solution{\n        vector<char> edgeOn = cur.edgeOn;\n        auto fe = fast_evaluate(edgeOn);\n        long long curS = fe.S;\n        int tries = 0;\n        while(tries < 12){\n            vector<char> inV = fe.inV;\n            vector<int>& bestD2 = fe.bestD2;\n            vector<pair<long long,int>> cand;\n            cand.reserve(M);\n            for(int e=0;e<M;e++){\n                if(edgeOn[e]) continue;\n                int u=edges[e].u, v=edges[e].v;\n                int a = inV[u], b = inV[v];\n                if(a ^ b){\n                    int t = a? v : u;\n                    long long better = 0;\n                    for(int k=0;k<K;k++){\n                        int d2 = d2sr[t][k];\n                        if(d2 < bestD2[k]) better++;\n                    }\n                    if(better>0){\n                        long long score = better*1000000LL - (edges[e].w / 1000LL);\n                        cand.emplace_back(score, e);\n                    }\n                }\n            }\n            if(cand.empty()) break;\n            sort(cand.begin(), cand.end(), greater<>());\n            bool added=false;\n            int upto = min((int)cand.size(), 10);\n            for(int idx=0; idx<upto; idx++){\n                int e = cand[idx].second;\n                edgeOn[e]=1;\n                auto fe2 = fast_evaluate(edgeOn);\n                if(fe2.allCovered && fe2.S < curS){\n                    fe = fe2;\n                    curS = fe2.S;\n                    added=true;\n                    break;\n                }else{\n                    edgeOn[e]=0;\n                }\n            }\n            if(!added) break;\n            tries++;\n        }\n        auto full = optimize_assignment(edgeOn);\n        vector<char> edgeOn2 = full.sol.edgeOn;\n        prune_unused_leaves(edgeOn2, full.sol.P);\n        auto full2 = optimize_assignment(edgeOn2);\n        Solution res = full2.sol;\n        shrink_radii(res);\n        return res;\n    };\n\n    auto path_addition_pass = [&](Solution cur)->Solution{\n        Solution bestS = cur;\n        auto fe = fast_evaluate(bestS.edgeOn);\n        vector<char> inV = fe.inV;\n        vector<pair<long long,int>> cand; // (score, t)\n        cand.reserve(N);\n        for(int t=0;t<N;t++){\n            if(inV[t]) continue;\n            long long better = 0;\n            for(int k=0;k<K;k++){\n                int d2 = d2sr[t][k];\n                if(d2 < fe.bestD2[k]) better++;\n            }\n            if(better==0) continue;\n            long long bestConn = (1LL<<60);\n            for(int s=0;s<N;s++){\n                if(!inV[s]) continue;\n                long long dw = distW[s][t];\n                if(dw < bestConn) bestConn = dw;\n            }\n            if(bestConn >= (1LL<<60)/2) continue;\n            long long score = better*1000000LL - (bestConn/1000LL);\n            cand.emplace_back(score, t);\n        }\n        if(cand.empty()) return bestS;\n        sort(cand.begin(), cand.end(), greater<>());\n        int tries = min(2, (int)cand.size());\n        for(int it=0; it<tries; it++){\n            int t = cand[it].second;\n            auto feNow = fast_evaluate(bestS.edgeOn);\n            vector<char> inVnow = feNow.inV;\n            long long bestConn = (1LL<<60);\n            int sBest = -1;\n            for(int s=0;s<N;s++){\n                if(!inVnow[s]) continue;\n                long long dw = distW[s][t];\n                if(dw < bestConn){ bestConn = dw; sBest = s; }\n            }\n            if(sBest==-1) continue;\n            vector<char> edgeOn = bestS.edgeOn;\n            int curv = t;\n            while(curv != sBest){\n                int eid = prevE[sBest][curv];\n                if(eid<0) break;\n                edgeOn[eid] = 1;\n                curv = prevV[sBest][curv];\n                if(curv<0) break;\n            }\n            auto full = optimize_assignment(edgeOn);\n            vector<char> edgeOn2 = full.sol.edgeOn;\n            prune_unused_leaves(edgeOn2, full.sol.P);\n            auto full2 = optimize_assignment(edgeOn2);\n            Solution candSol = full2.sol;\n            shrink_radii(candSol);\n            if(candSol.S < bestS.S){\n                bestS = candSol;\n            }\n        }\n        return bestS;\n    };\n\n    // New: edge replacement pass (replace heavy edge with cheaper path)\n    auto edge_replacement_pass = [&](Solution cur)->Solution{\n        Solution bestS = cur;\n        vector<int> onEdges;\n        for(int e=0;e<M;e++) if(cur.edgeOn[e]) onEdges.push_back(e);\n        sort(onEdges.begin(), onEdges.end(), [&](int a,int b){ return edges[a].w > edges[b].w; });\n        vector<char> inV0 = build_inV(cur.edgeOn);\n        int limit = min((int)onEdges.size(), 20);\n        for(int idx=0; idx<limit; idx++){\n            int e = onEdges[idx];\n            vector<char> edgeOn = bestS.edgeOn;\n            if(!edgeOn[e]) continue;\n            edgeOn[e] = 0;\n            vector<char> inV_A = build_inV(edgeOn);\n            vector<int> A_nodes, B_nodes;\n            for(int i=0;i<N;i++){\n                if(inV_A[i]) A_nodes.push_back(i);\n                else if(inV0[i]) B_nodes.push_back(i);\n            }\n            if(B_nodes.empty()) continue;\n            long long bestDW = (1LL<<60);\n            int aBest=-1, bBest=-1;\n            for(int a: A_nodes){\n                const auto &drow = distW[a];\n                for(int b: B_nodes){\n                    long long dw = drow[b];\n                    if(dw < bestDW){\n                        bestDW = dw; aBest=a; bBest=b;\n                    }\n                }\n            }\n            if(bestDW >= (1LL<<60)/2) continue;\n            int curv = bBest;\n            while(curv != aBest){\n                int eid = prevE[aBest][curv];\n                if(eid<0) { break; }\n                edgeOn[eid] = 1;\n                curv = prevV[aBest][curv];\n                if(curv<0) break;\n            }\n            auto full = optimize_assignment(edgeOn);\n            vector<char> edgeOn2 = full.sol.edgeOn;\n            prune_unused_leaves(edgeOn2, full.sol.P);\n            auto full2 = optimize_assignment(edgeOn2);\n            Solution candSol = full2.sol;\n            shrink_radii(candSol);\n            if(candSol.S < bestS.S){\n                bestS = candSol;\n                inV0 = build_inV(bestS.edgeOn);\n            }\n        }\n        return bestS;\n    };\n\n    auto ensure_full_coverage = [&](Solution& sol){\n        vector<char> inV = build_inV(sol.edgeOn);\n        auto isCoveredByP = [&](int k)->bool{\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                long long d2 = d2sr[i][k];\n                if(1LL*sol.P[i]*sol.P[i] >= d2) return true;\n            }\n            return false;\n        };\n        vector<int> uncovered;\n        uncovered.reserve(K);\n        for(int k=0;k<K;k++){\n            if(!isCoveredByP(k)) uncovered.push_back(k);\n        }\n        vector<int> needConnectResidents;\n        for(int k : uncovered){\n            int bestI = -1;\n            long long bestInc = (1LL<<62);\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                int needR = sqrt_ceil_ll(d2sr[i][k]);\n                if(needR > 5000) continue;\n                long long inc = 1LL*needR*needR - 1LL*sol.P[i]*sol.P[i];\n                if(inc < 0) inc = 0;\n                if(inc < bestInc){\n                    bestInc = inc; bestI = i;\n                }\n            }\n            if(bestI == -1){\n                needConnectResidents.push_back(k);\n            }else{\n                int needR = sqrt_ceil_ll(d2sr[bestI][k]);\n                if(needR > sol.P[bestI]) sol.P[bestI] = needR;\n            }\n        }\n        vector<char> toAddEdge(M, 0);\n        for(int k : needConnectResidents){\n            long long bestDist = (1LL<<60);\n            int bestI = -1;\n            for(int i : nearStationsForResid[k]){\n                if(distW[0][i] < bestDist){\n                    bestDist = distW[0][i];\n                    bestI = i;\n                }\n            }\n            if(bestI == -1) continue;\n            int cur = bestI;\n            while(cur != 0){\n                int eid = prevE[0][cur];\n                if(eid < 0) break;\n                toAddEdge[eid] = 1;\n                cur = prevV[0][cur];\n            }\n        }\n        bool anyAdd = false;\n        if(!needConnectResidents.empty()){\n            for(int e=0;e<M;e++){\n                if(toAddEdge[e] && !sol.edgeOn[e]){\n                    sol.edgeOn[e] = 1; anyAdd = true;\n                }\n            }\n            if(anyAdd){\n                inV = build_inV(sol.edgeOn);\n            }\n        }\n        vector<int> uncovered2;\n        for(int k=0;k<K;k++){\n            bool ok = false;\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                if(1LL*sol.P[i]*sol.P[i] >= (long long)d2sr[i][k]){ ok = true; break; }\n            }\n            if(!ok) uncovered2.push_back(k);\n        }\n        for(int k : uncovered2){\n            int bestI = -1;\n            long long bestInc = (1LL<<62);\n            for(int i : nearStationsForResid[k]){\n                if(!inV[i]) continue;\n                int needR = sqrt_ceil_ll(d2sr[i][k]);\n                if(needR > 5000) continue;\n                long long inc = 1LL*needR*needR - 1LL*sol.P[i]*sol.P[i];\n                if(inc < 0) inc = 0;\n                if(inc < bestInc){\n                    bestInc = inc; bestI = i;\n                }\n            }\n            if(bestI != -1){\n                int needR = sqrt_ceil_ll(d2sr[bestI][k]);\n                if(needR > sol.P[bestI]) sol.P[bestI] = needR;\n            }\n        }\n        sol.pSum = 0;\n        for(int i=0;i<N;i++){\n            if(sol.P[i] > 5000) sol.P[i] = 5000;\n            sol.pSum += 1LL*sol.P[i]*sol.P[i];\n        }\n        sol.edgeSum = 0;\n        for(int e=0;e<M;e++) if(sol.edgeOn[e]) sol.edgeSum += edges[e].w;\n        sol.S = sol.pSum + sol.edgeSum;\n    };\n\n    auto terminal_drop_search = [&](Solution cur)->Solution{\n        Solution bestS = cur;\n        int outer = 0;\n        while(outer < 2){\n            outer++;\n            auto fe = optimize_assignment(bestS.edgeOn);\n            vector<int> countAssigned(N, 0);\n            for(int r=0;r<K;r++){\n                int i = fe.assignTo[r];\n                if(i>=0) countAssigned[i]++;\n            }\n            vector<int> terminals;\n            for(int i=0;i<N;i++) if(fe.sol.P[i]>0) terminals.push_back(i);\n            vector<pair<pair<int,int>, int>> cand; // ((P^2, assigned), i)\n            for(int i: terminals){\n                if(i==0) continue;\n                cand.push_back({{fe.sol.P[i]*fe.sol.P[i], countAssigned[i]}, i});\n            }\n            sort(cand.begin(), cand.end());\n            bool improved = false;\n            int limit = min((int)cand.size(), 15);\n            for(int idx=0; idx<limit; idx++){\n                int drop = cand[idx].second;\n                vector<int> T;\n                T.push_back(0);\n                for(int v: terminals) if(v!=drop && v!=0) T.push_back(v);\n                vector<char> edgeOn = build_tree_for_terminals(T);\n                auto f2 = optimize_assignment(edgeOn);\n                vector<char> edgeOn2 = f2.sol.edgeOn;\n                prune_unused_leaves(edgeOn2, f2.sol.P);\n                auto f3 = optimize_assignment(edgeOn2);\n                Solution candSol = f3.sol;\n                ensure_full_coverage(candSol);\n                Solution candSol2 = steinerize_from_P(candSol);\n                if(candSol2.S < candSol.S) candSol = candSol2;\n                if(candSol.S < bestS.S){\n                    bestS = candSol;\n                    improved = true;\n                    break;\n                }\n            }\n            if(!improved) break;\n        }\n        return bestS;\n    };\n\n    // Terminal swap search: replace a terminal with a nearby station\n    auto terminal_swap_search = [&](Solution cur)->Solution{\n        Solution bestS = cur;\n        // derive terminal set\n        vector<int> terminals;\n        for(int i=0;i<N;i++) if(bestS.P[i] > 0) terminals.push_back(i);\n        if(terminals.empty()) return bestS;\n        // pick a few terminals with largest P^2\n        vector<pair<int,int>> order;\n        order.reserve(terminals.size());\n        for(int i: terminals){\n            if(i==0) continue;\n            order.emplace_back(bestS.P[i]*bestS.P[i], i);\n        }\n        sort(order.begin(), order.end(), greater<pair<int,int>>());\n        int Ttry = min(6, (int)order.size());\n        for(int t=0;t<Ttry;t++){\n            int i = order[t].second;\n            // consider nearest neighbors of i\n            int neighTry = 6;\n            int tried = 0;\n            for(int jIdx=1; jIdx<(int)nearStationsEuclid[i].size() && tried<neighTry; jIdx++){\n                int j = nearStationsEuclid[i][jIdx];\n                if(j==0 || j==i) continue;\n                tried++;\n                // build T' = terminals replacing i with j\n                vector<int> T;\n                T.push_back(0);\n                bool jIn = (bestS.P[j] > 0);\n                for(int v: terminals){\n                    if(v==i) continue;\n                    if(v!=0) T.push_back(v);\n                }\n                if(!jIn) T.push_back(j);\n                // build tree and optimize\n                vector<char> edgeOn = build_tree_for_terminals(T);\n                auto f1 = optimize_assignment(edgeOn);\n                vector<char> edgeOn2 = f1.sol.edgeOn;\n                prune_unused_leaves(edgeOn2, f1.sol.P);\n                auto f2 = optimize_assignment(edgeOn2);\n                Solution cand = f2.sol;\n                ensure_full_coverage(cand);\n                shrink_radii(cand);\n                if(cand.S < bestS.S){\n                    bestS = cand;\n                    // update terminals for potential subsequent swaps\n                    terminals.clear();\n                    for(int x=0;x<N;x++) if(bestS.P[x]>0) terminals.push_back(x);\n                }\n            }\n        }\n        return bestS;\n    };\n\n    // Build initial solutions\n    Solution sol_dyn = build_solution_setcover_dyn();\n    Solution sol_simple = build_solution_setcover_simple();\n    Solution sol_spt = build_solution_spt();\n\n    auto maybe_steinerize_iters = [&](Solution s)->Solution{\n        if (s.P.empty()) return s;\n        for(int it=0; it<2; ++it){\n            Solution s2 = steinerize_from_P(s);\n            if(s2.S < s.S) s = s2;\n            else break;\n        }\n        return s;\n    };\n    sol_dyn = maybe_steinerize_iters(sol_dyn);\n    sol_simple = maybe_steinerize_iters(sol_simple);\n    sol_spt = maybe_steinerize_iters(sol_spt);\n\n    Solution best = sol_dyn;\n    if(sol_simple.S < best.S) best = sol_simple;\n    if(sol_spt.S < best.S) best = sol_spt;\n\n    // Local search passes\n    Solution afterRem = removal_pass(best);\n    if(afterRem.S < best.S) best = afterRem;\n\n    Solution afterDrop = terminal_drop_search(best);\n    if(afterDrop.S < best.S) best = afterDrop;\n\n    Solution afterAdd = addition_pass(best);\n    if(afterAdd.S < best.S) best = afterAdd;\n\n    Solution afterPathAdd = path_addition_pass(best);\n    if(afterPathAdd.S < best.S) best = afterPathAdd;\n\n    Solution afterSwap = terminal_swap_search(best);\n    if(afterSwap.S < best.S) best = afterSwap;\n\n    Solution afterReplace = edge_replacement_pass(best);\n    if(afterReplace.S < best.S) best = afterReplace;\n\n    Solution afterRem2 = removal_pass(best);\n    if(afterRem2.S < best.S) best = afterRem2;\n\n    // Finalize: ensure coverage and final steinerization + shrink\n    auto finalize_solution = [&](Solution s)->Solution{\n        ensure_full_coverage(s);\n        Solution s2 = steinerize_from_P(s);\n        if(s2.S < s.S) s = s2;\n        shrink_radii(s);\n        return s;\n    };\n    best = finalize_solution(best);\n\n    // Output\n    for(int i=0;i<N;i++){\n        if(i) cout << ' ';\n        cout << best.P[i];\n    }\n    cout << '\\n';\n    for(int j=0;j<M;j++){\n        if(j) cout << ' ';\n        cout << (best.edgeOn[j] ? 1 : 0);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Move {\n    int x1, y1, x2, y2;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 30;\n    vector<vector<int>> A(N);\n    for (int x = 0; x < N; ++x) {\n        A[x].resize(x + 1);\n        for (int y = 0; y <= x; ++y) cin >> A[x][y];\n    }\n\n    const int LIMIT = 10000;\n    vector<Move> ops;\n    ops.reserve(LIMIT);\n\n    auto inRange = [&](int x, int y) -> bool {\n        return 0 <= x && x < N && 0 <= y && y <= x;\n    };\n\n    auto isViolation = [&](int x, int y) -> bool {\n        if (x >= N - 1) return false;\n        int v = A[x][y];\n        int c1 = A[x + 1][y];\n        int c2 = A[x + 1][y + 1];\n        return v > (c1 < c2 ? c1 : c2);\n    };\n\n    auto severityNow = [&](int x, int y) -> int {\n        if (x >= N - 1) return INT_MIN / 2;\n        int v = A[x][y];\n        int c1 = A[x + 1][y];\n        int c2 = A[x + 1][y + 1];\n        return v - (c1 < c2 ? c1 : c2);\n    };\n\n    // Subtriangle minima M[x][y] = min over subtriangle rooted at (x,y)\n    vector<vector<int>> M(N);\n    for (int x = 0; x < N; ++x) M[x].assign(x + 1, 0);\n\n    auto recomputeM = [&]() {\n        for (int y = 0; y < N; ++y) M[N - 1][y] = A[N - 1][y];\n        for (int x = N - 2; x >= 0; --x) {\n            for (int y = 0; y <= x; ++y) {\n                int m = A[x][y];\n                int ml = M[x + 1][y];\n                int mr = M[x + 1][y + 1];\n                if (ml < m) m = ml;\n                if (mr < m) m = mr;\n                M[x][y] = m;\n            }\n        }\n    };\n\n    recomputeM();\n\n    auto edgeDistance = [&](int x, int y) -> int {\n        return min(y, x - y);\n    };\n\n    auto chooseChild = [&](int x, int y) -> pair<int,int> {\n        // Choose smaller child; on tie, prefer smaller subtree min via M; then edge preference.\n        int v1 = A[x + 1][y];\n        int v2 = A[x + 1][y + 1];\n        if (v1 < v2) return {x + 1, y};\n        if (v2 < v1) return {x + 1, y + 1};\n        int mL = M[x + 1][y];\n        int mR = M[x + 1][y + 1];\n        if (mL < mR) return {x + 1, y};\n        if (mR < mL) return {x + 1, y + 1};\n        // still tie: prefer closer to edge (fewer parents)\n        int dL = edgeDistance(x + 1, y);\n        int dR = edgeDistance(x + 1, y + 1);\n        if (dL < dR) return {x + 1, y};\n        if (dR < dL) return {x + 1, y + 1};\n        // fallback\n        return {x + 1, y};\n    };\n\n    auto planPath = [&](int sx, int sy) {\n        vector<pair<int,int>> path;\n        int x = sx, y = sy;\n        int cur = A[x][y];\n        path.emplace_back(x, y);\n        while (x < N - 1) {\n            int c1 = A[x + 1][y];\n            int c2 = A[x + 1][y + 1];\n            int mn = (c1 < c2 ? c1 : c2);\n            if (cur <= mn) break;\n            auto [nx, ny] = chooseChild(x, y);\n            x = nx; y = ny;\n            path.emplace_back(x, y);\n        }\n        return path;\n    };\n\n    auto pathLen = [&](int sx, int sy) -> int {\n        int x = sx, y = sy;\n        int cur = A[x][y];\n        int len = 0;\n        while (x < N - 1) {\n            int c1 = A[x + 1][y];\n            int c2 = A[x + 1][y + 1];\n            int mn = (c1 < c2 ? c1 : c2);\n            if (cur <= mn) break;\n            auto [nx, ny] = chooseChild(x, y);\n            x = nx; y = ny;\n            ++len;\n        }\n        return len;\n    };\n\n    // Bottom-up pass; within each row, pick candidate by longest estimated path\n    for (int x = N - 2; x >= 0 && (int)ops.size() < LIMIT; --x) {\n        vector<char> done(x + 1, 0);\n        while ((int)ops.size() < LIMIT) {\n            int best_y = -1;\n            int best_len = -1;\n            int best_sev = INT_MIN;\n            int best_edge = INT_MAX;\n\n            // Scan current row for best candidate\n            for (int y = 0; y <= x; ++y) {\n                if (done[y]) continue;\n                if (!isViolation(x, y)) { done[y] = 1; continue; }\n                int len = pathLen(x, y);\n                int sev = severityNow(x, y);\n                int edg = edgeDistance(x, y);\n                if (len > best_len ||\n                    (len == best_len && sev > best_sev) ||\n                    (len == best_len && sev == best_sev && edg < best_edge)) {\n                    best_len = len;\n                    best_sev = sev;\n                    best_edge = edg;\n                    best_y = y;\n                }\n            }\n\n            if (best_y == -1 || best_len <= 0) break; // no more violations on this row\n\n            // Plan and execute path for best candidate\n            auto path = planPath(x, best_y);\n            int steps = (int)path.size() - 1;\n            if (steps > 0) {\n                int can = min(steps, LIMIT - (int)ops.size());\n                for (int i = 0; i < can; ++i) {\n                    auto [x1, y1] = path[i];\n                    auto [x2, y2] = path[i + 1];\n                    swap(A[x1][y1], A[x2][y2]);\n                    ops.push_back({x1, y1, x2, y2});\n                }\n                // Recompute subtriangle minima after this path\n                recomputeM();\n                if (can < steps) break; // hit budget\n            }\n            // Mark this y as done; heap property at (x, best_y) is stable thereafter\n            done[best_y] = 1;\n        }\n    }\n\n    // Safety net: event-driven cleanup if any violation persists and budget remains (rare)\n    if ((int)ops.size() < LIMIT) {\n        bool any = false;\n        for (int x = 0; x <= N - 2 && !any; ++x)\n            for (int y = 0; y <= x; ++y)\n                if (isViolation(x, y)) { any = true; break; }\n        if (any) {\n            vector<vector<char>> inQ(N);\n            for (int x = 0; x < N; ++x) inQ[x].assign(x + 1, 0);\n            deque<pair<int,int>> q;\n            auto pushQ = [&](int x, int y) {\n                if (!inRange(x, y) || x >= N - 1) return;\n                if (inQ[x][y]) return;\n                if (!isViolation(x, y)) return;\n                inQ[x][y] = 1;\n                q.emplace_back(x, y);\n            };\n            for (int x = 0; x <= N - 2; ++x)\n                for (int y = 0; y <= x; ++y)\n                    if (isViolation(x, y)) pushQ(x, y);\n\n            while (!q.empty() && (int)ops.size() < LIMIT) {\n                auto [sx, sy] = q.front(); q.pop_front();\n                inQ[sx][sy] = 0;\n                int x = sx, y = sy;\n                while (x < N - 1) {\n                    int v = A[x][y];\n                    int v1 = A[x + 1][y];\n                    int v2 = A[x + 1][y + 1];\n                    int mn = min(v1, v2);\n                    if (v <= mn) break;\n                    int tx = (v1 < v2 ? x + 1 : x + 1);\n                    int ty = (v1 < v2 ? y     : y + 1);\n                    if ((int)ops.size() >= LIMIT) break;\n                    swap(A[x][y], A[tx][ty]);\n                    ops.push_back({x, y, tx, ty});\n                    if (y - 1 >= 0) pushQ(x - 1, y - 1);\n                    if (y <= x - 1) pushQ(x - 1, y);\n                    x = tx; y = ty;\n                }\n                if (x < N - 1 && isViolation(x, y)) pushQ(x, y);\n            }\n        }\n    }\n\n    int K = min<int>((int)ops.size(), LIMIT);\n    cout << K << '\\n';\n    for (int i = 0; i < K; ++i) {\n        cout << ops[i].x1 << ' ' << ops[i].y1 << ' ' << ops[i].x2 << ' ' << ops[i].y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int i, j; };\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    const int H = D, W = D;\n    const int ei = 0, ej = (D - 1) / 2; // entrance\n    const int INF = 1e9;\n\n    // Obstacles\n    vector<vector<char>> obs(H, vector<char>(W, 0));\n    for (int k = 0; k < N; ++k) {\n        int r, c; cin >> r >> c;\n        obs[r][c] = 1;\n    }\n\n    auto inside = [&](int i, int j){ return 0 <= i && i < H && 0 <= j && j < W; };\n    int di[4] = {-1, 0, 1, 0};\n    int dj[4] = {0, 1, 0, -1};\n\n    // BFS distance from entrance (ignoring containers)\n    vector<vector<int>> dist(H, vector<int>(W, INF));\n    deque<Pos> dq;\n    dist[ei][ej] = 0;\n    dq.push_back({ei, ej});\n    while (!dq.empty()) {\n        auto p = dq.front(); dq.pop_front();\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = p.i + di[dir], nj = p.j + dj[dir];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (dist[ni][nj] > dist[p.i][p.j] + 1) {\n                dist[ni][nj] = dist[p.i][p.j] + 1;\n                dq.push_back({ni, nj});\n            }\n        }\n    }\n\n    // Target order: increasing distance from entrance, tie by (i,j)\n    vector<Pos> order;\n    order.reserve(H*W);\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        if (obs[i][j]) continue;\n        if (i == ei && j == ej) continue;\n        order.push_back({i, j});\n    }\n    sort(order.begin(), order.end(), [&](const Pos &a, const Pos &b){\n        if (dist[a.i][a.j] != dist[b.i][b.j]) return dist[a.i][a.j] < dist[b.i][b.j];\n        if (a.i != b.i) return a.i < b.i;\n        return a.j < b.j;\n    });\n    int M = (int)order.size();\n\n    // Rank index of each cell\n    vector<vector<int>> rankIndex(H, vector<int>(W, -1));\n    for (int idx = 0; idx < M; ++idx) {\n        rankIndex[order[idx].i][order[idx].j] = idx;\n    }\n\n    // State during placement\n    vector<vector<char>> empty(H, vector<char>(W, 0)); // empty and not obstacle (entrance included)\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) empty[i][j] = !obs[i][j];\n    vector<vector<int>> labelAt(H, vector<int>(W, -1)); // placed label or -1\n\n    // Reservation tracking\n    vector<int> prefOcc(M, 0);        // P[x]: #occupied among indices <= x\n    vector<char> seen(M, 0);          // seen labels\n    vector<int> seenPref(M, 0);       // S[x]: #labels <= x seen so far\n\n    // Articulation points on current empty graph\n    auto compute_articulation = [&](const vector<vector<char>>& curEmpty)->vector<vector<char>> {\n        vector<vector<int>> id(H, vector<int>(W, -1));\n        vector<Pos> nodes; nodes.reserve(H*W);\n        int vid = 0;\n        for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j)\n            if (curEmpty[i][j]) { id[i][j] = vid++; nodes.push_back({i,j}); }\n        int n = vid;\n        vector<vector<int>> g(n);\n        for (auto &p : nodes) {\n            int u = id[p.i][p.j];\n            for (int d = 0; d < 4; ++d) {\n                int ni = p.i + di[d], nj = p.j + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (!curEmpty[ni][nj]) continue;\n                int v = id[ni][nj];\n                g[u].push_back(v);\n            }\n        }\n        vector<int> tin(n, -1), low(n, -1), parent(n, -1);\n        vector<char> isArtV(n, 0);\n        int timer = 0;\n        function<void(int)> dfs = [&](int u){\n            tin[u] = low[u] = timer++;\n            int child = 0;\n            for (int v : g[u]) {\n                if (tin[v] == -1) {\n                    parent[v] = u; ++child;\n                    dfs(v);\n                    low[u] = min(low[u], low[v]);\n                    if (parent[u] != -1 && low[v] >= tin[u]) isArtV[u] = 1;\n                } else if (v != parent[u]) {\n                    low[u] = min(low[u], tin[v]);\n                }\n            }\n            if (parent[u] == -1 && child > 1) isArtV[u] = 1;\n        };\n        for (int u = 0; u < n; ++u) if (tin[u] == -1) dfs(u);\n\n        vector<vector<char>> isArt(H, vector<char>(W, 0));\n        for (auto &p : nodes) {\n            int u = id[p.i][p.j];\n            isArt[p.i][p.j] = isArtV[u];\n        }\n        return isArt;\n    };\n\n    auto count_safe_prefix = [&](const vector<vector<char>> &isArt, const vector<vector<char>> &curEmpty, int prefixLen)->int {\n        int cnt = 0;\n        for (int k = 0; k < M && k < prefixLen; ++k) {\n            int i = order[k].i, j = order[k].j;\n            if (!curEmpty[i][j]) continue;\n            if (!isArt[i][j]) cnt++;\n        }\n        return cnt;\n    };\n\n    int step = 0;\n\n    auto choose_position = [&](int label)->Pos {\n        vector<vector<char>> baseArt = compute_articulation(empty);\n\n        struct Cand { int i, j, idx, baseCost, deg, d; };\n        vector<Cand> cands;\n        cands.reserve(M);\n        for (int k = 0; k < M; ++k) {\n            int i = order[k].i, j = order[k].j;\n            if (!empty[i][j]) continue;     // already occupied\n            if (baseArt[i][j]) continue;    // avoid articulation to keep connectivity\n            int deg = 0;\n            for (int d = 0; d < 4; ++d) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (empty[ni][nj]) deg++;\n            }\n            int cost = abs(k - label);\n            cands.push_back({i, j, k, cost, deg, dist[i][j]});\n        }\n\n        if (cands.empty()) {\n            // Fallback: any empty non-entrance cell\n            for (int k = 0; k < M; ++k) {\n                int i = order[k].i, j = order[k].j;\n                if (!empty[i][j]) continue;\n                return {i, j};\n            }\n        }\n\n        // Window around target index\n        int Wrange = max(8, M / 6); // ~12 for M~80\n        vector<Cand> windowCands;\n        windowCands.reserve(cands.size());\n        for (auto &c : cands) if (abs(c.idx - label) <= Wrange) windowCands.push_back(c);\n        vector<Cand> useCands = windowCands.empty() ? cands : windowCands;\n\n        sort(useCands.begin(), useCands.end(), [&](const Cand& a, const Cand& b){\n            if (a.baseCost != b.baseCost) return a.baseCost < b.baseCost;\n            if (a.deg != b.deg) return a.deg < b.deg;\n            if (a.d != b.d) return a.d < b.d;\n            if (a.i != b.i) return a.i < b.i;\n            return a.j < b.j;\n        });\n\n        // Reservation-aware prefix constraint: P[x] <= S[x] + slack for x in [idx, label-1]\n        auto passes_reservation = [&](int idx, int slack)->bool {\n            if (label == 0) return true;\n            int upto = label - 1;\n            if (idx > upto) return true;\n            for (int x = idx; x <= upto; ++x) {\n                if (prefOcc[x] >= seenPref[x] + slack) return false;\n            }\n            return true;\n        };\n\n        int K = min<int>(25, useCands.size());      // evaluate top-K\n        int P = min<int>(20, M);                    // protect early prefix\n        int baseSafePrefix = count_safe_prefix(baseArt, empty, P);\n        int wUnlock = 2; // mild bonus\n\n        // Try with increasing slack to obey reservation\n        Pos best{-1, -1};\n        for (int slackCandidate : {1, 2, INT_MAX}) {\n            long long bestScoreLL = LLONG_MIN;\n            Pos bestHere{-1, -1};\n            int bestBaseCost = INT_MAX;\n            int bestDist = INT_MAX;\n\n            for (int z = 0; z < K; ++z) {\n                auto c = useCands[z];\n                if (slackCandidate != INT_MAX) {\n                    if (!passes_reservation(c.idx, slackCandidate)) continue;\n                }\n                // Tentative placement\n                empty[c.i][c.j] = 0;\n                vector<vector<char>> art2 = compute_articulation(empty);\n                int afterSafe = count_safe_prefix(art2, empty, P);\n                int benefit = afterSafe - baseSafePrefix;\n\n                long long score = -(long long)c.baseCost + (long long)wUnlock * benefit;\n                // tiny tie-breaker\n                score -= (c.deg >= 3 ? 1 : 0);\n\n                empty[c.i][c.j] = 1;\n\n                if (score > bestScoreLL) {\n                    bestScoreLL = score;\n                    bestHere = {c.i, c.j};\n                    bestBaseCost = c.baseCost;\n                    bestDist = c.d;\n                } else if (score == bestScoreLL) {\n                    if (c.baseCost < bestBaseCost) {\n                        bestHere = {c.i, c.j};\n                        bestBaseCost = c.baseCost; bestDist = c.d;\n                    } else if (c.baseCost == bestBaseCost) {\n                        if (c.d < bestDist) {\n                            bestHere = {c.i, c.j};\n                            bestDist = c.d;\n                        }\n                    }\n                }\n            }\n            if (bestHere.i != -1) { best = bestHere; break; }\n        }\n\n        if (best.i == -1) {\n            auto c = useCands[0];\n            best = {c.i, c.j};\n        }\n        return best;\n    };\n\n    // Interactive placement\n    for (step = 0; step < M; ++step) {\n        int t; cin >> t;\n\n        // update seen and prefix\n        seen[t] = 1;\n        int acc = 0;\n        for (int x = 0; x < M; ++x) {\n            acc += seen[x];\n            seenPref[x] = acc;\n        }\n\n        Pos p = choose_position(t);\n        // place container\n        empty[p.i][p.j] = 0;\n        labelAt[p.i][p.j] = t;\n        // update prefix occupancy\n        int idx = rankIndex[p.i][p.j];\n        for (int x = idx; x < M; ++x) prefOcc[x]++;\n\n        cout << p.i << ' ' << p.j << '\\n' << flush;\n    }\n\n    // Retrieval strategies: three variants, choose the one with fewer inversions\n    auto inversion_count = [&](const vector<int>& a)->long long {\n        int n = (int)a.size();\n        int MX = n + 2;\n        vector<int> bit(MX, 0);\n        auto add = [&](int i){ for (++i; i < MX; i += i & -i) bit[i] += 1; };\n        auto sum = [&](int i){ int s = 0; for (++i; i > 0; i -= i & -i) s += bit[i]; return s; };\n        long long inv = 0;\n        for (int i = 0; i < n; ++i) { inv += i - sum(a[i]); add(a[i]); }\n        return inv;\n    };\n\n    // Base occupancy\n    vector<vector<char>> occ0(H, vector<char>(W, 0));\n    for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) {\n        if (obs[i][j]) continue;\n        if (i == ei && j == ej) continue;\n        if (labelAt[i][j] >= 0) occ0[i][j] = 1;\n    }\n\n    // Strategy A: BFS-order (our target order). Always legal.\n    vector<pair<int,int>> seqA;\n    seqA.reserve(M);\n    for (int k = 0; k < M; ++k) seqA.emplace_back(order[k].i, order[k].j);\n    vector<int> labelsA; labelsA.reserve(M);\n    for (auto &p : seqA) labelsA.push_back(labelAt[p.first][p.second]);\n    long long invA = inversion_count(labelsA);\n\n    // Strategy B: greedy smallest-label frontier\n    vector<pair<int,int>> seqB;\n    {\n        auto occ = occ0;\n        struct Node { int label, i, j; bool operator<(const Node& o) const { return label > o.label; } };\n        priority_queue<Node> pq;\n        vector<vector<char>> inFrontier(H, vector<char>(W, 0));\n        auto try_push = [&](int i, int j){\n            if (!inside(i,j)) return;\n            if (obs[i][j]) return;\n            if (!occ[i][j]) return;\n            if (inFrontier[i][j]) return;\n            inFrontier[i][j] = 1;\n            pq.push({labelAt[i][j], i, j});\n        };\n        for (int d = 0; d < 4; ++d) {\n            int ni = ei + di[d], nj = ej + dj[d];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (occ[ni][nj]) try_push(ni, nj);\n        }\n        for (int step2 = 0; step2 < M; ++step2) {\n            while (!pq.empty() && !occ[pq.top().i][pq.top().j]) pq.pop();\n            if (pq.empty()) {\n                // Shouldn't happen; robustness: find any frontier cell\n                bool pushed = false;\n                for (int i = 0; i < H && !pushed; ++i) for (int j = 0; j < W && !pushed; ++j) {\n                    if (!occ[i][j]) continue;\n                    for (int d = 0; d < 4; ++d) {\n                        int ni = i + di[d], nj = j + dj[d];\n                        if (!inside(ni, nj)) continue;\n                        if (obs[ni][nj]) continue;\n                        if (!occ[ni][nj]) { try_push(i, j); pushed = true; break; }\n                    }\n                }\n                if (pq.empty()) break;\n            }\n            auto cur = pq.top(); pq.pop();\n            int ci = cur.i, cj = cur.j;\n            occ[ci][cj] = 0;\n            seqB.emplace_back(ci, cj);\n            for (int d = 0; d < 4; ++d) {\n                int ni = ci + di[d], nj = cj + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (obs[ni][nj]) continue;\n                if (occ[ni][nj]) try_push(ni, nj);\n            }\n        }\n    }\n    vector<int> labelsB; labelsB.reserve(M);\n    for (auto &p : seqB) labelsB.push_back(labelAt[p.first][p.second]);\n    long long invB = inversion_count(labelsB);\n\n    // Strategy C: greedy closest to BFS-rank head\n    vector<pair<int,int>> seqC;\n    {\n        auto occ = occ0;\n        struct NodeC {\n            int key, idx, label, i, j;\n            bool operator<(const NodeC& o) const {\n                if (key != o.key) return key > o.key;\n                if (label != o.label) return label > o.label;\n                return idx > o.idx;\n            }\n        };\n        priority_queue<NodeC> pq;\n        vector<vector<char>> inFrontier(H, vector<char>(W, 0));\n        int headIdx = 0;\n        auto try_push = [&](int i, int j){\n            if (!inside(i,j)) return;\n            if (obs[i][j]) return;\n            if (!occ[i][j]) return;\n            if (inFrontier[i][j]) return;\n            inFrontier[i][j] = 1;\n            int idx = rankIndex[i][j];\n            int key = abs(idx - headIdx);\n            pq.push(NodeC{key, idx, labelAt[i][j], i, j});\n        };\n        for (int d = 0; d < 4; ++d) {\n            int ni = ei + di[d], nj = ej + dj[d];\n            if (!inside(ni, nj)) continue;\n            if (obs[ni][nj]) continue;\n            if (occ[ni][nj]) try_push(ni, nj);\n        }\n        for (int step2 = 0; step2 < M; ++step2) {\n            while (!pq.empty() && !occ[pq.top().i][pq.top().j]) pq.pop();\n            if (pq.empty()) {\n                bool pushed = false;\n                for (int i = 0; i < H && !pushed; ++i) for (int j = 0; j < W && !pushed; ++j) {\n                    if (!occ[i][j]) continue;\n                    for (int d = 0; d < 4; ++d) {\n                        int ni = i + di[d], nj = j + dj[d];\n                        if (!inside(ni, nj)) continue;\n                        if (obs[ni][nj]) continue;\n                        if (!occ[ni][nj]) { try_push(i, j); pushed = true; break; }\n                    }\n                }\n                if (pq.empty()) break;\n            }\n            auto cur = pq.top(); pq.pop();\n            int ci = cur.i, cj = cur.j;\n            occ[ci][cj] = 0;\n            seqC.emplace_back(ci, cj);\n            // advance headIdx to next unremoved index\n            while (headIdx < M) {\n                auto p = order[headIdx];\n                if (occ[p.i][p.j]) break;\n                headIdx++;\n            }\n            for (int d = 0; d < 4; ++d) {\n                int ni = ci + di[d], nj = cj + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (obs[ni][nj]) continue;\n                if (occ[ni][nj]) try_push(ni, nj);\n            }\n        }\n    }\n    vector<int> labelsC; labelsC.reserve(M);\n    for (auto &p : seqC) labelsC.push_back(labelAt[p.first][p.second]);\n    long long invC = inversion_count(labelsC);\n\n    // Choose best sequence by minimal inversions\n    vector<pair<int,int>>* bestSeq = &seqA;\n    long long bestInv = invA;\n    if (invB < bestInv) { bestInv = invB; bestSeq = &seqB; }\n    if (invC < bestInv) { bestInv = invC; bestSeq = &seqC; }\n    if ((int)bestSeq->size() != M) {\n        // Fallback to any full sequence (A is always full)\n        bestSeq = &seqA;\n    }\n\n    for (auto &p : *bestSeq) {\n        cout << p.first << ' ' << p.second << '\\n';\n    }\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    if (!(cin >> n >> m)) return 0;\n    const int N = n * n;\n\n    vector<int> origGrid(N);\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j < n; ++j)\n            cin >> origGrid[i*n + j];\n\n    auto inb = [&](int r, int c)->bool { return 0 <= r && r < n && 0 <= c && c < n; };\n    const int dr[4] = {1, -1, 0, 0};\n    const int dc[4] = {0, 0, 1, -1};\n\n    // Boundary flags and BC/IC classification\n    vector<char> isBoundaryPos(N, 0);\n    vector<int> boundaryCount0(m+1, 0);\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j;\n            if (i == 0 || j == 0 || i == n-1 || j == n-1) {\n                isBoundaryPos[id] = 1;\n                boundaryCount0[origGrid[id]]++;\n            }\n        }\n    vector<char> isBC(m+1, 0), isIC(m+1, 0);\n    for (int c = 1; c <= m; ++c) isBC[c] = (boundaryCount0[c] > 0);\n    for (int c = 1; c <= m; ++c) isIC[c] = !isBC[c];\n\n    // Initial same-color degree on original\n    vector<int> degSame0(N, 0);\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j, c = origGrid[id], d = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                if (origGrid[ni*n + nj] == c) d++;\n            }\n            degSame0[id] = d;\n        }\n\n    // Cells adjacent to interior colors (guard cells)\n    vector<char> adjToIC(N, 0);\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j < n; ++j) {\n            int id = i*n + j;\n            bool flag = false;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = origGrid[ni*n + nj];\n                if (d != 0 && isIC[d]) { flag = true; break; }\n            }\n            adjToIC[id] = flag ? 1 : 0;\n        }\n\n    // Adjacency edges for each non-zero pair (u, v), u < v (original)\n    unordered_map<int, vector<pair<int,int>>> pairEdgesOrig;\n    pairEdgesOrig.reserve(4000);\n    auto add_pair_edge = [&](unordered_map<int, vector<pair<int,int>>> &mp, int a, int b, int idA, int idB){\n        if (a == 0 || b == 0 || a == b) return;\n        int u = a, v = b, idU = idA, idV = idB;\n        if (u > v) { swap(u, v); swap(idU, idV); }\n        int key = u*(m+1) + v;\n        mp[key].emplace_back(idU, idV);\n    };\n    for (int i = 0; i < n; ++i)\n        for (int j = 0; j+1 < n; ++j) {\n            int idA = i*n + j, idB = i*n + j + 1;\n            int a = origGrid[idA], b = origGrid[idB];\n            if (a != b) add_pair_edge(pairEdgesOrig, a, b, idA, idB);\n        }\n    for (int i = 0; i+1 < n; ++i)\n        for (int j = 0; j < n; ++j) {\n            int idA = i*n + j, idB = (i+1)*n + j;\n            int a = origGrid[idA], b = origGrid[idB];\n            if (a != b) add_pair_edge(pairEdgesOrig, a, b, idA, idB);\n        }\n\n    auto borderSides = [&](int id)->int {\n        int i = id / n, j = id % n;\n        return (i == 0) + (i == n-1) + (j == 0) + (j == n-1);\n    };\n\n    Timer timer;\n    const double TIME_LIMIT = 1.95;\n    std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    auto build_pair_edges_from_grid = [&](const vector<int> &grid) {\n        unordered_map<int, vector<pair<int,int>>> mp;\n        mp.reserve(4000);\n        for (int i = 0; i < n; ++i)\n            for (int j = 0; j+1 < n; ++j) {\n                int idA = i*n + j, idB = i*n + j + 1;\n                int a = grid[idA], b = grid[idB];\n                if (a != b) add_pair_edge(mp, a, b, idA, idB);\n            }\n        for (int i = 0; i+1 < n; ++i)\n            for (int j = 0; j < n; ++j) {\n                int idA = i*n + j, idB = (i+1)*n + j;\n                int a = grid[idA], b = grid[idB];\n                if (a != b) add_pair_edge(mp, a, b, idA, idB);\n            }\n        return mp;\n    };\n\n    auto run_once = [&](int runType, double time_budget)->pair<int, vector<int>> {\n        vector<int> grid = origGrid;\n        vector<int> sizeCount(m+1, 0);\n        for (int id = 0; id < N; ++id) sizeCount[grid[id]]++;\n        vector<int> degSame = degSame0;\n\n        // Non-zero pair counts\n        vector<vector<int>> pairCount(m+1, vector<int>(m+1, 0));\n        auto add_pair_cnt = [&](int a, int b, int delta){\n            if (a == 0 || b == 0 || a == b) return;\n            if (a > b) swap(a, b);\n            pairCount[a][b] += delta;\n        };\n        for (int i = 0; i < n; ++i)\n            for (int j = 0; j+1 < n; ++j) {\n                int a = grid[i*n + j], b = grid[i*n + j + 1];\n                if (a != b) add_pair_cnt(a, b, +1);\n            }\n        for (int i = 0; i+1 < n; ++i)\n            for (int j = 0; j < n; ++j) {\n                int a = grid[i*n + j], b = grid[(i+1)*n + j];\n                if (a != b) add_pair_cnt(a, b, +1);\n            }\n\n        // Adjacency to 0 edge counts\n        vector<int> adj0Count(m+1, 0);\n        for (int j = 0; j < n; ++j) {\n            int t = grid[0*n + j]; if (t) adj0Count[t]++;\n            int b = grid[(n-1)*n + j]; if (b) adj0Count[b]++;\n        }\n        for (int i = 0; i < n; ++i) {\n            int l = grid[i*n + 0]; if (l) adj0Count[l]++;\n            int r = grid[i*n + (n-1)]; if (r) adj0Count[r]++;\n        }\n        // internal 0 edges (initially none, but keep generic)\n        for (int i = 0; i < n; ++i)\n            for (int j = 0; j+1 < n; ++j) {\n                int a = grid[i*n + j], b = grid[i*n + j + 1];\n                if (a == 0 && b != 0) adj0Count[b]++;\n                if (a != 0 && b == 0) adj0Count[a]++;\n            }\n        for (int i = 0; i+1 < n; ++i)\n            for (int j = 0; j < n; ++j) {\n                int a = grid[i*n + j], b = grid[(i+1)*n + j];\n                if (a == 0 && b != 0) adj0Count[b]++;\n                if (a != 0 && b == 0) adj0Count[a]++;\n            }\n\n        // Anchors: choose endpoints for each pair (u, v)\n        vector<char> protectAnchor(N, 0);\n        auto choose_anchors = [&](const unordered_map<int, vector<pair<int,int>>> &pairEdges, int heuristicType) {\n            fill(protectAnchor.begin(), protectAnchor.end(), 0);\n            for (auto &kv : pairEdges) {\n                auto &vec = kv.second;\n                if (vec.empty()) continue;\n                int bestIdx = 0, bestCost = INT_MAX;\n                for (int idx = 0; idx < (int)vec.size(); ++idx) {\n                    int idU = vec[idx].first;\n                    int idV = vec[idx].second;\n                    int cost = 0;\n                    // Prefer endpoints adjacent to interior (effectively unremovable)\n                    if (!(adjToIC[idU] || adjToIC[idV])) cost += 5;\n                    // Prefer lower same-color degrees\n                    cost += (degSame0[idU] > 2) + (degSame0[idV] > 2);\n                    // Prefer border edges slightly\n                    if (!(isBoundaryPos[idU] || isBoundaryPos[idV])) cost += 1;\n                    // Heuristic variants\n                    if (heuristicType == 2) {\n                        cost += (isBoundaryPos[idU] ? 0 : 1) + (isBoundaryPos[idV] ? 0 : 1);\n                    } else if (heuristicType == 3) {\n                        cost += (degSame0[idU] + degSame0[idV] > 4) ? 2 : 0;\n                    } else if (heuristicType == 4) {\n                        // Stronger bias to small local degree\n                        cost += (degSame[idU] + degSame[idV]) * 2;\n                    }\n                    // Random jitter\n                    cost = cost * 8 + (int)(rng() & 7);\n                    if (cost < bestCost) { bestCost = cost; bestIdx = idx; }\n                }\n                int idU = vec[bestIdx].first;\n                int idV = vec[bestIdx].second;\n                protectAnchor[idU] = 1;\n                protectAnchor[idV] = 1;\n            }\n        };\n\n        if (runType >= 1 && runType <= 3) {\n            choose_anchors(pairEdgesOrig, runType);\n        }\n\n        auto hasZeroNeighbor = [&](int id)->bool {\n            int i = id / n, j = id % n;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                if (grid[ni*n + nj] == 0) return true;\n            }\n            return false;\n        };\n        auto is_accessible = [&](int id)->bool {\n            return isBoundaryPos[id] || hasZeroNeighbor(id);\n        };\n\n        // Articulation test: same-color neighbors remain connected after removing id\n        vector<int> seen(N, 0);\n        int stamp = 1;\n        auto neighbors_connected_after_remove = [&](int id, int color)->bool {\n            int i = id / n, j = id % n;\n            int sameNei[4], sn = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int nid = ni*n + nj;\n                if (grid[nid] == color) sameNei[sn++] = nid;\n            }\n            if (sn <= 1) return true;\n            stamp++;\n            deque<int> dq;\n            dq.push_back(sameNei[0]);\n            seen[sameNei[0]] = stamp;\n            int targetsLeft = sn - 1;\n            while (!dq.empty()) {\n                int u = dq.front(); dq.pop_front();\n                int ui = u / n, uj = u % n;\n                for (int k = 0; k < 4; ++k) {\n                    int vi = ui + dr[k], vj = uj + dc[k];\n                    if (!inb(vi, vj)) continue;\n                    int v = vi*n + vj;\n                    if (v == id) continue;\n                    if (grid[v] != color) continue;\n                    if (seen[v] == stamp) continue;\n                    seen[v] = stamp;\n                    for (int t = 1; t < sn; ++t) {\n                        if (v == sameNei[t]) { targetsLeft--; break; }\n                    }\n                    if (targetsLeft == 0) return true;\n                    dq.push_back(v);\n                }\n            }\n            return false;\n        };\n\n        // Core removal check (ignores anchor locking)\n        auto can_remove_core = [&](int id)->bool {\n            int c = grid[id];\n            if (c == 0) return false;\n            if (!isBC[c]) return false; // never touch interior colors\n            if (!is_accessible(id)) return false;\n            if (sizeCount[c] <= 1) return false;\n\n            // Do not create adjacency 0\u2013interior\n            int i = id / n, j = id % n;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d != 0 && isIC[d]) return false;\n            }\n\n            // Preserve non-zero adjacencies: don't remove last c\u2013d contact\n            int neighCols[4], counts[4], cnt = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d == 0 || d == c) continue;\n                bool found = false;\n                for (int t = 0; t < cnt; ++t) {\n                    if (neighCols[t] == d) { counts[t]++; found = true; break; }\n                }\n                if (!found) { neighCols[cnt] = d; counts[cnt] = 1; cnt++; }\n            }\n            for (int t = 0; t < cnt; ++t) {\n                int d = neighCols[t];\n                int a = c, b = d; if (a > b) swap(a, b);\n                if (pairCount[a][b] <= counts[t]) return false;\n            }\n\n            // Preserve adjacency to 0\n            int sameN = 0, zeroN = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d == c) sameN++;\n                else if (d == 0) zeroN++;\n            }\n            int bSides = borderSides(id);\n            int delta0 = sameN - zeroN - bSides;\n            if (adj0Count[c] + delta0 <= 0) return false;\n\n            // Connectivity: avoid articulation points\n            if (degSame[id] > 1) {\n                if (!neighbors_connected_after_remove(id, c)) return false;\n            }\n            return true;\n        };\n\n        auto can_remove = [&](int id)->bool {\n            if (protectAnchor[id]) return false;\n            return can_remove_core(id);\n        };\n        auto can_remove_allow_anchor = [&](int id)->bool {\n            return can_remove_core(id);\n        };\n\n        auto remove_cell = [&](int id) {\n            int c = grid[id];\n            int i = id / n, j = id % n;\n            // Update pair counts\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d != 0 && d != c) {\n                    int a = c, b = d; if (a > b) swap(a, b);\n                    if (pairCount[a][b] > 0) pairCount[a][b]--;\n                }\n            }\n            // Update degSame and adj0Count\n            int sameN = 0, zeroN = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int nid = ni*n + nj;\n                int d = grid[nid];\n                if (d == c) { degSame[nid]--; sameN++; }\n                else if (d == 0) zeroN++;\n            }\n            int bSides = borderSides(id);\n            adj0Count[c] += (sameN - zeroN - bSides);\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d != 0 && d != c) adj0Count[d]++;\n            }\n\n            sizeCount[c]--;\n            grid[id] = 0;\n            degSame[id] = 0;\n            if (protectAnchor[id]) protectAnchor[id] = 0;\n        };\n\n        auto hasZeroNeighbor_cached = [&](int id)->bool {\n            int i = id / n, j = id % n;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                if (grid[ni*n + nj] == 0) return true;\n            }\n            return false;\n        };\n\n        // Candidate priority\n        auto candidate_priority = [&](int id)->int {\n            int c = grid[id];\n            int i = id / n, j = id % n;\n            int neighCols[4], counts[4], cnt = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d == 0 || d == c) continue;\n                bool found = false;\n                for (int t = 0; t < cnt; ++t) {\n                    if (neighCols[t] == d) { counts[t]++; found = true; break; }\n                }\n                if (!found) { neighCols[cnt] = d; counts[cnt] = 1; cnt++; }\n            }\n            int slackMin = 1000000, slackSum = 0;\n            for (int t = 0; t < cnt; ++t) {\n                int d = neighCols[t];\n                int a = c, b = d; if (a > b) swap(a, b);\n                int slack = pairCount[a][b] - counts[t];\n                slackMin = min(slackMin, slack);\n                slackSum += slack;\n            }\n            if (cnt == 0) slackMin = 1000, slackSum = 1000;\n            // delta0 estimate\n            int sameN = 0, zeroN = 0;\n            for (int k = 0; k < 4; ++k) {\n                int ni = i + dr[k], nj = j + dc[k];\n                if (!inb(ni, nj)) continue;\n                int d = grid[ni*n + nj];\n                if (d == c) sameN++;\n                else if (d == 0) zeroN++;\n            }\n            int bSides = borderSides(id);\n            int delta0 = sameN - zeroN - bSides;\n\n            int score = 0;\n            score += degSame[id] * 8; // lower deg preferred\n            score += (slackMin >= 3 ? 0 : (slackMin == 2 ? 6 : 12));\n            score += max(0, 6 - min(slackSum, 6)); // prefer larger total slack\n            if (adj0Count[c] > 2 && delta0 < 0) score -= 2; // reduce extra 0-edges\n            if (adjToIC[id]) score += 60; // deprioritize guards (we won't remove)\n            score += (hasZeroNeighbor_cached(id) ? 0 : 3);\n            return score;\n        };\n\n        deque<int> Q;\n        vector<char> inQ(N, 0);\n        vector<int> boundaryIds;\n        boundaryIds.reserve(N);\n        for (int id = 0; id < N; ++id) if (isBoundaryPos[id]) boundaryIds.push_back(id);\n        if (runType == 3) {\n            shuffle(boundaryIds.begin(), boundaryIds.end(), rng);\n        }\n\n        auto push_cand = [&](int id) {\n            if (inQ[id]) return;\n            if (grid[id] == 0) return;\n            int c = grid[id];\n            if (!isBC[c]) return;\n            if (!isBoundaryPos[id] && !hasZeroNeighbor_cached(id)) return;\n            int pr = candidate_priority(id);\n            if (pr <= 12) Q.push_front(id);\n            else Q.push_back(id);\n            inQ[id] = 1;\n        };\n\n        // Seed candidates\n        for (int id : boundaryIds) {\n            int c = grid[id];\n            if (c == 0 || !isBC[c]) continue;\n            push_cand(id);\n        }\n\n        double start_t = timer.elapsed();\n        double budget_main = time_budget * 0.78;\n        double budget_cleanup = time_budget * 0.22;\n\n        // Optional pre-thinning for runType 4/5 (no anchors initially)\n        if (runType == 4 || runType == 5) {\n            double pre_budget = budget_main * 0.45;\n            double pre_start = timer.elapsed();\n            while (!Q.empty() && timer.elapsed() - pre_start < pre_budget) {\n                int id = Q.front(); Q.pop_front();\n                inQ[id] = 0;\n                if (grid[id] == 0) continue;\n                if (!is_accessible(id)) continue;\n                if (can_remove_core(id)) {\n                    int i = id / n, j = id % n;\n                    remove_cell(id);\n                    for (int k = 0; k < 4; ++k) {\n                        int ni = i + dr[k], nj = j + dc[k];\n                        if (!inb(ni, nj)) continue;\n                        int nid = ni*n + nj;\n                        if (grid[nid] != 0) push_cand(nid);\n                    }\n                } else {\n                    if (timer.elapsed() - pre_start < pre_budget * 0.95) {\n                        Q.push_back(id);\n                        inQ[id] = 1;\n                    }\n                }\n            }\n            // Recompute anchors on current grid\n            auto pairEdgesNow = build_pair_edges_from_grid(grid);\n            choose_anchors(pairEdgesNow, 4);\n        }\n\n        // Main carving\n        while (!Q.empty() && timer.elapsed() - start_t < budget_main) {\n            int id = Q.front(); Q.pop_front();\n            inQ[id] = 0;\n            if (grid[id] == 0) continue;\n            if (!is_accessible(id)) continue;\n            if (protectAnchor[id]) continue;\n            if (can_remove(id)) {\n                int i = id / n, j = id % n;\n                remove_cell(id);\n                for (int k = 0; k < 4; ++k) {\n                    int ni = i + dr[k], nj = j + dc[k];\n                    if (!inb(ni, nj)) continue;\n                    int nid = ni*n + nj;\n                    if (grid[nid] != 0) push_cand(nid);\n                }\n            } else {\n                if (timer.elapsed() - start_t < budget_main * 0.95) {\n                    Q.push_back(id);\n                    inQ[id] = 1;\n                }\n            }\n        }\n\n        // Cleanup: allow anchors to be removed too, if safe\n        if (budget_cleanup > 0 && timer.elapsed() - start_t < time_budget) {\n            bool improved = true;\n            int rounds = 0;\n            while (improved && timer.elapsed() - start_t < time_budget) {\n                improved = false;\n                rounds++;\n                for (int id = 0; id < N; ++id) {\n                    if (timer.elapsed() - start_t > time_budget) break;\n                    if (grid[id] == 0) continue;\n                    int c = grid[id];\n                    if (!isBC[c]) continue;\n                    if (!is_accessible(id)) continue;\n                    if (rounds <= 2 && !protectAnchor[id]) continue; // target anchors first\n                    if (can_remove_allow_anchor(id)) {\n                        int i = id / n, j = id % n;\n                        remove_cell(id);\n                        improved = true;\n                        for (int k = 0; k < 4; ++k) {\n                            int ni = i + dr[k], nj = j + dc[k];\n                            if (!inb(ni, nj)) continue;\n                            int nid = ni*n + nj;\n                            if (grid[nid] != 0) push_cand(nid);\n                        }\n                    }\n                }\n                int steps = 0;\n                while (!Q.empty() && timer.elapsed() - start_t < time_budget && steps < 800) {\n                    int id = Q.front(); Q.pop_front();\n                    inQ[id] = 0;\n                    if (grid[id] == 0) continue;\n                    if (!is_accessible(id)) continue;\n                    if (can_remove_allow_anchor(id)) {\n                        int i = id / n, j = id % n;\n                        remove_cell(id);\n                        improved = true;\n                        for (int k = 0; k < 4; ++k) {\n                            int ni = i + dr[k], nj = j + dc[k];\n                            if (!inb(ni, nj)) continue;\n                            int nid = ni*n + nj;\n                            if (grid[nid] != 0) push_cand(nid);\n                        }\n                    }\n                    steps++;\n                }\n            }\n        }\n\n        int zeros = 0;\n        for (int id = 0; id < N; ++id) if (grid[id] == 0) zeros++;\n        return {zeros, grid};\n    };\n\n    vector<int> bestGrid = origGrid;\n    int bestZeros = 0;\n\n    // Runs: baseline + two anchored variants + two-phase anchored (two variants) as time allows\n    vector<int> plan = {0, 1, 2, 4, 5};\n    for (int rt : plan) {\n        double remain = TIME_LIMIT - timer.elapsed();\n        if (remain < 0.15) break;\n        double budget;\n        if (rt == 0) budget = min(0.75, max(0.28, remain * 0.36));\n        else if (rt == 4 || rt == 5) budget = min(0.70, max(0.18, remain * 0.50));\n        else budget = min(0.60, max(0.17, remain * 0.42));\n        auto [zeros, grid] = run_once(rt, budget);\n        if (zeros > bestZeros) { bestZeros = zeros; bestGrid = move(grid); }\n    }\n\n    // Output best grid\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            if (j) cout << ' ';\n            cout << bestGrid[i*n + j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, D, Q;\n    if (!(cin >> N >> D >> Q)) return 0;\n\n    // RNG (deterministic per N,D,Q)\n    uint64_t seed = 1469598103934665603ull;\n    auto mix = [&](uint64_t x){ seed ^= x + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2); };\n    mix((uint64_t)N); mix((uint64_t)D); mix((uint64_t)Q);\n    mt19937_64 rng(seed);\n    uniform_real_distribution<double> ur01(0.0, 1.0);\n    uniform_real_distribution<double> urSym(-1.0, 1.0);\n\n    // Correlator estimate for 1-bit sensing\n    vector<int> score(N, 0);\n    vector<double> w_est(N, 1.0); // positive estimate for adaptive queries\n    vector<int> count_pm(N, 0);   // track +1 vs -1 usage per item\n\n    // Store rows for post-phase logistic regression (without intercept)\n    vector<int8_t> Aflat; Aflat.reserve((size_t)Q * N);\n    vector<int8_t> Y;     Y.reserve(Q);\n\n    vector<int> a(N, 0);\n    string resp;\n\n    auto output_query = [&](const vector<int>& a_out){\n        int nL = 0, nR = 0;\n        for (int i = 0; i < N; i++) {\n            if (a_out[i] == +1) nL++; else nR++;\n        }\n        cout << nL << ' ' << nR;\n        for (int i = 0; i < N; i++) if (a_out[i] == +1) cout << ' ' << i;\n        for (int i = 0; i < N; i++) if (a_out[i] == -1) cout << ' ' << i;\n        cout << \"\\n\" << flush;\n    };\n\n    auto build_balanced_query = [&](const vector<double>& w_cur, vector<int>& a_out){\n        vector<int> perm(N);\n        iota(perm.begin(), perm.end(), 0);\n        shuffle(perm.begin(), perm.end(), rng);\n\n        vector<int> L; L.reserve(N);\n        vector<int> R; R.reserve(N);\n        double sumL = 0.0, sumR = 0.0;\n\n        // Greedy balance predicted sums\n        for (int idx : perm) {\n            double wi = w_cur[idx];\n            if (sumL < sumR) {\n                L.push_back(idx); sumL += wi;\n            } else if (sumR < sumL) {\n                R.push_back(idx); sumR += wi;\n            } else {\n                // sums equal: use side-usage bias, then random\n                if (count_pm[idx] > 0) { R.push_back(idx); sumR += wi; }\n                else if (count_pm[idx] < 0) { L.push_back(idx); sumL += wi; }\n                else {\n                    if (ur01(rng) < 0.5) { L.push_back(idx); sumL += wi; }\n                    else { R.push_back(idx); sumR += wi; }\n                }\n            }\n        }\n        // Ensure both sides non-empty\n        if (L.empty()) { L.push_back(R.back()); sumL += w_cur[R.back()]; sumR -= w_cur[R.back()]; R.pop_back(); }\n        if (R.empty()) { R.push_back(L.back()); sumR += w_cur[L.back()]; sumL -= w_cur[L.back()]; L.pop_back(); }\n\n        // Small random perturbation (swap one random pair) to diversify queries\n        if (ur01(rng) < 0.10 && !L.empty() && !R.empty()) {\n            int il = uniform_int_distribution<int>(0, (int)L.size()-1)(rng);\n            int ir = uniform_int_distribution<int>(0, (int)R.size()-1)(rng);\n            swap(L[il], R[ir]);\n        }\n\n        // Randomly assign which side is +1 (\"left\")\n        bool flip = (ur01(rng) < 0.5);\n        a_out.assign(N, -1);\n        if (!flip) for (int idx : L) a_out[idx] = +1;\n        else for (int idx : R) a_out[idx] = +1;\n\n        // Update usage counts\n        for (int i = 0; i < N; i++) count_pm[i] += (a_out[i] > 0 ? +1 : -1);\n    };\n\n    // Query loop: adaptive balanced from the start\n    for (int q = 0; q < Q; q++) {\n        build_balanced_query(w_est, a);\n        output_query(a);\n\n        if (!(cin >> resp)) return 0;\n        int y = 0;\n        if (resp[0] == '>') y = +1;\n        else if (resp[0] == '<') y = -1;\n        else if (resp[0] == '=') y = 0;\n\n        if (y != 0) {\n            for (int i = 0; i < N; i++) {\n                score[i] += y * a[i];\n            }\n            for (int i = 0; i < N; i++) Aflat.push_back((int8_t)(a[i] > 0 ? 1 : -1));\n            Y.push_back((int8_t)y);\n        }\n\n        // Refresh w_est from correlator (shift to positive)\n        int mn = INT_MAX;\n        for (int i = 0; i < N; i++) mn = min(mn, score[i]);\n        double shift = -(double)mn + 1.0;\n        for (int i = 0; i < N; i++) w_est[i] = max(1e-3, (double)score[i] + shift);\n    }\n\n    // Initial weights from correlator\n    vector<double> w(N, 1.0);\n    {\n        int mn = INT_MAX;\n        for (int i = 0; i < N; i++) mn = min(mn, score[i]);\n        double shift = -(double)mn + 1.0;\n        for (int i = 0; i < N; i++) w[i] = max(1e-6, (double)score[i] + shift);\n    }\n\n    // Post-phase 1-bit logistic regression without intercept\n    int M = (int)Y.size();\n    if (M > 0) {\n        vector<double> x = w; // init from correlator\n        // Normalize to mean ~1 for stability\n        double meanx = 0.0;\n        for (double v : x) meanx += v;\n        meanx = (meanx > 0 ? meanx / N : 1.0);\n        for (double &v : x) v /= meanx;\n\n        double lambda = 1e-3; // L2 regularization\n        double Lg = 0.25 * (double)N * (double)M + 2.0 * lambda; // coarse Lipschitz bound\n        double eta = 1.0 / Lg;\n        int iters = min(220, max(80, M / 4));\n\n        vector<double> grad(N, 0.0);\n        const int8_t* Adata = Aflat.data();\n\n        for (int it = 0; it < iters; it++) {\n            fill(grad.begin(), grad.end(), 0.0);\n            for (int r = 0; r < M; r++) {\n                const int8_t* row = Adata + (size_t)r * N;\n                int8_t yr = Y[r];\n                double s = 0.0;\n                for (int i = 0; i < N; i++) s += (double)row[i] * x[i];\n                // p = - y * sigma(-y s)\n                double ys = (double)yr * s;\n                double p;\n                if (ys >= 0) {\n                    double e = exp(-ys);\n                    p = -(double)yr * (e / (1.0 + e));\n                } else {\n                    double e = exp(ys);\n                    p = -(double)yr * (1.0 / (1.0 + e));\n                }\n                for (int i = 0; i < N; i++) grad[i] += p * (double)row[i];\n            }\n            for (int i = 0; i < N; i++) {\n                grad[i] += 2.0 * lambda * x[i];\n                x[i] -= eta * grad[i];\n                if (x[i] < 1e-12) x[i] = 1e-12; // nonnegativity\n            }\n        }\n        w.swap(x);\n    }\n\n    // Multi-start LPT initializations (3 starts with small jitters), pick best by surrogate objective\n    auto build_assignment_by_LPT = [&](const vector<double>& wt) -> vector<int> {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng); // random tie-break\n        stable_sort(ord.begin(), ord.end(), [&](int i, int j){ return wt[i] > wt[j]; });\n        vector<int> assign(N, -1);\n        vector<double> binSum(D, 0.0);\n        for (int idx : ord) {\n            int best = 0;\n            double bestSum = binSum[0];\n            for (int b = 1; b < D; b++) {\n                if (binSum[b] < bestSum) { bestSum = binSum[b]; best = b; }\n            }\n            assign[idx] = best;\n            binSum[best] += w[idx]; // use true estimated weights w for objective\n        }\n        return assign;\n    };\n    auto objective_sqsum = [&](const vector<int>& assign)->double{\n        vector<double> s(D, 0.0);\n        for (int i = 0; i < N; i++) s[assign[i]] += w[i];\n        double v = 0.0;\n        for (int b = 0; b < D; b++) v += s[b] * s[b];\n        return v;\n    };\n\n    vector<int> best_assign;\n    double best_obj = 1e300;\n\n    // Start 0: plain w\n    {\n        vector<double> wt = w;\n        auto assign0 = build_assignment_by_LPT(wt);\n        double obj0 = objective_sqsum(assign0);\n        if (obj0 < best_obj) { best_obj = obj0; best_assign.swap(assign0); }\n    }\n    // Start 1: small jitter\n    {\n        vector<double> wt = w;\n        for (int i = 0; i < N; i++) wt[i] *= (1.0 + 0.05 * urSym(rng));\n        auto assign1 = build_assignment_by_LPT(wt);\n        double obj1 = objective_sqsum(assign1);\n        if (obj1 < best_obj) { best_obj = obj1; best_assign.swap(assign1); }\n    }\n    // Start 2: slightly larger jitter\n    {\n        vector<double> wt = w;\n        for (int i = 0; i < N; i++) wt[i] *= (1.0 + 0.10 * urSym(rng));\n        auto assign2 = build_assignment_by_LPT(wt);\n        double obj2 = objective_sqsum(assign2);\n        if (obj2 < best_obj) { best_obj = obj2; best_assign.swap(assign2); }\n    }\n\n    // Build bins from best assignment\n    vector<vector<int>> bins(D);\n    vector<double> binSum(D, 0.0);\n    vector<int> posInBin(N, -1);\n    auto addToBin = [&](int b, int id){\n        posInBin[id] = (int)bins[b].size();\n        bins[b].push_back(id);\n        binSum[b] += w[id];\n    };\n    auto removeFromBin = [&](int b, int id){\n        int pos = posInBin[id];\n        int last = bins[b].back();\n        bins[b][pos] = last;\n        posInBin[last] = pos;\n        bins[b].pop_back();\n        posInBin[id] = -1;\n        binSum[b] -= w[id];\n    };\n    auto moveItem = [&](int from, int to, int id){\n        removeFromBin(from, id);\n        addToBin(to, id);\n    };\n    auto swapItems = [&](int b1, int b2, int id1, int id2){\n        removeFromBin(b1, id1);\n        removeFromBin(b2, id2);\n        addToBin(b1, id2);\n        addToBin(b2, id1);\n    };\n\n    for (int i = 0; i < N; i++) addToBin(best_assign[i], i);\n    vector<int> assign = best_assign;\n\n    // Local search: single moves to lightest and exhaustive pair swaps across heavier\u2013lighter pairs\n    Timer timer;\n    const double TIME_BUDGET = 0.35; // seconds\n\n    auto extremes = [&](){\n        int l = 0, h = 0;\n        for (int b = 1; b < D; b++) {\n            if (binSum[b] < binSum[l]) l = b;\n            if (binSum[b] > binSum[h]) h = b;\n        }\n        return pair<int,int>(l,h);\n    };\n\n    while (timer.elapsed() < TIME_BUDGET) {\n        auto [lbin, hbin] = extremes();\n\n        // 1) Single move from any bin to lightest bin\n        double best_delta = 0.0;\n        int mv_from = -1, mv_id = -1;\n        for (int b = 0; b < D; b++) {\n            if (b == lbin) continue;\n            double gap = binSum[b] - binSum[lbin];\n            if (gap <= 1e-12) continue;\n            double target = 0.5 * gap;\n            for (int id : bins[b]) {\n                double wi = w[id];\n                if (wi < gap) {\n                    double delta = -2.0 * wi * gap + 2.0 * wi * wi; // change in s_b^2 + s_l^2\n                    if (mv_from == -1 || delta < best_delta - 1e-15 ||\n                        (fabs(delta - best_delta) <= 1e-15 && fabs(wi - target) < fabs(w[mv_id] - target))) {\n                        best_delta = delta;\n                        mv_from = b;\n                        mv_id = id;\n                    }\n                }\n            }\n        }\n        if (mv_from != -1 && best_delta < -1e-12) {\n            moveItem(mv_from, lbin, mv_id);\n            assign[mv_id] = lbin;\n            continue;\n        }\n\n        // 2) Pair swap across all heavier-lighter bin pairs\n        double best_swap_delta = 0.0;\n        int sw_bh = -1, sw_bl = -1, sw_i = -1, sw_j = -1;\n        for (int bh = 0; bh < D; bh++) {\n            for (int bl = 0; bl < D; bl++) {\n                if (binSum[bh] <= binSum[bl] + 1e-12) continue;\n                double gap = binSum[bh] - binSum[bl];\n                double target = 0.5 * gap;\n                for (int i_id : bins[bh]) {\n                    double wi = w[i_id];\n                    for (int j_id : bins[bl]) {\n                        double wj = w[j_id];\n                        double d = wi - wj;\n                        if (d <= 1e-12 || d >= gap - 1e-12) continue;\n                        double delta = 2.0 * (d * d - d * gap); // change in s_h^2 + s_l^2\n                        if (sw_bh == -1 || delta < best_swap_delta - 1e-15 ||\n                            (fabs(delta - best_swap_delta) <= 1e-15 && fabs(d - target) < fabs((w[sw_i] - w[sw_j]) - target))) {\n                            best_swap_delta = delta;\n                            sw_bh = bh; sw_bl = bl; sw_i = i_id; sw_j = j_id;\n                        }\n                    }\n                }\n            }\n        }\n        if (sw_bh != -1 && best_swap_delta < -1e-12) {\n            swapItems(sw_bh, sw_bl, sw_i, sw_j);\n            assign[sw_i] = sw_bl;\n            assign[sw_j] = sw_bh;\n            continue;\n        }\n\n        // No improving move found\n        break;\n    }\n\n    // Output final assignment\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << assign[i];\n    }\n    cout << '\\n' << flush;\n\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Heuristic solver with destination scoring by min-below and improved, safe splitting.\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    if (!(cin >> n >> m)) return 0;\n    vector<vector<int>> st(m); // bottom -> top\n    int per = n / m;\n    for (int i = 0; i < m; ++i) {\n        st[i].resize(per);\n        for (int j = 0; j < per; ++j) cin >> st[i][j];\n    }\n\n    const int INF = n + 1;\n    vector<pair<int,int>> ops;\n    ops.reserve(3000);\n\n    auto get_min_stack = [&](int idx)->int{\n        if (st[idx].empty()) return INF;\n        int mn = st[idx][0];\n        for (int v : st[idx]) if (v < mn) mn = v;\n        return mn;\n    };\n\n    auto carry_chain = [&](int &t) {\n        bool changed = true;\n        while (changed && t <= n) {\n            changed = false;\n            for (int i = 0; i < m && t <= n; ++i) {\n                if (!st[i].empty() && st[i].back() == t) {\n                    st[i].pop_back();\n                    ops.emplace_back(t, 0);\n                    ++t;\n                    changed = true;\n                }\n            }\n        }\n    };\n\n    auto move_suffix = [&](int src, int start_idx, int dest) {\n        // Move st[src][start_idx..end] to top of st[dest]\n        int S = (int)st[src].size();\n        if (!(0 <= start_idx && start_idx < S)) return; // safety\n        for (int k = start_idx; k < S; ++k) {\n            st[dest].push_back(st[src][k]);\n        }\n        st[src].resize(start_idx);\n    };\n\n    auto find_box = [&](int v, int &src, int &idx) {\n        src = -1; idx = -1;\n        for (int i = 0; i < m; ++i) {\n            for (int j = (int)st[i].size() - 1; j >= 0; --j) {\n                if (st[i][j] == v) { src = i; idx = j; return; }\n            }\n        }\n    };\n\n    auto choose_dest_minPrefix = [&](int src, int jv, int exclude1=-1, int exclude2=-1) -> int {\n        // Score candidates by how many from the block top are < min(old dest content).\n        int s = (int)st[src].size() - jv;\n        vector<int> topDown;\n        topDown.reserve(s);\n        for (int k = (int)st[src].size() - 1; k >= jv; --k) topDown.push_back(st[src][k]);\n\n        int bestD = -1;\n        int bestPrefix = -1;\n        int bestM = -1;\n        int bestTop = -1;\n        int bestNegSize = 0; // prefer smaller size\n        for (int d = 0; d < m; ++d) {\n            if (d == src || d == exclude1 || d == exclude2) continue;\n            int M = get_min_stack(d);\n            int prefix = 0;\n            while (prefix < s && topDown[prefix] < M) ++prefix; // strictly less than M\n\n            int topVal = st[d].empty() ? INF : st[d].back();\n            int negSize = - (int)st[d].size();\n\n            // tie-breakers: larger prefix, then larger M, then larger topVal, then smaller size\n            if (prefix > bestPrefix ||\n                (prefix == bestPrefix && (M > bestM ||\n                 (M == bestM && (topVal > bestTop ||\n                  (topVal == bestTop && negSize > bestNegSize)))))) {\n                bestPrefix = prefix;\n                bestM = M;\n                bestTop = topVal;\n                bestNegSize = negSize;\n                bestD = d;\n            }\n        }\n        if (bestD == -1) {\n            // fallback respecting excludes\n            for (int d = 0; d < m; ++d) {\n                if (d != src && d != exclude1 && d != exclude2) { bestD = d; break; }\n            }\n        }\n        return bestD;\n    };\n\n    auto choose_heavy_dest = [&](int src, int avoid)->int{\n        // For the heavy segment, prefer destination with large min (M) and large top.\n        int bestD = -1;\n        int bestM = -1;\n        int bestTop = -1;\n        int bestNegSize = 0;\n        for (int d = 0; d < m; ++d) {\n            if (d == src || d == avoid) continue;\n            int M = get_min_stack(d);\n            int topVal = st[d].empty() ? INF : st[d].back();\n            int negSize = - (int)st[d].size();\n            if (M > bestM || (M == bestM && (topVal > bestTop ||\n                 (topVal == bestTop && negSize > bestNegSize)))) {\n                bestM = M;\n                bestTop = topVal;\n                bestNegSize = negSize;\n                bestD = d;\n            }\n        }\n        if (bestD == -1) {\n            for (int d = 0; d < m; ++d) {\n                if (d != src && d != avoid) { bestD = d; break; }\n            }\n        }\n        return bestD;\n    };\n\n    auto attempt_split_then_move = [&](int src, int idx) -> bool {\n        // Try to split the above-block to create a good prefix >= 2 for the remainder on a good destination.\n        int jv = idx + 1;\n        int s = (int)st[src].size() - jv;\n        if (s <= 1) return false;\n\n        // Block top-down\n        vector<int> topDown;\n        topDown.reserve(s);\n        for (int k = (int)st[src].size() - 1; k >= jv; --k) topDown.push_back(st[src][k]);\n\n        // Choose best destination for the remainder\n        int destBest = choose_dest_minPrefix(src, jv);\n        if (destBest == -1) return false;\n        int Mbest = get_min_stack(destBest);\n\n        // Compute overall best-prefix for this dest; if already good (>=2), no need to split\n        int bestPrefix = 0;\n        while (bestPrefix < s && topDown[bestPrefix] < Mbest) ++bestPrefix;\n        if (bestPrefix >= 2) return false;\n\n        // Compute split point r: number of top elements >= Mbest\n        int r = 0;\n        while (r < s && topDown[r] >= Mbest) ++r;\n        if (r >= s) return false; // no \"good\" part\n        // Count consecutive \"good\" elements after r\n        int p = 0;\n        while (r + p < s && topDown[r + p] < Mbest) ++p;\n\n        // Require at least 2 good elements to justify an extra move AND r > 0 to move a non-empty heavy segment\n        if (p < 2 || r == 0) return false;\n\n        // Choose destination for the heavy top segment\n        int heavyDest = choose_heavy_dest(src, destBest);\n        if (heavyDest == -1) return false;\n\n        // First move: heavy top segment of size r to heavyDest\n        int startA = (int)st[src].size() - r; // start index of top r segment\n        if (!(0 <= startA && startA < (int)st[src].size())) return false; // safety\n        int vA = st[src][startA];\n        move_suffix(src, startA, heavyDest);\n        ops.emplace_back(vA, heavyDest + 1);\n\n        // Second move: remainder above t to a good destination (avoid heavyDest)\n        int new_jv = idx + 1;\n        if (!(0 <= new_jv && new_jv < (int)st[src].size())) {\n            // If nothing remains above t, no second move is needed\n            return true;\n        }\n        int dest2 = choose_dest_minPrefix(src, new_jv, heavyDest, -1);\n        if (dest2 == -1) {\n            // As a last resort, put it back onto best dest\n            dest2 = destBest;\n        }\n        int vB = st[src][new_jv];\n        move_suffix(src, new_jv, dest2);\n        ops.emplace_back(vB, dest2 + 1);\n\n        return true;\n    };\n\n    int t = 1;\n    carry_chain(t);\n\n    while (t <= n) {\n        int src, idx;\n        find_box(t, src, idx);\n        if (src == -1) break; // shouldn't happen\n\n        if (idx == (int)st[src].size() - 1) {\n            // Already top\n            st[src].pop_back();\n            ops.emplace_back(t, 0);\n            ++t;\n            carry_chain(t);\n            continue;\n        }\n\n        // Try improved, safe split\n        if (attempt_split_then_move(src, idx)) {\n            carry_chain(t);\n            continue;\n        }\n\n        // Normal: move whole suffix with destination chosen by min-prefix\n        int jv = idx + 1;\n        int dest = choose_dest_minPrefix(src, jv);\n        if (dest == -1) {\n            // Fallback: choose any stack != src\n            for (int d = 0; d < m; ++d) if (d != src) { dest = d; break; }\n        }\n        int v = st[src][jv];\n        move_suffix(src, jv, dest);\n        ops.emplace_back(v, dest + 1);\n\n        carry_chain(t);\n    }\n\n    if ((int)ops.size() > 5000) {\n        // Should not happen\n        ops.resize(5000);\n    }\n    for (auto &op : ops) {\n        cout << op.first << ' ' << op.second << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    unsigned long long x;\n    XorShift64(unsigned long long seed=88172645463393265ULL){x=seed;}\n    unsigned long long next() { x ^= x<<7; x ^= x>>9; return x; }\n    unsigned int nextUInt() { return (unsigned int)(next() & 0xFFFFFFFFULL); }\n};\n\nstruct UEdge { int u, v; char ch_uv, ch_vu; };\nstruct AdjPort {\n    int to;\n    int eid;\n    char ch;\n    long long target;\n    long long used;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    using ld = long double;\n    auto T0 = chrono::high_resolution_clock::now();\n    auto elapsed_ms = [&](){\n        return (double)chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - T0).count();\n    };\n\n    int N;\n    if (!(cin >> N)) return 0;\n\n    vector<string> hWall(max(0, N-1));\n    for (int i = 0; i < N-1; i++) cin >> hWall[i];\n    vector<string> vWall(N);\n    for (int i = 0; i < N; i++) cin >> vWall[i];\n\n    vector<vector<int>> d(N, vector<int>(N));\n    long long Dsum_ll = 0;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) { cin >> d[i][j]; Dsum_ll += d[i][j]; }\n    ld Dsum = (ld)Dsum_ll;\n\n    auto inb = [&](int i, int j){ return 0 <= i && i < N && 0 <= j && j < N; };\n    auto canMove = [&](int i, int j, int di, int dj){\n        int ni = i + di, nj = j + dj;\n        if (!inb(ni, nj)) return false;\n        if (di == 0 && dj == 1) return vWall[i][j] == '0';\n        if (di == 0 && dj == -1) return vWall[i][j-1] == '0';\n        if (di == 1 && dj == 0) return hWall[i][j] == '0';\n        if (di == -1 && dj == 0) return hWall[i-1][j] == '0';\n        return false;\n    };\n    auto id = [&](int i, int j){ return i * N + j; };\n    auto coord = [&](int v){ return pair<int,int>(v / N, v % N); };\n\n    int V = N * N;\n    int root = 0;\n\n    // Build undirected grid graph edges\n    vector<UEdge> edges; edges.reserve(2*N*(N-1));\n    vector<vector<pair<int,int>>> nodeNbrEid(V);\n    auto add_edge = [&](int u, int v, char ch_uv, char ch_vu){\n        int eid = (int)edges.size();\n        edges.push_back({u,v,ch_uv,ch_vu});\n        nodeNbrEid[u].push_back({v,eid});\n        nodeNbrEid[v].push_back({u,eid});\n    };\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int u = id(i,j);\n        if (j+1 < N && canMove(i,j,0,1)) add_edge(u, id(i,j+1), 'R','L');\n        if (i+1 < N && canMove(i,j,1,0)) add_edge(u, id(i+1,j), 'D','U');\n    }\n    int M = (int)edges.size();\n\n    // Directed adjacency for BFS\n    vector<vector<int>> adjGrid(V);\n    for (int u = 0; u < V; u++) for (auto [v,eid] : nodeNbrEid[u]) adjGrid[u].push_back(v);\n\n    // BFS distances\n    vector<int> dist(V, -1);\n    deque<int> dq;\n    dist[root] = 0; dq.push_back(root);\n    while (!dq.empty()) {\n        int u = dq.front(); dq.pop_front();\n        for (int v : adjGrid[u]) if (dist[v] == -1) { dist[v] = dist[u] + 1; dq.push_back(v); }\n    }\n    int maxDist = 0; for (int v = 0; v < V; v++) if (dist[v] > maxDist) maxDist = dist[v];\n\n    // Candidate parents and layers\n    vector<vector<int>> candPar(V);\n    for (int v = 0; v < V; v++) if (v != root) for (int u : adjGrid[v]) if (dist[u] == dist[v]-1) candPar[v].push_back(u);\n    vector<vector<int>> layers(maxDist+1);\n    for (int v = 0; v < V; v++) layers[dist[v]].push_back(v);\n\n    // Build balanced SPT for given weights\n    auto build_par_balanced = [&](const vector<ld>& w){\n        vector<int> par(V, -1), rootBranch(V, -1), childCnt(V,0);\n        vector<ld> load(V,0.0L), branchLoad(V,0.0L);\n        for (int v : layers[1]) {\n            par[v] = root; rootBranch[v] = v;\n            load[root] += w[v]; branchLoad[v] += w[v]; childCnt[root]++;\n        }\n        for (int Ld = 2; Ld <= maxDist; Ld++) for (int v : layers[Ld]) {\n            ld best1=1e300L, best2=1e300L; int best3=INT_MAX, bestP=candPar[v][0];\n            for (int p : candPar[v]) {\n                int b = rootBranch[p];\n                ld k1 = branchLoad[b], k2 = load[p]; int k3 = childCnt[p];\n                if (k1 < best1-1e-18L || (fabsl(k1-best1)<=1e-18L && (k2 < best2-1e-18L || (fabsl(k2-best2)<=1e-18L && (k3 < best3 || (k3==best3 && p<bestP)))))) {\n                    best1=k1; best2=k2; best3=k3; bestP=p;\n                }\n            }\n            int p = bestP; par[v]=p; int b = rootBranch[p]; rootBranch[v]=b;\n            for (int u=p; u!=-1; u=par[u]) load[u]+=w[v];\n            branchLoad[b]+=w[v]; childCnt[p]++;\n        }\n        return par;\n    };\n\n    const long long Lmax = 100000;\n\n    // Choose best base tree by proxy on base multiplicity\n    struct Param { ld beta, gamma; };\n    vector<Param> params = {\n        {0.0L, 0.0L}, {0.3L, 0.0L}, {0.5L, 0.0L}, {0.7L, 0.0L},\n        {0.3L, 0.5L}, {0.5L, 0.5L}, {0.7L, 0.5L}, {0.5L, 1.0L}\n    };\n    auto find_eid = [&](int a, int b){ for (auto [to,eid] : nodeNbrEid[a]) if (to==b) return eid; return -1; };\n    vector<int> par_best;\n    ld best_score = numeric_limits<ld>::infinity();\n    for (auto prm : params) {\n        vector<ld> w(V,0.0L);\n        for (int v = 0; v < V; v++) {\n            auto [i,j] = coord(v);\n            ld base = sqrtl((ld)max(0, d[i][j]));\n            ld dep = (ld)dist[v] + prm.gamma; if (v==root) dep = 1.0L + prm.gamma;\n            w[v] = prm.beta>0 ? base/powl(max((ld)1e-12,dep), prm.beta) : base;\n        }\n        vector<int> par = build_par_balanced(w);\n        vector<long long> deg0(V,0); long long L0=0;\n        for (int v = 0; v < V; v++) if (v != root) { int p=par[v]; int eid=find_eid(v,p); if (eid<0) continue; deg0[v]+=2; deg0[p]+=2; L0+=2; }\n        ld Ad0=0;\n        for (int v = 0; v < V; v++) { long long kv=max(1LL,deg0[v]/2); auto [i,j]=coord(v); Ad0 += (ld)d[i][j]/(ld)kv; }\n        ld score = 0.5L*((ld)L0*Ad0 - (ld)Dsum);\n        if (score < best_score) { best_score=score; par_best=move(par); }\n    }\n    vector<int> par = par_best;\n\n    // Base multiplicities (tree edges doubled)\n    vector<long long> m(M,0), base_m(M,0), deg(V,0);\n    long long L = 0;\n    for (int v=0; v<V; v++) if (v!=root) {\n        int p = par[v]; int eid = find_eid(v,p); if (eid<0) continue;\n        m[eid]+=2; base_m[eid]=2; deg[v]+=2; deg[p]+=2; L+=2;\n    }\n\n    // Initialize k and Ad\n    vector<long long> k(V,1);\n    ld Ad=0;\n    for (int v=0; v<V; v++) { long long kv=max(1LL,deg[v]/2); k[v]=kv; auto [i,j]=coord(v); Ad += (ld)d[i][j]/(ld)kv; }\n\n    // Precompute arrays and incidence lists\n    vector<int> eu(M), ev(M); vector<char> ch_uv(M), ch_vu(M);\n    for (int eid=0; eid<M; eid++){ eu[eid]=edges[eid].u; ev[eid]=edges[eid].v; ch_uv[eid]=edges[eid].ch_uv; ch_vu[eid]=edges[eid].ch_vu; }\n    vector<vector<int>> incEdges(V);\n    for (int eid=0; eid<M; eid++){ incEdges[eu[eid]].push_back(eid); incEdges[ev[eid]].push_back(eid); }\n\n    auto val_for_edge = [&](int eid)->ld{\n        int u=eu[eid], v=ev[eid]; auto [ui,uj]=coord(u); auto [vi,vj]=coord(v);\n        ld du=d[ui][uj], dv=d[vi][vj]; ld ku0=max<ld>(1.0,(ld)k[u]), kv0=max<ld>(1.0,(ld)k[v]);\n        return du/(ku0*(ku0+1.0L)) + dv/(kv0*(kv0+1.0L));\n    };\n    auto harm_for_edge = [&](int eid)->ld{\n        if (m[eid] <= base_m[eid]) return (ld)1e300;\n        int u=eu[eid], v=ev[eid]; ld ku0=(ld)k[u], kv0=(ld)k[v];\n        if (ku0<=1.0L || kv0<=1.0L) return (ld)1e300;\n        auto [ui,uj]=coord(u); auto [vi,vj]=coord(v);\n        ld du=d[ui][uj], dv=d[vi][vj];\n        return du/(ku0*(ku0-1.0L)) + dv/(kv0*(kv0-1.0L));\n    };\n    auto val_for_edge_with_delta = [&](int eid, int du_k, int dv_k)->ld{\n        int u=eu[eid], v=ev[eid]; ld ku0=(ld)k[u]+(ld)du_k, kv0=(ld)k[v]+(ld)dv_k;\n        ku0=max<ld>(1.0L, ku0); kv0=max<ld>(1.0L, kv0);\n        auto [ui,uj]=coord(u); auto [vi,vj]=coord(v);\n        ld du=d[ui][uj], dv=d[vi][vj];\n        return du/(ku0*(ku0+1.0L)) + dv/(kv0*(kv0+1.0L));\n    };\n\n    // Greedy additions (KKT threshold)\n    struct AddItem { ld val; int eid; int ku, kv; bool operator<(const AddItem& o) const { return val < o.val; } };\n    priority_queue<AddItem> pqAdd;\n    for (int eid=0; eid<M; eid++) pqAdd.push({val_for_edge(eid), eid, (int)k[eu[eid]], (int)k[ev[eid]]});\n\n    long long remLen = Lmax - L;\n    const ld eps = 1e-18L;\n    while (remLen >= 2 && !pqAdd.empty()) {\n        if (elapsed_ms() > 1500.0) break;\n        auto it = pqAdd.top(); pqAdd.pop();\n        int eid=it.eid, u=eu[eid], v=ev[eid];\n        if (it.ku!=(int)k[u] || it.kv!=(int)k[v]) { pqAdd.push({val_for_edge(eid), eid, (int)k[u], (int)k[v]}); continue; }\n        ld theta = 2.0L*Ad/((ld)L+2.0L);\n        if (it.val <= theta + eps) break;\n        if (remLen < 2) break;\n        long long ku_old=k[u], kv_old=k[v];\n        m[eid]+=2; deg[u]+=2; deg[v]+=2; k[u]++; k[v]++; L+=2; remLen-=2;\n        auto [ui,uj]=coord(u); auto [vi,vj]=coord(v);\n        ld duv=d[ui][uj], dvv=d[vi][vj];\n        Ad += duv*(1.0L/(ld)k[u] - 1.0L/(ld)ku_old);\n        Ad += dvv*(1.0L/(ld)k[v] - 1.0L/(ld)kv_old);\n        for (int e2: incEdges[u]) pqAdd.push({val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n        for (int e2: incEdges[v]) pqAdd.push({val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n    }\n\n    // Length-preserving 2-opt (small top-K scanning)\n    struct RemItem { ld harm; int eid; int ku, kv; };\n    struct RemComp { bool operator()(const RemItem&a, const RemItem&b) const { return a.harm > b.harm; } };\n    priority_queue<RemItem, vector<RemItem>, RemComp> pqRem;\n    for (int eid=0; eid<M; eid++) if (m[eid] > base_m[eid]) pqRem.push({harm_for_edge(eid), eid, (int)k[eu[eid]], (int)k[ev[eid]]});\n\n    int swapLimit=2000, swaps=0;\n    const int ATRIES=4, RTRIES=6;\n    while (swaps < swapLimit && !pqAdd.empty() && !pqRem.empty()) {\n        if (elapsed_ms() > 1750.0) break;\n        vector<AddItem> addPopped;\n        while ((int)addPopped.size() < ATRIES && !pqAdd.empty()) {\n            auto a = pqAdd.top(); pqAdd.pop();\n            int u=eu[a.eid], v=ev[a.eid];\n            if (a.ku!=(int)k[u] || a.kv!=(int)k[v]) { pqAdd.push({val_for_edge(a.eid), a.eid, (int)k[u], (int)k[v]}); continue; }\n            addPopped.push_back(a);\n        }\n        if (addPopped.empty()) break;\n\n        ld bestGain=0.0L; int bestAdd=-1, bestRem=-1;\n        vector<RemItem> remBuffer; remBuffer.reserve(RTRIES);\n        for (auto &a : addPopped) {\n            int eAdd=a.eid, ua=eu[eAdd], va=ev[eAdd];\n            remBuffer.clear();\n            int tries=0;\n            while (tries < RTRIES && !pqRem.empty()) {\n                auto r = pqRem.top(); pqRem.pop();\n                int ur=eu[r.eid], vr=ev[r.eid];\n                if (m[r.eid] <= base_m[r.eid]) {\n                    // outdated\n                } else if (r.ku!=(int)k[ur] || r.kv!=(int)k[vr]) {\n                    ld hnew = harm_for_edge(r.eid);\n                    if (hnew < 1e299L) pqRem.push({hnew, r.eid, (int)k[ur], (int)k[vr]});\n                } else {\n                    ld hcur = harm_for_edge(r.eid);\n                    if (hcur < 1e299L) { r.harm=hcur; remBuffer.push_back(r); tries++; }\n                }\n            }\n            for (auto &r : remBuffer) {\n                int eRem=r.eid, ur=eu[eRem], vr=ev[eRem];\n                int du_k=0, dv_k=0;\n                if (ua==ur) du_k--; if (ua==vr) du_k--;\n                if (va==ur) dv_k--; if (va==vr) dv_k--;\n                ld valA = val_for_edge_with_delta(eAdd, du_k, dv_k);\n                ld gain = valA - r.harm;\n                if (gain > bestGain + 1e-18L) { bestGain=gain; bestAdd=eAdd; bestRem=eRem; }\n            }\n            for (auto &r : remBuffer) pqRem.push(r);\n        }\n        for (auto &a : addPopped) pqAdd.push(a);\n        if (bestAdd==-1 || bestGain<=1e-18L) break;\n\n        int ur=eu[bestRem], vr=ev[bestRem];\n        long long ku_old=k[ur], kv_old=k[vr];\n        m[bestRem]-=2; deg[ur]-=2; deg[vr]-=2; k[ur]--; k[vr]--;\n        auto [uri,urj]=coord(ur); auto [vri,vrj]=coord(vr);\n        Ad += (ld)d[uri][urj]*(1.0L/(ld)k[ur] - 1.0L/(ld)ku_old);\n        Ad += (ld)d[vri][vrj]*(1.0L/(ld)k[vr] - 1.0L/(ld)kv_old);\n\n        int ua=eu[bestAdd], va=ev[bestAdd];\n        long long kua_old=k[ua], kva_old=k[va];\n        m[bestAdd]+=2; deg[ua]+=2; deg[va]+=2; k[ua]++; k[va]++;\n        auto [uai,uaj]=coord(ua); auto [vai,vaj]=coord(va);\n        Ad += (ld)d[uai][uaj]*(1.0L/(ld)k[ua] - 1.0L/(ld)kua_old);\n        Ad += (ld)d[vai][vaj]*(1.0L/(ld)k[va] - 1.0L/(ld)kva_old);\n\n        for (int e2: incEdges[ur]) { pqAdd.push({val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]}); if (m[e2]>base_m[e2]) pqRem.push({harm_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]}); }\n        for (int e2: incEdges[vr]) { pqAdd.push({val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]}); if (m[e2]>base_m[e2]) pqRem.push({harm_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]}); }\n        for (int e2: incEdges[ua]) { pqAdd.push({val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]}); if (m[e2]>base_m[e2]) pqRem.push({harm_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]}); }\n        for (int e2: incEdges[va]) { pqAdd.push({val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]}); if (m[e2]>base_m[e2]) pqRem.push({harm_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]}); }\n        swaps++;\n    }\n\n    // Post-2opt greedy fill\n    remLen = Lmax - L;\n    if (remLen >= 2) {\n        priority_queue<AddItem> pqAdd2;\n        for (int eid=0; eid<M; eid++) pqAdd2.push({val_for_edge(eid), eid, (int)k[eu[eid]], (int)k[ev[eid]]});\n        while (remLen >= 2 && !pqAdd2.empty()) {\n            if (elapsed_ms() > 1860.0) break;\n            auto it = pqAdd2.top(); pqAdd2.pop();\n            int eid=it.eid, u=eu[eid], v=ev[eid];\n            if (it.ku!=(int)k[u] || it.kv!=(int)k[v]) { pqAdd2.push({val_for_edge(eid), eid, (int)k[u], (int)k[v]}); continue; }\n            ld theta = 2.0L*Ad/((ld)L+2.0L);\n            if (it.val <= theta + eps) break;\n            if (remLen < 2) break;\n            long long ku_old=k[u], kv_old=k[v];\n            m[eid]+=2; deg[u]+=2; deg[v]+=2; k[u]++; k[v]++; L+=2; remLen-=2;\n            auto [ui,uj]=coord(u); auto [vi,vj]=coord(v);\n            Ad += (ld)d[ui][uj]*(1.0L/(ld)k[u] - 1.0L/(ld)ku_old);\n            Ad += (ld)d[vi][vj]*(1.0L/(ld)k[v] - 1.0L/(ld)kv_old);\n            for (int e2: incEdges[u]) pqAdd2.push({val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n            for (int e2: incEdges[v]) pqAdd2.push({val_for_edge(e2), e2, (int)k[eu[e2]], (int)k[ev[e2]]});\n        }\n    }\n\n    // Build adjacency ports for Euler traversal\n    vector<vector<AdjPort>> portsBase(V);\n    for (int eid=0; eid<M; eid++) if (m[eid] > 0) {\n        int u=eu[eid], v=ev[eid]; long long tgt=m[eid]/2;\n        portsBase[u].push_back({v,eid,ch_uv[eid],tgt,0});\n        portsBase[v].push_back({u,eid,ch_vu[eid],tgt,0});\n    }\n\n    // k_final for urgency normalization\n    vector<long long> k_final(V,1);\n    {\n        vector<long long> degF(V,0);\n        for (int eid=0; eid<M; eid++) if (m[eid] > 0) { degF[eu[eid]] += m[eid]; degF[ev[eid]] += m[eid]; }\n        for (int v=0; v<V; v++) k_final[v] = max(1LL, degF[v]/2);\n    }\n\n    // Build a route by proper Euler (stack -> vertex sequence -> moves)\n    auto build_route = [&](unsigned long long seed, bool allowBridgeCheck, ld urgMul)->pair<string, ld>{\n        vector<vector<AdjPort>> ports = portsBase;\n        vector<long long> rem = m;\n        XorShift64 rng(seed);\n        vector<int> visStamp(V, -1);\n        int curStamp = 0;\n\n        auto isNonBridgeIfRemove = [&](int v, int to, int eid)->bool{\n            if (!allowBridgeCheck) return true;\n            if (rem[eid] >= 2) return true;\n            if (elapsed_ms() > 1985.0) return true;\n            curStamp++;\n            deque<int> q;\n            visStamp[v] = curStamp; q.push_back(v);\n            while (!q.empty()) {\n                int x = q.front(); q.pop_front();\n                if (x == to) return true;\n                for (auto &pp : ports[x]) {\n                    int e2 = pp.eid;\n                    if (e2 == eid) continue;\n                    if (rem[e2] <= 0) continue;\n                    int y = pp.to;\n                    if (visStamp[y] != curStamp) { visStamp[y]=curStamp; q.push_back(y); }\n                }\n            }\n            return false;\n        };\n\n        auto choose_from = [&](int v, const vector<int>& idxs, int step, const vector<int>& lastVisited)->int{\n            if (idxs.empty()) return -1;\n            int bestIdx=-1; ld bestKey=1e100L; long long bestRem=-1; ld bestUrg=-1.0L;\n            for (int idx : idxs) {\n                int eid=ports[v][idx].eid, to=ports[v][idx].to;\n                ld t=(ld)ports[v][idx].target, uused=(ld)ports[v][idx].used;\n                ld noise = (ld)((rng.nextUInt() & 4095U))*1e-6L;\n                ld key = (t>0.0L) ? ((uused+noise)/t) : noise;\n                auto [ti,tj]=coord(to);\n                ld urg = urgMul * (ld)d[ti][tj] * (ld)((long long)step + 1 - (long long)lastVisited[to]) / (ld)max(1LL, k_final[to]);\n                if (key < bestKey - 1e-12L ||\n                    (fabsl(key-bestKey) <= 0.08L && urg > bestUrg + 1e-12L) ||\n                    (fabsl(key-bestKey) <= 1e-12L && fabsl(urg-bestUrg) <= 1e-12L && rem[eid] > bestRem)) {\n                    bestKey=key; bestIdx=idx; bestRem=rem[eid]; bestUrg=urg;\n                }\n            }\n            return bestIdx;\n        };\n\n        vector<int> st; st.reserve(L+5);\n        vector<int> out; out.reserve(L+5);\n        vector<int> lastVisited(V, 0);\n        int step = 0;\n\n        st.push_back(root);\n        while (!st.empty()) {\n            int v = st.back();\n            int chosen = -1;\n            vector<int> allIdx; allIdx.reserve(4);\n            vector<int> nonBridgeIdx; nonBridgeIdx.reserve(4);\n            for (int idx = 0; idx < (int)ports[v].size(); idx++) {\n                int eid=ports[v][idx].eid; if (rem[eid] <= 0) continue;\n                int to=ports[v][idx].to;\n                allIdx.push_back(idx);\n                if (rem[eid] >= 2) nonBridgeIdx.push_back(idx);\n                else if (isNonBridgeIfRemove(v,to,eid)) nonBridgeIdx.push_back(idx);\n            }\n            if (!nonBridgeIdx.empty()) chosen = choose_from(v, nonBridgeIdx, step, lastVisited);\n            if (chosen == -1) chosen = choose_from(v, allIdx, step, lastVisited);\n\n            if (chosen != -1) {\n                int eid=ports[v][chosen].eid, to=ports[v][chosen].to;\n                rem[eid]--;\n                ports[v][chosen].used++;\n                st.push_back(to);\n                lastVisited[to] = step + 1;\n                step++;\n            } else {\n                out.push_back(v);\n                st.pop_back();\n            }\n        }\n        reverse(out.begin(), out.end());\n        // derive moves from consecutive vertices\n        string ans;\n        ans.reserve(out.size()? out.size()-1: 0);\n        for (size_t i = 0; i+1 < out.size(); i++) {\n            int a=out[i], b=out[i+1];\n            auto [ai,aj]=coord(a); auto [bi,bj]=coord(b);\n            char ch='?';\n            if (bi==ai && bj==aj+1) ch='R';\n            else if (bi==ai && bj==aj-1) ch='L';\n            else if (bi==ai+1 && bj==aj) ch='D';\n            else if (bi==ai-1 && bj==aj) ch='U';\n            else {\n                bool found=false;\n                for (auto &pp: portsBase[a]) if (pp.to==b) { ch=pp.ch; found=true; break; }\n                if (!found) ch='U';\n            }\n            ans.push_back(ch);\n        }\n        if ((int)ans.size() > 100000) ans.resize(100000);\n\n        // exact score S\u0304\n        vector<int> firstVisit(V,-1), prevVisit(V,-1);\n        long double tri=0.0L;\n        int ci=0, cj=0;\n        auto apply_move = [&](char c){\n            if (c=='R') cj++;\n            else if (c=='L') cj--;\n            else if (c=='D') ci++;\n            else if (c=='U') ci--;\n        };\n        for (int t=1; t<=(int)ans.size(); t++) {\n            char c=ans[t-1]; apply_move(c);\n            int vtx=ci*N+cj; if (prevVisit[vtx]==-1) firstVisit[vtx]=t;\n            else { int g=t-prevVisit[vtx]; auto [vi,vj]=coord(vtx); tri += (long double)d[vi][vj]*(long double)g*(long double)(g-1)*0.5L; }\n            prevVisit[vtx]=t;\n        }\n        int Llen=(int)ans.size();\n        for (int vtx=0; vtx<V; vtx++) if (prevVisit[vtx]!=-1) {\n            int g=(Llen - prevVisit[vtx]) + (firstVisit[vtx]==-1 ? 0 : firstVisit[vtx]);\n            auto [vi,vj]=coord(vtx); tri += (long double)d[vi][vj]*(long double)g*(long double)(g-1)*0.5L;\n        }\n        long double Sbar = Llen>0 ? tri/(long double)Llen : 0.0L;\n        return {ans, (ld)Sbar};\n    };\n\n    // Try multiple tours, pick best by exact S\u0304\n    string bestAns; ld bestSc = numeric_limits<ld>::infinity();\n    vector<tuple<unsigned long long,bool,ld>> trials = {\n        {123456789ULL, true, 1.00L},\n        {987654321ULL, false, 0.85L},\n        {19260817ULL,  true, 1.25L},\n        {998244353ULL, true, 1.60L},\n        {1000003ULL,   false, 0.70L}\n    };\n    for (auto [seed, br, urgMul] : trials) {\n        if (elapsed_ms() > 1990.0) break;\n        auto [a, s] = build_route(seed, br, urgMul);\n        if (s < bestSc) { bestSc = s; bestAns = move(a); }\n    }\n\n    // Validate; if invalid, fallback to a safe DFS tour on the BFS tree\n    auto is_valid_route = [&](const string& ans)->bool{\n        int ci=0, cj=0;\n        for (char c : ans) {\n            int ni=ci, nj=cj;\n            if (c=='R') nj++; else if (c=='L') nj--; else if (c=='D') ni++; else if (c=='U') ni--;\n            if (!inb(ni,nj)) return false;\n            int di=ni-ci, dj=nj-cj;\n            if (!canMove(ci,cj,di,dj)) return false;\n            ci=ni; cj=nj;\n        }\n        return ci==0 && cj==0 && (int)ans.size() <= 100000;\n    };\n    if (!is_valid_route(bestAns)) {\n        // Fallback: simple DFS on the BFS tree (each tree edge twice)\n        vector<vector<pair<int,char>>> gridMoves(V);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            int u = id(i,j);\n            if (j+1 < N && canMove(i,j,0,1)) { gridMoves[u].push_back({id(i,j+1),'R'}); gridMoves[id(i,j+1)].push_back({u,'L'}); }\n            if (i+1 < N && canMove(i,j,1,0)) { gridMoves[u].push_back({id(i+1,j),'D'}); gridMoves[id(i+1,j)].push_back({u,'U'}); }\n        }\n        vector<vector<int>> children(V);\n        for (int v=0; v<V; v++) if (v!=root) children[par[v]].push_back(v);\n        string ans;\n        function<void(int)> dfs = [&](int u){\n            for (int v : children[u]) {\n                char ch='?';\n                for (auto &pr : gridMoves[u]) if (pr.first==v) { ch=pr.second; break; }\n                if (ch=='?') continue;\n                ans.push_back(ch);\n                dfs(v);\n                if (ch=='R') ans.push_back('L');\n                else if (ch=='L') ans.push_back('R');\n                else if (ch=='U') ans.push_back('D');\n                else if (ch=='D') ans.push_back('U');\n            }\n        };\n        dfs(root);\n        bestAns = ans;\n        if ((int)bestAns.size() > 100000) bestAns.resize(100000);\n    }\n\n    if ((int)bestAns.size() > 100000) bestAns.resize((size_t)100000);\n    cout << bestAns << '\\n';\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, r;\n    DSU(int n=0): n(n), p(n), r(n,0) { iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }\n    bool same(int a, int b){ return find(a)==find(b); }\n    bool unite(int a, int b){\n        a = find(a); b = find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n};\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed=88172645463393265ull){ x=seed; }\n    uint64_t next(){\n        x ^= x<<7;\n        x ^= x>>9;\n        return x;\n    }\n    int next_int(int l, int r){ // inclusive\n        return l + (int)(next() % (uint64_t)(r-l+1));\n    }\n    double next_double(){ return (next() >> 11) * (1.0 / (1ull<<53)); }\n};\n\nstruct Pos { short i, j; };\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if(!(cin >> N >> M)) return 0;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> A(N);\n    for(int i=0;i<N;i++) cin >> A[i];\n    vector<string> t(M);\n    for(int k=0;k<M;k++) cin >> t[k];\n\n    auto time_start = chrono::high_resolution_clock::now();\n    auto elapsed = [&](){\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - time_start).count();\n    };\n    const double TIME_LIMIT = 1.95;\n\n    XorShift rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Positions per letter\n    vector<vector<Pos>> pos(26);\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            int c = A[i][j]-'A';\n            pos[c].push_back(Pos{(short)i,(short)j});\n        }\n    }\n\n    // Start distance per letter (min)\n    vector<int> startDist(26, INT_MAX/4);\n    for(int c=0;c<26;c++){\n        for(auto &p : pos[c]){\n            startDist[c] = min(startDist[c], abs(p.i - si) + abs(p.j - sj));\n        }\n        if(startDist[c] == INT_MAX/4) startDist[c] = 20; // safety\n    }\n\n    // Letter-to-letter proxies:\n    // - dLLavg: average of K smallest distances (K=2) for movement proxy\n    // - dLLmin: minimum distance for DP lower bound\n    const int K_MIN = 2;\n    vector<vector<double>> dLLavg(26, vector<double>(26, 0.0));\n    vector<vector<int>> dLLmin(26, vector<int>(26, 0));\n    for(int a=0;a<26;a++){\n        for(int b=0;b<26;b++){\n            vector<int> ds;\n            ds.reserve(pos[a].size() * pos[b].size());\n            for(auto &pa : pos[a]){\n                for(auto &pb : pos[b]){\n                    ds.push_back(abs(pa.i - pb.i) + abs(pa.j - pb.j));\n                }\n            }\n            if(ds.empty()){\n                dLLavg[a][b] = 8.0;\n                dLLmin[a][b] = 8;\n            }else{\n                sort(ds.begin(), ds.end());\n                int cnt = min((int)ds.size(), K_MIN);\n                double s=0;\n                for(int i=0;i<cnt;i++) s += ds[i];\n                dLLavg[a][b] = s / cnt;\n                dLLmin[a][b] = ds[0];\n            }\n        }\n    }\n\n    // Overlap matrix f[i][j] in [0..4]\n    auto overlap = [&](const string& a, const string& b)->int{\n        for(int k=4;k>=1;k--){\n            bool ok = true;\n            for(int x=0;x<k;x++){\n                if(a[5-k+x] != b[x]){ ok=false; break; }\n            }\n            if(ok) return k;\n        }\n        return 0;\n    };\n    vector<vector<int>> f(M, vector<int>(M, 0));\n    for(int i=0;i<M;i++){\n        for(int j=0;j<M;j++){\n            if(i==j) continue;\n            f[i][j] = overlap(t[i], t[j]);\n        }\n    }\n\n    // Word letters\n    vector<array<int,5>> wlett(M);\n    for(int i=0;i<M;i++) for(int k=0;k<5;k++) wlett[i][k] = t[i][k] - 'A';\n\n    // Intra-word suffix proxy movement costs for each possible overlap ov (0..4)\n    vector<array<double,5>> intraSuf(M);\n    for(int j=0;j<M;j++){\n        double pref[6]={0};\n        for(int k=0;k<4;k++){\n            pref[k+1] = pref[k] + dLLavg[wlett[j][k]][wlett[j][k+1]];\n        }\n        for(int ov=0; ov<=4; ov++){\n            intraSuf[j][ov] = pref[4] - pref[ov];\n        }\n    }\n\n    // Estimated edge weights (maximize = -estimated_cost) and start weights\n    vector<vector<double>> W_est(M, vector<double>(M, -1e100));\n    vector<double> Wstart(M, 0.0);\n    for(int i=0;i<M;i++){\n        for(int j=0;j<M;j++){\n            if(i==j) continue;\n            int ov = f[i][j];\n            int lastc = wlett[i][4];\n            int firstNew = wlett[j][ov];\n            double boundary = dLLavg[lastc][firstNew];\n            double c = (5 - ov) + boundary + intraSuf[j][ov];\n            W_est[i][j] = -c;\n        }\n    }\n    for(int i=0;i<M;i++){\n        double c = 5.0 + startDist[wlett[i][0]] + (intraSuf[i][0]);\n        Wstart[i] = -c;\n    }\n\n    auto sum_overlaps = [&](const vector<int>& pi)->int{\n        int s=0;\n        for(int i=0;i+1<(int)pi.size();i++) s += f[pi[i]][pi[i+1]];\n        return s;\n    };\n\n    // Builders\n    auto build_by_arc_packing_weight = [&](const vector<vector<double>>& W, const vector<double>& Ws)->vector<int>{\n        struct Arc { int u, v; double w; uint64_t r; };\n        vector<Arc> arcs; arcs.reserve((size_t)M*(M-1));\n        for(int u=0;u<M;u++){\n            for(int v=0;v<M;v++){\n                if(u==v) continue;\n                arcs.push_back({u,v,W[u][v], (uint64_t)rng.next()});\n            }\n        }\n        sort(arcs.begin(), arcs.end(), [](const Arc& a, const Arc& b){\n            if(a.w != b.w) return a.w > b.w;\n            return a.r < b.r;\n        });\n        vector<int> succ(M,-1), pred(M,-1);\n        DSU uf(M);\n        for(const auto& e: arcs){\n            int u=e.u, v=e.v;\n            if(succ[u]!=-1) continue;\n            if(pred[v]!=-1) continue;\n            if(uf.same(u,v)) continue;\n            succ[u]=v; pred[v]=u; uf.unite(u,v);\n        }\n        // Chains\n        vector<char> used(M,0);\n        vector<vector<int>> chains;\n        for(int i=0;i<M;i++){\n            if(pred[i]==-1){\n                vector<int> chain;\n                int cur=i;\n                while(cur!=-1){\n                    chain.push_back(cur);\n                    used[cur]=1;\n                    cur = succ[cur];\n                }\n                chains.push_back(move(chain));\n            }\n        }\n        for(int i=0;i<M;i++) if(!used[i]){ chains.push_back(vector<int>{i}); used[i]=1; }\n        int Cn = (int)chains.size();\n        vector<int> head(Cn), tail(Cn);\n        for(int c=0;c<Cn;c++){ head[c]=chains[c].front(); tail[c]=chains[c].back(); }\n        // start chain by best Ws\n        int start = 0; double bestWs = -1e100;\n        for(int c=0;c<Cn;c++){ double w=Ws[head[c]]; if(w>bestWs){ bestWs=w; start=c; } }\n        vector<char> usedC(Cn,0);\n        vector<int> order; order.reserve(Cn);\n        int cur=start; usedC[cur]=1; order.push_back(cur);\n        for(int step=1; step<Cn; step++){\n            int nxt=-1; double best=-1e100;\n            for(int c=0;c<Cn;c++){\n                if(usedC[c]) continue;\n                double w = W[tail[cur]][head[c]];\n                if(w>best){ best=w; nxt=c; }\n            }\n            if(nxt==-1){ for(int c=0;c<Cn;c++) if(!usedC[c]){ nxt=c; break; } }\n            usedC[nxt]=1; order.push_back(nxt); cur=nxt;\n        }\n        vector<int> pi; pi.reserve(M);\n        for(int idx: order) for(int node: chains[idx]) pi.push_back(node);\n        return pi;\n    };\n\n    auto build_by_arc_packing_overlap = [&](){\n        vector<vector<double>> W_ov(M, vector<double>(M, 0.0));\n        for(int i=0;i<M;i++) for(int j=0;j<M;j++) if(i!=j) W_ov[i][j] = (double)f[i][j];\n        vector<double> Ws(M, 0.0);\n        return build_by_arc_packing_weight(W_ov, Ws);\n    };\n\n    auto build_by_nn = [&](int s, const vector<vector<double>>& W)->vector<int>{\n        vector<char> used(M,0);\n        vector<int> pi; pi.reserve(M);\n        int cur = s; used[cur]=1; pi.push_back(cur);\n        for(int k=1;k<M;k++){\n            int bestj=-1; double best=-1e100;\n            for(int j=0;j<M;j++){\n                if(used[j]) continue;\n                double w = W[cur][j];\n                if(w>best){ best=w; bestj=j; }\n            }\n            if(bestj==-1){ for(int j=0;j<M;j++) if(!used[j]){ bestj=j; break; } }\n            used[bestj]=1; pi.push_back(bestj); cur=bestj;\n        }\n        return pi;\n    };\n\n    // DP cost with strong early exit using tail lower bound based on minLL\n    auto dp_cost = [&](const vector<int>& letters, long long cutoff)->long long{\n        int L = (int)letters.size();\n        if(L==0) return (long long)1e18;\n        vector<int> tailLB(L, 0);\n        for(int k=L-2;k>=0;k--){\n            tailLB[k] = tailLB[k+1] + 1 + dLLmin[letters[k]][letters[k+1]];\n        }\n        int c0 = letters[0];\n        int P0 = (int)pos[c0].size();\n        if(P0==0) return (long long)1e18;\n        vector<int> dp_prev(P0);\n        int min_prev = INT_MAX/4;\n        for(int q=0;q<P0;q++){\n            int ii=pos[c0][q].i, jj=pos[c0][q].j;\n            dp_prev[q] = abs(ii-si) + abs(jj-sj) + 1;\n            min_prev = min(min_prev, dp_prev[q]);\n        }\n        if((long long)min_prev + tailLB[0] >= cutoff) return (long long)1e18;\n        for(int l=1;l<L;l++){\n            int c = letters[l];\n            int Pc = (int)pos[c].size();\n            int cp = letters[l-1];\n            int Pp = (int)pos[cp].size();\n            vector<int> dp_curr(Pc, INT_MAX/4);\n            int min_curr = INT_MAX/4;\n            for(int q=0;q<Pc;q++){\n                int qi=pos[c][q].i, qj=pos[c][q].j;\n                int best = INT_MAX/4;\n                for(int pidx=0;pidx<Pp;pidx++){\n                    int pi_i=pos[cp][pidx].i, pi_j=pos[cp][pidx].j;\n                    int cand = dp_prev[pidx] + abs(qi-pi_i) + abs(qj-pi_j) + 1;\n                    if(cand < best) best = cand;\n                }\n                dp_curr[q] = best;\n                if(best < min_curr) min_curr = best;\n            }\n            dp_prev.swap(dp_curr);\n            long long lb = (long long)min_curr + (l < L ? tailLB[l] : 0);\n            if(lb >= cutoff) return (long long)1e18;\n        }\n        int lastc = letters.back();\n        int Pl = (int)pos[lastc].size();\n        int bestv = INT_MAX/4;\n        for(int q=0;q<Pl;q++) bestv = min(bestv, dp_prev[q]);\n        return bestv;\n    };\n\n    auto dp_solve = [&](const vector<int>& letters)->pair<long long, vector<pair<int,int>>>{\n        int L = (int)letters.size();\n        vector<vector<int>> parent(L);\n        vector<int> dp_prev, dp_curr;\n        int c0 = letters[0];\n        int P0 = (int)pos[c0].size();\n        dp_prev.assign(P0, INT_MAX/4);\n        parent[0].assign(P0, -1);\n        for(int q=0;q<P0;q++){\n            int ii = pos[c0][q].i, jj = pos[c0][q].j;\n            int dist = abs(ii - si) + abs(jj - sj);\n            dp_prev[q] = dist + 1;\n        }\n        for(int l=1;l<L;l++){\n            int c = letters[l];\n            int Pc = (int)pos[c].size();\n            int cp = letters[l-1];\n            int Pp = (int)pos[cp].size();\n            dp_curr.assign(Pc, INT_MAX/4);\n            parent[l].assign(Pc, -1);\n            for(int q=0;q<Pc;q++){\n                int qi = pos[c][q].i, qj = pos[c][q].j;\n                int best = INT_MAX/4, bestp=-1;\n                for(int pidx=0;pidx<Pp;pidx++){\n                    int pi_i = pos[cp][pidx].i, pi_j = pos[cp][pidx].j;\n                    int cand = dp_prev[pidx] + abs(qi - pi_i) + abs(qj - pi_j) + 1;\n                    if(cand < best){\n                        best = cand;\n                        bestp = pidx;\n                    }\n                }\n                dp_curr[q] = best;\n                parent[l][q] = bestp;\n            }\n            dp_prev.swap(dp_curr);\n        }\n        int lastc = letters.back();\n        int Pl = (int)pos[lastc].size();\n        int bestq=0, bestv=INT_MAX/4;\n        for(int q=0;q<Pl;q++){\n            if(dp_prev[q] < bestv){ bestv = dp_prev[q]; bestq=q; }\n        }\n        vector<pair<int,int>> ops(letters.size());\n        int idx = bestq;\n        for(int l=L-1;l>=0;l--){\n            int c = letters[l];\n            ops[l] = {pos[c][idx].i, pos[c][idx].j};\n            if(l>0){\n                idx = parent[l][idx];\n                if(idx < 0) idx = 0;\n            }\n        }\n        return { (long long)bestv, ops };\n    };\n\n    auto build_letters_from_pi = [&](const vector<int>& pi)->vector<int>{\n        vector<int> letters;\n        letters.reserve(5*M);\n        for(int k=0;k<5;k++) letters.push_back(t[pi[0]][k]-'A');\n        for(int i=1;i<M;i++){\n            int a = pi[i-1], b = pi[i];\n            int ov = f[a][b];\n            for(int k=ov;k<5;k++) letters.push_back(t[b][k]-'A');\n        }\n        return letters;\n    };\n\n    // Overlap deltas\n    auto ov_insert_delta = [&](const vector<int>& p, int i, int j2)->int{\n        int N = p.size();\n        int x = p[i];\n        auto e = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        int delta = 0;\n        if(i == 0){\n            if(N >= 2) delta -= e(p[0], p[1]);\n        }else{\n            delta -= e(p[i-1], p[i]);\n            if(i < N-1){\n                delta -= e(p[i], p[i+1]);\n                delta += e(p[i-1], p[i+1]);\n            }\n        }\n        int len = N - 1;\n        auto getAfter = [&](int k)->int{\n            if(k < i) return p[k];\n            else return p[k+1];\n        };\n        if(len == 0) return delta;\n        if(j2 == 0){\n            int R = getAfter(0);\n            delta += e(x, R);\n        }else if(j2 == len){\n            int L = getAfter(len-1);\n            delta += e(L, x);\n        }else{\n            int L = getAfter(j2-1);\n            int R = getAfter(j2);\n            delta -= e(L, R);\n            delta += e(L, x);\n            delta += e(x, R);\n        }\n        return delta;\n    };\n    auto ov_swap_delta = [&](const vector<int>& p, int i, int j)->int{\n        if(i==j) return 0;\n        if(i>j) swap(i,j);\n        int n = p.size();\n        auto e = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        int a = p[i], b = p[j];\n        int before = 0, after = 0;\n        if(i+1 == j){\n            if(i-1>=0){ before += e(p[i-1], a); after += e(p[i-1], b); }\n            before += e(a, b);\n            after += e(b, a);\n            if(j+1<n){ before += e(b, p[j+1]); after += e(a, p[j+1]); }\n        }else{\n            if(i-1>=0){ before += e(p[i-1], a); after += e(p[i-1], b); }\n            if(i+1<n){ before += e(a, p[i+1]); after += e(b, p[i+1]); }\n            if(j-1>=0){ before += e(p[j-1], b); after += e(p[j-1], a); }\n            if(j+1<n){ before += e(b, p[j+1]); after += e(a, p[j+1]); }\n        }\n        return after - before;\n    };\n    auto ov_block_delta = [&](const vector<int>& p, int L, int R, int K)->int{\n        int N = p.size();\n        int B = R-L+1;\n        auto e = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        int delta = 0;\n        if(L>0) delta -= e(p[L-1], p[L]);\n        if(R<N-1) delta -= e(p[R], p[R+1]);\n        if(L>0 && R<N-1) delta += e(p[L-1], p[R+1]);\n        auto rem = [&](int k)->int{ return (k < L) ? p[k] : p[k + B]; };\n        if(K>0 && K < N-B){\n            delta -= e(rem(K-1), rem(K));\n        }\n        if(K>0){\n            delta += e(rem(K-1), p[L]);\n        }\n        if(K < N-B){\n            delta += e(p[R], rem(K));\n        }\n        return delta;\n    };\n\n    // Estimated deltas (W_est + Wstart)\n    auto est_insert_delta = [&](const vector<int>& p, int i, int j2)->double{\n        int n = p.size();\n        int x = p[i];\n        double delta = 0.0;\n        if(i == 0){\n            delta -= Wstart[p[0]];\n            if(n >= 2){\n                delta -= W_est[p[0]][p[1]];\n                delta += Wstart[p[1]];\n            }\n        }else{\n            delta -= W_est[p[i-1]][p[i]];\n            if(i < n-1){\n                delta -= W_est[p[i]][p[i+1]];\n                delta += W_est[p[i-1]][p[i+1]];\n            }\n        }\n        int len = n - 1;\n        auto getAfter = [&](int k)->int{\n            if(k < i) return p[k];\n            else return p[k+1];\n        };\n        if(len == 0){\n            delta += Wstart[x];\n            return delta;\n        }\n        if(j2 == 0){\n            int R = getAfter(0);\n            delta -= Wstart[R];\n            delta += Wstart[x];\n            delta += W_est[x][R];\n        }else if(j2 == len){\n            int L = getAfter(len-1);\n            delta += W_est[L][x];\n        }else{\n            int L = getAfter(j2-1);\n            int R = getAfter(j2);\n            delta -= W_est[L][R];\n            delta += W_est[L][x];\n            delta += W_est[x][R];\n        }\n        return delta;\n    };\n    auto est_swap_delta = [&](const vector<int>& p, int i, int j)->double{\n        if(i==j) return 0.0;\n        if(i>j) swap(i,j);\n        int n = p.size();\n        auto partial = [&](const vector<int>& arr)->double{\n            double s = 0.0;\n            if(i==0 || j==0) s += Wstart[arr[0]];\n            auto addEdge = [&](int k){ if(k>=0 && k<n-1) s += W_est[arr[k]][arr[k+1]]; };\n            addEdge(i-1); addEdge(i);\n            if(j-1 != i-1 && j-1 != i) addEdge(j-1);\n            if(j != i && j != i-1) addEdge(j);\n            return s;\n        };\n        double before = partial(p);\n        vector<int> q = p;\n        swap(q[i], q[j]);\n        double after  = partial(q);\n        return after - before;\n    };\n    auto est_block_delta = [&](const vector<int>& p, int L, int R, int K)->double{\n        int N = p.size();\n        int B = R-L+1;\n        double delta = 0.0;\n        double beforeStart = Wstart[p[0]];\n        double afterStart = beforeStart;\n        if(K==0){\n            afterStart = Wstart[p[L]];\n        }else if(L==0 && K>0){\n            if(R+1 < N) afterStart = Wstart[p[R+1]];\n        }\n        delta += (afterStart - beforeStart);\n        auto E = [&](int a, int b)->double{ if(a<0||b<0) return 0.0; return W_est[a][b]; };\n        if(L>0) delta -= E(p[L-1], p[L]);\n        if(R<N-1) delta -= E(p[R], p[R+1]);\n        if(L>0 && R<N-1) delta += E(p[L-1], p[R+1]);\n        auto rem = [&](int k)->int{ return (k < L) ? p[k] : p[k + B]; };\n        if(K>0 && K < N-B){\n            delta -= E(rem(K-1), rem(K));\n        }\n        if(K>0){\n            delta += E(rem(K-1), p[L]);\n        }\n        if(K < N-B){\n            delta += E(p[R], rem(K));\n        }\n        return delta;\n    };\n\n    // Dedup helper\n    auto add_seed = [&](vector<vector<int>>& seeds, const vector<int>& pi){\n        static unordered_set<uint64_t> seen;\n        uint64_t h=1469598103934665603ull;\n        for(int x: pi){\n            h ^= (uint64_t)(x + 0x9e3779b97f4a7c15ull);\n            h *= 1099511628211ull;\n        }\n        if(seen.insert(h).second){\n            seeds.push_back(pi);\n        }\n    };\n\n    // Build seeds (diverse)\n    vector<vector<int>> seeds;\n    for(int r=0;r<3;r++) add_seed(seeds, build_by_arc_packing_overlap());\n    for(int r=0;r<3;r++) add_seed(seeds, build_by_arc_packing_weight(W_est, Wstart));\n    // NN seeds by Wstart\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int a, int b){\n        if(Wstart[a] != Wstart[b]) return Wstart[a] > Wstart[b];\n        return a < b;\n    });\n    int NN_STARTS = min(M, 24);\n    for(int i=0;i<NN_STARTS;i++) add_seed(seeds, build_by_nn(idx[i], W_est));\n    for(int i=0;i<8;i++) add_seed(seeds, build_by_nn(rng.next_int(0, M-1), W_est));\n    // overlap-based NN for diversity\n    vector<vector<double>> W_ov(M, vector<double>(M, 0.0));\n    for(int a=0;a<M;a++) for(int b=0;b<M;b++) if(a!=b) W_ov[a][b] = (double)f[a][b];\n    for(int i=0;i<8;i++) add_seed(seeds, build_by_nn(rng.next_int(0, M-1), W_ov));\n\n    // Quick overlap-only insertion improvements for a permutation (few moves)\n    auto overlap_insertion_boost = [&](vector<int>& p, int max_moves){\n        int n = p.size();\n        auto eov = [&](int a, int b)->int{ if(a<0||b<0) return 0; return f[a][b]; };\n        auto delta = [&](int i, int j2)->int{\n            int N=n, x=p[i], d=0;\n            if(i==0){\n                if(N>=2) d -= eov(p[0],p[1]);\n            }else{\n                d -= eov(p[i-1],p[i]);\n                if(i<N-1){ d -= eov(p[i],p[i+1]); d += eov(p[i-1],p[i+1]); }\n            }\n            int len=N-1;\n            auto after=[&](int k)->int{ return (k<i)?p[k]:p[k+1]; };\n            if(len==0) return d;\n            if(j2==0){\n                int R=after(0); d += eov(x,R);\n            }else if(j2==len){\n                int L=after(len-1); d += eov(L,x);\n            }else{\n                int L=after(j2-1), R=after(j2);\n                d -= eov(L,R); d += eov(L,x); d += eov(x,R);\n            }\n            return d;\n        };\n        auto apply = [&](int i, int j2){\n            int x=p[i];\n            p.erase(p.begin()+i);\n            p.insert(p.begin()+j2,x);\n        };\n        for(int mv=0; mv<max_moves; mv++){\n            int best_i=-1, best_j=-1, best_d=0;\n            for(int i=0;i<n;i++){\n                for(int j2=0;j2<=n-1;j2++){\n                    if(j2==i) continue;\n                    int d = delta(i,j2);\n                    if(d > best_d){ best_d=d; best_i=i; best_j=j2; }\n                }\n            }\n            if(best_d > 0) apply(best_i, best_j);\n            else break;\n        }\n    };\n\n    // Rank seeds by estimated T, evaluate DP on top few\n    auto estimate_T = [&](const vector<int>& pi)->double{\n        double s = -Wstart[pi[0]];\n        for(int i=0;i+1<M;i++) s += -W_est[pi[i]][pi[i+1]];\n        return s;\n    };\n\n    struct SeedInfo { vector<int> pi; double est; };\n    vector<SeedInfo> seedInfos;\n    seedInfos.reserve(seeds.size());\n    for(auto &pi: seeds){\n        seedInfos.push_back({pi, estimate_T(pi)});\n    }\n    sort(seedInfos.begin(), seedInfos.end(), [](const SeedInfo& a, const SeedInfo& b){\n        return a.est < b.est;\n    });\n\n    struct Base { vector<int> pi; vector<int> letters; long long T; };\n    vector<Base> bases;\n    long long best_T_glob = (1LL<<60);\n    int CAP = 24;\n    for(int i=0; i<(int)seedInfos.size() && (int)bases.size()<CAP; i++){\n        if(elapsed() > TIME_LIMIT - 0.65) break;\n        auto pi = seedInfos[i].pi;\n        // quick overlap boost\n        overlap_insertion_boost(pi, 6);\n        vector<int> letters = build_letters_from_pi(pi);\n        long long Tcost = dp_cost(letters, best_T_glob);\n        bases.push_back({pi, letters, Tcost});\n        if(Tcost < best_T_glob) best_T_glob = Tcost;\n\n        // reversed\n        reverse(pi.begin(), pi.end());\n        overlap_insertion_boost(pi, 4);\n        vector<int> letters_r = build_letters_from_pi(pi);\n        long long Tr = dp_cost(letters_r, best_T_glob);\n        bases.push_back({pi, letters_r, Tr});\n        if(Tr < best_T_glob) best_T_glob = Tr;\n    }\n    sort(bases.begin(), bases.end(), [&](const Base& a, const Base& b){ return a.T < b.T; });\n    if(bases.empty()){\n        auto pi = build_by_arc_packing_overlap();\n        overlap_insertion_boost(pi, 8);\n        vector<int> letters = build_letters_from_pi(pi);\n        long long Tcost = dp_cost(letters, (1LL<<60));\n        bases.push_back({pi, letters, Tcost});\n    }\n    int useBases = min<int>((int)bases.size(), 3);\n\n    // Choose best baseline\n    vector<int> best_pi = bases[0].pi;\n    vector<int> best_letters = bases[0].letters;\n    long long best_T = bases[0].T;\n    for(int b=1;b<useBases;b++){\n        if(bases[b].T < best_T){\n            best_pi = bases[b].pi; best_letters = bases[b].letters; best_T = bases[b].T;\n        }\n    }\n\n    // Helper for trying a candidate\n    auto try_candidate = [&](vector<int>& cand_pi)->bool{\n        vector<int> letters = build_letters_from_pi(cand_pi);\n        long long Tcost = dp_cost(letters, best_T);\n        if(Tcost < best_T){\n            best_T = Tcost;\n            best_pi.swap(cand_pi);\n            best_letters.swap(letters);\n            return true;\n        }\n        return false;\n    };\n\n    // DP-validated local search with gating\n    while(elapsed() < TIME_LIMIT - 0.20){\n        int moveSel = rng.next_int(0, 99);\n        if(moveSel < 50){\n            int i = rng.next_int(0, M-1);\n            int j2 = rng.next_int(0, M-1);\n            if(j2==i) continue;\n            int dOv = ov_insert_delta(best_pi, i, j2);\n            if(dOv < -1) continue;\n            double dEst = est_insert_delta(best_pi, i, j2);\n            bool tryDP = false;\n            if(dOv >= 2) tryDP = true;\n            else if(dEst > 0.0 || dOv >= 0) tryDP = true;\n            else if(dEst > -0.3 && rng.next_int(0,99) < 5) tryDP = true;\n            if(!tryDP) continue;\n            vector<int> cand_pi = best_pi;\n            int x = cand_pi[i];\n            cand_pi.erase(cand_pi.begin()+i);\n            cand_pi.insert(cand_pi.begin()+j2, x);\n            try_candidate(cand_pi);\n        }else if(moveSel < 80){\n            int i = rng.next_int(0, M-1);\n            int j = rng.next_int(0, M-1);\n            if(i==j) continue;\n            if(i>j) swap(i,j);\n            int dOv = ov_swap_delta(best_pi, i, j);\n            if(dOv < -1) continue;\n            double dEst = est_swap_delta(best_pi, i, j);\n            bool tryDP = false;\n            if(dOv >= 2) tryDP = true;\n            else if(dEst > 0.0 || dOv >= 0) tryDP = true;\n            else if(dEst > -0.3 && rng.next_int(0,99) < 3) tryDP = true;\n            if(!tryDP) continue;\n            vector<int> cand_pi = best_pi;\n            swap(cand_pi[i], cand_pi[j]);\n            try_candidate(cand_pi);\n        }else{\n            int L = rng.next_int(0, M-2);\n            int maxlen = min(8, M - L);\n            int len = rng.next_int(2, maxlen);\n            int R = L + len - 1;\n            int K = rng.next_int(0, M - len);\n            if(K >= L && K <= R+1) continue;\n            int dOv = ov_block_delta(best_pi, L, R, K);\n            if(dOv < -1) continue;\n            double dEst = est_block_delta(best_pi, L, R, K);\n            bool tryDP = false;\n            if(dOv >= 2) tryDP = true;\n            else if(dEst > 0.0 || dOv >= 0) tryDP = true;\n            else if(dEst > -0.3 && rng.next_int(0,99) < 3) tryDP = true;\n            if(!tryDP) continue;\n            vector<int> cand_pi = best_pi;\n            vector<int> block;\n            block.reserve(R-L+1);\n            for(int i=L;i<=R;i++) block.push_back(cand_pi[i]);\n            cand_pi.erase(cand_pi.begin()+L, cand_pi.begin()+R+1);\n            cand_pi.insert(cand_pi.begin()+K, block.begin(), block.end());\n            try_candidate(cand_pi);\n        }\n    }\n\n    // Greedy adjacent swap pass (cheap DP-validated)\n    for(int pass=0; pass<2 && elapsed() < TIME_LIMIT - 0.12; pass++){\n        bool improved=false;\n        for(int i=0;i<M-1;i++){\n            int dOv = ov_swap_delta(best_pi, i, i+1);\n            if(dOv < -1) continue;\n            double dEst = est_swap_delta(best_pi, i, i+1);\n            if(dOv >= 1 || dEst > 0.05){\n                vector<int> cand_pi = best_pi;\n                swap(cand_pi[i], cand_pi[i+1]);\n                if(try_candidate(cand_pi)){ improved = true; if(elapsed() > TIME_LIMIT - 0.12) break; }\n            }\n        }\n        if(!improved) break;\n    }\n\n    // Final DP with reconstruction\n    auto [finalT, ops] = dp_solve(best_letters);\n    for(auto &p : ops){\n        cout << p.first << \" \" << p.second << \"\\n\";\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer for internal time budget\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::steady_clock::now(); }\n    double elapsed() const { return chrono::duration<double>(chrono::steady_clock::now() - st).count(); }\n};\n\nstatic inline int cell_id(int i, int j, int N) { return i * N + j; }\nstatic inline pair<int,int> cell_ij(int id, int N) { return {id / N, id % N}; }\n\nstruct Shape {\n    int id;\n    vector<pair<int,int>> offsets; // shape cells (relative)\n    int H=0, W=0;\n    vector<vector<int>> shiftsCells; // per shift, list of global cells covered\n    vector<vector<int>> coverShiftsByCell; // for each global cell, list of shifts covering it\n};\n\nstruct Problem {\n    int N, M;\n    double eps;\n    vector<Shape> shapes;\n};\n\nstruct State {\n    int N, M;\n    const Problem* prob;\n\n    vector<int> known; // -1 unknown, else exact v(i,j)\n    vector<int> drilledCells;\n    vector<int> vDrilled;\n    vector<int> drilledIndexOf;\n\n    vector<vector<uint8_t>> active; // per shape k, per shift p: active?\n    vector<int> activeCount;\n\n    // Prepared per-drilled coverage info\n    int D = 0;\n    vector<vector<int>> anyCoverKD;  // [k][d] 0/1 whether shape k could cover drilled cell d\n    vector<vector<int>> mustCoverKD; // [k][d] 0/1 whether shape k must cover drilled cell d\n    vector<int> sumAnyD, sumMustD;\n\n    // Cache: for each shape and shift, which drilled indices it covers\n    vector<vector<vector<int>>> coverDrilledCache; // [k][p] -> drilled indices covered\n\n    int opCount = 0;\n    int opLimit;\n\n    mt19937 rng;\n    Timer timer;\n    double timeLimitSec = 2.3; // internal limit; we can extend for a second attempt\n\n    State(const Problem* pr): prob(pr) {\n        N = pr->N; M = pr->M;\n        known.assign(N*N, -1);\n        drilledIndexOf.assign(N*N, -1);\n        active.resize(M);\n        activeCount.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            active[k].assign(Pk, 1);\n            activeCount[k] = Pk;\n        }\n        rng.seed(chrono::high_resolution_clock::now().time_since_epoch().count());\n        opLimit = 2 * N * N;\n    }\n\n    inline void flush() { cout.flush(); }\n\n    inline bool removeShift(int k, int p) {\n        if (active[k][p]) { active[k][p] = 0; --activeCount[k]; return true; }\n        return false;\n    }\n\n    int drill_cell(int c) {\n        if (known[c] != -1) return known[c];\n        auto [i,j] = cell_ij(c, N);\n        cout << \"q 1 \" << i << \" \" << j << \"\\n\";\n        flush();\n        string s;\n        if (!(cin >> s)) exit(0);\n        int val = stoi(s);\n        known[c] = val;\n        drilledIndexOf[c] = (int)drilledCells.size();\n        drilledCells.push_back(c);\n        vDrilled.push_back(val);\n        ++opCount;\n        if (val == 0) {\n            // eliminate all shifts covering this zero cell\n            for (int k = 0; k < M; ++k) {\n                if (activeCount[k] == 0) continue;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) removeShift(k, p);\n            }\n        }\n        return val;\n    }\n\n    bool allShapesHaveCandidates() const {\n        for (int k = 0; k < M; ++k) if (activeCount[k] <= 0) return false;\n        return true;\n    }\n\n    void recomputeCoverageBounds() {\n        D = (int)drilledCells.size();\n        anyCoverKD.assign(M, vector<int>(D, 0));\n        mustCoverKD.assign(M, vector<int>(D, 0));\n        sumAnyD.assign(D, 0);\n        sumMustD.assign(D, 0);\n        for (int k = 0; k < M; ++k) {\n            if (activeCount[k] <= 0) continue;\n            for (int d = 0; d < D; ++d) {\n                int c = drilledCells[d];\n                int cnt = 0;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) ++cnt;\n                anyCoverKD[k][d] = (cnt > 0) ? 1 : 0;\n                mustCoverKD[k][d] = (cnt == activeCount[k]) ? 1 : 0;\n                sumAnyD[d] += anyCoverKD[k][d];\n                sumMustD[d] += mustCoverKD[k][d];\n            }\n        }\n    }\n\n    void buildCoverDrilledCache() {\n        D = (int)drilledCells.size();\n        coverDrilledCache.assign(M, {});\n        for (int k = 0; k < M; ++k) {\n            int Pk = (int)prob->shapes[k].shiftsCells.size();\n            coverDrilledCache[k].assign(Pk, {});\n            for (int p = 0; p < Pk; ++p) {\n                if (!active[k][p]) continue;\n                const auto& cells = prob->shapes[k].shiftsCells[p];\n                auto& v = coverDrilledCache[k][p];\n                v.clear();\n                for (int c : cells) {\n                    int d = drilledIndexOf[c];\n                    if (d >= 0) v.push_back(d);\n                }\n                sort(v.begin(), v.end());\n                v.erase(unique(v.begin(), v.end()), v.end());\n            }\n        }\n    }\n\n    // Strong propagation with arc-consistency per shift\n    bool propagateConstraints(int maxIter = 100) {\n        for (int iter = 0; iter < maxIter; ++iter) {\n            bool changed = false;\n            recomputeCoverageBounds();\n            for (int d = 0; d < D; ++d) {\n                int v = vDrilled[d];\n                if (sumAnyD[d] < v || sumMustD[d] > v) return false;\n            }\n            buildCoverDrilledCache();\n\n            // v == 0\n            for (int d = 0; d < D; ++d) if (vDrilled[d] == 0) {\n                int c = drilledCells[d];\n                for (int k = 0; k < M; ++k) if (anyCoverKD[k][d]) {\n                    for (int p : prob->shapes[k].coverShiftsByCell[c]) if (removeShift(k,p)) changed = true;\n                }\n            }\n            // sumAny == v -> all possible must cover => remove non-covering shifts\n            for (int d = 0; d < D; ++d) {\n                if (sumAnyD[d] == vDrilled[d]) {\n                    int c = drilledCells[d];\n                    for (int k = 0; k < M; ++k) if (anyCoverKD[k][d]) {\n                        int Pk = (int)prob->shapes[k].shiftsCells.size();\n                        static vector<uint8_t> mark;\n                        mark.assign(Pk, 0);\n                        for (int p : prob->shapes[k].coverShiftsByCell[c]) mark[p] = 1;\n                        for (int p = 0; p < Pk; ++p) if (active[k][p] && !mark[p]) {\n                            if (removeShift(k,p)) changed = true;\n                        }\n                    }\n                }\n            }\n            // sumMust == v -> non-must shapes must avoid covering\n            for (int d = 0; d < D; ++d) {\n                if (sumMustD[d] == vDrilled[d]) {\n                    int c = drilledCells[d];\n                    for (int k = 0; k < M; ++k) if (anyCoverKD[k][d] && mustCoverKD[k][d] == 0) {\n                        for (int p : prob->shapes[k].coverShiftsByCell[c]) if (removeShift(k,p)) changed = true;\n                    }\n                }\n            }\n            // Per-shift feasibility using excl bounds\n            vector<vector<int>> lb_excl(M, vector<int>(D, 0));\n            vector<vector<int>> ub_excl(M, vector<int>(D, 0));\n            for (int k = 0; k < M; ++k) for (int d = 0; d < D; ++d) {\n                lb_excl[k][d] = sumMustD[d] - mustCoverKD[k][d];\n                ub_excl[k][d] = sumAnyD[d] - anyCoverKD[k][d];\n            }\n            for (int k = 0; k < M; ++k) {\n                int Pk = (int)prob->shapes[k].shiftsCells.size();\n                for (int p = 0; p < Pk; ++p) if (active[k][p]) {\n                    const auto& coverD = coverDrilledCache[k][p];\n                    int ptr = 0;\n                    bool ok = true;\n                    for (int d = 0; d < D; ++d) {\n                        int cover = 0;\n                        if (ptr < (int)coverD.size() && coverD[ptr] == d) { cover = 1; ++ptr; }\n                        int rem = vDrilled[d] - cover;\n                        if (rem < lb_excl[k][d] || rem > ub_excl[k][d]) { ok = false; break; }\n                    }\n                    if (!ok) {\n                        if (removeShift(k,p)) changed = true;\n                    }\n                }\n            }\n\n            if (!changed) break;\n            if (!allShapesHaveCandidates()) return false;\n        }\n        return allShapesHaveCandidates();\n    }\n\n    vector<int> chooseOrder(int targetCell = -1, int requireCovered = -1) {\n        vector<int> ord(M); iota(ord.begin(), ord.end(), 0);\n        auto canCover = [&](int k)->int {\n            if (targetCell < 0) return 0;\n            for (int p : prob->shapes[k].coverShiftsByCell[targetCell]) if (active[k][p]) return 1;\n            return 0;\n        };\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b){\n            if (requireCovered == 1) {\n                int ca = canCover(a), cb = canCover(b);\n                if (ca != cb) return ca > cb;\n            }\n            if (activeCount[a] != activeCount[b]) return activeCount[a] < activeCount[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    struct DFSContext {\n        State* st;\n        vector<int> order;\n        vector<int> cur; // current sum at drilled cells\n        vector<int> assign; // chosen shift per shape id\n        int solutionsLimit;\n        int solutionsFound;\n        vector<int> lastAssignment;\n        vector<int> unionCounts;\n        bool respectTime;\n        int targetCell;     // -1 none\n        int requireCovered; // -1 none, 0 force uncovered, 1 force covered\n        vector<vector<int>> sufAny, sufMust;\n        vector<vector<vector<int>>> *coverDrilledCachePtr;\n        vector<vector<int>> *anyCoverKDPtr;\n        vector<vector<int>> *mustCoverKDPtr;\n\n        DFSContext(State* st_, const vector<int>& order_, int solLim, bool respectTime_,\n                   int targetCell_ = -1, int requireCovered_ = -1)\n            : st(st_), order(order_), solutionsLimit(solLim), solutionsFound(0),\n              respectTime(respectTime_), targetCell(targetCell_), requireCovered(requireCovered_) {\n            int D = (int)st->drilledCells.size();\n            int M = st->M;\n            cur.assign(D, 0);\n            assign.assign(st->M, -1);\n            lastAssignment.assign(st->M, -1);\n            unionCounts.assign(st->N * st->N, 0);\n            coverDrilledCachePtr = &st->coverDrilledCache;\n            anyCoverKDPtr = &st->anyCoverKD;\n            mustCoverKDPtr = &st->mustCoverKD;\n            sufAny.assign(M + 1, vector<int>(D, 0));\n            sufMust.assign(M + 1, vector<int>(D, 0));\n            for (int pos = M - 1; pos >= 0; --pos) {\n                int k = order[pos];\n                for (int d = 0; d < D; ++d) {\n                    sufAny[pos][d] = sufAny[pos + 1][d] + (*anyCoverKDPtr)[k][d];\n                    sufMust[pos][d] = sufMust[pos + 1][d] + (*mustCoverKDPtr)[k][d];\n                }\n            }\n        }\n\n        void recordSolution() {\n            vector<uint8_t> covered(st->N * st->N, 0);\n            for (int pos = 0; pos < st->M; ++pos) {\n                int k = order[pos];\n                int p = assign[k];\n                if (p < 0) return;\n                for (int c : st->prob->shapes[k].shiftsCells[p]) covered[c] = 1;\n            }\n            for (int c = 0; c < st->N * st->N; ++c) if (covered[c]) ++unionCounts[c];\n            lastAssignment = assign;\n            ++solutionsFound;\n        }\n\n        bool viableChoice(int pos, int k, int p) {\n            if (requireCovered == 0 && targetCell >= 0) {\n                for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) return false;\n            }\n            const vector<int>& vDrilled = st->vDrilled;\n            const vector<int>& coverD = (*coverDrilledCachePtr)[k][p];\n            int D = (int)st->drilledCells.size();\n            int ptr = 0;\n            for (int d = 0; d < D; ++d) {\n                int cover = 0;\n                if (ptr < (int)coverD.size() && coverD[ptr] == d) { cover = 1; ++ptr; }\n                int remp = vDrilled[d] - (cur[d] + cover);\n                if (remp < 0) return false;\n                int ub_rem = sufAny[pos + 1][d];\n                int lb_rem = sufMust[pos + 1][d];\n                if (remp < lb_rem) return false;\n                if (remp > ub_rem) return false;\n            }\n            return true;\n        }\n\n        void dfs(int pos) {\n            if (solutionsFound >= solutionsLimit) return;\n            if (respectTime && st->timer.elapsed() > st->timeLimitSec) return;\n            if (pos == st->M) {\n                if (requireCovered == 1 && targetCell >= 0) {\n                    bool cov = false;\n                    for (int t = 0; t < st->M && !cov; ++t) {\n                        int k = order[t];\n                        int p = assign[k];\n                        if (p < 0) continue;\n                        for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) { cov = true; break; }\n                    }\n                    if (!cov) return;\n                }\n                recordSolution();\n                return;\n            }\n            int k = order[pos];\n\n            if (requireCovered == 1 && targetCell >= 0) {\n                bool coveredNow = false;\n                for (int t = 0; t < pos && !coveredNow; ++t) {\n                    int kk = order[t];\n                    int psel = assign[kk];\n                    if (psel < 0) continue;\n                    for (int c : st->prob->shapes[kk].shiftsCells[psel]) if (c == targetCell) { coveredNow = true; break; }\n                }\n                if (!coveredNow) {\n                    bool exists = false;\n                    for (int t = pos; t < st->M && !exists; ++t) {\n                        int kk = order[t];\n                        for (int p2 : st->prob->shapes[kk].coverShiftsByCell[targetCell]) if (st->active[kk][p2]) { exists = true; break; }\n                    }\n                    if (!exists) return;\n                }\n            }\n\n            const int Pk = (int)st->prob->shapes[k].shiftsCells.size();\n            vector<int> candidates;\n            candidates.reserve(st->activeCount[k]);\n            if (requireCovered == 1 && targetCell >= 0) {\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) {\n                    bool cov = false;\n                    for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) { cov = true; break; }\n                    if (cov) candidates.push_back(p);\n                }\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) {\n                    bool cov = false;\n                    for (int c : st->prob->shapes[k].shiftsCells[p]) if (c == targetCell) { cov = true; break; }\n                    if (!cov) candidates.push_back(p);\n                }\n            } else {\n                for (int p = 0; p < Pk; ++p) if (st->active[k][p]) candidates.push_back(p);\n            }\n\n            for (int p : candidates) {\n                if (!viableChoice(pos, k, p)) continue;\n                assign[k] = p;\n                for (int d : (*coverDrilledCachePtr)[k][p]) ++cur[d];\n                dfs(pos + 1);\n                for (int d : (*coverDrilledCachePtr)[k][p]) --cur[d];\n                assign[k] = -1;\n                if (solutionsFound >= solutionsLimit) return;\n                if (respectTime && st->timer.elapsed() > st->timeLimitSec) return;\n            }\n        }\n    };\n\n    // Enumerate up to L solutions using prepared caches/bounds\n    void enumerateSolutionsLimitedPrepared(int L, vector<int>& oneAssignOut, vector<int>& unionCountsOut, int& found) {\n        vector<int> order = chooseOrder();\n        DFSContext ctx(this, order, L, true);\n        ctx.dfs(0);\n        found = ctx.solutionsFound;\n        oneAssignOut = ctx.lastAssignment;\n        unionCountsOut = ctx.unionCounts;\n    }\n\n    bool existsAlternativeForCellPrepared(int c, int wantStatus) {\n        if (known[c] == 0 && wantStatus == 1) return false;\n        if (known[c] > 0 && wantStatus == 0) return false;\n        if (wantStatus == 1) {\n            bool anyCan = false;\n            for (int k = 0; k < M && !anyCan; ++k) {\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) { anyCan = true; break; }\n            }\n            if (!anyCan) return false;\n        }\n        if (wantStatus == 0) {\n            for (int k = 0; k < M; ++k) {\n                int coverCnt = 0;\n                for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) ++coverCnt;\n                if (activeCount[k] > 0 && coverCnt == activeCount[k]) return false;\n            }\n        }\n        int requireCovered = (wantStatus == 1) ? 1 : 0;\n        vector<int> order = chooseOrder(c, requireCovered);\n        DFSContext ctx(this, order, 1, true, c, requireCovered);\n        ctx.dfs(0);\n        return ctx.solutionsFound >= 1;\n    }\n\n    vector<uint8_t> buildUnionFromAssignment(const vector<int>& assign) {\n        vector<uint8_t> covered(N*N, 0);\n        for (int k = 0; k < M; ++k) {\n            int p = assign[k];\n            if (p < 0) continue;\n            for (int c : prob->shapes[k].shiftsCells[p]) covered[c] = 1;\n        }\n        return covered;\n    }\n\n    void computeMinMaxCover(vector<int>& minCover, vector<int>& maxCover) {\n        minCover.assign(N*N, 0);\n        maxCover.assign(N*N, 0);\n        for (int k = 0; k < M; ++k) {\n            if (activeCount[k] <= 0) continue;\n            for (int c = 0; c < N*N; ++c) {\n                const auto& vec = prob->shapes[k].coverShiftsByCell[c];\n                if (vec.empty()) continue;\n                int cnt = 0;\n                for (int p : vec) if (active[k][p]) ++cnt;\n                if (cnt > 0) ++maxCover[c];\n                if (cnt == activeCount[k]) ++minCover[c];\n            }\n        }\n    }\n\n    // Improved drilling score: discrimination potential per shape weighted by 1/activeCount, plus slight coverage\n    int drillScoreCell(int c) {\n        if (known[c] != -1) return -1;\n        double score = 0.0;\n        double coverTerm = 0.0;\n        for (int k = 0; k < M; ++k) {\n            int A = activeCount[k];\n            if (A <= 0) continue;\n            int cnt = 0;\n            for (int p : prob->shapes[k].coverShiftsByCell[c]) if (active[k][p]) ++cnt;\n            if (cnt <= 0) continue;\n            int non = A - cnt;\n            double w = 1.0 / (double)A;\n            score += w * (double)min(cnt, non);\n            coverTerm += cnt;\n        }\n        score += 0.05 * coverTerm;\n        int sc = (int)llround(score * 1000.0);\n        return sc;\n    }\n\n    // Choose a cell with maximum discrimination potential, skipping already decided ones\n    int bestDiscriminativeDrillCandidate(const vector<int>& minCover, const vector<int>& maxCover) {\n        int bestC = -1, bestScore = INT_MIN;\n        for (int c = 0; c < N*N; ++c) {\n            if (known[c] != -1) continue;\n            if (maxCover[c] == 0 || minCover[c] > 0) continue; // already decided\n            int sc = drillScoreCell(c);\n            if (sc > bestScore) { bestScore = sc; bestC = c; }\n        }\n        if (bestC == -1) {\n            vector<int> unknown;\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) unknown.push_back(c);\n            if (!unknown.empty()) bestC = unknown[rng() % unknown.size()];\n        }\n        return bestC;\n    }\n\n    // Choose top-L initial seeds (high discrimination potential)\n    vector<int> pick_top_seeds(int L) {\n        vector<pair<int,int>> v;\n        v.reserve(N*N);\n        for (int c = 0; c < N*N; ++c) {\n            int sc = drillScoreCell(c);\n            v.emplace_back(sc, c);\n        }\n        sort(v.begin(), v.end(), [&](const auto& a, const auto& b){\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n        vector<int> seeds;\n        for (int i = 0; i < (int)v.size() && (int)seeds.size() < L; ++i) seeds.push_back(v[i].second);\n        return seeds;\n    }\n\n    // One solve round. If doSeed is true, perform initial seeding. Returns a best union guess and whether uniqueness was proven.\n    pair<vector<uint8_t>, bool> solveRound(bool doSeed) {\n        if (doSeed) {\n            int K0 = min(16, max(6, (N + M) / 2));\n            vector<int> seeds = pick_top_seeds(K0);\n            for (int idx = 0; idx < (int)seeds.size(); ++idx) {\n                if (opCount >= opLimit) break;\n                int c = seeds[idx];\n                if (known[c] == -1) drill_cell(c);\n            }\n        }\n\n        if (!propagateConstraints()) {\n            // Contradiction: fallback to drilling all and return exact union\n            vector<uint8_t> res(N*N, 0);\n            for (int c = 0; c < N*N; ++c) {\n                if (opCount >= opLimit - 1) break;\n                if (known[c] == -1) drill_cell(c);\n            }\n            for (int c = 0; c < N*N; ++c) res[c] = (known[c] > 0) ? 1 : 0;\n            return {res, true};\n        }\n\n        vector<int> oneAssign, unionCounts;\n        int found = 0;\n        vector<uint8_t> lastBaseUnion; // best known union guess\n\n        while (true) {\n            if (opCount >= opLimit - 1) break;\n            if (timer.elapsed() > timeLimitSec) break;\n\n            // Deterministic classification\n            vector<int> minCover, maxCover;\n            computeMinMaxCover(minCover, maxCover);\n            bool allClassified = true;\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) {\n                if (!(maxCover[c] == 0 || minCover[c] > 0)) { allClassified = false; break; }\n            }\n            if (allClassified) {\n                vector<uint8_t> res(N*N, 0);\n                for (int c = 0; c < N*N; ++c) {\n                    if (known[c] != -1) res[c] = (known[c] > 0);\n                    else res[c] = (minCover[c] > 0) ? 1 : 0;\n                }\n                return {res, true};\n            }\n\n            // Prepare caches once this iteration\n            recomputeCoverageBounds();\n            buildCoverDrilledCache();\n\n            // Enumerate some solutions\n            enumerateSolutionsLimitedPrepared(100, oneAssign, unionCounts, found);\n            if (found == 0) {\n                if (!allShapesHaveCandidates()) {\n                    // Contradiction: drill all\n                    vector<uint8_t> res(N*N, 0);\n                    for (int c = 0; c < N*N; ++c) {\n                        if (opCount >= opLimit - 1) break;\n                        if (known[c] == -1) drill_cell(c);\n                    }\n                    for (int c = 0; c < N*N; ++c) res[c] = (known[c] > 0) ? 1 : 0;\n                    return {res, true};\n                }\n                int cPick = bestDiscriminativeDrillCandidate(minCover, maxCover);\n                if (cPick == -1) break;\n                drill_cell(cPick);\n                if (!propagateConstraints()) {\n                    vector<uint8_t> res(N*N, 0);\n                    for (int c = 0; c < N*N; ++c) {\n                        if (opCount >= opLimit - 1) break;\n                        if (known[c] == -1) drill_cell(c);\n                    }\n                    for (int c = 0; c < N*N; ++c) res[c] = (known[c] > 0) ? 1 : 0;\n                    return {res, true};\n                }\n                continue;\n            }\n\n            vector<uint8_t> baseUnion = buildUnionFromAssignment(oneAssign);\n            lastBaseUnion = baseUnion;\n\n            // Build ambiguous list\n            vector<pair<int,int>> cells; // (score, cell) lower score -> more ambiguous\n            for (int c = 0; c < N*N; ++c) if (known[c] == -1) {\n                int cnt = unionCounts[c];\n                int score = abs(found - 2*cnt);\n                cells.emplace_back(score, c);\n            }\n            sort(cells.begin(), cells.end(), [&](const auto& a, const auto& b){\n                if (a.first != b.first) return a.first < b.first;\n                return a.second < b.second;\n            });\n\n            bool alternativeFound = false;\n            bool completeScan = true;\n            int ambiguousCell = -1;\n            int Kcheck = min<int>(50, (int)cells.size());\n            int mostAmbScore = INT_MAX;\n            int mostAmbCell = -1;\n            for (int t = 0; t < Kcheck; ++t) {\n                if (timer.elapsed() > timeLimitSec) { completeScan = false; break; }\n                int c = cells[t].second;\n                if (cells[t].first < mostAmbScore) { mostAmbScore = cells[t].first; mostAmbCell = c; }\n                int want = baseUnion[c] ? 0 : 1;\n                if (existsAlternativeForCellPrepared(c, want)) {\n                    ambiguousCell = c;\n                    alternativeFound = true;\n                    break;\n                }\n            }\n            if (!alternativeFound && completeScan) {\n                for (int t = Kcheck; t < (int)cells.size(); ++t) {\n                    if (timer.elapsed() > timeLimitSec) { completeScan = false; break; }\n                    int c = cells[t].second;\n                    if (cells[t].first < mostAmbScore) { mostAmbScore = cells[t].first; mostAmbCell = c; }\n                    int want = baseUnion[c] ? 0 : 1;\n                    if (existsAlternativeForCellPrepared(c, want)) {\n                        ambiguousCell = c;\n                        alternativeFound = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!completeScan) {\n                int cPick = (mostAmbCell != -1) ? mostAmbCell : bestDiscriminativeDrillCandidate(vector<int>(N*N,0), vector<int>(N*N,1));\n                if (cPick == -1) break;\n                drill_cell(cPick);\n                if (!propagateConstraints()) {\n                    vector<uint8_t> res(N*N, 0);\n                    for (int c = 0; c < N*N; ++c) {\n                        if (opCount >= opLimit - 1) break;\n                        if (known[c] == -1) drill_cell(c);\n                    }\n                    for (int c = 0; c < N*N; ++c) res[c] = (known[c] > 0) ? 1 : 0;\n                    return {res, true};\n                }\n                continue;\n            }\n\n            if (!alternativeFound) {\n                // Uniquely determined\n                return {baseUnion, true};\n            } else {\n                drill_cell(ambiguousCell);\n                if (!propagateConstraints()) {\n                    vector<uint8_t> res(N*N, 0);\n                    for (int c = 0; c < N*N; ++c) {\n                        if (opCount >= opLimit - 1) break;\n                        if (known[c] == -1) drill_cell(c);\n                    }\n                    for (int c = 0; c < N*N; ++c) res[c] = (known[c] > 0) ? 1 : 0;\n                    return {res, true};\n                }\n            }\n        }\n\n        // Time/op-limit reached: return best known guess if available\n        if (!drilledCells.empty() && !oneAssign.empty()) {\n            vector<uint8_t> res = lastBaseUnion;\n            if (res.empty()) res = buildUnionFromAssignment(oneAssign);\n            return {res, false};\n        } else {\n            // As a last resort, include cells that currently have some possible coverage\n            vector<int> minCover, maxCover;\n            computeMinMaxCover(minCover, maxCover);\n            vector<uint8_t> res(N*N, 0);\n            for (int c = 0; c < N*N; ++c) {\n                if (known[c] != -1) res[c] = (known[c] > 0);\n                else res[c] = (maxCover[c] > 0) ? 1 : 0;\n            }\n            return {res, false};\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem prob;\n    if (!(cin >> prob.N >> prob.M >> prob.eps)) return 0;\n    prob.shapes.resize(prob.M);\n    for (int k = 0; k < prob.M; ++k) {\n        prob.shapes[k].id = k;\n        int d; cin >> d;\n        vector<pair<int,int>> offs;\n        offs.reserve(d);\n        int minI = INT_MAX, minJ = INT_MAX, maxI = INT_MIN, maxJ = INT_MIN;\n        for (int t = 0; t < d; ++t) {\n            int ii, jj; cin >> ii >> jj;\n            offs.emplace_back(ii, jj);\n            minI = min(minI, ii);\n            minJ = min(minJ, jj);\n            maxI = max(maxI, ii);\n            maxJ = max(maxJ, jj);\n        }\n        for (auto &p : offs) { p.first -= minI; p.second -= minJ; }\n        prob.shapes[k].offsets = offs;\n        prob.shapes[k].H = maxI - minI + 1;\n        prob.shapes[k].W = maxJ - minJ + 1;\n    }\n\n    // Precompute shifts\n    for (int k = 0; k < prob.M; ++k) {\n        auto &S = prob.shapes[k];\n        int maxDI = prob.N - S.H;\n        int maxDJ = prob.N - S.W;\n        for (int di = 0; di <= maxDI; ++di) {\n            for (int dj = 0; dj <= maxDJ; ++dj) {\n                vector<int> cells;\n                cells.reserve(S.offsets.size());\n                for (auto [oi, oj] : S.offsets) {\n                    int i = di + oi;\n                    int j = dj + oj;\n                    cells.push_back(cell_id(i, j, prob.N));\n                }\n                sort(cells.begin(), cells.end());\n                S.shiftsCells.push_back(move(cells));\n            }\n        }\n        S.coverShiftsByCell.assign(prob.N * prob.N, {});\n        for (int p = 0; p < (int)S.shiftsCells.size(); ++p) {\n            for (int c : S.shiftsCells[p]) S.coverShiftsByCell[c].push_back(p);\n        }\n    }\n\n    State st(&prob);\n\n    // First solve round (with seeding)\n    auto [unionSet1, unique1] = st.solveRound(true);\n\n    auto build_ans = [&](const vector<uint8_t>& unionSet){\n        vector<int> ans;\n        ans.reserve(st.N * st.N);\n        vector<uint8_t> used = unionSet;\n        for (int c = 0; c < st.N * st.N; ++c) if (unionSet[c]) ans.push_back(c);\n        // Ensure inclusion of drilled positives\n        for (int idx = 0; idx < (int)st.drilledCells.size(); ++idx) {\n            int c = st.drilledCells[idx];\n            if (st.known[c] > 0 && !used[c]) { ans.push_back(c); used[c] = 1; }\n        }\n        sort(ans.begin(), ans.end());\n        ans.erase(unique(ans.begin(), ans.end()), ans.end());\n        return ans;\n    };\n\n    auto print_answer = [&](const vector<int>& cells){\n        cout << \"a \" << cells.size();\n        for (int c : cells) {\n            auto [i,j] = cell_ij(c, st.N);\n            cout << \" \" << i << \" \" << j;\n        }\n        cout << \"\\n\";\n        cout.flush();\n    };\n\n    vector<int> ans1 = build_ans(unionSet1);\n    print_answer(ans1);\n    string resp;\n    if (!(cin >> resp)) return 0;\n    if (resp == \"1\") return 0;\n\n    // If wrong, try a second refine round with a larger time budget and no fresh seeding\n    st.timeLimitSec = 2.85; // extend internal limit for second attempt\n    auto [unionSet2, unique2] = st.solveRound(false);\n    vector<int> ans2 = build_ans(unionSet2);\n    print_answer(ans2);\n    if (!(cin >> resp)) return 0;\n    if (resp == \"1\") return 0;\n\n    // Last resort: drill remaining cells and answer exactly\n    for (int c = 0; c < st.N * st.N; ++c) {\n        if (st.opCount >= st.opLimit - 1) break;\n        if (st.known[c] == -1) st.drill_cell(c);\n    }\n    vector<uint8_t> exactUnion(st.N * st.N, 0);\n    for (int c = 0; c < st.N * st.N; ++c) exactUnion[c] = (st.known[c] > 0) ? 1 : 0;\n    vector<int> ans3 = build_ans(exactUnion);\n    print_answer(ans3);\n    if (!(cin >> resp)) return 0;\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Greedy water-filling for one day: full-width stripes, minimize deficiency\n// Produces heights k[i] >= 1 with sum k[i] = W.\nstatic vector<int> compute_heights_one_day(int W, const vector<int>& a_sorted) {\n    int N = (int)a_sorted.size();\n    struct MaxItem { int s; int i; bool operator<(const MaxItem& o) const { return s < o.s; } };\n    struct MinItem { int h; int i; bool operator<(const MinItem& o) const { if (h != o.h) return h > o.h; return i > o.i; } };\n\n    vector<int> k(N, 1);\n    int R = W - N;\n    priority_queue<MaxItem> pq;\n    for (int i = 0; i < N; i++) {\n        int s = a_sorted[i] - W; // shortage after base height=1\n        if (s < 0) s = 0;\n        pq.push(MaxItem{s, i});\n    }\n    while (R > 0 && !pq.empty()) {\n        MaxItem cur = pq.top(); pq.pop();\n        if (cur.s <= 0) break;\n        k[cur.i] += 1;\n        cur.s -= W;\n        if (cur.s < 0) cur.s = 0;\n        pq.push(cur);\n        R--;\n    }\n    if (R > 0) {\n        priority_queue<MinItem> minpq;\n        for (int i = 0; i < N; i++) minpq.push(MinItem{k[i], i});\n        while (R > 0) {\n            auto cur = minpq.top(); minpq.pop();\n            cur.h += 1;\n            k[cur.i] = cur.h;\n            minpq.push(cur);\n            R--;\n        }\n    }\n    int sumh = 0;\n    for (int h : k) sumh += h;\n    if (sumh != W && N > 0) {\n        k.back() += (W - sumh);\n    }\n    return k;\n}\n\n// Compute boundary positions (prefix sums excluding W) from heights (physical order).\nstatic vector<int> boundaries_from_heights(const vector<int>& H) {\n    int N = (int)H.size();\n    vector<int> B;\n    B.reserve(max(0, N - 1));\n    int acc = 0;\n    for (int i = 0; i + 1 < N; i++) {\n        acc += H[i];\n        B.push_back(acc);\n    }\n    return B;\n}\n\n// Count matches between two boundary sets (exact coordinate equality).\nstatic int count_matches(const vector<int>& B1, const vector<int>& B2) {\n    int i = 0, j = 0, m = (int)B1.size(), n = (int)B2.size(), cnt = 0;\n    while (i < m && j < n) {\n        if (B1[i] == B2[j]) { cnt++; i++; j++; }\n        else if (B1[i] < B2[j]) i++;\n        else j++;\n    }\n    return cnt;\n}\n\n// Subset-sum exact equals gap with bitset + reconstruction. Reorders 'rem' implicitly via an index order.\n// prefer_more: if true, prefer taking when both take/no-take are possible (more items); else prefer fewer items.\nstatic bool take_subset_sum_bitset(vector<int>& rem, int gap, vector<int>& seq, bool prefer_more) {\n    if (gap <= 0) return (gap == 0);\n    int m = (int)rem.size();\n    if (m == 0) return false;\n\n    vector<int> idx(m);\n    iota(idx.begin(), idx.end(), 0);\n    if (prefer_more) {\n        stable_sort(idx.begin(), idx.end(), [&](int x, int y){ return rem[x] < rem[y]; }); // ascending\n    } else {\n        stable_sort(idx.begin(), idx.end(), [&](int x, int y){ return rem[x] > rem[y]; }); // descending\n    }\n    vector<int> w(m), origIndex(m);\n    for (int t = 0; t < m; t++) { w[t] = rem[idx[t]]; origIndex[t] = idx[t]; }\n\n    int G = gap;\n    int BS = G + 1;\n    int wordN = (BS + 63) >> 6;\n    vector<vector<unsigned long long>> dp(m + 1, vector<unsigned long long>(wordN, 0ULL));\n    auto setbit = [&](vector<unsigned long long>& b, int pos){\n        b[pos >> 6] |= (1ULL << (pos & 63));\n    };\n    auto getbit = [&](const vector<unsigned long long>& b, int pos)->bool {\n        return (b[pos >> 6] >> (pos & 63)) & 1ULL;\n    };\n    setbit(dp[0], 0);\n\n    for (int t = 0; t < m; t++) {\n        dp[t + 1] = dp[t];\n        int shift = w[t];\n        if (shift <= G) {\n            int fullShiftWords = shift >> 6;\n            int bitShift = shift & 63;\n            for (int wi = wordN - 1; wi >= 0; --wi) {\n                unsigned long long v = 0;\n                int srcIdx = wi - fullShiftWords;\n                if (srcIdx >= 0 && srcIdx < wordN) {\n                    v |= (dp[t][srcIdx] << bitShift);\n                    if (bitShift && srcIdx > 0) {\n                        v |= (dp[t][srcIdx - 1] >> (64 - bitShift));\n                    }\n                }\n                dp[t + 1][wi] |= v;\n            }\n        }\n    }\n\n    if (!getbit(dp[m], G)) return false;\n\n    vector<char> chosen(m, 0);\n    int s = G;\n    for (int t = m; t >= 1; --t) {\n        int wt = w[t - 1];\n        bool can_not_take = getbit(dp[t - 1], s);\n        bool can_take = (s - wt >= 0) && getbit(dp[t - 1], s - wt);\n        if (can_not_take && can_take) {\n            if (prefer_more) {\n                chosen[t - 1] = 1; s -= wt;\n            } else {\n                // prefer not take\n            }\n        } else if (!can_not_take && can_take) {\n            chosen[t - 1] = 1; s -= wt;\n        } else {\n            // do nothing\n        }\n    }\n\n    vector<int> chosenOrig;\n    chosenOrig.reserve(m);\n    for (int t = 0; t < m; t++) if (chosen[t]) chosenOrig.push_back(origIndex[t]);\n\n    vector<int> chosenWeights;\n    chosenWeights.reserve(chosenOrig.size());\n    for (int id : chosenOrig) chosenWeights.push_back(rem[id]);\n    sort(chosenWeights.begin(), chosenWeights.end());\n    for (int wv : chosenWeights) seq.push_back(wv);\n\n    vector<char> mark(m, 0);\n    for (int id : chosenOrig) mark[id] = 1;\n    vector<int> rem2; rem2.reserve(m - (int)chosenOrig.size());\n    for (int i = 0; i < m; i++) if (!mark[i]) rem2.push_back(rem[i]);\n    rem.swap(rem2);\n\n    return true;\n}\n\n// Arrange heights to align with 'targets' via sequential subset-sum (exact equality).\n// Does not change multiset of heights; keeps sum == W.\nstatic vector<int> arrange_align_with_targets(const vector<int>& heights, const vector<int>& targets, int W, bool prefer_more) {\n    vector<int> rem = heights;\n    sort(rem.begin(), rem.end()); // deterministic\n    vector<int> seq; seq.reserve(rem.size());\n    int pos = 0;\n    for (int b : targets) {\n        if (b <= pos) continue;\n        int gap = b - pos;\n        if (take_subset_sum_bitset(rem, gap, seq, prefer_more)) {\n            pos = b;\n            if (rem.empty()) break;\n        }\n    }\n    for (int h : rem) seq.push_back(h);\n    int sum = 0; for (int h : seq) sum += h;\n    if (sum != W && !seq.empty()) seq.back() += (W - sum);\n    return seq;\n}\n\n// Two-sided alignment: prioritize matching intersection of prev/next boundaries as anchors,\n// then within each interval attempt to match remaining boundaries (prev-only and next-only). Heights multiset unchanged.\nstatic vector<int> align_two_sided_pref(const vector<int>& heights, const vector<int>& Bprev, const vector<int>& Bnext, int W, bool prefer_more) {\n    vector<int> rem = heights;\n    sort(rem.begin(), rem.end());\n    vector<int> seq; seq.reserve(rem.size());\n    int pos = 0;\n\n    vector<char> inPrev(W + 1, 0), inNext(W + 1, 0);\n    for (int b : Bprev) if (0 <= b && b <= W) inPrev[b] = 1;\n    for (int b : Bnext) if (0 <= b && b <= W) inNext[b] = 1;\n\n    // Match anchors at intersection\n    vector<int> anchors;\n    anchors.push_back(0);\n    for (int x = 1; x < W; x++) if (inPrev[x] && inNext[x]) {\n        int gap = x - pos;\n        if (gap > 0 && take_subset_sum_bitset(rem, gap, seq, prefer_more)) {\n            pos = x;\n            anchors.push_back(pos);\n            if (rem.empty()) break;\n        }\n    }\n    anchors.push_back(W);\n\n    // Build prev-only and next-only lists\n    vector<int> prevOnly, nextOnly;\n    for (int b : Bprev) if (b > 0 && b < W && !inNext[b]) prevOnly.push_back(b);\n    for (int b : Bnext) if (b > 0 && b < W && !inPrev[b]) nextOnly.push_back(b);\n\n    // Process segments\n    for (int sidx = 0; sidx + 1 < (int)anchors.size(); sidx++) {\n        int segStart = anchors[sidx];\n        int segEnd = anchors[sidx + 1];\n        pos = segStart;\n\n        vector<int> Tseg;\n        auto it1 = lower_bound(prevOnly.begin(), prevOnly.end(), segStart + 1);\n        while (it1 != prevOnly.end() && *it1 < segEnd) { Tseg.push_back(*it1); ++it1; }\n        auto it2 = lower_bound(nextOnly.begin(), nextOnly.end(), segStart + 1);\n        while (it2 != nextOnly.end() && *it2 < segEnd) { Tseg.push_back(*it2); ++it2; }\n        sort(Tseg.begin(), Tseg.end());\n        Tseg.erase(unique(Tseg.begin(), Tseg.end()), Tseg.end());\n\n        for (int b : Tseg) {\n            if (b <= pos) continue;\n            int gap = b - pos;\n            if (take_subset_sum_bitset(rem, gap, seq, prefer_more)) {\n                pos = b;\n            }\n            if (rem.empty()) break;\n        }\n        if (rem.empty()) break;\n    }\n\n    for (int h : rem) seq.push_back(h);\n\n    int sum = 0; for (int h : seq) sum += h;\n    if (sum != W && !seq.empty()) seq.back() += (W - sum);\n\n    return seq;\n}\n\n// Top-up aware alignment: use base heights L (ceil(a/W)) and slack S to match targets.\n// For each target boundary gap, choose a subset of remaining base heights whose sum <= gap and as large as possible,\n// then top up the last stripe by the difference using slack, if available.\nstatic vector<int> arrange_align_topup(const vector<int>& baseL, int slackS, const vector<int>& targets, int W, bool prefer_more) {\n    vector<int> rem = baseL;\n    sort(rem.begin(), rem.end());\n    vector<int> seq; seq.reserve(rem.size());\n    int pos = 0;\n    int slack = slackS;\n\n    for (int b : targets) {\n        if (b <= pos) continue;\n        int gap = b - pos;\n        if (rem.empty()) break;\n\n        int m = (int)rem.size();\n        vector<int> cnt(gap + 1, -1), prevs(gap + 1, -1), previ(gap + 1, -1);\n        cnt[0] = 0;\n        for (int t = 0; t < m; t++) {\n            int w = rem[t];\n            if (w > gap) continue;\n            for (int s = gap; s >= w; --s) {\n                if (cnt[s - w] != -1) {\n                    int cand = cnt[s - w] + 1;\n                    if (cnt[s] == -1) {\n                        cnt[s] = cand; prevs[s] = s - w; previ[s] = t;\n                    } else {\n                        if (prefer_more) {\n                            if (cand > cnt[s]) { cnt[s] = cand; prevs[s] = s - w; previ[s] = t; }\n                        } else {\n                            if (cand < cnt[s]) { cnt[s] = cand; prevs[s] = s - w; previ[s] = t; }\n                        }\n                    }\n                }\n            }\n        }\n        int bests = -1;\n        for (int s = gap; s >= 1; --s) if (cnt[s] != -1) { bests = s; break; }\n        if (bests == -1) continue;\n\n        int inc = gap - bests;\n        if (inc > slack) continue;\n\n        vector<char> chosen(m, 0);\n        int s = bests;\n        while (s > 0) {\n            int t = previ[s];\n            if (t < 0) break;\n            chosen[t] = 1;\n            s = prevs[s];\n        }\n\n        for (int t = 0; t < m; t++) if (chosen[t]) seq.push_back(rem[t]);\n        if (!seq.empty()) seq.back() += inc;\n        slack -= inc;\n\n        vector<int> rem2; rem2.reserve(m);\n        for (int t = 0; t < m; t++) if (!chosen[t]) rem2.push_back(rem[t]);\n        rem.swap(rem2);\n\n        pos = b;\n        if (rem.empty()) break;\n    }\n\n    for (int h : rem) seq.push_back(h);\n    int sum = 0; for (int h : seq) sum += h;\n    int need = W - sum;\n    if (need < 0) need = 0;\n    if (!seq.empty()) seq.back() += need;\n    return seq;\n}\n\n// Two-sided top-up alignment: prioritize anchors at prev\u2229next, then match prev-only and next-only within segments using slack.\nstatic vector<int> align_two_sided_topup(const vector<int>& baseL, int slackS, const vector<int>& Bprev, const vector<int>& Bnext, int W, bool prefer_more) {\n    vector<int> rem = baseL;\n    sort(rem.begin(), rem.end());\n    vector<int> seq; seq.reserve(rem.size());\n    int pos = 0;\n    int slack = slackS;\n\n    vector<char> inPrev(W + 1, 0), inNext(W + 1, 0);\n    for (int b : Bprev) if (0 <= b && b <= W) inPrev[b] = 1;\n    for (int b : Bnext) if (0 <= b && b <= W) inNext[b] = 1;\n\n    // Anchors\n    vector<int> anchors;\n    anchors.push_back(0);\n    for (int x = 1; x < W; x++) if (inPrev[x] && inNext[x]) {\n        int gap = x - pos;\n        if (gap > 0) {\n            int m = (int)rem.size();\n            if (m == 0) break;\n            vector<int> cnt(gap + 1, -1), prevs(gap + 1, -1), previ(gap + 1, -1);\n            cnt[0] = 0;\n            for (int t = 0; t < m; t++) {\n                int w = rem[t];\n                if (w > gap) continue;\n                for (int s = gap; s >= w; --s) {\n                    if (cnt[s - w] != -1) {\n                        int cand = cnt[s - w] + 1;\n                        if (cnt[s] == -1) {\n                            cnt[s] = cand; prevs[s] = s - w; previ[s] = t;\n                        } else {\n                            if (prefer_more) {\n                                if (cand > cnt[s]) { cnt[s] = cand; prevs[s] = s - w; previ[s] = t; }\n                            } else {\n                                if (cand < cnt[s]) { cnt[s] = cand; prevs[s] = s - w; previ[s] = t; }\n                            }\n                        }\n                    }\n                }\n            }\n            int bests = -1;\n            for (int s = gap; s >= 1; --s) if (cnt[s] != -1) { bests = s; break; }\n            if (bests != -1) {\n                int inc = gap - bests;\n                if (inc <= slack) {\n                    vector<char> chosen(m, 0);\n                    int s = bests;\n                    while (s > 0) {\n                        int t = previ[s];\n                        if (t < 0) break;\n                        chosen[t] = 1;\n                        s = prevs[s];\n                    }\n                    for (int t = 0; t < m; t++) if (chosen[t]) seq.push_back(rem[t]);\n                    if (!seq.empty()) seq.back() += inc;\n                    slack -= inc;\n                    vector<int> rem2; rem2.reserve(m);\n                    for (int t = 0; t < m; t++) if (!chosen[t]) rem2.push_back(rem[t]);\n                    rem.swap(rem2);\n                    pos = x;\n                    anchors.push_back(pos);\n                    if (rem.empty()) break;\n                }\n            }\n        }\n    }\n    anchors.push_back(W);\n\n    // Build prev-only and next-only lists\n    vector<int> prevOnly, nextOnly;\n    for (int b : Bprev) if (b > 0 && b < W && !inNext[b]) prevOnly.push_back(b);\n    for (int b : Bnext) if (b > 0 && b < W && !inPrev[b]) nextOnly.push_back(b);\n\n    // Process segments\n    for (int sidx = 0; sidx + 1 < (int)anchors.size(); sidx++) {\n        int segStart = anchors[sidx];\n        int segEnd = anchors[sidx + 1];\n        pos = segStart;\n\n        vector<int> Tseg;\n        auto it1 = lower_bound(prevOnly.begin(), prevOnly.end(), segStart + 1);\n        while (it1 != prevOnly.end() && *it1 < segEnd) { Tseg.push_back(*it1); ++it1; }\n        auto it2 = lower_bound(nextOnly.begin(), nextOnly.end(), segStart + 1);\n        while (it2 != nextOnly.end() && *it2 < segEnd) { Tseg.push_back(*it2); ++it2; }\n        sort(Tseg.begin(), Tseg.end());\n        Tseg.erase(unique(Tseg.begin(), Tseg.end()), Tseg.end());\n\n        for (int b : Tseg) {\n            if (b <= pos) continue;\n            int gap = b - pos;\n            int m = (int)rem.size();\n            if (m == 0) break;\n\n            vector<int> cnt(gap + 1, -1), prevs(gap + 1, -1), previ(gap + 1, -1);\n            cnt[0] = 0;\n            for (int t = 0; t < m; t++) {\n                int w = rem[t];\n                if (w > gap) continue;\n                for (int s = gap; s >= w; --s) {\n                    if (cnt[s - w] != -1) {\n                        int cand = cnt[s - w] + 1;\n                        if (cnt[s] == -1) {\n                            cnt[s] = cand; prevs[s] = s - w; previ[s] = t;\n                        } else {\n                            if (prefer_more) {\n                                if (cand > cnt[s]) { cnt[s] = cand; prevs[s] = s - w; previ[s] = t; }\n                            } else {\n                                if (cand < cnt[s]) { cnt[s] = cand; prevs[s] = s - w; previ[s] = t; }\n                            }\n                        }\n                    }\n                }\n            }\n            int bests = -1;\n            for (int s = gap; s >= 1; --s) if (cnt[s] != -1) { bests = s; break; }\n            if (bests == -1) continue;\n\n            int inc = gap - bests;\n            if (inc > slack) continue;\n\n            vector<char> chosen(m, 0);\n            int s = bests;\n            while (s > 0) {\n                int t = previ[s];\n                if (t < 0) break;\n                chosen[t] = 1;\n                s = prevs[s];\n            }\n            for (int t = 0; t < m; t++) if (chosen[t]) seq.push_back(rem[t]);\n            if (!seq.empty()) seq.back() += inc;\n            slack -= inc;\n\n            vector<int> rem2; rem2.reserve(m);\n            for (int t = 0; t < m; t++) if (!chosen[t]) rem2.push_back(rem[t]);\n            rem.swap(rem2);\n\n            pos = b;\n            if (rem.empty()) break;\n        }\n        if (rem.empty()) break;\n    }\n\n    for (int h : rem) seq.push_back(h);\n    int sum = 0; for (int h : seq) sum += h;\n    int need = W - sum;\n    if (need < 0) need = 0;\n    if (!seq.empty()) seq.back() += need;\n\n    return seq;\n}\n\n// Build rectangles from heights (physical order) and assign to reservations by ascending area.\nstatic vector<array<int,4>> build_rectangles_and_assign(int W, const vector<int>& heights, const vector<int>& a_sorted) {\n    int N = (int)heights.size();\n    vector<array<int,4>> rect_by_index(N);\n    int cur = 0;\n    for (int t = 0; t < N; t++) {\n        int h = heights[t];\n        int i0 = cur, i1 = cur + h;\n        if (i0 < 0) i0 = 0;\n        if (i1 > W) i1 = W;\n        rect_by_index[t] = {i0, 0, i1, W};\n        cur = i1;\n    }\n    if (cur != W && N > 0) {\n        rect_by_index[N - 1][2] += (W - cur);\n        if (rect_by_index[N - 1][2] < rect_by_index[N - 1][0]) rect_by_index[N - 1][2] = rect_by_index[N - 1][0] + 1;\n        if (rect_by_index[N - 1][2] > W) rect_by_index[N - 1][2] = W;\n    }\n\n    vector<pair<int,int>> height_with_idx;\n    height_with_idx.reserve(N);\n    for (int t = 0; t < N; t++) height_with_idx.emplace_back(heights[t], t);\n    sort(height_with_idx.begin(), height_with_idx.end()); // ascending by height\n\n    vector<array<int,4>> rect_out(N);\n    for (int k = 0; k < N; k++) {\n        int stripe_idx = height_with_idx[k].second;\n        rect_out[k] = rect_by_index[stripe_idx];\n    }\n    return rect_out;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int W, D, N;\n    if (!(cin >> W >> D >> N)) return 0;\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    // Precompute per-day water-filling heights and ceil-base heights with slack\n    vector<vector<int>> heightsWF(D);\n    vector<vector<int>> baseL(D);\n    vector<int> slackS(D, 0);\n    vector<char> hasSlack(D, 0);\n    for (int d = 0; d < D; d++) {\n        heightsWF[d] = compute_heights_one_day(W, a[d]);\n        baseL[d].resize(N);\n        long long sumL = 0;\n        for (int i = 0; i < N; i++) {\n            long long x = a[d][i];\n            int bh = (int)((x + W - 1) / W);\n            if (bh < 1) bh = 1;\n            baseL[d][i] = bh;\n            sumL += bh;\n        }\n        if (sumL <= W) {\n            hasSlack[d] = 1;\n            slackS[d] = W - (int)sumL;\n        } else {\n            hasSlack[d] = 0;\n            slackS[d] = 0;\n        }\n    }\n\n    // Initial arrangements\n    vector<vector<int>> dayHeights(D);\n\n    // Day 0: align to day 1 boundaries; prefer top-up if slack available.\n    if (D >= 2) {\n        vector<int> baseAsc1 = heightsWF[1];\n        sort(baseAsc1.begin(), baseAsc1.end());\n        vector<int> B1 = boundaries_from_heights(baseAsc1);\n        vector<int> cA, cB;\n        if (hasSlack[0]) {\n            cA = arrange_align_topup(baseL[0], slackS[0], B1, W, false);\n            cB = arrange_align_topup(baseL[0], slackS[0], B1, W, true);\n        } else {\n            cA = arrange_align_with_targets(heightsWF[0], B1, W, false);\n            cB = arrange_align_with_targets(heightsWF[0], B1, W, true);\n        }\n        int mA = count_matches(boundaries_from_heights(cA), B1);\n        int mB = count_matches(boundaries_from_heights(cB), B1);\n        dayHeights[0] = (mB > mA ? move(cB) : move(cA));\n    } else {\n        dayHeights[0] = heightsWF[0];\n        sort(dayHeights[0].begin(), dayHeights[0].end());\n    }\n\n    // Forward pass: align each day to previous boundaries\n    for (int d = 1; d < D; d++) {\n        vector<int> prevB = boundaries_from_heights(dayHeights[d - 1]);\n        vector<int> c1, c2;\n        if (hasSlack[d]) {\n            c1 = arrange_align_topup(baseL[d], slackS[d], prevB, W, false);\n            c2 = arrange_align_topup(baseL[d], slackS[d], prevB, W, true);\n        } else {\n            c1 = arrange_align_with_targets(heightsWF[d], prevB, W, false);\n            c2 = arrange_align_with_targets(heightsWF[d], prevB, W, true);\n        }\n        int m1 = count_matches(boundaries_from_heights(c1), prevB);\n        int m2 = count_matches(boundaries_from_heights(c2), prevB);\n        dayHeights[d] = (m2 > m1 ? move(c2) : move(c1));\n    }\n\n    auto score_with_neighbors = [&](const vector<int>& seq, const vector<int>& Bprev, const vector<int>& Bnext) -> pair<int,pair<int,int>> {\n        vector<int> Bcur = boundaries_from_heights(seq);\n        int mp = (Bprev.empty() ? 0 : count_matches(Bcur, Bprev));\n        int mn = (Bnext.empty() ? 0 : count_matches(Bcur, Bnext));\n        return {mp + mn, {mp, mn}};\n    };\n\n    auto generate_candidates_exact = [&](const vector<int>& heights, const vector<int>& Bprev, const vector<int>& Bnext) -> vector<vector<int>> {\n        vector<vector<int>> cands;\n\n        // Two-sided alignment\n        cands.push_back(align_two_sided_pref(heights, Bprev, Bnext, W, false));\n        cands.push_back(align_two_sided_pref(heights, Bprev, Bnext, W, true));\n\n        // Union of targets (ascending and reversed)\n        vector<int> U = Bprev;\n        U.insert(U.end(), Bnext.begin(), Bnext.end());\n        sort(U.begin(), U.end());\n        U.erase(unique(U.begin(), U.end()), U.end());\n        vector<int> Urev = U; reverse(Urev.begin(), Urev.end());\n\n        cands.push_back(arrange_align_with_targets(heights, U, W, false));\n        cands.push_back(arrange_align_with_targets(heights, U, W, true));\n        cands.push_back(arrange_align_with_targets(heights, Urev, W, false));\n        cands.push_back(arrange_align_with_targets(heights, Urev, W, true));\n\n        // Prev-only and Next-only (ascending and reversed)\n        vector<int> PrevAsc = Bprev, PrevRev = Bprev;\n        vector<int> NextAsc = Bnext, NextRev = Bnext;\n        reverse(PrevRev.begin(), PrevRev.end());\n        reverse(NextRev.begin(), NextRev.end());\n\n        cands.push_back(arrange_align_with_targets(heights, PrevAsc, W, false));\n        cands.push_back(arrange_align_with_targets(heights, PrevAsc, W, true));\n        cands.push_back(arrange_align_with_targets(heights, PrevRev, W, false));\n        cands.push_back(arrange_align_with_targets(heights, PrevRev, W, true));\n\n        cands.push_back(arrange_align_with_targets(heights, NextAsc, W, false));\n        cands.push_back(arrange_align_with_targets(heights, NextAsc, W, true));\n        cands.push_back(arrange_align_with_targets(heights, NextRev, W, false));\n        cands.push_back(arrange_align_with_targets(heights, NextRev, W, true));\n\n        // Baseline ascending (current heights multiset)\n        vector<int> baseAsc = heights;\n        sort(baseAsc.begin(), baseAsc.end());\n        cands.push_back(baseAsc);\n\n        // Deduplicate by boundary sets\n        struct VecHash {\n            size_t operator()(const vector<int>& v) const noexcept {\n                uint64_t h = 1469598103934665603ULL;\n                for (int x : v) { h ^= (uint64_t)x + 0x9e3779b97f4a7c15ULL + (h<<6) + (h>>2); }\n                return (size_t)h;\n            }\n        };\n        unordered_set<vector<int>, VecHash> seen;\n        vector<vector<int>> uniq;\n        uniq.reserve(cands.size());\n        for (auto& s : cands) {\n            auto B = boundaries_from_heights(s);\n            if (seen.insert(B).second) uniq.push_back(move(s));\n        }\n        return uniq;\n    };\n\n    const auto T0 = chrono::steady_clock::now();\n    const double TL = 2.85;\n\n    // Iterative refinement: a few sweeps with time guard.\n    int sweeps = 4;\n    for (int sw = 0; sw < sweeps; sw++) {\n        // Forward sweep\n        for (int d = 0; d < D; d++) {\n            if ((d & 3) == 0) {\n                auto now = chrono::steady_clock::now();\n                if (chrono::duration<double>(now - T0).count() > TL) goto AFTER_SMOOTH;\n            }\n            vector<int> Bprev = (d > 0) ? boundaries_from_heights(dayHeights[d - 1]) : vector<int>();\n            vector<int> Bnext = (d + 1 < D) ? boundaries_from_heights(dayHeights[d + 1]) : vector<int>();\n            auto curScore = score_with_neighbors(dayHeights[d], Bprev, Bnext);\n\n            auto cands = generate_candidates_exact(dayHeights[d], Bprev, Bnext);\n            // Add two-sided top-up candidates if slack exists\n            if (hasSlack[d]) {\n                cands.push_back(align_two_sided_topup(baseL[d], slackS[d], Bprev, Bnext, W, false));\n                cands.push_back(align_two_sided_topup(baseL[d], slackS[d], Bprev, Bnext, W, true));\n            }\n\n            int bestIdx = -1;\n            pair<int,pair<int,int>> bestScore = curScore;\n            for (int i = 0; i < (int)cands.size(); i++) {\n                auto sc = score_with_neighbors(cands[i], Bprev, Bnext);\n                if (sc.first > bestScore.first) {\n                    bestScore = sc; bestIdx = i;\n                } else if (sc.first == bestScore.first) {\n                    // Prefer more matches with prev in forward sweep\n                    if (sc.second.first > bestScore.second.first) {\n                        bestScore = sc; bestIdx = i;\n                    }\n                }\n            }\n            if (bestIdx != -1) dayHeights[d] = move(cands[bestIdx]);\n        }\n        // Backward sweep\n        for (int d = D - 1; d >= 0; d--) {\n            if ((d & 3) == 0) {\n                auto now = chrono::steady_clock::now();\n                if (chrono::duration<double>(now - T0).count() > TL) goto AFTER_SMOOTH;\n            }\n            vector<int> Bprev = (d > 0) ? boundaries_from_heights(dayHeights[d - 1]) : vector<int>();\n            vector<int> Bnext = (d + 1 < D) ? boundaries_from_heights(dayHeights[d + 1]) : vector<int>();\n            auto curScore = score_with_neighbors(dayHeights[d], Bprev, Bnext);\n\n            auto cands = generate_candidates_exact(dayHeights[d], Bprev, Bnext);\n            if (hasSlack[d]) {\n                cands.push_back(align_two_sided_topup(baseL[d], slackS[d], Bprev, Bnext, W, false));\n                cands.push_back(align_two_sided_topup(baseL[d], slackS[d], Bprev, Bnext, W, true));\n            }\n\n            int bestIdx = -1;\n            pair<int,pair<int,int>> bestScore = curScore;\n            for (int i = 0; i < (int)cands.size(); i++) {\n                auto sc = score_with_neighbors(cands[i], Bprev, Bnext);\n                if (sc.first > bestScore.first) {\n                    bestScore = sc; bestIdx = i;\n                } else if (sc.first == bestScore.first) {\n                    // Prefer more matches with next in backward sweep\n                    if (sc.second.second > bestScore.second.second) {\n                        bestScore = sc; bestIdx = i;\n                    }\n                }\n            }\n            if (bestIdx != -1) dayHeights[d] = move(cands[bestIdx]);\n        }\n    }\n\nAFTER_SMOOTH:\n    // Anchor smoothing repeated twice: compute frequent boundary rows across current schedule, then try to align days to anchors.\n    for (int rep = 0; rep < 2; rep++) {\n        vector<int> freq(W + 1, 0);\n        for (int d = 0; d < D; d++) {\n            auto B = boundaries_from_heights(dayHeights[d]);\n            for (int y : B) if (y > 0 && y < W) freq[y]++;\n        }\n        vector<pair<int,int>> order;\n        order.reserve(W - 1);\n        for (int y = 1; y < W; y++) order.emplace_back(freq[y], y);\n        sort(order.begin(), order.end(), [&](const auto& L, const auto& R){\n            if (L.first != R.first) return L.first > R.first;\n            return L.second < R.second;\n        });\n        int K = max(0, N - 1);\n        vector<int> anchors;\n        anchors.reserve(K);\n        for (int i = 0; i < (int)order.size() && (int)anchors.size() < K; i++) anchors.push_back(order[i].second);\n        sort(anchors.begin(), anchors.end());\n\n        for (int d = 0; d < D; d++) {\n            if ((d & 7) == 0) {\n                auto now = chrono::steady_clock::now();\n                if (chrono::duration<double>(now - T0).count() > TL) goto FINAL_STAB;\n            }\n            vector<int> Bprev = (d > 0) ? boundaries_from_heights(dayHeights[d - 1]) : vector<int>();\n            vector<int> Bnext = (d + 1 < D) ? boundaries_from_heights(dayHeights[d + 1]) : vector<int>();\n            auto curScore = score_with_neighbors(dayHeights[d], Bprev, Bnext);\n\n            vector<vector<int>> cands;\n            cands.reserve(4);\n            if (hasSlack[d]) {\n                cands.push_back(arrange_align_topup(baseL[d], slackS[d], anchors, W, false));\n                cands.push_back(arrange_align_topup(baseL[d], slackS[d], anchors, W, true));\n            } else {\n                cands.push_back(arrange_align_with_targets(dayHeights[d], anchors, W, false));\n                cands.push_back(arrange_align_with_targets(dayHeights[d], anchors, W, true));\n            }\n            int bestIdx = -1;\n            pair<int,pair<int,int>> bestScore = curScore;\n            for (int i = 0; i < (int)cands.size(); i++) {\n                auto sc = score_with_neighbors(cands[i], Bprev, Bnext);\n                if (sc.first > bestScore.first) {\n                    bestScore = sc; bestIdx = i;\n                }\n            }\n            if (bestIdx != -1) dayHeights[d] = move(cands[bestIdx]);\n        }\n    }\n\nFINAL_STAB:\n    // Final stabilization: prev-only exact and top-up; also two-sided top-up if slack exists.\n    for (int d = 0; d < D; d++) {\n        if ((d & 7) == 0) {\n            auto now = chrono::steady_clock::now();\n            if (chrono::duration<double>(now - T0).count() > TL) break;\n        }\n        vector<int> Bprev = (d > 0) ? boundaries_from_heights(dayHeights[d - 1]) : vector<int>();\n        vector<int> Bnext = (d + 1 < D) ? boundaries_from_heights(dayHeights[d + 1]) : vector<int>();\n        auto curScore = score_with_neighbors(dayHeights[d], Bprev, Bnext);\n\n        vector<vector<int>> cands;\n        cands.reserve(6);\n        // Exact prev-only reorders\n        cands.push_back(arrange_align_with_targets(dayHeights[d], Bprev, W, false));\n        cands.push_back(arrange_align_with_targets(dayHeights[d], Bprev, W, true));\n        if (hasSlack[d]) {\n            // Prev-only top-up\n            cands.push_back(arrange_align_topup(baseL[d], slackS[d], Bprev, W, false));\n            cands.push_back(arrange_align_topup(baseL[d], slackS[d], Bprev, W, true));\n            // Two-sided top-up\n            cands.push_back(align_two_sided_topup(baseL[d], slackS[d], Bprev, Bnext, W, false));\n            cands.push_back(align_two_sided_topup(baseL[d], slackS[d], Bprev, Bnext, W, true));\n        }\n\n        int bestIdx = -1;\n        pair<int,pair<int,int>> bestScore = curScore;\n        for (int i = 0; i < (int)cands.size(); i++) {\n            auto sc = score_with_neighbors(cands[i], Bprev, Bnext);\n            if (sc.first > bestScore.first) {\n                bestScore = sc; bestIdx = i;\n            }\n        }\n        if (bestIdx != -1) dayHeights[d] = move(cands[bestIdx]);\n    }\n\n    // Output rectangles for each day based on final heights, assign to reservations by ascending area.\n    for (int d = 0; d < D; d++) {\n        vector<array<int,4>> rects = build_rectangles_and_assign(W, dayHeights[d], a[d]);\n        for (int k = 0; k < N; k++) {\n            auto &r = rects[k];\n            int i0 = max(0, min(W, r[0]));\n            int j0 = max(0, min(W, r[1]));\n            int i1 = max(0, min(W, r[2]));\n            int j1 = max(0, min(W, r[3]));\n            if (i1 <= i0) i1 = min(W, i0 + 1);\n            if (j1 <= j0) j1 = min(W, j0 + 1);\n            cout << i0 << ' ' << j0 << ' ' << i1 << ' ' << j1 << '\\n';\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic const ll MOD = 998244353LL;\n\ninline ll cell_gain(ll rcur, int sval) {\n    // rcur, sval in [0, MOD-1]\n    return ((ll)sval >= (MOD - rcur)) ? ((ll)sval - MOD) : (ll)sval;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto T0 = chrono::steady_clock::now();\n    auto elapsed_ms = [&](){\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - T0).count();\n    };\n    const long long TIME_LIMIT_MS = 1950;\n\n    int N, M, K;\n    if (!(cin >> N >> M >> K)) return 0;\n\n    const int SZ = N * N; // 81\n    vector<ll> r0(SZ), r(SZ);\n    for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) {\n        ll x; cin >> x;\n        r0[i*N + j] = x % MOD;\n    }\n    r = r0;\n\n    // Stamps (3x3)\n    vector<array<int, 9>> stamp(M);\n    for (int m = 0; m < M; ++m) {\n        for (int u = 0; u < 3; ++u) for (int v = 0; v < 3; ++v) {\n            int x; cin >> x;\n            stamp[m][u*3 + v] = x;\n        }\n    }\n\n    const int P = N - 2;        // 7\n    const int POS_CNT = P * P;  // 49\n    const int OPS = M * POS_CNT;// 980\n\n    // pos -> (p,q)\n    vector<int> pos_p(POS_CNT), pos_q(POS_CNT);\n    for (int p = 0, idx = 0; p < P; ++p) for (int q = 0; q < P; ++q, ++idx) {\n        pos_p[idx] = p; pos_q[idx] = q;\n    }\n\n    // Precompute operations\n    vector<array<int, 9>> op_cells(OPS);\n    vector<array<int, 9>> op_svals(OPS);\n    vector<int> op_m(OPS), op_p(OPS), op_q(OPS), op_pos(OPS);\n    for (int m = 0; m < M; ++m) {\n        for (int pos = 0; pos < POS_CNT; ++pos) {\n            int p = pos_p[pos], q = pos_q[pos];\n            int op = m * POS_CNT + pos;\n            op_m[op] = m; op_p[op] = p; op_q[op] = q; op_pos[op] = pos;\n            for (int u = 0; u < 3; ++u) for (int v = 0; v < 3; ++v) {\n                int k = u*3 + v;\n                int i = p + u, j = q + v;\n                op_cells[op][k] = i * N + j;\n                op_svals[op][k] = stamp[m][k];\n            }\n        }\n    }\n\n    // Precompute overlap list for each op (anchors within Chebyshev dist <= 2)\n    vector<vector<int>> overlOps(OPS);\n    overlOps.assign(OPS, {});\n    for (int op = 0; op < OPS; ++op) {\n        int p = op_p[op], q = op_q[op];\n        overlOps[op].reserve(25 * M);\n        for (int dp = -2; dp <= 2; ++dp) {\n            int p2 = p + dp; if (p2 < 0 || p2 >= P) continue;\n            for (int dq = -2; dq <= 2; ++dq) {\n                int q2 = q + dq; if (q2 < 0 || q2 >= P) continue;\n                int pos2 = p2 * P + q2;\n                for (int m2 = 0; m2 < M; ++m2) {\n                    int op2 = m2 * POS_CNT + pos2;\n                    overlOps[op].push_back(op2);\n                }\n            }\n        }\n    }\n\n    auto apply_op = [&](vector<ll>& board, int op){\n        const auto &c = op_cells[op];\n        const auto &s = op_svals[op];\n        ll nr;\n        nr = board[c[0]] + (ll)s[0]; if (nr >= MOD) nr -= MOD; board[c[0]] = nr;\n        nr = board[c[1]] + (ll)s[1]; if (nr >= MOD) nr -= MOD; board[c[1]] = nr;\n        nr = board[c[2]] + (ll)s[2]; if (nr >= MOD) nr -= MOD; board[c[2]] = nr;\n        nr = board[c[3]] + (ll)s[3]; if (nr >= MOD) nr -= MOD; board[c[3]] = nr;\n        nr = board[c[4]] + (ll)s[4]; if (nr >= MOD) nr -= MOD; board[c[4]] = nr;\n        nr = board[c[5]] + (ll)s[5]; if (nr >= MOD) nr -= MOD; board[c[5]] = nr;\n        nr = board[c[6]] + (ll)s[6]; if (nr >= MOD) nr -= MOD; board[c[6]] = nr;\n        nr = board[c[7]] + (ll)s[7]; if (nr >= MOD) nr -= MOD; board[c[7]] = nr;\n        nr = board[c[8]] + (ll)s[8]; if (nr >= MOD) nr -= MOD; board[c[8]] = nr;\n    };\n    auto remove_op = [&](vector<ll>& board, int op){\n        const auto &c = op_cells[op];\n        const auto &s = op_svals[op];\n        ll nr;\n        nr = board[c[0]] - (ll)s[0]; if (nr < 0) nr += MOD; board[c[0]] = nr;\n        nr = board[c[1]] - (ll)s[1]; if (nr < 0) nr += MOD; board[c[1]] = nr;\n        nr = board[c[2]] - (ll)s[2]; if (nr < 0) nr += MOD; board[c[2]] = nr;\n        nr = board[c[3]] - (ll)s[3]; if (nr < 0) nr += MOD; board[c[3]] = nr;\n        nr = board[c[4]] - (ll)s[4]; if (nr < 0) nr += MOD; board[c[4]] = nr;\n        nr = board[c[5]] - (ll)s[5]; if (nr < 0) nr += MOD; board[c[5]] = nr;\n        nr = board[c[6]] - (ll)s[6]; if (nr < 0) nr += MOD; board[c[6]] = nr;\n        nr = board[c[7]] - (ll)s[7]; if (nr < 0) nr += MOD; board[c[7]] = nr;\n        nr = board[c[8]] - (ll)s[8]; if (nr < 0) nr += MOD; board[c[8]] = nr;\n    };\n\n    auto compute_gain_for_op = [&](const vector<ll>& board, int op)->ll{\n        const auto &c = op_cells[op];\n        const auto &s = op_svals[op];\n        ll sum = 0;\n        for (int k = 0; k < 9; ++k) sum += cell_gain(board[c[k]], s[k]);\n        return sum;\n    };\n    auto compute_gain_all = [&](const vector<ll>& board, vector<ll>& gain){\n        for (int op = 0; op < OPS; ++op) gain[op] = compute_gain_for_op(board, op);\n    };\n\n    vector<ll> gain(OPS, 0);\n    vector<int> overlapMark(OPS, 0);\n    int overlapTag = 1;\n\n    vector<ll> tmpR(SZ, 0), tmpR2(SZ, 0);\n    vector<int> tmpRMark(SZ, 0), tmpR2Mark(SZ, 0);\n    int tmpRTag = 1, tmpR2Tag = 1;\n\n    vector<int> selectedOps; selectedOps.reserve(K);\n\n    // Global greedy with selective 3-step (overlapped second + top-5 unaffected second) then fast 2-step\n    auto global_refill = [&](){\n        compute_gain_all(r, gain);\n        while ((int)selectedOps.size() < K) {\n            if (elapsed_ms() > TIME_LIMIT_MS) return;\n\n            vector<int> order(OPS);\n            iota(order.begin(), order.end(), 0);\n            sort(order.begin(), order.end(), [&](int a, int b){\n                if (gain[a] != gain[b]) return gain[a] > gain[b];\n                return a < b;\n            });\n\n            int stepsDone = (int)selectedOps.size();\n            bool useTriple = (stepsDone < 20) && (elapsed_ms() < TIME_LIMIT_MS * 0.70);\n            int T = useTriple ? 64 : 256;\n            if (T > OPS) T = OPS;\n\n            ll bestCombined = LLONG_MIN;\n            ll bestG1 = LLONG_MIN;\n            int bestOp = -1;\n\n            for (int idx = 0; idx < T; ++idx) {\n                int op1 = order[idx];\n                ll g1 = gain[op1];\n\n                // Mark overlapped with op1\n                ++overlapTag;\n                for (int t : overlOps[op1]) overlapMark[t] = overlapTag;\n\n                // Top-5 unaffected second candidates\n                array<int,5> op2_un_ops = {-1, -1, -1, -1, -1};\n                array<ll,5> op2_un_g = {LLONG_MIN, LLONG_MIN, LLONG_MIN, LLONG_MIN, LLONG_MIN};\n                ll bestUn2 = LLONG_MIN;\n                int ucount = 0;\n                for (int j = 0; j < OPS && ucount < 5; ++j) {\n                    int cand = order[j];\n                    if (overlapMark[cand] != overlapTag) {\n                        op2_un_ops[ucount] = cand;\n                        op2_un_g[ucount] = gain[cand];\n                        if (gain[cand] > bestUn2) bestUn2 = gain[cand];\n                        ++ucount;\n                    }\n                }\n\n                // Prepare r' after op1\n                ++tmpRTag;\n                const auto &c1 = op_cells[op1];\n                const auto &s1 = op_svals[op1];\n                for (int k = 0; k < 9; ++k) {\n                    int c = c1[k];\n                    ll nr = r[c] + (ll)s1[k]; if (nr >= MOD) nr -= MOD;\n                    tmpR[c] = nr; tmpRMark[c] = tmpRTag;\n                }\n\n                // Overlapped second under r': top-2\n                int topOp2a = -1, topOp2b = -1;\n                ll g2a = LLONG_MIN, g2b = LLONG_MIN;\n                ll bestOv2 = LLONG_MIN;\n                for (int t : overlOps[op1]) {\n                    const auto &c = op_cells[t];\n                    const auto &s = op_svals[t];\n                    ll sum = 0;\n                    for (int k = 0; k < 9; ++k) {\n                        ll rr = (tmpRMark[c[k]] == tmpRTag) ? tmpR[c[k]] : r[c[k]];\n                        sum += ((ll)s[k] >= (MOD - rr)) ? ((ll)s[k] - MOD) : (ll)s[k];\n                    }\n                    if (sum > bestOv2) bestOv2 = sum;\n                    if (sum > g2a) { g2b = g2a; topOp2b = topOp2a; g2a = sum; topOp2a = t; }\n                    else if (sum > g2b && t != topOp2a) { g2b = sum; topOp2b = t; }\n                }\n\n                ll combined = LLONG_MIN;\n\n                if (useTriple) {\n                    // Overlapped second candidates with exact overlapped third under r''\n                    array<int,2> cand2_ops = {topOp2a, topOp2b};\n                    array<ll,2> cand2_g = {g2a, g2b};\n                    ll best2plus3_ov = 0;\n\n                    for (int ci = 0; ci < 2; ++ci) {\n                        int op2 = cand2_ops[ci];\n                        if (op2 < 0) continue;\n                        ll g2 = cand2_g[ci];\n\n                        // r'' = r' + op2\n                        ++tmpR2Tag;\n                        const auto &c2 = op_cells[op2];\n                        const auto &s2 = op_svals[op2];\n                        for (int k = 0; k < 9; ++k) {\n                            int c = c2[k];\n                            ll rr1 = (tmpRMark[c] == tmpRTag) ? tmpR[c] : r[c];\n                            ll nr = rr1 + (ll)s2[k]; if (nr >= MOD) nr -= MOD;\n                            tmpR2[c] = nr; tmpR2Mark[c] = tmpR2Tag;\n                        }\n\n                        // Best overlapped third under r'' over union overlaps(op1) \u222a overlaps(op2)\n                        ll bestOv3 = LLONG_MIN;\n                        ++overlapTag;\n                        int tagA = overlapTag;\n                        for (int t : overlOps[op1]) overlapMark[t] = tagA;\n                        // First set\n                        for (int t : overlOps[op1]) {\n                            const auto &c = op_cells[t];\n                            const auto &s = op_svals[t];\n                            ll sum3 = 0;\n                            for (int k = 0; k < 9; ++k) {\n                                ll rr = (tmpR2Mark[c[k]] == tmpR2Tag) ? tmpR2[c[k]] :\n                                         (tmpRMark[c[k]] == tmpRTag ? tmpR[c[k]] : r[c[k]]);\n                                sum3 += ((ll)s[k] >= (MOD - rr)) ? ((ll)s[k] - MOD) : (ll)s[k];\n                            }\n                            if (sum3 > bestOv3) bestOv3 = sum3;\n                        }\n                        for (int t : overlOps[op2]) {\n                            if (overlapMark[t] == tagA) continue;\n                            const auto &c = op_cells[t];\n                            const auto &s = op_svals[t];\n                            ll sum3 = 0;\n                            for (int k = 0; k < 9; ++k) {\n                                ll rr = (tmpR2Mark[c[k]] == tmpR2Tag) ? tmpR2[c[k]] :\n                                         (tmpRMark[c[k]] == tmpRTag ? tmpR[c[k]] : r[c[k]]);\n                                sum3 += ((ll)s[k] >= (MOD - rr)) ? ((ll)s[k] - MOD) : (ll)s[k];\n                            }\n                            if (sum3 > bestOv3) bestOv3 = sum3;\n                        }\n\n                        // Best unaffected third under base gains outside union (approx)\n                        ++overlapTag;\n                        int unionTag = overlapTag;\n                        for (int t : overlOps[op1]) overlapMark[t] = unionTag;\n                        for (int t : overlOps[op2]) overlapMark[t] = unionTag;\n                        ll bestUn3 = 0;\n                        for (int j = 0; j < OPS; ++j) {\n                            int cand = order[j];\n                            if (overlapMark[cand] != unionTag) { bestUn3 = max(bestUn3, gain[cand]); break; }\n                        }\n\n                        ll best3 = max(bestOv3, bestUn3);\n                        if (best3 < 0) best3 = 0;\n                        ll twoPlusThree = g2 + best3;\n                        if (twoPlusThree < 0) twoPlusThree = 0;\n                        if (twoPlusThree > best2plus3_ov) best2plus3_ov = twoPlusThree;\n                    }\n\n                    // Unaffected second candidates (top-5) with exact union-overlap third under r'' and unaffected third\n                    ll best2plus3_un = 0;\n                    for (int ui = 0; ui < 5; ++ui) {\n                        int op2 = op2_un_ops[ui];\n                        if (op2 < 0) continue;\n                        ll g2 = op2_un_g[ui];\n\n                        // r'' = r' + op2\n                        ++tmpR2Tag;\n                        const auto &c2 = op_cells[op2];\n                        const auto &s2 = op_svals[op2];\n                        for (int k = 0; k < 9; ++k) {\n                            int c = c2[k];\n                            ll rr1 = (tmpRMark[c] == tmpRTag) ? tmpR[c] : r[c];\n                            ll nr = rr1 + (ll)s2[k]; if (nr >= MOD) nr -= MOD;\n                            tmpR2[c] = nr; tmpR2Mark[c] = tmpR2Tag;\n                        }\n\n                        // Best overlapped third under r'' over union overlaps(op1) \u222a overlaps(op2)\n                        ll bestOv3_union = LLONG_MIN;\n                        ++overlapTag;\n                        int tagU = overlapTag;\n                        for (int t : overlOps[op1]) overlapMark[t] = tagU;\n                        for (int t : overlOps[op1]) {\n                            const auto &c = op_cells[t];\n                            const auto &s = op_svals[t];\n                            ll sum3 = 0;\n                            for (int k = 0; k < 9; ++k) {\n                                ll rr = (tmpR2Mark[c[k]] == tmpR2Tag) ? tmpR2[c[k]] :\n                                         (tmpRMark[c[k]] == tmpRTag ? tmpR[c[k]] : r[c[k]]);\n                                sum3 += ((ll)s[k] >= (MOD - rr)) ? ((ll)s[k] - MOD) : (ll)s[k];\n                            }\n                            if (sum3 > bestOv3_union) bestOv3_union = sum3;\n                        }\n                        for (int t : overlOps[op2]) {\n                            if (overlapMark[t] == tagU) continue;\n                            const auto &c = op_cells[t];\n                            const auto &s = op_svals[t];\n                            ll sum3 = 0;\n                            for (int k = 0; k < 9; ++k) {\n                                ll rr = (tmpR2Mark[c[k]] == tmpR2Tag) ? tmpR2[c[k]] :\n                                         (tmpRMark[c[k]] == tmpRTag ? tmpR[c[k]] : r[c[k]]);\n                                sum3 += ((ll)s[k] >= (MOD - rr)) ? ((ll)s[k] - MOD) : (ll)s[k];\n                            }\n                            if (sum3 > bestOv3_union) bestOv3_union = sum3;\n                        }\n\n                        // Best unaffected third outside union (approx)\n                        ++overlapTag;\n                        int unionTag2 = overlapTag;\n                        for (int t : overlOps[op1]) overlapMark[t] = unionTag2;\n                        for (int t : overlOps[op2]) overlapMark[t] = unionTag2;\n                        ll bestUn3 = 0;\n                        for (int j = 0; j < OPS; ++j) {\n                            int cand = order[j];\n                            if (overlapMark[cand] != unionTag2) { bestUn3 = max(bestUn3, gain[cand]); break; }\n                        }\n\n                        ll best3 = max(bestOv3_union, bestUn3);\n                        if (best3 < 0) best3 = 0;\n                        ll twoPlusThree = g2 + best3;\n                        if (twoPlusThree < 0) twoPlusThree = 0;\n                        if (twoPlusThree > best2plus3_un) best2plus3_un = twoPlusThree;\n                    }\n\n                    ll candTriple = g1 + max(best2plus3_ov, best2plus3_un);\n                    ll cand2step = g1 + max(0LL, max(bestUn2, bestOv2));\n                    combined = max(candTriple, cand2step);\n                } else {\n                    // 2-step only\n                    ll best2 = max(bestUn2, bestOv2);\n                    if (best2 < 0) best2 = 0;\n                    combined = g1 + best2;\n                }\n\n                if (combined > bestCombined || (combined == bestCombined && g1 > bestG1)) {\n                    bestCombined = combined;\n                    bestG1 = g1;\n                    bestOp = op1;\n                }\n            }\n\n            if (bestOp == -1) break;\n            if (bestCombined <= 0) break;\n\n            selectedOps.push_back(bestOp);\n            apply_op(r, bestOp);\n            // Incremental gain updates for affected ops\n            for (int t : overlOps[bestOp]) gain[t] = compute_gain_for_op(r, t);\n        }\n    };\n\n    // Initial global greedy\n    global_refill();\n\n    // Deterministic RNG\n    uint64_t seed = 0x9e3779b97f4a7c15ULL ^ (uint64_t)N * 0xBF58476D1CE4E5B9ULL ^ (uint64_t)M * 0x94D049BB133111EBULL ^ (uint64_t)K;\n    auto rng64 = [&]()->uint64_t {\n        seed ^= seed << 7; seed ^= seed >> 9; seed *= 0xD6E8FEB86659FD93ULL; return seed;\n    };\n\n    // Local Neighborhood Search (LNS)\n    vector<char> allowedMark(OPS, 0);\n    vector<int> keptOpsBuf; keptOpsBuf.reserve(K);\n    vector<int> removedOpsBuf; removedOpsBuf.reserve(K);\n    vector<ll> r_work(SZ);\n    vector<ll> lgain(OPS, LLONG_MIN);\n    vector<int> allowedOps; allowedOps.reserve(OPS);\n\n    vector<ll> tmpR_local(SZ, 0);\n    vector<int> tmpRMark_local(SZ, 0);\n    int tmpRTag_local = 1;\n\n    auto recompute_local_gain_for_op = [&](int op)->ll{\n        const auto &c = op_cells[op];\n        const auto &s = op_svals[op];\n        ll sum = 0;\n        for (int k = 0; k < 9; ++k) sum += cell_gain(r_work[c[k]], s[k]);\n        return sum;\n    };\n\n    auto sum_region_cells = [&](const vector<ll>& board, int sp, int sq, int RA)->ll {\n        int i0 = sp, i1 = sp + RA + 1;\n        int j0 = sq, j1 = sq + RA + 1;\n        ll sum = 0;\n        for (int i = i0; i <= i1; ++i) for (int j = j0; j <= j1; ++j) sum += board[i*N + j];\n        return sum;\n    };\n\n    vector<int> newOps; newOps.reserve(K);\n\n    auto local_refill = [&](int cap, vector<int>& outOps){\n        outOps.clear();\n        allowedOps.clear();\n        for (int op = 0; op < OPS; ++op) if (allowedMark[op]) allowedOps.push_back(op);\n        if (allowedOps.empty() || cap <= 0) return;\n\n        for (int op : allowedOps) lgain[op] = recompute_local_gain_for_op(op);\n\n        vector<int> order; order.reserve(allowedOps.size());\n        int steps = 0;\n        while (steps < cap) {\n            if (elapsed_ms() > TIME_LIMIT_MS) return;\n\n            order = allowedOps;\n            sort(order.begin(), order.end(), [&](int a, int b){\n                if (lgain[a] != lgain[b]) return lgain[a] > lgain[b];\n                return a < b;\n            });\n\n            int T = min(64, (int)order.size());\n            ll bestCombined = LLONG_MIN, bestG1 = LLONG_MIN;\n            int bestOp = -1;\n\n            for (int idx = 0; idx < T; ++idx) {\n                int op1 = order[idx];\n                ll g1 = lgain[op1];\n\n                // Mark overlapped within allowed\n                ++overlapTag;\n                for (int t : overlOps[op1]) if (allowedMark[t]) overlapMark[t] = overlapTag;\n\n                // Best unaffected second\n                ll bestUn = 0;\n                for (int j = 0; j < (int)order.size(); ++j) {\n                    int cand = order[j];\n                    if (overlapMark[cand] != overlapTag) { bestUn = max(bestUn, lgain[cand]); break; }\n                }\n\n                // Hypothetical op1 on r_work\n                ++tmpRTag_local;\n                const auto &c1 = op_cells[op1];\n                const auto &s1 = op_svals[op1];\n                for (int k = 0; k < 9; ++k) {\n                    int c = c1[k];\n                    ll nr = r_work[c] + (ll)s1[k]; if (nr >= MOD) nr -= MOD;\n                    tmpR_local[c] = nr; tmpRMark_local[c] = tmpRTag_local;\n                }\n\n                // Best overlapped under r'\n                ll bestOv = LLONG_MIN;\n                for (int t : overlOps[op1]) {\n                    if (!allowedMark[t]) continue;\n                    const auto &c = op_cells[t];\n                    const auto &s = op_svals[t];\n                    ll sum = 0;\n                    for (int k = 0; k < 9; ++k) {\n                        ll rr = (tmpRMark_local[c[k]] == tmpRTag_local) ? tmpR_local[c[k]] : r_work[c[k]];\n                        sum += ((ll)s[k] >= (MOD - rr)) ? ((ll)s[k] - MOD) : (ll)s[k];\n                    }\n                    if (sum > bestOv) bestOv = sum;\n                }\n\n                ll best2 = max(bestUn, bestOv);\n                if (best2 < 0) best2 = 0;\n                ll combined = g1 + best2;\n\n                if (combined > bestCombined || (combined == bestCombined && g1 > bestG1)) {\n                    bestCombined = combined; bestG1 = g1; bestOp = op1;\n                }\n            }\n\n            if (bestOp == -1) break;\n            if (bestCombined <= 0) break;\n\n            outOps.push_back(bestOp);\n            apply_op(r_work, bestOp);\n            for (int t : overlOps[bestOp]) if (allowedMark[t]) lgain[t] = recompute_local_gain_for_op(t);\n\n            ++steps;\n        }\n    };\n\n    auto LNS_loop = [&](bool micro){\n        for (;;) {\n            if (elapsed_ms() > TIME_LIMIT_MS) break;\n            if (selectedOps.empty()) break;\n\n            int roll = (int)(rng64() % 100);\n            int RA;\n            if (micro) {\n                RA = (roll < 70 ? 2 : 3);\n            } else {\n                RA = (roll < 60 ? 3 : (roll < 95 ? 4 : 5));\n            }\n            if (RA > P) RA = P;\n            int sp = (int)(rng64() % (P - RA + 1));\n            int sq = (int)(rng64() % (P - RA + 1));\n\n            // Allowed ops mask\n            fill(allowedMark.begin(), allowedMark.end(), 0);\n            for (int p = sp; p < sp + RA; ++p) {\n                for (int q = sq; q < sq + RA; ++q) {\n                    int pos = p * P + q;\n                    for (int m = 0; m < M; ++m) allowedMark[m * POS_CNT + pos] = 1;\n                }\n            }\n\n            // Split selected ops\n            keptOpsBuf.clear();\n            removedOpsBuf.clear();\n            for (int op : selectedOps) {\n                if (allowedMark[op]) removedOpsBuf.push_back(op);\n                else keptOpsBuf.push_back(op);\n            }\n            if (removedOpsBuf.empty()) continue;\n\n            // Build r_work = r0 + keptOps\n            r_work = r0;\n            for (int op : keptOpsBuf) apply_op(r_work, op);\n\n            ll sumBefore = sum_region_cells(r, sp, sq, RA);\n\n            // Capacity for local rebuild\n            int cap = K - (int)keptOpsBuf.size();\n            int capMin = (int)removedOpsBuf.size();\n            int capBound = micro ? (2 * RA * RA) : (2 * RA * RA);\n            cap = max(min(cap, capBound), min(cap, capMin));\n            if (cap <= 0) continue;\n\n            local_refill(cap, newOps);\n\n            ll sumAfter = sum_region_cells(r_work, sp, sq, RA);\n            if (sumAfter > sumBefore) {\n                selectedOps = keptOpsBuf;\n                selectedOps.insert(selectedOps.end(), newOps.begin(), newOps.end());\n                r = r_work;\n                global_refill();\n            }\n        }\n    };\n\n    // First LNS pass\n    LNS_loop(false);\n\n    // Prune individually harmful operations\n    compute_gain_all(r, gain);\n    while (true) {\n        if (elapsed_ms() > TIME_LIMIT_MS) break;\n        ll bestDelta = 0;\n        int bestIdx = -1;\n        for (int i = 0; i < (int)selectedOps.size(); ++i) {\n            int op = selectedOps[i];\n            ll delta = 0;\n            for (int k = 0; k < 9; ++k) {\n                int c = op_cells[op][k];\n                int s = op_svals[op][k];\n                if (r[c] >= s) delta -= s; else delta += (MOD - s);\n            }\n            if (delta > bestDelta) { bestDelta = delta; bestIdx = i; }\n        }\n        if (bestIdx == -1) break;\n        int op = selectedOps[bestIdx];\n        remove_op(r, op);\n        for (int t : overlOps[op]) gain[t] = compute_gain_for_op(r, t);\n        selectedOps[bestIdx] = selectedOps.back();\n        selectedOps.pop_back();\n    }\n\n    // Second micro LNS pass if time remains\n    if (elapsed_ms() < TIME_LIMIT_MS * 0.95) {\n        LNS_loop(true);\n    }\n\n    // Final refill to use remaining capacity\n    global_refill();\n\n    // Output\n    cout << (int)selectedOps.size() << '\\n';\n    for (int op : selectedOps) {\n        cout << op_m[op] << ' ' << op_p[op] << ' ' << op_q[op] << '\\n';\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 5;\n    static constexpr int TOT = N * N;\n\n    int A[N][N];\n\n    // Grid occupancy: -1 for empty, otherwise container id\n    int occ[N][N];\n\n    // Spawn pointers per receiving row (col = 0)\n    int spawnIdx[N];\n\n    // Large crane state\n    int br = 0, bc = 0; // position\n    int hold = -1;      // container id held or -1\n\n    // Output strings\n    vector<string> S;\n\n    // Delivered tracking\n    bool delivered[TOT];\n    int deliveredCount = 0;\n\n    // Next expected id per dispatch row (row i expects i*N .. i*N+N-1 in order)\n    int nextExpected[N];\n\n    // Source row/index for each id\n    int srcRow[TOT], srcIdx[TOT];\n\n    // Persistent fetch target\n    bool hasFetch = false;\n    int trg_r = -1, trg_c = -1, trg_id = -1;\n\n    // Weights\n    static constexpr int INV_W = 140;   // a bit stronger than exact 100 to favor order\n    static constexpr int GATE_PEN = 20; // discourage out-of-order picks at receiving gates\n\n    Solver() {\n        memset(occ, -1, sizeof(occ));\n        memset(spawnIdx, 0, sizeof(spawnIdx));\n        memset(delivered, 0, sizeof(delivered));\n        S.assign(N, \"\");\n        for (int i = 0; i < N; i++) nextExpected[i] = i * N;\n    }\n\n    void readInput() {\n        int n;\n        if (!(cin >> n)) exit(0); // N is always 5\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                cin >> A[i][j];\n            }\n        }\n        // Precompute sources\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = A[i][j];\n                srcRow[id] = i;\n                srcIdx[id] = j;\n            }\n        }\n    }\n\n    // Step 1: Spawn if possible at receiving gates (col 0)\n    void step1_spawn() {\n        for (int i = 0; i < N; i++) {\n            if (spawnIdx[i] >= N) continue; // no more to spawn for this row\n            if (occ[i][0] == -1) {\n                // Spawn is blocked only if a crane holding a container is at that gate\n                if (!(br == i && bc == 0 && hold != -1)) {\n                    int id = A[i][spawnIdx[i]];\n                    occ[i][0] = id;\n                    spawnIdx[i]++;\n                }\n            }\n        }\n    }\n\n    // Step 3: Dispatch at gates (col 4)\n    void step3_dispatch() {\n        for (int i = 0; i < N; i++) {\n            if (occ[i][4] != -1) {\n                int id = occ[i][4];\n                occ[i][4] = -1;\n                if (!delivered[id]) {\n                    delivered[id] = true;\n                    deliveredCount++;\n                }\n            }\n        }\n        // Update nextExpected per row according to delivered flags\n        for (int r = 0; r < N; r++) {\n            int lo = r * N;\n            int hi = lo + N;\n            while (nextExpected[r] < hi && delivered[nextExpected[r]]) nextExpected[r]++;\n        }\n    }\n\n    inline int manhattan(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    // Prefer horizontal move first when going to dispatch gates (to reach col 4),\n    // and also generally lean horizontal-first to reduce zig-zag.\n    char stepTowardBiased(int cr, int cc, int tr, int tc) {\n        int dr = tr - cr;\n        int dc = tc - cc;\n        if (dc != 0) {\n            return (dc > 0) ? 'R' : 'L';\n        } else if (dr != 0) {\n            return (dr > 0) ? 'D' : 'U';\n        }\n        return '.';\n    }\n\n    char stepToward(int tr, int tc) {\n        return stepTowardBiased(br, bc, tr, tc);\n    }\n\n    // Tier 1: find best in-order container present on the grid (not at dispatch gates)\n    bool findBestInOrder(int &tr, int &tc, int &tid) {\n        int bestTravel = INT_MAX;\n        int br0 = br, bc0 = bc;\n        bool found = false;\n        int brst = -1, bcst = -1, bid = -1;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = occ[r][c];\n                if (id == -1) continue;\n                if (c == N - 1) continue; // ignore dispatch gates\n                int dr = id / N;\n                if (id == nextExpected[dr]) {\n                    int travel = manhattan(br0, bc0, r, c) + manhattan(r, c, dr, N - 1);\n                    if (travel < bestTravel || (travel == bestTravel && id < bid)) {\n                        bestTravel = travel;\n                        brst = r; bcst = c; bid = id;\n                        found = true;\n                    }\n                }\n            }\n        }\n        if (found) {\n            tr = brst; tc = bcst; tid = bid;\n        }\n        return found;\n    }\n\n    // Compute best imminent in-order row (spawns next turn if we keep gate empty)\n    // Returns true if exists and sets row and estimated cost (go+wait+deliver)\n    bool bestImminentInOrderRow(int &row, int &estCost) {\n        int bestRow = -1;\n        int bestCost = INT_MAX;\n        for (int r = 0; r < N; r++) {\n            int hi = (r + 1) * N;\n            if (nextExpected[r] >= hi) continue; // row complete\n            if (occ[r][0] != -1) continue;       // gate not empty now\n            if (spawnIdx[r] >= N) continue;\n            if (A[r][spawnIdx[r]] != nextExpected[r]) continue; // not imminent\n            int d_gate = manhattan(br, bc, r, 0);\n            int d_del = 4; // from gate to dispatch gate\n            int cost = d_gate + 1 + d_del;\n            if (cost < bestCost || (cost == bestCost && r < bestRow)) {\n                bestCost = cost;\n                bestRow = r;\n            }\n        }\n        if (bestRow != -1) {\n            row = bestRow;\n            estCost = bestCost;\n            return true;\n        }\n        return false;\n    }\n\n    // Weighted out-of-order fallback; returns best cost and fills tr, tc, tid\n    bool findWeightedOutOfOrder(int &tr, int &tc, int &tid, long long &bestCostOut) {\n        long long bestCost = (1LL << 60);\n        int bestR = -1, bestC = -1, bestID = -1;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = occ[r][c];\n                if (id == -1) continue;\n                if (c == N - 1) continue; // ignore dispatch gates\n                int dr = id / N;\n                int expected = nextExpected[dr];\n                int m = (id >= expected ? (id - expected) : 0);\n                int travel = manhattan(br, bc, r, c) + manhattan(r, c, dr, N - 1);\n                long long cost = (long long)travel + 1LL * INV_W * m;\n                if (c == 0 && id != expected) cost += GATE_PEN;\n                if (cost < bestCost || (cost == bestCost && id < bestID)) {\n                    bestCost = cost;\n                    bestR = r; bestC = c; bestID = id;\n                }\n            }\n        }\n        if (bestID != -1) {\n            tr = bestR; tc = bestC; tid = bestID;\n            bestCostOut = bestCost;\n            return true;\n        }\n        return false;\n    }\n\n    // If we have a non-inorder target but an inorder candidate exists now, retarget to best inorder\n    void maybeRetargetToInOrder() {\n        if (!hasFetch) return;\n        int dr_t = trg_id / N;\n        if (trg_id == nextExpected[dr_t]) return; // already inorder\n        int curBestR = -1, curBestC = -1, curBestID = -1;\n        int curBestTravel = INT_MAX;\n        bool found = false;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = occ[r][c];\n                if (id == -1 || c == N - 1) continue;\n                int dr = id / N;\n                if (id == nextExpected[dr]) {\n                    found = true;\n                    int travel = manhattan(br, bc, r, c) + manhattan(r, c, dr, N - 1);\n                    if (travel < curBestTravel || (travel == curBestTravel && id < curBestID)) {\n                        curBestTravel = travel;\n                        curBestR = r; curBestC = c; curBestID = id;\n                    }\n                }\n            }\n        }\n        if (found) {\n            trg_r = curBestR; trg_c = curBestC; trg_id = curBestID;\n            hasFetch = true;\n        }\n    }\n\n    int chooseWaitRow() {\n        int bestR = -1;\n        int bestDist = INT_MAX;\n        int bestPicks = INT_MAX;\n        for (int r = 0; r < N; r++) {\n            int hi = (r + 1) * N;\n            if (nextExpected[r] >= hi) continue; // row complete\n            int dist = manhattan(br, bc, r, 0);\n            int jWanted = srcIdx[nextExpected[r]];\n            int picksNeeded = 0;\n            if (occ[r][0] != -1) {\n                int ig = srcIdx[occ[r][0]];\n                if (jWanted >= ig) picksNeeded = jWanted - ig;\n                else picksNeeded = 0;\n            } else {\n                int s = spawnIdx[r];\n                if (jWanted >= s) picksNeeded = jWanted - s;\n                else picksNeeded = 0;\n            }\n            if (dist < bestDist || (dist == bestDist && picksNeeded < bestPicks) ||\n                (dist == bestDist && picksNeeded == bestPicks && r < bestR)) {\n                bestDist = dist;\n                bestPicks = picksNeeded;\n                bestR = r;\n            }\n        }\n        if (bestR == -1) bestR = 0; // fallback\n        return bestR;\n    }\n\n    // Decide the large crane's action\n    char decideAction() {\n        if (hold != -1) {\n            int dr = hold / N;\n            int dc = N - 1; // 4\n            if (br == dr && bc == dc) {\n                // Drop if empty\n                if (occ[br][bc] == -1) return 'Q';\n                // If occupied (very unlikely), wait\n                return '.';\n            } else {\n                return stepToward(dr, dc);\n            }\n        } else {\n            // Opportunistic in-order pick at current cell (avoid dispatch gate)\n            if (occ[br][bc] != -1 && bc != N - 1) {\n                int id = occ[br][bc];\n                int dr = id / N;\n                if (id == nextExpected[dr]) {\n                    return 'P';\n                }\n            }\n\n            // Invalidate stale target\n            if (hasFetch) {\n                if (!(trg_r >= 0 && trg_r < N && trg_c >= 0 && trg_c < N && occ[trg_r][trg_c] == trg_id)) {\n                    hasFetch = false;\n                }\n            }\n\n            // Possibly retarget to an in-order container if available\n            if (hasFetch) {\n                maybeRetargetToInOrder();\n            }\n\n            // If still no target, try to find an in-order present now\n            if (!hasFetch) {\n                int tr, tc, tid;\n                if (findBestInOrder(tr, tc, tid)) {\n                    trg_r = tr; trg_c = tc; trg_id = tid; hasFetch = true;\n                }\n            }\n\n            if (!hasFetch) {\n                // Compute both options: imminent in-order wait vs weighted out-of-order pick\n                int rowWait, waitCost;\n                bool hasWait = bestImminentInOrderRow(rowWait, waitCost);\n                int tr, tc, tid;\n                long long outCost;\n                bool hasOut = findWeightedOutOfOrder(tr, tc, tid, outCost);\n\n                if (hasWait && (!hasOut || (long long)waitCost <= outCost)) {\n                    // Go wait at that gate\n                    if (br == rowWait && bc == 0) return '.';\n                    return stepToward(rowWait, 0);\n                }\n\n                if (hasOut) {\n                    trg_r = tr; trg_c = tc; trg_id = tid; hasFetch = true;\n                } else {\n                    // No candidates (only at gates or done): choose a decent waiting row\n                    int wr = chooseWaitRow();\n                    if (br == wr && bc == 0) return '.';\n                    return stepToward(wr, 0);\n                }\n            }\n\n            // We have a target: move toward it; only pick when exactly on it\n            if (br == trg_r && bc == trg_c) {\n                if (occ[br][bc] == trg_id) {\n                    return 'P';\n                } else {\n                    // Target disappeared; replan next turn\n                    hasFetch = false;\n                    return '.';\n                }\n            } else {\n                return stepToward(trg_r, trg_c);\n            }\n        }\n    }\n\n    // Apply the big crane action to our simulation state\n    void applyBigAction(char act) {\n        if (act == 'U') br--;\n        else if (act == 'D') br++;\n        else if (act == 'L') bc--;\n        else if (act == 'R') bc++;\n        else if (act == 'P') {\n            // Pick: valid if not holding and cell has a container (we avoid dispatch gate in decisions)\n            if (hold == -1 && occ[br][bc] != -1) {\n                hold = occ[br][bc];\n                occ[br][bc] = -1;\n                hasFetch = false; // reset target after picking\n            }\n        } else if (act == 'Q') {\n            // Drop: valid if holding and cell empty\n            if (hold != -1 && occ[br][bc] == -1) {\n                occ[br][bc] = hold;\n                hold = -1;\n            }\n        }\n        // '.' does nothing\n    }\n\n    void run() {\n        const int MAX_TURNS = 10000;\n        for (int t = 0; t < MAX_TURNS; t++) {\n            // Step 1: spawn\n            step1_spawn();\n\n            // Step 2: actions\n            char bigAct = decideAction();\n\n            // Record outputs\n            S[0].push_back(bigAct);\n            for (int i = 1; i < N; i++) {\n                // Bomb small cranes at t=0, then idle (dots after removal)\n                if (t == 0) S[i].push_back('B');\n                else S[i].push_back('.');\n            }\n\n            // Apply big action to state\n            applyBigAction(bigAct);\n\n            // Step 3: dispatch\n            step3_dispatch();\n\n            if (deliveredCount >= TOT) break;\n        }\n\n        // Pad strings to equal length\n        size_t L = 0;\n        for (int i = 0; i < N; i++) L = max(L, S[i].size());\n        for (int i = 0; i < N; i++) {\n            if (S[i].size() < L) S[i].append(L - S[i].size(), '.');\n        }\n    }\n\n    void output() {\n        for (int i = 0; i < N; i++) cout << S[i] << \"\\n\";\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.run();\n    solver.output();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\n// RNG for deterministic randomness\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed=1469598103934665603ULL){ x=seed; }\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int randint(int l, int r){ // inclusive\n        return l + int(next() % (uint64_t)(r-l+1));\n    }\n    double rand01(){\n        return (next() >> 11) * (1.0 / (1ull<<53));\n    }\n    template<class T>\n    void shuffle_vec(vector<T>& a){\n        for(int i=(int)a.size()-1;i>0;i--){\n            int j = int(next() % (uint64_t)(i+1));\n            swap(a[i], a[j]);\n        }\n    }\n};\n\n// Weighted sampler for small arrays\nstruct WeightedSampler {\n    vector<uint64_t> pref;\n    uint64_t sum = 0;\n    WeightedSampler() {}\n    WeightedSampler(const vector<int>& w){ build(w); }\n    void build(const vector<int>& w){\n        pref.resize(w.size());\n        sum = 0;\n        for(size_t i=0;i<w.size();++i){\n            sum += (w[i] > 0 ? (uint64_t)w[i] : 1);\n            pref[i] = sum;\n        }\n        if(sum == 0){\n            // Avoid zero sum: make uniform\n            pref.resize(w.size());\n            for(size_t i=0;i<w.size();++i){\n                sum += 1;\n                pref[i] = sum;\n            }\n        }\n    }\n    int sample(RNG& rng) const {\n        if(pref.empty()) return 0;\n        uint64_t r = rng.next() % sum;\n        size_t idx = lower_bound(pref.begin(), pref.end(), r+1) - pref.begin();\n        if(idx >= pref.size()) idx = pref.size()-1;\n        return (int)idx;\n    }\n};\n\n// Helpers to convert between (r,c) and linear id\nstatic inline int vid(int N, int r, int c){ return r*N + c; }\nstatic inline pair<int,int> rc_from_id(int N, int v){ return {v / N, v % N}; }\n\n// 2-regular graph adjacency utilities\nstatic inline void adj_add(vector<array<int,2>>& nb, int u, int v){\n    if(nb[u][0] == v || nb[u][1] == v) return;\n    if(nb[u][0] == -1) nb[u][0] = v;\n    else if(nb[u][1] == -1) nb[u][1] = v;\n    if(nb[v][0] == u || nb[v][1] == u) return;\n    if(nb[v][0] == -1) nb[v][0] = u;\n    else if(nb[v][1] == -1) nb[v][1] = u;\n}\nstatic inline void adj_remove(vector<array<int,2>>& nb, int u, int v){\n    if(nb[u][0] == v) nb[u][0] = -1;\n    else if(nb[u][1] == v) nb[u][1] = -1;\n    if(nb[v][0] == u) nb[v][0] = -1;\n    else if(nb[v][1] == u) nb[v][1] = -1;\n}\n\n// Cycle builder with two schemes\nstruct CycleBuilder {\n    int N, M, Br, Bc;\n    vector<array<int,2>> nb;\n\n    CycleBuilder(int N): N(N), M(N*N), Br(N/2), Bc(N/2), nb(M, {-1,-1}) {}\n\n    inline void clear() { nb.assign(M, array<int,2>{-1,-1}); }\n\n    inline void add_edge(int u, int v){ adj_add(nb, u, v); }\n    inline void remove_edge(int u, int v){ adj_remove(nb, u, v); }\n\n    void build_2x2_cycles(){\n        clear();\n        for(int br=0; br<Br; ++br){\n            for(int bc=0; bc<Bc; ++bc){\n                int x = 2*br, y = 2*bc;\n                int a = vid(N, x,   y);\n                int b = vid(N, x,   y+1);\n                int c = vid(N, x+1, y+1);\n                int d = vid(N, x+1, y);\n                add_edge(a,b);\n                add_edge(b,c);\n                add_edge(c,d);\n                add_edge(d,a);\n            }\n        }\n    }\n\n    // Horizontal-first\n    void merge_horizontally_all(){\n        for(int br=0; br<Br; ++br){\n            int x0 = 2*br;\n            for(int bc=0; bc<Bc-1; ++bc){\n                int y1 = 2*bc+1;\n                int y2 = 2*bc+2;\n                int a = vid(N, x0,   y1);\n                int b = vid(N, x0+1, y1);\n                int c = vid(N, x0,   y2);\n                int d = vid(N, x0+1, y2);\n                remove_edge(a,b);\n                remove_edge(c,d);\n                add_edge(a,c);\n                add_edge(b,d);\n            }\n        }\n    }\n    void merge_vertically_with_anchors(const vector<int>& anchors){\n        for(int br=0; br<Br-1; ++br){\n            int r1 = 2*br+1;\n            int r2 = 2*br+2;\n            int colBlock = anchors[br];\n            if(colBlock < 0) colBlock = 0;\n            if(colBlock >= Bc) colBlock = Bc-1;\n            int y0 = 2*colBlock;\n            int y1 = y0 + 1;\n            int a = vid(N, r1, y0);\n            int b = vid(N, r1, y1);\n            int c = vid(N, r2, y0);\n            int d = vid(N, r2, y1);\n            remove_edge(a,b);\n            remove_edge(c,d);\n            add_edge(a,c);\n            add_edge(b,d);\n        }\n    }\n\n    // Vertical-first\n    void merge_vertically_all(){\n        for(int bc=0; bc<Bc; ++bc){\n            int y0 = 2*bc;\n            int y1 = y0 + 1;\n            for(int br=0; br<Br-1; ++br){\n                int x1 = 2*br+1;\n                int x2 = 2*br+2;\n                int a = vid(N, x1, y0);\n                int b = vid(N, x1, y1);\n                int c = vid(N, x2, y1);\n                int d = vid(N, x2, y0);\n                remove_edge(a,b);\n                remove_edge(d,c);\n                add_edge(a,d);\n                add_edge(b,c);\n            }\n        }\n    }\n    void merge_horizontally_with_anchors(const vector<int>& anchorsCols){\n        for(int bc=0; bc<Bc-1; ++bc){\n            int cblock = anchorsCols[bc];\n            if(cblock < 0) cblock = 0;\n            if(cblock >= Br) cblock = Br-1;\n            int r0 = 2*cblock;\n            int r1 = r0 + 1;\n            int yL = 2*bc+1;\n            int yR = 2*bc+2;\n            int a = vid(N, r0, yL);\n            int b = vid(N, r1, yL);\n            int c = vid(N, r0, yR);\n            int d = vid(N, r1, yR);\n            remove_edge(a,b);\n            remove_edge(c,d);\n            add_edge(a,c);\n            add_edge(b,d);\n        }\n    }\n\n    vector<pair<int,int>> extract_cycle_path(){\n        vector<pair<int,int>> path;\n        path.reserve(M);\n        int start = vid(N, 0, 0);\n        int cur = start;\n        int prev = -1;\n        vector<char> seen(M, 0);\n        for(int cnt=0; cnt<M; ++cnt){\n            if(cur < 0 || cur >= M){ path.clear(); return path; }\n            if(seen[cur]){ path.clear(); return path; }\n            seen[cur] = 1;\n            path.emplace_back(rc_from_id(N, cur));\n            int n0 = nb[cur][0], n1 = nb[cur][1];\n            int nxt = (n0 == prev ? n1 : n0);\n            if(nxt == -1){ path.clear(); return path; }\n            prev = cur;\n            cur = nxt;\n        }\n        auto [xr, xc] = path.back();\n        int last = vid(N, xr, xc);\n        if(!(nb[last][0] == start || nb[last][1] == start)){\n            path.clear();\n        }\n        return path;\n    }\n\n    vector<pair<int,int>> build_scheme_A(const vector<int>& anchors){\n        build_2x2_cycles();\n        merge_horizontally_all();\n        merge_vertically_with_anchors(anchors);\n        return extract_cycle_path();\n    }\n    vector<pair<int,int>> build_scheme_B(const vector<int>& anchorsCols){\n        build_2x2_cycles();\n        merge_vertically_all();\n        merge_horizontally_with_anchors(anchorsCols);\n        return extract_cycle_path();\n    }\n};\n\n// Rotate path coordinates by rot=0..3\nstatic vector<pair<int,int>> rotate_path(const vector<pair<int,int>>& path, int N, int rot){\n    vector<pair<int,int>> res;\n    res.reserve(path.size());\n    for(auto [r,c] : path){\n        int nr=r, nc=c;\n        if(rot==1){ nr = c; nc = N-1 - r; }\n        else if(rot==2){ nr = N-1 - r; nc = N-1 - c; }\n        else if(rot==3){ nr = N-1 - c; nc = r; }\n        res.emplace_back(nr,nc);\n    }\n    return res;\n}\n\n// Evaluate one directed path: returns (cost, bestStartIndex)\nstatic pair<long long,int> eval_directed_path(const vector<pair<int,int>>& pos,\n                                              const vector<vector<int>>& h,\n                                              long long base)\n{\n    int M = (int)pos.size();\n    vector<long long> arr(M);\n    for(int i=0;i<M;i++){\n        arr[i] = h[pos[i].first][pos[i].second];\n    }\n    vector<long long> pre2(2*M+1, 0);\n    for(int i=0;i<2*M;i++){\n        pre2[i+1] = pre2[i] + arr[i%M];\n    }\n    vector<long long> prefpre2(2*M+1, 0);\n    for(int i=1;i<=2*M;i++){\n        prefpre2[i] = prefpre2[i-1] + pre2[i-1];\n    }\n    long long minVal = LLONG_MAX;\n    for(int i=0;i<M;i++) minVal = min(minVal, pre2[i]);\n    vector<int> starts;\n    for(int s=0;s<M;s++) if(pre2[s] == minVal) starts.push_back(s);\n\n    long long bestCost = (1LL<<62);\n    int bestS = 0;\n    for(int s: starts){\n        long long sumPre2Range = (prefpre2[s+M] - prefpre2[s+1]); // pre2[s+1..s+M-1]\n        long long dsum = sumPre2Range - 1LL*(M-1)*pre2[s];\n        int sx = pos[s].first, sy = pos[s].second;\n        int repositionDist = abs(sx) + abs(sy);\n        long long moveCost = 100LL*((M-1) + repositionDist);\n        long long cost = base + moveCost + dsum;\n        if(cost < bestCost){\n            bestCost = cost;\n            bestS = s;\n        }\n    }\n    return {bestCost, bestS};\n}\n\nstruct EvalResult {\n    long long cost;\n    int startIndex;\n    int rot;\n    bool reversed;\n};\n\n// Evaluate best among 4 rotations and both directions\nstatic EvalResult eval_cycle_any_orientation(const vector<pair<int,int>>& cyc,\n                                             const vector<vector<int>>& h,\n                                             long long base, int N)\n{\n    EvalResult best{(1LL<<62), 0, 0, false};\n    for(int rot=0; rot<4; ++rot){\n        auto p = rotate_path(cyc, N, rot);\n        auto [c1, s1] = eval_directed_path(p, h, base);\n        if(c1 < best.cost){\n            best = {c1, s1, rot, false};\n        }\n        auto pr = p;\n        reverse(pr.begin(), pr.end());\n        auto [c2, s2] = eval_directed_path(pr, h, base);\n        if(c2 < best.cost){\n            best = {c2, s2, rot, true};\n        }\n    }\n    return best;\n}\n\n// Build nb from path cycle\nstatic vector<array<int,2>> nb_from_path(const vector<pair<int,int>>& path, int N){\n    int M = (int)path.size();\n    vector<array<int,2>> nb(N*N, array<int,2>{-1,-1});\n    auto ID = [&](int idx){ return vid(N, path[idx].first, path[idx].second); };\n    for(int i=0;i<M;i++){\n        int u = ID(i);\n        int v = ID((i+1)%M);\n        adj_add(nb, u, v);\n    }\n    return nb;\n}\n\n// Extract path from nb (single cycle)\nstatic vector<pair<int,int>> path_from_nb(const vector<array<int,2>>& nb, int N){\n    int M = N*N;\n    vector<pair<int,int>> path;\n    path.reserve(M);\n    int start = vid(N, 0, 0);\n    int cur = start;\n    int prev = -1;\n    vector<char> seen(M, 0);\n    for(int cnt=0; cnt<M; ++cnt){\n        if(cur < 0 || cur >= M){ path.clear(); return path; }\n        if(seen[cur]){ path.clear(); return path; }\n        seen[cur] = 1;\n        path.emplace_back(rc_from_id(N, cur));\n        int n0 = nb[cur][0], n1 = nb[cur][1];\n        int nxt = (n0 == prev ? n1 : n0);\n        if(nxt == -1){ path.clear(); return path; }\n        prev = cur;\n        cur = nxt;\n    }\n    auto [xr, xc] = path.back();\n    int last = vid(N, xr, xc);\n    if(!(nb[last][0] == start || nb[last][1] == start)){\n        path.clear();\n    }\n    return path;\n}\n\n// Attempt 2x2 plaquette flip on square (x,y); returns true if flipped\nstatic bool try_flip_square(vector<array<int,2>>& nb, int N, int x, int y){\n    int a = vid(N, x,   y);\n    int b = vid(N, x,   y+1);\n    int c = vid(N, x+1, y+1);\n    int d = vid(N, x+1, y);\n\n    auto used = [&](int u, int v)->bool{\n        return nb[u][0]==v || nb[u][1]==v;\n    };\n\n    bool ab = used(a,b);\n    bool bc = used(b,c);\n    bool cd = used(c,d);\n    bool da = used(d,a);\n\n    if(ab && cd && !bc && !da){\n        adj_remove(nb, a, b);\n        adj_remove(nb, c, d);\n        adj_add(nb, b, c);\n        adj_add(nb, d, a);\n        return true;\n    }else if(bc && da && !ab && !cd){\n        adj_remove(nb, b, c);\n        adj_remove(nb, d, a);\n        adj_add(nb, a, b);\n        adj_add(nb, c, d);\n        return true;\n    }\n    return false;\n}\n\nstruct CycleCandidate {\n    vector<pair<int,int>> path; // oriented path (rotated/reversed)\n    vector<int> anchors;        // seam anchors used\n    char scheme;                // 'A' or 'B'\n    long long cost;             // minimal cost for this oriented path (across starts)\n};\n\nstatic CycleCandidate optimize_scheme_A(\n    int N, const vector<vector<int>>& h, long long base, RNG& rng,\n    const chrono::steady_clock::time_point& t0, double anchorBudgetMs)\n{\n    CycleBuilder cb(N);\n    int Br = N/2, Bc = N/2;\n    auto elapsedMs = [&](){ return chrono::duration<double, milli>(chrono::steady_clock::now() - t0).count(); };\n\n    // Seeds\n    vector<vector<int>> seeds;\n    for(int k=0;k<Bc;k++){ vector<int> anc(max(Br-1,0), k); seeds.push_back(anc); if((int)seeds.size()>=4) break; }\n    for(int k=0;k<Bc && (int)seeds.size()<8;k++){ vector<int> anc(max(Br-1,0)); for(int br=0;br<Br-1;br++) anc[br]=(k+br)%Bc; seeds.push_back(anc); }\n    for(int k=0;k<Bc && (int)seeds.size()<12;k++){ vector<int> anc(max(Br-1,0)); for(int br=0;br<Br-1;br++) anc[br]=(k-br+Bc)%Bc; seeds.push_back(anc); }\n    for(int t=0;t<18;t++){ vector<int> anc(max(Br-1,0)); for(int br=0;br<Br-1;br++) anc[br]=rng.randint(0,Bc-1); seeds.push_back(anc); }\n\n    long long bestCostGlobal = (1LL<<62);\n    vector<pair<int,int>> bestPathGlobal;\n    vector<int> bestAnchorsGlobal;\n\n    for(size_t si=0; si<seeds.size(); ++si){\n        if(elapsedMs() > anchorBudgetMs) break;\n        long long currentBestCost = (1LL<<62);\n        vector<pair<int,int>> bestPathThisSeed;\n        vector<int> bestAnchorsThisSeed;\n        vector<int> currentAnch = seeds[si];\n        bool improvedOverall = true;\n        int pass = 0;\n        while(improvedOverall && pass < 5){\n            improvedOverall = false;\n            pass++;\n            for(int br=0;br<Br-1;br++){\n                if(elapsedMs() > anchorBudgetMs) break;\n                long long localBest = (1LL<<62);\n                int bestK = currentAnch[br];\n                for(int k=0;k<Bc;k++){\n                    currentAnch[br] = k;\n                    auto cyc = cb.build_scheme_A(currentAnch);\n                    if(cyc.empty()) continue;\n                    auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n                    if(ev.cost < localBest){\n                        localBest = ev.cost;\n                        bestK = k;\n                    }\n                }\n                currentAnch[br] = bestK;\n            }\n            auto cyc = cb.build_scheme_A(currentAnch);\n            if(!cyc.empty()){\n                auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n                if(ev.cost + 1e-9 < currentBestCost){\n                    currentBestCost = ev.cost;\n                    improvedOverall = true;\n                    bestPathThisSeed = rotate_path(cyc, N, ev.rot);\n                    if(ev.reversed) reverse(bestPathThisSeed.begin(), bestPathThisSeed.end());\n                    bestAnchorsThisSeed = currentAnch;\n                }\n            }\n        }\n        if(currentBestCost < bestCostGlobal && !bestPathThisSeed.empty()){\n            bestCostGlobal = currentBestCost;\n            bestPathGlobal = bestPathThisSeed;\n            bestAnchorsGlobal = bestAnchorsThisSeed;\n        }\n    }\n\n    if(bestPathGlobal.empty()){\n        vector<int> anc(max(Br-1,0), 0);\n        auto cyc = cb.build_scheme_A(anc);\n        if(cyc.empty()) return {{}, {}, 'A', (1LL<<62)};\n        auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n        auto path = rotate_path(cyc, N, ev.rot);\n        if(ev.reversed) reverse(path.begin(), path.end());\n        return {path, anc, 'A', ev.cost};\n    }else{\n        return {bestPathGlobal, bestAnchorsGlobal, 'A', bestCostGlobal};\n    }\n}\n\nstatic CycleCandidate optimize_scheme_B(\n    int N, const vector<vector<int>>& h, long long base, RNG& rng,\n    const chrono::steady_clock::time_point& t0, double anchorBudgetMs)\n{\n    CycleBuilder cb(N);\n    int Br = N/2, Bc = N/2;\n    auto elapsedMs = [&](){ return chrono::duration<double, milli>(chrono::steady_clock::now() - t0).count(); };\n\n    vector<vector<int>> seeds;\n    for(int k=0;k<Br;k++){ vector<int> anc(max(Bc-1,0), k); seeds.push_back(anc); if((int)seeds.size()>=4) break; }\n    for(int k=0;k<Br && (int)seeds.size()<8;k++){ vector<int> anc(max(Bc-1,0)); for(int bc=0;bc<Bc-1;bc++) anc[bc]=(k+bc)%Br; seeds.push_back(anc); }\n    for(int k=0;k<Br && (int)seeds.size()<12;k++){ vector<int> anc(max(Bc-1,0)); for(int bc=0;bc<Bc-1;bc++) anc[bc]=(k-bc+Br)%Br; seeds.push_back(anc); }\n    for(int t=0;t<18;t++){ vector<int> anc(max(Bc-1,0)); for(int bc=0;bc<Bc-1;bc++) anc[bc]=rng.randint(0,Br-1); seeds.push_back(anc); }\n\n    long long bestCostGlobal = (1LL<<62);\n    vector<pair<int,int>> bestPathGlobal;\n    vector<int> bestAnchorsGlobal;\n\n    for(size_t si=0; si<seeds.size(); ++si){\n        if(elapsedMs() > anchorBudgetMs) break;\n        long long currentBestCost = (1LL<<62);\n        vector<pair<int,int>> bestPathThisSeed;\n        vector<int> bestAnchorsThisSeed;\n        vector<int> currentAnch = seeds[si];\n        bool improvedOverall = true;\n        int pass = 0;\n        while(improvedOverall && pass < 5){\n            improvedOverall = false;\n            pass++;\n            for(int bc=0; bc<Bc-1; bc++){\n                if(elapsedMs() > anchorBudgetMs) break;\n                long long localBest = (1LL<<62);\n                int bestK = currentAnch[bc];\n                for(int k=0;k<Br;k++){\n                    currentAnch[bc] = k;\n                    auto cyc = cb.build_scheme_B(currentAnch);\n                    if(cyc.empty()) continue;\n                    auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n                    if(ev.cost < localBest){\n                        localBest = ev.cost;\n                        bestK = k;\n                    }\n                }\n                currentAnch[bc] = bestK;\n            }\n            auto cyc = cb.build_scheme_B(currentAnch);\n            if(!cyc.empty()){\n                auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n                if(ev.cost + 1e-9 < currentBestCost){\n                    currentBestCost = ev.cost;\n                    improvedOverall = true;\n                    bestPathThisSeed = rotate_path(cyc, N, ev.rot);\n                    if(ev.reversed) reverse(bestPathThisSeed.begin(), bestPathThisSeed.end());\n                    bestAnchorsThisSeed = currentAnch;\n                }\n            }\n        }\n        if(currentBestCost < bestCostGlobal && !bestPathThisSeed.empty()){\n            bestCostGlobal = currentBestCost;\n            bestPathGlobal = bestPathThisSeed;\n            bestAnchorsGlobal = bestAnchorsThisSeed;\n        }\n    }\n\n    if(bestPathGlobal.empty()){\n        vector<int> anc(max(Bc-1,0), 0);\n        auto cyc = cb.build_scheme_B(anc);\n        if(cyc.empty()) return {{}, {}, 'B', (1LL<<62)};\n        auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n        auto path = rotate_path(cyc, N, ev.rot);\n        if(ev.reversed) reverse(path.begin(), path.end());\n        return {path, anc, 'B', ev.cost};\n    }else{\n        return {bestPathGlobal, bestAnchorsGlobal, 'B', bestCostGlobal};\n    }\n}\n\n// SA over anchors with time budget; includes occasional two-index perturbations\nstatic CycleCandidate anchor_sa(const CycleCandidate& init,\n                                int N, const vector<vector<int>>& h, long long base,\n                                RNG& rng,\n                                const chrono::steady_clock::time_point& t0,\n                                double budgetMs, double timeLimitMs)\n{\n    auto elapsedMs = [&](){ return chrono::duration<double, milli>(chrono::steady_clock::now() - t0).count(); };\n    double startMs = elapsedMs();\n    double endMs = min(startMs + budgetMs, timeLimitMs * 0.85);\n\n    if(init.path.empty()) return init;\n\n    CycleBuilder cb(N);\n    int Br = N/2, Bc = N/2;\n\n    vector<int> curAnch = init.anchors;\n    vector<pair<int,int>> curPath = init.path;\n    long long curCost = init.cost;\n\n    vector<int> bestAnch = curAnch;\n    vector<pair<int,int>> bestPath = curPath;\n    long long bestCost = curCost;\n\n    int L = (init.scheme=='A' ? max(Br-1,0) : max(Bc-1,0));\n    int range = (init.scheme=='A' ? Bc : Br);\n\n    double T0 = 4000.0, Tend = 2.0;\n    int attempts = 0;\n    int maxAttempts = 20000;\n\n    while(elapsedMs() < endMs && attempts < maxAttempts){\n        attempts++;\n        if(L == 0) break;\n\n        vector<pair<int,int>> changes;\n        if(rng.rand01() < 0.7 || L == 1){\n            int idx = rng.randint(0, L-1);\n            int newval;\n            if(rng.rand01() < 0.7){\n                int delta = rng.randint(-1, 1);\n                newval = (curAnch[idx] + delta) % range;\n                if(newval < 0) newval += range;\n            }else newval = rng.randint(0, range-1);\n            if(newval == curAnch[idx]) continue;\n            changes.emplace_back(idx, newval);\n        }else{\n            int i1 = rng.randint(0, L-1);\n            int i2 = rng.randint(0, L-1);\n            if(i1 == i2) continue;\n            int v1 = rng.randint(0, range-1);\n            int v2 = rng.randint(0, range-1);\n            if(v1 == curAnch[i1] && v2 == curAnch[i2]) continue;\n            changes.emplace_back(i1, v1);\n            changes.emplace_back(i2, v2);\n        }\n\n        vector<int> savedVals;\n        savedVals.reserve(changes.size());\n        for(auto &p : changes){\n            savedVals.push_back(curAnch[p.first]);\n            curAnch[p.first] = p.second;\n        }\n\n        vector<pair<int,int>> cyc = (init.scheme=='A') ? cb.build_scheme_A(curAnch)\n                                                       : cb.build_scheme_B(curAnch);\n        if(cyc.empty()){\n            for(size_t k=0;k<changes.size();++k) curAnch[changes[k].first] = savedVals[k];\n            continue;\n        }\n        auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n        vector<pair<int,int>> newPath = rotate_path(cyc, N, ev.rot);\n        if(ev.reversed) reverse(newPath.begin(), newPath.end());\n        long long newCost = ev.cost;\n\n        long long delta = newCost - curCost;\n        double frac = (elapsedMs() - startMs) / max(1e-9, (endMs - startMs));\n        if(frac < 0) frac = 0;\n        if(frac > 1) frac = 1;\n        double T = T0 * pow(Tend / T0, frac);\n\n        bool accept = (delta <= 0) || (rng.rand01() < exp(-(double)delta / max(1.0, T)));\n        if(accept){\n            curCost = newCost;\n            curPath.swap(newPath);\n            if(curCost < bestCost){\n                bestCost = curCost;\n                bestPath = curPath;\n                bestAnch = curAnch;\n            }\n        }else{\n            for(size_t k=0;k<changes.size();++k) curAnch[changes[k].first] = savedVals[k];\n        }\n    }\n\n    return {bestPath, bestAnch, init.scheme, bestCost};\n}\n\n// Precompute 2x2 square weights and heavy order\nstatic void compute_square_weights(int N, const vector<vector<int>>& h,\n                                   vector<int>& order, vector<int>& weight)\n{\n    int S = (N-1)*(N-1);\n    order.resize(S);\n    weight.resize(S);\n    vector<pair<int,int>> vec; vec.reserve(S);\n    for(int x=0;x<N-1;x++){\n        for(int y=0;y<N-1;y++){\n            long long w = 0;\n            w += llabs((long long)h[x][y]);\n            w += llabs((long long)h[x][y+1]);\n            w += llabs((long long)h[x+1][y+1]);\n            w += llabs((long long)h[x+1][y]);\n            int id = x*(N-1)+y;\n            weight[id] = (int)w;\n            vec.emplace_back((int)w, id);\n        }\n    }\n    sort(vec.begin(), vec.end(), [&](const auto& a, const auto& b){\n        if(a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n    for(int i=0;i<S;i++) order[i] = vec[i].second;\n}\n\n// Local improvement on a cycle path with a time budget (deterministic + SA randomized)\nstatic pair<long long, vector<pair<int,int>>> local_improve(\n    const vector<pair<int,int>>& initPath,\n    int N, const vector<vector<int>>& h, long long base,\n    RNG& rng,\n    const chrono::steady_clock::time_point& t0,\n    double budgetMs,\n    double timeLimitMs,\n    const vector<int>& sqOrder,\n    const vector<int>& sqWeight)\n{\n    auto elapsedMs = [&](){ return chrono::duration<double, milli>(chrono::steady_clock::now() - t0).count(); };\n    double startMs = elapsedMs();\n    double endMs = min(startMs + budgetMs, timeLimitMs * 0.95);\n\n    auto nb = nb_from_path(initPath, N);\n\n    auto rebuild_and_eval = [&](vector<array<int,2>>& nbCur)->pair<long long, vector<pair<int,int>>>{\n        auto path2 = path_from_nb(nbCur, N);\n        if(path2.empty()){\n            return { (1LL<<62), {} };\n        }\n        auto [costF, sF] = eval_directed_path(path2, h, base);\n        auto pr = path2;\n        reverse(pr.begin(), pr.end());\n        auto [costR, sR] = eval_directed_path(pr, h, base);\n        if(costF <= costR) return {costF, path2};\n        else return {costR, pr};\n    };\n\n    auto [curCost, curPath] = rebuild_and_eval(nb);\n    if(curPath.empty()){\n        curPath = initPath;\n        curCost = eval_directed_path(curPath, h, base).first;\n    }\n    long long bestCost = curCost;\n    vector<pair<int,int>> bestPath = curPath;\n    vector<array<int,2>> bestNb = nb;\n\n    // Deterministic passes: heavy squares first\n    int passes = 0;\n    while(passes < 2 && elapsedMs() < endMs){\n        bool improved = false;\n        for(int id : sqOrder){\n            if(elapsedMs() > endMs) break;\n            int x = id / (N-1);\n            int y = id % (N-1);\n            if(try_flip_square(nb, N, x, y)){\n                auto [newCost, newPath] = rebuild_and_eval(nb);\n                if(newCost < curCost){\n                    curCost = newCost;\n                    curPath.swap(newPath);\n                    improved = true;\n                    if(curCost < bestCost){\n                        bestCost = curCost;\n                        bestPath = curPath;\n                        bestNb = nb;\n                    }\n                }else{\n                    try_flip_square(nb, N, x, y);\n                }\n            }\n        }\n        if(!improved) break;\n        passes++;\n    }\n\n    // Randomized SA flips with heavy-bias sampling, occasionally pair flips\n    {\n        WeightedSampler sampler(sqWeight);\n        double T0 = 4000.0, Tend = 1.5;\n        int attempts = 0;\n        int maxAttempts = 50000;\n        while(elapsedMs() < endMs && attempts < maxAttempts){\n            attempts++;\n            int id;\n            if(rng.rand01() < 0.7){\n                int idx = sampler.sample(rng);\n                id = idx;\n            }else{\n                id = rng.randint(0, (N-1)*(N-1)-1);\n            }\n            int x = id / (N-1);\n            int y = id % (N-1);\n\n            bool twoFlip = (rng.rand01() < 0.2);\n            if(!twoFlip){\n                if(try_flip_square(nb, N, x, y)){\n                    auto [newCost, newPath] = rebuild_and_eval(nb);\n                    long long delta = newCost - curCost;\n                    double frac = (elapsedMs() - startMs) / max(1e-9, (endMs - startMs));\n                    if(frac < 0) frac = 0; if(frac > 1) frac = 1;\n                    double T = T0 * pow(Tend / T0, frac);\n                    bool accept = (delta <= 0) || (rng.rand01() < exp(-(double)delta / max(1.0, T)));\n                    if(accept){\n                        curCost = newCost;\n                        curPath.swap(newPath);\n                        if(curCost < bestCost){\n                            bestCost = curCost;\n                            bestPath = curPath;\n                            bestNb = nb;\n                        }\n                    }else{\n                        try_flip_square(nb, N, x, y);\n                    }\n                }\n            }else{\n                // choose neighbor square\n                static const int dx[4] = {1,0,-1,0};\n                static const int dy[4] = {0,1,0,-1};\n                int dir = rng.randint(0,3);\n                int nx = x + dx[dir];\n                int ny = y + dy[dir];\n                if(0 <= nx && nx < N-1 && 0 <= ny && ny < N-1){\n                    bool f1 = try_flip_square(nb, N, x, y);\n                    bool f2 = try_flip_square(nb, N, nx, ny);\n                    if(f1 || f2){\n                        auto [newCost, newPath] = rebuild_and_eval(nb);\n                        long long delta = newCost - curCost;\n                        double frac = (elapsedMs() - startMs) / max(1e-9, (endMs - startMs));\n                        if(frac < 0) frac = 0; if(frac > 1) frac = 1;\n                        double T = T0 * pow(Tend / T0, frac);\n                        bool accept = (delta <= 0) || (rng.rand01() < exp(-(double)delta / max(1.0, T)));\n                        if(accept){\n                            curCost = newCost;\n                            curPath.swap(newPath);\n                            if(curCost < bestCost){\n                                bestCost = curCost;\n                                bestPath = curPath;\n                                bestNb = nb;\n                            }\n                        }else{\n                            // revert flips\n                            if(f2) try_flip_square(nb, N, nx, ny);\n                            if(f1) try_flip_square(nb, N, x, y);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Final quick deterministic sweep on heavy squares if time remains\n    if(elapsedMs() < endMs){\n        for(int id : sqOrder){\n            if(elapsedMs() > endMs) break;\n            int x = id / (N-1);\n            int y = id % (N-1);\n            if(try_flip_square(nb, N, x, y)){\n                auto [newCost, newPath] = rebuild_and_eval(nb);\n                if(newCost < bestCost){\n                    bestCost = newCost;\n                    bestPath = newPath;\n                    bestNb = nb;\n                }else{\n                    try_flip_square(nb, N, x, y);\n                }\n            }\n        }\n    }\n\n    return {bestCost, bestPath};\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto t0 = chrono::steady_clock::now();\n    const double TIME_LIMIT_MS = 1950.0;\n\n    int N;\n    if(!(cin>>N)) return 0;\n    vector<vector<int>> h(N, vector<int>(N));\n    long long base = 0;\n    uint64_t seedMix = 1469598103934665603ULL;\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            cin>>h[i][j];\n            base += llabs((long long)h[i][j]);\n            uint64_t v = (uint64_t)(h[i][j] + 100);\n            seedMix ^= v + 0x9e3779b97f4a7c15ULL + (seedMix<<6) + (seedMix>>2);\n        }\n    }\n    RNG rng(seedMix ^ (uint64_t)N * 0x9e3779b97f4a7c15ULL);\n\n    auto elapsedMs = [&](){ return chrono::duration<double, milli>(chrono::steady_clock::now() - t0).count(); };\n\n    // Precompute square weight order and weights\n    vector<int> sqOrder, sqWeight;\n    compute_square_weights(N, h, sqOrder, sqWeight);\n\n    // Time budget split\n    double anchorBudgetMs = TIME_LIMIT_MS * 0.45;\n\n    // Greedy optimize cycles using both schemes within time budget\n    CycleCandidate candA = optimize_scheme_A(N, h, base, rng, t0, anchorBudgetMs);\n    CycleCandidate candB = optimize_scheme_B(N, h, base, rng, t0, anchorBudgetMs);\n\n    // If both empty, fallback\n    if(candA.path.empty() && candB.path.empty()){\n        CycleBuilder cb(N);\n        vector<int> anc(max(N/2-1,0), 0);\n        auto cyc = cb.build_scheme_A(anc);\n        vector<pair<int,int>> path;\n        if(cyc.empty()){\n            for(int i=0;i<N;i++){\n                if(i%2==0) for(int j=0;j<N;j++) path.emplace_back(i,j);\n                else for(int j=N-1;j>=0;j--) path.emplace_back(i,j);\n            }\n            long long cost = eval_directed_path(path, h, base).first;\n            candA = {path, anc, 'A', cost};\n        }else{\n            auto ev = eval_cycle_any_orientation(cyc, h, base, N);\n            path = rotate_path(cyc, N, ev.rot);\n            if(ev.reversed) reverse(path.begin(), path.end());\n            candA = {path, anc, 'A', ev.cost};\n        }\n    }\n\n    // Anchor SA budgets\n    double timeUsed = elapsedMs();\n    double anchorSaBudget = max(0.0, TIME_LIMIT_MS * 0.60 - timeUsed); // leave ~40% for flips\n    anchorSaBudget = min(anchorSaBudget, max(0.0, TIME_LIMIT_MS * 0.75 - timeUsed)); // safety\n\n    if(anchorSaBudget > 4.0){\n        double budgetA = 0.0, budgetB = 0.0;\n        if(!candA.path.empty() && !candB.path.empty()){\n            if(candA.cost <= candB.cost){\n                budgetA = anchorSaBudget * 0.60;\n                budgetB = anchorSaBudget * 0.40;\n            }else{\n                budgetA = anchorSaBudget * 0.40;\n                budgetB = anchorSaBudget * 0.60;\n            }\n        }else if(!candA.path.empty()){\n            budgetA = anchorSaBudget;\n        }else if(!candB.path.empty()){\n            budgetB = anchorSaBudget;\n        }\n        if(budgetA > 1.0 && !candA.path.empty()){\n            auto impA = anchor_sa(candA, N, h, base, rng, t0, budgetA, TIME_LIMIT_MS);\n            if(impA.cost < candA.cost) candA = impA;\n        }\n        if(budgetB > 1.0 && !candB.path.empty()){\n            auto impB = anchor_sa(candB, N, h, base, rng, t0, budgetB, TIME_LIMIT_MS);\n            if(impB.cost < candB.cost) candB = impB;\n        }\n    }\n\n    // Choose best candidate\n    CycleCandidate bestCand = (candB.path.empty() || (!candA.path.empty() && candA.cost <= candB.cost)) ? candA : candB;\n    CycleCandidate secondCand = (bestCand.path == candA.path ? candB : candA);\n\n    // Local improvement budgets\n    timeUsed = elapsedMs();\n    double localBudgetTotal = max(0.0, TIME_LIMIT_MS * 0.92 - timeUsed);\n    vector<pair<int,int>> finalPath = bestCand.path;\n    long long finalCost = bestCand.cost;\n\n    if(localBudgetTotal > 5.0){\n        double budgetBest = localBudgetTotal * 0.65;\n        double budgetSecond = localBudgetTotal * 0.35;\n        if(secondCand.path.empty()) { budgetBest = localBudgetTotal; budgetSecond = 0; }\n\n        if(budgetBest > 1.0){\n            auto [c1, p1] = local_improve(bestCand.path, N, h, base, rng, t0, budgetBest, TIME_LIMIT_MS, sqOrder, sqWeight);\n            if(c1 < finalCost){ finalCost = c1; finalPath = p1; }\n        }\n        if(budgetSecond > 1.0 && !secondCand.path.empty()){\n            auto [c2, p2] = local_improve(secondCand.path, N, h, base, rng, t0, budgetSecond, TIME_LIMIT_MS, sqOrder, sqWeight);\n            if(c2 < finalCost){ finalCost = c2; finalPath = p2; }\n        }\n    }\n\n    // Final small polish if time remains\n    double rem = TIME_LIMIT_MS * 0.95 - elapsedMs();\n    if(rem > 5.0){\n        auto [cFin, pFin] = local_improve(finalPath, N, h, base, rng, t0, rem, TIME_LIMIT_MS, sqOrder, sqWeight);\n        if(cFin < finalCost){ finalCost = cFin; finalPath = pFin; }\n    }\n\n    // Compute best start index on final oriented path (safety)\n    auto [__, startIdx] = eval_directed_path(finalPath, h, base);\n    int M = N*N;\n\n    // Emit operations\n    vector<string> ops;\n    ops.reserve(M*3 + 200);\n\n    int cx = 0, cy = 0;\n    long long load = 0;\n\n    auto move_to = [&](int tx, int ty){\n        while(cy < ty){ ops.emplace_back(\"R\"); cy++; }\n        while(cy > ty){ ops.emplace_back(\"L\"); cy--; }\n        while(cx < tx){ ops.emplace_back(\"D\"); cx++; }\n        while(cx > tx){ ops.emplace_back(\"U\"); cx--; }\n    };\n\n    // Reposition to start\n    int sx = finalPath[startIdx].first, sy = finalPath[startIdx].second;\n    move_to(sx, sy);\n\n    // Traverse along the cycle from the chosen start\n    for(int t=0;t<M;t++){\n        int idx = (startIdx + t) % M;\n        int x = finalPath[idx].first, y = finalPath[idx].second;\n        int val = h[x][y];\n        if(val > 0){\n            ops.emplace_back(\"+\" + to_string(val));\n            load += val;\n            h[x][y] = 0;\n        }else if(val < 0){\n            int need = -val;\n            long long give = min<long long>(need, load);\n            if(give > 0){\n                ops.emplace_back(\"-\" + to_string(give));\n                load -= give;\n                h[x][y] += (int)give;\n            }\n        }\n        if(t != M-1){\n            int nx = finalPath[(idx+1)%M].first, ny = finalPath[(idx+1)%M].second;\n            if(nx == x){\n                if(ny == y+1){ ops.emplace_back(\"R\"); cy++; }\n                else if(ny == y-1){ ops.emplace_back(\"L\"); cy--; }\n                else { move_to(nx, ny); }\n            }else if(ny == y){\n                if(nx == x+1){ ops.emplace_back(\"D\"); cx++; }\n                else if(nx == x-1){ ops.emplace_back(\"U\"); cx--; }\n                else { move_to(nx, ny); }\n            }else{\n                move_to(nx, ny);\n            }\n        }\n    }\n\n    for(const auto& s : ops) cout << s << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\n// AHC035 \"Grain\" heuristic with:\n// - Two-anchor alternatives and position variants,\n// - Per-restart selection,\n// - Hybrid edge softmax (quantile and sum-of-max),\n// - Adaptive softmax sharpness (beta) per restart from empirical stddev,\n// - Pairwise precomputation for fast local search,\n// - Biased local search towards the current strongest edge to accelerate convergence.\n\nstruct RNG {\n    uint64_t x;\n    RNG() {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        x = seed ^ (seed << 13);\n    }\n    inline uint32_t next_u32() {\n        uint64_t y = x;\n        y ^= (y << 7);\n        y ^= (y >> 9);\n        x = y;\n        return (uint32_t)(y & 0xffffffffu);\n    }\n    inline int randint(int lo, int hi) { // inclusive\n        uint32_t r = next_u32();\n        return lo + (int)(r % (uint32_t)(hi - lo + 1));\n    }\n    inline double rand01() { return (next_u32() / 4294967296.0); }\n};\n\nstruct Params {\n    // Node term\n    double wV, wRare, wCnt, wMissNode;\n    // Pair spread scaling (expected carriers): pairSpread = pairFactor * (both + 0.5*one)\n    double pairFactor;\n    // Quantile softmax base params (beta is adapted): q = mean + alpha * sigma, muQ * log(sum exp(betaQ*q))\n    double alpha, betaQ, muQ;\n    // Sum-of-max softmax base params (beta is adapted): muM * log(sum exp(betaM*smax))\n    double betaM, muM;\n    // Anchor selection scoring\n    double anchQuant, anchBoth, anchOne, anchV;\n    // Iterations per restart\n    int iters;\n    // Base target coverage per dimension\n    int baseTarget;\n    // Forced count of top-V seeds\n    int forceTopV;\n};\n\nstruct RestartPlan { int confIdx; int posVar; int lockMode; };\n// lockMode: 2=lock both anchor pairs; 1=lock first pair only; 0=unlock; -1=no anchors\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    if (!(cin >> N >> M >> T)) return 0;\n    const int SEED_COUNT = 2 * N * (N - 1); // 60 for N=6\n\n    vector<vector<int>> X(SEED_COUNT, vector<int>(M));\n    for (int i = 0; i < SEED_COUNT; i++)\n        for (int j = 0; j < M; j++) cin >> X[i][j];\n\n    // Xmax per dimension\n    vector<int> Xmax(M, 0);\n    for (int l = 0; l < M; l++) {\n        int mx = 0;\n        for (int k = 0; k < SEED_COUNT; k++) mx = max(mx, X[k][l]);\n        Xmax[l] = mx;\n    }\n\n    // Grid topology\n    auto pos_id = [&](int i, int j){ return i * N + j; };\n    vector<vector<int>> neighbors(N*N);\n    vector<int> deg(N*N, 0);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int u = pos_id(i,j);\n        if (i > 0)   neighbors[u].push_back(pos_id(i-1,j));\n        if (i+1 < N) neighbors[u].push_back(pos_id(i+1,j));\n        if (j > 0)   neighbors[u].push_back(pos_id(i,j-1));\n        if (j+1 < N) neighbors[u].push_back(pos_id(i,j+1));\n        deg[u] = (int)neighbors[u].size();\n    }\n    // Undirected edges\n    vector<pair<int,int>> edges;\n    for (int u = 0; u < N*N; u++) for (int v: neighbors[u]) if (u < v) edges.emplace_back(u, v);\n    const int E = (int)edges.size(); // 60\n    // Edge indices per position\n    vector<vector<int>> edgeIdxByPos(N*N);\n    for (int ei = 0; ei < E; ei++) {\n        auto [u,v] = edges[ei];\n        edgeIdxByPos[u].push_back(ei);\n        edgeIdxByPos[v].push_back(ei);\n    }\n\n    // Position order: degree desc, center proximity asc\n    vector<int> posOrder(N*N);\n    iota(posOrder.begin(), posOrder.end(), 0);\n    const double ci = (N-1)/2.0, cj = (N-1)/2.0;\n    sort(posOrder.begin(), posOrder.end(), [&](int a, int b){\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        int ai = a / N, aj = a % N;\n        int bi = b / N, bj = b % N;\n        double da = fabs(ai - ci) + fabs(aj - cj);\n        double db = fabs(bi - ci) + fabs(bj - cj);\n        if (da != db) return da < db;\n        return a < b;\n    });\n\n    // Central anchor position variants\n    // Two central horizontal edges (disjoint)\n    int i1 = N/2 - 1, j1 = N/2 - 1;\n    int i2 = N/2,     j2 = N/2 - 1;\n    int H1Apos = pos_id(i1, j1);\n    int H1Bpos = pos_id(i1, j1 + 1);\n    int H2Apos = pos_id(i2, j2);\n    int H2Bpos = pos_id(i2, j2 + 1);\n    // Two central vertical edges (disjoint)\n    int V1Apos = pos_id(i1, j1);\n    int V1Bpos = pos_id(i1 + 1, j1);\n    int V2Apos = pos_id(i1, j1 + 1);\n    int V2Bpos = pos_id(i1 + 1, j1 + 1);\n\n    RNG rng;\n\n    auto paramsForTurn = [&](int t)->Params{\n        if (t <= 3) {\n            return Params{\n                // Node\n                0.16, 10.0, 9.0, 8.5,\n                // Pair spread scaling\n                240.0,\n                // Quantile softmax\n                1.8, 0.0050, 3000.0,\n                // Sum-of-max softmax\n                0.0045, 1200.0,\n                // Anchor selection\n                1.0, 9.0, 3.5, 0.001,\n                // iters/restart\n                18000,\n                // base coverage\n                3,\n                // force top-V\n                4\n            };\n        } else if (t <= 6) {\n            return Params{\n                0.18, 9.0, 8.0, 6.0,\n                210.0,\n                2.2, 0.0052, 3400.0,\n                0.0049, 1500.0,\n                1.0, 9.0, 3.0, 0.0015,\n                17000,\n                2,\n                5\n            };\n        } else if (t <= 8) {\n            return Params{\n                0.20, 8.0, 7.0, 5.0,\n                180.0,\n                2.6, 0.0058, 3800.0,\n                0.0052, 1800.0,\n                1.0, 9.0, 2.5, 0.0020,\n                16000,\n                2,\n                6\n            };\n        } else {\n            return Params{\n                0.24, 6.0, 5.0, 1.5,\n                150.0,\n                3.2, 0.0065, 5000.0,\n                0.0058, 2200.0,\n                1.0, 10.0, 2.0, 0.0030,\n                15000,\n                1,\n                8\n            };\n        }\n    };\n\n    auto clampd = [&](double x, double lo, double hi){ return x < lo ? lo : (x > hi ? hi : x); };\n\n    auto pBiasForTurn = [&](int t)->double{\n        if (t <= 3) return 0.5;\n        if (t <= 6) return 0.6;\n        if (t <= 8) return 0.65;\n        return 0.7;\n    };\n\n    for (int t = 0; t < T; t++) {\n        auto P = paramsForTurn(t);\n\n        // V and carriers\n        vector<int> V(SEED_COUNT, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            int s = 0; for (int l = 0; l < M; l++) s += X[k][l];\n            V[k] = s;\n        }\n        vector<uint16_t> bits(SEED_COUNT, 0);\n        vector<int> cnt(M, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            uint16_t m = 0;\n            for (int l = 0; l < M; l++) if (X[k][l] == Xmax[l]) m |= (1u << l);\n            bits[k] = m;\n            for (int l = 0; l < M; l++) if ((m >> l) & 1u) cnt[l]++;\n        }\n        uint16_t dimsAvail = 0;\n        for (int l = 0; l < M; l++) if (cnt[l] > 0) dimsAvail |= (1u << l);\n\n        // Rarity weights: Xmax[l] / cnt[l]\n        vector<double> wdim(M, 0.0);\n        for (int l = 0; l < M; l++) wdim[l] = (cnt[l] ? (double)Xmax[l] / (double)cnt[l] : 0.0);\n\n        // sumW over masks\n        int MASKSZ = 1 << M;\n        vector<double> sumW(MASKSZ, 0.0);\n        for (int m = 1; m < MASKSZ; m++) {\n            int lb = __builtin_ctz(m);\n            int prev = m & (m - 1);\n            sumW[m] = sumW[prev] + wdim[lb];\n        }\n\n        vector<double> rareSum(SEED_COUNT, 0.0);\n        vector<int> carrierCnt(SEED_COUNT, 0);\n        for (int k = 0; k < SEED_COUNT; k++) {\n            rareSum[k] = sumW[bits[k]];\n            carrierCnt[k] = __builtin_popcount((unsigned)bits[k]);\n        }\n\n        // Precompute pairwise stats per turn\n        static float pairMean[64][64], pairSigma[64][64], pairSMax[64][64];\n        static double pairSpreadVal[64][64];\n        for (int a = 0; a < SEED_COUNT; a++) {\n            pairMean[a][a] = 0.5f * V[a];\n            pairSigma[a][a] = 0.0f;\n            pairSMax[a][a] = (float)V[a];\n            pairSpreadVal[a][a] = P.pairFactor * (rareSum[a]); // both-only\n            for (int b = a + 1; b < SEED_COUNT; b++) {\n                float mean = 0.5f * (V[a] + V[b]);\n                double s2 = 0.0;\n                int smax = 0;\n                const auto &xa = X[a], &xb = X[b];\n                for (int l = 0; l < M; l++) {\n                    int aa = xa[l], bb = xb[l];\n                    int d = aa - bb;\n                    s2 += (double)d * (double)d;\n                    smax += (aa > bb ? aa : bb);\n                }\n                float sigma = 0.5f * (float)sqrt(max(0.0, s2));\n                pairMean[a][b] = pairMean[b][a] = mean;\n                pairSigma[a][b] = pairSigma[b][a] = sigma;\n                pairSMax[a][b] = pairSMax[b][a] = (float)smax;\n\n                double both = sumW[bits[a] & bits[b]];\n                double one  = sumW[bits[a] ^ bits[b]];\n                double spread = P.pairFactor * (both + 0.5 * one);\n                pairSpreadVal[a][b] = pairSpreadVal[b][a] = spread;\n            }\n        }\n\n        auto edgeQuant = [&](int a, int b)->double{\n            return (double)pairMean[a][b] + P.alpha * (double)pairSigma[a][b];\n        };\n        auto edgeSMax = [&](int a, int b)->double{\n            return (double)pairSMax[a][b];\n        };\n        auto pairSpread = [&](int a, int b)->double{\n            return pairSpreadVal[a][b];\n        };\n\n        // Build top-K anchor1 candidates\n        struct PairSc { double sc; int a, b; };\n        vector<PairSc> cand1;\n        cand1.reserve(SEED_COUNT * (SEED_COUNT-1) / 2);\n        for (int a = 0; a < SEED_COUNT; a++) {\n            for (int b = a + 1; b < SEED_COUNT; b++) {\n                double q = edgeQuant(a,b);\n                double sboth = sumW[bits[a] & bits[b]];\n                double sone  = sumW[bits[a] ^ bits[b]];\n                double sc = P.anchQuant * q + P.anchBoth * sboth + P.anchOne * sone + P.anchV * (V[a] + V[b]);\n                sc += (rng.rand01() - 0.5) * 1e-6;\n                cand1.push_back({sc, a, b});\n            }\n        }\n        sort(cand1.begin(), cand1.end(), [&](const PairSc& x, const PairSc& y){ return x.sc > y.sc; });\n        int K1 = min<int>(3, cand1.size());\n\n        // Build up to 2 anchor configurations ((a1,b1),(a2,b2))\n        struct AnchConf { int a1, b1, a2, b2; };\n        vector<AnchConf> anchConfs;\n        anchConfs.reserve(2);\n        for (int c = 0; c < K1 && (int)anchConfs.size() < 2; c++) {\n            int a1 = cand1[c].a, b1 = cand1[c].b;\n            int bestA2 = -1, bestB2 = -1; double bestSc2 = -1e100;\n            for (int d = 0; d < (int)cand1.size(); d++) {\n                int a2 = cand1[d].a, b2 = cand1[d].b;\n                if (a2==a1 || a2==b1 || b2==a1 || b2==b1) continue;\n                if (cand1[d].sc > bestSc2) { bestSc2 = cand1[d].sc; bestA2=a2; bestB2=b2; }\n            }\n            if (bestA2 == -1) {\n                for (int a = 0; a < SEED_COUNT && bestA2==-1; a++) if (a!=a1 && a!=b1)\n                    for (int b = a+1; b < SEED_COUNT; b++) if (b!=a1 && b!=b1) { bestA2=a; bestB2=b; break; }\n            }\n            if (bestA2 != -1) anchConfs.push_back({a1,b1,bestA2,bestB2});\n        }\n        if (anchConfs.empty()) {\n            int a1 = cand1[0].a, b1 = cand1[0].b;\n            int a2=-1,b2=-1;\n            for (int a = 0; a < SEED_COUNT && a2==-1; a++) if (a!=a1 && a!=b1)\n                for (int b = a+1; b < SEED_COUNT; b++) if (b!=a1 && b!=b1) { a2=a; b2=b; break; }\n            if (a2==-1){ a2=a1; b2=b1; }\n            anchConfs.push_back({a1,b1,a2,b2});\n        }\n\n        // Position variants: 0=HH, 1=VV\n        vector<vector<pair<int,int>>> posVariants;\n        posVariants.push_back({{H1Apos,H1Bpos},{H2Apos,H2Bpos}});\n        posVariants.push_back({{V1Apos,V1Bpos},{V2Apos,V2Bpos}});\n\n        // Restart plans (per-restart selection)\n        vector<RestartPlan> plans;\n        plans.push_back({0, 0, 2}); // HH lock both\n        plans.push_back({0, 0, 1}); // HH lock first\n        plans.push_back({0, 1, 2}); // VV lock both\n        if ((int)anchConfs.size() >= 2) plans.push_back({1, 0, 2}); // second config HH lock both\n        plans.push_back({0, 0, 0}); // HH unlock\n        plans.push_back({0, -1, -1}); // no anchors\n\n        // Helper: selection per restart\n        auto selectSeeds = [&](const vector<int>& anchorSeeds)->vector<int>{\n            vector<int> selected;\n            selected.reserve(N*N);\n            vector<char> used(SEED_COUNT, 0);\n            auto include = [&](int k){ if (!used[k]) { used[k] = 1; selected.push_back(k); } };\n            // include anchors\n            for (int k : anchorSeeds) include(k);\n            // ensure one carrier per dimension\n            for (int l = 0; l < M; l++) {\n                if (cnt[l] == 0) continue;\n                int best = -1, bestV = -1;\n                for (int k = 0; k < SEED_COUNT; k++) if (!used[k] && ((bits[k] >> l) & 1u)) {\n                    if (V[k] > bestV) bestV = V[k], best = k;\n                }\n                if (best != -1 && (int)selected.size() < N*N) include(best);\n            }\n            // force top-V\n            vector<int> ordV(SEED_COUNT);\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            int forcedTop = 0;\n            for (int k : ordV) {\n                if (forcedTop >= P.forceTopV) break;\n                if (!used[k]) { include(k); forcedTop++; }\n            }\n            // dynamic coverage targets\n            vector<int> targetCov(M, P.baseTarget);\n            for (int l = 0; l < M; l++) {\n                if (cnt[l] <= 2) targetCov[l] = min(P.baseTarget + 2, 5);\n                else if (cnt[l] <= 4) targetCov[l] = min(P.baseTarget + 1, 4);\n            }\n            vector<int> cov(M, 0);\n            for (int k : selected) for (int l = 0; l < M; l++) if ((bits[k] >> l) & 1u) cov[l]++;\n            auto needWeight = [&](int l)->double{\n                if (cnt[l] == 0) return 0.0;\n                int need = max(0, targetCov[l] - cov[l]);\n                if (need <= 0) return 0.0;\n                return (double)need * (1.0 + 2.5 * ((double)Xmax[l] / max(1, cnt[l])));\n            };\n            // forced mask from anchorSeeds only\n            uint16_t forcedMask = 0;\n            for (int k : anchorSeeds) forcedMask |= bits[k];\n            uint16_t missForced = (uint16_t)(dimsAvail & (~forcedMask));\n            // greedy fill\n            while ((int)selected.size() < N*N) {\n                int bestK = -1; double bestSc = -1e100;\n                for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) {\n                    double covGain = 0.0;\n                    for (int l = 0; l < M; l++) if ((bits[k] >> l) & 1u) covGain += needWeight(l);\n                    double missGain = sumW[bits[k] & missForced];\n                    double sc = 0.012 * V[k] + covGain + 80.0 * missGain;\n                    if (sc > bestSc) bestSc = sc, bestK = k;\n                }\n                if (bestK == -1) break;\n                include(bestK);\n                for (int l = 0; l < M; l++) if ((bits[bestK] >> l) & 1u) cov[l]++;\n            }\n            if ((int)selected.size() < N*N) {\n                vector<int> rest;\n                for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) rest.push_back(k);\n                sort(rest.begin(), rest.end(), [&](int a, int b){\n                    if (V[a] != V[b]) return V[a] > V[b];\n                    return a < b;\n                });\n                for (int k : rest) { if ((int)selected.size() >= N*N) break; include(k); }\n            }\n            return selected;\n        };\n\n        // Initial assignment builder for a given mode\n        auto build_initial_assignment = [&](int posVar,\n                                            const vector<int>& anchors, // [a1,b1,a2,b2] or empty\n                                            const vector<pair<int,int>>& posPairs,\n                                            const vector<int>& selected,\n                                            const vector<double>& nodeWeight)->vector<int>{\n            vector<int> assignPos(N*N, -1);\n            vector<char> usedSeed(SEED_COUNT, 0);\n            auto noise = [&](double amp){ return (rng.rand01() - 0.5) * amp; };\n\n            if (posVar == -1) {\n                // no anchors: simple ranking\n                vector<pair<double,int>> ord;\n                for (int k : selected) ord.emplace_back(nodeWeight[k] + noise(0.05), k);\n                sort(ord.begin(), ord.end(), greater<>());\n                int idx = 0;\n                for (int pos : posOrder) assignPos[pos] = ord[idx++].second;\n            } else {\n                // place anchors: anchors.size() == 4 ideally\n                if (!anchors.empty() && (int)posPairs.size() >= 2 && (int)anchors.size() >= 4) {\n                    // pair 0\n                    assignPos[posPairs[0].first] = anchors[0]; usedSeed[anchors[0]] = 1;\n                    assignPos[posPairs[0].second] = anchors[1]; usedSeed[anchors[1]] = 1;\n                    // pair 1\n                    assignPos[posPairs[1].first] = anchors[2]; usedSeed[anchors[2]] = 1;\n                    assignPos[posPairs[1].second] = anchors[3]; usedSeed[anchors[3]] = 1;\n\n                    auto neighExcluding = [&](int pos, int excl){\n                        vector<int> v; v.reserve(3);\n                        for (int nb : neighbors[pos]) if (nb != excl) v.push_back(nb);\n                        return v;\n                    };\n                    auto endpointMiss = [&](int seed)->uint16_t{\n                        return (uint16_t)(dimsAvail & (~bits[seed]));\n                    };\n\n                    for (int i = 0; i < 2; i++) {\n                        int seedA = anchors[2*i], seedB = anchors[2*i+1];\n                        int posA = posPairs[i].first, posB = posPairs[i].second;\n                        uint16_t missA = endpointMiss(seedA);\n                        uint16_t missB = endpointMiss(seedB);\n                        vector<int> neighA = neighExcluding(posA, posB);\n                        vector<int> neighB = neighExcluding(posB, posA);\n\n                        auto scoreForMask = [&](int k, uint16_t miss)->double{\n                            return 300.0 * sumW[bits[k] & miss] + 0.05 * V[k] + 10.0 * rareSum[k] + (rng.rand01()-0.5)*0.01;\n                        };\n\n                        auto assign_neigh = [&](const vector<int>& neigh, uint16_t miss){\n                            vector<pair<double,int>> cand;\n                            for (int k : selected) if (!usedSeed[k]) cand.emplace_back(scoreForMask(k, miss), k);\n                            sort(cand.begin(), cand.end(), greater<>());\n                            for (int p : neigh) {\n                                if (assignPos[p] != -1) continue;\n                                int chosen = -1;\n                                for (auto &pr : cand) {\n                                    int k = pr.second;\n                                    if (!usedSeed[k]) { chosen = k; break; }\n                                }\n                                if (chosen != -1) { assignPos[p] = chosen; usedSeed[chosen] = 1; }\n                            }\n                        };\n                        assign_neigh(neighA, missA);\n                        assign_neigh(neighB, missB);\n                    }\n                }\n                // Fill remaining by nodeWeight ranking\n                vector<pair<double,int>> ord;\n                for (int k : selected) if (!usedSeed[k]) ord.emplace_back(nodeWeight[k] + noise(0.05), k);\n                sort(ord.begin(), ord.end(), greater<>());\n                for (int pos : posOrder) if (assignPos[pos] == -1) {\n                    if (!ord.empty()) {\n                        int k = ord.back().second; ord.pop_back();\n                        assignPos[pos] = k; usedSeed[k] = 1;\n                    }\n                }\n            }\n            // Safety fill\n            for (int pos = 0; pos < N*N; pos++) if (assignPos[pos] == -1) {\n                for (int k : selected) if (!usedSeed[k]) { assignPos[pos] = k; usedSeed[k] = 1; break; }\n            }\n            return assignPos;\n        };\n\n        auto totalObjective = [&](const vector<int>& assignPos,\n                                  double sumExpQ, double sumExpM,\n                                  const vector<double>& nodeWeight)->double{\n            double nodeTerm = 0.0;\n            for (int p = 0; p < N*N; p++) nodeTerm += deg[p] * nodeWeight[assignPos[p]];\n            double pairTerm = 0.0;\n            for (auto &e : edges) {\n                int a = assignPos[e.first], b = assignPos[e.second];\n                pairTerm += pairSpread(a, b);\n            }\n            double softQ = P.muQ * log(max(1e-300, sumExpQ));\n            double softM = P.muM * log(max(1e-300, sumExpM));\n            return nodeTerm + pairTerm + softQ + softM;\n        };\n\n        double bestObj = -1e100;\n        vector<int> bestAssign;\n\n        for (const RestartPlan &pl : plans) {\n            vector<int> anchorSeeds;\n            vector<pair<int,int>> posPairs;\n            if (pl.lockMode != -1) {\n                auto &ac = anchConfs[min(pl.confIdx, (int)anchConfs.size()-1)];\n                anchorSeeds = {ac.a1, ac.b1, ac.a2, ac.b2};\n                if (pl.posVar == 0) posPairs = {{H1Apos,H1Bpos},{H2Apos,H2Bpos}};\n                else posPairs = {{V1Apos,V1Bpos},{V2Apos,V2Bpos}};\n            }\n\n            // Selection for this restart\n            vector<int> selected = selectSeeds(anchorSeeds);\n\n            // Compute nodeWeight for this restart (missing genes relative to anchorSeeds union)\n            uint16_t forcedMask = 0;\n            for (int k : anchorSeeds) forcedMask |= bits[k];\n            uint16_t missForced = (uint16_t)(dimsAvail & (~forcedMask));\n            vector<double> nodeWeight(SEED_COUNT, 0.0);\n            for (int k = 0; k < SEED_COUNT; k++) {\n                nodeWeight[k] = P.wV * V[k] + P.wRare * rareSum[k] + P.wCnt * carrierCnt[k]\n                              + P.wMissNode * sumW[bits[k] & missForced];\n            }\n\n            // Adaptive betas from selected pairs\n            auto compute_sd = [&](bool useQuant)->double{\n                int n = (int)selected.size();\n                if (n <= 1) return 1.0;\n                double sum = 0.0, sum2 = 0.0;\n                long long cntPairs = 0;\n                for (int i = 0; i < n; i++) {\n                    int a = selected[i];\n                    for (int j = i+1; j < n; j++) {\n                        int b = selected[j];\n                        double val = useQuant ? ((double)pairMean[a][b] + P.alpha * (double)pairSigma[a][b])\n                                              : (double)pairSMax[a][b];\n                        sum += val;\n                        sum2 += val * val;\n                        cntPairs++;\n                    }\n                }\n                if (cntPairs == 0) return 1.0;\n                double mean = sum / (double)cntPairs;\n                double var = max(0.0, sum2 / (double)cntPairs - mean * mean);\n                double sd = sqrt(var);\n                return sd > 1e-9 ? sd : 1.0;\n            };\n            double sdQ = compute_sd(true);\n            double sdM = compute_sd(false);\n            double betaQ = clampd(4.0 / sdQ, 1e-4, 2e-2);\n            double betaM = clampd(4.0 / sdM, 1e-4, 2e-2);\n\n            // Build initial assignment\n            int posVar = (pl.lockMode == -1 ? -1 : pl.posVar);\n            vector<int> assignPos = build_initial_assignment(posVar, anchorSeeds, posPairs, selected, nodeWeight);\n\n            // Prepare edge exponent arrays for both softmax terms\n            vector<double> edgeExpQ(E, 0.0), edgeExpM(E, 0.0);\n            double sumExpQ = 0.0, sumExpM = 0.0;\n            for (int ei = 0; ei < E; ei++) {\n                int u = edges[ei].first, v = edges[ei].second;\n                int a = assignPos[u], b = assignPos[v];\n                double q = (double)pairMean[a][b] + P.alpha * (double)pairSigma[a][b];\n                double m = (double)pairSMax[a][b];\n                double eQ = exp(betaQ * q);\n                double eM = exp(betaM * m);\n                edgeExpQ[ei] = eQ; sumExpQ += eQ;\n                edgeExpM[ei] = eM; sumExpM += eM;\n            }\n\n            double currentObj = totalObjective(assignPos, sumExpQ, sumExpM, nodeWeight);\n\n            int iters = P.iters;\n            vector<char> mark(E, 0);\n            vector<int> changed; changed.reserve(16);\n\n            auto isLockedPos = [&](int pos)->bool{\n                if (pl.lockMode == -1) return false;\n                if (posPairs.empty()) return false;\n                if (pl.lockMode == 2) {\n                    if (pos == posPairs[0].first || pos == posPairs[0].second ||\n                        pos == posPairs[1].first || pos == posPairs[1].second) return true;\n                } else if (pl.lockMode == 1) {\n                    if (pos == posPairs[0].first || pos == posPairs[0].second) return true;\n                }\n                return false;\n            };\n\n            auto pickRandomPosNotLocked = [&]()->int{\n                for (int tries = 0; tries < 20; tries++) {\n                    int p = rng.randint(0, N*N-1);\n                    if (!isLockedPos(p)) return p;\n                }\n                // fallback\n                for (int p = 0; p < N*N; p++) if (!isLockedPos(p)) return p;\n                return 0;\n            };\n\n            double pBias = pBiasForTurn(t);\n            int bestEdgeIdx = -1;\n            auto recomputeBestEdge = [&](){\n                double bestScore = -1e300;\n                int idx = -1;\n                for (int ei = 0; ei < E; ei++) {\n                    double score = P.muQ * edgeExpQ[ei] + P.muM * edgeExpM[ei];\n                    if (score > bestScore) { bestScore = score; idx = ei; }\n                }\n                bestEdgeIdx = idx;\n            };\n            recomputeBestEdge();\n\n            for (int it = 0; it < iters; it++) {\n                if ((it & 63) == 0) recomputeBestEdge();\n\n                int aPos, bPos;\n                bool useBias = rng.rand01() < pBias && bestEdgeIdx >= 0;\n                if (useBias) {\n                    int u = edges[bestEdgeIdx].first;\n                    int v = edges[bestEdgeIdx].second;\n                    // try to pick unlocked endpoint\n                    int cand[2] = {u, v};\n                    int pick = rng.randint(0, 1);\n                    aPos = cand[pick];\n                    if (isLockedPos(aPos)) aPos = cand[1 - pick];\n                    if (isLockedPos(aPos)) aPos = pickRandomPosNotLocked();\n                    bPos = pickRandomPosNotLocked();\n                    if (aPos == bPos) { bPos = pickRandomPosNotLocked(); }\n                } else {\n                    aPos = pickRandomPosNotLocked();\n                    bPos = pickRandomPosNotLocked();\n                    if (aPos == bPos) continue;\n                }\n\n                // Enforce locks (redundant checks)\n                if (pl.lockMode == 2) {\n                    if (!posPairs.empty()) {\n                        if (aPos == posPairs[0].first || aPos == posPairs[0].second ||\n                            aPos == posPairs[1].first || aPos == posPairs[1].second) continue;\n                        if (bPos == posPairs[0].first || bPos == posPairs[0].second ||\n                            bPos == posPairs[1].first || bPos == posPairs[1].second) continue;\n                    }\n                } else if (pl.lockMode == 1) {\n                    if (!posPairs.empty()) {\n                        if (aPos == posPairs[0].first || aPos == posPairs[0].second) continue;\n                        if (bPos == posPairs[0].first || bPos == posPairs[0].second) continue;\n                    }\n                }\n\n                if (aPos == bPos) continue;\n                int ka = assignPos[aPos];\n                int kb = assignPos[bPos];\n\n                double delta = 0.0;\n                // Node term\n                delta += deg[aPos] * (nodeWeight[kb] - nodeWeight[ka]);\n                delta += deg[bPos] * (nodeWeight[ka] - nodeWeight[kb]);\n\n                // Pair spread and softmax updates for changed edges\n                double deltaPair = 0.0;\n                changed.clear();\n                for (int ei : edgeIdxByPos[aPos]) if (!mark[ei]) { mark[ei] = 1; changed.push_back(ei); }\n                for (int ei : edgeIdxByPos[bPos]) if (!mark[ei]) { mark[ei] = 1; changed.push_back(ei); }\n\n                double newSumExpQ = sumExpQ, newSumExpM = sumExpM;\n                for (int ei : changed) {\n                    int u = edges[ei].first, v = edges[ei].second;\n                    int su = assignPos[u], sv = assignPos[v];\n                    if (u == aPos) su = kb; else if (u == bPos) su = ka;\n                    if (v == aPos) sv = kb; else if (v == bPos) sv = ka;\n\n                    // Pair spread delta\n                    double oldPS = pairSpread(assignPos[u], assignPos[v]);\n                    double newPS = pairSpread(su, sv);\n                    deltaPair += newPS - oldPS;\n\n                    // Softmax updates\n                    double oldEQ = edgeExpQ[ei];\n                    double oldEM = edgeExpM[ei];\n                    double q = (double)pairMean[su][sv] + P.alpha * (double)pairSigma[su][sv];\n                    double m = (double)pairSMax[su][sv];\n                    double newEQ = exp(betaQ * q);\n                    double newEM = exp(betaM * m);\n                    newSumExpQ += (newEQ - oldEQ);\n                    newSumExpM += (newEM - oldEM);\n                }\n                for (int ei : changed) mark[ei] = 0;\n\n                delta += deltaPair;\n                if (newSumExpQ <= 0 || newSumExpM <= 0) continue;\n                double deltaSoft = P.muQ * (log(newSumExpQ) - log(sumExpQ))\n                                 + P.muM * (log(newSumExpM) - log(sumExpM));\n                double totalDelta = delta + deltaSoft;\n\n                if (totalDelta > 1e-12) {\n                    swap(assignPos[aPos], assignPos[bPos]);\n                    // Update edge arrays and sums\n                    for (int ei : changed) {\n                        int u = edges[ei].first, v = edges[ei].second;\n                        int a = assignPos[u], b = assignPos[v];\n                        double q = (double)pairMean[a][b] + P.alpha * (double)pairSigma[a][b];\n                        double m = (double)pairSMax[a][b];\n                        double eQ = exp(betaQ * q);\n                        double eM = exp(betaM * m);\n                        sumExpQ += (eQ - edgeExpQ[ei]);\n                        sumExpM += (eM - edgeExpM[ei]);\n                        edgeExpQ[ei] = eQ;\n                        edgeExpM[ei] = eM;\n                    }\n                    currentObj += totalDelta;\n                }\n            }\n\n            double obj = currentObj;\n            if (obj > bestObj) {\n                bestObj = obj;\n                bestAssign = assignPos;\n            }\n        }\n\n        // Output plan\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int pos = i * N + j;\n                cout << bestAssign[pos] << (j + 1 == N ? '\\n' : ' ');\n            }\n        }\n        cout.flush();\n\n        // Read next generation\n        for (int i = 0; i < SEED_COUNT; i++)\n            for (int j = 0; j < M; j++) cin >> X[i][j];\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int x, y; };\n\nstruct Hungarian {\n    static pair<long long, vector<int>> solve(const vector<vector<int>>& cost) {\n        int n = (int)cost.size();\n        const int INF = 1e9;\n        vector<int> u(n+1), v(n+1), p(n+1), way(n+1);\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            int j0 = 0;\n            vector<int> minv(n+1, INF);\n            vector<char> used(n+1, false);\n            do {\n                used[j0] = true;\n                int i0 = p[j0], delta = INF, j1 = 0;\n                for (int j = 1; j <= n; j++) if (!used[j]) {\n                    int cur = cost[i0-1][j-1] - u[i0] - v[j];\n                    if (cur < minv[j]) { minv[j] = cur; way[j] = j0; }\n                    if (minv[j] < delta) { delta = minv[j]; j1 = j; }\n                }\n                for (int j = 0; j <= n; j++) {\n                    if (used[j]) { u[p[j]] += delta; v[j] -= delta; }\n                    else minv[j] -= delta;\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n        vector<int> assignment(n, -1);\n        for (int j = 1; j <= n; j++) if (p[j] != 0) assignment[p[j]-1] = j-1;\n        long long value = -v[0];\n        return {value, assignment};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto T0 = chrono::steady_clock::now();\n    auto time_up = [&]() -> bool {\n        auto t1 = chrono::steady_clock::now();\n        double ms = chrono::duration<double, milli>(t1 - T0).count();\n        return ms > 2800.0; // soft guard\n    };\n\n    int N, M, V;\n    if (!(cin >> N >> M >> V)) return 0;\n    vector<string> ss(N), tt(N);\n    for (int i = 0; i < N; i++) cin >> ss[i];\n    for (int i = 0; i < N; i++) cin >> tt[i];\n\n    vector<vector<int>> occ(N, vector<int>(N, 0));\n    vector<Pos> sources, targets;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int s = ss[i][j] - '0';\n        int t = tt[i][j] - '0';\n        occ[i][j] = s;\n        if (s == 1 && t == 0) sources.push_back({i,j});\n        if (s == 0 && t == 1) targets.push_back({i,j});\n    }\n    int D = (int)sources.size();\n\n    int Vp = 2;\n    const int DX[4] = {0, 1, 0, -1}; // 0=E,1=S,2=W,3=N\n    const int DY[4] = {1, 0, -1, 0};\n\n    auto rotdist = [&](int cur, int req) {\n        int d = (req - cur + 4) % 4;\n        return min(d, 4 - d);\n    };\n    auto enumerate_adj = [&](int bx, int by) -> vector<tuple<int,int,int>> {\n        vector<tuple<int,int,int>> res;\n        if (by - 1 >= 0) res.emplace_back(bx, by - 1, 0);\n        if (by + 1 < N) res.emplace_back(bx, by + 1, 2);\n        if (bx - 1 >= 0) res.emplace_back(bx - 1, by, 1);\n        if (bx + 1 < N) res.emplace_back(bx + 1, by, 3);\n        return res;\n    };\n    auto pureMoveCost = [&](int rx0, int ry0, int dir0, int ax, int ay, int adir) -> int {\n        int mv = abs(rx0 - ax) + abs(ry0 - ay);\n        int rr = rotdist(dir0, adir);\n        return max(mv, rr);\n    };\n    auto fusedCost = [&](int rx0, int ry0, int dir0, int ax, int ay, int adir, bool fuseP) -> int {\n        int mv = abs(rx0 - ax) + abs(ry0 - ay);\n        int rr = rotdist(dir0, adir);\n        int c = max(mv, rr);\n        if (fuseP && mv == 0 && rr == 0) return 1;\n        return c;\n    };\n\n    if ((int)targets.size() != D) {\n        cout << 2 << \"\\n\";\n        cout << 0 << \" \" << 1 << \"\\n\";\n        cout << 0 << \" \" << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Adjacencies for sources and targets\n    vector<vector<tuple<int,int,int>>> srcAdj(D), tarAdj(D);\n    for (int i = 0; i < D; i++) srcAdj[i] = enumerate_adj(sources[i].x, sources[i].y);\n    for (int j = 0; j < D; j++) tarAdj[j] = enumerate_adj(targets[j].x, targets[j].y);\n    for (int i = 0; i < D; i++) if (srcAdj[i].empty()) {\n        if (sources[i].y - 1 >= 0) srcAdj[i].emplace_back(sources[i].x, sources[i].y - 1, 0);\n        else srcAdj[i].emplace_back(sources[i].x, sources[i].y + 1, 2);\n    }\n    for (int j = 0; j < D; j++) if (tarAdj[j].empty()) {\n        if (targets[j].y - 1 >= 0) tarAdj[j].emplace_back(targets[j].x, targets[j].y - 1, 0);\n        else tarAdj[j].emplace_back(targets[j].x, targets[j].y + 1, 2);\n    }\n\n    // Hungarian assignment with orientation-aware costs\n    vector<vector<int>> hcost(D, vector<int>(D, 0));\n    for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) {\n        int best = INT_MAX;\n        for (auto &sa : srcAdj[i]) {\n            int sx, sy, sd; tie(sx, sy, sd) = sa;\n            for (auto &ta : tarAdj[j]) {\n                int tx, ty, td; tie(tx, ty, td) = ta;\n                int c = pureMoveCost(sx, sy, sd, tx, ty, td);\n                best = min(best, c);\n            }\n        }\n        hcost[i][j] = (best == INT_MAX ? 0 : best);\n    }\n    vector<int> pairTo(D, -1);\n    if (D > 0) {\n        auto res = Hungarian::solve(hcost);\n        pairTo = res.second;\n    }\n\n    // Per-task adjacencies after assignment\n    vector<vector<tuple<int,int,int>>> pickAdj(D), dropAdj(D);\n    for (int i = 0; i < D; i++) {\n        pickAdj[i] = srcAdj[i];\n        dropAdj[i] = tarAdj[pairTo[i]];\n        if (pickAdj[i].empty()) {\n            auto b = sources[i];\n            if (b.y - 1 >= 0) pickAdj[i].emplace_back(b.x, b.y - 1, 0);\n            else pickAdj[i].emplace_back(b.x, b.y + 1, 2);\n        }\n        if (dropAdj[i].empty()) {\n            auto c = targets[pairTo[i]];\n            if (c.y - 1 >= 0) dropAdj[i].emplace_back(c.x, c.y - 1, 0);\n            else dropAdj[i].emplace_back(c.x, c.y + 1, 2);\n        }\n    }\n\n    // linkCost orientation-aware\n    vector<vector<int>> linkCost(D, vector<int>(D, 0));\n    for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) {\n        if (i == j) { linkCost[i][j] = 0; continue; }\n        int best = INT_MAX;\n        for (auto &di : dropAdj[i]) {\n            int dx, dy, dd; tie(dx, dy, dd) = di;\n            for (auto &pj : pickAdj[j]) {\n                int px, py, pd; tie(px, py, pd) = pj;\n                int c = pureMoveCost(dx, dy, dd, px, py, pd);\n                best = min(best, c);\n            }\n        }\n        linkCost[i][j] = (best == INT_MAX ? 0 : best);\n    }\n\n    auto path_cost = [&](const vector<int>& path) -> long long {\n        long long s = 0;\n        for (int i = 0; i + 1 < (int)path.size(); i++) s += linkCost[path[i]][path[i+1]];\n        return s;\n    };\n\n    // Seed RNG\n    uint64_t seed = 1469598103934665603ULL;\n    auto mix = [&](uint64_t x) {\n        x ^= x >> 33; x *= 0xff51afd7ed558ccdULL;\n        x ^= x >> 33; x *= 0xc4ceb9fe1a85ec53ULL;\n        x ^= x >> 33; return x;\n    };\n    seed = mix(seed ^ (uint64_t)N ^ ((uint64_t)M << 21) ^ ((uint64_t)V << 42));\n    for (int i = 0; i < N; i++) for (char c : ss[i]) seed = mix(seed ^ (uint64_t)(c));\n    for (int i = 0; i < N; i++) for (char c : tt[i]) seed = mix(seed ^ (uint64_t)(c));\n    auto rng = [&]() -> uint64_t { seed ^= seed << 7; seed ^= seed >> 9; return seed; };\n\n    // Build multiple initial routes (NN) and pick best by linkCost\n    vector<int> ord;\n    if (D > 0) {\n        vector<int> minOut(D, INT_MAX), minIn(D, INT_MAX);\n        for (int i = 0; i < D; i++) {\n            for (int j = 0; j < D; j++) if (i != j) {\n                minOut[i] = min(minOut[i], linkCost[i][j]);\n                minIn[i]  = min(minIn[i],  linkCost[j][i]);\n            }\n            if (minOut[i] == INT_MAX) minOut[i] = 0;\n            if (minIn[i]  == INT_MAX) minIn[i]  = 0;\n        }\n        int start1 = 0, bestScore = INT_MAX, bestOut = INT_MAX;\n        for (int i = 0; i < D; i++) {\n            int score = minOut[i] - minIn[i];\n            if (score < bestScore || (score == bestScore && minOut[i] < bestOut)) {\n                bestScore = score; bestOut = minOut[i]; start1 = i;\n            }\n        }\n        int start2 = (int)(rng() % max(1, D));\n        int start3 = 0; for (int i = 0; i < D; i++) if (minOut[i] < minOut[start3]) start3 = i;\n        int start4 = 0; for (int i = 0; i < D; i++) if (minIn[i] > minIn[start4]) start4 = i;\n\n        vector<int> starts = {start1};\n        if (find(starts.begin(), starts.end(), start3) == starts.end()) starts.push_back(start3);\n        if (find(starts.begin(), starts.end(), start4) == starts.end()) starts.push_back(start4);\n        while ((int)starts.size() < min(D, 6) && (int)starts.size() < D) {\n            int s0 = (int)(rng() % D);\n            if (find(starts.begin(), starts.end(), s0) == starts.end()) starts.push_back(s0);\n        }\n\n        auto build_nn = [&](int start) {\n            vector<int> used(D, 0), p; p.reserve(D);\n            int cur = start; used[cur] = 1; p.push_back(cur);\n            for (int k = 1; k < D; k++) {\n                int bestj = -1, bestd = INT_MAX;\n                for (int j = 0; j < D; j++) if (!used[j]) {\n                    int d = linkCost[cur][j];\n                    if (d < bestd) { bestd = d; bestj = j; }\n                }\n                if (bestj == -1) for (int j = 0; j < D; j++) if (!used[j]) { bestj = j; break; }\n                used[bestj] = 1; p.push_back(bestj); cur = bestj;\n            }\n            return p;\n        };\n\n        auto quick_2opt = [&](vector<int>& p) {\n            if (D < 3) return;\n            auto computePref = [&]() {\n                vector<long long> pref(D, 0);\n                for (int t = 0; t + 1 < D; t++) {\n                    long long diff = (long long)linkCost[p[t+1]][p[t]] - (long long)linkCost[p[t]][p[t+1]];\n                    pref[t+1] = pref[t] + diff;\n                }\n                return pref;\n            };\n            for (int outer = 0; outer < 1 && !time_up(); outer++) {\n                bool changed = true;\n                while (changed && !time_up()) {\n                    auto pref = computePref();\n                    changed = false;\n                    for (int i = 0; i < D - 1 && !changed; i++) {\n                        for (int j = i + 1; j < D && !changed; j++) {\n                            long long delta = 0;\n                            if (i > 0) delta += (long long)linkCost[p[i-1]][p[j]] - (long long)linkCost[p[i-1]][p[i]];\n                            if (j + 1 < D) delta += (long long)linkCost[p[i]][p[j+1]] - (long long)linkCost[p[j]][p[j+1]];\n                            long long internal = pref[j] - pref[i];\n                            delta += internal;\n                            if (delta < 0) {\n                                reverse(p.begin() + i, p.begin() + j + 1);\n                                changed = true;\n                            }\n                        }\n                    }\n                }\n            }\n        };\n\n        long long bestCost = LLONG_MAX; vector<int> bestOrd;\n        for (int st : starts) {\n            auto cand = build_nn(st);\n            quick_2opt(cand);\n            long long c = path_cost(cand);\n            if (c < bestCost) { bestCost = c; bestOrd = cand; }\n            if (time_up()) break;\n        }\n        ord = bestOrd.empty() ? build_nn(start1) : bestOrd;\n    }\n\n    // Directed 2-opt with recomputation\n    if (D >= 3 && !time_up()) {\n        auto computePref = [&]() {\n            vector<long long> pref(D, 0);\n            for (int t = 0; t + 1 < D; t++) {\n                long long diff = (long long)linkCost[ord[t+1]][ord[t]] - (long long)linkCost[ord[t]][ord[t+1]];\n                pref[t+1] = pref[t] + diff;\n            }\n            return pref;\n        };\n        for (int outer = 0; outer < 2 && !time_up(); outer++) {\n            bool changedAny = false;\n            while (!time_up()) {\n                auto pref = computePref();\n                bool changed = false;\n                for (int i = 0; i < D - 1 && !changed; i++) {\n                    for (int j = i + 1; j < D && !changed; j++) {\n                        long long delta = 0;\n                        if (i > 0) delta += (long long)linkCost[ord[i-1]][ord[j]] - (long long)linkCost[ord[i-1]][ord[i]];\n                        if (j + 1 < D) delta += (long long)linkCost[ord[i]][ord[j+1]] - (long long)linkCost[ord[j]][ord[j+1]];\n                        long long internal = pref[j] - pref[i];\n                        delta += internal;\n                        if (delta < 0) {\n                            reverse(ord.begin() + i, ord.begin() + j + 1);\n                            changed = true;\n                            changedAny = true;\n                        }\n                    }\n                }\n                if (!changed) break;\n            }\n            if (!changedAny) break;\n        }\n    }\n\n    // Node swap\n    auto swap_delta = [&](int i, int j, const vector<int>& p) -> long long {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n        int u = p[i], v = p[j];\n        auto edge = [&](int a, int b)->long long {\n            if (a < 0 || b < 0) return 0LL;\n            return (long long)linkCost[a][b];\n        };\n        if (j == i + 1) {\n            int a = (i-1 >= 0 ? p[i-1] : -1);\n            int d = (j+1 < D ? p[j+1] : -1);\n            long long oldc = edge(a,u) + edge(u,v) + edge(v,d);\n            long long newc = edge(a,v) + edge(v,u) + edge(u,d);\n            return newc - oldc;\n        } else {\n            int a = (i-1 >= 0 ? p[i-1] : -1);\n            int b = (i+1 < D ? p[i+1] : -1);\n            int c = (j-1 >= 0 ? p[j-1] : -1);\n            int d = (j+1 < D ? p[j+1] : -1);\n            long long oldc = edge(a,u) + edge(u,b) + edge(c,v) + edge(v,d);\n            long long newc = edge(a,v) + edge(v,b) + edge(c,u) + edge(u,d);\n            return newc - oldc;\n        }\n    };\n    if (D >= 3 && !time_up()) {\n        for (int pass = 0; pass < 2 && !time_up(); pass++) {\n            bool improved = false;\n            for (int i = 0; i < D && !time_up(); i++) {\n                for (int j = i+1; j < D && !time_up(); j++) {\n                    long long delta = swap_delta(i, j, ord);\n                    if (delta < 0) { swap(ord[i], ord[j]); improved = true; }\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    // Or-opt\n    if (D >= 3 && !time_up()) {\n        bool improved = true;\n        for (int pass = 0; pass < 4 && improved && !time_up(); pass++) {\n            improved = false;\n            for (int i = 0; i < D && !time_up(); i++) {\n                int a = ord[i];\n                long long delta_rem = 0;\n                if (D >= 2) {\n                    if (i == 0) delta_rem -= linkCost[ord[0]][ord[1]];\n                    else if (i == D-1) delta_rem -= linkCost[ord[D-2]][ord[D-1]];\n                    else {\n                        delta_rem -= linkCost[ord[i-1]][ord[i]];\n                        delta_rem -= linkCost[ord[i]][ord[i+1]];\n                        delta_rem += linkCost[ord[i-1]][ord[i+1]];\n                    }\n                }\n                auto idxAfterRemoval = [&](int p)->int { return (p < i) ? ord[p] : ord[p+1]; };\n                long long bestDelta = 0; int bestPos = -1;\n                for (int p = 0; p <= D-1 && !time_up(); p++) {\n                    if (p == i || p == i+1) continue;\n                    long long delta_ins = 0;\n                    if (p == 0) {\n                        int nxt = idxAfterRemoval(0);\n                        delta_ins += linkCost[a][nxt];\n                    } else if (p == D-1) {\n                        int prv = idxAfterRemoval(D-2);\n                        delta_ins += linkCost[prv][a];\n                    } else {\n                        int prv = idxAfterRemoval(p-1);\n                        int nxt = idxAfterRemoval(p);\n                        delta_ins -= linkCost[prv][nxt];\n                        delta_ins += linkCost[prv][a] + linkCost[a][nxt];\n                    }\n                    long long delta = delta_rem + delta_ins;\n                    if (delta < bestDelta) { bestDelta = delta; bestPos = p; }\n                }\n                if (bestPos != -1) {\n                    vector<int> tmp; tmp.reserve(D);\n                    for (int k = 0; k < D; k++) if (k != i) tmp.push_back(ord[k]);\n                    tmp.insert(tmp.begin() + bestPos, a);\n                    ord.swap(tmp);\n                    improved = true;\n                }\n            }\n        }\n    }\n\n    // Sliding-window DP reorder (k=8)\n    if (D >= 10 && !time_up()) {\n        const int K = 8;\n        for (int l = 1; l + K < D && !time_up(); l++) {\n            int r = l + K - 1;\n            int prev = ord[l-1];\n            int nextn = ord[r+1];\n            long long oldc = 0;\n            oldc += linkCost[prev][ord[l]];\n            for (int i = l; i < r; i++) oldc += linkCost[ord[i]][ord[i+1]];\n            oldc += linkCost[ord[r]][nextn];\n\n            vector<int> nodes(K);\n            for (int i = 0; i < K; i++) nodes[i] = ord[l + i];\n            int FULL = (1<<K) - 1;\n            const int INF = 1e9;\n            static int dpw[1<<8][8];\n            static short prew[1<<8][8];\n            for (int m = 0; m <= FULL; m++) for (int j = 0; j < K; j++) dpw[m][j] = INF, prew[m][j] = -1;\n\n            for (int j = 0; j < K; j++) dpw[1<<j][j] = linkCost[prev][nodes[j]];\n            for (int m = 1; m <= FULL; m++) {\n                for (int j = 0; j < K; j++) if (m & (1<<j)) {\n                    int cur = dpw[m][j];\n                    if (cur >= INF) continue;\n                    int rem = FULL ^ m;\n                    while (rem) {\n                        int b = rem & -rem;\n                        int kidx = __builtin_ctz(rem);\n                        int val = cur + linkCost[nodes[j]][nodes[kidx]];\n                        if (val < dpw[m | (1<<kidx)][kidx]) {\n                            dpw[m | (1<<kidx)][kidx] = val;\n                            prew[m | (1<<kidx)][kidx] = j;\n                        }\n                        rem ^= b;\n                    }\n                }\n            }\n            long long best = LLONG_MAX; int last = -1;\n            for (int j = 0; j < K; j++) {\n                long long val = (long long)dpw[FULL][j] + linkCost[nodes[j]][nextn];\n                if (val < best) { best = val; last = j; }\n            }\n            if (best + 0 < oldc) {\n                int m = FULL, j = last;\n                vector<int> seq; seq.reserve(K);\n                while (m) {\n                    seq.push_back(nodes[j]);\n                    int pj = prew[m][j];\n                    m ^= (1<<j);\n                    j = pj;\n                    if (j < 0 && m) { seq.clear(); break; }\n                }\n                if (!seq.empty()) {\n                    reverse(seq.begin(), seq.end());\n                    for (int i = 0; i < K; i++) ord[l+i] = seq[i];\n                }\n            }\n        }\n    }\n\n    // DP-evaluated hill climbing on route (limited iterations), using coarse delta filter\n    auto eval_dp_cost = [&](const vector<int>& route) -> long long {\n        int T = (int)route.size();\n        const long long INFLL = (1LL<<60);\n        vector<long long> prev_dp, cur_dp;\n        // First task: initial orientation 0 at chosen pick pos\n        int t0 = route[0];\n        int dsz0 = (int)dropAdj[t0].size();\n        prev_dp.assign(dsz0, INFLL);\n        for (int jd = 0; jd < dsz0; jd++) {\n            long long best = INFLL;\n            for (int jp = 0; jp < (int)pickAdj[t0].size(); jp++) {\n                int px, py, pdir; tie(px, py, pdir) = pickAdj[t0][jp];\n                int dx, dy, ddir; tie(dx, dy, ddir) = dropAdj[t0][jd];\n                long long c = (long long)fusedCost(px, py, 0, px, py, pdir, true)\n                            + (long long)fusedCost(px, py, pdir, dx, dy, ddir, true);\n                best = min(best, c);\n            }\n            prev_dp[jd] = best;\n        }\n        for (int idx = 1; idx < T; idx++) {\n            int ti = route[idx];\n            int prevt = route[idx-1];\n            int dsz = (int)dropAdj[ti].size();\n            int pdsz = (int)dropAdj[prevt].size();\n            cur_dp.assign(dsz, INFLL);\n            for (int jd = 0; jd < dsz; jd++) {\n                int dx, dy, ddir; tie(dx, dy, ddir) = dropAdj[ti][jd];\n                long long best = INFLL;\n                for (int kd = 0; kd < pdsz; kd++) {\n                    if (prev_dp[kd] >= INFLL/2) continue;\n                    int sx, sy, sdir; tie(sx, sy, sdir) = dropAdj[prevt][kd];\n                    for (int jp = 0; jp < (int)pickAdj[ti].size(); jp++) {\n                        int px, py, pdir; tie(px, py, pdir) = pickAdj[ti][jp];\n                        long long c = prev_dp[kd]\n                                    + (long long)fusedCost(sx, sy, sdir, px, py, pdir, true)\n                                    + (long long)fusedCost(px, py, pdir, dx, dy, ddir, true);\n                        if (c < best) best = c;\n                    }\n                }\n                cur_dp[jd] = best;\n            }\n            prev_dp.swap(cur_dp);\n        }\n        long long ans = (1LL<<60);\n        for (long long v : prev_dp) ans = min(ans, v);\n        return ans;\n    };\n\n    if (D >= 3 && !time_up()) {\n        long long bestCoarse = path_cost(ord);\n        long long bestDP = eval_dp_cost(ord);\n        int maxIter = 800; // conservative\n        for (int it = 0; it < maxIter && !time_up(); it++) {\n            bool do2opt = ((rng() >> 2) & 1);\n            int i = (int)(rng() % D);\n            int j = (int)(rng() % D);\n            if (i == j) continue;\n            if (i > j) swap(i, j);\n            if (do2opt) {\n                if (i + 1 >= j) continue;\n                long long delta = 0;\n                if (i > 0) delta += (long long)linkCost[ord[i-1]][ord[j]] - (long long)linkCost[ord[i-1]][ord[i]];\n                if (j + 1 < D) delta += (long long)linkCost[ord[i]][ord[j+1]] - (long long)linkCost[ord[j]][ord[j+1]];\n                // internal reversed edges difference\n                // compute prefix quickly\n                // For filter, just accept if delta < 0 (approx)\n                if (delta >= 0) continue;\n                vector<int> cand = ord;\n                reverse(cand.begin() + i, cand.begin() + j + 1);\n                long long c = eval_dp_cost(cand);\n                if (c < bestDP) {\n                    bestDP = c; ord.swap(cand);\n                    bestCoarse += delta; // approximate update\n                }\n            } else {\n                long long delta = swap_delta(i, j, ord);\n                if (delta >= 0) continue;\n                vector<int> cand = ord; swap(cand[i], cand[j]);\n                long long c = eval_dp_cost(cand);\n                if (c < bestDP) {\n                    bestDP = c; ord.swap(cand);\n                    bestCoarse += delta;\n                }\n            }\n        }\n    }\n\n    if (D == 0) {\n        cout << Vp << \"\\n\";\n        cout << 0 << \" \" << 1 << \"\\n\";\n        cout << 0 << \" \" << 0 << \"\\n\";\n        return 0;\n    }\n\n    // Final global DP over the fixed route to choose pick/drop adjacencies\n    int T = D;\n    vector<vector<long long>> dp(T);\n    vector<vector<int>> prevDrop(T), pickChosen(T);\n    const long long INFLL = (1LL<<60);\n    for (int i = 0; i < T; i++) {\n        int ti = ord[i];\n        int dsz = (int)dropAdj[ti].size();\n        dp[i].assign(dsz, INFLL);\n        prevDrop[i].assign(dsz, -1);\n        pickChosen[i].assign(dsz, -1);\n        if (i == 0) {\n            for (int jd = 0; jd < dsz; jd++) {\n                long long best = INFLL; int bestP = -1;\n                for (int jp = 0; jp < (int)pickAdj[ti].size(); jp++) {\n                    int px, py, pdir; tie(px, py, pdir) = pickAdj[ti][jp];\n                    int dx, dy, ddir; tie(dx, dy, ddir) = dropAdj[ti][jd];\n                    long long c = (long long)fusedCost(px, py, 0, px, py, pdir, true)\n                                + (long long)fusedCost(px, py, pdir, dx, dy, ddir, true);\n                    if (c < best) { best = c; bestP = jp; }\n                }\n                dp[i][jd] = best;\n                pickChosen[i][jd] = bestP;\n            }\n        } else {\n            int prevTask = ord[i-1];\n            int pdsz = (int)dropAdj[prevTask].size();\n            for (int jd = 0; jd < dsz; jd++) {\n                long long best = INFLL; int bestPrev = -1; int bestP = -1;\n                int dx, dy, ddir; tie(dx, dy, ddir) = dropAdj[ti][jd];\n                for (int kd = 0; kd < pdsz; kd++) {\n                    if (dp[i-1][kd] >= INFLL/2) continue;\n                    int sx, sy, sdir; tie(sx, sy, sdir) = dropAdj[prevTask][kd];\n                    for (int jp = 0; jp < (int)pickAdj[ti].size(); jp++) {\n                        int px, py, pdir; tie(px, py, pdir) = pickAdj[ti][jp];\n                        long long c = dp[i-1][kd]\n                                    + (long long)fusedCost(sx, sy, sdir, px, py, pdir, true)\n                                    + (long long)fusedCost(px, py, pdir, dx, dy, ddir, true);\n                        if (c < best) { best = c; bestPrev = kd; bestP = jp; }\n                    }\n                }\n                dp[i][jd] = best;\n                prevDrop[i][jd] = bestPrev;\n                pickChosen[i][jd] = bestP;\n            }\n        }\n    }\n    vector<int> bestDropIdx(T, -1), bestPickIdx(T, -1);\n    {\n        int last = -1; long long best = INFLL;\n        for (int jd = 0; jd < (int)dp[T-1].size(); jd++) {\n            if (dp[T-1][jd] < best) { best = dp[T-1][jd]; last = jd; }\n        }\n        int cur = last;\n        for (int i = T-1; i >= 0; i--) {\n            bestDropIdx[i] = cur;\n            bestPickIdx[i] = pickChosen[i][cur];\n            cur = prevDrop[i][cur];\n        }\n    }\n\n    // Initial root at chosen first pick adjacency, orientation east\n    int first = ord[0];\n    int rx, ry, dir;\n    {\n        int px, py, pdir; tie(px, py, pdir) = pickAdj[first][bestPickIdx[0]];\n        rx = px; ry = py; dir = 0;\n    }\n\n    // Output design and initial root\n    cout << Vp << \"\\n\";\n    cout << 0 << \" \" << 1 << \"\\n\";\n    cout << rx << \" \" << ry << \"\\n\";\n\n    vector<string> ops; ops.reserve(100000);\n    bool holding = false;\n\n    auto push_turn = [&](char moveCh, char rotCh, bool P) {\n        string s(2*Vp, '.');\n        s[0] = moveCh;\n        s[1] = (rotCh == 'L' || rotCh == 'R') ? rotCh : '.';\n        s[2] = '.';\n        s[3] = (P ? 'P' : '.');\n\n        if (moveCh == 'U') rx -= 1;\n        else if (moveCh == 'D') rx += 1;\n        else if (moveCh == 'L') ry -= 1;\n        else if (moveCh == 'R') ry += 1;\n        rx = max(0, min(N-1, rx));\n        ry = max(0, min(N-1, ry));\n\n        if (rotCh == 'L') dir = (dir + 3) % 4;\n        else if (rotCh == 'R') dir = (dir + 1) % 4;\n\n        if (P) {\n            int fx = rx + DX[dir];\n            int fy = ry + DY[dir];\n            if (0 <= fx && fx < N && 0 <= fy && fy < N) {\n                if (!holding) {\n                    if (occ[fx][fy] == 1) { occ[fx][fy] = 0; holding = true; }\n                } else {\n                    if (occ[fx][fy] == 0) { occ[fx][fy] = 1; holding = false; }\n                }\n            }\n        }\n        ops.push_back(s);\n    };\n    auto rotate_step_char = [&](int cur, int req) -> char {\n        int d = (req - cur + 4) % 4;\n        if (d == 0) return '.';\n        if (d == 1) return 'R';\n        if (d == 3) return 'L';\n        return 'R';\n    };\n    auto move_rotate_to = [&](int tx, int ty, int reqdir, bool fuseP) {\n        int dx = abs(rx - tx);\n        int dy = abs(ry - ty);\n        int rotNeed = rotdist(dir, reqdir);\n        int totMoves = dx + dy;\n        int rotTail = max(0, rotNeed - totMoves);\n        int totalSteps = totMoves + rotTail;\n\n        int stepIdx = 0;\n        while (rx != tx) {\n            char mv = (rx < tx ? 'D' : 'U');\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn(mv, rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000 || time_up()) return;\n        }\n        while (ry != ty) {\n            char mv = (ry < ty ? 'R' : 'L');\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn(mv, rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000 || time_up()) return;\n        }\n        while (dir != reqdir) {\n            char rot = rotate_step_char(dir, reqdir);\n            bool Pflag = fuseP && (stepIdx == totalSteps - 1);\n            push_turn('.', rot, Pflag);\n            stepIdx++;\n            if ((int)ops.size() >= 100000 || time_up()) return;\n        }\n        if (fuseP && totalSteps == 0) {\n            push_turn('.', '.', true);\n        }\n    };\n\n    // Execute tasks with DP-chosen adjacencies\n    for (int i = 0; i < T; i++) {\n        if ((int)ops.size() >= 100000 || time_up()) break;\n        int ti = ord[i];\n        int pi = bestPickIdx[i];\n        int di = bestDropIdx[i];\n        int px, py, pdir; tie(px, py, pdir) = pickAdj[ti][pi];\n        move_rotate_to(px, py, pdir, true);\n        int dx, dy, ddir; tie(dx, dy, ddir) = dropAdj[ti][di];\n        move_rotate_to(dx, dy, ddir, true);\n    }\n\n    for (auto &s : ops) cout << s << \"\\n\";\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int LIM = 100000;\nstatic const int PERIM_LIMIT = 400000;\n\nstruct Pt { int x, y, w; };\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { st = chrono::high_resolution_clock::now(); }\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nstruct Candidate {\n    vector<pair<int,int>> poly;\n    long long approxScore = LLONG_MIN;\n    long long exactScore = LLONG_MIN;\n};\n\nstatic bool point_on_edge(const vector<pair<int,int>>& poly, int x, int y) {\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        int x1 = poly[i].first, y1 = poly[i].second;\n        int x2 = poly[(i+1)%m].first, y2 = poly[(i+1)%m].second;\n        if (x1 == x2) {\n            if (x == x1) {\n                int lo = min(y1, y2), hi = max(y1, y2);\n                if (lo <= y && y <= hi) return true;\n            }\n        } else if (y1 == y2) {\n            if (y == y1) {\n                int lo = min(x1, x2), hi = max(x1, x2);\n                if (lo <= x && x <= hi) return true;\n            }\n        }\n    }\n    return false;\n}\nstatic bool point_in_polygon(const vector<pair<int,int>>& poly, int x, int y) {\n    if (point_on_edge(poly, x, y)) return true;\n    bool inside = false;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        int x1 = poly[i].first, y1 = poly[i].second;\n        int x2 = poly[(i+1)%m].first, y2 = poly[(i+1)%m].second;\n        if (y1 == y2) continue;\n        int ymin = min(y1, y2), ymax = max(y1, y2);\n        if (y < ymin || y >= ymax) continue;\n        double xint = (x1 == x2) ? (double)x1 : x1 + (double)(x2 - x1) * (double)(y - y1) / (double)(y2 - y1);\n        if ((double)x < xint) inside = !inside;\n    }\n    return inside;\n}\nstatic long long exact_score_polygon(const vector<pair<int,int>>& poly, const vector<Pt>& pts) {\n    long long s = 0;\n    for (const auto& p : pts) if (point_in_polygon(poly, p.x, p.y)) s += p.w;\n    return s;\n}\nstatic long long polygon_perimeter(const vector<pair<int,int>>& poly) {\n    long long peri = 0;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; ++i) {\n        auto a = poly[i], b = poly[(i+1)%m];\n        peri += llabs((long long)a.first - b.first) + llabs((long long)a.second - b.second);\n    }\n    return peri;\n}\n\n// Grid utilities\nstatic vector<vector<int>> build_grid_W(int G, const vector<Pt>& pts) {\n    vector<vector<int>> W(G, vector<int>(G, 0));\n    for (const auto& p : pts) {\n        int xi = (int)((long long)p.x * G / 100001); if (xi < 0) xi = 0; if (xi >= G) xi = G-1;\n        int yi = (int)((long long)p.y * G / 100001); if (yi < 0) yi = 0; if (yi >= G) yi = G-1;\n        W[yi][xi] += p.w;\n    }\n    return W;\n}\nstatic void build_grid_lines(int G, vector<int>& xs, vector<int>& ys) {\n    xs.resize(G+1); ys.resize(G+1);\n    for (int i = 0; i <= G; ++i) {\n        long long t = 1LL * i * 100001;\n        int v = (int)((t + G - 1) / G);\n        if (v > LIM) v = LIM;\n        xs[i] = v;\n        ys[i] = v;\n    }\n}\n\n// Coarse best rectangle on a grid\nstruct RectIdx { int L, R, B, T; };\nstatic RectIdx coarse_best_rect_from_W(const vector<vector<int>>& W) {\n    int H = (int)W.size(); if (H == 0) return {0,0,0,0};\n    int G = (int)W[0].size();\n    vector<long long> acc(G);\n    long long bestSum = LLONG_MIN;\n    RectIdx best{0,0,0,0};\n    for (int top = 0; top < H; ++top) {\n        fill(acc.begin(), acc.end(), 0);\n        for (int bot = top; bot < H; ++bot) {\n            for (int j = 0; j < G; ++j) acc[j] += W[bot][j];\n            long long s = 0, best1D = LLONG_MIN;\n            int start = 0, l = 0, r = -1;\n            for (int j = 0; j < G; ++j) {\n                if (s <= 0) { s = acc[j]; start = j; }\n                else s += acc[j];\n                if (best1D == LLONG_MIN || s > best1D) { best1D = s; l = start; r = j; }\n            }\n            if (best1D > bestSum) { bestSum = best1D; best = {l, r, top, bot}; }\n        }\n    }\n    return best;\n}\nstatic vector<pair<int,int>> rect_to_polygon(const RectIdx& r, const vector<int>& xs, const vector<int>& ys) {\n    int Lx = xs[r.L];\n    int Rx = xs[r.R+1] - 1; if (Rx < Lx) Rx = Lx;\n    int By = ys[r.B];\n    int Ty = ys[r.T+1] - 1; if (Ty < By) Ty = By;\n    vector<pair<int,int>> poly;\n    poly.emplace_back(Lx, By);\n    poly.emplace_back(Rx, By);\n    poly.emplace_back(Rx, Ty);\n    poly.emplace_back(Lx, Ty);\n    return poly;\n}\n\n// Region grower\nstruct RegionGrower {\n    int G;\n    vector<vector<int>> W;  // [j][i]\n    vector<int> xs, ys;\n    vector<int> wx, hy;\n    vector<vector<char>> inR;\n    vector<vector<unsigned char>> nmask;\n\n    RegionGrower(int G_, const vector<vector<int>>& W_, const vector<int>& xs_, const vector<int>& ys_)\n        : G(G_), W(W_), xs(xs_), ys(ys_) {\n        wx.resize(G); hy.resize(G);\n        for (int i = 0; i < G; ++i) {\n            wx[i] = xs[i+1] - xs[i]; if (wx[i] < 1) wx[i] = 1;\n            hy[i] = ys[i+1] - ys[i]; if (hy[i] < 1) hy[i] = 1;\n        }\n        inR.assign(G, vector<char>(G, 0));\n        nmask.assign(G, vector<unsigned char>(G, 0));\n    }\n    inline bool inside_bounds(int i, int j) const { return 0 <= i && i < G && 0 <= j && j < G; }\n    inline int delta_perim_for_cell(int i, int j, unsigned char mask) const {\n        int left = (mask & 1) ? 1 : 0;\n        int right = (mask & 2) ? 1 : 0;\n        int bottom = (mask & 4) ? 1 : 0;\n        int top = (mask & 8) ? 1 : 0;\n        int res = 2 * (wx[i] + hy[j]) - 2 * ( hy[j]*(left + right) + wx[i]*(bottom + top) );\n        return res;\n    }\n    inline unsigned char neighbor_mask_inside(const vector<vector<char>>& inside, int i, int j) const {\n        unsigned char m = 0;\n        if (i > 0 && inside[j][i-1]) m |= 1;\n        if (i+1 < G && inside[j][i+1]) m |= 2;\n        if (j > 0 && inside[j-1][i]) m |= 4;\n        if (j+1 < G && inside[j+1][i]) m |= 8;\n        return m;\n    }\n    inline int degree_inside(const vector<vector<char>>& inside, int i, int j) const {\n        int d = 0;\n        if (i > 0 && inside[j][i-1]) ++d;\n        if (i+1 < G && inside[j][i+1]) ++d;\n        if (j > 0 && inside[j-1][i]) ++d;\n        if (j+1 < G && inside[j+1][i]) ++d;\n        return d;\n    }\n    inline bool is_boundary_cell(const vector<vector<char>>& inside, int i, int j) const {\n        if (!inside[j][i]) return false;\n        if (i == 0 || !inside[j][i-1]) return true;\n        if (i+1 == G || !inside[j][i+1]) return true;\n        if (j == 0 || !inside[j-1][i]) return true;\n        if (j+1 == G || !inside[j+1][i]) return true;\n        return false;\n    }\n\n    void reset() {\n        for (int j = 0; j < G; ++j) {\n            fill(inR[j].begin(), inR[j].end(), 0);\n            fill(nmask[j].begin(), nmask[j].end(), 0);\n        }\n    }\n\n    struct GrowResult {\n        vector<vector<char>> inside;\n        long long approxScore = 0;\n        long long perim = 0;\n        bool valid = false;\n    };\n\n    struct PQEntry {\n        double key;\n        int i, j;\n        int ver;\n        bool operator<(const PQEntry& other) const { return key < other.key; } // largest first\n    };\n\n    vector<vector<char>> fill_holes(const vector<vector<char>>& sel) const {\n        vector<vector<char>> visited(G, vector<char>(G, 0));\n        deque<pair<int,int>> dq;\n        auto push_border = [&](int i, int j) {\n            if (!inside_bounds(i,j)) return;\n            if (sel[j][i]) return;\n            if (visited[j][i]) return;\n            visited[j][i] = 1; dq.emplace_back(i,j);\n        };\n        for (int i = 0; i < G; ++i) { push_border(i, 0); push_border(i, G-1); }\n        for (int j = 0; j < G; ++j) { push_border(0, j); push_border(G-1, j); }\n        while (!dq.empty()) {\n            auto [i, j] = dq.front(); dq.pop_front();\n            auto try_push = [&](int ni, int nj) {\n                if (!inside_bounds(ni,nj)) return;\n                if (sel[nj][ni]) return;\n                if (visited[nj][ni]) return;\n                visited[nj][ni] = 1; dq.emplace_back(ni,nj);\n            };\n            try_push(i-1,j); try_push(i+1,j); try_push(i,j-1); try_push(i,j+1);\n        }\n        vector<vector<char>> inside(G, vector<char>(G, 0));\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) inside[j][i] = sel[j][i] || (!visited[j][i] && !sel[j][i]);\n        return inside;\n    }\n    void prune_negative_leaves(vector<vector<char>>& inside) const {\n        deque<pair<int,int>> dq;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) {\n            if (!inside[j][i]) continue;\n            if (W[j][i] < 0 && degree_inside(inside, i, j) <= 1) dq.emplace_back(i,j);\n        }\n        int cntInside = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (inside[j][i]) ++cntInside;\n        while (!dq.empty()) {\n            auto [i,j] = dq.front(); dq.pop_front();\n            if (!inside[j][i]) continue;\n            if (W[j][i] >= 0) continue;\n            int d = degree_inside(inside, i, j);\n            if (d > 1) continue;\n            if (cntInside <= 1) break;\n            inside[j][i] = 0;\n            --cntInside;\n            if (i > 0 && inside[j][i-1] && W[j][i-1] < 0 && degree_inside(inside, i-1, j) <= 1) dq.emplace_back(i-1,j);\n            if (i+1 < G && inside[j][i+1] && W[j][i+1] < 0 && degree_inside(inside, i+1, j) <= 1) dq.emplace_back(i+1,j);\n            if (j > 0 && inside[j-1][i] && W[j-1][i] < 0 && degree_inside(inside, i, j-1) <= 1) dq.emplace_back(i,j-1);\n            if (j+1 < G && inside[j+1][i] && W[j+1][i] < 0 && degree_inside(inside, i, j+1) <= 1) dq.emplace_back(i,j+1);\n        }\n    }\n    vector<vector<char>> best_component(const vector<vector<char>>& inside, long long& sumW) const {\n        vector<vector<char>> vis(G, vector<char>(G, 0));\n        long long bestSum = LLONG_MIN;\n        int bestId = -1;\n        vector<int> compId(G*G, -1);\n        vector<long long> compSum;\n        int cid = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) {\n            if (!inside[j][i] || vis[j][i]) continue;\n            long long s = 0;\n            deque<pair<int,int>> dq; dq.emplace_back(i,j); vis[j][i] = 1;\n            vector<pair<int,int>> cells;\n            while (!dq.empty()) {\n                auto [ci, cj] = dq.front(); dq.pop_front();\n                cells.emplace_back(ci,cj);\n                s += W[cj][ci];\n                auto try_push = [&](int ni, int nj){\n                    if (ni<0||ni>=G||nj<0||nj>=G) return;\n                    if (!inside[nj][ni] || vis[nj][ni]) return;\n                    vis[nj][ni] = 1; dq.emplace_back(ni,nj);\n                };\n                try_push(ci-1,cj); try_push(ci+1,cj); try_push(ci,cj-1); try_push(ci,cj+1);\n            }\n            compSum.push_back(s);\n            if (s > bestSum) { bestSum = s; bestId = cid; }\n            for (auto &q : cells) compId[q.second*G + q.first] = cid;\n            ++cid;\n        }\n        vector<vector<char>> out(G, vector<char>(G, 0));\n        if (bestId < 0) { sumW = 0; return out; }\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) {\n            if (inside[j][i] && compId[j*G + i] == bestId) out[j][i] = 1;\n        }\n        sumW = compSum[bestId];\n        return out;\n    }\n    long long compute_perimeter(const vector<vector<char>>& mask) const {\n        long long per = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (mask[j][i]) {\n            if (i == 0 || !mask[j][i-1]) per += hy[j];\n            if (i+1 == G || !mask[j][i+1]) per += hy[j];\n            if (j == 0 || !mask[j-1][i]) per += wx[i];\n            if (j+1 == G || !mask[j+1][i]) per += wx[i];\n        }\n        return per;\n    }\n\n    // Shrink inside mask to fit PERIM_LIMIT, removing leaf boundary cells greedily\n    void shrink_to_fit(vector<vector<char>>& inside, long long& approxScore) const {\n        long long per = compute_perimeter(inside);\n        if (per <= PERIM_LIMIT) return;\n\n        struct RemCand { double key; int i, j; int stamp; long long perDec; int scoreLoss; };\n        vector<vector<int>> stamp(G, vector<int>(G, 0));\n        int curStamp = 1;\n        auto mk_key = [&](long long perDec, int scoreLoss)->double {\n            // Prefer negative/zero loss, large perDec; use small denom for non-positive\n            double denom = (scoreLoss <= 0 ? 0.5 : (double)scoreLoss);\n            return (double)perDec / denom;\n        };\n        auto is_boundary = [&](int i, int j)->bool {\n            return is_boundary_cell(inside, i, j);\n        };\n        // Priority queue max-heap on key\n        auto cmp = [](const RemCand& a, const RemCand& b){\n            if (a.key != b.key) return a.key < b.key;\n            return a.perDec < b.perDec;\n        };\n        priority_queue<RemCand, vector<RemCand>, decltype(cmp)> pq(cmp);\n\n        auto push_cand = [&](int i, int j){\n            if (!inside[j][i]) return;\n            if (!is_boundary(i,j)) return;\n            int deg = degree_inside(inside, i, j);\n            if (deg > 1) return; // leaf-only to preserve connectivity\n            unsigned char m = neighbor_mask_inside(inside, i, j);\n            int dper_add = delta_perim_for_cell(i, j, m);\n            long long dper_remove = - (long long)dper_add;\n            if (dper_remove >= 0) return; // removal should reduce perimeter\n            long long perDec = -dper_remove;\n            int scoreLoss = - W[j][i];\n            RemCand rc{ mk_key(perDec, scoreLoss), i, j, ++stamp[j][i], perDec, scoreLoss };\n            pq.push(rc);\n        };\n\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) push_cand(i,j);\n\n        while (per > PERIM_LIMIT && !pq.empty()) {\n            RemCand rc = pq.top(); pq.pop();\n            int i = rc.i, j = rc.j;\n            if (!inside[j][i]) continue;\n            if (!is_boundary(i,j)) continue;\n            if (degree_inside(inside, i, j) > 1) continue;\n            unsigned char m = neighbor_mask_inside(inside, i, j);\n            int dper_add = delta_perim_for_cell(i, j, m);\n            long long dper_remove = - (long long)dper_add;\n            if (dper_remove >= 0) continue;\n            // remove\n            inside[j][i] = 0;\n            per += dper_remove;\n            approxScore -= W[j][i];\n            // update neighbors (they may become leaves)\n            if (i > 0) push_cand(i-1, j);\n            if (i+1 < G) push_cand(i+1, j);\n            if (j > 0) push_cand(i, j-1);\n            if (j+1 < G) push_cand(i, j+1);\n        }\n    }\n\n    // Growth from seed and from mask as earlier\n    GrowResult grow_from_seed(int si, int sj, int mode, double lambda, double time_limit_sec, Timer& tim) {\n        reset();\n        vector<vector<int>> ver(G, vector<int>(G, 0));\n        priority_queue<PQEntry> pq;\n        auto push_update = [&](int i, int j) {\n            if (inR[j][i]) return;\n            unsigned char mask = nmask[j][i];\n            if (mask == 0) return;\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (sc <= 0 && dper >= 0) return;\n                double key = (double)sc / (double)max(1, dper + (dper==0));\n                key += 1e-9 * sc;\n                pq.push({key, i, j, ++ver[j][i]});\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) return;\n                pq.push({gain, i, j, ++ver[j][i]});\n            }\n        };\n\n        long long perim = 0;\n        auto add_cell = [&](int ci, int cj) {\n            unsigned char mask = 0;\n            if (ci > 0 && inR[cj][ci-1]) mask |= 1;\n            if (ci+1 < G && inR[cj][ci+1]) mask |= 2;\n            if (cj > 0 && inR[cj-1][ci]) mask |= 4;\n            if (cj+1 < G && inR[cj+1][ci]) mask |= 8;\n            int dper = delta_perim_for_cell(ci, cj, mask);\n            perim += dper;\n            inR[cj][ci] = 1;\n            if (ci > 0 && !inR[cj][ci-1]) { nmask[cj][ci-1] |= 2; push_update(ci-1, cj); }\n            if (ci+1 < G && !inR[cj][ci+1]) { nmask[cj][ci+1] |= 1; push_update(ci+1, cj); }\n            if (cj > 0 && !inR[cj-1][ci]) { nmask[cj-1][ci] |= 8; push_update(ci, cj-1); }\n            if (cj+1 < G && !inR[cj+1][ci]) { nmask[cj+1][ci] |= 4; push_update(ci, cj+1); }\n        };\n\n        if (mode == 0 && W[sj][si] <= 0) { GrowResult gr; gr.valid = false; return gr; }\n        add_cell(si, sj);\n        if (perim > PERIM_LIMIT) { GrowResult gr; gr.valid = false; return gr; }\n\n        while (!pq.empty()) {\n            if (tim.elapsed() > time_limit_sec) break;\n            auto e = pq.top(); pq.pop();\n            int i = e.i, j = e.j;\n            if (inR[j][i]) continue;\n            if (e.ver != ver[j][i]) continue;\n            unsigned char mask = nmask[j][i];\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (sc <= 0 && dper >= 0) continue;\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) continue;\n            }\n            if (perim + dper > PERIM_LIMIT) continue;\n            add_cell(i, j);\n        }\n\n        auto inside = fill_holes(inR);\n        prune_negative_leaves(inside);\n        long long dummy = 0;\n        inside = best_component(inside, dummy);\n        long long approxScore = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (inside[j][i]) approxScore += W[j][i];\n\n        GrowResult gr;\n        gr.inside = move(inside);\n        gr.approxScore = approxScore;\n        gr.perim = compute_perimeter(gr.inside);\n        gr.valid = true;\n        return gr;\n    }\n\n    GrowResult grow_from_mask(vector<vector<char>> inside, int mode, double lambda, double time_limit_sec, Timer& tim) {\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) { inR[j][i] = inside[j][i] ? 1 : 0; nmask[j][i] = 0; }\n        vector<vector<int>> ver(G, vector<int>(G, 0));\n        priority_queue<PQEntry> pq;\n\n        auto set_frontier_for_cell = [&](int i, int j) {\n            if (!inR[j][i]) return;\n            if (i > 0 && !inR[j][i-1]) nmask[j][i-1] |= 2;\n            if (i+1 < G && !inR[j][i+1]) nmask[j][i+1] |= 1;\n            if (j > 0 && !inR[j-1][i]) nmask[j-1][i] |= 8;\n            if (j+1 < G && !inR[j+1][i]) nmask[j+1][i] |= 4;\n        };\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) set_frontier_for_cell(i,j);\n\n        auto push_update = [&](int i, int j) {\n            if (inR[j][i]) return;\n            unsigned char mask = nmask[j][i]; if (mask == 0) return;\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (sc <= 0 && dper >= 0) return;\n                double key = (double)sc / (double)max(1, dper + (dper==0));\n                key += 1e-9 * sc;\n                pq.push({key, i, j, ++ver[j][i]});\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) return;\n                pq.push({gain, i, j, ++ver[j][i]});\n            }\n        };\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (!inR[j][i]) push_update(i,j);\n\n        long long perim = compute_perimeter(inR);\n        auto add_cell = [&](int ci, int cj) {\n            unsigned char mask = 0;\n            if (ci > 0 && inR[cj][ci-1]) mask |= 1;\n            if (ci+1 < G && inR[cj][ci+1]) mask |= 2;\n            if (cj > 0 && inR[cj-1][ci]) mask |= 4;\n            if (cj+1 < G && inR[cj+1][ci]) mask |= 8;\n            int dper = delta_perim_for_cell(ci, cj, mask);\n            perim += dper;\n            inR[cj][ci] = 1;\n            if (ci > 0 && !inR[cj][ci-1]) { nmask[cj][ci-1] |= 2; push_update(ci-1, cj); }\n            if (ci+1 < G && !inR[cj][ci+1]) { nmask[cj][ci+1] |= 1; push_update(ci+1, cj); }\n            if (cj > 0 && !inR[cj-1][ci]) { nmask[cj-1][ci] |= 8; push_update(ci, cj-1); }\n            if (cj+1 < G && !inR[cj+1][ci]) { nmask[cj+1][ci] |= 4; push_update(ci, cj+1); }\n        };\n\n        while (!pq.empty()) {\n            if (tim.elapsed() > time_limit_sec) break;\n            auto e = pq.top(); pq.pop();\n            int i = e.i, j = e.j;\n            if (inR[j][i]) continue;\n            if (e.ver != ver[j][i]) continue;\n            unsigned char mask = nmask[j][i];\n            int dper = delta_perim_for_cell(i, j, mask);\n            int sc = W[j][i];\n            if (mode == 0) {\n                if (sc <= 0 && dper >= 0) continue;\n            } else {\n                double gain = (double)sc - lambda * (double)dper;\n                if (gain <= 0.0) continue;\n            }\n            if (perim + dper > PERIM_LIMIT) continue;\n            add_cell(i, j);\n        }\n\n        auto inside2 = fill_holes(inR);\n        prune_negative_leaves(inside2);\n        long long dummy = 0;\n        inside2 = best_component(inside2, dummy);\n\n        GrowResult gr;\n        gr.inside = move(inside2);\n        gr.approxScore = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (gr.inside[j][i]) gr.approxScore += W[j][i];\n        gr.perim = compute_perimeter(gr.inside);\n        gr.valid = true;\n        return gr;\n    }\n\n    vector<pair<int,int>> inside_to_polygon(const vector<vector<char>>& inside) const {\n        struct KeyHash { size_t operator()(const uint64_t& k) const noexcept { return std::hash<uint64_t>{}(k); } };\n        auto keyOf = [&](int x, int y)->uint64_t { return (uint64_t)((uint32_t)x) << 32 | (uint32_t)y; };\n        unordered_map<uint64_t, int, KeyHash> id;\n        vector<pair<int,int>> verts;\n        vector<vector<int>> adj;\n\n        auto get_id = [&](int x, int y)->int {\n            uint64_t key = keyOf(x, y);\n            auto it = id.find(key);\n            if (it != id.end()) return it->second;\n            int idx = (int)verts.size();\n            verts.emplace_back(x, y);\n            adj.emplace_back();\n            id.emplace(key, idx);\n            return idx;\n        };\n        auto add_edge = [&](int x1, int y1, int x2, int y2){\n            if (x1 == x2 && y1 == y2) return;\n            int a = get_id(x1, y1);\n            int b = get_id(x2, y2);\n            adj[a].push_back(b);\n            adj[b].push_back(a);\n        };\n\n        for (int j = 0; j < G; ++j) {\n            for (int i = 0; i < G; ++i) {\n                if (!inside[j][i]) continue;\n                int x0 = xs[i], x1 = xs[i+1];\n                int y0 = ys[j], y1 = ys[j+1];\n                if (i == 0 || !inside[j][i-1]) add_edge(x0, y0, x0, y1);\n                if (i+1 == G || !inside[j][i+1]) add_edge(x1, y0, x1, y1);\n                if (j == 0 || !inside[j-1][i]) add_edge(x0, y0, x1, y0);\n                if (j+1 == G || !inside[j+1][i]) add_edge(x0, y1, x1, y1);\n            }\n        }\n        if (verts.empty()) return {};\n        // Start at minimal (y,x)\n        int start = 0;\n        for (int i = 1; i < (int)verts.size(); ++i) {\n            if (verts[i].second < verts[start].second ||\n                (verts[i].second == verts[start].second && verts[i].first < verts[start].first)) {\n                start = i;\n            }\n        }\n        vector<int> path;\n        int cur = start, prev = -1;\n        for (int step = 0; step < 400000; ++step) {\n            path.push_back(cur);\n            int next = -1;\n            for (int nb : adj[cur]) {\n                if (nb == prev) continue;\n                next = nb; break;\n            }\n            if (next == -1) {\n                if (!adj[cur].empty()) next = adj[cur][0];\n                else break;\n            }\n            prev = cur;\n            cur = next;\n            if (cur == start) break;\n        }\n        vector<pair<int,int>> poly;\n        for (int idv : path) poly.push_back(verts[idv]);\n        if (!poly.empty() && poly.front() == poly.back()) poly.pop_back();\n        // remove consecutive duplicates\n        vector<pair<int,int>> tmp;\n        for (auto &p : poly) { if (!tmp.empty() && tmp.back() == p) continue; tmp.push_back(p); }\n        poly.swap(tmp);\n        // simplify collinear\n        if (poly.size() >= 3) {\n            vector<pair<int,int>> simp;\n            int m = (int)poly.size();\n            for (int i = 0; i < m; ++i) {\n                auto p0 = poly[(i + m - 1) % m];\n                auto p1 = poly[i];\n                auto p2 = poly[(i + 1) % m];\n                bool col = ( (p0.first == p1.first && p1.first == p2.first) ||\n                             (p0.second == p1.second && p1.second == p2.second) );\n                if (!col) simp.push_back(p1);\n            }\n            poly.swap(simp);\n        }\n        return poly;\n    }\n};\n\n// Rectangle refinement baseline\nstruct Rect {\n    int L, R, B, T;\n    long long perim() const { return 2LL * (max(0, R - L) + max(0, T - B)); }\n    void ensure_min_size() {\n        L = max(L, 0); B = max(B, 0); R = min(R, LIM); T = min(T, LIM);\n        if (L >= R) { if (L > 0) L = R - 1; else R = L + 1; }\n        if (B >= T) { if (B > 0) B = T - 1; else T = B + 1; }\n        L = max(L, 0); B = max(B, 0); R = min(R, LIM); T = min(T, LIM);\n    }\n};\nstruct ColData { vector<int> xs; vector<vector<int>> ys; vector<vector<int>> pref; };\nstruct RowData { vector<int> ys; vector<vector<int>> xs; vector<vector<int>> pref; };\n\nstruct Refiner {\n    const ColData &col; const RowData &row;\n    Refiner(const ColData& c, const RowData& r): col(c), row(r) {}\n    inline int col_sum_idx(int xi, int B, int T) const {\n        if (xi < 0 || xi >= (int)col.xs.size()) return 0;\n        const auto &ysv = col.ys[xi]; const auto &pf = col.pref[xi];\n        auto itL = lower_bound(ysv.begin(), ysv.end(), B);\n        auto itR = upper_bound(ysv.begin(), ysv.end(), T);\n        int l = (int)(itL - ysv.begin()), r = (int)(itR - ysv.begin());\n        return pf[r] - pf[l];\n    }\n    inline int row_sum_idx(int yi, int L, int R) const {\n        if (yi < 0 || yi >= (int)row.ys.size()) return 0;\n        const auto &xsv = row.xs[yi]; const auto &pf = row.pref[yi];\n        auto itL = lower_bound(xsv.begin(), xsv.end(), L);\n        auto itR = upper_bound(xsv.begin(), xsv.end(), R);\n        int l = (int)(itL - xsv.begin()), r = (int)(itR - xsv.begin());\n        return pf[r] - pf[l];\n    }\n    pair<long long,int> best_expand_left(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.L};\n        int kmax = (int)min<long long>(r.L, remain / 2); if (kmax <= 0) return {0, r.L};\n        int idx = (int)(lower_bound(col.xs.begin(), col.xs.end(), r.L) - col.xs.begin()) - 1;\n        if (idx < 0) return {0, r.L};\n        int xLower = r.L - kmax; long long best = 0, run = 0; int bestL = r.L;\n        for (int i = idx; i >= 0; --i) {\n            int x = col.xs[i]; if (x < xLower) break;\n            run += col_sum_idx(i, r.B, r.T);\n            if (run > best) { best = run; bestL = x; }\n        }\n        return {best, bestL};\n    }\n    pair<long long,int> best_shrink_left(const Rect& r) const {\n        if (r.L >= r.R) return {0, r.L};\n        int targetMax = r.R - 1;\n        int iL = (int)(lower_bound(col.xs.begin(), col.xs.end(), r.L) - col.xs.begin());\n        int iR = (int)(upper_bound(col.xs.begin(), col.xs.end(), targetMax) - col.xs.begin()) - 1;\n        if (iL > iR) return {0, r.L};\n        long long best = 0, run = 0; int bestL = r.L;\n        for (int i = iL; i <= iR; ++i) {\n            run += - (long long)col_sum_idx(i, r.B, r.T);\n            if (run > best) {\n                best = run;\n                int newL = col.xs[i] + 1; if (newL > targetMax) newL = targetMax;\n                bestL = newL;\n            }\n        }\n        return {best, bestL};\n    }\n    pair<long long,int> best_expand_right(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.R};\n        int kmax = (int)min<long long>(LIM - r.R, remain / 2); if (kmax <= 0) return {0, r.R};\n        int idx = (int)(upper_bound(col.xs.begin(), col.xs.end(), r.R) - col.xs.begin());\n        if (idx >= (int)col.xs.size()) return {0, r.R};\n        int xUpper = r.R + kmax; long long best = 0, run = 0; int bestR = r.R;\n        for (int i = idx; i < (int)col.xs.size(); ++i) {\n            int x = col.xs[i]; if (x > xUpper) break;\n            run += col_sum_idx(i, r.B, r.T);\n            if (run > best) { best = run; bestR = x; }\n        }\n        return {best, bestR};\n    }\n    pair<long long,int> best_shrink_right(const Rect& r) const {\n        if (r.L >= r.R) return {0, r.R};\n        int targetMin = r.L + 1;\n        int iL = (int)(lower_bound(col.xs.begin(), col.xs.end(), targetMin) - col.xs.begin());\n        int iR = (int)(upper_bound(col.xs.begin(), col.xs.end(), r.R) - col.xs.begin()) - 1;\n        if (iL > iR) return {0, r.R};\n        long long best = 0, run = 0; int bestR = r.R;\n        for (int i = iR; i >= iL; --i) {\n            run += - (long long)col_sum_idx(i, r.B, r.T);\n            if (run > best) {\n                best = run;\n                int newR = col.xs[i] - 1; if (newR < targetMin) newR = targetMin;\n                bestR = newR;\n            }\n        }\n        return {best, bestR};\n    }\n    pair<long long,int> best_expand_bottom(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.B};\n        int kmax = (int)min<long long>(r.B, remain / 2); if (kmax <= 0) return {0, r.B};\n        int idx = (int)(lower_bound(row.ys.begin(), row.ys.end(), r.B) - row.ys.begin()) - 1;\n        if (idx < 0) return {0, r.B};\n        int yLower = r.B - kmax; long long best = 0, run = 0; int bestB = r.B;\n        for (int i = idx; i >= 0; --i) {\n            int y = row.ys[i]; if (y < yLower) break;\n            run += row_sum_idx(i, r.L, r.R);\n            if (run > best) { best = run; bestB = y; }\n        }\n        return {best, bestB};\n    }\n    pair<long long,int> best_shrink_bottom(const Rect& r) const {\n        if (r.B >= r.T) return {0, r.B};\n        int targetMax = r.T - 1;\n        int iL = (int)(lower_bound(row.ys.begin(), row.ys.end(), r.B) - row.ys.begin());\n        int iR = (int)(upper_bound(row.ys.begin(), row.ys.end(), targetMax) - row.ys.begin()) - 1;\n        if (iL > iR) return {0, r.B};\n        long long best = 0, run = 0; int bestB = r.B;\n        for (int i = iL; i <= iR; ++i) {\n            run += - (long long)row_sum_idx(i, r.L, r.R);\n            if (run > best) {\n                best = run;\n                int newB = row.ys[i] + 1; if (newB > targetMax) newB = targetMax;\n                bestB = newB;\n            }\n        }\n        return {best, bestB};\n    }\n    pair<long long,int> best_expand_top(const Rect& r, long long curPerim) const {\n        long long remain = PERIM_LIMIT - curPerim; if (remain < 2) return {0, r.T};\n        int kmax = (int)min<long long>(LIM - r.T, remain / 2); if (kmax <= 0) return {0, r.T};\n        int idx = (int)(upper_bound(row.ys.begin(), row.ys.end(), r.T) - row.ys.begin());\n        if (idx >= (int)row.ys.size()) return {0, r.T};\n        int yUpper = r.T + kmax; long long best = 0, run = 0; int bestT = r.T;\n        for (int i = idx; i < (int)row.ys.size(); ++i) {\n            int y = row.ys[i]; if (y > yUpper) break;\n            run += row_sum_idx(i, r.L, r.R);\n            if (run > best) { best = run; bestT = y; }\n        }\n        return {best, bestT};\n    }\n    pair<long long,int> best_shrink_top(const Rect& r) const {\n        if (r.B >= r.T) return {0, r.T};\n        int targetMin = r.B + 1;\n        int iL = (int)(lower_bound(row.ys.begin(), row.ys.end(), targetMin) - row.ys.begin());\n        int iR = (int)(upper_bound(row.ys.begin(), row.ys.end(), r.T) - row.ys.begin()) - 1;\n        if (iL > iR) return {0, r.T};\n        long long best = 0, run = 0; int bestT = r.T;\n        for (int i = iR; i >= iL; --i) {\n            run += - (long long)row_sum_idx(i, r.L, r.R);\n            if (run > best) {\n                best = run;\n                int newT = row.ys[i] - 1; if (newT < targetMin) newT = targetMin;\n                bestT = newT;\n            }\n        }\n        return {best, bestT};\n    }\n    Rect refine(Rect r) const {\n        r.ensure_min_size();\n        long long curPerim = r.perim();\n        for (int it = 0; it < 200; ++it) {\n            array<long long, 8> delta{};\n            array<int, 8> newCoord{};\n            auto [d0, nl0] = best_expand_left(r, curPerim); delta[0] = d0; newCoord[0] = nl0;\n            auto [d1, nl1] = best_shrink_left(r);         delta[1] = d1; newCoord[1] = nl1;\n            auto [d2, nr2] = best_expand_right(r, curPerim);delta[2] = d2; newCoord[2] = nr2;\n            auto [d3, nr3] = best_shrink_right(r);        delta[3] = d3; newCoord[3] = nr3;\n            auto [d4, nb4] = best_expand_bottom(r, curPerim);delta[4] = d4; newCoord[4] = nb4;\n            auto [d5, nb5] = best_shrink_bottom(r);       delta[5] = d5; newCoord[5] = nb5;\n            auto [d6, nt6] = best_expand_top(r, curPerim);delta[6] = d6; newCoord[6] = nt6;\n            auto [d7, nt7] = best_shrink_top(r);          delta[7] = d7; newCoord[7] = nt7;\n            long long bestDelta = 0; int bestMove = -1;\n            for (int k = 0; k < 8; ++k) if (delta[k] > bestDelta) { bestDelta = delta[k]; bestMove = k; }\n            if (bestDelta <= 0) break;\n            if (bestMove == 0) { int oldL = r.L; r.L = newCoord[0]; curPerim += 2LL * (oldL - r.L); }\n            else if (bestMove == 1) { int oldL = r.L; r.L = newCoord[1]; curPerim -= 2LL * (r.L - oldL); }\n            else if (bestMove == 2) { int oldR = r.R; r.R = newCoord[2]; curPerim += 2LL * (r.R - oldR); }\n            else if (bestMove == 3) { int oldR = r.R; r.R = newCoord[3]; curPerim -= 2LL * (oldR - r.R); }\n            else if (bestMove == 4) { int oldB = r.B; r.B = newCoord[4]; curPerim += 2LL * (oldB - r.B); }\n            else if (bestMove == 5) { int oldB = r.B; r.B = newCoord[5]; curPerim -= 2LL * (r.B - oldB); }\n            else if (bestMove == 6) { int oldT = r.T; r.T = newCoord[6]; curPerim += 2LL * (r.T - oldT); }\n            else if (bestMove == 7) { int oldT = r.T; r.T = newCoord[7]; curPerim -= 2LL * (oldT - r.T); }\n            r.ensure_min_size();\n            if (curPerim > PERIM_LIMIT) {\n                while (r.perim() > PERIM_LIMIT && r.R - r.L > 1) --r.R;\n                while (r.perim() > PERIM_LIMIT && r.T - r.B > 1) --r.T;\n                curPerim = r.perim();\n            }\n        }\n        r.ensure_min_size();\n        return r;\n    }\n};\n\n// Pair-of-components connection heuristic\nstruct PairConnector {\n    int G;\n    vector<vector<int>> W;\n    vector<int> xs, ys;\n    RegionGrower grower;\n\n    PairConnector(int G_, const vector<vector<int>>& W_, const vector<int>& xs_, const vector<int>& ys_)\n        : G(G_), W(W_), xs(xs_), ys(ys_), grower(G_, W_, xs_, ys_) {}\n\n    struct Comp {\n        long long sum = 0;\n        vector<pair<int,int>> cells;\n        vector<pair<int,int>> border;\n    };\n\n    vector<Comp> top_positive_components(int K) {\n        vector<vector<char>> vis(G, vector<char>(G, 0));\n        vector<Comp> comps;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) {\n            if (vis[j][i] || W[j][i] <= 0) continue;\n            Comp c;\n            deque<pair<int,int>> dq;\n            dq.emplace_back(i,j);\n            vis[j][i] = 1;\n            while (!dq.empty()) {\n                auto [ci, cj] = dq.front(); dq.pop_front();\n                c.cells.emplace_back(ci, cj);\n                c.sum += W[cj][ci];\n                bool isBorder = false;\n                auto try_push = [&](int ni, int nj) {\n                    if (ni<0||ni>=G||nj<0||nj>=G) { isBorder = true; return; }\n                    if (W[nj][ni] <= 0) { isBorder = true; return; }\n                    if (vis[nj][ni]) return;\n                    vis[nj][ni] = 1; dq.emplace_back(ni, nj);\n                };\n                try_push(ci-1,cj); try_push(ci+1,cj); try_push(ci,cj-1); try_push(ci,cj+1);\n                if (isBorder) c.border.emplace_back(ci, cj);\n            }\n            comps.push_back(move(c));\n        }\n        sort(comps.begin(), comps.end(), [](const Comp& a, const Comp& b){ return a.sum > b.sum; });\n        if ((int)comps.size() > K) comps.resize(K);\n        return comps;\n    }\n\n    Candidate connect_two(const Comp& A, const Comp& B) {\n        const long long INF = (1LL<<60);\n        vector<vector<long long>> dist(G, vector<long long>(G, INF));\n        vector<vector<pair<int,int>>> prev(G, vector<pair<int,int>>(G, {-1,-1}));\n        using Node = pair<long long, pair<int,int>>;\n        priority_queue<Node, vector<Node>, greater<Node>> pq;\n        auto inA = vector<vector<char>>(G, vector<char>(G, 0));\n        auto inB = vector<vector<char>>(G, vector<char>(G, 0));\n        for (auto &p : A.cells) inA[p.second][p.first] = 1;\n        for (auto &p : B.cells) inB[p.second][p.first] = 1;\n\n        for (auto &p : A.border) {\n            int i = p.first, j = p.second;\n            dist[j][i] = 0;\n            pq.push({0, {i,j}});\n        }\n\n        auto cell_cost = [&](int i, int j)->long long {\n            long long c = (W[j][i] < 0 ? -W[j][i] : 0);\n            return c + 1;\n        };\n\n        pair<int,int> meet = {-1,-1};\n        vector<int> di = {-1,1,0,0};\n        vector<int> dj = {0,0,-1,1};\n        while (!pq.empty()) {\n            auto [d, ij] = pq.top(); pq.pop();\n            int i = ij.first, j = ij.second;\n            if (d != dist[j][i]) continue;\n            if (inB[j][i]) { meet = {i,j}; break; }\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + di[dir], nj = j + dj[dir];\n                if (ni < 0 || ni >= G || nj < 0 || nj >= G) continue;\n                long long nd = d + cell_cost(ni, nj);\n                if (nd < dist[nj][ni]) {\n                    dist[nj][ni] = nd;\n                    prev[nj][ni] = {i,j};\n                    pq.push({nd, {ni, nj}});\n                }\n            }\n        }\n\n        vector<vector<char>> inside(G, vector<char>(G, 0));\n        for (auto &p : A.cells) inside[p.second][p.first] = 1;\n        for (auto &p : B.cells) inside[p.second][p.first] = 1;\n\n        if (meet.first != -1) {\n            int ci = meet.first, cj = meet.second;\n            while (prev[cj][ci].first != -1) {\n                if (!inA[cj][ci] && !inB[cj][ci]) inside[cj][ci] = 1;\n                auto pr = prev[cj][ci];\n                ci = pr.first; cj = pr.second;\n            }\n        }\n\n        // Clean\n        inside = grower.fill_holes(inside);\n        grower.prune_negative_leaves(inside);\n        long long approxScore = 0;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (inside[j][i]) approxScore += W[j][i];\n\n        // Shrink to fit if needed\n        grower.shrink_to_fit(inside, approxScore);\n\n        // Light saturation and shrink again\n        {\n            Timer loc;\n            auto s1 = grower.grow_from_mask(inside, 0, 0.0, 0.008, loc);\n            if (s1.valid) { inside = move(s1.inside); approxScore = s1.approxScore; }\n            Timer loc2;\n            auto s2 = grower.grow_from_mask(inside, 1, 0.0035, 0.006, loc2);\n            if (s2.valid) { inside = move(s2.inside); approxScore = s2.approxScore; }\n            grower.shrink_to_fit(inside, approxScore);\n        }\n\n        auto poly = grower.inside_to_polygon(inside);\n        Candidate c;\n        c.poly = move(poly);\n        c.approxScore = approxScore;\n        return c;\n    }\n};\n\n// Greedy multi-component connector with saturation and multi-start\nstruct GreedyConnector {\n    int G;\n    vector<vector<int>> W;\n    vector<int> xs, ys;\n    RegionGrower grower;\n\n    GreedyConnector(int G_, const vector<vector<int>>& W_, const vector<int>& xs_, const vector<int>& ys_)\n        : G(G_), W(W_), xs(xs_), ys(ys_), grower(G_, W_, xs_, ys_) {}\n\n    using Comp = PairConnector::Comp;\n\n    vector<Comp> top_positive_components(int K) {\n        PairConnector pc(G, W, xs, ys);\n        return pc.top_positive_components(K);\n    }\n\n    Candidate build_greedy_from(int startIdx, int topKComps, int maxConnect, double time_budget_sec) {\n        Candidate empty;\n        auto comps = top_positive_components(topKComps);\n        if ((int)comps.size() <= startIdx) return empty;\n\n        vector<vector<char>> inside(G, vector<char>(G, 0));\n        vector<char> used(comps.size(), 0);\n        for (auto &p : comps[startIdx].cells) inside[p.second][p.first] = 1;\n        used[startIdx] = 1;\n\n        auto compute_inside_score = [&]()->long long {\n            long long s = 0;\n            for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (inside[j][i]) s += W[j][i];\n            return s;\n        };\n        long long approxScore = compute_inside_score();\n\n        auto dijkstra_from_inside = [&](vector<vector<long long>>& dist, vector<vector<pair<int,int>>>& prev) {\n            const long long INF = (1LL<<60);\n            dist.assign(G, vector<long long>(G, INF));\n            prev.assign(G, vector<pair<int,int>>(G, {-1,-1}));\n            using Node = pair<long long, pair<int,int>>;\n            priority_queue<Node, vector<Node>, greater<Node>> pq;\n            auto is_boundary = [&](int i, int j)->bool {\n                if (!inside[j][i]) return false;\n                if (i==0 || !inside[j][i-1]) return true;\n                if (i+1==G || !inside[j][i+1]) return true;\n                if (j==0 || !inside[j-1][i]) return true;\n                if (j+1==G || !inside[j+1][i]) return true;\n                return false;\n            };\n            for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (is_boundary(i,j)) {\n                dist[j][i] = 0; pq.push({0, {i,j}});\n            }\n            auto step_cost = [&](int ni, int nj)->long long {\n                if (inside[nj][ni]) return 0;\n                long long c = (W[nj][ni] < 0 ? -W[nj][ni] : 0);\n                return c + 1;\n            };\n            vector<int> di = {-1,1,0,0};\n            vector<int> dj = {0,0,-1,1};\n            while (!pq.empty()) {\n                auto [d, ij] = pq.top(); pq.pop();\n                int i = ij.first, j = ij.second;\n                if (d != dist[j][i]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + di[dir], nj = j + dj[dir];\n                    if (ni < 0 || ni >= G || nj < 0 || nj >= G) continue;\n                    long long nd = d + step_cost(ni, nj);\n                    if (nd < dist[nj][ni]) {\n                        dist[nj][ni] = nd;\n                        prev[nj][ni] = {i,j};\n                        pq.push({nd, {ni, nj}});\n                    }\n                }\n            }\n        };\n\n        for (int iter = 0; iter < maxConnect; ++iter) {\n            vector<vector<long long>> dist;\n            vector<vector<pair<int,int>>> prev;\n            dijkstra_from_inside(dist, prev);\n\n            long long bestGain = 0;\n            int bestIdx = -1;\n            vector<pair<int,int>> bestPath;\n            vector<vector<char>> bestInsideFilled;\n            long long bestNewScore = approxScore;\n\n            for (int idx = 0; idx < (int)comps.size(); ++idx) if (!used[idx]) {\n                long long bestD = (1LL<<60);\n                pair<int,int> enter = {-1,-1};\n                for (auto &p : comps[idx].border) {\n                    int i = p.first, j = p.second;\n                    if (dist[j][i] < bestD) { bestD = dist[j][i]; enter = p; }\n                }\n                if (enter.first == -1 || bestD >= (1LL<<60)) continue;\n                vector<pair<int,int>> path;\n                int ci = enter.first, cj = enter.second;\n                while (prev[cj][ci].first != -1) {\n                    if (!inside[cj][ci]) path.emplace_back(ci, cj);\n                    auto pr = prev[cj][ci];\n                    ci = pr.first; cj = pr.second;\n                }\n                vector<vector<char>> in2 = inside;\n                for (auto &p : comps[idx].cells) in2[p.second][p.first] = 1;\n                for (auto &p : path) in2[p.second][p.first] = 1;\n                in2 = grower.fill_holes(in2);\n                grower.prune_negative_leaves(in2);\n                long long per = grower.compute_perimeter(in2);\n                if (per > PERIM_LIMIT) continue;\n                long long sc = 0;\n                for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (in2[j][i]) sc += W[j][i];\n                long long gain = sc - approxScore;\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestIdx = idx;\n                    bestPath = path;\n                    bestInsideFilled = move(in2);\n                    bestNewScore = sc;\n                }\n            }\n            if (bestIdx == -1) break;\n            for (auto &p : comps[bestIdx].cells) inside[p.second][p.first] = 1;\n            for (auto &p : bestPath) inside[p.second][p.first] = 1;\n            used[bestIdx] = 1;\n            approxScore = bestNewScore;\n            inside = bestInsideFilled;\n        }\n\n        // Saturation and shrink\n        {\n            Timer loc;\n            auto s1 = grower.grow_from_mask(inside, 0, 0.0, time_budget_sec * 0.6, loc);\n            if (s1.valid) { inside = move(s1.inside); approxScore = s1.approxScore; }\n            Timer loc2;\n            auto s2 = grower.grow_from_mask(inside, 1, 0.0035, time_budget_sec * 0.4, loc2);\n            if (s2.valid) { inside = move(s2.inside); approxScore = s2.approxScore; }\n            grower.shrink_to_fit(inside, approxScore);\n        }\n\n        auto poly = grower.inside_to_polygon(inside);\n        Candidate c;\n        c.poly = move(poly);\n        c.approxScore = approxScore;\n        return c;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<Pt> pts;\n    pts.reserve(2*N);\n    for (int i = 0; i < N; ++i) { int x,y; cin >> x >> y; pts.push_back({x,y,+1}); }\n    for (int i = 0; i < N; ++i) { int x,y; cin >> x >> y; pts.push_back({x,y,-1}); }\n\n    Timer tim;\n    const double TL = 1.98;\n\n    vector<Candidate> finalCandidates;\n\n    // Rectangle refiner preprocessing\n    ColData col; RowData row;\n    {\n        vector<int> allX, allY;\n        allX.reserve(pts.size()); allY.reserve(pts.size());\n        for (auto &p : pts) { allX.push_back(p.x); allY.push_back(p.y); }\n        sort(allX.begin(), allX.end()); allX.erase(unique(allX.begin(), allX.end()), allX.end());\n        sort(allY.begin(), allY.end()); allY.erase(unique(allY.begin(), allY.end()), allY.end());\n        col.xs = allX; row.ys = allY;\n        col.ys.assign(col.xs.size(), {}); col.pref.assign(col.xs.size(), {});\n        row.xs.assign(row.ys.size(), {}); row.pref.assign(row.ys.size(), {});\n        vector<vector<pair<int,int>>> tempX(col.xs.size());\n        vector<vector<pair<int,int>>> tempY(row.ys.size());\n        for (const auto& p : pts) {\n            int xi = (int)(lower_bound(col.xs.begin(), col.xs.end(), p.x) - col.xs.begin());\n            int yi = (int)(lower_bound(row.ys.begin(), row.ys.end(), p.y) - row.ys.begin());\n            tempX[xi].emplace_back(p.y, p.w);\n            tempY[yi].emplace_back(p.x, p.w);\n        }\n        for (size_t i = 0; i < tempX.size(); ++i) {\n            auto &vec = tempX[i];\n            sort(vec.begin(), vec.end());\n            vector<int> ysMerged; vector<int> wsMerged;\n            ysMerged.reserve(vec.size()); wsMerged.reserve(vec.size());\n            for (size_t k = 0; k < vec.size();) {\n                int y = vec[k].first; int s = 0; size_t k2 = k;\n                while (k2 < vec.size() && vec[k2].first == y) { s += vec[k2].second; ++k2; }\n                ysMerged.push_back(y); wsMerged.push_back(s); k = k2;\n            }\n            col.ys[i] = move(ysMerged);\n            col.pref[i].assign(wsMerged.size()+1, 0);\n            for (size_t t = 0; t < wsMerged.size(); ++t) col.pref[i][t+1] = col.pref[i][t] + wsMerged[t];\n        }\n        for (size_t i = 0; i < tempY.size(); ++i) {\n            auto &vec = tempY[i];\n            sort(vec.begin(), vec.end());\n            vector<int> xsMerged; vector<int> wsMerged;\n            xsMerged.reserve(vec.size()); wsMerged.reserve(vec.size());\n            for (size_t k = 0; k < vec.size();) {\n                int x = vec[k].first; int s = 0; size_t k2 = k;\n                while (k2 < vec.size() && vec[k2].first == x) { s += vec[k2].second; ++k2; }\n                xsMerged.push_back(x); wsMerged.push_back(s); k = k2;\n            }\n            row.xs[i] = move(xsMerged);\n            row.pref[i].assign(wsMerged.size()+1, 0);\n            for (size_t t = 0; t < wsMerged.size(); ++t) row.pref[i][t+1] = row.pref[i][t] + wsMerged[t];\n        }\n    }\n    Refiner ref(col, row);\n\n    // Rectangle seeds from coarse grids with refinement\n    vector<int> Gs_rect = {64, 96, 128};\n    for (int G : Gs_rect) {\n        if (tim.elapsed() > TL * 0.50) break;\n        auto Wg = build_grid_W(G, pts);\n        auto rr = coarse_best_rect_from_W(Wg);\n        vector<int> xs, ys; build_grid_lines(G, xs, ys);\n        vector<pair<int,int>> poly = rect_to_polygon(rr, xs, ys);\n        Rect r{poly[0].first, poly[1].first, poly[0].second, poly[2].second};\n        r.ensure_min_size();\n        Rect refined = ref.refine(r);\n        vector<pair<int,int>> poly2 = {\n            {refined.L, refined.B}, {refined.R, refined.B}, {refined.R, refined.T}, {refined.L, refined.T}\n        };\n        long long peri = polygon_perimeter(poly2);\n        if (peri <= PERIM_LIMIT) {\n            Candidate cand; cand.poly = move(poly2);\n            cand.exactScore = exact_score_polygon(cand.poly, pts);\n            cand.approxScore = cand.exactScore;\n            finalCandidates.push_back(move(cand));\n        }\n    }\n\n    // Full area rectangle as fallback\n    {\n        vector<pair<int,int>> poly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n        Candidate cand; cand.poly = move(poly);\n        cand.exactScore = exact_score_polygon(cand.poly, pts);\n        cand.approxScore = cand.exactScore;\n        finalCandidates.push_back(move(cand));\n    }\n\n    // Multi-scale region growth with saturation\n    struct GridCfg { int G; int maxSeeds; int minSep; vector<double> lambdas; int keepPerGrid; };\n    vector<GridCfg> grids = {\n        {96, 6, 4, {0.0025, 0.005, 0.01}, 6},\n        {128, 5, 4, {0.0025, 0.005}, 6},\n        {160, 3, 4, {0.003, 0.006}, 4},\n        {72,  4, 3, {0.005, 0.01}, 4}\n    };\n\n    double growth_end_time = min(1.55, TL - 0.35);\n    vector<Candidate> regionCandidates;\n\n    for (auto cfg : grids) {\n        if (tim.elapsed() > growth_end_time) break;\n        int G = cfg.G;\n        auto Wg = build_grid_W(G, pts);\n        vector<int> xs, ys; build_grid_lines(G, xs, ys);\n        RegionGrower grower(G, Wg, xs, ys);\n\n        // seeds: components + best cells\n        struct Cell { int w, i, j; };\n        vector<Cell> cells;\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (Wg[j][i] > 0) cells.push_back({Wg[j][i], i, j});\n        sort(cells.begin(), cells.end(), [](const Cell& a, const Cell& b){\n            if (a.w != b.w) return a.w > b.w;\n            if (a.j != b.j) return a.j < b.j;\n            return a.i < b.i;\n        });\n        vector<pair<int,int>> seeds;\n        vector<vector<char>> vis(G, vector<char>(G, 0));\n        for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) {\n            if (vis[j][i] || Wg[j][i] <= 0) continue;\n            int bestI = i, bestJ = j, bestW = Wg[j][i];\n            deque<pair<int,int>> dq; dq.emplace_back(i,j); vis[j][i] = 1;\n            while (!dq.empty()) {\n                auto [ci, cj] = dq.front(); dq.pop_front();\n                int cw = Wg[cj][ci];\n                if (cw > bestW) { bestW = cw; bestI = ci; bestJ = cj; }\n                auto try_push = [&](int ni, int nj) {\n                    if (ni<0||ni>=G||nj<0||nj>=G) return;\n                    if (vis[nj][ni]) return;\n                    if (Wg[nj][ni] <= 0) return;\n                    vis[nj][ni] = 1; dq.emplace_back(ni,nj);\n                };\n                try_push(ci-1,cj); try_push(ci+1,cj); try_push(ci,cj-1); try_push(ci,cj+1);\n            }\n            seeds.emplace_back(bestI, bestJ);\n        }\n        for (const auto& c : cells) {\n            bool ok = true;\n            for (auto [si, sj] : seeds) if (abs(si - c.i) + abs(sj - c.j) < cfg.minSep) { ok = false; break; }\n            if (!ok) continue;\n            seeds.emplace_back(c.i, c.j);\n            if ((int)seeds.size() >= cfg.maxSeeds) break;\n        }\n        if (seeds.empty()) {\n            int bi=0,bj=0,bw=INT_MIN;\n            for (int j = 0; j < G; ++j) for (int i = 0; i < G; ++i) if (Wg[j][i] > bw) { bw = Wg[j][i]; bi=i; bj=j; }\n            seeds.emplace_back(bi,bj);\n        }\n\n        auto consider_inside = [&](const vector<vector<char>>& inside, long long approxScore) {\n            auto poly = grower.inside_to_polygon(inside);\n            if (poly.empty()) return;\n            long long peri = polygon_perimeter(poly);\n            if (peri > PERIM_LIMIT) return;\n            if ((int)poly.size() > 1000) return;\n            Candidate c; c.poly = move(poly); c.approxScore = approxScore;\n            regionCandidates.push_back(move(c));\n        };\n\n        double time_limit_sec = TL - 0.15;\n        for (auto [si, sj] : seeds) {\n            if (tim.elapsed() > growth_end_time) break;\n            // ratio growth\n            {\n                auto gr = grower.grow_from_seed(si, sj, 0, 0.0, time_limit_sec, tim);\n                if (gr.valid) {\n                    consider_inside(gr.inside, gr.approxScore);\n                    if (tim.elapsed() > growth_end_time) break;\n                    auto gr2 = grower.grow_from_mask(gr.inside, 0, 0.0, time_limit_sec, tim);\n                    if (gr2.valid) consider_inside(gr2.inside, gr2.approxScore);\n                }\n            }\n            // lambda growth\n            for (double lam : cfg.lambdas) {\n                if (tim.elapsed() > growth_end_time) break;\n                auto gr = grower.grow_from_seed(si, sj, 1, lam, time_limit_sec, tim);\n                if (gr.valid) {\n                    consider_inside(gr.inside, gr.approxScore);\n                    if (tim.elapsed() > growth_end_time) break;\n                    auto gr2 = grower.grow_from_mask(gr.inside, 0, 0.0, time_limit_sec, tim);\n                    if (gr2.valid) consider_inside(gr2.inside, gr2.approxScore);\n                }\n            }\n        }\n    }\n\n    // Pair-of-components connection heuristic on a fine grid (top 5 comps) with saturation/shrink\n    {\n        int G = 128;\n        auto Wg = build_grid_W(G, pts);\n        vector<int> xs, ys; build_grid_lines(G, xs, ys);\n        PairConnector pc(G, Wg, xs, ys);\n        auto comps = pc.top_positive_components(5);\n        int C = (int)comps.size();\n        for (int a = 0; a < C; ++a) for (int b = a+1; b < C; ++b) {\n            auto cand = pc.connect_two(comps[a], comps[b]);\n            if (!cand.poly.empty()) {\n                long long peri = polygon_perimeter(cand.poly);\n                if (peri <= PERIM_LIMIT && (int)cand.poly.size() <= 1000) {\n                    regionCandidates.push_back(move(cand));\n                }\n            }\n        }\n    }\n\n    // Greedy multi-component connector with saturation and two starts\n    {\n        int G = 128;\n        auto Wg = build_grid_W(G, pts);\n        vector<int> xs, ys; build_grid_lines(G, xs, ys);\n        GreedyConnector gc(G, Wg, xs, ys);\n        auto cand0 = gc.build_greedy_from(0, 6, 4, 0.05);\n        if (!cand0.poly.empty() && polygon_perimeter(cand0.poly) <= PERIM_LIMIT && (int)cand0.poly.size() <= 1000) {\n            regionCandidates.push_back(move(cand0));\n        }\n        auto cand1 = gc.build_greedy_from(1, 6, 4, 0.05);\n        if (!cand1.poly.empty() && polygon_perimeter(cand1.poly) <= PERIM_LIMIT && (int)cand1.poly.size() <= 1000) {\n            regionCandidates.push_back(move(cand1));\n        }\n    }\n\n    // Keep top region candidates by approx and compute exact for best K within time\n    sort(regionCandidates.begin(), regionCandidates.end(), [](const Candidate& a, const Candidate& b){\n        return a.approxScore > b.approxScore;\n    });\n    int topK = min(36, (int)regionCandidates.size());\n    double score_time_budget = TL - tim.elapsed() - 0.12; // safety\n    if (score_time_budget < 0) score_time_budget = 0;\n    Timer scoreTim;\n    for (int i = 0; i < topK; ++i) {\n        if (scoreTim.elapsed() > score_time_budget) break;\n        regionCandidates[i].exactScore = exact_score_polygon(regionCandidates[i].poly, pts);\n        finalCandidates.push_back(move(regionCandidates[i]));\n    }\n\n    // Select best exact among all\n    long long bestScore = LLONG_MIN;\n    int bestIdx = -1;\n    for (int i = 0; i < (int)finalCandidates.size(); ++i) {\n        long long sc = finalCandidates[i].exactScore;\n        if (sc > bestScore) { bestScore = sc; bestIdx = i; }\n    }\n\n    vector<pair<int,int>> bestPoly;\n    if (bestIdx >= 0) bestPoly = finalCandidates[bestIdx].poly;\n    else bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n\n    // Sanity constraints\n    if ((int)bestPoly.size() < 4) bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n    long long peri = polygon_perimeter(bestPoly);\n    if (peri > PERIM_LIMIT) {\n        for (int iter = 0; iter < 1000 && peri > PERIM_LIMIT; ++iter) {\n            int maxx = 0, maxy = 0;\n            for (auto &p : bestPoly) { maxx = max(maxx, p.first); maxy = max(maxy, p.second); }\n            for (auto &p : bestPoly) {\n                if (p.first == maxx && maxx > 0) --p.first;\n                if (p.second == maxy && maxy > 0) --p.second;\n            }\n            peri = polygon_perimeter(bestPoly);\n        }\n    }\n    if ((int)bestPoly.size() > 1000) {\n        vector<pair<int,int>> simp;\n        int step = (int)bestPoly.size() / 900 + 1;\n        for (int i = 0; i < (int)bestPoly.size(); i += step) simp.push_back(bestPoly[i]);\n        if (simp.size() < 4) bestPoly = { {0,0},{LIM,0},{LIM,LIM},{0,LIM} };\n        else bestPoly.swap(simp);\n    }\n\n    cout << bestPoly.size() << \"\\n\";\n    for (auto &p : bestPoly) cout << p.first << \" \" << p.second << \"\\n\";\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\n// 64-bit splitmix RNG\nstatic uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct Op {\n    int p;   // rectangle index\n    int r;   // rotation 0/1\n    char d;  // 'U' or 'L'\n    int b;   // base index or -1\n};\n\nstruct Column {\n    long long cw;   // column width (top width)\n    long long ch;   // accumulated height\n    int top_id;     // top rectangle id of this column\n    int last_id;    // last placed rectangle in this column\n};\n\nstruct Param {\n    double lamW;              // base weight for W increase\n    double lamH;              // base weight for H overflow\n    long long fudge;          // base stacking margin (>=0)\n    double fudgeFrac;         // additional margin as fraction of column width\n    double newColBias;        // base bias for opening new column (scaled by avgMin)\n    int lookK;                // lookahead count\n    double fitCountWeight;    // reward per future fit (scaled by avgMin) for new-columns\n    double fitHeightWeight;   // reward per sum of future fitted heights (multiplied with lamH) for new-columns\n    double stackFitCountWeight;   // reward per future fit for stacking (scaled by avgMin)\n    double stackFitHeightWeight;  // reward per sum of future fitted heights (with lamH) for stacking\n    double dynAlpha;          // exponent for dynamic lam adjustment by W/H\n    double progBiasC;         // progress-dependent bias coefficient (scaled by avgMin)\n    double widthCapMul;       // soft width cap multiplier * avgMin\n    double widthCapPenalty;   // penalty coefficient for width exceeding soft cap\n    double minOpenFactor;     // factor for suffix quantile threshold for opening (using q70)\n    double minOpenPenalty;    // penalty scale if cw below threshold (multiplied with lamW)\n    double wideBonusMul;      // bonus coefficient (scaled by avgMin) vs q90 for opening\n    double colCountPenalty;   // penalty per existing column (scaled by avgMin)\n    unsigned tieRand;         // seed for tie-breaking\n    string tag;               // label\n};\n\nstruct PlanResult {\n    vector<Op> ops;\n    long long W_est;\n    long long H_est;\n};\n\nstruct BuildCtx {\n    const vector<long long>& w;\n    const vector<long long>& h;\n    double avgMin;                  // typical instance scale\n    const vector<long long>& q70;   // suffix 70th percentile of min(w,h), length N+1 (q70[N]=0)\n    const vector<long long>& q90;   // suffix 90th percentile of min(w,h), length N+1 (q90[N]=0)\n};\n\n// Core builder (column-based) on given sizes\nstatic PlanResult build_columns_core(const BuildCtx& ctx, const Param& P) {\n    const auto& wp = ctx.w;\n    const auto& hp = ctx.h;\n    int N = (int)wp.size();\n\n    vector<Op> ops; ops.reserve(N);\n    vector<Column> cols; cols.reserve(N);\n\n    long long W = 0, H = 0;\n    int lastTopId = -1;\n    uint64_t rng = splitmix64((uint64_t)P.tieRand + 0x123456789abcdefULL);\n\n    auto future_fit_stats = [&](int iStart, long long capWidth, long long fudgeBase, double fudgeFrac)->pair<int, long long> {\n        long long cap = capWidth - (long long)llround(fudgeBase + fudgeFrac * (double)capWidth);\n        if (cap < 0) cap = 0;\n        int K = max(0, P.lookK);\n        if (K == 0) return {0, 0};\n        int end = min(N, iStart + K);\n        int cnt = 0;\n        long long sumH = 0;\n        for (int j = iStart; j < end; ++j) {\n            bool o0 = (wp[j] <= cap);\n            bool o1 = (hp[j] <= cap);\n            if (!o0 && !o1) continue;\n            ++cnt;\n            long long hmin = (o0 ? hp[j] : (long long)4e18);\n            if (o1) hmin = min(hmin, wp[j]);\n            if (hmin < (long long)4e18) sumH += hmin;\n        }\n        return {cnt, sumH};\n    };\n\n    for (int i = 0; i < N; ++i) {\n        long long w0 = wp[i], h0 = hp[i];\n        long long w1 = hp[i], h1 = wp[i];\n\n        // Dynamic weights by current aspect ratio\n        double Wr = max(1LL, W), Hr = max(1LL, H);\n        double ratio = Wr / Hr;\n        double wfac = (P.dynAlpha != 0.0 ? pow(ratio, P.dynAlpha) : 1.0);\n        double hfac = (P.dynAlpha != 0.0 ? pow(1.0 / ratio, P.dynAlpha) : 1.0);\n        double lamW_eff = max(0.0, P.lamW * wfac);\n        double lamH_eff = max(0.0, P.lamH * hfac);\n\n        // Progress-dependent bias\n        double prog = (N > 1 ? (double)i / (double)(N - 1) : 1.0);\n        double biasEff = P.newColBias + (prog - 0.5) * ctx.avgMin * P.progBiasC;\n\n        // Best stacking candidate\n        bool hasStack = false;\n        int bestCol = -1;\n        int bestRot = 0;\n        double bestCostStack = 1e300;\n        long long bestSlack = LLONG_MAX;   // prioritize minimal slack first\n        long long bestNewColH = LLONG_MAX; // then smaller resulting height\n\n        for (int j = 0; j < (int)cols.size(); ++j) {\n            long long effFudge = P.fudge + (long long)llround(P.fudgeFrac * (double)cols[j].cw);\n            long long cap = cols[j].cw - effFudge;\n            if (cap < 0) cap = 0;\n            bool fit0 = (w0 <= cap);\n            bool fit1 = (w1 <= cap);\n            if (!fit0 && !fit1) continue;\n\n            int rotSel; long long useW, useH;\n            if (fit0 && fit1) {\n                long long newH0 = cols[j].ch + h0;\n                long long newH1 = cols[j].ch + h1;\n                if (newH0 < newH1) { rotSel = 0; useW = w0; useH = h0; }\n                else if (newH1 < newH0) { rotSel = 1; useW = w1; useH = h1; }\n                else {\n                    if (w0 <= w1) { rotSel = 0; useW = w0; useH = h0; }\n                    else { rotSel = 1; useW = w1; useH = h1; }\n                }\n            } else if (fit0) { rotSel = 0; useW = w0; useH = h0; }\n            else { rotSel = 1; useW = w1; useH = h1; }\n\n            long long newColH = cols[j].ch + useH;\n            long long dH = (newColH > H ? (newColH - H) : 0LL);\n            double cost = lamH_eff * (double)dH;\n\n            // Stacking lookahead rewards (prefer columns that will absorb future items)\n            auto st = future_fit_stats(i + 1, cols[j].cw, P.fudge, P.fudgeFrac);\n            int cntFit = st.first;\n            long long sumHFit = st.second;\n            cost -= P.stackFitCountWeight * (double)cntFit;\n            cost -= lamH_eff * P.stackFitHeightWeight * (double)sumHFit;\n\n            long long slack = cols[j].cw - useW;\n            bool better = false;\n            if (!hasStack || cost < bestCostStack) better = true;\n            else if (fabs(cost - bestCostStack) < 1e-12) {\n                if (slack < bestSlack) better = true;\n                else if (slack == bestSlack) {\n                    if (newColH < bestNewColH) better = true;\n                    else if (newColH == bestNewColH) {\n                        rng = splitmix64(rng);\n                        if ((rng & 1ULL) == 0ULL) better = true;\n                    }\n                }\n            }\n\n            if (better) {\n                hasStack = true;\n                bestCol = j;\n                bestRot = rotSel;\n                bestCostStack = cost;\n                bestSlack = slack;\n                bestNewColH = newColH;\n            }\n        }\n\n        // Evaluate opening a new column (both rotations) with lookahead rewards and width soft cap\n        auto eval_newcol = [&](int rot)->tuple<double,long long,long long> {\n            long long cw = (rot==0? w0 : w1);\n            long long ch = (rot==0? h0 : h1);\n            long long dH = max(0LL, ch - H);\n            double cost = lamW_eff * (double)cw + lamH_eff * (double)dH + biasEff;\n\n            // Lookahead rewards: count and sum of fitted heights\n            auto st = future_fit_stats(i + 1, cw, P.fudge, P.fudgeFrac);\n            int cntFit = st.first;\n            long long sumHFit = st.second;\n            cost -= P.fitCountWeight * (double)cntFit;\n            cost -= lamH_eff * P.fitHeightWeight * (double)sumHFit;\n\n            // Suffix-quantile based penalty for too-narrow columns (q70)\n            long long thrQ = (i + 1 <= N ? ctx.q70[i + 1] : 0LL);\n            double thr = P.minOpenFactor * (double)thrQ;\n            if ((double)cw < thr) {\n                cost += lamW_eff * P.minOpenPenalty * (thr - (double)cw);\n            }\n\n            // Soft width cap penalty\n            double capW = P.widthCapMul * ctx.avgMin;\n            if ((double)cw > capW) {\n                cost += lamW_eff * P.widthCapPenalty * ((double)cw - capW);\n            }\n\n            // Wide bonus vs suffix q90 to prepare for wide future items\n            long long thrQ90 = (i + 1 <= N ? ctx.q90[i + 1] : 0LL);\n            if ((double)cw > (double)thrQ90) {\n                cost -= lamW_eff * P.wideBonusMul * ((double)cw - (double)thrQ90);\n            }\n\n            // Column count penalty\n            cost += P.colCountPenalty * (double)cols.size();\n\n            return {cost, cw, ch};\n        };\n\n        auto [costNew0, cw0, ch0] = eval_newcol(0);\n        auto [costNew1, cw1, ch1] = eval_newcol(1);\n\n        double newColCost; long long newCW, newCH; int newRot;\n        if (costNew1 < costNew0 - 1e-12 || (fabs(costNew1 - costNew0) < 1e-12 && (cw1 < cw0 || (cw1 == cw0 && ch1 < ch0)))) {\n            newColCost = costNew1; newCW = cw1; newCH = ch1; newRot = 1;\n        } else {\n            newColCost = costNew0; newCW = cw0; newCH = ch0; newRot = 0;\n        }\n\n        if (hasStack && bestCostStack <= newColCost) {\n            // Stack into existing column\n            Op op;\n            op.p = i;\n            op.r = bestRot;\n            op.d = 'L';\n            op.b = cols[bestCol].last_id;\n            ops.push_back(op);\n\n            long long hAdd = (bestRot == 0 ? h0 : h1);\n            cols[bestCol].ch += hAdd;\n            cols[bestCol].last_id = i;\n            H = max(H, cols[bestCol].ch);\n        } else {\n            // Open a new column appended to the right\n            Op op;\n            op.p = i;\n            op.r = newRot;\n            op.d = 'U';\n            op.b = (lastTopId == -1 ? -1 : lastTopId);\n            ops.push_back(op);\n\n            Column c;\n            c.cw = newCW;\n            c.ch = newCH;\n            c.top_id = i;\n            c.last_id = i;\n            cols.push_back(c);\n\n            lastTopId = i;\n            W += newCW;\n            H = max(H, newCH);\n        }\n    }\n\n    return {ops, W, H};\n}\n\n// Wrapper to build either column-mode (normal) or row-mode (transposed)\nenum Mode { COLMODE = 0, ROWMODE = 1 };\n\nstatic PlanResult build_plan(const vector<long long>& w, const vector<long long>& h, double avgMin,\n                             const vector<long long>& q70, const vector<long long>& q90,\n                             const Param& P, Mode mode) {\n    if (mode == COLMODE) {\n        BuildCtx ctx{w, h, avgMin, q70, q90};\n        return build_columns_core(ctx, P);\n    } else {\n        // Transpose sizes\n        vector<long long> wt = h, ht = w;\n        BuildCtx ctxT{wt, ht, avgMin, q70, q90}; // avgMin & quantiles used as scale signals; acceptable\n        PlanResult rt = build_columns_core(ctxT, P);\n        // Map operations back: swap U<->L, r -> 1 - r\n        for (auto &op : rt.ops) {\n            op.r = 1 - op.r;\n            op.d = (op.d == 'U' ? 'L' : 'U');\n        }\n        swap(rt.W_est, rt.H_est);\n        return rt;\n    }\n}\n\n// Compute suffix quantile array Q[i] = quantile of ms[i..N-1], Q[N] = 0\nstatic vector<long long> compute_suffix_quantile(const vector<long long>& ms, double quant) {\n    int N = (int)ms.size();\n    vector<long long> Q(N + 1, 0);\n    for (int i = 0; i < N; ++i) {\n        vector<long long> v;\n        v.reserve(N - i);\n        for (int j = i; j < N; ++j) v.push_back(ms[j]);\n        sort(v.begin(), v.end());\n        int m = (int)v.size();\n        if (m > 0) {\n            int idx = (int)floor((m - 1) * quant + 1e-9);\n            if (idx < 0) idx = 0;\n            if (idx >= m) idx = m - 1;\n            Q[i] = v[idx];\n        } else Q[i] = 0;\n    }\n    Q[N] = 0;\n    return Q;\n}\n\nstruct Task { Param P; Mode mode; };\n\nstruct BestEntry {\n    Param P;\n    Mode mode;\n    long long score; // measured W'+H'\n};\n\nstatic void insert_best(vector<BestEntry>& bests, const BestEntry& e, int K) {\n    bests.push_back(e);\n    sort(bests.begin(), bests.end(), [](const BestEntry& a, const BestEntry& b){ return a.score < b.score; });\n    if ((int)bests.size() > K) bests.resize(K);\n}\n\n// Jitter/exploit around a Param\nstatic void jitter_param(Param& P, double avgMin, long long sigma, std::mt19937_64& rng) {\n    std::uniform_real_distribution<double> ur(0.0, 1.0);\n    double j1 = (ur(rng) - 0.5) * 0.25; // +-12.5%\n    double j2 = (ur(rng) - 0.5) * 0.25;\n    P.lamW = max(0.2, P.lamW * (1.0 + j1));\n    P.lamH = max(0.2, P.lamH * (1.0 + j2));\n    P.newColBias += (ur(rng) - 0.5) * (0.06 * avgMin);\n    P.fitCountWeight = max(0.0, P.fitCountWeight * (1.0 + (ur(rng) - 0.5) * 0.3));\n    P.fitHeightWeight = max(0.0, P.fitHeightWeight * (1.0 + (ur(rng) - 0.5) * 0.3));\n    P.stackFitCountWeight = max(0.0, P.stackFitCountWeight * (1.0 + (ur(rng) - 0.5) * 0.3));\n    P.stackFitHeightWeight = max(0.0, P.stackFitHeightWeight * (1.0 + (ur(rng) - 0.5) * 0.3));\n    P.dynAlpha = max(0.0, P.dynAlpha * (1.0 + (ur(rng) - 0.5) * 0.2));\n    P.progBiasC = max(0.0, P.progBiasC * (1.0 + (ur(rng) - 0.5) * 0.3));\n    P.widthCapMul = max(1.2, P.widthCapMul * (1.0 + (ur(rng) - 0.5) * 0.15));\n    P.widthCapPenalty = max(0.02, P.widthCapPenalty * (1.0 + (ur(rng) - 0.5) * 0.25));\n    P.minOpenFactor = min(1.1, max(0.6, P.minOpenFactor * (1.0 + (ur(rng) - 0.5) * 0.2)));\n    P.minOpenPenalty = max(0.0, P.minOpenPenalty * (1.0 + (ur(rng) - 0.5) * 0.25));\n    P.wideBonusMul = max(0.0, P.wideBonusMul * (1.0 + (ur(rng) - 0.5) * 0.25));\n    P.colCountPenalty = max(0.0, P.colCountPenalty * (1.0 + (ur(rng) - 0.5) * 0.25));\n    long long jfudge = (long long)((ur(rng) - 0.5) * (double)max(1LL, sigma/4)); // +-sigma/8\n    long long nf = P.fudge + jfudge;\n    if (nf < 0) nf = 0;\n    if (nf > max(1LL, sigma)) nf = max(1LL, sigma);\n    P.fudge = nf;\n    P.fudgeFrac = max(0.0, P.fudgeFrac * (1.0 + (ur(rng) - 0.5) * 0.3));\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    long long sigma;\n    if (!(cin >> N >> T >> sigma)) return 0;\n    vector<long long> w(N), h(N);\n    for (int i = 0; i < N; ++i) cin >> w[i] >> h[i];\n\n    // Typical scale = average min side\n    double avgMin = 0.0;\n    vector<long long> ms(N);\n    for (int i = 0; i < N; ++i) {\n        ms[i] = min(w[i], h[i]);\n        avgMin += (double)ms[i];\n    }\n    avgMin /= max(1, N);\n\n    // Suffix quantiles for min side\n    vector<long long> q70 = compute_suffix_quantile(ms, 0.70);\n    vector<long long> q90 = compute_suffix_quantile(ms, 0.90);\n\n    // Parameter portfolio (safe, diverse; fudge >= 0)\n    vector<Task> tasks;\n\n    auto clamp_fudge = [&](long long f)->long long {\n        if (f < 0) f = 0;\n        long long maxF = max(1LL, sigma);\n        if (f > maxF) f = maxF;\n        return f;\n    };\n\n    auto add_combo = [&](double lW, double lH, long long f, double fudgeFrac,\n                         double biasMul, int lookK,\n                         double fitCntMul, double fitHMul,\n                         double stackCntMul, double stackHMul,\n                         double dynA, double progC,\n                         double widthCapMul, double widthCapPenalty,\n                         double minOpenFactor, double minOpenPenalty,\n                         double wideBonusMul, double colCountPenMul,\n                         const string& tag, int modeInt) {\n        Param P;\n        P.lamW = lW;\n        P.lamH = lH;\n        P.fudge = clamp_fudge(f);\n        P.fudgeFrac = max(0.0, fudgeFrac);\n        P.newColBias = biasMul * avgMin;        // scaled by avgMin\n        P.lookK = lookK;\n        P.fitCountWeight = max(0.0, fitCntMul) * avgMin;  // scaled by avgMin\n        P.fitHeightWeight = max(0.0, fitHMul);            // dimensionless, multiplied with lamH\n        P.stackFitCountWeight = max(0.0, stackCntMul) * avgMin;\n        P.stackFitHeightWeight = max(0.0, stackHMul);\n        P.dynAlpha = max(0.0, dynA);\n        P.progBiasC = max(0.0, progC);                    // multiplied by avgMin inside\n        P.widthCapMul = max(1.0, widthCapMul);            // soft cap multiplier on avgMin\n        P.widthCapPenalty = max(0.0, widthCapPenalty);    // penalty factor for over-cap width\n        P.minOpenFactor = min(max(0.5, minOpenFactor), 1.2);\n        P.minOpenPenalty = max(0.0, minOpenPenalty);\n        P.wideBonusMul = max(0.0, wideBonusMul);\n        P.colCountPenalty = max(0.0, colCountPenMul) * avgMin;\n        uint64_t seed = 0;\n        seed ^= (uint64_t)(lW * 1000 + 7) + ((uint64_t)(lH * 1000 + 13) << 1);\n        seed ^= (uint64_t)(P.fudge + 101) + ((uint64_t)(biasMul * 1000 + 17) << 2);\n        seed ^= ((uint64_t)lookK << 3) + ((uint64_t)(fitCntMul * 100 + 19) << 5);\n        seed ^= ((uint64_t)(fitHMul * 100 + 23) << 7);\n        seed ^= ((uint64_t)(stackCntMul * 100 + 27) << 9);\n        seed ^= ((uint64_t)(stackHMul * 100 + 31) << 11);\n        seed ^= ((uint64_t)(dynA * 1000 + 29) << 13) ^ ((uint64_t)(progC * 1000 + 31) << 15);\n        seed ^= ((uint64_t)(widthCapMul * 1000 + 37) << 17) ^ ((uint64_t)(widthCapPenalty * 1000 + 41) << 19);\n        seed ^= ((uint64_t)(minOpenFactor * 1000 + 43) << 21) ^ ((uint64_t)(minOpenPenalty * 1000 + 47) << 23);\n        seed ^= ((uint64_t)(wideBonusMul * 1000 + 53) << 25) ^ ((uint64_t)(colCountPenMul * 1000 + 59) << 27);\n        P.tieRand = (unsigned)splitmix64(seed);\n        P.tag = tag + (modeInt==0 ? \"_col\" : \"_row\");\n        tasks.push_back({P, modeInt==0 ? COLMODE : ROWMODE});\n    };\n\n    // Fudge levels\n    long long F0 = 0;\n    long long F1 = max(0LL, sigma / 8);\n    long long F2 = max(0LL, sigma / 4);\n    long long F3 = max(0LL, sigma / 2);\n\n    // Build tasks for both modes; safer sets first\n    vector<long long> fudges = {F1, F0, F2};\n    for (auto f : fudges) {\n        // Balanced with adaptive margin and lookahead\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.0, 1.0, f, 0.02,  0.00, 8, 0.12, 0.05, 0.06, 0.02, 0.20, 0.40,\n                      1.8, 0.15, 0.80, 0.20, 0.01, 0.01, \"bal_f\"+to_string(f), m);\n        // Encourage stacking (narrow W)\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.6, 1.0, f, 0.02, +0.06, 6, 0.00, 0.00, 0.05, 0.02, 0.20, 0.40,\n                      1.6, 0.20, 0.75, 0.15, 0.00, 0.02, \"W+_f\"+to_string(f), m);\n        // Stronger W\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.9, 1.0, f, 0.02, +0.10, 6, 0.00, 0.00, 0.05, 0.02, 0.15, 0.40,\n                      1.5, 0.25, 0.70, 0.15, 0.00, 0.03, \"W++_f\"+to_string(f), m);\n        // Encourage new columns to control height\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.0, 1.5, f, 0.02, -0.05, 8, 0.14, 0.06, 0.04, 0.02, 0.25, 0.50,\n                      2.0, 0.10, 0.85, 0.10, 0.02, 0.00, \"H+_f\"+to_string(f), m);\n        // Stronger height-friendly\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.0, 1.9, f, 0.02, -0.10,10, 0.16, 0.07, 0.04, 0.02, 0.30, 0.60,\n                      2.2, 0.08, 0.90, 0.10, 0.02, 0.00, \"H++_f\"+to_string(f), m);\n        // Balanced with stronger lookahead\n        for (int m = 0; m < 2; ++m)\n            add_combo(1.0, 1.0, f, 0.02, -0.03, 9, 0.15, 0.06, 0.05, 0.02, 0.25, 0.50,\n                      1.9, 0.12, 0.80, 0.20, 0.01, 0.01, \"balFit_f\"+to_string(f), m);\n    }\n    // Extra-safe with larger fudge\n    for (int m = 0; m < 2; ++m)\n        add_combo(1.2, 1.0, F3, 0.02, +0.06, 6, 0.00, 0.00, 0.04, 0.02, 0.20, 0.40,\n                  1.6, 0.20, 0.75, 0.15, 0.00, 0.03, \"W+_f\"+to_string(F3), m);\n    for (int m = 0; m < 2; ++m)\n        add_combo(1.0, 1.2, F3, 0.02, -0.04, 8, 0.10, 0.04, 0.04, 0.02, 0.25, 0.50,\n                  2.0, 0.10, 0.85, 0.12, 0.01, 0.01, \"H+_f\"+to_string(F3), m);\n\n    // Limit exploration to about T/3 turns (at least 12) to leave more for exploitation\n    int E = min((int)tasks.size(), max(12, T / 3));\n\n    vector<BestEntry> bests; bests.reserve(8);\n    const int TOPK = 6;\n\n    std::mt19937_64 rng(20250914);\n    std::uniform_real_distribution<double> ur(0.0, 1.0);\n\n    for (int t = 0; t < T; ++t) {\n        Param P;\n        Mode mode;\n        string tag;\n\n        if (t < E) {\n            // Exploration\n            auto &task = tasks[t % (int)tasks.size()];\n            P = task.P;\n            mode = task.mode;\n            tag = \"explore_\" + P.tag;\n        } else {\n            // Exploitation\n            if (bests.empty()) {\n                auto &task = tasks[t % (int)tasks.size()];\n                P = task.P;\n                mode = task.mode;\n                tag = \"fallback_\" + P.tag;\n            } else {\n                // Choose among top-K with bias toward best\n                int pick = 0;\n                double r = ur(rng);\n                if (r < 0.60) pick = 0;\n                else if (r < 0.80 && (int)bests.size() >= 2) pick = 1;\n                else pick = (int)(ur(rng) * (int)bests.size());\n                if (pick >= (int)bests.size()) pick = (int)bests.size() - 1;\n\n                P = bests[pick].P;\n                mode = bests[pick].mode;\n\n                // Jitter around this configuration\n                jitter_param(P, avgMin, sigma, rng);\n\n                // Occasionally re-explore a baseline\n                if (ur(rng) < 0.10) {\n                    auto &task = tasks[(int)(rng() % tasks.size())];\n                    P = task.P;\n                    mode = task.mode;\n                    tag = \"reexplore_\" + P.tag;\n                } else {\n                    tag = string(\"exploit_\") + (mode == COLMODE ? \"col\" : \"row\");\n                }\n            }\n        }\n\n        // Build and output plan\n        P.tieRand = (unsigned)splitmix64((uint64_t)rng());\n        PlanResult res = build_plan(w, h, avgMin, q70, q90, P, mode);\n\n        // Optional comment for debugging\n        cout << \"# t=\" << t\n             << \" mode=\" << (mode==COLMODE ? \"col\" : \"row\")\n             << \" W_est=\" << res.W_est << \" H_est=\" << res.H_est\n             << \" lamW=\" << fixed << setprecision(2) << P.lamW\n             << \" lamH=\" << P.lamH\n             << \" fudge=\" << P.fudge\n             << \" fFrac=\" << P.fudgeFrac\n             << \" bias=\" << P.newColBias\n             << \" lookK=\" << P.lookK\n             << \" tag=\" << tag << \"\\n\";\n\n        cout << res.ops.size() << \"\\n\";\n        for (auto &op : res.ops) {\n            cout << op.p << \" \" << op.r << \" \" << op.d << \" \" << op.b << \"\\n\";\n        }\n        cout.flush();\n\n        long long Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n\n        long long approxScore = Wm + Hm;\n        BestEntry e{P, mode, approxScore};\n        insert_best(bests, e, TOPK);\n    }\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double ms() const {\n        return chrono::duration<double, milli>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nstatic const uint16_t INF16 = (uint16_t)30000;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    if (!(cin >> N >> M >> H)) return 0;\n    vector<int> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n    vector<vector<int>> g(N);\n    for (int i = 0; i < M; i++) {\n        int u, v; cin >> u >> v;\n        g[u].push_back(v);\n        g[v].push_back(u);\n    }\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n    Timer timer;\n\n    // 1) All-pairs shortest distances via BFS from each node\n    vector<uint16_t> Dist((size_t)N * (size_t)N, INF16);\n    {\n        vector<int> q; q.reserve(N);\n        vector<int> dist(N);\n        for (int s = 0; s < N; s++) {\n            fill(dist.begin(), dist.end(), -1);\n            q.clear(); q.push_back(s); dist[s] = 0;\n            for (size_t qi = 0; qi < q.size(); qi++) {\n                int u = q[qi];\n                for (int v : g[u]) if (dist[v] == -1) {\n                    dist[v] = dist[u] + 1;\n                    q.push_back(v);\n                }\n            }\n            uint16_t* row = &Dist[(size_t)s * N];\n            for (int v = 0; v < N; v++) row[v] = dist[v] >= 0 ? (uint16_t)dist[v] : INF16;\n        }\n    }\n\n    // Precompute within-H sets (for root selection tie-break and intersections)\n    vector<vector<int>> withinH(N);\n    for (int u = 0; u < N; u++) {\n        const uint16_t* Du = &Dist[(size_t)u * N];\n        for (int v = 0; v < N; v++) if (Du[v] <= (uint16_t)H) withinH[u].push_back(v);\n    }\n\n    // 2) Build a root set to ensure coverage within H by farthest-first, then prune\n    vector<int> roots;\n    vector<char> isRoot(N, 0);\n    vector<uint16_t> dR(N, INF16);\n\n    int s0 = int(min_element(A.begin(), A.end()) - A.begin()); // start from low-beauty vertex\n    roots.push_back(s0);\n    isRoot[s0] = 1;\n    {\n        const uint16_t* D0 = &Dist[(size_t)s0 * N];\n        for (int v = 0; v < N; v++) dR[v] = D0[v];\n    }\n\n    auto recompute_dR = [&]() {\n        fill(dR.begin(), dR.end(), INF16);\n        for (int r : roots) {\n            const uint16_t* Dr = &Dist[(size_t)r * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dr[v]);\n        }\n    };\n\n    while (true) {\n        uint16_t dmax = 0;\n        for (int v = 0; v < N; v++) if (dR[v] > dmax) dmax = dR[v];\n        if (dmax <= (uint16_t)H) break;\n\n        vector<int> far;\n        for (int v = 0; v < N; v++) if (dR[v] == dmax) far.push_back(v);\n\n        int bestCand = -1, bestA = INT_MAX;\n        long long bestCoverW = -1;\n        for (int cand : far) {\n            long long coverW = 0;\n            for (int u : withinH[cand]) if (dR[u] > (uint16_t)H) coverW += A[u];\n            if (coverW > bestCoverW || (coverW == bestCoverW && A[cand] < bestA)) {\n                bestCoverW = coverW; bestA = A[cand]; bestCand = cand;\n            }\n        }\n        if (bestCand == -1) bestCand = far[0];\n\n        if (!isRoot[bestCand]) {\n            roots.push_back(bestCand);\n            isRoot[bestCand] = 1;\n            const uint16_t* Dn = &Dist[(size_t)bestCand * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dn[v]);\n        } else {\n            int cand2 = -1;\n            for (int v = 0; v < N; v++) if (dR[v] > (uint16_t)H) { cand2 = v; break; }\n            if (cand2 == -1) break;\n            roots.push_back(cand2);\n            isRoot[cand2] = 1;\n            const uint16_t* Dn = &Dist[(size_t)cand2 * N];\n            for (int v = 0; v < N; v++) dR[v] = min<uint16_t>(dR[v], Dn[v]);\n        }\n    }\n\n    auto compute_min12 = [&](vector<uint16_t>& m1, vector<uint16_t>& m2, vector<int>& arg) {\n        m1.assign(N, INF16); m2.assign(N, INF16); arg.assign(N, -1);\n        for (int r : roots) {\n            const uint16_t* Dr = &Dist[(size_t)r * N];\n            for (int v = 0; v < N; v++) {\n                uint16_t d = Dr[v];\n                if (d < m1[v]) { m2[v] = m1[v]; m1[v] = d; arg[v] = r; }\n                else if (d < m2[v]) m2[v] = d;\n            }\n        }\n    };\n\n    // Prune redundant roots\n    {\n        vector<uint16_t> m1, m2; vector<int> arg;\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            compute_min12(m1, m2, arg);\n            for (int i = 0; i < (int)roots.size(); i++) {\n                int r = roots[i];\n                bool safe = true;\n                for (int v = 0; v < N; v++) if (arg[v] == r && m2[v] > (uint16_t)H) { safe = false; break; }\n                if (safe) {\n                    isRoot[r] = 0;\n                    roots.erase(roots.begin() + i);\n                    changed = true;\n                    break;\n                }\n            }\n        }\n        recompute_dR();\n    }\n\n    // 3) Build initial forest via multi-source BFS\n    vector<int> parent(N, -1);\n    vector<uint16_t> depth(N, INF16);\n    deque<int> dq;\n    for (int r : roots) {\n        depth[r] = 0; parent[r] = -1; dq.push_back(r);\n    }\n    while (!dq.empty()) {\n        int u = dq.front(); dq.pop_front();\n        if (depth[u] >= (uint16_t)H) continue;\n        uint16_t nd = depth[u] + 1;\n        for (int v : g[u]) if (depth[v] == INF16) {\n            depth[v] = nd; parent[v] = u; dq.push_back(v);\n        }\n    }\n    for (int v = 0; v < N; v++) if (depth[v] == INF16) { depth[v] = 0; parent[v] = -1; }\n\n    // 4) Prepare dynamic tree structures\n    vector<vector<int>> children(N);\n    vector<int> posInParent(N, -1);\n    for (int v = 0; v < N; v++) if (parent[v] != -1) {\n        int p = parent[v];\n        posInParent[v] = (int)children[p].size();\n        children[p].push_back(v);\n    }\n\n    vector<int> tin(N, 0), tout(N, 0), order(N, -1), rootsNow;\n    vector<long long> subSum(N, 0);\n    vector<uint16_t> subMax(N, 0);\n\n    function<void(int,int&,uint16_t)> dfs = [&](int u, int &timerDfs, uint16_t h) {\n        depth[u] = h;\n        tin[u] = timerDfs;\n        order[timerDfs] = u;\n        timerDfs++;\n        long long s = A[u];\n        uint16_t mx = h;\n        for (int w : children[u]) {\n            dfs(w, timerDfs, (uint16_t)(h + 1));\n            s += subSum[w];\n            mx = max<uint16_t>(mx, subMax[w]);\n        }\n        subSum[u] = s;\n        subMax[u] = mx;\n        tout[u] = timerDfs;\n    };\n    auto recompute_tree_info = [&]() {\n        rootsNow.clear();\n        for (int v = 0; v < N; v++) if (parent[v] == -1) rootsNow.push_back(v);\n        int tval = 0;\n        for (int r : rootsNow) dfs(r, tval, 0);\n    };\n    recompute_tree_info();\n\n    auto is_ancestor = [&](int u, int v) -> bool {\n        return tin[u] <= tin[v] && tout[v] <= tout[u];\n    };\n    auto remove_from_parent = [&](int u) {\n        int p = parent[u];\n        if (p == -1) return;\n        int idx = posInParent[u];\n        int last = children[p].back();\n        swap(children[p][idx], children[p].back());\n        children[p].pop_back();\n        posInParent[last] = idx;\n        posInParent[u] = -1;\n        parent[u] = -1;\n    };\n    auto add_to_parent = [&](int u, int p) {\n        parent[u] = p;\n        posInParent[u] = (int)children[p].size();\n        children[p].push_back(u);\n    };\n\n    struct Move { int u, x; int L, R; int delta; long long gain; };\n\n    // 5) Batch deepening rounds: greedy selection with strong conflict checks and parent reuse\n    auto batch_deepen = [&](double end_ms, int TOPK) {\n        while (timer.ms() < end_ms) {\n            vector<Move> cand;\n            cand.reserve(N * 2);\n            for (int u = 0; u < N; u++) {\n                if (subMax[u] >= (uint16_t)H) continue; // subtree already at cap\n                int du = depth[u];\n                struct C { long long gain; int delta; int x; };\n                vector<C> top; top.reserve(TOPK);\n                for (int x : g[u]) {\n                    if (x == parent[u]) continue;\n                    if (is_ancestor(u, x)) continue; // avoid cycle\n                    int dx = depth[x];\n                    int delta = dx + 1 - du;\n                    if (delta <= 0) continue;\n                    if ((int)subMax[u] + delta > H) continue;\n                    long long gain = 1LL * delta * subSum[u];\n                    if (gain <= 0) continue;\n                    if ((int)top.size() < TOPK) {\n                        top.push_back({gain, delta, x});\n                        if ((int)top.size() == TOPK)\n                            sort(top.begin(), top.end(), [](const C& a, const C& b){ return a.gain > b.gain; });\n                    } else if (gain > top.back().gain) {\n                        top.back() = {gain, delta, x};\n                        sort(top.begin(), top.end(), [](const C& a, const C& b){ return a.gain > b.gain; });\n                    }\n                }\n                for (auto &t : top) {\n                    cand.push_back(Move{u, t.x, tin[u], tout[u], t.delta, t.gain});\n                }\n            }\n            if (cand.empty()) break;\n\n            sort(cand.begin(), cand.end(), [](const Move& a, const Move& b){\n                if (a.gain != b.gain) return a.gain > b.gain;\n                if (a.delta != b.delta) return a.delta > b.delta;\n                return a.u < b.u;\n            });\n\n            vector<Move> selected;\n            selected.reserve(cand.size());\n            vector<pair<int,int>> usedIntervals; usedIntervals.reserve(cand.size());\n            vector<int> usedParentTin; usedParentTin.reserve(cand.size());\n            vector<char> usedSubtree(N, 0); // moved roots\n\n            for (const auto &m : cand) {\n                if (usedSubtree[m.u]) continue;    // one move per subtree\n                if (usedSubtree[m.x]) continue;    // parent x must not be moved in this batch\n\n                bool conflict = false;\n                for (size_t i = 0; i < usedIntervals.size(); i++) {\n                    int L = usedIntervals[i].first, R = usedIntervals[i].second;\n                    if (!(m.R <= L || R <= m.L)) { conflict = true; break; } // disjoint subtrees\n                    if (L <= tin[m.x] && tin[m.x] < R) { conflict = true; break; } // x inside selected subtree\n                }\n                if (conflict) continue;\n                // reverse: any selected parent located inside this subtree?\n                for (int tpx : usedParentTin) {\n                    if (m.L <= tpx && tpx < m.R) { conflict = true; break; }\n                }\n                if (conflict) continue;\n\n                selected.push_back(m);\n                usedIntervals.emplace_back(m.L, m.R);\n                usedParentTin.push_back(tin[m.x]);\n                usedSubtree[m.u] = 1;\n            }\n\n            if (selected.empty()) break;\n\n            // Apply: increase depths in subtrees then reparent\n            for (const auto &m : selected) {\n                for (int i = m.L; i < m.R; i++) {\n                    int w = order[i];\n                    depth[w] = (uint16_t)(depth[w] + m.delta);\n                }\n            }\n            for (const auto &m : selected) {\n                int u = m.u, x = m.x;\n                remove_from_parent(u);\n                add_to_parent(u, x);\n            }\n\n            // Recompute exact depths and subtree info\n            recompute_tree_info();\n        }\n    };\n\n    // First deepening phase (slightly extended time cap and more candidates)\n    batch_deepen(1970.0, 6);\n\n    // 6) Final safety pass: enforce height <= H by reattaching to deep already-processed neighbors\n    // Rebuild children from current parent (for traversal)\n    for (int v = 0; v < N; v++) { children[v].clear(); posInParent[v] = -1; }\n    for (int v = 0; v < N; v++) if (parent[v] != -1) {\n        int p = parent[v];\n        posInParent[v] = (int)children[p].size();\n        children[p].push_back(v);\n    }\n    // Recompute tin/tout before safety (useful for cycle avoidance)\n    recompute_tree_info();\n\n    vector<int> rootsFinal;\n    for (int v = 0; v < N; v++) if (parent[v] == -1) rootsFinal.push_back(v);\n\n    struct Frame { int u; int it; int h; };\n    vector<Frame> st;\n    st.reserve(N);\n    vector<int> assignedDepth(N, -1);\n\n    auto push_root = [&](int r) {\n        st.push_back({r, 0, 0});\n    };\n    for (int r : rootsFinal) push_root(r);\n\n    while (!st.empty()) {\n        Frame &fr = st.back();\n        int u = fr.u;\n        if (fr.it == 0) {\n            int h = fr.h;\n            if (h > H) {\n                int bestY = -1, bestHy = -1;\n                for (int y : g[u]) {\n                    if (assignedDepth[y] == -1) continue; // only already processed\n                    if (assignedDepth[y] > H - 1) continue;\n                    // Avoid cycle: y not in original subtree of u\n                    if (tin[u] <= tin[y] && tin[y] < tout[u]) continue;\n                    if (assignedDepth[y] > bestHy) {\n                        bestHy = assignedDepth[y];\n                        bestY = y;\n                    }\n                }\n                if (bestY != -1) {\n                    parent[u] = bestY;\n                    h = bestHy + 1;\n                } else {\n                    parent[u] = -1;\n                    h = 0;\n                }\n                fr.h = h;\n            }\n            assignedDepth[u] = fr.h;\n        }\n        if (fr.it < (int)children[u].size()) {\n            int v = children[u][fr.it++];\n            st.push_back({v, 0, fr.h + 1});\n        } else {\n            st.pop_back();\n        }\n    }\n\n    // Optional final small deepening phase after safety\n    for (int v = 0; v < N; v++) { children[v].clear(); posInParent[v] = -1; }\n    for (int v = 0; v < N; v++) if (parent[v] != -1) {\n        int p = parent[v];\n        posInParent[v] = (int)children[p].size();\n        children[p].push_back(v);\n    }\n    recompute_tree_info();\n    if (timer.ms() < 1990.0) {\n        batch_deepen(1997.0, 4);\n    }\n\n    // Output final parents\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << parent[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Action {\n    char d;      // 'L','R','U','D'\n    int p;       // row/column index\n    int k;       // length (number of shifts each way)\n    int cost;    // 2*k\n    uint64_t mask; // bitmask of covered Oni (M <= 64; here M=40)\n};\n\nstatic inline char opposite(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\nstatic inline int ctz64(uint64_t x) { return __builtin_ctzll(x); }\n\npair<int,int> simulate(const vector<string>& init, const vector<pair<char,int>>& ops) {\n    int N = init.size();\n    vector<string> g = init;\n    int rem_oni = 0;\n    for (auto &row : g) for (char ch : row) if (ch == 'x') rem_oni++;\n    int removed_oni = 0, removed_fuku = 0;\n    for (auto [d,p] : ops) {\n        if (d == 'L') {\n            char out = g[p][0];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int j = 0; j < N-1; ++j) g[p][j] = g[p][j+1];\n            g[p][N-1] = '.';\n        } else if (d == 'R') {\n            char out = g[p][N-1];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\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            char out = g[0][p];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int i = 0; i < N-1; ++i) g[i][p] = g[i+1][p];\n            g[N-1][p] = '.';\n        } else { // 'D'\n            char out = g[N-1][p];\n            if (out == 'x') removed_oni++;\n            else if (out == 'o') removed_fuku++;\n            for (int i = N-1; i >= 1; --i) g[i][p] = g[i-1][p];\n            g[0][p] = '.';\n        }\n    }\n    int X = rem_oni - removed_oni;\n    int Y = removed_fuku;\n    return {X, Y};\n}\n\n// Build reduced candidate actions: only k at points where we \"pass a new Oni\".\n// Deduplicate identical masks (keep cheapest) and prune dominated actions (subset with >= cost).\nvector<Action> build_candidates_tight(const vector<string>& grid, const vector<pair<int,int>>& oni_pos,\n                                      const vector<vector<int>>& oni_id) {\n    int N = grid.size();\n    vector<Action> acts;\n    acts.reserve(400);\n\n    // Precompute Lsafe/Rsafe/Usafe/Dsafe based on Fukunokami positions\n    vector<int> Lsafe(N), Rsafe(N);\n    for (int r = 0; r < N; ++r) {\n        int firstF = N, lastF = -1;\n        for (int j = 0; j < N; ++j) if (grid[r][j] == 'o') {\n            firstF = min(firstF, j);\n            lastF = max(lastF, j);\n        }\n        Lsafe[r] = (firstF == N ? N : firstF);\n        Rsafe[r] = (lastF == -1 ? N : (N - 1 - lastF));\n    }\n    vector<int> Usafe(N), Dsafe(N);\n    for (int c = 0; c < N; ++c) {\n        int firstF = N, lastF = -1;\n        for (int i = 0; i < N; ++i) if (grid[i][c] == 'o') {\n            firstF = min(firstF, i);\n            lastF = max(lastF, i);\n        }\n        Usafe[c] = (firstF == N ? N : firstF);\n        Dsafe[c] = (lastF == -1 ? N : (N - 1 - lastF));\n    }\n\n    // Row-left actions\n    for (int r = 0; r < N; ++r) {\n        uint64_t mask = 0;\n        for (int j = 0; j < Lsafe[r]; ++j) {\n            int id = oni_id[r][j];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = j + 1;\n                Action a; a.d = 'L'; a.p = r; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n    // Row-right actions\n    for (int r = 0; r < N; ++r) {\n        uint64_t mask = 0;\n        for (int j = N-1; j >= N - Rsafe[r]; --j) {\n            int id = oni_id[r][j];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = N - j;\n                Action a; a.d = 'R'; a.p = r; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n    // Col-up actions\n    for (int c = 0; c < N; ++c) {\n        uint64_t mask = 0;\n        for (int i = 0; i < Usafe[c]; ++i) {\n            int id = oni_id[i][c];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = i + 1;\n                Action a; a.d = 'U'; a.p = c; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n    // Col-down actions\n    for (int c = 0; c < N; ++c) {\n        uint64_t mask = 0;\n        for (int i = N-1; i >= N - Dsafe[c]; --i) {\n            int id = oni_id[i][c];\n            if (id != -1) {\n                mask |= (1ULL << id);\n                int k = N - i;\n                Action a; a.d = 'D'; a.p = c; a.k = k; a.cost = 2*k; a.mask = mask;\n                acts.push_back(a);\n            }\n        }\n    }\n\n    // Deduplicate identical masks keeping minimal cost\n    unordered_map<uint64_t, int> bestIdx;\n    bestIdx.reserve(acts.size()*2);\n    vector<Action> filtered;\n    filtered.reserve(acts.size());\n    for (int i = 0; i < (int)acts.size(); ++i) {\n        auto it = bestIdx.find(acts[i].mask);\n        if (it == bestIdx.end()) {\n            bestIdx[acts[i].mask] = (int)filtered.size();\n            filtered.push_back(acts[i]);\n        } else {\n            int idx = it->second;\n            if (acts[i].cost < filtered[idx].cost) filtered[idx] = acts[i];\n        }\n    }\n\n    // Dominated action removal: if mask_i subset of mask_j and cost_i >= cost_j, drop i\n    int A = filtered.size();\n    vector<char> dominated(A, 0);\n    for (int i = 0; i < A; ++i) if (!dominated[i]) {\n        for (int j = 0; j < A; ++j) if (i != j && !dominated[i]) {\n            if ((filtered[i].mask & ~filtered[j].mask) == 0ULL) { // i \u2286 j\n                if (filtered[i].cost >= filtered[j].cost) dominated[i] = 1;\n            }\n        }\n    }\n    vector<Action> filtered2;\n    filtered2.reserve(A);\n    for (int i = 0; i < A; ++i) if (!dominated[i]) filtered2.push_back(filtered[i]);\n    return filtered2;\n}\n\nint selection_cost(const vector<int>& sel, const vector<Action>& acts) {\n    long long s = 0;\n    for (int idx : sel) s += acts[idx].cost;\n    if (s > INT_MAX) return INT_MAX;\n    return (int)s;\n}\n\nvector<int> prune_selection(const vector<int>& sel, const vector<Action>& acts, int M) {\n    if (sel.empty()) return sel;\n    vector<int> cnt(M, 0);\n    for (int idx : sel) {\n        uint64_t m = acts[idx].mask;\n        while (m) { int b = ctz64(m); cnt[b]++; m &= m - 1; }\n    }\n    vector<int> order = sel;\n    sort(order.begin(), order.end(), [&](int a, int b){\n        if (acts[a].cost != acts[b].cost) return acts[a].cost > acts[b].cost;\n        return a < b;\n    });\n    vector<char> alive(acts.size(), 0);\n    for (int idx : sel) alive[idx] = 1;\n\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        for (int idx : order) {\n            if (!alive[idx]) continue;\n            uint64_t m = acts[idx].mask;\n            bool can = true;\n            while (m) {\n                int b = ctz64(m);\n                if (cnt[b] <= 1) { can = false; break; }\n                m &= m - 1;\n            }\n            if (can) {\n                uint64_t mm = acts[idx].mask;\n                while (mm) { int b = ctz64(mm); cnt[b]--; mm &= mm - 1; }\n                alive[idx] = 0;\n                changed = true;\n            }\n        }\n    }\n    vector<int> res;\n    res.reserve(sel.size());\n    for (int idx : sel) if (alive[idx]) res.push_back(idx);\n    return res;\n}\n\n// Greedy selection with weights, per-action cost noise, and stochastic pick among top-K\nvector<int> greedy_select_weighted_noisy(const vector<Action>& acts, int M, const vector<double>& w,\n                                         std::mt19937& rng, double noise_beta = 0.12, int pickK = 3, double pickP2 = 0.15, double pickP3 = 0.05) {\n    int A = (int)acts.size();\n    vector<double> costEff(A);\n    uniform_real_distribution<double> urand(0.0, 1.0);\n    for (int i = 0; i < A; ++i) {\n        double noise = 1.0 + noise_beta * (urand(rng) * 2.0 - 1.0); // [1-beta, 1+beta]\n        noise = max(0.5, min(2.0, noise));\n        costEff[i] = acts[i].cost * noise;\n    }\n\n    vector<int> order(A);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    vector<int> rank(A);\n    for (int i = 0; i < A; ++i) rank[order[i]] = i;\n\n    uint64_t covered = 0;\n    // Restrict to bits that appear in acts\n    uint64_t unionMask = 0;\n    for (auto &a : acts) unionMask |= a.mask;\n\n    vector<int> sel;\n    sel.reserve(M);\n\n    auto allCovered = [&](){ return (covered & unionMask) == unionMask; };\n\n    while (!allCovered()) {\n        array<int, 3> topIdx = {-1, -1, -1};\n        array<double, 3> topRatio = {1e100, 1e100, 1e100};\n        array<int, 3> topCost = {INT_MAX, INT_MAX, INT_MAX};\n        array<int, 3> topRank = {INT_MAX, INT_MAX, INT_MAX};\n\n        for (int a = 0; a < A; ++a) {\n            uint64_t gmask = acts[a].mask & ~covered;\n            if (!gmask) continue;\n            double gain = 0.0;\n            uint64_t mm = gmask;\n            while (mm) { int b = ctz64(mm); gain += w[b]; mm &= mm - 1; }\n            if (gain <= 0.0) continue;\n            double ratio = costEff[a] / gain;\n            for (int k = 0; k < min(pickK, 3); ++k) {\n                if (ratio < topRatio[k] ||\n                    (ratio == topRatio[k] && (acts[a].cost < topCost[k] ||\n                                              (acts[a].cost == topCost[k] && rank[a] < topRank[k])))) {\n                    for (int t = min(pickK, 3)-1; t > k; --t) { topIdx[t] = topIdx[t-1]; topRatio[t] = topRatio[t-1]; topCost[t] = topCost[t-1]; topRank[t] = topRank[t-1]; }\n                    topIdx[k] = a; topRatio[k] = ratio; topCost[k] = acts[a].cost; topRank[k] = rank[a];\n                    break;\n                }\n            }\n        }\n        int chosen = -1;\n        if (topIdx[0] == -1) break;\n        double r = urand(rng);\n        if (pickK >= 3 && r < pickP3 && topIdx[2] != -1) chosen = topIdx[2];\n        else if (r < pickP2 && topIdx[1] != -1) chosen = topIdx[1];\n        else chosen = topIdx[0];\n\n        sel.push_back(chosen);\n        covered |= acts[chosen].mask;\n    }\n\n    sel = prune_selection(sel, acts, M);\n    return sel;\n}\n\nvector<int> compute_counts(const vector<int>& sel, const vector<Action>& acts, int M) {\n    vector<int> cnt(M, 0);\n    for (int idx : sel) {\n        uint64_t m = acts[idx].mask;\n        while (m) { int b = ctz64(m); cnt[b]++; m &= m - 1; }\n    }\n    return cnt;\n}\n\npair<vector<int>, int> greedy_repair(uint64_t remU, const vector<Action>& acts, const vector<char>& banned, const vector<double>& w) {\n    vector<int> add;\n    int addCost = 0;\n    uint64_t rem = remU;\n    while (rem) {\n        int best = -1;\n        double best_ratio = 1e100;\n        int best_cost = INT_MAX;\n        for (int a = 0; a < (int)acts.size(); ++a) {\n            if ((int)banned.size() == (int)acts.size() && banned[a]) continue;\n            uint64_t gm = acts[a].mask & rem;\n            if (!gm) continue;\n            double gain = 0.0;\n            uint64_t mm = gm;\n            while (mm) { int b = ctz64(mm); gain += w[b]; mm &= mm - 1; }\n            double ratio = acts[a].cost / gain;\n            if (ratio < best_ratio || (ratio == best_ratio && acts[a].cost < best_cost)) {\n                best = a; best_ratio = ratio; best_cost = acts[a].cost;\n            }\n        }\n        if (best == -1) return {{}, INT_MAX};\n        add.push_back(best);\n        addCost += acts[best].cost;\n        rem &= ~acts[best].mask;\n    }\n    return {add, addCost};\n}\n\n// Exact DP to cover a small set of Oni (Rem). Returns chosen action indices and cost, or INF if impossible.\npair<vector<int>, int> exact_cover_dp(uint64_t Rem,\n                                      const vector<Action>& acts,\n                                      const vector<vector<int>>& coverActs,\n                                      const vector<char>& banned,\n                                      int r_limit = 16,\n                                      int cand_limit = 60) {\n    if (Rem == 0ULL) return {{}, 0};\n    vector<int> bits;\n    uint64_t tmp = Rem;\n    while (tmp) { bits.push_back(ctz64(tmp)); tmp &= tmp - 1; }\n    int r = (int)bits.size();\n    if (r > r_limit) return {{}, INT_MAX};\n    int A = (int)acts.size();\n\n    vector<int> compIdx(64, -1);\n    for (int i = 0; i < r; ++i) compIdx[bits[i]] = i;\n    int FULL = (1 << r) - 1;\n\n    vector<char> used(A, 0);\n    vector<int> candIdx;\n    candIdx.reserve(256);\n    for (int b : bits) for (int a : coverActs[b]) {\n        if (!banned.empty() && banned[a]) continue;\n        if (!used[a]) { used[a] = 1; candIdx.push_back(a); }\n    }\n    if (candIdx.empty()) return {{}, INT_MAX};\n\n    struct Cand { int idx; int cost; int pmask; double ratio; };\n    vector<Cand> cands; cands.reserve(candIdx.size());\n    for (int ai : candIdx) {\n        uint64_t m = acts[ai].mask & Rem;\n        if (!m) continue;\n        int pm = 0;\n        while (m) { int b = ctz64(m); pm |= (1 << compIdx[b]); m &= m - 1; }\n        int pc = __builtin_popcount((unsigned)pm);\n        if (pc == 0) continue;\n        Cand c{ai, acts[ai].cost, pm, (double)acts[ai].cost / (double)pc};\n        cands.push_back(c);\n    }\n    if (cands.empty()) return {{}, INT_MAX};\n\n    // ensure essentials\n    vector<int> essential;\n    essential.reserve(r);\n    for (int i = 0; i < r; ++i) {\n        int best = -1, bestCost = INT_MAX;\n        int bitMask = (1 << i);\n        for (auto &c : cands) if (c.pmask & bitMask) {\n            if (c.cost < bestCost) { bestCost = c.cost; best = c.idx; }\n        }\n        if (best != -1) essential.push_back(best);\n    }\n\n    sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){\n        if (a.ratio != b.ratio) return a.ratio < b.ratio;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return a.idx < b.idx;\n    });\n    vector<int> finalIdx;\n    finalIdx.reserve(min((int)cands.size(), cand_limit) + (int)essential.size());\n    for (int i = 0; i < (int)cands.size() && (int)finalIdx.size() < cand_limit; ++i) finalIdx.push_back(cands[i].idx);\n    sort(finalIdx.begin(), finalIdx.end());\n    for (int e : essential) if (!binary_search(finalIdx.begin(), finalIdx.end(), e)) finalIdx.push_back(e);\n\n    struct FinalCand { int idx; int cost; int pmask; };\n    vector<FinalCand> fin;\n    fin.reserve(finalIdx.size());\n    for (int ai : finalIdx) {\n        uint64_t m = acts[ai].mask & Rem;\n        if (!m) continue;\n        int pm = 0;\n        while (m) { int b = ctz64(m); int ci = compIdx[b]; if (ci >= 0) pm |= (1 << ci); m &= m - 1; }\n        if (pm == 0) continue;\n        fin.push_back({ai, acts[ai].cost, pm});\n    }\n    if (fin.empty()) return {{}, INT_MAX};\n\n    int Smax = 1 << r;\n    const int INF = 1e9;\n    vector<int> dp(Smax, INF), parent(Smax, -1), which(Smax, -1);\n    dp[0] = 0;\n    for (auto &c : fin) {\n        int pm = c.pmask, cc = c.cost, ci = c.idx;\n        for (int S = 0; S < Smax; ++S) {\n            if (dp[S] == INF) continue;\n            int T = S | pm;\n            if (dp[S] + cc < dp[T]) {\n                dp[T] = dp[S] + cc;\n                parent[T] = S;\n                which[T] = ci;\n            }\n        }\n    }\n    if (dp[FULL] >= INF) return {{}, INT_MAX};\n    vector<int> picks;\n    int cur = FULL;\n    while (cur != 0) {\n        int wi = which[cur];\n        if (wi == -1) { picks.clear(); break; }\n        picks.push_back(wi);\n        cur = parent[cur];\n    }\n    if (picks.empty() && FULL != 0) return {{}, INT_MAX};\n    return {picks, dp[FULL]};\n}\n\n// Build cover lists: for each Oni id, which actions cover it\nvector<vector<int>> build_cover_lists(const vector<Action>& acts, int M) {\n    vector<vector<int>> cover(M);\n    for (int a = 0; a < (int)acts.size(); ++a) {\n        uint64_t m = acts[a].mask;\n        while (m) { int b = ctz64(m); cover[b].push_back(a); m &= m - 1; }\n    }\n    return cover;\n}\n\n// Local improvement using exact DP replacements; 'locked' actions are not removed.\nvoid local_improvement_dp_locked(vector<int>& sel, const vector<Action>& acts, int M,\n                                 const vector<vector<int>>& coverActs, std::mt19937& rng,\n                                 const vector<char>& locked,\n                                 double time_limit_ms = 100.0) {\n    auto t0 = chrono::high_resolution_clock::now();\n    auto time_ok = [&](){\n        auto t1 = chrono::high_resolution_clock::now();\n        double ms = chrono::duration<double, std::milli>(t1 - t0).count();\n        return ms < time_limit_ms;\n    };\n\n    int A = acts.size();\n    if (sel.empty()) return;\n    vector<int> cnt = compute_counts(sel, acts, M);\n    int bestCost = selection_cost(sel, acts);\n\n    // 1->k replacements\n    bool improved_global = true;\n    while (improved_global && time_ok()) {\n        improved_global = false;\n        vector<int> order = sel;\n        shuffle(order.begin(), order.end(), rng);\n        for (int sIdx : order) {\n            if (!time_ok()) break;\n            if (locked[sIdx]) continue;\n            uint64_t m = acts[sIdx].mask;\n            uint64_t uniqueMask = 0;\n            uint64_t mm = m;\n            while (mm) { int b = ctz64(mm); if (cnt[b] == 1) uniqueMask |= (1ULL << b); mm &= mm - 1; }\n            if (!uniqueMask) continue;\n            int r = __builtin_popcountll(uniqueMask);\n            vector<char> banned; // empty banned: allow any action (except we already have unique not covered by others)\n            vector<int> addList; int addCost = INT_MAX;\n            if (r <= 16) {\n                auto res = exact_cover_dp(uniqueMask, acts, coverActs, banned, 16, 80);\n                addList = res.first; addCost = res.second;\n            }\n            if (r > 16 || addCost == INT_MAX) {\n                vector<double> w(M, 1.0);\n                auto gr = greedy_repair(uniqueMask, acts, banned, w);\n                addList = gr.first; addCost = gr.second;\n            }\n            if (addCost >= acts[sIdx].cost) continue;\n            vector<int> newSel;\n            newSel.reserve(sel.size() - 1 + addList.size());\n            for (int id : sel) if (id != sIdx) newSel.push_back(id);\n            for (int id : addList) newSel.push_back(id);\n            newSel = prune_selection(newSel, acts, M);\n            int newCost = selection_cost(newSel, acts);\n            if (newCost < bestCost) {\n                sel.swap(newSel);\n                bestCost = newCost;\n                cnt = compute_counts(sel, acts, M);\n                improved_global = true;\n                break;\n            }\n        }\n    }\n\n    if (!time_ok()) return;\n\n    // 2->k replacements: random tries\n    int tries = 80;\n    while (tries-- > 0 && time_ok()) {\n        if ((int)sel.size() < 2) break;\n        int ia = rng() % sel.size();\n        int ib = rng() % sel.size();\n        if (ia == ib) continue;\n        int s1 = sel[ia], s2 = sel[ib];\n        if (locked[s1] || locked[s2]) continue;\n        // compute uncovered if removing s1,s2\n        vector<int> cnt2 = cnt;\n        uint64_t baseCovered = 0;\n        for (int id : sel) if (id != s1 && id != s2) baseCovered |= acts[id].mask;\n        uint64_t remU = (acts[s1].mask | acts[s2].mask) & ~baseCovered;\n        if (!remU) {\n            // removing both reduces cost\n            vector<int> newSel;\n            newSel.reserve(sel.size()-2);\n            for (int id : sel) if (id != s1 && id != s2) newSel.push_back(id);\n            newSel = prune_selection(newSel, acts, M);\n            int newCost = selection_cost(newSel, acts);\n            if (newCost < bestCost) {\n                sel.swap(newSel);\n                bestCost = newCost;\n                cnt = compute_counts(sel, acts, M);\n            }\n            continue;\n        }\n        int r = __builtin_popcountll(remU);\n        vector<char> banned; // allow any actions\n        vector<int> addList; int addCost = INT_MAX;\n        if (r <= 16) {\n            auto res = exact_cover_dp(remU, acts, coverActs, banned, 16, 100);\n            addList = res.first; addCost = res.second;\n        }\n        if (r > 16 || addCost == INT_MAX) {\n            vector<double> w(M, 1.0);\n            auto gr = greedy_repair(remU, acts, banned, w);\n            addList = gr.first; addCost = gr.second;\n        }\n        int removedCost = acts[s1].cost + acts[s2].cost;\n        if (addCost >= removedCost) continue;\n        vector<int> newSel;\n        newSel.reserve(sel.size() - 2 + addList.size());\n        for (int id : sel) if (id != s1 && id != s2) newSel.push_back(id);\n        for (int id : addList) newSel.push_back(id);\n        newSel = prune_selection(newSel, acts, M);\n        int newCost = selection_cost(newSel, acts);\n        if (newCost < bestCost) {\n            sel.swap(newSel);\n            bestCost = newCost;\n            cnt = compute_counts(sel, acts, M);\n        }\n    }\n}\n\n// Large Neighborhood Search (LNS): remove a small random set of non-locked actions and repair\nvoid lns_improve(vector<int>& sel, const vector<Action>& acts, int M,\n                 const vector<vector<int>>& coverActs, const vector<char>& locked,\n                 std::mt19937& rng, double time_limit_ms = 150.0) {\n    auto t0 = chrono::high_resolution_clock::now();\n    auto time_ok = [&](){\n        auto t1 = chrono::high_resolution_clock::now();\n        double ms = chrono::duration<double, std::milli>(t1 - t0).count();\n        return ms < time_limit_ms;\n    };\n\n    int bestCost = selection_cost(sel, acts);\n    if (sel.empty()) return;\n\n    uniform_real_distribution<double> urand(0.0, 1.0);\n\n    while (time_ok()) {\n        // choose group size\n        int gs;\n        double r = urand(rng);\n        if (r < 0.5) gs = 3;\n        else if (r < 0.85) gs = 2;\n        else gs = 4;\n        if (gs > (int)sel.size()) gs = sel.size();\n\n        // pick gs distinct non-locked actions\n        vector<int> idxs;\n        idxs.reserve(gs);\n        int attempts = 0;\n        while ((int)idxs.size() < gs && attempts < 50) {\n            int pos = rng() % sel.size();\n            int s = sel[pos];\n            if (locked[s]) { attempts++; continue; }\n            bool ok = true;\n            for (int x : idxs) if (x == s) { ok = false; break; }\n            if (ok) idxs.push_back(s);\n            attempts++;\n        }\n        if (idxs.empty()) break;\n\n        // compute uncovered by removing idxs\n        uint64_t baseCovered = 0, unionGroup = 0;\n        for (int id : sel) {\n            bool inGroup = false;\n            for (int g : idxs) if (id == g) { inGroup = true; break; }\n            if (!inGroup) baseCovered |= acts[id].mask;\n            else unionGroup |= acts[id].mask;\n        }\n        uint64_t remU = unionGroup & ~baseCovered;\n        if (!remU) {\n            // removal alone improves\n            vector<int> newSel;\n            newSel.reserve(sel.size() - (int)idxs.size());\n            for (int id : sel) {\n                bool inGroup = false;\n                for (int g : idxs) if (id == g) { inGroup = true; break; }\n                if (!inGroup) newSel.push_back(id);\n            }\n            newSel = prune_selection(newSel, acts, M);\n            int newCost = selection_cost(newSel, acts);\n            if (newCost < bestCost) {\n                sel.swap(newSel);\n                bestCost = newCost;\n            }\n            continue;\n        }\n\n        int rbits = __builtin_popcountll(remU);\n        vector<char> banned; // allow any\n        vector<int> addList; int addCost = INT_MAX;\n        if (rbits <= 18) {\n            auto res = exact_cover_dp(remU, acts, coverActs, banned, 18, 120);\n            addList = res.first; addCost = res.second;\n        }\n        if (rbits > 18 || addCost == INT_MAX) {\n            vector<double> w(M, 1.0);\n            auto gr = greedy_repair(remU, acts, banned, w);\n            addList = gr.first; addCost = gr.second;\n        }\n        int removedCost = 0;\n        for (int g : idxs) removedCost += acts[g].cost;\n        if (addCost >= removedCost) continue;\n\n        vector<int> newSel;\n        newSel.reserve(sel.size() - (int)idxs.size() + addList.size());\n        for (int id : sel) {\n            bool inGroup = false;\n            for (int g : idxs) if (id == g) { inGroup = true; break; }\n            if (!inGroup) newSel.push_back(id);\n        }\n        for (int id : addList) newSel.push_back(id);\n        newSel = prune_selection(newSel, acts, M);\n        int newCost = selection_cost(newSel, acts);\n        if (newCost < bestCost) {\n            sel.swap(newSel);\n            bestCost = newCost;\n        }\n    }\n}\n\n// Build baseline actions: per Oni minimal safe cycle\nvector<Action> build_baseline_actions(const vector<string>& grid,\n                                      const vector<pair<int,int>>& oni_pos) {\n    int N = grid.size();\n    vector<Action> acts;\n    acts.reserve(oni_pos.size());\n\n    vector<vector<int>> fuku_row_pref(N, vector<int>(N+1, 0));\n    vector<vector<int>> fuku_col_pref(N, vector<int>(N+1, 0));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            fuku_row_pref[i][j+1] = fuku_row_pref[i][j] + (grid[i][j] == 'o');\n            fuku_col_pref[j][i+1] = fuku_col_pref[j][i] + (grid[i][j] == 'o');\n        }\n    }\n    auto no_fuku_row = [&](int r, int l, int rgt) -> bool {\n        if (l > rgt) return true;\n        return (fuku_row_pref[r][rgt+1] - fuku_row_pref[r][l]) == 0;\n    };\n    auto no_fuku_col = [&](int c, int top, int bot) -> bool {\n        if (top > bot) return true;\n        return (fuku_col_pref[c][bot+1] - fuku_col_pref[c][top]) == 0;\n    };\n\n    for (auto [i, j] : oni_pos) {\n        vector<pair<int,pair<char,int>>> cand; // cost, (dir, k)\n        if (no_fuku_col(j, 0, i-1)) { int k = i + 1; cand.push_back({2*k, {'U', k}}); }\n        if (no_fuku_col(j, i+1, N-1)) { int k = N - i; cand.push_back({2*k, {'D', k}}); }\n        if (no_fuku_row(i, 0, j-1)) { int k = j + 1; cand.push_back({2*k, {'L', k}}); }\n        if (no_fuku_row(i, j+1, N-1)) { int k = N - j; cand.push_back({2*k, {'R', k}}); }\n        if (cand.empty()) continue;\n        auto best = min_element(cand.begin(), cand.end(),\n                                [](auto& a, auto& b){ return a.first < b.first; });\n        Action a; a.d = best->second.first; a.p = (a.d == 'L' || a.d == 'R') ? i : j; a.k = best->second.second; a.cost = best->first; a.mask = 0;\n        acts.push_back(a);\n    }\n    return acts;\n}\n\nvector<pair<char,int>> actions_to_ops(const vector<int>& sel, const vector<Action>& acts) {\n    vector<pair<char,int>> ops;\n    long long total = 0;\n    for (int idx : sel) total += acts[idx].cost;\n    ops.reserve((size_t)total);\n    for (int idx : sel) {\n        const auto& a = acts[idx];\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(a.d, a.p);\n        char od = opposite(a.d);\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(od, a.p);\n    }\n    return ops;\n}\nvector<pair<char,int>> actions_to_ops_direct(const vector<Action>& acts) {\n    vector<pair<char,int>> ops;\n    long long total = 0;\n    for (auto& a : acts) total += a.cost;\n    ops.reserve((size_t)total);\n    for (auto& a : acts) {\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(a.d, a.p);\n        char od = opposite(a.d);\n        for (int t = 0; t < a.k; ++t) ops.emplace_back(od, a.p);\n    }\n    return ops;\n}\n\n// Kernelization: pick forced actions (Oni covered by exactly one action).\nstruct KernelResult {\n    vector<Action> reducedActs;\n    vector<int> forcedIdx; // indices in original 'acts'\n    uint64_t forcedCovered = 0;\n};\nKernelResult kernelize_forced(const vector<Action>& acts, int M) {\n    int A = acts.size();\n    vector<Action> work = acts; // will mutate masks\n    vector<char> forcedA(A, 0);\n    uint64_t forcedCovered = 0;\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        vector<vector<int>> cover(M);\n        for (int a = 0; a < A; ++a) if (!forcedA[a] && work[a].mask) {\n            uint64_t m = work[a].mask;\n            while (m) { int b = ctz64(m); cover[b].push_back(a); m &= m - 1; }\n        }\n        for (int b = 0; b < M; ++b) {\n            if (cover[b].empty()) continue;\n            if ((int)cover[b].size() == 1) {\n                int a = cover[b][0];\n                if (forcedA[a]) continue;\n                forcedA[a] = 1;\n                forcedCovered |= acts[a].mask; // use original mask\n                for (int i = 0; i < A; ++i) if (!forcedA[i] && work[i].mask) {\n                    work[i].mask &= ~acts[a].mask;\n                }\n                changed = true;\n            }\n        }\n    }\n    vector<Action> reduced;\n    reduced.reserve(A);\n    for (int i = 0; i < A; ++i) {\n        if (forcedA[i]) continue;\n        if (work[i].mask == 0) continue;\n        reduced.push_back(work[i]);\n    }\n    vector<int> forcedIdx;\n    forcedIdx.reserve(A);\n    for (int i = 0; i < A; ++i) if (forcedA[i]) forcedIdx.push_back(i);\n    return {reduced, forcedIdx, forcedCovered};\n}\n\n// Primal-dual style selector as another seed\nvector<int> primal_dual_select(const vector<Action>& acts, int M) {\n    int A = acts.size();\n    if (A == 0) return {};\n    vector<double> slack(A);\n    for (int i = 0; i < A; ++i) slack[i] = acts[i].cost;\n    vector<char> selected(A, 0);\n    uint64_t unionMask = 0;\n    for (auto &a : acts) unionMask |= a.mask;\n    uint64_t uncovered = unionMask;\n    auto cover = build_cover_lists(acts, M);\n\n    while (uncovered) {\n        // pick bit with smallest cover size\n        int bestBit = -1;\n        int bestDeg = INT_MAX;\n        uint64_t tmp = uncovered;\n        while (tmp) {\n            int b = ctz64(tmp);\n            int deg = 0;\n            for (int a : cover[b]) if (!selected[a]) deg++;\n            if (deg > 0 && deg < bestDeg) { bestDeg = deg; bestBit = b; }\n            tmp &= tmp - 1;\n        }\n        if (bestBit == -1) break;\n        int bestA = -1;\n        double bestSlack = 1e100;\n        for (int a : cover[bestBit]) if (!selected[a]) {\n            if (slack[a] < bestSlack) { bestSlack = slack[a]; bestA = a; }\n        }\n        if (bestA == -1) break;\n        if (bestSlack > 0) {\n            for (int a : cover[bestBit]) if (!selected[a]) slack[a] -= bestSlack;\n        }\n        selected[bestA] = 1;\n        uncovered &= ~acts[bestA].mask;\n    }\n    vector<int> sel;\n    for (int i = 0; i < A; ++i) if (selected[i]) sel.push_back(i);\n    sel = prune_selection(sel, acts, M);\n    return sel;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> N)) return 0;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n\n    vector<pair<int,int>> oni_pos;\n    vector<vector<int>> oni_id(N, vector<int>(N, -1));\n    for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j)\n        if (grid[i][j] == 'x') {\n            int id = oni_pos.size();\n            oni_pos.emplace_back(i, j);\n            oni_id[i][j] = id;\n        }\n    int M = (int)oni_pos.size();\n\n    // Build candidates with pruning\n    vector<Action> actsAll = build_candidates_tight(grid, oni_pos, oni_id);\n\n    // Kernelization: forced picks\n    KernelResult ker = kernelize_forced(actsAll, M);\n    vector<Action> acts = ker.reducedActs;\n    vector<int> forcedIdxAll = ker.forcedIdx; // indices in actsAll\n\n    // Availability per Oni on reduced acts\n    vector<int> avail(M, 0);\n    for (auto &a : acts) {\n        uint64_t m = a.mask;\n        while (m) { int b = ctz64(m); avail[b]++; m &= m - 1; }\n    }\n\n    // Weight variants\n    vector<vector<double>> weightVariants;\n    {\n        vector<double> w0(M, 1.0), w1(M, 1.0), w2(M, 1.0), w3(M, 1.0);\n        for (int i = 0; i < M; ++i) {\n            int av = max(1, avail[i]);\n            w1[i] = 1.0 / sqrt((double)av);\n            w2[i] = 1.0 / (double)av;\n            w3[i] = (av <= 2 ? 3.0 : (av == 3 ? 2.0 : 1.0)); // scarcity boost\n        }\n        weightVariants.push_back(w0);\n        weightVariants.push_back(w1);\n        weightVariants.push_back(w2);\n        weightVariants.push_back(w3);\n    }\n\n    std::mt19937 rng(712367 + (uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Multiple weighted greedy restarts with noise and stochasticity\n    vector<int> bestSel2;\n    int bestCost2 = INT_MAX;\n    int restarts = 28;\n    for (int t = 0; t < restarts; ++t) {\n        const auto& w = weightVariants[t % weightVariants.size()];\n        vector<int> sel2 = greedy_select_weighted_noisy(acts, M, w, rng, 0.12, 3, 0.15, 0.05);\n        int cst2 = selection_cost(sel2, acts);\n        if (cst2 < bestCost2) { bestSel2 = move(sel2); bestCost2 = cst2; }\n    }\n    // Primal-dual seed\n    {\n        vector<int> sel2 = primal_dual_select(acts, M);\n        int cst2 = selection_cost(sel2, acts);\n        if (cst2 < bestCost2) { bestSel2 = move(sel2); bestCost2 = cst2; }\n    }\n\n    // Combine forced picks + selected from reduced acts into combined acts space\n    vector<Action> combinedActs;\n    combinedActs.reserve(forcedIdxAll.size() + acts.size());\n    // push forced actions with original masks\n    for (int idxAll : forcedIdxAll) combinedActs.push_back(actsAll[idxAll]);\n    // then remaining acts (already have forced bits removed)\n    for (auto &a : acts) combinedActs.push_back(a);\n\n    // Build initial combined selection indices\n    vector<int> selCombined;\n    selCombined.reserve(forcedIdxAll.size() + bestSel2.size());\n    for (int i = 0; i < (int)forcedIdxAll.size(); ++i) selCombined.push_back(i);\n    for (int i : bestSel2) selCombined.push_back((int)forcedIdxAll.size() + i);\n    // Prune globally\n    selCombined = prune_selection(selCombined, combinedActs, M);\n\n    // Local improvement with DP; lock forced picks\n    vector<char> locked(combinedActs.size(), 0);\n    for (int i = 0; i < (int)forcedIdxAll.size(); ++i) locked[i] = 1;\n    auto coverActs = build_cover_lists(combinedActs, M);\n    local_improvement_dp_locked(selCombined, combinedActs, M, coverActs, rng, locked, 120.0);\n\n    // LNS improvement\n    lns_improve(selCombined, combinedActs, M, coverActs, locked, rng, 200.0);\n\n    // Final prune\n    selCombined = prune_selection(selCombined, combinedActs, M);\n\n    // Produce greedy ops and validate strictly\n    auto opsGreedy = actions_to_ops(selCombined, combinedActs);\n    auto checkGreedy = simulate(grid, opsGreedy);\n    bool greedyValid = (checkGreedy.first == 0 && checkGreedy.second == 0);\n\n    // Baseline fallback (guaranteed safe)\n    vector<Action> baseActs = build_baseline_actions(grid, oni_pos);\n    auto opsBase = actions_to_ops_direct(baseActs);\n    auto checkBase = simulate(grid, opsBase);\n    bool baseValid = (checkBase.first == 0 && checkBase.second == 0);\n\n    vector<pair<char,int>> ops;\n    if (greedyValid && baseValid) {\n        ops = (opsGreedy.size() <= opsBase.size()) ? move(opsGreedy) : move(opsBase);\n    } else if (greedyValid) {\n        ops = move(opsGreedy);\n    } else if (baseValid) {\n        ops = move(opsBase);\n    } else {\n        ops = move(opsBase);\n    }\n\n    if ((int)ops.size() > 4*N*N) {\n        if (baseValid && (int)opsBase.size() <= 4*N*N) {\n            ops = move(opsBase);\n        } else if (greedyValid && (int)opsGreedy.size() <= 4*N*N) {\n            ops = move(opsGreedy);\n        } else {\n            ops.resize(4*N*N);\n        }\n    }\n\n    for (auto &op : ops) cout << op.first << ' ' << op.second << '\\n';\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() { reset(); }\n    void reset() { st = chrono::high_resolution_clock::now(); }\n    double ms() const {\n        return chrono::duration<double, std::milli>(\n            chrono::high_resolution_clock::now() - st\n        ).count();\n    }\n};\n\nstruct Candidate {\n    vector<int> a, b;\n    long long E_full = (1LL<<62);\n    long long E_part = (1LL<<62);\n};\n\nstatic long long simulate_error_full(const vector<int>& a, const vector<int>& b,\n                                     int L, const vector<int>& T) {\n    int N = (int)a.size();\n    vector<int> t(N, 0);\n    int cur = 0;\n    for (int step = 0; step < L; ++step) {\n        t[cur] += 1;\n        if (t[cur] & 1) cur = a[cur];\n        else cur = b[cur];\n    }\n    long long E = 0;\n    for (int i = 0; i < N; ++i) {\n        E += llabs((long long)t[i] - (long long)T[i]);\n    }\n    return E;\n}\n\nstatic long long simulate_error_partial(const vector<int>& a, const vector<int>& b,\n                                        int Lpart, const vector<int>& Tpart) {\n    int N = (int)a.size();\n    vector<int> t(N, 0);\n    int cur = 0;\n    for (int step = 0; step < Lpart; ++step) {\n        t[cur] += 1;\n        if (t[cur] & 1) cur = a[cur];\n        else cur = b[cur];\n    }\n    long long E = 0;\n    for (int i = 0; i < N; ++i) {\n        E += llabs((long long)t[i] - (long long)Tpart[i]);\n    }\n    return E;\n}\n\n// Build a-edge from an order\nstatic void build_a_from_order(const vector<int>& order, vector<int>& a) {\n    int N = (int)order.size();\n    a.assign(N, 0);\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    }\n}\n\n// Compute residual target D[j] = 2*T[j] - T[prev(j)] for given order (no clamping)\nstatic void residuals_from_order(const vector<int>& order, const vector<int>& T, vector<long long>& D) {\n    int N = (int)order.size();\n    D.assign(N, 0);\n    for (int k = 0; k < N; ++k) {\n        int j = order[k];\n        int prev = order[(k-1+N)%N];\n        D[j] = 2LL * (long long)T[j] - (long long)T[prev];\n    }\n}\n\n// Snake order A: evens ascending then odds descending\nstatic vector<int> build_snake_order_A(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng); // random tie-breaking\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    vector<int> evenIdx, oddIdx;\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) evenIdx.push_back(ord[i]);\n        else oddIdx.push_back(ord[i]);\n    }\n    vector<int> order;\n    order.reserve(N);\n    for (int x : evenIdx) order.push_back(x);\n    for (int k = (int)oddIdx.size()-1; k >= 0; --k) order.push_back(oddIdx[k]);\n    return order;\n}\n\n// Snake order B: odds ascending then evens descending\nstatic vector<int> build_snake_order_B(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    vector<int> evenIdx, oddIdx;\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) evenIdx.push_back(ord[i]);\n        else oddIdx.push_back(ord[i]);\n    }\n    vector<int> order;\n    order.reserve(N);\n    for (int x : oddIdx) order.push_back(x);\n    for (int k = (int)evenIdx.size()-1; k >= 0; --k) order.push_back(evenIdx[k]);\n    return order;\n}\n\n// Pure ascending order cycle\nstatic vector<int> build_ascending_order(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    return ord;\n}\n\n// Alternating extremes: low, high, low2, high2, ...\nstatic vector<int> build_alternating_extremes(const vector<int>& T, mt19937_64& rng) {\n    int N = (int)T.size();\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] < T[j];\n        return i < j;\n    });\n    vector<int> order;\n    order.reserve(N);\n    int l = 0, r = N - 1;\n    bool takeLow = true;\n    while (l <= r) {\n        if (takeLow) order.push_back(ord[l++]);\n        else order.push_back(ord[r--]);\n        takeLow = !takeLow;\n    }\n    return order;\n}\n\n// Greedy ring insertion to minimize sum of c(prev, curr) where c = max(0, Tprev - 2*Tcurr)\nstatic long long edge_cost(int prev, int curr, const vector<int>& T) {\n    long long v = (long long)T[prev] - 2LL * (long long)T[curr];\n    return v > 0 ? v : 0;\n}\nstatic vector<int> build_insertion_order(const vector<int>& T, mt19937_64& rng, int seedMode = 0) {\n    int N = (int)T.size();\n    vector<int> nodes(N);\n    iota(nodes.begin(), nodes.end(), 0);\n    // pick initial two nodes\n    int u = 0, v = 1;\n    if (seedMode == 0) {\n        // choose u median by T\n        vector<int> idx = nodes;\n        stable_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        u = idx[N/2];\n    } else if (seedMode == 1) {\n        // choose u from upper quartile\n        vector<int> idx = nodes;\n        stable_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        u = idx[(3*N)/4];\n    } else {\n        // random u\n        u = (int)(rng() % N);\n    }\n    // choose v minimizing edge_cost(u,v)+edge_cost(v,u)\n    long long best = (1LL<<62);\n    for (int cand : nodes) if (cand != u) {\n        long long sc = edge_cost(u, cand, T) + edge_cost(cand, u, T);\n        if (sc < best) { best = sc; v = cand; }\n    }\n    vector<int> cycle;\n    cycle.push_back(u);\n    cycle.push_back(v);\n    vector<char> used(N, 0);\n    used[u] = used[v] = 1;\n    while ((int)cycle.size() < N) {\n        int x = -1;\n        long long bestDelta = (1LL<<62);\n        // try every unused node and every insertion arc\n        for (int cand : nodes) {\n            if (used[cand]) continue;\n            int m = (int)cycle.size();\n            for (int i = 0; i < m; ++i) {\n                int p = cycle[i];\n                int q = cycle[(i+1)%m];\n                long long delta = edge_cost(p, cand, T) + edge_cost(cand, q, T) - edge_cost(p, q, T);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    x = cand;\n                }\n            }\n        }\n        // insert x at best position\n        int bestPos = -1;\n        {\n            int m = (int)cycle.size();\n            for (int i = 0; i < m; ++i) {\n                int p = cycle[i];\n                int q = cycle[(i+1)%m];\n                long long delta = edge_cost(p, x, T) + edge_cost(x, q, T) - edge_cost(p, q, T);\n                if (delta == bestDelta) { bestPos = (i+1)%m; break; }\n            }\n        }\n        if (bestPos == -1) bestPos = (int)cycle.size(); // fallback\n        cycle.insert(cycle.begin() + bestPos, x);\n        used[x] = 1;\n    }\n    return cycle;\n}\n\n// Greedy assignment of b with residual r initialized to D\nstatic void greedy_assign_b(const vector<int>& T, vector<long long>& r,\n                            mt19937_64 &rng, vector<int>& b) {\n    int N = (int)T.size();\n    b.assign(N, 0);\n    vector<int> items(N);\n    iota(items.begin(), items.end(), 0);\n    shuffle(items.begin(), items.end(), rng);\n    stable_sort(items.begin(), items.end(), [&](int i, int j){\n        if (T[i] != T[j]) return T[i] > T[j];\n        return i < j;\n    });\n\n    for (int idx = 0; idx < N; ++idx) {\n        int i = items[idx];\n        long long w = T[i];\n        long long bestDelta = (1LL<<62);\n        vector<int> cands;\n        for (int j = 0; j < N; ++j) {\n            long long rj = r[j];\n            long long delta = llabs(rj - w) - llabs(rj);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                cands.clear();\n                cands.push_back(j);\n            } else if (delta == bestDelta) {\n                cands.push_back(j);\n            }\n        }\n        int j = cands[rng() % cands.size()];\n        b[i] = j;\n        r[j] -= w;\n    }\n}\n\n// Local improvement: move single items from oversupplied bins (r<0) to deficit bins (r>0)\nstatic void local_improve_moves(const vector<int>& T, vector<long long>& r,\n                                vector<int>& b, mt19937_64 &rng, int passes = 2) {\n    int N = (int)T.size();\n    vector<vector<int>> itemsOfBin(N);\n    itemsOfBin.assign(N, {});\n    for (int i = 0; i < N; ++i) itemsOfBin[b[i]].push_back(i);\n\n    for (int pass = 0; pass < passes; ++pass) {\n        vector<int> deficits, overs;\n        for (int j = 0; j < N; ++j) {\n            if (r[j] > 0) deficits.push_back(j);\n            else if (r[j] < 0) overs.push_back(j);\n        }\n        if (deficits.empty() || overs.empty()) break;\n        // fill larger deficits first\n        stable_sort(deficits.begin(), deficits.end(), [&](int x, int y){ return r[x] > r[y]; });\n        for (int k : deficits) {\n            long long rk = r[k];\n            long long bestGain = 0; // negative delta means improvement\n            int bestFromBin = -1;\n            int bestItem = -1;\n            for (int j : overs) {\n                if (itemsOfBin[j].empty()) continue;\n                long long rj = r[j];\n                for (int ii : itemsOfBin[j]) {\n                    long long w = T[ii];\n                    long long delta = llabs(rj + w) + llabs(rk - w) - (llabs(rj) + llabs(rk));\n                    if (delta < bestGain) {\n                        bestGain = delta;\n                        bestFromBin = j;\n                        bestItem = ii;\n                    }\n                }\n            }\n            if (bestItem != -1) {\n                int j = bestFromBin;\n                int ii = bestItem;\n                long long w = T[ii];\n                // apply move: remove from j, add to k\n                r[j] += w;\n                r[k] -= w;\n                // update bins\n                auto &vj = itemsOfBin[j];\n                for (int idx = 0; idx < (int)vj.size(); ++idx) {\n                    if (vj[idx] == ii) {\n                        vj[idx] = vj.back();\n                        vj.pop_back();\n                        break;\n                    }\n                }\n                itemsOfBin[k].push_back(ii);\n                b[ii] = k;\n            }\n        }\n    }\n}\n\n// Pair-swap local improvement on b\nstatic void local_swap_improve(const vector<int>& T, vector<long long>& r,\n                               vector<int>& b, mt19937_64 &rng, int tries = 220) {\n    int N = (int)T.size();\n    for (int t = 0; t < tries; ++t) {\n        int i1 = rng() % N;\n        int i2 = rng() % N;\n        if (i1 == i2) continue;\n        int j1 = b[i1];\n        int j2 = b[i2];\n        if (j1 == j2) continue;\n        long long w1 = T[i1], w2 = T[i2];\n        long long old = llabs(r[j1]) + llabs(r[j2]);\n        long long r1p = r[j1] + w1 - w2;\n        long long r2p = r[j2] + w2 - w1;\n        long long nw = llabs(r1p) + llabs(r2p);\n        if (nw < old) {\n            r[j1] = r1p;\n            r[j2] = r2p;\n            b[i1] = j2;\n            b[i2] = j1;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, L;\n    if (!(cin >> N >> L)) return 0;\n    vector<int> T(N);\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    Timer timer;\n    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    const double TIME_LIMIT_MS = 1950.0;\n\n    // Prepare partial target Tpart with rounding so that sum Tpart = Lpart\n    const int Lpart = min(L, 120000);\n    vector<int> Tpart(N, 0);\n    {\n        long long sumBase = 0;\n        struct Rem { long long r; int i; };\n        vector<Rem> rems;\n        rems.reserve(N);\n        for (int i = 0; i < N; ++i) {\n            long long num = 1LL * T[i] * Lpart;\n            int base = (int)(num / L);\n            long long rem = num - 1LL * base * L;\n            Tpart[i] = base;\n            sumBase += base;\n            rems.push_back({rem, i});\n        }\n        int need = Lpart - (int)sumBase;\n        stable_sort(rems.begin(), rems.end(), [&](const Rem& a, const Rem& b){\n            if (a.r != b.r) return a.r > b.r;\n            return a.i < b.i;\n        });\n        for (int k = 0; k < need; ++k) Tpart[rems[k].i] += 1;\n    }\n\n    // Build a variety of a-edge orders (and their reverses)\n    vector<vector<int>> orders;\n    orders.reserve(16);\n    auto add_with_reverse = [&](const vector<int>& ord) {\n        orders.push_back(ord);\n        vector<int> rev = ord;\n        reverse(rev.begin(), rev.end());\n        orders.push_back(rev);\n    };\n    add_with_reverse(build_snake_order_A(T, rng));\n    add_with_reverse(build_snake_order_B(T, rng));\n    add_with_reverse(build_ascending_order(T, rng));\n    add_with_reverse(build_alternating_extremes(T, rng));\n    add_with_reverse(build_insertion_order(T, rng, 0));\n    add_with_reverse(build_insertion_order(T, rng, 1));\n    add_with_reverse(build_insertion_order(T, rng, 2));\n\n    // Precompute a-edges and D for each order\n    struct AInfo { vector<int> a; vector<long long> D; };\n    vector<AInfo> ainfos;\n    ainfos.resize(orders.size());\n    for (size_t oi = 0; oi < orders.size(); ++oi) {\n        build_a_from_order(orders[oi], ainfos[oi].a);\n        residuals_from_order(orders[oi], T, ainfos[oi].D);\n    }\n\n    // Search parameters\n    const int TOP_PART = 10;            // keep top candidates by partial error\n    const double FINAL_SIM_BUDGET_MS = 300.0; // reserve time for full sims\n\n    vector<Candidate> topCandidates;\n\n    auto try_candidate = [&](const AInfo& ai) {\n        vector<long long> r = ai.D;\n        vector<int> b(N, 0);\n        greedy_assign_b(T, r, rng, b);\n        local_improve_moves(T, r, b, rng, 2);\n        local_swap_improve(T, r, b, rng, 240);\n\n        Candidate c;\n        c.a = ai.a;\n        c.b = b;\n        c.E_part = simulate_error_partial(c.a, c.b, Lpart, Tpart);\n\n        // maintain top list by partial error\n        if ((int)topCandidates.size() < TOP_PART) {\n            topCandidates.push_back(c);\n            sort(topCandidates.begin(), topCandidates.end(),\n                 [](const Candidate& x, const Candidate& y){ return x.E_part < y.E_part; });\n        } else if (c.E_part < topCandidates.back().E_part) {\n            topCandidates.back() = c;\n            sort(topCandidates.begin(), topCandidates.end(),\n                 [](const Candidate& x, const Candidate& y){ return x.E_part < y.E_part; });\n        }\n    };\n\n    // Main loop: try many b-assignments over the different a cycles\n    size_t oi = 0;\n    while (timer.ms() < TIME_LIMIT_MS - FINAL_SIM_BUDGET_MS) {\n        try_candidate(ainfos[oi]);\n        oi++;\n        if (oi >= ainfos.size()) oi = 0;\n    }\n\n    // Fallback if no candidates generated\n    if (topCandidates.empty()) {\n        vector<int> a(N), b(N);\n        iota(a.begin(), a.end(), 0);\n        for (int i = 0; i < N; ++i) b[i] = (i+1) % N;\n        for (int i = 0; i < N; ++i) cout << a[i] << \" \" << b[i] << \"\\n\";\n        return 0;\n    }\n\n    // Full simulation for top few\n    // Simulate as many as time allows, up to 8\n    int simulate_k = min(8, (int)topCandidates.size());\n    for (int i = 0; i < simulate_k; ++i) {\n        if (timer.ms() > TIME_LIMIT_MS) break;\n        topCandidates[i].E_full = simulate_error_full(topCandidates[i].a, topCandidates[i].b, L, T);\n    }\n    // Select best by full error if available, else by partial\n    Candidate best = topCandidates[0];\n    for (int i = 0; i < simulate_k; ++i) {\n        if (topCandidates[i].E_full < best.E_full) best = topCandidates[i];\n    }\n    if (best.E_full >= (1LL<<61)) {\n        best = *min_element(topCandidates.begin(), topCandidates.end(),\n                            [](const Candidate& x, const Candidate& y){\n                                return x.E_part < y.E_part;\n                            });\n    }\n\n    // Output best\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\n// DSU\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    int find(int x){ return p[x]==x ? x : p[x]=find(p[x]); }\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; sz[a]+=sz[b];\n        return true;\n    }\n};\n\n// Morton (Z-order) 15-bit interleave (coords <= 10000)\nstatic inline uint64_t morton_code(uint32_t x, uint32_t y) {\n    uint64_t code = 0;\n    for (int i = 0; i < 15; ++i) {\n        code |= (uint64_t)((x >> i) & 1u) << (2*i);\n        code |= (uint64_t)((y >> i) & 1u) << (2*i + 1);\n    }\n    return code;\n}\n\n// Hilbert order (bits=15)\nstatic inline uint64_t hilbert_index(uint32_t x, uint32_t y) {\n    const uint32_t n = 1u << 15;\n    uint64_t d = 0;\n    uint32_t rx, ry, s;\n    for (s = n >> 1; s > 0; s >>= 1) {\n        rx = (x & s) ? 1u : 0u;\n        ry = (y & s) ? 1u : 0u;\n        d += (uint64_t)s * (uint64_t)s * ((3u * rx) ^ ry);\n        if (ry == 0) {\n            if (rx == 1) {\n                x = (n - 1) - x;\n                y = (n - 1) - y;\n            }\n            uint32_t t = x; x = y; y = t;\n        }\n    }\n    return d;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, Q, L, W;\n    if (!(cin >> N >> M >> Q >> L >> W)) return 0;\n    vector<int> G(M);\n    for(int i=0;i<M;i++) cin >> G[i];\n    vector<int> lx(N), rx(N), ly(N), ry(N);\n    for(int i=0;i<N;i++){\n        cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n    }\n\n    // Centers and widths\n    vector<int> xc(N), yc(N), wx(N), wy(N);\n    for (int i = 0; i < N; ++i) {\n        xc[i] = (lx[i] + rx[i]) / 2;\n        yc[i] = (ly[i] + ry[i]) / 2;\n        wx[i] = rx[i] - lx[i];\n        wy[i] = ry[i] - ly[i];\n    }\n\n    // Variances and uncertainty\n    vector<double> varx(N), vary(N), diag(N);\n    for (int i = 0; i < N; ++i) {\n        varx[i] = (double)wx[i] * (double)wx[i] / 12.0;\n        vary[i] = (double)wy[i] * (double)wy[i] / 12.0;\n        diag[i] = hypot((double)wx[i], (double)wy[i]);\n    }\n\n    auto ed2 = [&](int u, int v)->double{\n        double dx = (double)xc[u] - (double)xc[v];\n        double dy = (double)yc[u] - (double)yc[v];\n        return dx*dx + dy*dy + varx[u] + varx[v] + vary[u] + vary[v];\n    };\n\n    // Build candidate orders: Morton, Hilbert, and Greedy NN (ed2)\n    vector<vector<int>> orders;\n\n    // Morton\n    {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        vector<uint64_t> code(N);\n        for (int i = 0; i < N; ++i) code[i] = morton_code((uint32_t)xc[i], (uint32_t)yc[i]);\n        sort(ord.begin(), ord.end(), [&](int a, int b){ return code[a] < code[b]; });\n        orders.push_back(move(ord));\n    }\n    // Hilbert\n    {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        vector<uint64_t> code(N);\n        for (int i = 0; i < N; ++i) code[i] = hilbert_index((uint32_t)xc[i], (uint32_t)yc[i]);\n        sort(ord.begin(), ord.end(), [&](int a, int b){ return code[a] < code[b]; });\n        orders.push_back(move(ord));\n    }\n    // Greedy Nearest-Neighbor (open path)\n    {\n        vector<int> ord;\n        ord.reserve(N);\n        vector<char> used(N, 0);\n        // start from smallest Hilbert code node\n        int start = 0;\n        {\n            uint64_t best = (uint64_t)-1;\n            for (int i = 0; i < N; ++i) {\n                uint64_t h = hilbert_index((uint32_t)xc[i], (uint32_t)yc[i]);\n                if (h < best) { best = h; start = i; }\n            }\n        }\n        int cur = start;\n        used[cur] = 1;\n        ord.push_back(cur);\n        for (int step = 1; step < N; ++step) {\n            int bestj = -1;\n            double bd = 1e300;\n            for (int j = 0; j < N; ++j) if (!used[j]) {\n                double d2 = ed2(cur, j);\n                if (d2 < bd) { bd = d2; bestj = j; }\n            }\n            if (bestj == -1) break;\n            used[bestj] = 1;\n            ord.push_back(bestj);\n            cur = bestj;\n        }\n        if ((int)ord.size() == N) orders.push_back(move(ord));\n    }\n\n    auto path_cost = [&](const vector<int>& ord)->double{\n        double s = 0.0;\n        for (int i = 0; i+1 < (int)ord.size(); ++i) s += ed2(ord[i], ord[i+1]);\n        return s;\n    };\n\n    // Pick best by neighbor sum\n    int bestOrdIdx = 0;\n    double bestPath = 1e300;\n    for (int i = 0; i < (int)orders.size(); ++i) {\n        double sc = path_cost(orders[i]);\n        if (sc < bestPath) {\n            bestPath = sc;\n            bestOrdIdx = i;\n        }\n    }\n    vector<int> ord = orders[bestOrdIdx];\n\n    // Windowed 2-opt on open path (few passes)\n    auto two_opt_improve = [&](vector<int>& path){\n        const int Nn = (int)path.size();\n        if (Nn < 4) return;\n        const int WINDOW = 60; // local window\n        const int PASSES = 2;\n        for (int pass = 0; pass < PASSES; ++pass) {\n            bool improved = false;\n            for (int i = 1; i <= Nn - 3; ++i) {\n                int jmax = min(Nn - 2, i + WINDOW);\n                for (int j = i + 1; j <= jmax; ++j) {\n                    int a = path[i-1];\n                    int b = path[i];\n                    int c = path[j];\n                    int d = path[j+1];\n                    double before = ed2(a,b) + ed2(c,d);\n                    double after  = ed2(a,c) + ed2(b,d);\n                    if (after + 1e-9 < before) {\n                        reverse(path.begin() + i, path.begin() + j + 1);\n                        improved = true;\n                        break;\n                    }\n                }\n                if (improved) continue;\n            }\n            if (!improved) break;\n        }\n    };\n    two_opt_improve(ord);\n\n    // Build group boundaries (fixed sizes)\n    vector<int> start(M+1, 0);\n    for (int k = 0; k < M; ++k) start[k+1] = start[k] + G[k];\n\n    // One-pass boundary smoothing: swap one element across boundary if improves expected MST cost\n    auto mst_cost_ed2 = [&](const vector<int>& nodes)->double{\n        int n = (int)nodes.size();\n        if (n <= 1) return 0.0;\n        vector<char> used(n, 0);\n        vector<double> best(n, 1e300);\n        best[0] = 0.0;\n        double cost = 0.0;\n        for (int it = 0; it < n; ++it) {\n            int v = -1;\n            double bv = 1e300;\n            for (int i = 0; i < n; ++i) if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n            if (v == -1) break;\n            used[v] = 1;\n            cost += (v==0 ? 0.0 : bv);\n            for (int u = 0; u < n; ++u) if (!used[u]) {\n                double w = ed2(nodes[v], nodes[u]);\n                if (w < best[u]) best[u] = w;\n            }\n        }\n        return cost;\n    };\n\n    auto group_nodes_by_ord = [&](int l, int r)->vector<int>{\n        vector<int> v;\n        v.reserve(r-l);\n        for (int i = l; i < r; ++i) v.push_back(ord[i]);\n        return v;\n    };\n\n    for (int k = 0; k+1 < M; ++k) {\n        if (G[k] == 0 || G[k+1] == 0) continue;\n        int posL = start[k+1] - 1;\n        int posR = start[k+1];\n        int left_id = ord[posL];\n        int right_id = ord[posR];\n\n        vector<int> grpL = group_nodes_by_ord(start[k], start[k+1]);\n        vector<int> grpR = group_nodes_by_ord(start[k+1], start[k+2]);\n        double before = mst_cost_ed2(grpL) + mst_cost_ed2(grpR);\n\n        grpL.back() = right_id;\n        grpR[0] = left_id;\n        double after = mst_cost_ed2(grpL) + mst_cost_ed2(grpR);\n\n        if (after + 1e-9 < before) {\n            swap(ord[posL], ord[posR]);\n        }\n    }\n\n    // Build groups from ord\n    vector<vector<int>> groups(M);\n    {\n        int ptr = 0;\n        for (int k = 0; k < M; ++k) {\n            groups[k].reserve(G[k]);\n            for (int t = 0; t < G[k]; ++t) groups[k].push_back(ord[ptr++]);\n        }\n    }\n\n    // Group uncertainty\n    vector<double> g_unc(M, 0.0);\n    for (int k = 0; k < M; ++k) {\n        double s = 0.0;\n        for (int id : groups[k]) s += diag[id];\n        g_unc[k] = (G[k] > 0 ? s / (double)G[k] : 0.0);\n    }\n\n    // Approx MST edges per group (expected distances)\n    auto mst_edges_ed2 = [&](const vector<int>& nodes)->vector<pair<int,int>>{\n        int n = (int)nodes.size();\n        vector<char> used(n, 0);\n        vector<double> best(n, 1e300);\n        vector<int> parent(n, -1);\n        if (n > 0) best[0] = 0.0;\n        vector<pair<int,int>> edges;\n        edges.reserve(max(0, n-1));\n        for (int it = 0; it < n; ++it) {\n            int v = -1;\n            double bv = 1e300;\n            for (int i = 0; i < n; ++i) if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n            if (v == -1) break;\n            used[v] = 1;\n            if (parent[v] != -1) edges.emplace_back(nodes[parent[v]], nodes[v]);\n            for (int u = 0; u < n; ++u) if (!used[u]) {\n                double w = ed2(nodes[v], nodes[u]);\n                if (w < best[u]) { best[u] = w; parent[u] = v; }\n            }\n        }\n        return edges;\n    };\n    vector<vector<pair<int,int>>> approxEdges(M);\n    for (int k = 0; k < M; ++k) {\n        approxEdges[k] = mst_edges_ed2(groups[k]);\n    }\n\n    // Query function\n    auto do_query = [&](const vector<int>& subset)->vector<pair<int,int>>{\n        int l = (int)subset.size();\n        cout << \"? \" << l;\n        for (int i = 0; i < l; ++i) cout << \" \" << subset[i];\n        cout << \"\\n\" << flush;\n        vector<pair<int,int>> res;\n        res.reserve(max(0, l-1));\n        for (int i = 0; i < l-1; ++i) {\n            int a,b; cin >> a >> b;\n            res.emplace_back(a,b);\n        }\n        return res;\n    };\n\n    int queries_used = 0;\n    vector<vector<pair<int,int>>> oracle_edges(M);\n\n    // Stage A: small groups 3..L\n    vector<int> small_groups;\n    for (int k = 0; k < M; ++k) if (G[k] >= 3 && G[k] <= L) small_groups.push_back(k);\n    sort(small_groups.begin(), small_groups.end(), [&](int a, int b){\n        if (G[a] != G[b]) return G[a] > G[b];\n        if (g_unc[a] != g_unc[b]) return g_unc[a] > g_unc[b];\n        return a < b;\n    });\n    for (int k : small_groups) {\n        if (queries_used >= Q) break;\n        auto res = do_query(groups[k]);\n        ++queries_used;\n        oracle_edges[k].insert(oracle_edges[k].end(), res.begin(), res.end());\n    }\n\n    // Stage B: large groups -> disjoint connected chunks (BFS on approx MST) with benefit scoring\n    struct Chunk {\n        int k;\n        vector<int> sub;\n        double benefit; // sum of variances on MST edges inside the chunk\n        bool operator<(Chunk const& other) const { return benefit > other.benefit; } // for sort desc\n    };\n    vector<Chunk> chunks_all;\n    vector<Chunk> chunks2; // size-2\n    vector<int> id2pos(N, -1);\n\n    for (int k = 0; k < M; ++k) {\n        if (G[k] <= L) continue;\n        const auto &grp = groups[k];\n        int sz = (int)grp.size();\n\n        for (int i = 0; i < sz; ++i) id2pos[grp[i]] = i;\n        vector<vector<int>> adj(sz);\n        for (auto &e : approxEdges[k]) {\n            int u = id2pos[e.first];\n            int v = id2pos[e.second];\n            if (u >= 0 && v >= 0) {\n                adj[u].push_back(v);\n                adj[v].push_back(u);\n            }\n        }\n\n        vector<char> used(sz, 0);\n        int remaining = sz;\n\n        auto pick_seed = [&]()->int{\n            for (int i = 0; i < sz; ++i) if (!used[i] && (int)adj[i].size() <= 1) return i;\n            for (int i = 0; i < sz; ++i) if (!used[i]) return i;\n            return -1;\n        };\n\n        vector<vector<int>> subs_local;\n        while (remaining > 0) {\n            int seed = pick_seed();\n            if (seed == -1) break;\n            deque<int> dq;\n            dq.push_back(seed);\n            vector<char> enq(sz, 0);\n            enq[seed] = 1;\n\n            vector<int> subset_local;\n            while (!dq.empty() && (int)subset_local.size() < L) {\n                int v = dq.front(); dq.pop_front();\n                if (used[v]) continue;\n                used[v] = 1;\n                subset_local.push_back(v);\n                --remaining;\n                for (int to : adj[v]) if (!used[to] && !enq[to]) {\n                    dq.push_back(to); enq[to] = 1;\n                }\n            }\n            if (!subset_local.empty()) subs_local.push_back(move(subset_local));\n            else break;\n        }\n\n        // Convert to city IDs and compute benefit\n        for (auto &loc : subs_local) {\n            vector<int> sub; sub.reserve(loc.size());\n            for (int idx : loc) sub.push_back(grp[idx]);\n            // Compute benefit on approx MST edges inside sub\n            vector<char> in(sz, 0);\n            for (int id : sub) in[id2pos[id]] = 1;\n            double ben = 0.0;\n            for (auto &e : approxEdges[k]) {\n                int u = id2pos[e.first], v = id2pos[e.second];\n                if (in[u] && in[v]) {\n                    ben += varx[e.first] + varx[e.second] + vary[e.first] + vary[e.second];\n                }\n            }\n            if ((int)sub.size() >= 3) chunks_all.push_back({k, move(sub), ben});\n            else if ((int)sub.size() == 2) chunks2.push_back({k, move(sub), ben});\n        }\n\n        for (int i = 0; i < sz; ++i) id2pos[grp[i]] = -1;\n    }\n\n    sort(chunks_all.begin(), chunks_all.end()); // by benefit desc\n    sort(chunks2.begin(), chunks2.end());\n\n    for (auto &ch : chunks_all) {\n        if (queries_used >= Q) break;\n        auto res = do_query(ch.sub);\n        ++queries_used;\n        oracle_edges[ch.k].insert(oracle_edges[ch.k].end(), res.begin(), res.end());\n    }\n    for (auto &ch : chunks2) {\n        if (queries_used >= Q) break;\n        auto res = do_query(ch.sub);\n        ++queries_used;\n        oracle_edges[ch.k].insert(oracle_edges[ch.k].end(), res.begin(), res.end());\n    }\n\n    // If any budget remains, query size-2 groups by uncertainty\n    if (queries_used < Q) {\n        vector<int> size2groups;\n        for (int k = 0; k < M; ++k) if (G[k] == 2) size2groups.push_back(k);\n        sort(size2groups.begin(), size2groups.end(), [&](int a, int b){\n            if (g_unc[a] != g_unc[b]) return g_unc[a] > g_unc[b];\n            return a < b;\n        });\n        for (int k : size2groups) {\n            if (queries_used >= Q) break;\n            auto res = do_query(groups[k]);\n            ++queries_used;\n            oracle_edges[k].insert(oracle_edges[k].end(), res.begin(), res.end());\n        }\n    }\n\n    // Output final answer\n    cout << \"!\" << \"\\n\";\n\n    // Build final edges per group\n    vector<int> pos(N, -1);\n    for (int k = 0; k < M; ++k) {\n        const auto &grp = groups[k];\n        int sz = (int)grp.size();\n\n        // Print city IDs for this group\n        for (int i = 0; i < sz; ++i) {\n            if (i) cout << \" \";\n            cout << grp[i];\n        }\n        cout << \"\\n\";\n\n        if (sz <= 1) continue;\n\n        for (int i = 0; i < sz; ++i) pos[grp[i]] = i;\n\n        // Force oracle edges first\n        vector<pair<int,int>> final_edges;\n        final_edges.reserve(max(0, sz-1));\n        DSU dsu(sz);\n\n        auto add_edge_if = [&](int u, int v){\n            int iu = pos[u], iv = pos[v];\n            if (iu < 0 || iv < 0) return;\n            if (dsu.unite(iu, iv)) final_edges.emplace_back(u, v);\n        };\n\n        {\n            unordered_set<long long> seen;\n            seen.reserve(oracle_edges[k].size()*2+1);\n            auto enc = [](int a, int b)->long long{\n                if (a > b) swap(a,b);\n                return ((long long)a<<32) ^ (long long)b;\n            };\n            for (auto &e : oracle_edges[k]) {\n                int a = e.first, b = e.second;\n                if (a == b) continue;\n                if (pos[a] == -1 || pos[b] == -1) continue;\n                long long key = enc(a,b);\n                if (seen.insert(key).second) {\n                    add_edge_if(a,b);\n                    if ((int)final_edges.size() == sz-1) break;\n                }\n            }\n        }\n\n        // Add approximate MST edges next\n        for (auto &e : approxEdges[k]) {\n            if ((int)final_edges.size() == sz-1) break;\n            add_edge_if(e.first, e.second);\n        }\n\n        // Fallback: connect remaining components greedily by expected distance\n        if ((int)final_edges.size() < sz-1) {\n            unordered_map<int, vector<int>> comp_nodes;\n            comp_nodes.reserve(sz*2+1);\n            for (int i = 0; i < sz; ++i) comp_nodes[dsu.find(i)].push_back(grp[i]);\n\n            while ((int)comp_nodes.size() > 1 && (int)final_edges.size() < sz-1) {\n                double bestW = 1e300;\n                int bu=-1, bv=-1;\n                vector<pair<int, vector<int>>> comps;\n                comps.reserve(comp_nodes.size());\n                for (auto &kv : comp_nodes) comps.push_back(kv);\n                for (size_t i = 0; i < comps.size(); ++i) {\n                    for (size_t j = i+1; j < comps.size(); ++j) {\n                        for (int u : comps[i].second) {\n                            for (int v : comps[j].second) {\n                                double w = ed2(u, v);\n                                if (w < bestW) { bestW = w; bu = u; bv = v; }\n                            }\n                        }\n                    }\n                }\n                if (bu != -1) {\n                    add_edge_if(bu, bv);\n                    comp_nodes.clear();\n                    for (int i = 0; i < sz; ++i) comp_nodes[dsu.find(i)].push_back(grp[i]);\n                } else break;\n            }\n        }\n\n        for (auto &e : final_edges) cout << e.first << \" \" << e.second << \"\\n\";\n\n        for (int i = 0; i < sz; ++i) pos[grp[i]] = -1;\n    }\n\n    cout.flush();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Directions: 0:U, 1:D, 2:L, 3:R\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\nstatic const char dch[4] = {'U', 'D', 'L', 'R'};\n\nstruct Step {\n    char a; // 'M','S','A'\n    char d; // 'U','D','L','R'\n};\n\nstruct BFSResult {\n    bool ok = false;\n    vector<Step> path; // Non-empty only when needPath=true\n    int dist = -1;\n};\n\nstruct GridEnv {\n    int N;\n    vector<uint8_t> G; // 0 free, 1 blocked\n    GridEnv() {}\n    GridEnv(int N_) : N(N_), G(N_*N_, 0) {}\n    inline bool inside(int i, int j) const { return (0 <= i && i < N && 0 <= j && j < N); }\n    inline int id(int i, int j) const { return i * N + j; }\n    inline pair<int,int> coord(int idx) const { return {idx / N, idx % N}; }\n};\n\nstatic inline int dir_from_to(pair<int,int> a, pair<int,int> b) {\n    int di2 = b.first - a.first;\n    int dj2 = b.second - a.second;\n    if (di2 == -1 && dj2 == 0) return 0; // U\n    if (di2 == 1 && dj2 == 0)  return 1; // D\n    if (di2 == 0 && dj2 == -1) return 2; // L\n    if (di2 == 0 && dj2 == 1)  return 3; // R\n    return -1;\n}\n\n// Build local mapping around target t = (ti,tj) for enhanced BFS\nstatic inline void build_local_bits(const GridEnv &env, int ti, int tj,\n                                    vector<int> &cellToBit, vector<pair<int,int>> &bitPos) {\n    int NN = env.N * env.N;\n    cellToBit.assign(NN, -1);\n    bitPos.clear();\n    auto add_bit = [&](int i, int j) {\n        cellToBit[env.id(i, j)] = (int)bitPos.size();\n        bitPos.emplace_back(i, j);\n    };\n    add_bit(ti, tj); // bit 0 is target itself\n    if (env.inside(ti - 1, tj)) add_bit(ti - 1, tj);\n    if (env.inside(ti + 1, tj)) add_bit(ti + 1, tj);\n    if (env.inside(ti, tj - 1)) add_bit(ti, tj - 1);\n    if (env.inside(ti, tj + 1)) add_bit(ti, tj + 1);\n}\n\n// Compute slide destination with local mask\nstatic inline pair<int,int> slide_with_mask(const GridEnv &env, int i, int j, int d,\n                                            const vector<int> &cellToBit, int mask) {\n    int ci = i, cj = j;\n    while (true) {\n        int ni = ci + di[d], nj = cj + dj[d];\n        if (!env.inside(ni, nj)) break;\n        int idx = env.id(ni, nj);\n        int b = cellToBit[idx];\n        bool blocked = (b != -1 ? ((mask >> b) & 1) : env.G[idx]);\n        if (blocked) break;\n        ci = ni; cj = nj;\n    }\n    return {ci, cj};\n}\n\n// Enhanced BFS: allows M, S, and A on the target and its four neighbors only (local mask).\n// Returns both distance and, optionally, the action path.\nstatic BFSResult bfs_enhanced(const GridEnv &env, pair<int,int> s, pair<int,int> t, bool needPath) {\n    int N = env.N;\n    int NN = N * N;\n    int si = s.first, sj = s.second;\n    int ti = t.first, tj = t.second;\n    int sId = env.id(si, sj);\n    int tId = env.id(ti, tj);\n\n    vector<int> cellToBit;\n    vector<pair<int,int>> bitPos;\n    build_local_bits(env, ti, tj, cellToBit, bitPos);\n    int K = (int)bitPos.size();\n    int MS = 1 << K;\n\n    auto is_blocked = [&](int idx, int mask) -> bool {\n        int b = cellToBit[idx];\n        if (b != -1) return (mask >> b) & 1;\n        return env.G[idx];\n    };\n\n    int initMask = 0;\n    for (int b = 0; b < K; ++b) {\n        auto [bi, bj] = bitPos[b];\n        if (env.G[env.id(bi, bj)]) initMask |= (1 << b);\n    }\n\n    int SZ = NN * MS;\n    vector<char> vis(SZ, 0);\n    vector<int> distArr(SZ, -1);\n\n    vector<int> par, how, hdir;\n    if (needPath) {\n        par.assign(SZ, -1);\n        how.assign(SZ, 0);\n        hdir.assign(SZ, 0);\n    }\n\n    auto enc = [&](int pos, int mask) { return pos * MS + mask; };\n    int start = enc(sId, initMask);\n    deque<int> q;\n    vis[start] = 1;\n    distArr[start] = 0;\n    q.push_back(start);\n    int goal = -1;\n\n    while (!q.empty()) {\n        int u = q.front(); q.pop_front();\n        int pos = u / MS;\n        int mask = u % MS;\n        if (pos == tId) { goal = u; break; }\n\n        auto [ui, uj] = env.coord(pos);\n\n        // Move\n        for (int d = 0; d < 4; ++d) {\n            int vi = ui + di[d], vj = uj + dj[d];\n            if (!env.inside(vi, vj)) continue;\n            int vpos = env.id(vi, vj);\n            if (is_blocked(vpos, mask)) continue;\n            int v = enc(vpos, mask);\n            if (!vis[v]) {\n                vis[v] = 1;\n                distArr[v] = distArr[u] + 1;\n                if (needPath) { par[v] = u; how[v] = 'M'; hdir[v] = dch[d]; }\n                q.push_back(v);\n            }\n        }\n        // Slide\n        for (int d = 0; d < 4; ++d) {\n            auto [vi, vj] = slide_with_mask(env, ui, uj, d, cellToBit, mask);\n            if (vi == ui && vj == uj) continue;\n            int vpos = env.id(vi, vj);\n            int v = enc(vpos, mask);\n            if (!vis[v]) {\n                vis[v] = 1;\n                distArr[v] = distArr[u] + 1;\n                if (needPath) { par[v] = u; how[v] = 'S'; hdir[v] = dch[d]; }\n                q.push_back(v);\n            }\n        }\n        // Alter on local cells\n        for (int d = 0; d < 4; ++d) {\n            int vi = ui + di[d], vj = uj + dj[d];\n            if (!env.inside(vi, vj)) continue;\n            int b = cellToBit[env.id(vi, vj)];\n            if (b == -1) continue;\n            int nmask = mask ^ (1 << b);\n            int v = enc(pos, nmask);\n            if (!vis[v]) {\n                vis[v] = 1;\n                distArr[v] = distArr[u] + 1;\n                if (needPath) { par[v] = u; how[v] = 'A'; hdir[v] = dch[d]; }\n                q.push_back(v);\n            }\n        }\n    }\n\n    if (goal == -1) {\n        return BFSResult{false, {}, -1};\n    }\n\n    int dist = distArr[goal];\n    if (!needPath) {\n        return BFSResult{true, {}, dist};\n    }\n\n    vector<Step> path;\n    int cur = goal;\n    while (cur != start) {\n        path.push_back(Step{(char)how[cur], (char)hdir[cur]});\n        cur = par[cur];\n    }\n    reverse(path.begin(), path.end());\n    return BFSResult{true, path, dist};\n}\n\nstatic inline int dist_enhanced(const GridEnv &env, pair<int,int> s, pair<int,int> t) {\n    auto res = bfs_enhanced(env, s, t, false);\n    if (!res.ok) return INT_MAX / 4;\n    return res.dist;\n}\n\nstatic inline BFSResult path_enhanced(const GridEnv &env, pair<int,int> s, pair<int,int> t) {\n    return bfs_enhanced(env, s, t, true);\n}\n\n// Apply a Step to the state: update position and grid (for Alter).\nstatic inline void apply_step(GridEnv &env, pair<int,int> &pos, const Step &st) {\n    int i = pos.first, j = pos.second;\n    int d = 0;\n    for (int k = 0; k < 4; ++k) if (dch[k] == st.d) { d = k; break; }\n    if (st.a == 'M') {\n        int ni = i + di[d], nj = j + dj[d];\n        pos = {ni, nj};\n    } else if (st.a == 'S') {\n        int ci = i, cj = j;\n        while (true) {\n            int ni = ci + di[d], nj = cj + dj[d];\n            if (!env.inside(ni, nj)) break;\n            if (env.G[env.id(ni, nj)]) break;\n            ci = ni; cj = nj;\n        }\n        pos = {ci, cj};\n    } else if (st.a == 'A') {\n        int ni = i + di[d], nj = j + dj[d];\n        if (env.inside(ni, nj)) {\n            int idx = env.id(ni, nj);\n            env.G[idx] ^= 1;\n        }\n    }\n}\n\nstatic inline void compute_top_rows_cols(const vector<pair<int,int>>& P, int startIdx, int N,\n                                         vector<int>& topRows, vector<int>& topCols) {\n    vector<int> rc(N, 0), cc(N, 0);\n    for (int i = startIdx; i < (int)P.size(); ++i) {\n        rc[P[i].first]++; cc[P[i].second]++;\n    }\n    vector<pair<int,int>> rv, cv;\n    rv.reserve(N); cv.reserve(N);\n    for (int r = 0; r < N; ++r) rv.emplace_back(rc[r], r);\n    for (int c = 0; c < N; ++c) cv.emplace_back(cc[c], c);\n    sort(rv.begin(), rv.end(), greater<>());\n    sort(cv.begin(), cv.end(), greater<>());\n    topRows.clear(); topCols.clear();\n    int need = 3; // top-3 rows/cols\n    for (int i = 0; i < (int)rv.size() && (int)topRows.size() < need; ++i) {\n        if (rv[i].first == 0) break;\n        topRows.push_back(rv[i].second);\n    }\n    for (int i = 0; i < (int)cv.size() && (int)topCols.size() < need; ++i) {\n        if (cv[i].first == 0) break;\n        topCols.push_back(cv[i].second);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    vector<pair<int,int>> P(M);\n    for (int k = 0; k < M; ++k) cin >> P[k].first >> P[k].second;\n\n    GridEnv env(N);\n    vector<Step> ans;\n    const long long cap = 2LL * N * M;\n\n    pair<int,int> cur = P[0];\n\n    int NN = N * N;\n\n    for (int k = 1; k < M; ++k) {\n        pair<int,int> target = P[k];\n        pair<int,int> next1 = (k + 1 < M ? P[k + 1] : make_pair(-1, -1));\n        pair<int,int> next2 = (k + 2 < M ? P[k + 2] : make_pair(-1, -1));\n        pair<int,int> next3 = (k + 3 < M ? P[k + 3] : make_pair(-1, -1));\n        pair<int,int> next4 = (k + 4 < M ? P[k + 4] : make_pair(-1, -1));\n\n        // Plan path for current leg\n        auto plan = path_enhanced(env, cur, target);\n        if (!plan.ok) {\n            plan = path_enhanced(env, cur, target);\n            if (!plan.ok) break;\n        }\n        vector<Step> path = plan.path;\n\n        // Baseline distances for upcoming legs under current env\n        int base1 = (k + 1 < M) ? dist_enhanced(env, target, next1) : 0;\n        int base2 = (k + 2 < M) ? dist_enhanced(env, next1, next2) : 0;\n        int base3 = (k + 3 < M) ? dist_enhanced(env, next2, next3) : 0;\n        int base4 = (k + 4 < M) ? dist_enhanced(env, next3, next4) : 0;\n\n        // Precompute neighbor-of-next flags for quick membership checks\n        vector<char> isNeigh1(NN, 0), isNeigh2(NN, 0), isNeigh3(NN, 0), isNeigh4(NN, 0);\n        if (k + 1 < M) {\n            int ti = next1.first, tj = next1.second;\n            for (int d = 0; d < 4; ++d) {\n                int ni = ti + di[d], nj = tj + dj[d];\n                if (env.inside(ni, nj)) isNeigh1[env.id(ni, nj)] = 1;\n            }\n        }\n        if (k + 2 < M) {\n            int ti = next2.first, tj = next2.second;\n            for (int d = 0; d < 4; ++d) {\n                int ni = ti + di[d], nj = tj + dj[d];\n                if (env.inside(ni, nj)) isNeigh2[env.id(ni, nj)] = 1;\n            }\n        }\n        if (k + 3 < M) {\n            int ti = next3.first, tj = next3.second;\n            for (int d = 0; d < 4; ++d) {\n                int ni = ti + di[d], nj = tj + dj[d];\n                if (env.inside(ni, nj)) isNeigh3[env.id(ni, nj)] = 1;\n            }\n        }\n        if (k + 4 < M) {\n            int ti = next4.first, tj = next4.second;\n            for (int d = 0; d < 4; ++d) {\n                int ni = ti + di[d], nj = tj + dj[d];\n                if (env.inside(ni, nj)) isNeigh4[env.id(ni, nj)] = 1;\n            }\n        }\n\n        // Build rail preferences: top rows/cols among remaining targets (k+1..M-1)\n        vector<int> topRows, topCols;\n        compute_top_rows_cols(P, k + 1, N, topRows, topCols);\n\n        // Execute path with opportunistic toggles\n        pair<int,int> pos = cur;\n        int i = 0;\n        int toggledCount = 0;\n        const int maxTogglesPerLeg = 4;\n\n        struct Cand {\n            int idx;\n            char dir;\n            int score;\n        };\n\n        auto try_opportunistic_toggle = [&](int &remLen, int &b1, int &b2, int &b3, int &b4) -> bool {\n            if (toggledCount >= maxTogglesPerLeg) return false;\n\n            // Build adjacent candidates with priority score\n            vector<Cand> cands;\n            for (int d = 0; d < 4; ++d) {\n                int ni = pos.first + di[d], nj = pos.second + dj[d];\n                if (!env.inside(ni, nj)) continue;\n                int idx = env.id(ni, nj);\n                int sc = 0;\n                if (k + 1 < M) {\n                    if (isNeigh1[idx]) sc += 9;\n                    if (ni == next1.first || nj == next1.second) sc += 4;\n                }\n                if (k + 2 < M) {\n                    if (isNeigh2[idx]) sc += 6;\n                    if (ni == next2.first || nj == next2.second) sc += 3;\n                }\n                if (k + 3 < M) {\n                    if (isNeigh3[idx]) sc += 4;\n                    if (ni == next3.first || nj == next3.second) sc += 2;\n                }\n                if (k + 4 < M) {\n                    if (isNeigh4[idx]) sc += 3;\n                    if (ni == next4.first || nj == next4.second) sc += 1;\n                }\n                bool onRail = false;\n                for (int r : topRows) if (ni == r) { onRail = true; break; }\n                if (!onRail) for (int c : topCols) if (nj == c) { onRail = true; break; }\n                if (onRail) sc += 2;\n\n                cands.push_back(Cand{idx, dch[d], sc});\n            }\n            // Dedup by idx and keep best score/dir\n            sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){\n                if (a.idx != b.idx) return a.idx < b.idx;\n                return a.score > b.score;\n            });\n            vector<Cand> uniq;\n            for (auto &c : cands) {\n                if (uniq.empty() || uniq.back().idx != c.idx) uniq.push_back(c);\n            }\n            // Sort by score desc, keep topK\n            sort(uniq.begin(), uniq.end(), [](const Cand& a, const Cand& b){\n                return a.score > b.score;\n            });\n            int topK = min(4, (int)uniq.size());\n            uniq.resize(topK);\n\n            int bestDelta = 0;\n            int bestType = 0; // 1 single, 2 pair\n            Cand bestA, bestB;\n\n            auto eval_state = [&](int tglCount) -> int {\n                int cur_new = dist_enhanced(env, pos, target);\n                if (cur_new >= INT_MAX / 8) return INT_MAX / 4;\n                int n1_new = (k + 1 < M) ? dist_enhanced(env, target, next1) : 0;\n                int n2_new = (k + 2 < M) ? dist_enhanced(env, next1, next2) : 0;\n                int n3_new = (k + 3 < M) ? dist_enhanced(env, next2, next3) : 0;\n                int n4_new = (k + 4 < M) ? dist_enhanced(env, next3, next4) : 0;\n                int delta = tglCount + (cur_new - remLen)\n                            + (n1_new - b1) + (n2_new - b2) + (n3_new - b3) + (n4_new - b4);\n                return delta;\n            };\n\n            // Evaluate singles\n            for (int a = 0; a < (int)uniq.size(); ++a) {\n                int idxA = uniq[a].idx;\n                env.G[idxA] ^= 1;\n                int delta = eval_state(1);\n                env.G[idxA] ^= 1;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestA = uniq[a];\n                }\n            }\n            // Evaluate pairs (only if we haven't toggled too much)\n            if (toggledCount <= maxTogglesPerLeg - 2 && (int)uniq.size() >= 2) {\n                for (int a = 0; a < (int)uniq.size(); ++a) {\n                    for (int b = a + 1; b < (int)uniq.size(); ++b) {\n                        int idxA = uniq[a].idx;\n                        int idxB = uniq[b].idx;\n                        if (idxA == idxB) continue;\n                        env.G[idxA] ^= 1;\n                        env.G[idxB] ^= 1;\n                        int delta = eval_state(2);\n                        env.G[idxA] ^= 1;\n                        env.G[idxB] ^= 1;\n                        if (delta < bestDelta) {\n                            bestDelta = delta;\n                            bestType = 2;\n                            bestA = uniq[a];\n                            bestB = uniq[b];\n                        }\n                    }\n                }\n            }\n\n            if (bestType != 0 && bestDelta < 0) {\n                if (bestType == 1) {\n                    if ((long long)ans.size() + 1LL > cap) return false;\n                    ans.push_back(Step{'A', bestA.dir});\n                    env.G[bestA.idx] ^= 1;\n                    toggledCount += 1;\n                } else {\n                    if ((long long)ans.size() + 2LL > cap) return false;\n                    ans.push_back(Step{'A', bestA.dir});\n                    env.G[bestA.idx] ^= 1;\n                    ans.push_back(Step{'A', bestB.dir});\n                    env.G[bestB.idx] ^= 1;\n                    toggledCount += 2;\n                }\n                // Replan remainder from current pos\n                auto repl = path_enhanced(env, pos, target);\n                if (repl.ok) {\n                    path = repl.path;\n                    i = 0;\n                    remLen = (int)path.size();\n                    // Recompute base distances under new env\n                    if (k + 1 < M) b1 = dist_enhanced(env, target, next1);\n                    if (k + 2 < M) b2 = dist_enhanced(env, next1, next2);\n                    if (k + 3 < M) b3 = dist_enhanced(env, next2, next3);\n                    if (k + 4 < M) b4 = dist_enhanced(env, next3, next4);\n                    return true;\n                } else {\n                    // Revert if replanning fails (unlikely)\n                    if (bestType == 1) {\n                        env.G[bestA.idx] ^= 1;\n                        ans.pop_back();\n                        toggledCount -= 1;\n                    } else {\n                        env.G[bestA.idx] ^= 1;\n                        env.G[bestB.idx] ^= 1;\n                        ans.pop_back();\n                        ans.pop_back();\n                        toggledCount -= 2;\n                    }\n                }\n            }\n            return false;\n        };\n\n        while (i < (int)path.size()) {\n            int remLen = (int)path.size() - i;\n            // Try an opportunistic toggle before executing next step\n            if (try_opportunistic_toggle(remLen, base1, base2, base3, base4)) {\n                continue; // toggled and replanned; evaluate again\n            }\n            // Execute next step\n            if ((long long)ans.size() + 1LL > cap) goto OUTPUT;\n            Step st = path[i];\n            ans.push_back(st);\n            apply_step(env, pos, st);\n            ++i;\n        }\n\n        // We are now at target\n        cur = target;\n\n        // Post-arrival toggles at target: evaluate all non-empty subsets of its neighbors\n        if (k + 1 < M) {\n            // Recompute base distances under current env (they may have changed in loop)\n            base1 = dist_enhanced(env, cur, next1);\n            base2 = (k + 2 < M) ? dist_enhanced(env, next1, next2) : 0;\n            base3 = (k + 3 < M) ? dist_enhanced(env, next2, next3) : 0;\n            base4 = (k + 4 < M) ? dist_enhanced(env, next3, next4) : 0;\n\n            // Gather neighbors of target with directions\n            vector<pair<int,char>> neigh; // (idx, dir)\n            for (int d = 0; d < 4; ++d) {\n                int ni = cur.first + di[d], nj = cur.second + dj[d];\n                if (env.inside(ni, nj)) {\n                    neigh.emplace_back(env.id(ni, nj), dch[d]);\n                }\n            }\n\n            int S = (int)neigh.size();\n            int bestDelta = 0;\n            int bestMask = 0; // bitmask over neighbors\n\n            // Evaluate all non-empty subsets (up to 15)\n            for (int mask = 1; mask < (1 << S); ++mask) {\n                // Apply subset\n                for (int b = 0; b < S; ++b) if (mask & (1 << b)) env.G[neigh[b].first] ^= 1;\n\n                int d1 = dist_enhanced(env, cur, next1);\n                int d2 = (k + 2 < M) ? dist_enhanced(env, next1, next2) : 0;\n                int d3 = (k + 3 < M) ? dist_enhanced(env, next2, next3) : 0;\n                int d4 = (k + 4 < M) ? dist_enhanced(env, next3, next4) : 0;\n\n                // Revert subset\n                for (int b = 0; b < S; ++b) if (mask & (1 << b)) env.G[neigh[b].first] ^= 1;\n\n                if (d1 >= INT_MAX / 8) continue;\n                int tglCount = __builtin_popcount((unsigned)mask);\n                int delta = tglCount + (d1 - base1) + (d2 - base2) + (d3 - base3) + (d4 - base4);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestMask = mask;\n                }\n            }\n\n            // Apply the best subset if beneficial and within cap\n            if (bestDelta < 0 && bestMask != 0) {\n                for (int b = 0; b < S; ++b) if (bestMask & (1 << b)) {\n                    if ((long long)ans.size() + 1LL > cap) goto OUTPUT;\n                    ans.push_back(Step{'A', neigh[b].second});\n                    env.G[neigh[b].first] ^= 1;\n                }\n            }\n        }\n    }\n\nOUTPUT:\n    for (auto &st : ans) {\n        cout << st.a << ' ' << st.d << '\\n';\n    }\n    return 0;\n}"}}}