{"model_name":"gpt-5.1-codex-high","codes":{"1":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Rect {\n    int x1, y1, x2, y2;\n};\n\nconst int BOARD_SIZE = 10000;\nconst int GROW_ITER_PER_RECT = 7;\nconst int SHRINK_ITER_PER_RECT = 4;\nconst int EXPAND_STEP_LIMIT = 1000;\nconst int SHRINK_STEP_LIMIT = 1000;\nconst int RANDOM_SHRINK_STEP_LIMIT = 40;\nconst int STAGNATION_LIMIT = 32;\n\nlong long rect_area(const Rect &r) {\n    return 1LL * (r.x2 - r.x1) * (r.y2 - r.y1);\n}\n\narray<int, 4> compute_expand_limits(const vector<Rect> &rects, int idx) {\n    const Rect &ri = rects[idx];\n    array<int, 4> lim = {ri.x1, BOARD_SIZE - ri.x2, ri.y1, BOARD_SIZE - ri.y2};\n    int n = rects.size();\n    for (int j = 0; j < n; ++j) if (j != idx) {\n        const Rect &rj = rects[j];\n        bool overlapY = (ri.y1 < rj.y2) && (ri.y2 > rj.y1);\n        bool overlapX = (ri.x1 < rj.x2) && (ri.x2 > rj.x1);\n        if (overlapY) {\n            if (rj.x2 <= ri.x1) {\n                int gap = max(0, ri.x1 - rj.x2);\n                lim[0] = min(lim[0], gap);\n            }\n            if (rj.x1 >= ri.x2) {\n                int gap = max(0, rj.x1 - ri.x2);\n                lim[1] = min(lim[1], gap);\n            }\n        }\n        if (overlapX) {\n            if (rj.y2 <= ri.y1) {\n                int gap = max(0, ri.y1 - rj.y2);\n                lim[2] = min(lim[2], gap);\n            }\n            if (rj.y1 >= ri.y2) {\n                int gap = max(0, rj.y1 - ri.y2);\n                lim[3] = min(lim[3], gap);\n            }\n        }\n    }\n    for (int d = 0; d < 4; ++d) lim[d] = max(lim[d], 0);\n    return lim;\n}\n\nbool grow_rect(int idx, vector<Rect> &rects, const vector<int> &target, mt19937 &rng) {\n    bool changed = false;\n    int n = rects.size();\n    for (int iter = 0; iter < GROW_ITER_PER_RECT; ++iter) {\n        Rect &rc = rects[idx];\n        long long width = rc.x2 - rc.x1;\n        long long height = rc.y2 - rc.y1;\n        long long area = width * height;\n        long long def = (long long)target[idx] - area;\n        if (def <= 0) break;\n\n        auto lim = compute_expand_limits(rects, idx);\n        long long unitArea[4] = {height, height, width, width};\n        double baseW = width + 0.5;\n        double baseH = height + 0.5;\n\n        double bestScore = -1;\n        vector<int> bestDirs;\n        for (int dir = 0; dir < 4; ++dir) {\n            int max_step = lim[dir];\n            if (max_step <= 0) continue;\n            long long uArea = unitArea[dir];\n            if (uArea <= 0) continue;\n            long long potential = 1LL * max_step * uArea;\n            long long effective = min(def, potential);\n            if (effective <= 0) continue;\n            double weight = 1.0;\n            if (dir <= 1) weight = baseH / baseW;\n            else weight = baseW / baseH;\n            double score = effective * weight;\n            if (score > bestScore + 1e-6) {\n                bestScore = score;\n                bestDirs.clear();\n                bestDirs.push_back(dir);\n            } else if (fabs(score - bestScore) <= 1e-6) {\n                bestDirs.push_back(dir);\n            }\n        }\n        if (bestDirs.empty()) break;\n        int dir = bestDirs[rng() % bestDirs.size()];\n        long long uArea = unitArea[dir];\n        if (uArea <= 0) break;\n        long long needed_units = (def + uArea - 1) / uArea;\n        long long limit = lim[dir];\n        if (limit <= 0) break;\n        limit = min<long long>(limit, EXPAND_STEP_LIMIT);\n        long long w = max(1LL, min(limit, needed_units));\n        if (dir == 0) rc.x1 -= (int)w;\n        else if (dir == 1) rc.x2 += (int)w;\n        else if (dir == 2) rc.y1 -= (int)w;\n        else rc.y2 += (int)w;\n        changed = true;\n    }\n    return changed;\n}\n\nbool shrink_rect(int idx, vector<Rect> &rects, const vector<int> &target,\n                 const vector<int> &xs, const vector<int> &ys, mt19937 &rng) {\n    bool changed = false;\n    for (int iter = 0; iter < SHRINK_ITER_PER_RECT; ++iter) {\n        Rect &rc = rects[idx];\n        long long width = rc.x2 - rc.x1;\n        long long height = rc.y2 - rc.y1;\n        long long area = width * height;\n        long long def = (long long)target[idx] - area;\n        if (def >= 0) break;\n        int avail[4] = {\n            xs[idx] - rc.x1,\n            rc.x2 - (xs[idx] + 1),\n            ys[idx] - rc.y1,\n            rc.y2 - (ys[idx] + 1)\n        };\n        long long unitArea[4] = {height, height, width, width};\n        double bestScore = -1;\n        vector<int> dirs;\n        for (int dir = 0; dir < 4; ++dir) {\n            if (avail[dir] <= 0 || unitArea[dir] <= 0) continue;\n            long long potential = 1LL * avail[dir] * unitArea[dir];\n            if (potential <= 0) continue;\n            long long effective = min(-def, potential);\n            double score = effective;\n            if (score > bestScore + 1e-6) {\n                bestScore = score;\n                dirs.clear();\n                dirs.push_back(dir);\n            } else if (fabs(score - bestScore) <= 1e-6) {\n                dirs.push_back(dir);\n            }\n        }\n        if (dirs.empty()) break;\n        int dir = dirs[rng() % dirs.size()];\n        long long uArea = unitArea[dir];\n        long long need_units = (-def + uArea - 1) / uArea;\n        long long limit = min<long long>(avail[dir], SHRINK_STEP_LIMIT);\n        if (limit <= 0) break;\n        long long w = max(1LL, min(limit, need_units));\n        if (dir == 0) rc.x1 += (int)w;\n        else if (dir == 1) rc.x2 -= (int)w;\n        else if (dir == 2) rc.y1 += (int)w;\n        else rc.y2 -= (int)w;\n        changed = true;\n    }\n    return changed;\n}\n\nbool shrink_phase(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                  const vector<int> &target, mt19937 &rng) {\n    int n = rects.size();\n    vector<pair<long long, int>> overs;\n    overs.reserve(n);\n    for (int i = 0; i < n; ++i) {\n        long long def = (long long)target[i] - rect_area(rects[i]);\n        if (def < 0) overs.emplace_back(-def, i);\n    }\n    sort(overs.begin(), overs.end(), greater<>());\n    bool changed = false;\n    for (auto &p : overs) {\n        if (shrink_rect(p.second, rects, target, xs, ys, rng)) changed = true;\n    }\n    return changed;\n}\n\nbool random_shrink(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                   mt19937 &rng, int operations) {\n    int n = rects.size();\n    if (n == 0) return false;\n    bool changed = false;\n    uniform_int_distribution<int> dist_idx(0, n - 1);\n    for (int t = 0; t < operations; ++t) {\n        int idx = dist_idx(rng);\n        Rect &rc = rects[idx];\n        int avail[4] = {\n            xs[idx] - rc.x1,\n            rc.x2 - (xs[idx] + 1),\n            ys[idx] - rc.y1,\n            rc.y2 - (ys[idx] + 1)\n        };\n        vector<int> dirs;\n        for (int d = 0; d < 4; ++d) if (avail[d] > 0) dirs.push_back(d);\n        if (dirs.empty()) continue;\n        int dir = dirs[rng() % dirs.size()];\n        int cap = min(avail[dir], RANDOM_SHRINK_STEP_LIMIT);\n        if (cap <= 0) continue;\n        int amount = 1 + (cap > 1 ? rng() % cap : 0);\n        if (dir == 0) rc.x1 += amount;\n        else if (dir == 1) rc.x2 -= amount;\n        else if (dir == 2) rc.y1 += amount;\n        else rc.y2 -= amount;\n        changed = true;\n    }\n    return changed;\n}\n\ndouble compute_score(const vector<Rect> &rects, const vector<int> &target) {\n    double sum = 0.0;\n    int n = rects.size();\n    for (int i = 0; i < n; ++i) {\n        long long s = rect_area(rects[i]);\n        long long r = target[i];\n        if (s <= 0 || r <= 0) continue;\n        long long mn = min(s, r);\n        long long mx = max(s, r);\n        if (mx == 0) continue;\n        double ratio = (double)mn / (double)mx;\n        double p = 2.0 * ratio - ratio * ratio;\n        sum += p;\n    }\n    return sum;\n}\n\nbool validate_rects(const vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys) {\n    int n = rects.size();\n    for (int i = 0; i < n; ++i) {\n        const Rect &r = rects[i];\n        if (r.x1 < 0 || r.x1 >= r.x2 || r.x2 > BOARD_SIZE) return false;\n        if (r.y1 < 0 || r.y1 >= r.y2 || r.y2 > BOARD_SIZE) return false;\n        if (!(r.x1 <= xs[i] && xs[i] + 1 <= r.x2)) return false;\n        if (!(r.y1 <= ys[i] && ys[i] + 1 <= r.y2)) return false;\n    }\n    for (int i = 0; i < n; ++i) {\n        for (int j = i + 1; j < n; ++j) {\n            const Rect &a = rects[i];\n            const Rect &b = rects[j];\n            if (max(a.x1, b.x1) < min(a.x2, b.x2) &&\n                max(a.y1, b.y1) < min(a.y2, b.y2)) return false;\n        }\n    }\n    return true;\n}\n\nstruct AttemptResult {\n    vector<Rect> rects;\n    double score;\n};\n\nAttemptResult run_attempt(const vector<Rect> &start_rects, const vector<int> &xs, const vector<int> &ys,\n                          const vector<int> &target, mt19937 &rng,\n                          const chrono::steady_clock::time_point &start_time,\n                          double time_limit) {\n    vector<Rect> rects = start_rects;\n    vector<Rect> best_rect = rects;\n    double best_score = compute_score(rects, target);\n    int n = rects.size();\n    vector<long long> defs(n);\n    int stagnation = 0;\n\n    for (int pass = 0; ; ++pass) {\n        if ((pass & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n            if (elapsed >= time_limit) break;\n        }\n        for (int i = 0; i < n; ++i) defs[i] = (long long)target[i] - rect_area(rects[i]);\n\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n        bool sort_by_def = (pass % 3 != 1);\n        if (sort_by_def) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (defs[a] != defs[b]) return defs[a] > defs[b];\n                return a < b;\n            });\n        }\n\n        bool changedExp = false;\n        for (int idx : order) {\n            if (grow_rect(idx, rects, target, rng)) changedExp = true;\n        }\n\n        bool changedShrink = shrink_phase(rects, xs, ys, target, rng);\n        bool changed = changedExp || changedShrink;\n        bool randomChanged = false;\n\n        if (!changed) {\n            stagnation++;\n            if (stagnation % 3 == 0) {\n                int ops = max(1, n / 4);\n                randomChanged = random_shrink(rects, xs, ys, rng, ops);\n            }\n            if (randomChanged) {\n                changed = true;\n                stagnation = 0;\n            } else if (stagnation > STAGNATION_LIMIT) {\n                rects = best_rect;\n                bool perturbed = random_shrink(rects, xs, ys, rng, max(1, n));\n                stagnation = 0;\n                if (!perturbed) break;\n                else continue;\n            }\n        } else {\n            stagnation = 0;\n        }\n\n        double cur_score = compute_score(rects, target);\n        if (cur_score > best_score + 1e-9) {\n            best_score = cur_score;\n            best_rect = rects;\n        }\n    }\n    return {best_rect, best_score};\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> xs(n), ys(n), rs(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> xs[i] >> ys[i] >> rs[i];\n    }\n\n    vector<Rect> base(n);\n    for (int i = 0; i < n; ++i) {\n        base[i] = {xs[i], ys[i], xs[i] + 1, ys[i] + 1};\n    }\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    const double TIME_LIMIT = 4.85;\n    auto start_time = chrono::steady_clock::now();\n\n    vector<Rect> seed = base;\n    vector<Rect> best = base;\n    double best_score = compute_score(base, rs);\n\n    while (true) {\n        AttemptResult res = run_attempt(seed, xs, ys, rs, rng, start_time, TIME_LIMIT);\n        if (res.score > best_score + 1e-9) {\n            best_score = res.score;\n            best = res.rects;\n        }\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n        if (elapsed >= TIME_LIMIT - 0.2) break;\n        seed = res.rects;\n        if (!random_shrink(seed, xs, ys, rng, max(1, n / 2))) break;\n    }\n\n    if (!validate_rects(best, xs, ys)) best = base;\n\n    for (const auto &r : best) {\n        cout << r.x1 << ' ' << r.y1 << ' ' << r.x2 << ' ' << r.y2 << '\\n';\n    }\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int N2 = N * N;\n    static constexpr int MAX_TILES = 2500;\n    using VisitBitset = bitset<MAX_TILES>;\n\n    struct Neighbor {\n        int to;\n        char dir;\n    };\n    struct Node {\n        VisitBitset visited;\n        int pos = 0;\n        int score = 0;\n        int parent = -1;\n        char move = '?';\n        int depth = 0;\n    };\n    struct Candidate {\n        double eval;\n        int idx;\n    };\n    struct Features {\n        int mobility = 0;\n        int nei1 = 0;\n        int nei2 = 0;\n        int two = 0;\n    };\n\n    vector<int> tileOf;\n    vector<int> value;\n    vector<vector<Neighbor>> adj;\n    int startIdx = 0;\n\n    mt19937_64 rng;\n    chrono::steady_clock::time_point timeStart;\n    string bestPath;\n    int bestScore = 0;\n\n    const double TIME_LIMIT = 1.95;\n    const double LENGTH_WEIGHT = 8.0;\n    const double MOBILITY_WEIGHT = 16.0;\n    const double NEI1_WEIGHT = 1.1;\n    const double NEI2_WEIGHT = 0.4;\n    const double TWO_WEIGHT = 0.6;\n    const double RANDOM_WEIGHT = 0.8;\n\n    const double GREEDY_VALUE_WEIGHT = 1.0;\n    const double GREEDY_MOB_WEIGHT = 20.0;\n    const double GREEDY_NEI_WEIGHT = 0.9;\n    const double GREEDY_TWO_WEIGHT = 0.4;\n    const double GREEDY_RANDOM_WEIGHT = 0.4;\n    const int MAX_GREEDY_STEPS = 1500;\n    const int MAX_GREEDY_CANDIDATES = 3;\n\n    inline double rand01() {\n        static constexpr double INV = 1.0 / (1ULL << 53);\n        return (rng() >> 11) * INV;\n    }\n    inline double elapsed() const {\n        using namespace chrono;\n        return duration<double>(steady_clock::now() - timeStart).count();\n    }\n    inline bool timeUp() const {\n        return elapsed() > TIME_LIMIT;\n    }\n\n    Features calcFeatures(const VisitBitset &vis, int pos) const {\n        Features feat;\n        for (const auto &nb : adj[pos]) {\n            if (vis.test(tileOf[nb.to])) continue;\n            ++feat.mobility;\n            int val = value[nb.to];\n            if (val >= feat.nei1) {\n                feat.nei2 = feat.nei1;\n                feat.nei1 = val;\n            } else if (val > feat.nei2) {\n                feat.nei2 = val;\n            }\n            for (const auto &nb2 : adj[nb.to]) {\n                if (vis.test(tileOf[nb2.to])) continue;\n                int val2 = value[nb2.to];\n                if (val2 > feat.two) feat.two = val2;\n            }\n        }\n        return feat;\n    }\n\n    string buildPath(const vector<Node> &pool, int idx) const {\n        string res;\n        res.reserve(pool[idx].depth);\n        int cur = idx;\n        while (cur != -1) {\n            const Node &node = pool[cur];\n            if (node.parent == -1) break;\n            res.push_back(node.move);\n            cur = node.parent;\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    void greedyExtend(const Node &startNode, string path) {\n        VisitBitset vis = startNode.visited;\n        int pos = startNode.pos;\n        int score = startNode.score;\n        array<Neighbor, 4> moveBuf;\n        int steps = 0;\n        while (!timeUp() && steps < MAX_GREEDY_STEPS) {\n            int moveCount = 0;\n            for (const auto &nb : adj[pos]) {\n                if (vis.test(tileOf[nb.to])) continue;\n                moveBuf[moveCount++] = nb;\n            }\n            if (moveCount == 0) break;\n            double bestEval = -1e100;\n            int bestIdx = -1;\n            VisitBitset bestVis;\n            for (int i = 0; i < moveCount; ++i) {\n                VisitBitset nextVis = vis;\n                nextVis.set(tileOf[moveBuf[i].to]);\n                Features feat = calcFeatures(nextVis, moveBuf[i].to);\n                double eval = GREEDY_VALUE_WEIGHT * value[moveBuf[i].to]\n                            + GREEDY_MOB_WEIGHT * feat.mobility\n                            + GREEDY_NEI_WEIGHT * feat.nei1\n                            + GREEDY_TWO_WEIGHT * feat.two\n                            + GREEDY_RANDOM_WEIGHT * rand01();\n                if (eval > bestEval) {\n                    bestEval = eval;\n                    bestIdx = i;\n                    bestVis = nextVis;\n                }\n            }\n            if (bestIdx == -1) break;\n            const Neighbor &chosen = moveBuf[bestIdx];\n            vis = bestVis;\n            pos = chosen.to;\n            score += value[pos];\n            path.push_back(chosen.dir);\n            ++steps;\n        }\n        if (score > bestScore || (score == bestScore && path.size() > bestPath.size())) {\n            bestScore = score;\n            bestPath = std::move(path);\n        }\n    }\n\n    void runBeam(int beamWidth) {\n        if (timeUp()) return;\n        const size_t MAX_POOL_RESERVE = 220000;\n        vector<Node> pool;\n        size_t reserveSize = min<size_t>(static_cast<size_t>(beamWidth) * 900 + 1000ULL, MAX_POOL_RESERVE);\n        pool.reserve(reserveSize);\n\n        pool.emplace_back();\n        Node &root = pool.back();\n        root.visited.reset();\n        root.visited.set(tileOf[startIdx]);\n        root.pos = startIdx;\n        root.score = value[startIdx];\n        root.parent = -1;\n        root.move = '?';\n        root.depth = 0;\n\n        int runBestIdx = 0;\n        int runBestScore = root.score;\n\n        vector<int> current;\n        current.reserve(beamWidth);\n        current.push_back(0);\n\n        vector<Candidate> candBuf;\n        candBuf.reserve(beamWidth * 4 + 10);\n\n        array<Neighbor, 4> moveBuf;\n        bool forceStop = false;\n\n        while (!current.empty() && !forceStop) {\n            if (timeUp()) break;\n            candBuf.clear();\n            for (int idx : current) {\n                if (timeUp()) { forceStop = true; break; }\n                VisitBitset parentVis = pool[idx].visited;\n                int pos = pool[idx].pos;\n                int baseScore = pool[idx].score;\n                int depth = pool[idx].depth;\n\n                int moveCount = 0;\n                for (const auto &nb : adj[pos]) {\n                    if (parentVis.test(tileOf[nb.to])) continue;\n                    moveBuf[moveCount++] = nb;\n                }\n                if (moveCount == 0) continue;\n                if (moveCount > 1) {\n                    shuffle(moveBuf.begin(), moveBuf.begin() + moveCount, rng);\n                }\n                for (int mi = 0; mi < moveCount; ++mi) {\n                    if (timeUp()) { forceStop = true; break; }\n                    const Neighbor &nb = moveBuf[mi];\n                    pool.emplace_back();\n                    Node &child = pool.back();\n                    child.visited = parentVis;\n                    child.visited.set(tileOf[nb.to]);\n                    child.pos = nb.to;\n                    child.score = baseScore + value[nb.to];\n                    child.parent = idx;\n                    child.move = nb.dir;\n                    child.depth = depth + 1;\n                    int childIdx = (int)pool.size() - 1;\n\n                    Features feat = calcFeatures(child.visited, child.pos);\n                    double eval = child.score\n                                + LENGTH_WEIGHT * child.depth\n                                + MOBILITY_WEIGHT * feat.mobility\n                                + NEI1_WEIGHT * feat.nei1\n                                + NEI2_WEIGHT * feat.nei2\n                                + TWO_WEIGHT * feat.two\n                                + RANDOM_WEIGHT * rand01();\n\n                    candBuf.push_back({eval, childIdx});\n\n                    if (child.score > runBestScore ||\n                        (child.score == runBestScore && child.depth > pool[runBestIdx].depth)) {\n                        runBestScore = child.score;\n                        runBestIdx = childIdx;\n                    }\n                }\n                if (forceStop) break;\n            }\n            if (forceStop || candBuf.empty()) break;\n\n            auto cmp = [](const Candidate &a, const Candidate &b) { return a.eval > b.eval; };\n            if ((int)candBuf.size() > beamWidth) {\n                partial_sort(candBuf.begin(), candBuf.begin() + beamWidth, candBuf.end(), cmp);\n                candBuf.resize(beamWidth);\n            } else {\n                sort(candBuf.begin(), candBuf.end(), cmp);\n            }\n\n            current.clear();\n            current.reserve(candBuf.size());\n            for (const auto &cand : candBuf) current.push_back(cand.idx);\n        }\n\n        string runBestPath = buildPath(pool, runBestIdx);\n        if (runBestScore > bestScore ||\n            (runBestScore == bestScore && runBestPath.size() > bestPath.size())) {\n            bestScore = runBestScore;\n            bestPath = runBestPath;\n        }\n\n        if (!timeUp()) {\n            vector<int> greedies;\n            greedies.reserve(MAX_GREEDY_CANDIDATES);\n            greedies.push_back(runBestIdx);\n            for (int idx : current) {\n                if ((int)greedies.size() >= MAX_GREEDY_CANDIDATES) break;\n                bool dup = false;\n                for (int g : greedies) if (g == idx) { dup = true; break; }\n                if (!dup) greedies.push_back(idx);\n            }\n            for (int idx : greedies) {\n                if (timeUp()) break;\n                string path = buildPath(pool, idx);\n                greedyExtend(pool[idx], std::move(path));\n            }\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        int si, sj;\n        if (!(cin >> si >> sj)) return;\n        tileOf.resize(N2);\n        int maxTile = -1;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int t;\n                cin >> t;\n                int idx = i * N + j;\n                tileOf[idx] = t;\n                maxTile = max(maxTile, t);\n            }\n        }\n        [[maybe_unused]] int tileCount = maxTile + 1;\n        value.resize(N2);\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int p;\n                cin >> p;\n                value[i * N + j] = p;\n            }\n        }\n        startIdx = si * N + sj;\n\n        adj.assign(N2, {});\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n        const char dirChar[4] = {'U', 'D', 'L', 'R'};\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int idx = i * N + j;\n                for (int d = 0; d < 4; ++d) {\n                    int ni = i + di[d];\n                    int nj = j + dj[d];\n                    if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                    int nidx = ni * N + nj;\n                    adj[idx].push_back({nidx, dirChar[d]});\n                }\n            }\n        }\n\n        bestScore = value[startIdx];\n        bestPath.clear();\n\n        timeStart = chrono::steady_clock::now();\n        rng.seed(chrono::steady_clock::now().time_since_epoch().count());\n\n        vector<int> beamOptions = {60, 80, 100};\n        int iteration = 0;\n        while (!timeUp()) {\n            int bw = beamOptions[iteration % beamOptions.size()];\n            runBeam(bw);\n            ++iteration;\n        }\n\n        cout << bestPath << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\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    static constexpr int HOR = H * (W - 1);\n    static constexpr int VER = (H - 1) * W;\n    static constexpr int EDGE_CNT = HOR + VER;\n\n    // Parameters\n    const double INIT_MEAN = 5000.0;\n    const double INIT_PERT = 200.0;\n\n    const double BASE_VAR = 1.0e7;        // prior variance scale\n    const double INFO_OFFSET = 0.5;\n    const double MIN_VAR = 1.0e4;\n    const double MAX_INFO = 600.0;\n    const double INFO_GAIN_BASE = 1.2;    // total info per path\n\n    const double MEAS_NOISE_COEFF = (0.2 * 0.2) / 12.0; // variance of noise factor\n    const double MEAS_VAR_FLOOR = 1e5;\n\n    const double MIN_EDGE_WEIGHT = 900.0;\n    const double MAX_EDGE_WEIGHT = 9200.0;\n\n    const double ALPHA_MIN = 0.05;\n    const double ALPHA_MAX = 0.9;\n\n    const double EXPLORE_COEFF = 600.0;\n    const double EXPLORE_BASE = 1.0;\n    const double MIN_SEARCH_WEIGHT = 1.0;\n\n    vector<double> edgeWeight;\n    vector<int> edgeUse;\n    vector<double> edgeInfo;\n\n    vector<double> dist;\n    vector<int> prevNode;\n    vector<int> prevEdge;\n    vector<char> prevMove;\n\n    mt19937 rng;\n\n    Solver()\n        : edgeWeight(EDGE_CNT),\n          edgeUse(EDGE_CNT, 0),\n          edgeInfo(EDGE_CNT, 0.0),\n          dist(N),\n          prevNode(N),\n          prevEdge(N),\n          prevMove(N) {\n        rng.seed(chrono::steady_clock::now().time_since_epoch().count());\n        uniform_real_distribution<double> perturb(-INIT_PERT, INIT_PERT);\n        for (int i = 0; i < EDGE_CNT; ++i) {\n            edgeWeight[i] = INIT_MEAN + perturb(rng);\n        }\n    }\n\n    inline int nodeId(int i, int j) const { return i * W + j; }\n    inline int horId(int i, int j) const { return i * (W - 1) + j; }\n    inline int verId(int i, int j) const { return HOR + i * W + j; }\n\n    double edgeCostForSearch(int eid) const {\n        double bias = EXPLORE_COEFF / sqrt(edgeUse[eid] + EXPLORE_BASE);\n        double w = edgeWeight[eid] - bias;\n        if (w < MIN_SEARCH_WEIGHT) w = MIN_SEARCH_WEIGHT;\n        return w;\n    }\n\n    void buildFallback(int si, int sj, int ti, int tj, string &path, vector<int> &pathEdges) {\n        path.clear();\n        pathEdges.clear();\n        int ci = si, cj = sj;\n        auto pushStep = [&](char mv) {\n            path.push_back(mv);\n            if (mv == 'U') {\n                pathEdges.push_back(verId(ci - 1, cj));\n                --ci;\n            } else if (mv == 'D') {\n                pathEdges.push_back(verId(ci, cj));\n                ++ci;\n            } else if (mv == 'L') {\n                pathEdges.push_back(horId(ci, cj - 1));\n                --cj;\n            } else { // 'R'\n                pathEdges.push_back(horId(ci, cj));\n                ++cj;\n            }\n        };\n        while (ci < ti) pushStep('D');\n        while (ci > ti) pushStep('U');\n        while (cj < tj) pushStep('R');\n        while (cj > tj) pushStep('L');\n    }\n\n    void computePath(int si, int sj, int ti, int tj, string &path, vector<int> &pathEdges) {\n        path.clear();\n        pathEdges.clear();\n        int start = nodeId(si, sj);\n        int target = nodeId(ti, tj);\n        const double INF = 1e100;\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevNode.begin(), prevNode.end(), -1);\n        fill(prevEdge.begin(), prevEdge.end(), -1);\n        fill(prevMove.begin(), prevMove.end(), 0);\n\n        struct PQNode {\n            double dist;\n            int node;\n            bool operator<(const PQNode &other) const {\n                return dist > other.dist;\n            }\n        };\n\n        priority_queue<PQNode> pq;\n        dist[start] = 0.0;\n        pq.push({0.0, start});\n\n        while (!pq.empty()) {\n            PQNode cur = pq.top();\n            pq.pop();\n            if (cur.dist > dist[cur.node]) continue;\n            if (cur.node == target) break;\n            int i = cur.node / W;\n            int j = cur.node % W;\n\n            if (i > 0) {\n                int nb = cur.node - W;\n                int eid = verId(i - 1, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'U';\n                    pq.push({nd, nb});\n                }\n            }\n            if (i + 1 < H) {\n                int nb = cur.node + W;\n                int eid = verId(i, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                prevMove[nb] = 'D';\n                    pq.push({nd, nb});\n                }\n            }\n            if (j > 0) {\n                int nb = cur.node - 1;\n                int eid = horId(i, j - 1);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'L';\n                    pq.push({nd, nb});\n                }\n            }\n            if (j + 1 < W) {\n                int nb = cur.node + 1;\n                int eid = horId(i, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'R';\n                    pq.push({nd, nb});\n                }\n            }\n        }\n\n        if (start != target && prevEdge[target] == -1) {\n            buildFallback(si, sj, ti, tj, path, pathEdges);\n            return;\n        }\n        int cur = target;\n        while (cur != start) {\n            int pe = prevEdge[cur];\n            if (pe == -1) {\n                buildFallback(si, sj, ti, tj, path, pathEdges);\n                return;\n            }\n            path.push_back(prevMove[cur]);\n            pathEdges.push_back(pe);\n            cur = prevNode[cur];\n        }\n        reverse(path.begin(), path.end());\n        reverse(pathEdges.begin(), pathEdges.end());\n    }\n\n    void update(const vector<int> &pathEdges, double measurement) {\n        if (pathEdges.empty()) return;\n        size_t m = pathEdges.size();\n        vector<double> vars;\n        vars.reserve(m);\n        double predicted = 0.0;\n        double sumVar = 0.0;\n        for (int eid : pathEdges) {\n            predicted += edgeWeight[eid];\n            double var = BASE_VAR / (edgeInfo[eid] + INFO_OFFSET);\n            if (var < MIN_VAR) var = MIN_VAR;\n            vars.push_back(var);\n            sumVar += var;\n        }\n        if (sumVar <= 0.0) sumVar = MIN_VAR;\n\n        double residual = measurement - predicted;\n        double safePred = max(predicted, 1.0);\n        double measurementVar = MEAS_NOISE_COEFF * safePred * safePred + MEAS_VAR_FLOOR;\n        double alpha = sumVar / (sumVar + measurementVar);\n        if (alpha < ALPHA_MIN) alpha = ALPHA_MIN;\n        if (alpha > ALPHA_MAX) alpha = ALPHA_MAX;\n\n        double scale = alpha * residual / sumVar;\n        for (size_t idx = 0; idx < m; ++idx) {\n            int eid = pathEdges[idx];\n            double delta = vars[idx] * scale;\n            double newWeight = edgeWeight[eid] + delta;\n            if (newWeight < MIN_EDGE_WEIGHT) newWeight = MIN_EDGE_WEIGHT;\n            else if (newWeight > MAX_EDGE_WEIGHT) newWeight = MAX_EDGE_WEIGHT;\n            edgeWeight[eid] = newWeight;\n        }\n\n        double invSumVar = 1.0 / sumVar;\n        for (size_t idx = 0; idx < m; ++idx) {\n            int eid = pathEdges[idx];\n            double infoGain = INFO_GAIN_BASE * vars[idx] * invSumVar;\n            edgeInfo[eid] = min(edgeInfo[eid] + infoGain, MAX_INFO);\n            edgeUse[eid] = min(edgeUse[eid] + 1, 1000000000);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    string path;\n    path.reserve(128);\n    vector<int> pathEdges;\n    pathEdges.reserve(128);\n\n    for (int q = 0; q < 1000; ++q) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        solver.computePath(si, sj, ti, tj, path, pathEdges);\n        cout << path << '\\n' << flush;\n\n        int measurement;\n        if (!(cin >> measurement)) return 0;\n        if (measurement < 0) return 0;  // judge signals failure\n\n        solver.update(pathEdges, static_cast<double>(measurement));\n    }\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 20;\nconstexpr int MAXLEN = 12;\nconstexpr int ORIENT = 2;\nconstexpr int PL_PER_ORIENT = N * N;\nconstexpr int PL = ORIENT * PL_PER_ORIENT;\nconstexpr uint8_t EMPTY = 0xFF;\nconst double TIME_LIMIT = 2.9;\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 Placement {\n    array<uint8_t, MAXLEN> rows;\n    array<uint8_t, MAXLEN> cols;\n    array<int, MAXLEN> cellIndex; // base index ((r*N + c)<<3)\n};\n\nstruct Read {\n    string s;\n    vector<uint8_t> codes;\n    int len;\n};\n\nusing Grid = array<array<uint8_t, N>, N>;\n\nvector<Placement> build_placements() {\n    vector<Placement> placements(PL);\n    int idx = 0;\n    for (int ori = 0; ori < 2; ++ori) {\n        for (int line = 0; line < N; ++line) {\n            for (int start = 0; start < N; ++start) {\n                Placement &p = placements[idx++];\n                for (int t = 0; t < MAXLEN; ++t) {\n                    int r, c;\n                    if (ori == 0) { // horizontal\n                        r = line;\n                        c = (start + t) % N;\n                    } else { // vertical\n                        r = (start + t) % N;\n                        c = line;\n                    }\n                    p.rows[t] = static_cast<uint8_t>(r);\n                    p.cols[t] = static_cast<uint8_t>(c);\n                    p.cellIndex[t] = ((r * N + c) << 3);\n                }\n            }\n        }\n    }\n    return placements;\n}\n\nGrid seed_grid(const vector<Read> &reads, const vector<Placement> &placements, mt19937_64 &rng) {\n    Grid grid;\n    for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) grid[i][j] = EMPTY;\n\n    int M = reads.size();\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b){\n        if (reads[a].len != reads[b].len) return reads[a].len > reads[b].len;\n        return a < b;\n    });\n\n    for (int idx : order) {\n        const Read &rd = reads[idx];\n        int len = rd.len;\n        int chosen = -1;\n        int cnt = 0;\n        for (int pid = 0; pid < PL; ++pid) {\n            bool ok = true;\n            const auto &prow = placements[pid].rows;\n            const auto &pcol = placements[pid].cols;\n            for (int t = 0; t < len; ++t) {\n                uint8_t cur = grid[prow[t]][pcol[t]];\n                if (cur != EMPTY && cur != rd.codes[t]) { ok = false; break; }\n            }\n            if (ok) {\n                ++cnt;\n                if ((uint64_t)rng() % cnt == 0) chosen = pid;\n            }\n        }\n        if (chosen != -1) {\n            const auto &prow = placements[chosen].rows;\n            const auto &pcol = placements[chosen].cols;\n            for (int t = 0; t < len; ++t) {\n                grid[prow[t]][pcol[t]] = rd.codes[t];\n            }\n        }\n    }\n\n    uniform_int_distribution<int> dist(0, 7);\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            if (grid[i][j] == EMPTY) grid[i][j] = static_cast<uint8_t>(dist(rng));\n    return grid;\n}\n\nint compute_delta(int iter, int total) {\n    if (total <= 4) return 1;\n    if (iter * 3 >= total * 2) return 1;\n    if (iter * 3 >= total) return 2;\n    return 3;\n}\n\nvoid run_em(Grid &grid, int iterations, const vector<Read> &reads,\n            const vector<Placement> &placements, vector<double> &counts,\n            array<uint8_t, PL> &matchBuf, const vector<double> &weights,\n            double inertia, Timer &timer) {\n    for (int iter = 0; iter < iterations; ++iter) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n        fill(counts.begin(), counts.end(), 0.0);\n        int delta = compute_delta(iter, iterations);\n\n        for (const Read &rd : reads) {\n            const uint8_t *codes = rd.codes.data();\n            int len = rd.len;\n            int best = 0;\n            for (int pid = 0; pid < PL; ++pid) {\n                const auto &prow = placements[pid].rows;\n                const auto &pcol = placements[pid].cols;\n                int match = 0;\n                for (int t = 0; t < len; ++t) {\n                    if (grid[prow[t]][pcol[t]] == codes[t]) ++match;\n                }\n                matchBuf[pid] = static_cast<uint8_t>(match);\n                if (match > best) best = match;\n            }\n            if (best == 0) continue;\n            int threshold = best - delta;\n            if (threshold < 0) threshold = 0;\n\n            double totalWeight = 0.0;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = matchBuf[pid];\n                if (match < threshold) continue;\n                double w = weights[match];\n                if (w <= 0.0) continue;\n                totalWeight += w;\n            }\n            if (totalWeight <= 0.0) continue;\n            double inv = 1.0 / totalWeight;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = matchBuf[pid];\n                if (match < threshold) continue;\n                double w = weights[match];\n                if (w <= 0.0) continue;\n                double scaled = w * inv;\n                const auto &cellIdx = placements[pid].cellIndex;\n                for (int t = 0; t < len; ++t) {\n                    counts[cellIdx[t] + codes[t]] += scaled;\n                }\n            }\n        }\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                counts[((r * N + c) << 3) + grid[r][c]] += inertia;\n            }\n        }\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int base = ((r * N + c) << 3);\n                double bestVal = -1e100;\n                int bestLetter = grid[r][c];\n                for (int letter = 0; letter < 8; ++letter) {\n                    double v = counts[base + letter];\n                    if (v > bestVal) {\n                        bestVal = v;\n                        bestLetter = letter;\n                    }\n                }\n                grid[r][c] = static_cast<uint8_t>(bestLetter);\n            }\n        }\n    }\n}\n\nvoid repair_grid(Grid &grid, const vector<Read> &reads, const vector<Placement> &placements,\n                 int threshold, Timer &timer, vector<int> &bestPid, vector<int> &mism) {\n    int M = reads.size();\n    for (int i = 0; i < M; ++i) {\n        if (timer.elapsed() > TIME_LIMIT) return;\n        const Read &rd = reads[i];\n        int len = rd.len;\n        int bestMatch = -1;\n        int pidBest = -1;\n        for (int pid = 0; pid < PL; ++pid) {\n            const auto &prow = placements[pid].rows;\n            const auto &pcol = placements[pid].cols;\n            int match = 0;\n            for (int t = 0; t < len; ++t) {\n                if (grid[prow[t]][pcol[t]] == rd.codes[t]) ++match;\n            }\n            if (match > bestMatch) {\n                bestMatch = match;\n                pidBest = pid;\n                if (match == len) break;\n            }\n        }\n        if (bestMatch < 0) {\n            bestMatch = 0;\n            pidBest = 0;\n        }\n        bestPid[i] = pidBest;\n        mism[i] = len - bestMatch;\n    }\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b){\n        if (mism[a] != mism[b]) return mism[a] < mism[b];\n        return reads[a].len > reads[b].len;\n    });\n\n    for (int idx : order) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n        int m = mism[idx];\n        if (m == 0 || m > threshold) continue;\n        int pid = bestPid[idx];\n        const Read &rd = reads[idx];\n        const auto &prow = placements[pid].rows;\n        const auto &pcol = placements[pid].cols;\n        for (int t = 0; t < rd.len; ++t) {\n            grid[prow[t]][pcol[t]] = rd.codes[t];\n        }\n    }\n}\n\nint evaluate_grid(const Grid &grid, const vector<Read> &reads) {\n    array<array<uint8_t, N * 2>, N> rowBuf;\n    array<array<uint8_t, N * 2>, N> colBuf;\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N * 2; ++j)\n            rowBuf[i][j] = grid[i][j % N];\n    for (int j = 0; j < N; ++j)\n        for (int i = 0; i < N * 2; ++i)\n            colBuf[j][i] = grid[i % N][j];\n\n    int count = 0;\n    for (const Read &rd : reads) {\n        bool ok = false;\n        int len = rd.len;\n        const uint8_t *codes = rd.codes.data();\n        for (int i = 0; i < N && !ok; ++i) {\n            for (int start = 0; start < N; ++start) {\n                bool match = true;\n                for (int t = 0; t < len; ++t) {\n                    if (rowBuf[i][start + t] != codes[t]) { match = false; break; }\n                }\n                if (match) { ok = true; break; }\n            }\n        }\n        if (!ok) {\n            for (int j = 0; j < N && !ok; ++j) {\n                for (int start = 0; start < N; ++start) {\n                    bool match = true;\n                    for (int t = 0; t < len; ++t) {\n                        if (colBuf[j][start + t] != codes[t]) { match = false; break; }\n                    }\n                    if (match) { ok = true; break; }\n                }\n            }\n        }\n        if (ok) ++count;\n    }\n    return count;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N_input, M;\n    if (!(cin >> N_input >> M)) return 0;\n    vector<Read> reads(M);\n    for (int i = 0; i < M; ++i) {\n        string s; cin >> s;\n        reads[i].s = s;\n        reads[i].len = s.size();\n        reads[i].codes.resize(s.size());\n        for (int j = 0; j < (int)s.size(); ++j) {\n            reads[i].codes[j] = static_cast<uint8_t>(s[j] - 'A');\n        }\n    }\n\n    auto placements = build_placements();\n    vector<double> weights(MAXLEN + 1, 0.0);\n    weights[1] = 0.05;\n    double val = 1.0;\n    for (int m = 2; m <= MAXLEN; ++m) {\n        weights[m] = val;\n        val *= 1.75;\n    }\n    vector<double> counts(N * N * 8, 0.0);\n    array<uint8_t, PL> matchBuf{};\n    Timer timer;\n    mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    Grid bestGrid;\n    int bestScore = -1;\n\n    vector<int> bestPid(M), mism(M);\n\n    auto run_restart = [&](int mainIter, int postIter) {\n        Grid grid = seed_grid(reads, placements, rng);\n\n        run_em(grid, mainIter, reads, placements, counts, matchBuf, weights, 0.35, timer);\n        int score = evaluate_grid(grid, reads);\n        if (score > bestScore) {\n            bestScore = score;\n            bestGrid = grid;\n        }\n\n        if (TIME_LIMIT - timer.elapsed() > 0.35) {\n            repair_grid(grid, reads, placements, 1, timer, bestPid, mism);\n            run_em(grid, postIter, reads, placements, counts, matchBuf, weights, 0.25, timer);\n            score = evaluate_grid(grid, reads);\n            if (score > bestScore) {\n                bestScore = score;\n                bestGrid = grid;\n            }\n        }\n    };\n\n    int restarts = 0;\n    while (true) {\n        double elapsed = timer.elapsed();\n        double remaining = TIME_LIMIT - elapsed;\n        if (remaining <= 0) break;\n        if (remaining < 0.25 && restarts > 0) break;\n        run_restart(30, 6);\n        ++restarts;\n        if (timer.elapsed() > TIME_LIMIT) break;\n    }\n    if (restarts == 0) {\n        run_restart(30, 6);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        string line(N, 'A');\n        for (int j = 0; j < N; ++j) {\n            line[j] = static_cast<char>('A' + bestGrid[i][j]);\n        }\n        cout << line << '\\n';\n    }\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, si, sj;\n    if (!(cin >> N >> si >> sj)) return 0;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n    int total = N * N;\n    auto idx = [&](int i, int j) { return i * N + j; };\n\n    vector<int> cost(total, -1);\n    vector<int> road_cells;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (grid[i][j] != '#') {\n                int id = idx(i, j);\n                cost[id] = grid[i][j] - '0';\n                road_cells.push_back(id);\n            }\n        }\n    }\n    int start_id = idx(si, sj);\n\n    // Build row segments\n    vector<int> row_id(total, -1);\n    vector<vector<int>> row_cells;\n    row_cells.reserve(N * N / 2);\n    for (int i = 0; i < N; ++i) {\n        int j = 0;\n        while (j < N) {\n            if (grid[i][j] == '#') {\n                ++j;\n                continue;\n            }\n            int seg_id = (int)row_cells.size();\n            vector<int> cells;\n            while (j < N && grid[i][j] != '#') {\n                int cell = idx(i, j);\n                row_id[cell] = seg_id;\n                cells.push_back(cell);\n                ++j;\n            }\n            row_cells.push_back(move(cells));\n        }\n    }\n    int R = row_cells.size();\n\n    // Build column segments\n    vector<int> col_id(total, -1);\n    vector<vector<int>> col_cells;\n    col_cells.reserve(N * N / 2);\n    for (int j = 0; j < N; ++j) {\n        int i = 0;\n        while (i < N) {\n            if (grid[i][j] == '#') {\n                ++i;\n                continue;\n            }\n            int seg_id = (int)col_cells.size();\n            vector<int> cells;\n            while (i < N && grid[i][j] != '#') {\n                int cell = idx(i, j);\n                col_id[cell] = seg_id;\n                cells.push_back(cell);\n                ++i;\n            }\n            col_cells.push_back(move(cells));\n        }\n    }\n    int C = col_cells.size();\n\n    // Bipartite graph: rows -> columns\n    vector<vector<int>> adj(R);\n    for (int cell : road_cells) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && c >= 0) adj[r].push_back(c);\n    }\n    for (auto &vec : adj) {\n        sort(vec.begin(), vec.end());\n        vec.erase(unique(vec.begin(), vec.end()), vec.end());\n    }\n\n    // Maximum matching (Kuhn DFS)\n    vector<int> matchRow(R, -1), matchCol(C, -1);\n    vector<char> seen(C, 0);\n    auto dfs_match = [&](auto &&self, int u) -> bool {\n        for (int v : adj[u]) {\n            if (seen[v]) continue;\n            seen[v] = 1;\n            if (matchCol[v] == -1 || self(self, matchCol[v])) {\n                matchRow[u] = v;\n                matchCol[v] = u;\n                return true;\n            }\n        }\n        return false;\n    };\n    for (int u = 0; u < R; ++u) {\n        fill(seen.begin(), seen.end(), 0);\n        dfs_match(dfs_match, u);\n    }\n\n    // Minimum vertex cover via alternating BFS\n    vector<char> visRow(R, 0), visCol(C, 0);\n    queue<int> q;\n    for (int u = 0; u < R; ++u) {\n        if (matchRow[u] == -1) {\n            visRow[u] = 1;\n            q.push(u);\n        }\n    }\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        for (int v : adj[u]) {\n            if (matchRow[u] == v) continue;\n            if (visCol[v]) continue;\n            visCol[v] = 1;\n            int mu = matchCol[v];\n            if (mu != -1 && !visRow[mu]) {\n                visRow[mu] = 1;\n                q.push(mu);\n            }\n        }\n    }\n    vector<char> row_cover(R, 0), col_cover(C, 0);\n    for (int r = 0; r < R; ++r) row_cover[r] = !visRow[r];\n    for (int c = 0; c < C; ++c) col_cover[c] = visCol[c];\n\n    // If matching-based cover failed (shouldn't), fall back to all rows\n    bool cover_ok = true;\n    for (int cell : road_cells) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        bool covered = false;\n        if (r >= 0 && row_cover[r]) covered = true;\n        if (c >= 0 && col_cover[c]) covered = true;\n        if (!covered) { cover_ok = false; break; }\n    }\n    if (!cover_ok) {\n        fill(row_cover.begin(), row_cover.end(), 1);\n        fill(col_cover.begin(), col_cover.end(), 0);\n    }\n\n    // Dijkstra from start\n    const int INF = 1e9;\n    vector<int> dist(total, INF);\n    vector<int> parent(total, -1);\n    priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n    dist[start_id] = 0;\n    pq.push({0, start_id});\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    while (!pq.empty()) {\n        auto [d, u] = pq.top(); pq.pop();\n        if (d != dist[u]) continue;\n        int ui = u / N, uj = u % N;\n        for (int dir = 0; dir < 4; ++dir) {\n            int vi = ui + di[dir];\n            int vj = uj + dj[dir];\n            if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n            int v = idx(vi, vj);\n            if (cost[v] == -1) continue;\n            int nd = d + cost[v];\n            if (nd < dist[v]) {\n                dist[v] = nd;\n                parent[v] = u;\n                pq.push({nd, v});\n            }\n        }\n    }\n\n    // Choose target cells\n    vector<char> row_need(R, 0), col_need(C, 0);\n    for (int r = 0; r < R; ++r) row_need[r] = row_cover[r];\n    for (int c = 0; c < C; ++c) col_need[c] = col_cover[c];\n    vector<char> is_target(total, 0);\n    vector<int> targets;\n    targets.reserve(row_cells.size() + col_cells.size());\n    auto add_target = [&](int cell) {\n        if (!is_target[cell]) {\n            is_target[cell] = 1;\n            targets.push_back(cell);\n        }\n    };\n\n    vector<int> sorted_cells = road_cells;\n    sort(sorted_cells.begin(), sorted_cells.end(), [&](int a, int b) {\n        if (dist[a] != dist[b]) return dist[a] < dist[b];\n        return a < b;\n    });\n    for (int cell : sorted_cells) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r < 0 || c < 0) continue;\n        if (row_need[r] && col_need[c]) {\n            add_target(cell);\n            row_need[r] = 0;\n            col_need[c] = 0;\n        }\n    }\n    for (int r = 0; r < R; ++r) {\n        if (!row_need[r]) continue;\n        const auto &vec = row_cells[r];\n        int best = vec[0];\n        int bestDist = dist[best];\n        for (int cell : vec) {\n            if (dist[cell] < bestDist) {\n                bestDist = dist[cell];\n                best = cell;\n            }\n        }\n        add_target(best);\n        row_need[r] = 0;\n        int c = col_id[best];\n        if (c >= 0 && col_need[c]) col_need[c] = 0;\n    }\n    for (int c = 0; c < C; ++c) {\n        if (!col_need[c]) continue;\n        const auto &vec = col_cells[c];\n        int best = vec[0];\n        int bestDist = dist[best];\n        for (int cell : vec) {\n            if (dist[cell] < bestDist) {\n                bestDist = dist[cell];\n                best = cell;\n            }\n        }\n        add_target(best);\n        col_need[c] = 0;\n    }\n\n    // Ensure every required segment really has a target\n    vector<char> row_hit(R, 0), col_hit(C, 0);\n    for (int cell : targets) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0) row_hit[r] = 1;\n        if (c >= 0) col_hit[c] = 1;\n    }\n    for (int r = 0; r < R; ++r) {\n        if (row_cover[r] && !row_hit[r]) {\n            const auto &vec = row_cells[r];\n            int best = vec[0];\n            int bestDist = dist[best];\n            for (int cell : vec) if (dist[cell] < bestDist) { bestDist = dist[cell]; best = cell; }\n            add_target(best);\n            row_hit[r] = 1;\n            int c = col_id[best];\n            if (c >= 0) col_hit[c] = 1;\n        }\n    }\n    for (int c = 0; c < C; ++c) {\n        if (col_cover[c] && !col_hit[c]) {\n            const auto &vec = col_cells[c];\n            int best = vec[0];\n            int bestDist = dist[best];\n            for (int cell : vec) if (dist[cell] < bestDist) { bestDist = dist[cell]; best = cell; }\n            add_target(best);\n            col_hit[c] = 1;\n            int r = row_id[best];\n            if (r >= 0) row_hit[r] = 1;\n        }\n    }\n    if (targets.empty()) add_target(start_id);\n\n    // Build required nodes via shortest-path tree paths\n    vector<char> required(total, 0);\n    required[start_id] = 1;\n    bool need_all = false;\n    auto mark_path = [&](int node) {\n        while (!required[node]) {\n            required[node] = 1;\n            if (node == start_id) return;\n            int p = parent[node];\n            if (p == -1) { need_all = true; return; }\n            node = p;\n        }\n    };\n    for (int cell : targets) mark_path(cell);\n    if (need_all) {\n        fill(required.begin(), required.end(), 0);\n        for (int cell : road_cells) required[cell] = 1;\n        required[start_id] = 1;\n    }\n\n    // Build adjacency of the induced tree\n    vector<vector<int>> treeAdj(total);\n    for (int v = 0; v < total; ++v) {\n        if (!required[v]) continue;\n        int p = parent[v];\n        if (p == -1) continue;\n        if (!required[p]) continue;\n        treeAdj[v].push_back(p);\n        treeAdj[p].push_back(v);\n    }\n\n    auto dir_char = [&](int from, int to) -> char {\n        int fi = from / N, fj = from % N;\n        int ti = to / N, tj = to % N;\n        if (ti == fi - 1 && tj == fj) return 'U';\n        if (ti == fi + 1 && tj == fj) return 'D';\n        if (tj == fj - 1 && ti == fi) return 'L';\n        if (tj == fj + 1 && ti == fi) return 'R';\n        return 'U'; // should not happen\n    };\n\n    // DFS traversal of tree\n    string route;\n    route.reserve(required.size() * 2);\n    struct Frame { int node, parent, idx; };\n    vector<Frame> stack;\n    stack.push_back({start_id, -1, 0});\n    while (!stack.empty()) {\n        Frame &fr = stack.back();\n        if (fr.idx == (int)treeAdj[fr.node].size()) {\n            stack.pop_back();\n            if (fr.parent != -1) route.push_back(dir_char(fr.node, fr.parent));\n            continue;\n        }\n        int v = treeAdj[fr.node][fr.idx++];\n        if (v == fr.parent) continue;\n        route.push_back(dir_char(fr.node, v));\n        stack.push_back({v, fr.node, 0});\n    }\n\n    cout << route << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Node {\n    long long priority;\n    int task;\n    bool operator<(const Node& other) const {\n        if (priority != other.priority) return priority < other.priority; // max-heap\n        return task > other.task;\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>> req(N, vector<int>(K));\n    for (int i = 0; i < N; ++i)\n        for (int k = 0; k < K; ++k)\n            cin >> req[i][k];\n\n    vector<vector<int>> adj(N);\n    vector<int> indeg(N, 0);\n    for (int i = 0; i < R; ++i) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        adj[u].push_back(v);\n        indeg[v]++;\n    }\n\n    vector<int> sum_d(N, 0), max_d(N, 0);\n    for (int i = 0; i < N; ++i) {\n        int s = 0, m = 0;\n        for (int k = 0; k < K; ++k) {\n            s += req[i][k];\n            m = max(m, req[i][k]);\n        }\n        sum_d[i] = s;\n        max_d[i] = m;\n    }\n\n    // Longest distance to sink (since u<v we can walk backwards).\n    vector<int> level(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        int best = 0;\n        for (int v : adj[i]) best = max(best, level[v] + 1);\n        level[i] = best;\n    }\n\n    auto calc_priority = [&](int i) -> long long {\n        long long val = 0;\n        val += 1'000'000LL * level[i];\n        val += 1'000LL * sum_d[i];\n        val += 10LL * (int)adj[i].size();\n        val += (1000 - i); // small tie breaker\n        return val;\n    };\n\n    priority_queue<Node> pq;\n    vector<int> task_state(N, 0); // 0 not ready, 1 ready, 2 in progress, 3 done\n    for (int i = 0; i < N; ++i) {\n        if (indeg[i] == 0) {\n            task_state[i] = 1;\n            pq.push({calc_priority(i), i});\n        }\n    }\n\n    vector<int> worker_task(M, -1);\n    vector<int> worker_start(M, -1);\n    vector<double> worker_ability(M, 1.0);\n    const double ability_alpha = 0.3;\n    int completed_tasks = 0;\n    int day = 1;\n\n    while (true) {\n        // prepare worker order\n        vector<int> idle_workers;\n        idle_workers.reserve(M);\n        for (int j = 0; j < M; ++j)\n            if (worker_task[j] == -1)\n                idle_workers.push_back(j);\n\n        sort(idle_workers.begin(), idle_workers.end(),\n             [&](int a, int b) {\n                 if (fabs(worker_ability[a] - worker_ability[b]) > 1e-9)\n                     return worker_ability[a] > worker_ability[b];\n                 return a < b;\n             });\n\n        // fetch tasks\n        vector<Node> fetched;\n        if (!idle_workers.empty()) {\n            fetched.reserve(idle_workers.size());\n            while (fetched.size() < idle_workers.size() && !pq.empty()) {\n                Node cur = pq.top(); pq.pop();\n                if (task_state[cur.task] != 1) continue; // stale entry\n                fetched.push_back(cur);\n            }\n        }\n\n        vector<int> task_order(fetched.size());\n        iota(task_order.begin(), task_order.end(), 0);\n        sort(task_order.begin(), task_order.end(),\n             [&](int lhs, int rhs) {\n                 int t1 = fetched[lhs].task;\n                 int t2 = fetched[rhs].task;\n                 if (sum_d[t1] != sum_d[t2]) return sum_d[t1] > sum_d[t2];\n                 if (level[t1] != level[t2]) return level[t1] > level[t2];\n                 return t1 < t2;\n             });\n\n        size_t assign_cnt = min(fetched.size(), idle_workers.size());\n        vector<bool> task_used(fetched.size(), false);\n        vector<pair<int,int>> outputs;\n        outputs.reserve(assign_cnt);\n\n        for (size_t idx = 0; idx < assign_cnt; ++idx) {\n            int worker = idle_workers[idx];\n            int task_idx = task_order[idx];\n            Node item = fetched[task_idx];\n            int task = item.task;\n\n            worker_task[worker] = task;\n            worker_start[worker] = day;\n            task_state[task] = 2;\n            task_used[task_idx] = true;\n            outputs.emplace_back(worker, task);\n        }\n\n        // push back unused ready tasks (safety net)\n        for (size_t i = 0; i < fetched.size(); ++i) {\n            if (!task_used[i]) {\n                pq.push(fetched[i]);\n            }\n        }\n\n        // output for this day\n        cout << outputs.size();\n        for (auto &p : outputs) {\n            cout << ' ' << (p.first + 1) << ' ' << (p.second + 1);\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int n_finish;\n        if (!(cin >> n_finish)) return 0;\n        if (n_finish == -1) break;\n\n        vector<int> finished_workers(n_finish);\n        for (int i = 0; i < n_finish; ++i) {\n            cin >> finished_workers[i];\n            finished_workers[i]--; // to 0-index\n        }\n\n        for (int w : finished_workers) {\n            if (w < 0 || w >= M) continue;\n            int task = worker_task[w];\n            if (task == -1) continue;\n            int duration = day - worker_start[w] + 1;\n            if (duration <= 0) duration = 1;\n            double difficulty = max(1, sum_d[task]);\n            double ratio = difficulty / duration;\n            worker_ability[w] = worker_ability[w] * (1.0 - ability_alpha) + ratio * ability_alpha;\n            if (worker_ability[w] < 1e-6) worker_ability[w] = 1e-6;\n\n            worker_task[w] = -1;\n            worker_start[w] = -1;\n\n            task_state[task] = 3;\n            completed_tasks++;\n\n            for (int nxt : adj[task]) {\n                indeg[nxt]--;\n                if (indeg[nxt] == 0 && task_state[nxt] == 0) {\n                    task_state[nxt] = 1;\n                    pq.push({calc_priority(nxt), nxt});\n                }\n            }\n        }\n\n        day++;\n        if (day > 2100) break; // safety\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int OFFICE = 400;\n\nstruct Order {\n    int ax, ay, cx, cy;\n    int len;\n    int base;\n};\n\ninline int manhattan(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\nlong long calcCost(const vector<int>& route, long long sumLen, const vector<Order>& orders) {\n    if (route.empty()) return 0;\n    long long cost = sumLen;\n    int first = route[0];\n    cost += manhattan(OFFICE, OFFICE, orders[first].ax, orders[first].ay);\n    for (int i = 0; i + 1 < (int)route.size(); ++i) {\n        const Order& cur = orders[route[i]];\n        const Order& nxt = orders[route[i + 1]];\n        cost += manhattan(cur.cx, cur.cy, nxt.ax, nxt.ay);\n    }\n    const Order& last = orders[route.back()];\n    cost += manhattan(last.cx, last.cy, OFFICE, OFFICE);\n    return cost;\n}\n\nvector<int> buildInitialRoute(const vector<int>& selected, const vector<Order>& orders) {\n    vector<int> remaining = selected;\n    vector<int> route;\n    route.reserve(remaining.size());\n    while (!remaining.empty()) {\n        int bestPos = 0;\n        int bestDist = INT_MAX;\n        if (route.empty()) {\n            for (int i = 0; i < (int)remaining.size(); ++i) {\n                int idx = remaining[i];\n                int d = manhattan(OFFICE, OFFICE, orders[idx].ax, orders[idx].ay);\n                if (d < bestDist || (d == bestDist && orders[idx].len < orders[remaining[bestPos]].len)) {\n                    bestDist = d;\n                    bestPos = i;\n                }\n            }\n        } else {\n            int last = route.back();\n            for (int i = 0; i < (int)remaining.size(); ++i) {\n                int idx = remaining[i];\n                int d = manhattan(orders[last].cx, orders[last].cy, orders[idx].ax, orders[idx].ay);\n                if (d < bestDist || (d == bestDist && orders[idx].len < orders[remaining[bestPos]].len)) {\n                    bestDist = d;\n                    bestPos = i;\n                }\n            }\n        }\n        route.push_back(remaining[bestPos]);\n        remaining[bestPos] = remaining.back();\n        remaining.pop_back();\n    }\n    return route;\n}\n\nlong long twoOptImprove(vector<int>& route, long long sumLen, const vector<Order>& orders) {\n    long long bestCost = calcCost(route, sumLen, orders);\n    int n = route.size();\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int i = 0; i < n - 1; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                reverse(route.begin() + i, route.begin() + j + 1);\n                long long newCost = calcCost(route, sumLen, orders);\n                if (newCost < bestCost) {\n                    bestCost = newCost;\n                    improved = true;\n                } else {\n                    reverse(route.begin() + i, route.begin() + j + 1);\n                }\n            }\n        }\n    }\n    return bestCost;\n}\n\nstruct XorShift {\n    uint64_t state;\n    XorShift(uint64_t seed = 88172645463393265ULL) {\n        if (seed == 0) seed = 88172645463393265ULL;\n        state = seed;\n    }\n    inline uint64_t nextU64() {\n        state ^= state << 7;\n        state ^= state >> 9;\n        return state;\n    }\n    inline int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N_ORDERS = 1000;\n    const int K = 50;\n\n    vector<Order> orders(N_ORDERS);\n    for (int i = 0; i < N_ORDERS; ++i) {\n        int a, b, c, d;\n        if (!(cin >> a >> b >> c >> d)) return 0;\n        orders[i].ax = a;\n        orders[i].ay = b;\n        orders[i].cx = c;\n        orders[i].cy = d;\n        orders[i].len = manhattan(a, b, c, d);\n        orders[i].base = manhattan(OFFICE, OFFICE, a, b) + orders[i].len + manhattan(c, d, OFFICE, OFFICE);\n    }\n\n    vector<int> orderIdx(N_ORDERS);\n    iota(orderIdx.begin(), orderIdx.end(), 0);\n    sort(orderIdx.begin(), orderIdx.end(), [&](int lhs, int rhs) {\n        if (orders[lhs].base != orders[rhs].base) return orders[lhs].base < orders[rhs].base;\n        return lhs < rhs;\n    });\n\n    vector<int> selectedList(orderIdx.begin(), orderIdx.begin() + K);\n    vector<char> selected(N_ORDERS, 0);\n    for (int id : selectedList) selected[id] = 1;\n\n    long long currSumLen = 0;\n    for (int id : selectedList) currSumLen += orders[id].len;\n\n    vector<int> route = buildInitialRoute(selectedList, orders);\n    long long currCost = calcCost(route, currSumLen, orders);\n    currCost = twoOptImprove(route, currSumLen, orders);\n\n    vector<int> bestRoute = route;\n    long long bestCost = currCost;\n    long long bestSumLen = currSumLen;\n\n    int topSize = min(200, N_ORDERS);\n    vector<int> topCandidates(orderIdx.begin(), orderIdx.begin() + topSize);\n\n    uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n    XorShift rng(seed);\n\n    const double TIME_LIMIT = 1.85;\n    const double START_TEMP = 2000.0;\n    const double END_TEMP = 5.0;\n    const double LOG_RATIO = log(END_TEMP / START_TEMP);\n\n    auto saStart = chrono::steady_clock::now();\n    double temp = START_TEMP;\n    double elapsed = 0.0;\n    long long iteration = 0;\n    const int N = route.size();\n\n    if (N > 0) {\n        while (true) {\n            if ((iteration & 63LL) == 0) {\n                auto now = chrono::steady_clock::now();\n                elapsed = chrono::duration<double>(now - saStart).count();\n                if (elapsed > TIME_LIMIT) break;\n                double progress = min(1.0, elapsed / TIME_LIMIT);\n                temp = START_TEMP * exp(LOG_RATIO * progress);\n            }\n            ++iteration;\n\n            int op = rng.nextInt(100);\n            if (op < 45) {\n                int i = rng.nextInt(N);\n                int j = rng.nextInt(N - 1);\n                if (j >= i) ++j;\n                swap(route[i], route[j]);\n                long long newCost = calcCost(route, currSumLen, orders);\n                bool accept = false;\n                if (newCost < currCost) {\n                    accept = true;\n                } else {\n                    double prob = exp((double)(currCost - newCost) / temp);\n                    if (prob > rng.nextDouble()) accept = true;\n                }\n                if (accept) {\n                    currCost = newCost;\n                    if (currCost < bestCost) {\n                        bestCost = currCost;\n                        bestRoute = route;\n                        bestSumLen = currSumLen;\n                    }\n                } else {\n                    swap(route[i], route[j]);\n                }\n            } else if (op < 85) {\n                int l = rng.nextInt(N);\n                int r = rng.nextInt(N);\n                if (l == r) continue;\n                if (l > r) swap(l, r);\n                reverse(route.begin() + l, route.begin() + r + 1);\n                long long newCost = calcCost(route, currSumLen, orders);\n                bool accept = false;\n                if (newCost < currCost) {\n                    accept = true;\n                } else {\n                    double prob = exp((double)(currCost - newCost) / temp);\n                    if (prob > rng.nextDouble()) accept = true;\n                }\n                if (accept) {\n                    currCost = newCost;\n                    if (currCost < bestCost) {\n                        bestCost = currCost;\n                        bestRoute = route;\n                        bestSumLen = currSumLen;\n                    }\n                } else {\n                    reverse(route.begin() + l, route.begin() + r + 1);\n                }\n            } else {\n                int pos = rng.nextInt(N);\n                int oldIdx = route[pos];\n                int newIdx = -1;\n                if (!topCandidates.empty() && rng.nextDouble() < 0.7) {\n                    for (int attempt = 0; attempt < 7; ++attempt) {\n                        int cand = topCandidates[rng.nextInt((int)topCandidates.size())];\n                        if (!selected[cand]) {\n                            newIdx = cand;\n                            break;\n                        }\n                    }\n                }\n                if (newIdx == -1) {\n                    do {\n                        newIdx = rng.nextInt(N_ORDERS);\n                    } while (selected[newIdx]);\n                }\n                route[pos] = newIdx;\n                selected[oldIdx] = 0;\n                selected[newIdx] = 1;\n                long long deltaLen = (long long)orders[newIdx].len - orders[oldIdx].len;\n                currSumLen += deltaLen;\n                long long newCost = calcCost(route, currSumLen, orders);\n                bool accept = false;\n                if (newCost < currCost) {\n                    accept = true;\n                } else {\n                    double prob = exp((double)(currCost - newCost) / temp);\n                    if (prob > rng.nextDouble()) accept = true;\n                }\n                if (accept) {\n                    currCost = newCost;\n                    if (currCost < bestCost) {\n                        bestCost = currCost;\n                        bestRoute = route;\n                        bestSumLen = currSumLen;\n                    }\n                } else {\n                    currSumLen -= deltaLen;\n                    route[pos] = oldIdx;\n                    selected[oldIdx] = 1;\n                    selected[newIdx] = 0;\n                }\n            }\n        }\n    }\n\n    bestSumLen = 0;\n    for (int idx : bestRoute) bestSumLen += orders[idx].len;\n    bestCost = twoOptImprove(bestRoute, bestSumLen, orders);\n    bestCost = calcCost(bestRoute, bestSumLen, orders);  // final verification if needed\n\n    vector<pair<int, int>> path;\n    path.reserve(bestRoute.size() * 2 + 2);\n    path.emplace_back(OFFICE, OFFICE);\n    for (int idx : bestRoute) {\n        path.emplace_back(orders[idx].ax, orders[idx].ay);\n        path.emplace_back(orders[idx].cx, orders[idx].cy);\n    }\n    path.emplace_back(OFFICE, OFFICE);\n\n    int m = bestRoute.size();\n    cout << m;\n    for (int idx : bestRoute) cout << ' ' << (idx + 1);\n    cout << '\\n';\n    cout << path.size();\n    for (auto [x, y] : path) {\n        cout << ' ' << x << ' ' << y;\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 400;\nconstexpr int M = 1995;\n\nstruct Edge {\n    int u, v;\n    int d;\n    bool in_ref = false;\n};\n\nstruct DSU {\n    vector<int> parent;\n    vector<int> sz;\n    int comp;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        parent.resize(n);\n        sz.assign(n, 1);\n        iota(parent.begin(), parent.end(), 0);\n        comp = n;\n    }\n    int find(int x) {\n        if (parent[x] == x) return x;\n        return parent[x] = find(parent[x]);\n    }\n    int root_size(int r) const { return sz[r]; }\n    int merge_roots(int a, int b, int &loser) {\n        a = find(a);\n        b = find(b);\n        if (a == b) {\n            loser = -1;\n            return a;\n        }\n        if (sz[a] < sz[b]) swap(a, b);\n        parent[b] = a;\n        sz[a] += sz[b];\n        sz[b] = 0;\n        comp--;\n        loser = b;\n        return a;\n    }\n};\n\nint rounded_distance(const pair<int,int>& A, const pair<int,int>& B) {\n    long long dx = (long long)A.first - B.first;\n    long long dy = (long long)A.second - B.second;\n    double dist = std::sqrt((double)dx * dx + (double)dy * dy);\n    return (int)std::llround(dist);\n}\n\ninline void remove_future_edge(int ru, int rv, vector<vector<int>>& adj, vector<int>& out_deg) {\n    if (ru == rv) return;\n    --adj[ru][rv];\n    --adj[rv][ru];\n    --out_deg[ru];\n    --out_deg[rv];\n    if (adj[ru][rv] < 0) adj[ru][rv] = 0;\n    if (adj[rv][ru] < 0) adj[rv][ru] = 0;\n    if (out_deg[ru] < 0) out_deg[ru] = 0;\n    if (out_deg[rv] < 0) out_deg[rv] = 0;\n}\n\nvoid merge_adj(int keep, int lose, vector<vector<int>>& adj, vector<int>& out_deg) {\n    if (lose < 0 || keep == lose) return;\n    int between = adj[keep][lose];\n    adj[keep][lose] = adj[lose][keep] = 0;\n    out_deg[keep] = out_deg[keep] + out_deg[lose] - 2 * between;\n    if (out_deg[keep] < 0) out_deg[keep] = 0;\n    out_deg[lose] = 0;\n    for (int c = 0; c < N; ++c) {\n        if (c == keep || c == lose) continue;\n        int add = adj[lose][c];\n        if (add == 0) continue;\n        adj[keep][c] += add;\n        adj[c][keep] = adj[keep][c];\n    }\n    fill(adj[lose].begin(), adj[lose].end(), 0);\n    for (int c = 0; c < N; ++c) adj[c][lose] = 0;\n    adj[keep][keep] = 0;\n}\n\ndouble compute_threshold(double progress, double comp_frac, const Edge &edge,\n                         int sizeA, int sizeB, int outA, int outB) {\n    constexpr double BASE_START = 1.17;\n    constexpr double BASE_END = 1.87;\n    constexpr double BASE_POWER = 0.65;\n    constexpr double COMP_COEFF = 0.22;\n    constexpr double COMP_POWER = 0.8;\n    constexpr double LAG_COEFF = 0.35;\n    constexpr double LEAD_COEFF = 0.12;\n    constexpr double REF_BONUS = 0.18;\n    constexpr double SMALLD_LIMIT = 120.0;\n    constexpr double SMALLD_COEFF = 0.22;\n    constexpr double SIZE_COEFF = 0.27;\n    constexpr double SIZE_POWER = 0.65;\n    constexpr double DENSITY_TARGET = 1.6;\n    constexpr double DENSITY_COEFF = 0.45;\n    constexpr double OUT_TARGET = 10.0;\n    constexpr double OUT_COEFF = 0.38;\n    constexpr double LARGE_LIMIT = 250.0;\n    constexpr double LARGE_SPAN = 350.0;\n    constexpr double LARGE_COEFF = 0.08;\n    constexpr double MIN_THRESHOLD = 1.05;\n    constexpr double MAX_THRESHOLD = 2.35;\n\n    progress = std::clamp(progress, 0.0, 1.0);\n    comp_frac = std::clamp(comp_frac, 0.0, 1.0);\n\n    double base = BASE_START + (BASE_END - BASE_START) * std::pow(progress, BASE_POWER);\n    base += COMP_COEFF * std::pow(comp_frac, COMP_POWER);\n    double lag = std::clamp(progress - comp_frac, 0.0, 1.0);\n    double lead = std::clamp(comp_frac - progress, 0.0, 1.0);\n    base += LAG_COEFF * lag;\n    base -= LEAD_COEFF * lead;\n\n    double thr = base;\n    if (edge.in_ref) thr += REF_BONUS;\n\n    double size_frac = double(sizeA + sizeB) / double(N);\n    size_frac = std::clamp(size_frac, 0.0, 1.0);\n    thr += SIZE_COEFF * std::pow(size_frac, SIZE_POWER);\n\n    double dist_factor = std::clamp((SMALLD_LIMIT - double(edge.d)) / SMALLD_LIMIT, 0.0, 1.0);\n    thr += SMALLD_COEFF * dist_factor;\n\n    double densityA = (sizeA > 0) ? double(outA) / double(sizeA) : 0.0;\n    double densityB = (sizeB > 0) ? double(outB) / double(sizeB) : 0.0;\n    double density = std::min(densityA, densityB);\n    double risk = std::clamp((DENSITY_TARGET - density) / DENSITY_TARGET, 0.0, 1.0);\n    thr += DENSITY_COEFF * risk;\n\n    int min_out = std::min(outA, outB);\n    double out_factor = std::clamp((OUT_TARGET - double(min_out)) / OUT_TARGET, 0.0, 1.0);\n    thr += OUT_COEFF * out_factor;\n\n    double large_factor = std::clamp((double(edge.d) - LARGE_LIMIT) / LARGE_SPAN, 0.0, 1.0);\n    thr -= LARGE_COEFF * large_factor;\n\n    return std::clamp(thr, MIN_THRESHOLD, MAX_THRESHOLD);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<pair<int,int>> pos(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> pos[i].first >> pos[i].second;\n    }\n\n    vector<Edge> edges(M);\n    vector<vector<int>> adj(N, vector<int>(N, 0));\n    vector<int> out_deg(N, 0);\n\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        edges[i].d = rounded_distance(pos[u], pos[v]);\n        adj[u][v] += 1;\n        adj[v][u] += 1;\n        out_deg[u] += 1;\n        out_deg[v] += 1;\n    }\n\n    // Reference MST with distances d_i\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.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 ref_dsu(N);\n    int need = N - 1;\n    for (int idx : order) {\n        int loser;\n        ref_dsu.merge_roots(edges[idx].u, edges[idx].v, loser);\n        if (loser != -1) {\n            edges[idx].in_ref = true;\n            if (--need == 0) break;\n        }\n    }\n\n    DSU dsu(N);\n    std::mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n    std::uniform_real_distribution<double> noise_dist(-0.02, 0.02);\n    constexpr double FINAL_MIN = 1.02;\n    constexpr double FINAL_MAX = 2.40;\n\n    for (int i = 0; i < M; ++i) {\n        int len;\n        if (!(cin >> len)) return 0;\n        Edge &edge = edges[i];\n        int ru = dsu.find(edge.u);\n        int rv = dsu.find(edge.v);\n\n        if (ru == rv) {\n            cout << 0 << '\\n' << flush;\n            continue;\n        }\n\n        remove_future_edge(ru, rv, adj, out_deg);\n\n        bool accept = false;\n        if (out_deg[ru] == 0 || out_deg[rv] == 0) {\n            accept = true;\n        } else {\n            int sizeA = dsu.root_size(ru);\n            int sizeB = dsu.root_size(rv);\n            int outA = out_deg[ru];\n            int outB = out_deg[rv];\n            double progress = double(i) / double(M);\n            double comp_frac = double(N - dsu.comp) / double(N - 1);\n            double threshold = compute_threshold(progress, comp_frac, edge, sizeA, sizeB, outA, outB);\n            threshold += noise_dist(rng);\n            threshold = std::clamp(threshold, FINAL_MIN, FINAL_MAX);\n            double denom = edge.d > 0 ? double(edge.d) : 1.0;\n            double ratio = double(len) / denom;\n            if (ratio <= threshold) accept = true;\n        }\n\n        if (accept) {\n            cout << 1 << '\\n' << flush;\n            int loser;\n            int keep = dsu.merge_roots(ru, rv, loser);\n            merge_adj(keep, loser, adj, out_deg);\n        } else {\n            cout << 0 << '\\n' << flush;\n        }\n    }\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int x, y;\n};\n\nstruct Candidate {\n    Point pos;\n    vector<int> block_dirs;\n};\n\nconst int H = 30;\nconst int W = 30;\nconst int DX[4] = {-1, 1, 0, 0}; // U, D, L, R\nconst int DY[4] = {0, 0, -1, 1};\nconst char MOVE_CH[4] = {'U', 'D', 'L', 'R'};\nconst char BLOCK_CH[4] = {'u', 'd', 'l', 'r'};\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < H && 0 <= y && y < W;\n}\n\nvector<int> hungarian(const vector<vector<int>>& a) {\n    int n = (int)a.size();\n    int m = (int)a[0].size();\n    assert(n <= m);\n    const int INF = 1e9;\n    vector<int> u(n + 1), v(m + 1), p(m + 1), way(m + 1);\n    for (int i = 1; i <= n; ++i) {\n        p[0] = i;\n        vector<int> minv(m + 1, INF);\n        vector<char> used(m + 1, false);\n        int j0 = 0;\n        do {\n            used[j0] = true;\n            int i0 = p[j0], delta = INF, j1 = 0;\n            for (int j = 1; j <= m; ++j) if (!used[j]) {\n                int cur = a[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= m; ++j) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    v[j] -= delta;\n                } else {\n                    minv[j] -= delta;\n                }\n            }\n            j0 = j1;\n        } while (p[j0] != 0);\n        do {\n            int j1 = way[j0];\n            p[j0] = p[j1];\n            j0 = j1;\n        } while (j0);\n    }\n    vector<int> ans(n, -1);\n    for (int j = 1; j <= m; ++j) if (p[j]) {\n        ans[p[j] - 1] = j - 1;\n    }\n    return ans;\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<Point> pets(N);\n    vector<int> pet_type(N);\n    for (int i = 0; i < N; ++i) {\n        int px, py, pt;\n        cin >> px >> py >> pt;\n        --px; --py;\n        pets[i] = {px, py};\n        pet_type[i] = pt;\n    }\n    int M;\n    cin >> M;\n    vector<Point> humans(M);\n    for (int i = 0; i < M; ++i) {\n        int hx, hy;\n        cin >> hx >> hy;\n        --hx; --hy;\n        humans[i] = {hx, hy};\n    }\n\n    vector<vector<int>> pet_count(H, vector<int>(W, 0));\n    for (auto &p : pets) {\n        if (inside(p.x, p.y)) pet_count[p.x][p.y]++;\n    }\n\n    // Prepare candidate slots (top & bottom rows, spaced every 4 columns).\n    vector<int> cols;\n    for (int y = 1; y < 29; y += 4) cols.push_back(y);\n    vector<Candidate> candidates;\n    for (int y : cols) {\n        Candidate top;\n        top.pos = {0, y};\n        top.block_dirs = {2, 3, 1}; // L, R, Down\n        candidates.push_back(top);\n    }\n    for (int y : cols) {\n        Candidate bottom;\n        bottom.pos = {H - 1, y};\n        bottom.block_dirs = {2, 3, 0}; // L, R, Up\n        candidates.push_back(bottom);\n    }\n    int C = candidates.size();\n    assert(C >= M);\n\n    vector<vector<int>> cost(M, vector<int>(C));\n    for (int i = 0; i < M; ++i) {\n        for (int j = 0; j < C; ++j) {\n            cost[i][j] = abs(humans[i].x - candidates[j].pos.x)\n                       + abs(humans[i].y - candidates[j].pos.y);\n        }\n    }\n    vector<int> assign = hungarian(cost);\n\n    vector<Point> targets(M);\n    vector<vector<int>> block_plans(M);\n    for (int i = 0; i < M; ++i) {\n        targets[i] = candidates[assign[i]].pos;\n        block_plans[i] = candidates[assign[i]].block_dirs;\n    }\n\n    vector<vector<int>> blocked(H, vector<int>(W, 0));\n    bool block_phase = false;\n\n    auto char_to_dir = [&](char c) -> int {\n        if (c == 'U' || c == 'u') return 0;\n        if (c == 'D' || c == 'd') return 1;\n        if (c == 'L' || c == 'l') return 2;\n        if (c == 'R' || c == 'r') return 3;\n        return -1;\n    };\n\n    for (int turn = 0; turn < 300; ++turn) {\n        bool all_at_target = true;\n        for (int i = 0; i < M; ++i) {\n            if (humans[i].x != targets[i].x || humans[i].y != targets[i].y) {\n                all_at_target = false;\n                break;\n            }\n        }\n        if (!block_phase && all_at_target) block_phase = true;\n\n        vector<Point> start_pos = humans;\n        string actions(M, '.');\n\n        for (int i = 0; i < M; ++i) {\n            char act = '.';\n            const auto &pos = start_pos[i];\n            const auto &target = targets[i];\n            if (pos.x != target.x || pos.y != target.y) {\n                if (pos.x < target.x) act = MOVE_CH[1];\n                else if (pos.x > target.x) act = MOVE_CH[0];\n                else if (pos.y < target.y) act = MOVE_CH[3];\n                else if (pos.y > target.y) act = MOVE_CH[2];\n            } else if (block_phase) {\n                for (int dir : block_plans[i]) {\n                    int nx = pos.x + DX[dir];\n                    int ny = pos.y + DY[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (blocked[nx][ny]) continue;\n                    if (pet_count[nx][ny] > 0) continue;\n                    bool adj_pet = false;\n                    for (int d = 0; d < 4; ++d) {\n                        int ax = nx + DX[d];\n                        int ay = ny + DY[d];\n                        if (inside(ax, ay) && pet_count[ax][ay] > 0) {\n                            adj_pet = true;\n                            break;\n                        }\n                    }\n                    if (adj_pet) continue;\n                    bool human_there = false;\n                    for (int j = 0; j < M; ++j) {\n                        if (start_pos[j].x == nx && start_pos[j].y == ny) {\n                            human_there = true;\n                            break;\n                        }\n                    }\n                    if (human_there) continue;\n                    act = BLOCK_CH[dir];\n                    break;\n                }\n            }\n            actions[i] = act;\n        }\n\n        cout << actions << endl;\n\n        // Apply actions\n        for (int i = 0; i < M; ++i) {\n            char act = actions[i];\n            humans[i] = start_pos[i];\n            int dir = char_to_dir(act);\n            if (act == '.' || dir == -1) continue;\n            if ('A' <= act && act <= 'Z') {\n                humans[i].x += DX[dir];\n                humans[i].y += DY[dir];\n            } else {\n                int nx = humans[i].x + DX[dir];\n                int ny = humans[i].y + DY[dir];\n                if (inside(nx, ny)) blocked[nx][ny] = 1;\n            }\n        }\n\n        // Read pet movements and update positions\n        for (int i = 0; i < N; ++i) {\n            string s;\n            if (!(cin >> s)) return 0;\n            Point &p = pets[i];\n            for (char c : s) {\n                int dir = char_to_dir(c);\n                if (dir == -1) continue;\n                p.x += DX[dir];\n                p.y += DY[dir];\n            }\n        }\n        for (int x = 0; x < H; ++x) {\n            fill(pet_count[x].begin(), pet_count[x].end(), 0);\n        }\n        for (const auto &p : pets) {\n            if (inside(p.x, p.y)) pet_count[p.x][p.y]++;\n        }\n    }\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int H = 20;\nconstexpr int W = 20;\nconstexpr int N = H * W;\nconstexpr int MAX_L = 200;\nconst char DIR_CHARS[4] = {'U', 'D', 'L', 'R'};\nconstexpr double TIME_LIMIT = 1.95;\nconstexpr double IMPROVE_EPS = 1e-9;\n\nstruct BeamParam {\n    double weight;\n    double noise;\n    int width;\n};\n\nstruct StepResult {\n    double score;\n    double reachProb;\n};\n\ninline StepResult apply_transition_raw(const double* from, double* to, int dir, int step,\n                                       double forgetProb, double moveProb,\n                                       const array<array<int, N>, 4>& neighbor,\n                                       int targetIdx) {\n    StepResult res{0.0, 0.0};\n    fill(to, to + N, 0.0);\n    const double rewardFactor = 401.0 - (step + 1);\n    for (int idx = 0; idx < N; ++idx) {\n        double prob = from[idx];\n        if (prob <= 1e-15) continue;\n        double stayProb = prob * forgetProb;\n        int nxt = neighbor[dir][idx];\n        double move = prob * moveProb;\n        if (nxt == idx) {\n            stayProb += move;\n        } else if (nxt == targetIdx) {\n            res.score += rewardFactor * move;\n            res.reachProb += move;\n        } else {\n            to[nxt] += move;\n        }\n        to[idx] += stayProb;\n    }\n    return res;\n}\n\ninline double expected_distance_raw(const double* dist, const double* distTarget) {\n    double sum = 0.0;\n    for (int idx = 0; idx < N; ++idx) sum += dist[idx] * distTarget[idx];\n    return sum;\n}\n\nvector<int> compute_distances(const array<array<int, N>, 4>& neighbor, int targetIdx) {\n    const int INF = 1e9;\n    vector<int> dist(N, INF);\n    queue<int> q;\n    dist[targetIdx] = 0;\n    q.push(targetIdx);\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        for (int dir = 0; dir < 4; ++dir) {\n            int v = neighbor[dir][u];\n            if (v == u) continue;\n            if (dist[v] > dist[u] + 1) {\n                dist[v] = dist[u] + 1;\n                q.push(v);\n            }\n        }\n    }\n    return dist;\n}\n\nstruct BeamResult {\n    vector<int> seq;\n    double score;\n};\n\nBeamResult run_beam(const BeamParam& param,\n                    const array<array<int, N>, 4>& neighbor,\n                    const vector<double>& distTarget,\n                    int startIdx, int targetIdx,\n                    double forgetProb,\n                    mt19937& rng) {\n    const double moveProb = 1.0 - forgetProb;\n    struct Candidate {\n        array<double, N> dist;\n        double score;\n        double heuristic;\n        array<uint8_t, MAX_L> path;\n        int len;\n    };\n\n    const double* distPtr = distTarget.data();\n    vector<Candidate> beam;\n    beam.reserve(param.width);\n    vector<Candidate> next;\n    next.reserve(param.width * 4);\n\n    Candidate init;\n    init.dist.fill(0.0);\n    init.dist[startIdx] = 1.0;\n    init.score = 0.0;\n    init.len = 0;\n    init.heuristic = -param.weight * distPtr[startIdx];\n    beam.push_back(init);\n\n    uniform_real_distribution<double> noiseDist(-param.noise, param.noise);\n    auto cmp = [](const Candidate& a, const Candidate& b) {\n        return a.heuristic > b.heuristic;\n    };\n\n    for (int step = 0; step < MAX_L; ++step) {\n        next.clear();\n        for (const Candidate& cand : beam) {\n            for (int dir = 0; dir < 4; ++dir) {\n                Candidate child;\n                if (cand.len > 0) {\n                    copy_n(cand.path.begin(), cand.len, child.path.begin());\n                }\n                child.len = cand.len + 1;\n                child.path[cand.len] = static_cast<uint8_t>(dir);\n                StepResult sr = apply_transition_raw(cand.dist.data(), child.dist.data(),\n                                                     dir, step, forgetProb, moveProb,\n                                                     neighbor, targetIdx);\n                child.score = cand.score + sr.score;\n                double expDist = expected_distance_raw(child.dist.data(), distPtr);\n                double noise = (param.noise > 0) ? noiseDist(rng) : 0.0;\n                child.heuristic = child.score - param.weight * expDist + noise;\n                next.push_back(std::move(child));\n            }\n        }\n        if (next.empty()) break;\n        if ((int)next.size() > param.width) {\n            partial_sort(next.begin(), next.begin() + param.width, next.end(), cmp);\n            next.resize(param.width);\n        } else {\n            sort(next.begin(), next.end(), cmp);\n        }\n        beam.swap(next);\n    }\n\n    Candidate best = beam[0];\n    for (const Candidate& cand : beam) if (cand.score > best.score) best = cand;\n    vector<int> seq(MAX_L);\n    for (int i = 0; i < MAX_L; ++i) seq[i] = best.path[i];\n    return {seq, best.score};\n}\n\nstruct Evaluator {\n    const array<array<int, N>, 4>& neighbor;\n    int startIdx;\n    int targetIdx;\n    double forgetProb;\n    double moveProb;\n    vector<double> cur, nxt;\n    Evaluator(const array<array<int, N>, 4>& neighbor_, int s, int t, double p)\n        : neighbor(neighbor_), startIdx(s), targetIdx(t), forgetProb(p), moveProb(1.0 - p),\n          cur(N, 0.0), nxt(N, 0.0) {}\n\n    double evaluate(const vector<int>& seq) {\n        fill(cur.begin(), cur.end(), 0.0);\n        cur[startIdx] = 1.0;\n        double total = 0.0;\n        double mass = 1.0;\n        for (int step = 0; step < (int)seq.size(); ++step) {\n            StepResult sr = apply_transition_raw(cur.data(), nxt.data(), seq[step], step,\n                                                 forgetProb, moveProb, neighbor, targetIdx);\n            total += sr.score;\n            cur.swap(nxt);\n            mass -= sr.reachProb;\n            if (mass < 0) mass = 0;\n            if (mass <= 1e-12) break;\n        }\n        return total;\n    }\n};\n\nvector<int> build_fallback() {\n    vector<int> seq(MAX_L);\n    for (int i = 0; i < MAX_L; ++i) {\n        int mod = i % 4;\n        if (mod < 3) seq[i] = 1; else seq[i] = 3; // more Down than Right\n    }\n    return seq;\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    cin >> si >> sj >> ti >> tj >> p;\n    vector<string> h(H), v(H - 1);\n    for (int i = 0; i < H; ++i) cin >> h[i];\n    for (int i = 0; i < H - 1; ++i) cin >> v[i];\n\n    array<array<int, N>, 4> neighbor;\n    auto idx = [&](int r, int c) { return r * W + c; };\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int id = idx(i, j);\n            // Up\n            if (i > 0 && v[i - 1][j] == '0') neighbor[0][id] = idx(i - 1, j);\n            else neighbor[0][id] = id;\n            // Down\n            if (i < H - 1 && v[i][j] == '0') neighbor[1][id] = idx(i + 1, j);\n            else neighbor[1][id] = id;\n            // Left\n            if (j > 0 && h[i][j - 1] == '0') neighbor[2][id] = idx(i, j - 1);\n            else neighbor[2][id] = id;\n            // Right\n            if (j < W - 1 && h[i][j] == '0') neighbor[3][id] = idx(i, j + 1);\n            else neighbor[3][id] = id;\n        }\n    }\n\n    int startIdx = idx(si, sj);\n    int targetIdx = idx(ti, tj);\n\n    vector<int> distInt = compute_distances(neighbor, targetIdx);\n    vector<double> distTarget(N);\n    for (int i = 0; i < N; ++i) distTarget[i] = (double)distInt[i];\n\n    mt19937 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n\n    vector<BeamParam> params;\n    double factor = 0.8 + 0.8 * p;\n    params.push_back({0.8 * factor, 2e-4, 10});\n    params.push_back({1.1 * factor, 1e-4, 12});\n    params.push_back({1.5 * factor, 5e-5, 12});\n    params.push_back({2.1 * factor, 2e-5, 14});\n    params.push_back({2.8 * factor, 1e-5, 16});\n\n    vector<vector<int>> candidates;\n    candidates.reserve(params.size() + 1);\n\n    double beamTimeLimit = min(1.0, TIME_LIMIT * 0.6);\n    for (size_t i = 0; i < params.size(); ++i) {\n        BeamResult res = run_beam(params[i], neighbor, distTarget, startIdx, targetIdx, p, rng);\n        candidates.push_back(std::move(res.seq));\n        if (elapsed() > beamTimeLimit) break;\n    }\n    if (candidates.empty()) candidates.push_back(build_fallback());\n\n    Evaluator evaluator(neighbor, startIdx, targetIdx, p);\n\n    double bestScore = -1.0;\n    vector<int> bestSeq;\n    for (const auto& seq : candidates) {\n        double sc = evaluator.evaluate(seq);\n        if (sc > bestScore + IMPROVE_EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n    }\n    if (bestSeq.empty()) bestSeq = build_fallback(), bestScore = evaluator.evaluate(bestSeq);\n\n    // Coordinate descent\n    double cdTimeLimit = TIME_LIMIT * 0.9;\n    bool improved = true;\n    int passes = 0;\n    while (improved && elapsed() < cdTimeLimit && passes < 2) {\n        improved = false;\n        ++passes;\n        for (int pos = 0; pos < MAX_L; ++pos) {\n            if (elapsed() > cdTimeLimit) break;\n            int orig = bestSeq[pos];\n            double localBest = bestScore;\n            int bestDir = orig;\n            for (int dir = 0; dir < 4; ++dir) {\n                if (dir == orig) continue;\n                bestSeq[pos] = dir;\n                double candScore = evaluator.evaluate(bestSeq);\n                if (candScore > localBest + IMPROVE_EPS) {\n                    localBest = candScore;\n                    bestDir = dir;\n                }\n            }\n            bestSeq[pos] = bestDir;\n            if (bestDir != orig) {\n                bestScore = localBest;\n                improved = true;\n            }\n        }\n    }\n\n    // Random hill climbing\n    double randomTimeLimit = TIME_LIMIT * 0.98;\n    uniform_int_distribution<int> posDist(0, MAX_L - 1);\n    uniform_int_distribution<int> dirDist(0, 3);\n    int randomTrials = 200;\n    for (int iter = 0; iter < randomTrials && elapsed() < randomTimeLimit; ++iter) {\n        int pos = posDist(rng);\n        int newDir = dirDist(rng);\n        if (newDir == bestSeq[pos]) continue;\n        int oldDir = bestSeq[pos];\n        bestSeq[pos] = newDir;\n        double candScore = evaluator.evaluate(bestSeq);\n        if (candScore > bestScore + IMPROVE_EPS) {\n            bestScore = candScore;\n        } else {\n            bestSeq[pos] = oldDir;\n        }\n    }\n\n    string answer;\n    answer.reserve(MAX_L);\n    for (int dir : bestSeq) answer.push_back(DIR_CHARS[dir]);\n    cout << answer << '\\n';\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int H = 30;\nconstexpr int W = 30;\nconstexpr int DIR = 4;\nconstexpr int N = H * W;\nconstexpr int STATE = N * DIR;\n\nconstexpr int di[4] = {0, -1, 0, 1};   // left, up, right, down\nconstexpr int dj[4] = {-1, 0, 1, 0};\n\nconstexpr 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\nconstexpr int ROT_NEXT[8] = {1, 2, 3, 0, 5, 4, 7, 6};\nint ROT_TABLE[8][4];\n\nstruct EvalResult {\n    long long score;\n    int l1;\n    int l2;\n    int loopCount;\n};\n\nstruct Evaluator {\n    array<int, STATE> visitedStamp{};\n    array<int, STATE> pathStamp{};\n    array<int, STATE> pathPos{};\n    int visitedToken = 0;\n    int pathToken = 0;\n    vector<int> pathList;\n\n    Evaluator() { pathList.reserve(STATE); }\n\n    EvalResult operator()(const vector<int>& finalType) {\n        ++visitedToken;\n        int visitedTok = visitedToken;\n        const int* typePtr = finalType.data();\n\n        // mark directions without tracks\n        for (int cell = 0; cell < N; ++cell) {\n            int type = typePtr[cell];\n            int baseIdx = cell << 2;\n            const int* row = TO[type];\n            for (int d = 0; d < DIR; ++d) {\n                if (row[d] == -1) {\n                    visitedStamp[baseIdx + d] = visitedTok;\n                }\n            }\n        }\n\n        long long best1 = 0, best2 = 0;\n        int loops = 0;\n\n        for (int cell = 0; cell < N; ++cell) {\n            int baseIdx = cell << 2;\n            for (int d = 0; d < DIR; ++d) {\n                int idx = baseIdx + d;\n                if (visitedStamp[idx] == visitedTok) continue;\n\n                ++pathToken;\n                int pathTok = pathToken;\n                pathList.clear();\n\n                int i = cell / W;\n                int j = cell - i * W;\n                int curCell = cell;\n                int curDir = d;\n                int len = 0;\n\n                while (true) {\n                    int stateIdx = (curCell << 2) | curDir;\n                    if (visitedStamp[stateIdx] == visitedTok) {\n                        break;\n                    }\n                    if (pathStamp[stateIdx] == pathTok) {\n                        int loopLen = len - pathPos[stateIdx];\n                        if (loopLen > 0) {\n                            ++loops;\n                            if (loopLen >= best1) {\n                                best2 = best1;\n                                best1 = loopLen;\n                            } else if (loopLen > best2) {\n                                best2 = loopLen;\n                            }\n                        }\n                        break;\n                    }\n                    pathStamp[stateIdx] = pathTok;\n                    pathPos[stateIdx] = len;\n                    pathList.push_back(stateIdx);\n\n                    int type = typePtr[curCell];\n                    int nextDir = TO[type][curDir];\n                    if (nextDir == -1) break;\n\n                    int ni = i + di[nextDir];\n                    int nj = j + dj[nextDir];\n                    if (ni < 0 || ni >= H || nj < 0 || nj >= W) break;\n\n                    i = ni;\n                    j = nj;\n                    curCell = ni * W + nj;\n                    curDir = (nextDir + 2) & 3;\n                    ++len;\n                }\n\n                for (int s : pathList) {\n                    visitedStamp[s] = visitedTok;\n                }\n            }\n        }\n\n        long long score = (loops >= 2) ? best1 * best2 : 0LL;\n        return {score, (int)best1, (int)best2, loops};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> base(N);\n    for (int i = 0; i < H; ++i) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < W; ++j) {\n            base[i * W + j] = s[j] - '0';\n        }\n    }\n\n    for (int t = 0; t < 8; ++t) {\n        ROT_TABLE[t][0] = t;\n        for (int r = 1; r < 4; ++r) {\n            ROT_TABLE[t][r] = ROT_NEXT[ROT_TABLE[t][r - 1]];\n        }\n    }\n\n    auto start = chrono::steady_clock::now();\n    auto getTime = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    vector<int> rot(N, 0);\n    vector<int> finalType(N);\n\n    // boundary-friendly initial orientation\n    for (int cell = 0; cell < N; ++cell) {\n        int i = cell / W;\n        int j = cell - i * W;\n        int bestR = 0;\n        int bestVal = -1;\n        for (int r = 0; r < 4; ++r) {\n            int type = ROT_TABLE[base[cell]][r];\n            const int* row = TO[type];\n            int val = 0;\n            for (int d = 0; d < DIR; ++d) {\n                if (row[d] == -1) continue;\n                int ni = i + di[d];\n                int nj = j + dj[d];\n                if (0 <= ni && ni < H && 0 <= nj && nj < W) ++val;\n            }\n            if (val > bestVal || (val == bestVal && (rng() & 1))) {\n                bestVal = val;\n                bestR = r;\n            }\n        }\n        rot[cell] = bestR;\n        finalType[cell] = ROT_TABLE[base[cell]][bestR];\n    }\n\n    Evaluator evaluator;\n    EvalResult curEval = evaluator(finalType);\n    long long currentScore = curEval.score;\n    vector<int> bestRot = rot;\n    long long bestScore = currentScore;\n\n    const double TIME_LIMIT = 1.9;\n    const double T0 = 5.0;\n    const double T1 = 0.1;\n\n    while (true) {\n        double elapsed = getTime();\n        if (elapsed > TIME_LIMIT) break;\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        double temp = T0 + (T1 - T0) * progress;\n\n        int cell = rng() % N;\n        int oldR = rot[cell];\n        int oldType = finalType[cell];\n\n        int newR, newType;\n        while (true) {\n            int diff = rng() % 3 + 1;\n            newR = (oldR + diff) & 3;\n            newType = ROT_TABLE[base[cell]][newR];\n            if (newType != oldType) break;\n        }\n\n        rot[cell] = newR;\n        finalType[cell] = newType;\n\n        EvalResult newEval = evaluator(finalType);\n        long long newScore = newEval.score;\n        long long delta = newScore - currentScore;\n\n        bool accept = false;\n        if (delta >= 0) {\n            accept = true;\n        } else {\n            double prob = exp(delta / temp);\n            if (dist01(rng) < prob) accept = true;\n        }\n\n        if (accept) {\n            currentScore = newScore;\n            if (newScore > bestScore) {\n                bestScore = newScore;\n                bestRot = rot;\n            }\n        } else {\n            rot[cell] = oldR;\n            finalType[cell] = oldType;\n        }\n    }\n\n    rot = bestRot;\n    string answer;\n    answer.reserve(N);\n    for (int idx = 0; idx < N; ++idx) {\n        answer.push_back(char('0' + rot[idx]));\n    }\n    cout << answer << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N, T;\nvector<uint8_t> g_visited;\nvector<int> g_queue;\n\nconst int MOVE_DX[4] = {-1, 1, 0, 0};          // U, D, L, R (blank movement)\nconst int MOVE_DY[4] = {0, 0, -1, 1};\nconst char MOVE_CHAR[4] = {'U', 'D', 'L', 'R'};\nconst int MOVE_OPP[4]  = {1, 0, 3, 2};\n\nconst int CONN_DX[4] = {0, -1, 0, 1};          // L, U, R, D (edge directions)\nconst int CONN_DY[4] = {-1, 0, 1, 0};\nconst int CONN_BIT[4] = {1, 2, 4, 8};\nconst int CONN_OPP[4] = {2, 3, 0, 1};\n\nstruct EvalResult {\n    int matched_edges;\n    int largest_tree;\n    int largest_component;\n};\n\nstruct AttemptResult {\n    EvalResult eval;\n    string sequence;\n};\n\ninline void applyMove(vector<int>& board, int& blank_pos, int dir) {\n    int x = blank_pos / N;\n    int y = blank_pos % N;\n    int nx = x + MOVE_DX[dir];\n    int ny = y + MOVE_DY[dir];\n    int nidx = nx * N + ny;\n    swap(board[blank_pos], board[nidx]);\n    blank_pos = nidx;\n}\n\nEvalResult evaluateBoard(const vector<int>& board) {\n    EvalResult res{0, 0, 0};\n    int total = N * N;\n    // count matched edges (right and down to avoid duplicates)\n    for (int i = 0; i < N; ++i) {\n        int base = i * N;\n        for (int j = 0; j < N; ++j) {\n            int idx = base + j;\n            int val = board[idx];\n            if (val == 0) continue;\n            if (j + 1 < N) {\n                int nb = board[idx + 1];\n                if (nb && (val & CONN_BIT[2]) && (nb & CONN_BIT[0])) res.matched_edges++;\n            }\n            if (i + 1 < N) {\n                int nb = board[idx + N];\n                if (nb && (val & CONN_BIT[3]) && (nb & CONN_BIT[1])) res.matched_edges++;\n            }\n        }\n    }\n    fill(g_visited.begin(), g_visited.end(), 0);\n    for (int idx = 0; idx < total; ++idx) {\n        if (board[idx] == 0 || g_visited[idx]) continue;\n        int head = 0, tail = 0;\n        g_queue[tail++] = idx;\n        g_visited[idx] = 1;\n        int nodes = 0;\n        int edges_twice = 0;\n        while (head < tail) {\n            int v = g_queue[head++];\n            nodes++;\n            int vx = v / N;\n            int vy = v % N;\n            int val = board[v];\n            for (int d = 0; d < 4; ++d) {\n                if (!(val & CONN_BIT[d])) continue;\n                int nx = vx + CONN_DX[d];\n                int ny = vy + CONN_DY[d];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                int nidx = nx * N + ny;\n                int nval = board[nidx];\n                if (nval == 0) continue;\n                if (!(nval & CONN_BIT[CONN_OPP[d]])) continue;\n                edges_twice++;\n                if (!g_visited[nidx]) {\n                    g_visited[nidx] = 1;\n                    g_queue[tail++] = nidx;\n                }\n            }\n        }\n        int edges = edges_twice / 2;\n        res.largest_component = max(res.largest_component, nodes);\n        if (edges == nodes - 1) res.largest_tree = max(res.largest_tree, nodes);\n    }\n    return res;\n}\n\ninline bool evalBetter(const EvalResult& a, const EvalResult& b) {\n    if (a.largest_tree != b.largest_tree) return a.largest_tree > b.largest_tree;\n    if (a.largest_component != b.largest_component) return a.largest_component > b.largest_component;\n    if (a.matched_edges != b.matched_edges) return a.matched_edges > b.matched_edges;\n    return false;\n}\n\ninline bool evalEqual(const EvalResult& a, const EvalResult& b) {\n    return a.largest_tree == b.largest_tree &&\n           a.largest_component == b.largest_component &&\n           a.matched_edges == b.matched_edges;\n}\n\nAttemptResult runAttempt(const vector<int>& initial_board, int blank_init, int limit_steps,\n                         int total_tiles, mt19937& rng) {\n    vector<int> board = initial_board;\n    int blank = blank_init;\n    string seq;\n    seq.reserve(limit_steps);\n\n    EvalResult best_eval = evaluateBoard(board);\n    int best_prefix = 0;\n\n    if (best_eval.largest_tree == total_tiles) {\n        return {best_eval, \"\"};\n    }\n\n    vector<int> dirs;\n    dirs.reserve(4);\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n    const double base_explore = 0.35;\n\n    for (int step = 0; step < limit_steps; ++step) {\n        dirs.clear();\n        int x = blank / N;\n        int y = blank % N;\n        if (x > 0) dirs.push_back(0);\n        if (x + 1 < N) dirs.push_back(1);\n        if (y > 0) dirs.push_back(2);\n        if (y + 1 < N) dirs.push_back(3);\n        if (dirs.empty()) break;\n\n        shuffle(dirs.begin(), dirs.end(), rng);\n        double progress = (limit_steps > 1) ? static_cast<double>(step) / (limit_steps - 1) : 1.0;\n        progress = min(max(progress, 0.0), 1.0);\n        double explore_prob = base_explore * (1.0 - progress);\n        if (explore_prob < 0.0) explore_prob = 0.0;\n\n        int chosen_dir = dirs[0];\n        EvalResult chosen_eval;\n\n        if (dist01(rng) < explore_prob) {\n            int dir = dirs[rng() % dirs.size()];\n            applyMove(board, blank, dir);\n            chosen_eval = evaluateBoard(board);\n            chosen_dir = dir;\n        } else {\n            bool has_best = false;\n            EvalResult cand_eval;\n            int cand_dir = -1;\n            for (int dir : dirs) {\n                applyMove(board, blank, dir);\n                EvalResult eval = evaluateBoard(board);\n                applyMove(board, blank, MOVE_OPP[dir]);\n                if (!has_best || evalBetter(eval, cand_eval)) {\n                    cand_eval = eval;\n                    cand_dir = dir;\n                    has_best = true;\n                } else if (!evalBetter(cand_eval, eval)) {\n                    if (rng() & 1) {\n                        cand_eval = eval;\n                        cand_dir = dir;\n                    }\n                }\n            }\n            applyMove(board, blank, cand_dir);\n            chosen_eval = cand_eval;\n            chosen_dir = cand_dir;\n        }\n\n        seq.push_back(MOVE_CHAR[chosen_dir]);\n\n        if (evalBetter(chosen_eval, best_eval)) {\n            best_eval = chosen_eval;\n            best_prefix = static_cast<int>(seq.size());\n            if (best_eval.largest_tree == total_tiles) break;\n        }\n    }\n\n    string best_seq = (best_prefix == 0) ? string() : seq.substr(0, best_prefix);\n    return {best_eval, best_seq};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T;\n    vector<int> initial_board(N * N);\n    int blank_pos = -1;\n    for (int i = 0; i < N; ++i) {\n        string row;\n        cin >> row;\n        for (int j = 0; j < N; ++j) {\n            char c = row[j];\n            int val = (c <= '9') ? c - '0' : 10 + (c - 'a');\n            initial_board[i * N + j] = val;\n            if (val == 0) blank_pos = i * N + j;\n        }\n    }\n\n    g_visited.assign(N * N, 0);\n    g_queue.assign(N * N, 0);\n\n    int total_tiles = N * N - 1;\n    EvalResult best_eval = evaluateBoard(initial_board);\n    string best_sequence = \"\";\n\n    mt19937 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    const double TIME_LIMIT = 2.8;\n    auto start_time = chrono::steady_clock::now();\n    int attempts = 0;\n\n    if (best_eval.largest_tree != total_tiles) {\n        while (true) {\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - start_time).count();\n            if (attempts > 0 && elapsed > TIME_LIMIT) break;\n            AttemptResult res = runAttempt(initial_board, blank_pos, T, total_tiles, rng);\n            attempts++;\n            if (evalBetter(res.eval, best_eval)) {\n                best_eval = res.eval;\n                best_sequence = res.sequence;\n            } else if (evalEqual(res.eval, best_eval)) {\n                if (best_sequence.empty() || (!res.sequence.empty() && res.sequence.size() < best_sequence.size())) {\n                    best_sequence = res.sequence;\n                }\n            }\n            if (best_eval.largest_tree == total_tiles && best_sequence.empty()) break;\n        }\n    }\n\n    cout << best_sequence << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int x, y;\n};\nstruct Line {\n    long long A, B, C;\n};\nstruct Key {\n    unsigned long long lo, hi;\n};\nusing CountArr = array<int, 11>;\n\nconst long long COORD_LIMIT = 1'000'000'000LL;\nconst double TIME_LIMIT = 2.8;\nconst int DIR_LIMIT = 1000;\nconst int DIR_ATTEMPTS = 40;\n\nint N, K;\narray<int, 11> demand;\nvector<Point> points;\n\nvector<unsigned long long> pattern_lo, pattern_hi;\nvector<Key> tmp_keys;\nvector<int> order_idx;\nvector<long long> proj_values;\nvector<int> gap_indices;\nvector<Line> lines_current;\nint bits_used = 0;\n\nmt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\nchrono::steady_clock::time_point start_time;\nbool time_up = false;\n\ninline long long absll(long long x) { return x >= 0 ? x : -x; }\n\nlong long floor_div(long long a, long long b) {\n    assert(b != 0);\n    if (b < 0) { a = -a; b = -b; }\n    if (a >= 0) return a / b;\n    return - ((-a + b - 1) / b);\n}\nlong long ceil_div(long long a, long long b) {\n    assert(b != 0);\n    if (b < 0) { a = -a; b = -b; }\n    if (a >= 0) return (a + b - 1) / b;\n    return - ((-a) / b);\n}\n\nlong long ext_gcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) {\n        x = (a >= 0) ? 1 : -1;\n        y = 0;\n        return absll(a);\n    }\n    long long x1, y1;\n    long long g = ext_gcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\ninline bool check_time() {\n    if (time_up) return true;\n    double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    if (elapsed > TIME_LIMIT) time_up = true;\n    return time_up;\n}\n\nvoid reset_state() {\n    fill(pattern_lo.begin(), pattern_lo.end(), 0ULL);\n    fill(pattern_hi.begin(), pattern_hi.end(), 0ULL);\n    lines_current.clear();\n    lines_current.reserve(K);\n    bits_used = 0;\n}\n\nint score_from_counts(const CountArr &cnt) {\n    int sc = 0;\n    for (int d = 1; d <= 10; ++d) sc += min(demand[d], cnt[d]);\n    return sc;\n}\n\nint recompute_current(CountArr &out_cnt) {\n    out_cnt.fill(0);\n    for (int i = 0; i < N; ++i) {\n        tmp_keys[i] = {pattern_lo[i], pattern_hi[i]};\n        order_idx[i] = i;\n    }\n    auto cmp = [&](int lhs, int rhs) {\n        const Key &a = tmp_keys[lhs];\n        const Key &b = tmp_keys[rhs];\n        if (a.hi != b.hi) return a.hi < b.hi;\n        return a.lo < b.lo;\n    };\n    sort(order_idx.begin(), order_idx.end(), cmp);\n    int idx = 0;\n    while (idx < N) {\n        int j = idx + 1;\n        while (j < N) {\n            const Key &ka = tmp_keys[order_idx[idx]];\n            const Key &kb = tmp_keys[order_idx[j]];\n            if (ka.lo != kb.lo || ka.hi != kb.hi) break;\n            ++j;\n        }\n        int cnt = j - idx;\n        if (cnt <= 10) out_cnt[cnt]++;\n        idx = j;\n    }\n    return score_from_counts(out_cnt);\n}\n\nint evaluate_candidate(const Line &line) {\n    if (bits_used >= 128) return -1;\n    for (int i = 0; i < N; ++i) {\n        long long val = line.A * points[i].x + line.B * points[i].y - line.C;\n        if (val == 0) return -1;\n        unsigned long long bit = (val > 0) ? 1ULL : 0ULL;\n        unsigned long long lo = pattern_lo[i];\n        unsigned long long hi = pattern_hi[i];\n        if (bits_used < 64) lo |= bit << bits_used;\n        else hi |= bit << (bits_used - 64);\n        tmp_keys[i] = {lo, hi};\n        order_idx[i] = i;\n    }\n    auto cmp = [&](int lhs, int rhs) {\n        const Key &a = tmp_keys[lhs];\n        const Key &b = tmp_keys[rhs];\n        if (a.hi != b.hi) return a.hi < b.hi;\n        return a.lo < b.lo;\n    };\n    sort(order_idx.begin(), order_idx.end(), cmp);\n    CountArr cnt;\n    cnt.fill(0);\n    int idx = 0;\n    while (idx < N) {\n        int j = idx + 1;\n        while (j < N) {\n            const Key &ka = tmp_keys[order_idx[idx]];\n            const Key &kb = tmp_keys[order_idx[j]];\n            if (ka.lo != kb.lo || ka.hi != kb.hi) break;\n            ++j;\n        }\n        int c = j - idx;\n        if (c <= 10) cnt[c]++;\n        idx = j;\n    }\n    return score_from_counts(cnt);\n}\n\ninline long long rand_ll(long long l, long long r) {\n    unsigned long long range = (unsigned long long)(r - l + 1);\n    return l + (long long)(rng() % range);\n}\n\nint pick_gap_index(const vector<int> &gaps) {\n    int sz = (int)gaps.size();\n    int type = (int)(rng() % 4);\n    if (type == 0) {\n        return gaps[(int)(rng() % sz)];\n    }\n    if (type == 1) {\n        int limit = min(sz, 15);\n        return gaps[(int)(rng() % limit)];\n    }\n    if (type == 2) {\n        int limit = min(sz, 15);\n        return gaps[sz - 1 - (int)(rng() % limit)];\n    }\n    int width = min(sz, 25);\n    int center = sz / 2;\n    int offset = (int)(rng() % max(1, width));\n    int idx = center + offset - width / 2;\n    idx = max(0, min(sz - 1, idx));\n    return gaps[idx];\n}\n\nbool generate_candidate_line(Line &line) {\n    static const pair<int,int> preset[4] = {{1,0},{0,1},{1,1},{1,-1}};\n    for (int attempt = 0; attempt < DIR_ATTEMPTS; ++attempt) {\n        long long a = 0, b = 0;\n        int mode = (int)(rng() % 6);\n        if (mode < 4) {\n            a = preset[mode].first;\n            b = preset[mode].second;\n        } else {\n            do {\n                a = rand_ll(-DIR_LIMIT, DIR_LIMIT);\n                b = rand_ll(-DIR_LIMIT, DIR_LIMIT);\n            } while (a == 0 && b == 0);\n        }\n        long long g = std::gcd(absll(a), absll(b));\n        if (g == 0) continue;\n        a /= g;\n        b /= g;\n        if (a < 0 || (a == 0 && b < 0)) {\n            a = -a;\n            b = -b;\n        }\n        for (int i = 0; i < N; ++i) {\n            proj_values[i] = a * points[i].x + b * points[i].y;\n        }\n        sort(proj_values.begin(), proj_values.end());\n        gap_indices.clear();\n        for (int i = 1; i < N; ++i) {\n            if (proj_values[i] - proj_values[i - 1] >= 2) gap_indices.push_back(i);\n        }\n        if (gap_indices.empty()) continue;\n        int pos = pick_gap_index(gap_indices);\n        long long left = proj_values[pos - 1];\n        long long right = proj_values[pos];\n        long long c = rand_ll(left + 1, right - 1);\n        line = {a, b, c};\n        return true;\n    }\n    return false;\n}\n\nvoid apply_line(const Line &line) {\n    for (int i = 0; i < N; ++i) {\n        long long val = line.A * points[i].x + line.B * points[i].y - line.C;\n        if (val == 0) val = 1; // should not happen\n        unsigned long long bit = (val > 0) ? 1ULL : 0ULL;\n        if (bits_used < 64) pattern_lo[i] |= bit << bits_used;\n        else pattern_hi[i] |= bit << (bits_used - 64);\n    }\n    lines_current.push_back(line);\n    ++bits_used;\n}\n\nbool line_to_points(const Line &line, array<long long,4> &out) {\n    long long A = line.A, B = line.B, C = line.C;\n    if (A == 0 && B == 0) return false;\n    if (B == 0) {\n        long long x = C / A;\n        long long y1 = -COORD_LIMIT + 1;\n        long long y2 = y1 + 1;\n        out = {x, y1, x, y2};\n        return true;\n    }\n    if (A == 0) {\n        long long y = C / B;\n        long long x1 = -COORD_LIMIT + 1;\n        long long x2 = x1 + 1;\n        out = {x1, y, x2, y};\n        return true;\n    }\n    long long x0, y0;\n    long long g = ext_gcd(A, B, x0, y0);\n    if (g == 0) return false;\n    if (C % g != 0) return false;\n    long long mult = C / g;\n    x0 *= mult;\n    y0 *= mult;\n    auto range_for = [&](long long base, long long coeff) -> pair<long long,long long> {\n        const long long INF = (1LL << 60);\n        if (coeff == 0) {\n            if (absll(base) > COORD_LIMIT) return {1, 0};\n            return {-INF, INF};\n        }\n        long long low = -INF, high = INF;\n        if (coeff > 0) {\n            low = max(low, ceil_div(-COORD_LIMIT - base, coeff));\n            high = min(high, floor_div(COORD_LIMIT - base, coeff));\n        } else {\n            high = min(high, floor_div(-COORD_LIMIT - base, coeff));\n            low = max(low, ceil_div(COORD_LIMIT - base, coeff));\n        }\n        return {low, high};\n    };\n    auto rx = range_for(x0, B);\n    auto ry = range_for(y0, -A);\n    long long low = max(rx.first, ry.first);\n    long long high = min(rx.second, ry.second);\n    if (low > high) return false;\n    auto point_from = [&](long long k) -> pair<long long,long long> {\n        return {x0 + B * k, y0 - A * k};\n    };\n    long long k0 = 0;\n    if (k0 < low) k0 = low;\n    if (k0 > high) k0 = high;\n    auto P = point_from(k0);\n    if (absll(P.first) > COORD_LIMIT || absll(P.second) > COORD_LIMIT) {\n        P = point_from(low);\n        k0 = low;\n    }\n    long long qk = (k0 < high) ? k0 + 1 : k0 - 1;\n    auto Q = point_from(qk);\n    if (absll(Q.first) > COORD_LIMIT || absll(Q.second) > COORD_LIMIT || (Q.first == P.first && Q.second == P.second)) {\n        bool found = false;\n        for (long long delta = 1; delta <= 200000 && !found; ++delta) {\n            if (k0 + delta <= high) {\n                auto cand = point_from(k0 + delta);\n                if (absll(cand.first) <= COORD_LIMIT && absll(cand.second) <= COORD_LIMIT && (cand.first != P.first || cand.second != P.second)) {\n                    Q = cand;\n                    found = true;\n                    break;\n                }\n            }\n            if (k0 - delta >= low) {\n                auto cand = point_from(k0 - delta);\n                if (absll(cand.first) <= COORD_LIMIT && absll(cand.second) <= COORD_LIMIT && (cand.first != P.first || cand.second != P.second)) {\n                    Q = cand;\n                    found = true;\n                    break;\n                }\n            }\n        }\n        if (!found) return false;\n    }\n    out = {P.first, P.second, Q.first, Q.second};\n    return true;\n}\n\ninline int candidate_trials(int iter) {\n    if (iter < 10) return 40;\n    if (iter < 30) return 30;\n    if (iter < 60) return 25;\n    return 20;\n}\n\nstruct AttemptResult {\n    int score;\n    vector<Line> lines;\n};\n\nAttemptResult run_attempt() {\n    reset_state();\n    CountArr current_counts;\n    int current_score = recompute_current(current_counts);\n    vector<Line> best_lines_local = lines_current;\n    int best_score_local = current_score;\n\n    for (int iter = 0; iter < K; ++iter) {\n        if (check_time()) break;\n        int trials = candidate_trials(iter);\n        Line best_line{};\n        int best_line_score = -1;\n        bool found = false;\n        for (int t = 0; t < trials; ++t) {\n            if (check_time()) break;\n            Line cand;\n            if (!generate_candidate_line(cand)) continue;\n            int sc = evaluate_candidate(cand);\n            if (sc < 0) continue;\n            if (!found || sc > best_line_score) {\n                best_line_score = sc;\n                best_line = cand;\n                found = true;\n            }\n        }\n        if (!found || check_time()) break;\n        apply_line(best_line);\n        current_score = recompute_current(current_counts);\n        if (current_score > best_score_local) {\n            best_score_local = current_score;\n            best_lines_local = lines_current;\n        }\n    }\n    return {best_score_local, std::move(best_lines_local)};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K;\n    for (int d = 1; d <= 10; ++d) cin >> demand[d];\n    points.resize(N);\n    for (int i = 0; i < N; ++i) cin >> points[i].x >> points[i].y;\n\n    pattern_lo.assign(N, 0ULL);\n    pattern_hi.assign(N, 0ULL);\n    tmp_keys.resize(N);\n    order_idx.resize(N);\n    proj_values.resize(N);\n    gap_indices.reserve(N);\n    lines_current.reserve(K);\n\n    start_time = chrono::steady_clock::now();\n    int global_best_score = -1;\n    vector<Line> global_best_lines;\n\n    while (!check_time()) {\n        AttemptResult res = run_attempt();\n        if (res.score > global_best_score) {\n            global_best_score = res.score;\n            global_best_lines = res.lines;\n        }\n        if (check_time()) break;\n    }\n    if (global_best_score < 0) {\n        global_best_score = 0;\n        global_best_lines.clear();\n    }\n\n    vector<array<long long,4>> output;\n    output.reserve(global_best_lines.size());\n    for (const auto &ln : global_best_lines) {\n        array<long long,4> pts;\n        if (!line_to_points(ln, pts)) {\n            // Fallback (should not happen): use simple axis line\n            pts = {-COORD_LIMIT + 1, -COORD_LIMIT + 1, -COORD_LIMIT + 2, -COORD_LIMIT + 1};\n        }\n        output.push_back(pts);\n    }\n\n    cout << output.size() << '\\n';\n    for (auto &v : output) {\n        cout << v[0] << ' ' << v[1] << ' ' << v[2] << ' ' << v[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr double TIME_LIMIT = 4.8;\n\n    struct Candidate {\n        int ax, ay;\n        int bx, by;\n        int cx, cy;\n        int dx, dy;\n    };\n\n    int N, M;\n    int center;\n    vector<vector<int>> rowDots, colDots;\n    vector<vector<char>> hasDot;\n    vector<vector<char>> usedH, usedV;\n    vector<vector<int>> weight;\n    vector<array<int, 8>> operations;\n    chrono::steady_clock::time_point startTime;\n\n    double elapsed() const {\n        using namespace chrono;\n        return duration<double>(steady_clock::now() - startTime).count();\n    }\n\n    void addDot(int x, int y) {\n        if (hasDot[x][y]) return;\n        hasDot[x][y] = 1;\n        auto &row = rowDots[y];\n        row.insert(lower_bound(row.begin(), row.end(), x), x);\n        auto &col = colDots[x];\n        col.insert(lower_bound(col.begin(), col.end(), y), y);\n    }\n\n    bool horizontalSegmentUnused(int y, int x1, int x2) const {\n        if (x1 == x2) return false;\n        int l = min(x1, x2);\n        int r = max(x1, x2);\n        for (int x = l; x < r; ++x) {\n            if (usedH[y][x]) return false;\n        }\n        return true;\n    }\n\n    bool verticalSegmentUnused(int x, int y1, int y2) const {\n        if (y1 == y2) return false;\n        int l = min(y1, y2);\n        int r = max(y1, y2);\n        for (int y = l; y < r; ++y) {\n            if (usedV[x][y]) return false;\n        }\n        return true;\n    }\n\n    void markHorizontal(int y, int x1, int x2) {\n        if (x1 == x2) return;\n        int l = min(x1, x2);\n        int r = max(x1, x2);\n        for (int x = l; x < r; ++x) usedH[y][x] = 1;\n    }\n\n    void markVertical(int x, int y1, int y2) {\n        if (y1 == y2) return;\n        int l = min(y1, y2);\n        int r = max(y1, y2);\n        for (int y = l; y < r; ++y) usedV[x][y] = 1;\n    }\n\n    bool rowSegmentClear(int y, int xStart, int xEnd) const {\n        if (xStart == xEnd) return false;\n        const auto &row = rowDots[y];\n        auto it = lower_bound(row.begin(), row.end(), xStart);\n        if (it == row.end() || *it != xStart) return false;\n        int idx = int(it - row.begin());\n        if (xEnd > xStart) {\n            if (idx + 1 < (int)row.size() && row[idx + 1] < xEnd) return false;\n        } else {\n            if (idx - 1 >= 0 && row[idx - 1] > xEnd) return false;\n        }\n        return true;\n    }\n\n    bool colSegmentClear(int x, int yStart, int yEnd) const {\n        if (yStart == yEnd) return false;\n        const auto &col = colDots[x];\n        auto it = lower_bound(col.begin(), col.end(), yStart);\n        if (it == col.end() || *it != yStart) return false;\n        int idx = int(it - col.begin());\n        if (yEnd > yStart) {\n            if (idx + 1 < (int)col.size() && col[idx + 1] < yEnd) return false;\n        } else {\n            if (idx - 1 >= 0 && col[idx - 1] > yEnd) return false;\n        }\n        return true;\n    }\n\n    bool findBestCandidate(Candidate &best, bool &timeoutFlag) {\n        double bestScore = -1.0;\n        int bestLen = numeric_limits<int>::max();\n        Candidate bestCand{};\n        bool found = false;\n        timeoutFlag = false;\n        bool stop = false;\n\n        for (int y = 0; y < N && !stop; ++y) {\n            if ((y & 3) == 0 && elapsed() > TIME_LIMIT) {\n                timeoutFlag = true;\n                stop = true;\n                break;\n            }\n            const auto &row = rowDots[y];\n            int rowSize = (int)row.size();\n            if (rowSize < 2) continue;\n\n            for (int idx = 0; idx < rowSize && !stop; ++idx) {\n                if ((idx & 7) == 0 && elapsed() > TIME_LIMIT) {\n                    timeoutFlag = true;\n                    stop = true;\n                    break;\n                }\n                int ax = row[idx];\n                int left = (idx > 0) ? row[idx - 1] : -1;\n                bool leftFree = (left != -1) && horizontalSegmentUnused(y, ax, left);\n                int right = (idx + 1 < rowSize) ? row[idx + 1] : -1;\n                bool rightFree = (right != -1) && horizontalSegmentUnused(y, ax, right);\n                if (!leftFree && !rightFree) continue;\n\n                const auto &col = colDots[ax];\n                int pos = int(lower_bound(col.begin(), col.end(), y) - col.begin());\n                int down = (pos > 0) ? col[pos - 1] : -1;\n                bool downFree = (down != -1) && verticalSegmentUnused(ax, y, down);\n                int up = (pos + 1 < (int)col.size()) ? col[pos + 1] : -1;\n                bool upFree = (up != -1) && verticalSegmentUnused(ax, y, up);\n                if (!upFree && !downFree) continue;\n\n                auto evaluate = [&](int yB, int xC) {\n                    if (yB == -1 || xC == -1) return;\n                    int dx = xC;\n                    int dy = yB;\n                    if (hasDot[dx][dy]) return;\n                    if (!rowSegmentClear(yB, ax, dx)) return;\n                    if (!colSegmentClear(xC, y, dy)) return;\n                    if (!horizontalSegmentUnused(yB, ax, dx)) return;\n                    if (!verticalSegmentUnused(xC, y, dy)) return;\n                    double score = weight[dx][dy];\n                    int len = abs(xC - ax) + abs(yB - y);\n                    if (!found || score > bestScore || (score == bestScore && len < bestLen)) {\n                        found = true;\n                        bestScore = score;\n                        bestLen = len;\n                        bestCand = {ax, y, ax, yB, xC, y, dx, dy};\n                    }\n                };\n\n                if (upFree) {\n                    if (rightFree) evaluate(up, right);\n                    if (leftFree) evaluate(up, left);\n                }\n                if (downFree) {\n                    if (rightFree) evaluate(down, right);\n                    if (leftFree) evaluate(down, left);\n                }\n            }\n        }\n\n        if (!found) return false;\n        best = bestCand;\n        return true;\n    }\n\n    void applyCandidate(const Candidate &cand) {\n        markVertical(cand.ax, cand.ay, cand.by);\n        markHorizontal(cand.ay, cand.ax, cand.cx);\n        markHorizontal(cand.by, cand.ax, cand.cx);\n        markVertical(cand.cx, cand.cy, cand.dy);\n        addDot(cand.dx, cand.dy);\n        operations.push_back({cand.dx, cand.dy,\n                              cand.bx, cand.by,\n                              cand.ax, cand.ay,\n                              cand.cx, cand.cy});\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M)) return;\n        rowDots.assign(N, vector<int>());\n        colDots.assign(N, vector<int>());\n        hasDot.assign(N, vector<char>(N, 0));\n        int seg = max(N - 1, 0);\n        usedH.assign(N, vector<char>(seg, 0));\n        usedV.assign(N, vector<char>(seg, 0));\n        weight.assign(N, vector<int>(N, 0));\n        operations.clear();\n        operations.reserve(N * N);\n\n        center = (N - 1) / 2;\n        for (int x = 0; x < N; ++x)\n            for (int y = 0; y < N; ++y) {\n                int dx = x - center;\n                int dy = y - center;\n                weight[x][y] = dx * dx + dy * dy + 1;\n            }\n\n        for (int i = 0; i < M; ++i) {\n            int x, y;\n            cin >> x >> y;\n            addDot(x, y);\n        }\n\n        startTime = chrono::steady_clock::now();\n        while (true) {\n            if (elapsed() > TIME_LIMIT) break;\n            Candidate cand;\n            bool timeout = false;\n            if (!findBestCandidate(cand, timeout)) break;\n            applyCandidate(cand);\n            if (timeout) break;\n        }\n\n        cout << operations.size() << '\\n';\n        for (auto &op : operations) {\n            for (int i = 0; i < 8; ++i) {\n                if (i) cout << ' ';\n                cout << op[i];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 10;\n    using Grid = array<array<uint8_t, N>, N>;\n    static constexpr array<char, 4> DIRS = {'F', 'B', 'L', 'R'};\n\n    // evaluation parameters\n    static constexpr double ZONE_ALPHA = 0.35;\n    static constexpr double W_COMPONENT = 1.0;\n    static constexpr double W_ADJ_SAME = 18.0;\n    static constexpr double W_ADJ_DIFF = 13.0;\n    static constexpr double W_ZONE = 60.0;\n    static constexpr double W_LARGEST = 12.0;\n    static constexpr double W_COMP_COUNT = 20.0;\n    static constexpr double LOOKAHEAD_WEIGHT = 0.35;\n\n    vector<int> flavors = vector<int>(100);\n    array<int, 3> totalCounts{};\n    Grid board{};\n    int placed = 0;\n    mt19937 rng;\n\n    bool readInput() {\n        totalCounts.fill(0);\n        for (int i = 0; i < 100; ++i) {\n            if (!(cin >> flavors[i])) return false;\n            if (1 <= flavors[i] && flavors[i] <= 3) {\n                totalCounts[flavors[i] - 1]++;\n            }\n        }\n        uint32_t seed = 1234567u;\n        for (int i = 0; i < 100; ++i) {\n            seed = seed * 1000003u + static_cast<uint32_t>(flavors[i]) * 239u + i;\n        }\n        rng.seed(seed);\n        return true;\n    }\n\n    struct Decision {\n        char dir = 'F';\n        Grid board{};\n    };\n\n    void solve() {\n        for (auto &row : board) row.fill(0);\n        placed = 0;\n        for (int t = 0; t < 100; ++t) {\n            int p;\n            if (!(cin >> p)) return;\n            placeCandy(p, flavors[t]);\n            ++placed;\n            Decision dec = chooseMove(placed);\n            board = dec.board;\n            cout << dec.dir << endl;  // endl also flushes (required by the interactive spec)\n        }\n    }\n\n    void placeCandy(int idx, int flavor) {\n        int target = idx;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (board[r][c] == 0) {\n                    if (--target == 0) {\n                        board[r][c] = static_cast<uint8_t>(flavor);\n                        return;\n                    }\n                }\n            }\n        }\n    }\n\n    void applyTilt(Grid &g, char dir) const {\n        if (dir == 'F') {\n            for (int c = 0; c < N; ++c) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int r = 0; r < N; ++r) if (g[r][c]) tmp[k++] = g[r][c];\n                for (int r = 0; r < N; ++r) g[r][c] = (r < k) ? tmp[r] : 0;\n            }\n        } else if (dir == 'B') {\n            for (int c = 0; c < N; ++c) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int r = 0; r < N; ++r) if (g[r][c]) tmp[k++] = g[r][c];\n                int idx = k - 1;\n                for (int r = N - 1; r >= 0; --r) {\n                    if (idx >= 0) g[r][c] = tmp[idx--];\n                    else g[r][c] = 0;\n                }\n            }\n        } else if (dir == 'L') {\n            for (int r = 0; r < N; ++r) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int c = 0; c < N; ++c) if (g[r][c]) tmp[k++] = g[r][c];\n                for (int c = 0; c < N; ++c) g[r][c] = (c < k) ? tmp[c] : 0;\n            }\n        } else { // 'R'\n            for (int r = 0; r < N; ++r) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int c = 0; c < N; ++c) if (g[r][c]) tmp[k++] = g[r][c];\n                int idx = k - 1;\n                for (int c = N - 1; c >= 0; --c) {\n                    if (idx >= 0) g[r][c] = tmp[idx--];\n                    else g[r][c] = 0;\n                }\n            }\n        }\n    }\n\n    double evaluate(const Grid &g, int filled) const {\n        array<int,3> cnt = {0,0,0};\n        array<double,3> sumR = {0.0,0.0,0.0};\n        array<double,3> sumC = {0.0,0.0,0.0};\n        double sameAdj = 0.0;\n        double diffAdj = 0.0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int val = g[r][c];\n                if (!val) continue;\n                int idx = val - 1;\n                cnt[idx]++;\n                sumR[idx] += r;\n                sumC[idx] += c;\n                if (r + 1 < N && g[r + 1][c]) {\n                    if (g[r + 1][c] == val) sameAdj += 1.0;\n                    else diffAdj += 1.0;\n                }\n                if (c + 1 < N && g[r][c + 1]) {\n                    if (g[r][c + 1] == val) sameAdj += 1.0;\n                    else diffAdj += 1.0;\n                }\n            }\n        }\n\n        array<double,3> meanR = {0.0,0.0,0.0}, meanC = {0.0,0.0,0.0};\n        for (int i = 0; i < 3; ++i) {\n            if (cnt[i]) {\n                meanR[i] = sumR[i] / cnt[i];\n                meanC[i] = sumC[i] / cnt[i];\n            }\n        }\n\n        double zoneScore = 0.0;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int val = g[r][c];\n                if (!val) continue;\n                int idx = val - 1;\n                double dr = r - meanR[idx];\n                double dc = c - meanC[idx];\n                double dist2 = dr * dr + dc * dc;\n                zoneScore += 1.0 / (1.0 + ZONE_ALPHA * dist2);\n            }\n        }\n\n        array<array<uint8_t, N>, N> vis{};\n        array<int,3> compCounts = {0,0,0};\n        array<int,3> largest = {0,0,0};\n        double compScore = 0.0;\n        const int dr4[4] = {-1, 1, 0, 0};\n            const int dc4[4] = {0, 0, -1, 1};\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!g[r][c] || vis[r][c]) continue;\n                int color = g[r][c];\n                queue<pair<int,int>> q;\n                q.emplace(r,c);\n                vis[r][c] = 1;\n                int sz = 0;\n                while (!q.empty()) {\n                    auto [cr, cc] = q.front(); q.pop();\n                    ++sz;\n                    for (int d = 0; d < 4; ++d) {\n                        int nr = cr + dr4[d];\n                        int nc = cc + dc4[d];\n                        if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                        if (vis[nr][nc]) continue;\n                        if (g[nr][nc] != color) continue;\n                        vis[nr][nc] = 1;\n                        q.emplace(nr, nc);\n                    }\n                }\n                compScore += 1.0 * sz * sz;\n                int idx = color - 1;\n                compCounts[idx]++;\n                largest[idx] = max(largest[idx], sz);\n            }\n        }\n\n        int compCountSum = compCounts[0] + compCounts[1] + compCounts[2];\n        int largestSum = largest[0] + largest[1] + largest[2];\n\n        double fillRatio = (filled <= 0 ? 0.0 : static_cast<double>(filled) / 100.0);\n        double zoneFactor = 0.4 + 0.6 * (1.0 - fillRatio);\n        double zoneWeight = W_ZONE * zoneFactor;\n        double adjFactor = 0.4 + 0.6 * fillRatio;\n        double adjSameWeight = W_ADJ_SAME * adjFactor;\n        double adjDiffWeight = W_ADJ_DIFF * adjFactor;\n        double compCountWeight = W_COMP_COUNT * fillRatio * fillRatio;\n\n        double score = W_COMPONENT * compScore\n                     + adjSameWeight * sameAdj\n                     - adjDiffWeight * diffAdj\n                     + zoneWeight * zoneScore\n                     + W_LARGEST * largestSum\n                     - compCountWeight * compCountSum;\n\n        return score;\n    }\n\n    int getSampleLimit(int filled) const {\n        if (filled < 25) return 20;\n        if (filled < 50) return 16;\n        if (filled < 75) return 12;\n        if (filled < 90) return 10;\n        return 8;\n    }\n\n    double evaluateWithLookahead(const Grid &state, int filled) {\n        double base = evaluate(state, filled);\n        if (filled >= 100 || LOOKAHEAD_WEIGHT <= 1e-9) return base;\n        int nextIdx = filled;\n        if (nextIdx >= (int)flavors.size()) return base;\n\n        int emptiesIdx[N * N];\n        int emptiesSz = 0;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (state[r][c] == 0) {\n                    emptiesIdx[emptiesSz++] = r * N + c;\n                }\n            }\n        }\n        if (emptiesSz == 0) return base;\n\n        int limit = getSampleLimit(filled);\n        if (limit <= 0) limit = 1;\n        int sampleCount = min(limit, emptiesSz);\n        for (int i = 0; i < sampleCount; ++i) {\n            int span = emptiesSz - i;\n            int j = i + static_cast<int>(rng() % span);\n            swap(emptiesIdx[i], emptiesIdx[j]);\n        }\n\n        const int nextFlavor = flavors[nextIdx];\n        double accum = 0.0;\n        for (int i = 0; i < sampleCount; ++i) {\n            int idx = emptiesIdx[i];\n            int r = idx / N;\n            int c = idx % N;\n            Grid tmp = state;\n            tmp[r][c] = static_cast<uint8_t>(nextFlavor);\n\n            double bestNext = -1e100;\n            for (char dir : DIRS) {\n                Grid fut = tmp;\n                applyTilt(fut, dir);\n                double val = evaluate(fut, filled + 1);\n                if (val > bestNext) bestNext = val;\n            }\n            accum += bestNext;\n        }\n        double avg = accum / sampleCount;\n\n        double fillRatio = static_cast<double>(filled) / 100.0;\n        double adapt = 0.3 + 0.7 * (1.0 - fillRatio);\n        double coverage = (emptiesSz <= sampleCount) ? 1.0 :\n                          static_cast<double>(sampleCount) / emptiesSz;\n        double coverageFactor = sqrt(max(1e-9, coverage));\n        double lookFactor = LOOKAHEAD_WEIGHT * adapt * coverageFactor;\n        if (lookFactor > 0.5) lookFactor = 0.5;\n\n        return base * (1.0 - lookFactor) + avg * lookFactor;\n    }\n\n    double randomNoise() {\n        return (static_cast<double>(rng() & 0xffffu) / 65535.0 - 0.5) * 1e-3;\n    }\n\n    Decision chooseMove(int filled) {\n        Decision best;\n        bool first = true;\n        double bestScore = -1e100;\n        for (char dir : DIRS) {\n            Grid cand = board;\n            applyTilt(cand, dir);\n            double score = evaluateWithLookahead(cand, filled);\n            score += randomNoise();\n            if (first || score > bestScore) {\n                first = false;\n                bestScore = score;\n                best.dir = dir;\n                best.board = cand;\n            }\n        }\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    if (!solver.readInput()) return 0;\n    solver.solve();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Designer {\n    int N = 60;\n    int A = 32;\n    int P;\n    int payloadEdges;\n    int payloadWords;\n    vector<vector<int>> anchorAdj; // A x A\n    vector<uint64_t> anchorAdjMask; // per anchor bitmask\n    vector<uint64_t> payloadAnchorMask; // per payload row mask\n    vector<int> degAA_can, degAP_can;\n    vector<vector<uint64_t>> graphCodes; // per graph payload bits\n    vector<pair<int,int>> payloadPairs;\n    vector<vector<int>> payloadPairIdx;\n    mt19937_64 rng;\n    Designer() {\n        P = N - A;\n        payloadEdges = P*(P-1)/2;\n        payloadWords = (payloadEdges + 63) / 64;\n        payloadPairIdx.assign(P, vector<int>(P, -1));\n        int idx = 0;\n        for(int u=0;u<P;u++) for(int v=u+1; v<P; v++) {\n            payloadPairIdx[u][v] = idx++;\n            payloadPairs.push_back({u,v});\n        }\n    }\n    uint64_t randMask(int bits) {\n        uint64_t mask = 0;\n        for(int i=0;i<bits;i+=64) mask |= (rng() << i);\n        if(bits<64) mask &= ((1ULL<<bits)-1);\n        else if(bits % 64) mask &= ((1ULL<<(bits%64))-1) << (bits/64*64);\n        return mask;\n    }\n    void generateAnchorAdj(double prob=0.8) {\n        anchorAdj.assign(A, vector<int>(A,0));\n        anchorAdjMask.assign(A,0);\n        for(int i=0;i<A;i++){\n            for(int j=i+1;j<A;j++){\n                bool edge = (rng() % 1000) < int(prob*1000);\n                anchorAdj[i][j]=anchorAdj[j][i]=edge;\n            }\n        }\n        for(int i=0;i<A;i++){\n            uint64_t mask=0;\n            for(int j=0;j<A;j++) if(anchorAdj[i][j]) mask |= (1ULL<<j);\n            anchorAdjMask[i]=mask;\n        }\n        degAA_can.assign(A,0);\n        for(int i=0;i<A;i++){\n            for(int j=0;j<A;j++) if(anchorAdj[i][j]) degAA_can[i]++;\n        }\n    }\n    void generatePayloadRows(int minWeight=10, int maxWeight=22, int minDist=8) {\n        payloadAnchorMask.clear();\n        while((int)payloadAnchorMask.size()<P){\n            uint64_t mask = 0;\n            for(int b=0;b<A;b++){\n                if(rng()&1) mask |= (1ULL<<b);\n            }\n            int weight = __builtin_popcountll(mask);\n            if(weight<minWeight || weight>maxWeight) continue;\n            bool ok=true;\n            for(auto &prev: payloadAnchorMask){\n                int dist = __builtin_popcountll(mask ^ prev);\n                if(dist < minDist){ ok=false; break; }\n            }\n            if(ok) payloadAnchorMask.push_back(mask);\n        }\n        degAP_can.assign(A,0);\n        for(auto &mask: payloadAnchorMask){\n            for(int b=0;b<A;b++) if((mask>>b)&1ULL) degAP_can[b]++;\n        }\n    }\n    vector<uint64_t> randomPayloadBits() {\n        vector<uint64_t> bits(payloadWords,0);\n        for(int w=0;w<payloadWords;w++) bits[w]=rng();\n        if(payloadEdges % 64){\n            uint64_t mask = (1ULL<<(payloadEdges%64))-1;\n            bits.back() &= mask;\n        }\n        return bits;\n    }\n    int hamming(const vector<uint64_t>&a,const vector<uint64_t>&b){\n        int s=0; for(size_t i=0;i<a.size();i++) s+=__builtin_popcountll(a[i]^b[i]); return s;\n    }\n    void generateGraphCodes(int M, int minDist=120){\n        graphCodes.clear();\n        while((int)graphCodes.size()<M){\n            auto cand = randomPayloadBits();\n            bool ok=true;\n            for(auto &exist: graphCodes){\n                if(hamming(cand,exist)<minDist){ ok=false; break; }\n            }\n            if(ok) graphCodes.push_back(cand);\n        }\n    }\n    void build(int M, int epsInt){\n        uint64_t seed = 1234567ULL + 10007ULL*M + 7919ULL*epsInt;\n        rng.seed(seed);\n        generateAnchorAdj();\n        generatePayloadRows();\n        generateGraphCodes(M);\n    }\n    string graphString(int k){\n        string s;\n        s.reserve(N*(N-1)/2);\n        auto &code = graphCodes[k];\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                bool val=false;\n                if(i<A && j<A){\n                    val = anchorAdj[i][j];\n                }else if(i<A && j>=A){\n                    int p = j-A;\n                    val = (payloadAnchorMask[p]>>i)&1ULL;\n                }else{\n                    int u = i-A;\n                    int v = j-A;\n                    int idx = payloadPairIdx[u][v];\n                    val = (code[idx>>6] >> (idx&63)) & 1ULL;\n                }\n                s.push_back(val?'1':'0');\n            }\n        }\n        return s;\n    }\n};\n\nstruct Hungarian {\n    int n;\n    vector<vector<int>> cost;\n    vector<int> assignment;\n    Hungarian(int n=0):n(n){\n        cost.assign(n, vector<int>(n,0));\n        assignment.assign(n,-1);\n    }\n    void resize(int m){\n        n=m;\n        cost.assign(n, vector<int>(n,0));\n        assignment.assign(n,-1);\n    }\n    void solve(){\n        const int INF = 1e9;\n        vector<int> u(n+1,0), v(n+1,0), p(n+1,0), way(n+1,0);\n        for(int i=1;i<=n;i++){\n            p[0]=i;\n            vector<int> minv(n+1, INF);\n            vector<char> used(n+1,false);\n            int j0=0;\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> ans(n,-1);\n        for(int j=1;j<=n;j++) if(p[j]>0) ans[p[j]-1]=j-1;\n        assignment=ans;\n    }\n};\n\nstruct Decoder {\n    Designer *des;\n    int N,A,P;\n    Decoder(Designer* d):des(d){\n        N=d->N; A=d->A; P=d->P;\n    }\n    vector<uint64_t> parse(const string &s){\n        vector<uint64_t> adj(N,0);\n        int pos=0;\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                if(s[pos++]=='1'){\n                    adj[i]|=(1ULL<<j);\n                    adj[j]|=(1ULL<<i);\n                }\n            }\n        }\n        return adj;\n    }\n    vector<int> selectAnchors(const vector<uint64_t>&adj){\n        vector<int> deg(N);\n        for(int i=0;i<N;i++) deg[i]=__builtin_popcountll(adj[i]);\n        vector<int> order(N);\n        iota(order.begin(), order.end(),0);\n        sort(order.begin(), order.end(), [&](int x,int y){\n            if(deg[x]!=deg[y]) return deg[x]>deg[y];\n            return x<y;\n        });\n        vector<int> anchors(order.begin(), order.begin()+A);\n        vector<char> in(N,false);\n        uint64_t mask=0;\n        for(int v: anchors){ in[v]=true; mask|=(1ULL<<v); }\n        for(int iter=0;iter<4;iter++){\n            bool improved=false;\n            vector<int> degIn(N,0);\n            for(int v=0;v<N;v++){\n                degIn[v]=__builtin_popcountll(adj[v]&mask);\n                if(in[v]) degIn[v]--;\n            }\n            int bestGain=0, bestU=-1, bestV=-1;\n            for(int u: anchors){\n                for(int v=0;v<N;v++) if(!in[v]){\n                    int gain = degIn[v]-degIn[u];\n                    if(gain>bestGain){\n                        bestGain=gain; bestU=u; bestV=v;\n                    }\n                }\n            }\n            if(bestGain>0){\n                in[bestU]=false; in[bestV]=true;\n                mask ^= (1ULL<<bestU);\n                mask |= (1ULL<<bestV);\n                for(auto &x: anchors) if(x==bestU){ x=bestV; break; }\n                improved=true;\n            }\n            if(!improved) break;\n        }\n        sort(anchors.begin(), anchors.end());\n        return anchors;\n    }\n    pair<vector<int>, vector<int>> mapAnchors(const vector<uint64_t>&adj, const vector<int>&anchors){\n        vector<int> payloads;\n        vector<char> isAnchor(N,false);\n        for(int v:anchors) isAnchor[v]=true;\n        for(int i=0;i<N;i++) if(!isAnchor[i]) payloads.push_back(i);\n        vector<vector<int>> obsAA(A, vector<int>(A,0));\n        vector<int> degAA_obs(A,0), degAP_obs(A,0);\n        for(int i=0;i<A;i++){\n            for(int j=i+1;j<A;j++){\n                bool bit = (adj[anchors[i]]>>anchors[j]) & 1ULL;\n                obsAA[i][j]=obsAA[j][i]=bit;\n            }\n            degAA_obs[i]=0;\n            for(int j=0;j<A;j++) if(obsAA[i][j]) degAA_obs[i]++;\n            uint64_t payloadMask=0;\n            for(int v: payloads) payloadMask|=(1ULL<<v);\n            degAP_obs[i]=__builtin_popcountll(adj[anchors[i]] & payloadMask);\n        }\n        vector<int> orderCan(A), orderObs(A);\n        iota(orderCan.begin(), orderCan.end(),0);\n        iota(orderObs.begin(), orderObs.end(),0);\n        sort(orderCan.begin(), orderCan.end(), [&](int x,int y){\n            if(des->degAA_can[x]!=des->degAA_can[y])\n                return des->degAA_can[x]>des->degAA_can[y];\n            if(des->degAP_can[x]!=des->degAP_can[y])\n                return des->degAP_can[x]>des->degAP_can[y];\n            return x<y;\n        });\n        sort(orderObs.begin(), orderObs.end(), [&](int x,int y){\n            if(degAA_obs[x]!=degAA_obs[y])\n                return degAA_obs[x]>degAA_obs[y];\n            if(degAP_obs[x]!=degAP_obs[y])\n                return degAP_obs[x]>degAP_obs[y];\n            return x<y;\n        });\n        vector<int> assign(A);\n        for(int i=0;i<A;i++) assign[orderCan[i]]=orderObs[i];\n        auto calcCost=[&](const vector<int>&perm){\n            int cost=0;\n            for(int i=0;i<A;i++){\n                for(int j=i+1;j<A;j++){\n                    cost += des->anchorAdj[i][j] ^ obsAA[perm[i]][perm[j]];\n                }\n            }\n            return cost;\n        };\n        int currentCost = calcCost(assign);\n        vector<int> best=assign; int bestCost=currentCost;\n        uniform_int_distribution<int> dist(0,A-1);\n        double temp=5.0;\n        for(int iter=0;iter<5000;iter++){\n            int i=dist(des->rng), j=dist(des->rng);\n            if(i==j) continue;\n            if(i>j) swap(i,j);\n            int ai=assign[i], aj=assign[j];\n            int delta=0;\n            for(int k=0;k<A;k++){\n                if(k==i || k==j) continue;\n                int ak=assign[k];\n                delta += (des->anchorAdj[i][k] ^ obsAA[aj][ak]) - (des->anchorAdj[i][k] ^ obsAA[ai][ak]);\n                delta += (des->anchorAdj[j][k] ^ obsAA[ai][ak]) - (des->anchorAdj[j][k] ^ obsAA[aj][ak]);\n            }\n            delta += (des->anchorAdj[i][j] ^ obsAA[aj][ai]) - (des->anchorAdj[i][j] ^ obsAA[ai][aj]);\n            if(delta < 0 || (temp>1e-9 && uniform_real_distribution<double>(0.0,1.0)(des->rng) < exp(-delta/temp))){\n                swap(assign[i], assign[j]);\n                currentCost += delta;\n                if(currentCost < bestCost){\n                    bestCost=currentCost;\n                    best=assign;\n                }\n            }\n            temp *= 0.995;\n        }\n        vector<int> actualAnchor(A);\n        for(int i=0;i<A;i++) actualAnchor[i]=anchors[best[i]];\n        return {actualAnchor, payloads};\n    }\n    vector<int> mapPayloads(const vector<uint64_t>&adj, const vector<int>&anchorVertices, const vector<int>&payloads){\n        int payloadCount=P;\n        vector<uint64_t> anchorMaskPerPayload(payloadCount,0);\n        vector<int> anchorPos(N,-1);\n        for(int i=0;i<A;i++) anchorPos[anchorVertices[i]]=i;\n        for(int idx=0; idx<payloadCount; idx++){\n            uint64_t mask=0;\n            int v=payloads[idx];\n            for(int i=0;i<A;i++){\n                if((adj[v]>>anchorVertices[i]) & 1ULL) mask |= (1ULL<<i);\n            }\n            anchorMaskPerPayload[idx]=mask;\n        }\n        Hungarian hung(payloadCount);\n        for(int i=0;i<payloadCount;i++){\n            for(int j=0;j<payloadCount;j++){\n                int dist = __builtin_popcountll(anchorMaskPerPayload[i] ^ des->payloadAnchorMask[j]);\n                hung.cost[i][j]=dist;\n            }\n        }\n        hung.solve();\n        vector<int> actual(P);\n        for(int j=0;j<payloadCount;j++){\n            int idx=-1;\n            for(int i=0;i<payloadCount;i++){\n                if(hung.assignment[i]==j){ idx=i; break; }\n            }\n            actual[j]=payloads[idx];\n        }\n        return actual;\n    }\n    vector<uint64_t> observedPayloadBits(const vector<uint64_t>&adj, const vector<int>&payloadMap){\n        vector<uint64_t> bits(des->payloadWords,0);\n        int idx=0;\n        for(int u=0;u<P;u++){\n            for(int v=u+1; v<P; v++){\n                int realU=payloadMap[u];\n                int realV=payloadMap[v];\n                bool bit = (adj[realU]>>realV)&1ULL;\n                if(bit) bits[idx>>6] |= (1ULL<<(idx&63));\n                idx++;\n            }\n        }\n        return bits;\n    }\n    int decode(const string &s){\n        auto adj = parse(s);\n        auto anchors = selectAnchors(adj);\n        auto [anchorMap, payloadList] = mapAnchors(adj, anchors);\n        auto payloadMap = mapPayloads(adj, anchorMap, payloadList);\n        auto obsBits = observedPayloadBits(adj, payloadMap);\n        int best=-1, bestDist=1e9;\n        for(int k=0;k<(int)des->graphCodes.size();k++){\n            int dist = des->hamming(obsBits, des->graphCodes[k]);\n            if(dist < bestDist){\n                bestDist = dist;\n                best = k;\n            }\n        }\n        if(best==-1) best=0;\n        return best;\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int M;\n    double eps;\n    if(!(cin>>M>>eps)) return 0;\n    int epsInt = int(round(eps*100+1e-9));\n    Designer designer;\n    designer.build(M, epsInt);\n    cout<<designer.N<<\"\\n\";\n    for(int k=0;k<M;k++){\n        string g = designer.graphString(k);\n        cout<<g<<\"\\n\";\n    }\n    cout.flush();\n    Decoder decoder(&designer);\n    for(int q=0;q<100;q++){\n        string H;\n        cin>>H;\n        int ans = decoder.decode(H);\n        cout<<ans<<\"\\n\";\n        cout.flush();\n    }\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n};\n\nvector<double> compute_edge_scores(\n        int N, int M,\n        const vector<int>& U,\n        const vector<int>& V,\n        const vector<int>& W,\n        const vector<vector<pair<int,int>>>& graph,\n        Timer &timer,\n        double time_limit,\n        mt19937_64 &rng) {\n\n    const long long INF = (1LL<<60);\n    vector<double> score(M, 0.0);\n    vector<long long> dist(N, INF);\n    vector<double> sigma(N, 0.0);\n    vector<double> delta(N, 0.0);\n    vector<vector<int>> preds(N);\n    for (int i = 0; i < N; ++i) preds[i].reserve(graph[i].size());\n    vector<int> order;\n    order.reserve(N);\n    vector<int> nodes(N);\n    iota(nodes.begin(), nodes.end(), 0);\n    shuffle(nodes.begin(), nodes.end(), rng);\n    int processed = 0;\n\n    for (int idx = 0; idx < N; ++idx) {\n        int s = nodes[idx];\n        fill(dist.begin(), dist.end(), INF);\n        fill(sigma.begin(), sigma.end(), 0.0);\n        fill(delta.begin(), delta.end(), 0.0);\n        for (int i = 0; i < N; ++i) preds[i].clear();\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        dist[s] = 0;\n        sigma[s] = 1.0;\n        pq.emplace(0LL, s);\n        order.clear();\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            order.push_back(v);\n            for (auto [to, eid] : graph[v]) {\n                long long nd = d + W[eid];\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    pq.emplace(nd, to);\n                    sigma[to] = sigma[v];\n                    preds[to].clear();\n                    preds[to].push_back(eid);\n                } else if (nd == dist[to]) {\n                    sigma[to] += sigma[v];\n                    preds[to].push_back(eid);\n                }\n            }\n        }\n        while (!order.empty()) {\n            int w = order.back();\n            order.pop_back();\n            if (sigma[w] <= 0.0) continue;\n            double coeff = (1.0 + delta[w]) / sigma[w];\n            for (int eid : preds[w]) {\n                int v = (U[eid] == w) ? V[eid] : U[eid];\n                double contrib = sigma[v] * coeff;\n                delta[v] += contrib;\n                score[eid] += contrib;\n            }\n        }\n        ++processed;\n        if ((processed & 15) == 0 && timer.elapsed() > time_limit) break;\n    }\n    if (processed == 0) processed = 1;\n    if (processed < N) {\n        double scale = static_cast<double>(N) / processed;\n        for (auto &v : score) v *= scale;\n    }\n    for (auto &v : score) {\n        if (!(v > 0.0)) v = 1e-9;\n    }\n    return score;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Timer timer;\n    const double TOTAL_TIME_LIMIT = 5.8;\n    const double CENTRALITY_LIMIT = 2.5;\n    const double MOVE_EPS = 1e-9;\n    const double VERTEX_COEFF = 0.08;\n    const double DAYCOUNT_COEFF = 0.02;\n\n    int N, M, D, K;\n    if (!(cin >> N >> M >> D >> K)) return 0;\n    vector<int> U(M), V(M), W(M);\n    vector<vector<pair<int,int>>> graph(N);\n    for (int i = 0; i < M; ++i) {\n        int u, v, w;\n        cin >> u >> v >> w;\n        --u; --v;\n        U[i] = u; V[i] = v; W[i] = w;\n        graph[u].push_back({v, i});\n        graph[v].push_back({u, i});\n    }\n    for (int i = 0; i < N; ++i) {\n        int x, y;\n        cin >> x >> y; // unused, but read to consume input\n    }\n\n    mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    vector<double> edgeScore = compute_edge_scores(N, M, U, V, W, graph, timer, CENTRALITY_LIMIT, rng);\n    long double totalScore = 0.0L;\n    for (double v : edgeScore) totalScore += v;\n    if (totalScore <= 0.0L) totalScore = 1.0L;\n    long double baseScale = (totalScore * totalScore) / ( (long double)max(1, M) * (long double)max(1, D) );\n    double alpha = (double)(baseScale * VERTEX_COEFF);\n    double beta = (double)(baseScale * DAYCOUNT_COEFF);\n    const double MIN_WEIGHT = 1e-9;\n    const double MAX_WEIGHT = 1e100;\n    if (!isfinite(alpha) || alpha < MIN_WEIGHT) alpha = MIN_WEIGHT;\n    if (!isfinite(beta) || beta < MIN_WEIGHT) beta = MIN_WEIGHT;\n    alpha = min(alpha, MAX_WEIGHT);\n    beta = min(beta, MAX_WEIGHT);\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (edgeScore[a] != edgeScore[b]) return edgeScore[a] > edgeScore[b];\n        return a < b;\n    });\n\n    vector<int> assignment(M, 0);\n    vector<double> dayScore(D, 0.0);\n    vector<int> dayCount(D, 0);\n    vector<int> offsets(N);\n    for (int i = 0; i < N; ++i) offsets[i] = i * D;\n    vector<int> vertexDayCount(N * D, 0);\n\n    for (int eid : order) {\n        double s = edgeScore[eid];\n        int u = U[eid], v = V[eid];\n        int baseU = offsets[u], baseV = offsets[v];\n        double bestVal = numeric_limits<double>::infinity();\n        int bestDay = -1;\n        for (int d = 0; d < D; ++d) {\n            if (dayCount[d] >= K) continue;\n            double val = dayScore[d] * s\n                       + alpha * (vertexDayCount[baseU + d] + vertexDayCount[baseV + d])\n                       + beta * dayCount[d];\n            if (val < bestVal - 1e-9 || (abs(val - bestVal) <= 1e-9 && (rng() & 1))) {\n                bestVal = val;\n                bestDay = d;\n            }\n        }\n        if (bestDay == -1) {\n            for (int d = 0; d < D; ++d) {\n                if (dayCount[d] < K) {\n                    bestDay = d;\n                    break;\n                }\n            }\n            if (bestDay == -1) bestDay = 0;\n        }\n        assignment[eid] = bestDay;\n        dayScore[bestDay] += s;\n        dayCount[bestDay] += 1;\n        vertexDayCount[baseU + bestDay] += 1;\n        vertexDayCount[baseV + bestDay] += 1;\n    }\n\n    vector<int> indices(M);\n    iota(indices.begin(), indices.end(), 0);\n    bool time_up = false;\n    while (!time_up) {\n        if (timer.elapsed() > TOTAL_TIME_LIMIT) break;\n        bool improved = false;\n        shuffle(indices.begin(), indices.end(), rng);\n        for (int eid : indices) {\n            if (timer.elapsed() > TOTAL_TIME_LIMIT) { time_up = true; break; }\n            double s = edgeScore[eid];\n            int oldDay = assignment[eid];\n            int u = U[eid], v = V[eid];\n            int baseU = offsets[u], baseV = offsets[v];\n            int cnt_u_old = vertexDayCount[baseU + oldDay];\n            int cnt_v_old = vertexDayCount[baseV + oldDay];\n            double bestDelta = 0.0;\n            int bestDay = oldDay;\n            for (int d = 0; d < D; ++d) {\n                if (d == oldDay) continue;\n                if (dayCount[d] >= K) continue;\n                double delta = s * (dayScore[d] - dayScore[oldDay])\n                             + alpha * ((vertexDayCount[baseU + d] + vertexDayCount[baseV + d]) - (cnt_u_old + cnt_v_old))\n                             + beta * (dayCount[d] - dayCount[oldDay]);\n                if (delta + MOVE_EPS < bestDelta) {\n                    bestDelta = delta;\n                    bestDay = d;\n                }\n            }\n            if (bestDay != oldDay && bestDelta < -MOVE_EPS) {\n                dayScore[oldDay] -= s;\n                dayScore[bestDay] += s;\n                dayCount[oldDay] -= 1;\n                dayCount[bestDay] += 1;\n                vertexDayCount[baseU + oldDay] -= 1;\n                vertexDayCount[baseU + bestDay] += 1;\n                vertexDayCount[baseV + oldDay] -= 1;\n                vertexDayCount[baseV + bestDay] += 1;\n                assignment[eid] = bestDay;\n                improved = true;\n            }\n        }\n        if (!improved || time_up) break;\n    }\n\n    for (int i = 0; i < M; ++i) {\n        if (i) cout << ' ';\n        cout << (assignment[i] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Cell {\n    int x, y, z;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int D;\n    if (!(cin >> D)) return 0;\n    vector<vector<string>> front(2, vector<string>(D));\n    vector<vector<string>> right(2, vector<string>(D));\n    for (int i = 0; i < 2; ++i) {\n        for (int z = 0; z < D; ++z) cin >> front[i][z];\n        for (int z = 0; z < D; ++z) cin >> right[i][z];\n    }\n    mt19937 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    auto build_min = [&](const vector<string> &F, const vector<string> &R) {\n        vector<Cell> cells;\n        cells.reserve(D * D);\n        for (int z = 0; z < D; ++z) {\n            vector<int> xs, ys;\n            for (int x = 0; x < D; ++x) if (F[z][x] == '1') xs.push_back(x);\n            for (int y = 0; y < D; ++y) if (R[z][y] == '1') ys.push_back(y);\n            if (xs.empty() || ys.empty()) {\n                if (xs.empty()) xs.push_back(0);\n                if (ys.empty()) ys.push_back(0);\n            }\n            shuffle(xs.begin(), xs.end(), rng);\n            shuffle(ys.begin(), ys.end(), rng);\n            if (xs.size() >= ys.size()) {\n                for (size_t i = 0; i < xs.size(); ++i) {\n                    cells.push_back({xs[i], ys[i % ys.size()], z});\n                }\n            } else {\n                for (size_t i = 0; i < ys.size(); ++i) {\n                    cells.push_back({xs[i % xs.size()], ys[i], z});\n                }\n            }\n        }\n        return cells;\n    };\n    auto build_dense = [&](const vector<string> &F, const vector<string> &R) {\n        vector<Cell> cells;\n        cells.reserve(D * D * D);\n        for (int z = 0; z < D; ++z) {\n            vector<int> xs, ys;\n            for (int x = 0; x < D; ++x) if (F[z][x] == '1') xs.push_back(x);\n            for (int y = 0; y < D; ++y) if (R[z][y] == '1') ys.push_back(y);\n            if (xs.empty() || ys.empty()) {\n                if (xs.empty()) xs.push_back(0);\n                if (ys.empty()) ys.push_back(0);\n            }\n            for (int x : xs) for (int y : ys) cells.push_back({x, y, z});\n        }\n        return cells;\n    };\n    vector<Cell> cells[2];\n    cells[0] = build_min(front[0], right[0]);\n    cells[1] = build_min(front[1], right[1]);\n    const int D3 = D * D * D;\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n    auto verify = [&](const vector<int> &grid, const vector<string> &F, const vector<string> &R) {\n        for (int z = 0; z < D; ++z) {\n            for (int x = 0; x < D; ++x) {\n                bool occ = false;\n                for (int y = 0; y < D; ++y)\n                    if (grid[idx(x, y, z)]) { occ = true; break; }\n                if (occ != (F[z][x] == '1')) return false;\n            }\n            for (int y = 0; y < D; ++y) {\n                bool occ = false;\n                for (int x = 0; x < D; ++x)\n                    if (grid[idx(x, y, z)]) { occ = true; break; }\n                if (occ != (R[z][y] == '1')) return false;\n            }\n        }\n        return true;\n    };\n    auto place = [&](const vector<Cell> &c0, const vector<Cell> &c1) {\n        size_t s0 = c0.size(), s1 = c1.size();\n        int n = static_cast<int>(max(s0, s1));\n        vector<int> g0(D3, 0), g1(D3, 0);\n        for (size_t i = 0; i < s0; ++i) {\n            auto [x, y, z] = c0[i];\n            g0[idx(x, y, z)] = static_cast<int>(i) + 1;\n        }\n        for (size_t i = 0; i < s1; ++i) {\n            auto [x, y, z] = c1[i];\n            g1[idx(x, y, z)] = static_cast<int>(i) + 1;\n        }\n        return tuple<int, vector<int>, vector<int>>(n, move(g0), move(g1));\n    };\n    auto [n, grid0, grid1] = place(cells[0], cells[1]);\n    if (!verify(grid0, front[0], right[0]) || !verify(grid1, front[1], right[1])) {\n        cells[0] = build_dense(front[0], right[0]);\n        cells[1] = build_dense(front[1], right[1]);\n        tie(n, grid0, grid1) = place(cells[0], cells[1]);\n        // These should now be valid; in practice the fallback never triggers.\n        assert(verify(grid0, front[0], right[0]));\n        assert(verify(grid1, front[1], right[1]));\n    }\n    cout << n << '\\n';\n    for (int i = 0; i < D3; ++i) {\n        if (i) cout << ' ';\n        cout << grid0[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < D3; ++i) {\n        if (i) cout << ' ';\n        cout << grid1[i];\n    }\n    cout << '\\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};\nstruct AdjEdge {\n    int to;\n    long long w;\n    int id;\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    vector<long long> xs(N), ys(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> xs[i] >> ys[i];\n    }\n\n    vector<Edge> edges(M);\n    vector<vector<AdjEdge>> graph(N);\n    for (int j = 0; j < M; ++j) {\n        int u, v;\n        long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n        graph[u].push_back({v, w, j});\n        graph[v].push_back({u, w, j});\n    }\n\n    vector<long long> ax(K), ay(K);\n    for (int k = 0; k < K; ++k) {\n        cin >> ax[k] >> ay[k];\n    }\n\n    // Assign residents to nearest station (geometrically)\n    vector<long long> maxSq(N, 0);\n    for (int k = 0; k < K; ++k) {\n        long long bestSq = (1LL << 62);\n        int bestIdx = 0;\n        for (int i = 0; i < N; ++i) {\n            long long dx = xs[i] - ax[k];\n            long long dy = ys[i] - ay[k];\n            long long sq = dx * dx + dy * dy;\n            if (sq < bestSq) {\n                bestSq = sq;\n                bestIdx = i;\n            }\n        }\n        if (bestSq > maxSq[bestIdx]) maxSq[bestIdx] = bestSq;\n    }\n\n    auto ceil_sqrt = [](long long v) -> int {\n        if (v <= 0) return 0;\n        long long x = sqrt((long double)v);\n        while (x * x < v) ++x;\n        while (x > 0 && (x - 1) * (x - 1) >= v) --x;\n        return (int)x;\n    };\n\n    vector<int> P(N, 0);\n    vector<char> needed(N, false);\n    needed[0] = true;\n    for (int i = 0; i < N; ++i) {\n        int pi = ceil_sqrt(maxSq[i]);\n        if (pi > 5000) pi = 5000;\n        P[i] = pi;\n        if (pi > 0) needed[i] = true;\n    }\n\n    vector<int> terminals;\n    vector<int> termIndex(N, -1);\n    for (int i = 0; i < N; ++i) {\n        if (needed[i]) {\n            termIndex[i] = (int)terminals.size();\n            terminals.push_back(i);\n        }\n    }\n    if (termIndex[0] == -1) {\n        termIndex[0] = (int)terminals.size();\n        terminals.push_back(0);\n    }\n\n    const long long INF = (1LL << 60);\n    vector<vector<long long>> distMat(N, vector<long long>(N, INF));\n    vector<vector<int>> parentEdge(N, vector<int>(N, -1));\n    vector<vector<int>> parentVertex(N, vector<int>(N, -1));\n\n    // All-pairs shortest paths via Dijkstra from every vertex\n    for (int s = 0; s < N; ++s) {\n        vector<long long> dist(N, INF);\n        vector<int> prevE(N, -1), prevV(N, -1);\n        dist[s] = 0;\n        using Node = pair<long long, int>;\n        priority_queue<Node, vector<Node>, greater<Node>> pq;\n        pq.push({0, s});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            for (auto &ed : graph[v]) {\n                int to = ed.to;\n                long long nd = d + ed.w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    prevE[to] = ed.id;\n                    prevV[to] = v;\n                    pq.push({nd, to});\n                }\n            }\n        }\n        distMat[s] = dist;\n        parentEdge[s] = prevE;\n        parentVertex[s] = prevV;\n    }\n\n    vector<int> B(M, 0);\n\n    auto add_path = [&](int source, int target) {\n        if (source == target) return;\n\n        auto follow = [&](int s, int t) -> bool {\n            int cur = t;\n            while (cur != s) {\n                int e = parentEdge[s][cur];\n                int pv = parentVertex[s][cur];\n                if (e == -1 || pv == -1) return false;\n                B[e] = 1;\n                cur = pv;\n            }\n            return true;\n        };\n\n        if (follow(source, target)) return;\n\n        vector<long long> dist(N, INF);\n        vector<int> prevE(N, -1), prevV(N, -1);\n        dist[source] = 0;\n        using Node = pair<long long, int>;\n        priority_queue<Node, vector<Node>, greater<Node>> pq;\n        pq.push({0, source});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            for (auto &ed : graph[v]) {\n                int to = ed.to;\n                long long nd = d + ed.w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    prevE[to] = ed.id;\n                    prevV[to] = v;\n                    pq.push({nd, to});\n                }\n            }\n        }\n        if (dist[target] == INF) return;\n        parentEdge[source] = prevE;\n        parentVertex[source] = prevV;\n        follow(source, target);\n    };\n\n    // Approximate Steiner tree by MST on metric closure of terminals\n    int T = terminals.size();\n    vector<long long> key(T, INF);\n    vector<int> parent(T, -1);\n    vector<char> used(T, false);\n    int rootTerm = termIndex[0];\n    key[rootTerm] = 0;\n    for (int iter = 0; iter < T; ++iter) {\n        int u = -1;\n        long long best = INF;\n        for (int i = 0; i < T; ++i) {\n            if (!used[i] && key[i] < best) {\n                best = key[i];\n                u = i;\n            }\n        }\n        if (u == -1) break;\n        used[u] = true;\n        if (parent[u] != -1) {\n            int a = terminals[u];\n            int b = terminals[parent[u]];\n            add_path(a, b);\n        }\n        for (int v = 0; v < T; ++v) {\n            if (used[v]) continue;\n            long long d = distMat[terminals[u]][terminals[v]];\n            if (d < key[v]) {\n                key[v] = d;\n                parent[v] = u;\n            }\n        }\n    }\n\n    // Ensure every broadcasting station is reachable from station 1\n    auto reachable = [&]() -> vector<char> {\n        vector<char> vis(N, false);\n        queue<int> q;\n        vis[0] = true;\n        q.push(0);\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            for (auto &ed : graph[v]) {\n                if (!B[ed.id]) continue;\n                int to = ed.to;\n                if (!vis[to]) {\n                    vis[to] = true;\n                    q.push(to);\n                }\n            }\n        }\n        return vis;\n    };\n\n    while (true) {\n        auto vis = reachable();\n        bool need_more = false;\n        for (int v : terminals) {\n            if (!vis[v]) {\n                add_path(0, v);\n                need_more = true;\n            }\n        }\n        if (!need_more) break;\n    }\n\n    // Output\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << P[i];\n    }\n    cout << '\\n';\n    for (int j = 0; j < M; ++j) {\n        if (j) cout << ' ';\n        cout << (B[j] ? 1 : 0);\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    constexpr 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) {\n            if (!(cin >> a[x][y])) return 0;\n        }\n    }\n\n    vector<array<int, 4>> ops;\n    ops.reserve(5000);\n\n    auto swapBall = [&](int x1, int y1, int x2, int y2) {\n        ops.push_back({x1, y1, x2, y2});\n        swap(a[x1][y1], a[x2][y2]);\n    };\n\n    for (int x = N - 2; x >= 0; --x) {\n        for (int y = 0; y <= x; ++y) {\n            int cx = x, cy = y;\n            while (cx < N - 1) {\n                int bestY = cy;\n                int bestVal = a[cx + 1][cy];\n                int rightVal = a[cx + 1][cy + 1];\n                if (rightVal < bestVal) {\n                    bestVal = rightVal;\n                    bestY = cy + 1;\n                }\n                if (a[cx][cy] <= bestVal) break;\n                swapBall(cx, cy, cx + 1, bestY);\n                ++cx;\n                cy = bestY;\n            }\n        }\n    }\n\n    assert(ops.size() <= 10000);\n\n    cout << ops.size() << '\\n';\n    for (auto &op : ops) {\n        cout << op[0] << ' ' << op[1] << ' ' << op[2] << ' ' << op[3] << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int DX[4] = {1, -1, 0, 0};\nconst int DY[4] = {0, 0, 1, -1};\n\nconst int EMPTY     = -1;\nconst int ENTRANCE  = -2;\nconst int OBSTACLE  = -3;\nconst int TEMPBLOCK = -4;\n\nint D;\nint entrance_i, entrance_j;\nvector<vector<int>> grid;\nvector<pair<int,int>> cell_order;   // BFS order of usable cells (without entrance)\nint empty_cells_remaining = 0;\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < D && 0 <= y && y < D;\n}\n\nbool is_safe_cell(int x, int y) {\n    grid[x][y] = TEMPBLOCK;\n    queue<int> q;\n    vector<char> visited(D * D, 0);\n    int start = entrance_i * D + entrance_j;\n    q.push(start);\n    visited[start] = 1;\n    int reachable_empty = 0;\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int cx = v / D;\n        int cy = v % D;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = cx + DX[dir];\n            int ny = cy + DY[dir];\n            if (!inside(nx, ny)) continue;\n            int id = nx * D + ny;\n            if (visited[id]) continue;\n            int val = grid[nx][ny];\n            if (val == OBSTACLE || val == TEMPBLOCK) continue;\n            if (val >= 0) continue;            // already occupied by a container\n            visited[id] = 1;\n            q.push(id);\n            if (val == EMPTY) ++reachable_empty;\n        }\n    }\n    grid[x][y] = EMPTY;\n    return reachable_empty == empty_cells_remaining - 1;\n}\n\npair<int,int> choose_cell(int number) {\n    int M = (int)cell_order.size();\n    int target = max(0, min(number, M - 1));\n    pair<int,int> ans = {-1, -1};\n\n    auto try_index = [&](int idx) -> bool {\n        auto [x, y] = cell_order[idx];\n        if (grid[x][y] != EMPTY) return false;\n        if (!is_safe_cell(x, y)) return false;\n        ans = {x, y};\n        return true;\n    };\n\n    for (int off = 0; off < M; ++off) {\n        int idx = target - off;\n        if (idx >= 0 && try_index(idx)) return ans;\n        if (off == 0) continue;\n        idx = target + off;\n        if (idx < M && try_index(idx)) return ans;\n    }\n    for (int idx = 0; idx < M; ++idx)\n        if (try_index(idx)) return ans;\n\n    // Fallback (should never happen if graph stays connected)\n    for (auto [x, y] : cell_order)\n        if (grid[x][y] == EMPTY) return {x, y};\n    return {entrance_i, entrance_j};\n}\n\nvector<pair<int,int>> build_retrieval_order() {\n    int M = (int)cell_order.size();\n    vector<pair<int,int>> order;\n    order.reserve(M);\n\n    vector<vector<char>> cleared(D, vector<char>(D, false));\n    vector<vector<char>> in_queue(D, vector<char>(D, false));\n    cleared[entrance_i][entrance_j] = true;\n\n    struct Node {\n        int value;\n        int tie;\n        int x, y;\n    };\n    struct Cmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.value != b.value) return a.value > b.value;\n            if (a.tie != b.tie)     return a.tie > b.tie;\n            if (a.x != b.x)         return a.x > b.x;\n            return a.y > b.y;\n        }\n    };\n\n    priority_queue<Node, vector<Node>, Cmp> pq;\n    int tie_counter = 0;\n\n    auto push_node = [&](int x, int y) {\n        if (!inside(x, y)) return;\n        if (cleared[x][y]) return;\n        if (grid[x][y] < 0) return;        // obstacle / entrance / already empty\n        if (in_queue[x][y]) return;\n        pq.push(Node{grid[x][y], tie_counter++, x, y});\n        in_queue[x][y] = true;\n    };\n\n    for (int dir = 0; dir < 4; ++dir)\n        push_node(entrance_i + DX[dir], entrance_j + DY[dir]);\n\n    auto refill = [&]() {\n        if (!pq.empty()) return;\n        for (int x = 0; x < D; ++x) {\n            for (int y = 0; y < D; ++y) {\n                if (grid[x][y] < 0 || cleared[x][y] || in_queue[x][y]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int nx = x + DX[dir];\n                    int ny = y + DY[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (cleared[nx][ny]) {\n                        push_node(x, y);\n                        break;\n                    }\n                }\n            }\n        }\n    };\n\n    while ((int)order.size() < M) {\n        refill();\n        if (pq.empty()) break;           // should not happen\n        Node cur = pq.top(); pq.pop();\n        if (cleared[cur.x][cur.y]) continue;\n        order.push_back({cur.x, cur.y});\n        cleared[cur.x][cur.y] = true;\n        grid[cur.x][cur.y] = EMPTY;\n        for (int dir = 0; dir < 4; ++dir)\n            push_node(cur.x + DX[dir], cur.y + DY[dir]);\n    }\n    return order;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> D >> N)) return 0;\n    entrance_i = 0;\n    entrance_j = (D - 1) / 2;\n\n    grid.assign(D, vector<int>(D, EMPTY));\n    for (int k = 0; k < N; ++k) {\n        int r, c; cin >> r >> c;\n        grid[r][c] = OBSTACLE;\n    }\n    grid[entrance_i][entrance_j] = ENTRANCE;\n\n    // Pre-compute BFS order (without entrance)\n    vector<vector<int>> dist(D, vector<int>(D, -1));\n    queue<pair<int,int>> q;\n    q.push({entrance_i, entrance_j});\n    dist[entrance_i][entrance_j] = 0;\n    cell_order.clear();\n\n    while (!q.empty()) {\n        auto [x, y] = q.front(); q.pop();\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = x + DX[dir];\n            int ny = y + DY[dir];\n            if (!inside(nx, ny)) continue;\n            if (grid[nx][ny] == OBSTACLE) continue;\n            if (dist[nx][ny] != -1) continue;\n            dist[nx][ny] = dist[x][y] + 1;\n            q.push({nx, ny});\n            if (!(nx == entrance_i && ny == entrance_j))\n                cell_order.push_back({nx, ny});\n        }\n    }\n\n    empty_cells_remaining = (int)cell_order.size();\n    int total_containers = empty_cells_remaining;\n\n    for (int step = 0; step < total_containers; ++step) {\n        int t; cin >> t;\n        auto cell = choose_cell(t);\n        grid[cell.first][cell.second] = t;\n        --empty_cells_remaining;\n        cout << cell.first << ' ' << cell.second << '\\n' << flush;\n    }\n\n    auto retrieval = build_retrieval_order();\n    for (auto [x, y] : retrieval)\n        cout << x << ' ' << y << '\\n';\n    cout.flush();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr double TIME_LIMIT = 1.90; // seconds\n    int n, m;\n    vector<int> board; // flattened n*n grid\n    vector<vector<int>> adjCount;      // current adjacency multiplicities\n    vector<vector<char>> initialEdge;  // adjacency existence in the original map\n    vector<int> colorCount;\n    vector<char> isBoundaryColor;\n    vector<int> visitStamp;\n    int visitToken = 1;\n    chrono::steady_clock::time_point startTime;\n\n    inline bool timeExceeded() const {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n        return elapsed > TIME_LIMIT;\n    }\n\n    inline void changeAdj(int a, int b, int delta) {\n        if (a == b || delta == 0) return;\n        adjCount[a][b] += delta;\n        adjCount[b][a] += delta;\n#ifdef DEBUG\n        if (adjCount[a][b] < 0) {\n            cerr << \"Adjacency count negative between \" << a << \" and \" << b << \"\\n\";\n            abort();\n        }\n#endif\n    }\n\n    bool checkConnectivity(int idxRemove, int color) {\n        if (colorCount[color] <= 1) return false; // shouldn't be called\n\n        int i = idxRemove / n;\n        int j = idxRemove % n;\n        static const int di[4] = {1, -1, 0, 0};\n        static const int dj[4] = {0, 0, 1, -1};\n\n        int start = -1;\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir], nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n            int nidx = ni * n + nj;\n            if (board[nidx] == color) {\n                start = nidx;\n                break;\n            }\n        }\n        if (start == -1) {\n            for (int idx = 0; idx < n * n; ++idx) {\n                if (idx == idxRemove) continue;\n                if (board[idx] == color) {\n                    start = idx;\n                    break;\n                }\n            }\n            if (start == -1) return false; // no other cell (should not happen)\n        }\n\n        visitToken++;\n        if (visitToken == INT_MAX) {\n            fill(visitStamp.begin(), visitStamp.end(), 0);\n            visitToken = 1;\n        }\n        deque<int> dq;\n        dq.push_back(start);\n        visitStamp[start] = visitToken;\n        int target = colorCount[color] - 1;\n        int reached = 0;\n        while (!dq.empty()) {\n            int cur = dq.front(); dq.pop_front();\n            reached++;\n            if (reached == target) return true;\n            int ci = cur / n;\n            int cj = cur % n;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = ci + di[dir], nj = cj + dj[dir];\n                if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n                int nidx = ni * n + nj;\n                if (nidx == idxRemove) continue;\n                if (board[nidx] == color && visitStamp[nidx] != visitToken) {\n                    visitStamp[nidx] = visitToken;\n                    dq.push_back(nidx);\n                }\n            }\n        }\n        return reached == target;\n    }\n\n    bool tryRemove(int i, int j) {\n        int idx = i * n + j;\n        int c = board[idx];\n        if (c == 0) return false;\n        if (!isBoundaryColor[c]) return false;\n        if (colorCount[c] <= 1) return false;\n\n        static const int di[4] = {1, -1, 0, 0};\n        static const int dj[4] = {0, 0, 1, -1};\n\n        int zeroEdges = 0;\n        int sameNeighbors = 0;\n        array<int, 4> neighborColors{};\n        array<int, 4> neighborEdgeCounts{};\n        int neighborKinds = 0;\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                zeroEdges++;\n                continue;\n            }\n            int d = board[ni * n + nj];\n            if (d == 0) {\n                zeroEdges++;\n            } else if (d == c) {\n                sameNeighbors++;\n            } else {\n                if (!initialEdge[0][d]) return false; // would create forbidden adjacency with 0\n                bool found = false;\n                for (int t = 0; t < neighborKinds; ++t) {\n                    if (neighborColors[t] == d) {\n                        neighborEdgeCounts[t]++;\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) {\n                    neighborColors[neighborKinds] = d;\n                    neighborEdgeCounts[neighborKinds] = 1;\n                    neighborKinds++;\n                }\n            }\n        }\n\n        if (zeroEdges == 0) return false; // not adjacent to zero region\n        if (adjCount[c][0] <= zeroEdges) return false; // would remove last c-0 adjacency\n        for (int t = 0; t < neighborKinds; ++t) {\n            int d = neighborColors[t];\n            int edges = neighborEdgeCounts[t];\n            if (adjCount[c][d] <= edges) return false; // would remove last c-d contact\n        }\n\n        if (sameNeighbors >= 2 && !checkConnectivity(idx, c)) return false;\n\n        // Remove adjacencies touching this cell\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                changeAdj(c, 0, -1);\n            } else {\n                int d = board[ni * n + nj];\n                if (d == c) continue;\n                changeAdj(c, d, -1);\n            }\n        }\n\n        board[idx] = 0;\n        colorCount[c]--;\n\n        // Add new adjacencies between the fresh zero cell and its neighbors\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n            int d = board[ni * n + nj];\n            if (d == 0) continue;\n            changeAdj(0, d, +1);\n        }\n\n        return true;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n >> m;\n        board.assign(n * n, 0);\n        colorCount.assign(m + 1, 0);\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int c;\n                cin >> c;\n                board[i * n + j] = c;\n                colorCount[c]++;\n            }\n        }\n\n        adjCount.assign(m + 1, vector<int>(m + 1, 0));\n        initialEdge.assign(m + 1, vector<char>(m + 1, 0));\n\n        auto addEdge = [&](int a, int b) {\n            if (a == b) return;\n            adjCount[a][b] += 1;\n            adjCount[b][a] += 1;\n            initialEdge[a][b] = initialEdge[b][a] = 1;\n        };\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int idx = i * n + j;\n                int c = board[idx];\n                if (i + 1 < n) addEdge(c, board[idx + n]);\n                if (j + 1 < n) addEdge(c, board[idx + 1]);\n                if (i == 0) addEdge(c, 0);\n                if (i == n - 1) addEdge(c, 0);\n                if (j == 0) addEdge(c, 0);\n                if (j == n - 1) addEdge(c, 0);\n            }\n        }\n\n        isBoundaryColor.assign(m + 1, 0);\n        for (int c = 1; c <= m; ++c) {\n            if (initialEdge[0][c]) isBoundaryColor[c] = 1;\n        }\n\n        visitStamp.assign(n * n, 0);\n        startTime = chrono::steady_clock::now();\n\n        deque<int> q;\n        vector<char> inQueue(n * n, 0);\n        auto pushCell = [&](int i, int j) {\n            if (i < 0 || i >= n || j < 0 || j >= n) return;\n            int idx = i * n + j;\n            if (board[idx] == 0) return;\n            if (!inQueue[idx]) {\n                inQueue[idx] = 1;\n                q.push_back(idx);\n            }\n        };\n\n        for (int i = 0; i < n; ++i) {\n            pushCell(i, 0);\n            pushCell(i, n - 1);\n        }\n        for (int j = 0; j < n; ++j) {\n            pushCell(0, j);\n            pushCell(n - 1, j);\n        }\n\n        while (!q.empty()) {\n            if (timeExceeded()) break;\n            int idx = q.front(); q.pop_front();\n            inQueue[idx] = 0;\n            if (board[idx] == 0) continue;\n            int i = idx / n;\n            int j = idx % n;\n            if (tryRemove(i, j)) {\n                static const int di[4] = {1, -1, 0, 0};\n                static const int dj[4] = {0, 0, 1, -1};\n                for (int dir = 0; dir < 4; ++dir) {\n                    pushCell(i + di[dir], j + dj[dir]);\n                }\n            }\n        }\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                if (j) cout << ' ';\n                cout << board[i * n + j];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Query {\n    vector<int> idx;\n    vector<int8_t> coeff;\n    double scale = 1.0;\n    double invScale = 1.0;\n    double invScaleSq = 1.0;\n    int result = 0; // 1: L>R, -1: L<R, 0: equal\n};\n\nvector<double> estimate_weights(const vector<Query>& queries, int N, mt19937& rng) {\n    vector<double> w(N, 1.0);\n    if (queries.empty()) return w;\n    const double minW = 1e-6;\n    const double lr_main = 0.05;\n    const double lr_eq = 0.04;\n    const double reg = 1e-4;\n    uniform_int_distribution<int> qdist(0, (int)queries.size() - 1);\n    int iterations = min(200000, max(20000, 30 * (int)queries.size()));\n\n    for (int iter = 0; iter < iterations; ++iter) {\n        const Query& qu = queries[qdist(rng)];\n        if (qu.idx.empty()) continue;\n        double diff = 0.0;\n        for (size_t k = 0; k < qu.idx.size(); ++k) diff += w[qu.idx[k]] * qu.coeff[k];\n\n        if (qu.result == 0) {\n            double grad_base = diff * qu.invScaleSq;\n            for (size_t k = 0; k < qu.idx.size(); ++k) {\n                int idx = qu.idx[k];\n                double grad = grad_base * qu.coeff[k] + reg * w[idx];\n                w[idx] -= lr_eq * grad;\n                if (w[idx] < minW) w[idx] = minW;\n            }\n        } else {\n            int y = qu.result;\n            double score = diff * qu.invScale;\n            double s = y * score;\n            double sigma;\n            if (s >= 0) {\n                double e = exp(-s);\n                sigma = e / (1.0 + e);\n            } else {\n                double e = exp(s);\n                sigma = 1.0 / (1.0 + e);\n            }\n            double grad_base = -y * sigma * qu.invScale;\n            for (size_t k = 0; k < qu.idx.size(); ++k) {\n                int idx = qu.idx[k];\n                double grad = grad_base * qu.coeff[k] + reg * w[idx];\n                w[idx] -= lr_main * grad;\n                if (w[idx] < minW) w[idx] = minW;\n            }\n        }\n\n        if ((iter & 255) == 0) {\n            double mean = 0.0;\n            for (double val : w) mean += val;\n            mean /= N;\n            if (mean > 0) for (double &val : w) val /= mean;\n        }\n    }\n\n    double perceptron_lr = 0.02;\n    for (int pass = 0; pass < 2; ++pass) {\n        for (const Query& qu : queries) {\n            if (qu.idx.empty()) continue;\n            double diff = 0.0;\n            for (size_t k = 0; k < qu.idx.size(); ++k) diff += w[qu.idx[k]] * qu.coeff[k];\n            double margin = 0.05 * qu.scale;\n            bool violation = false;\n            if (qu.result == 1) {\n                if (diff < margin) violation = true;\n            } else if (qu.result == -1) {\n                if (diff > -margin) violation = true;\n            } else {\n                if (fabs(diff) > margin) violation = true;\n            }\n            if (!violation) continue;\n\n            if (qu.result == 0) {\n                double grad_base = diff * qu.invScaleSq;\n                for (size_t k = 0; k < qu.idx.size(); ++k) {\n                    int idx = qu.idx[k];\n                    w[idx] -= perceptron_lr * grad_base * qu.coeff[k];\n                    if (w[idx] < minW) w[idx] = minW;\n                }\n            } else {\n                for (size_t k = 0; k < qu.idx.size(); ++k) {\n                    int idx = qu.idx[k];\n                    w[idx] += perceptron_lr * qu.result * qu.coeff[k];\n                    if (w[idx] < minW) w[idx] = minW;\n                }\n            }\n        }\n        double mean = 0.0;\n        for (double val : w) mean += val;\n        mean /= N;\n        if (mean > 0) for (double &val : w) val /= mean;\n    }\n\n    double sum = 0.0;\n    for (double val : w) sum += val;\n    if (sum > 0) {\n        double factor = (double)N / sum;\n        for (double &val : w) val *= factor;\n    }\n    return w;\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    vector<Query> queries;\n    queries.reserve(Q);\n    vector<double> biasScore(N, 0.0);\n\n    mt19937 rng(\n        (uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> uniform01(0.0, 1.0);\n\n    auto ask = [&](const vector<int>& L, const vector<int>& R) -> int {\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string resp;\n        if (!(cin >> resp)) exit(0);\n        int res = 0;\n        if (!resp.empty()) {\n            if (resp[0] == '>') res = 1;\n            else if (resp[0] == '<') res = -1;\n        }\n\n        Query q;\n        q.result = res;\n        q.idx.reserve(L.size() + R.size());\n        q.coeff.reserve(L.size() + R.size());\n        for (int x : L) { q.idx.push_back(x); q.coeff.push_back(1); }\n        for (int x : R) { q.idx.push_back(x); q.coeff.push_back(-1); }\n        int len = (int)q.idx.size();\n        if (len == 0) len = 1;\n        q.scale = sqrt((double)len);\n        q.invScale = 1.0 / q.scale;\n        q.invScaleSq = q.invScale * q.invScale;\n        queries.push_back(std::move(q));\n\n        if (res == 1) {\n            for (int x : L) biasScore[x] += 1.0;\n            for (int x : R) biasScore[x] -= 1.0;\n        } else if (res == -1) {\n            for (int x : L) biasScore[x] -= 1.0;\n            for (int x : R) biasScore[x] += 1.0;\n        }\n        return res;\n    };\n\n    int champion = 0;\n    for (int i = 1; i < N && (int)queries.size() < Q; ++i) {\n        vector<int> L = {champion};\n        vector<int> R = {i};\n        int res = ask(L, R);\n        if (res == -1) champion = i;\n    }\n\n    while ((int)queries.size() < Q) {\n        vector<int> L, R;\n        int type = rng() % 3;\n        if (type == 0) {\n            int a = rng() % N;\n            int b = rng() % N;\n            while (b == a) b = rng() % N;\n            L = {a};\n            R = {b};\n        } else if (type == 1) {\n            vector<int> picks;\n            picks.reserve(4);\n            while ((int)picks.size() < 4) {\n                int x = rng() % N;\n                bool ok = true;\n                for (int y : picks) if (y == x) { ok = false; break; }\n                if (ok) picks.push_back(x);\n            }\n            L = {picks[0], picks[1]};\n            R = {picks[2], picks[3]};\n        } else {\n            double density = 0.18 + 0.22 * (double)N / 100.0;\n            density = min(0.35, max(0.18, density));\n            for (int i = 0; i < N; ++i) {\n                double v = uniform01(rng);\n                if (v < density) L.push_back(i);\n                else if (v < 2.0 * density) R.push_back(i);\n            }\n            if (L.empty() && !R.empty()) {\n                L.push_back(R.back());\n                R.pop_back();\n            }\n            if (R.empty() && !L.empty()) {\n                R.push_back(L.back());\n                L.pop_back();\n            }\n            if (L.empty() || R.empty()) {\n                int a = rng() % N;\n                int b = rng() % N;\n                while (b == a) b = rng() % N;\n                L = {a};\n                R = {b};\n            }\n        }\n        ask(L, R);\n    }\n\n    vector<double> weights = estimate_weights(queries, N, rng);\n\n    double maxAbs = 0.0;\n    for (double s : biasScore) maxAbs = max(maxAbs, fabs(s));\n    if (maxAbs < 1e-9) maxAbs = 1.0;\n    const double alpha = 0.4;\n    for (int i = 0; i < N; ++i) {\n        double factor = 1.0 + alpha * (biasScore[i] / maxAbs);\n        weights[i] *= factor;\n        if (weights[i] < 1e-6) weights[i] = 1e-6;\n    }\n\n    double sum = 0.0;\n    for (double v : weights) sum += v;\n    if (sum > 0.0) {\n        double factor = (double)N / sum;\n        for (double &v : weights) v *= factor;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        double noise = 0.98 + 0.04 * uniform01(rng);\n        weights[i] *= noise;\n    }\n    sum = 0.0;\n    for (double v : weights) sum += v;\n    if (sum > 0.0) {\n        double factor = (double)N / sum;\n        for (double &v : weights) v *= factor;\n    }\n\n    double mean = 0.0;\n    for (double v : weights) mean += v;\n    mean /= N;\n    double var = 0.0;\n    for (double v : weights) {\n        double diff = v - mean;\n        var += diff * diff;\n    }\n    var /= N;\n    if (var < 1e-4) {\n        for (int i = 0; i < N; ++i) {\n            double factor = 1.0 + 0.5 * (biasScore[i] / maxAbs);\n            weights[i] = max(1e-6, factor);\n        }\n        sum = 0.0;\n        for (double v : weights) sum += v;\n        if (sum > 0.0) {\n            double factor = (double)N / sum;\n            for (double &v : weights) v *= factor;\n        }\n    }\n\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(),\n         [&](int a, int b) {\n             if (weights[a] != weights[b]) return weights[a] > weights[b];\n             return a < b;\n         });\n\n    vector<int> assignment(N, 0);\n    vector<double> bucket_sum(D, 0.0);\n    vector<int> bucket_size(D, 0);\n\n    for (int idx : order) {\n        int best = 0;\n        for (int d = 1; d < D; ++d) {\n            if (bucket_sum[d] + 1e-9 < bucket_sum[best]) best = d;\n            else if (fabs(bucket_sum[d] - bucket_sum[best]) <= 1e-9 &&\n                     bucket_size[d] < bucket_size[best]) best = d;\n        }\n        assignment[idx] = best;\n        bucket_sum[best] += weights[idx];\n        bucket_size[best] += 1;\n    }\n\n    double total = 0.0;\n    for (double s : bucket_sum) total += s;\n    double target = total / D;\n\n    if (D > 1) {\n        int LS_ITERS = 10000 + 200 * N;\n        uniform_int_distribution<int> distItem(0, N - 1);\n        uniform_int_distribution<int> distBucket(0, D - 1);\n        for (int iter = 0; iter < LS_ITERS; ++iter) {\n            if (rng() & 1) {\n                int i = distItem(rng);\n                int from = assignment[i];\n                int to = distBucket(rng);\n                if (from == to) continue;\n                double wi = weights[i];\n                double sa = bucket_sum[from];\n                double sb = bucket_sum[to];\n                double oldScore = (sa - target) * (sa - target) +\n                                  (sb - target) * (sb - target);\n                double na = sa - wi;\n                double nb = sb + wi;\n                double newScore = (na - target) * (na - target) +\n                                  (nb - target) * (nb - target);\n                if (newScore + 1e-9 < oldScore) {\n                    assignment[i] = to;\n                    bucket_sum[from] = na;\n                    bucket_sum[to] = nb;\n                    bucket_size[from]--;\n                    bucket_size[to]++;\n                }\n            } else {\n                int i = distItem(rng);\n                int j = distItem(rng);\n                if (assignment[i] == assignment[j]) continue;\n                int a = assignment[i];\n                int b = assignment[j];\n                double wi = weights[i];\n                double wj = weights[j];\n                double sa = bucket_sum[a];\n                double sb = bucket_sum[b];\n                double oldScore = (sa - target) * (sa - target) +\n                                  (sb - target) * (sb - target);\n                double na = sa - wi + wj;\n                double nb = sb - wj + wi;\n                double newScore = (na - target) * (na - target) +\n                                  (nb - target) * (nb - target);\n                if (newScore + 1e-9 < oldScore) {\n                    assignment[i] = b;\n                    assignment[j] = a;\n                    bucket_sum[a] = na;\n                    bucket_sum[b] = nb;\n                }\n            }\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << assignment[i];\n    }\n    cout << '\\n' << flush;\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int n, m;\n    struct Pos {\n        int stack = -1;\n        int idx = -1;\n    };\n    vector<vector<int>> stacks;\n    vector<Pos> pos;\n    vector<pair<int,int>> operations;\n    long long energy = 0;\n\n    int choose_destination(int source, int chunk_min) {\n        const int INF = 1e9;\n        int best = -1;\n        long long bestScore = (1LL << 62);\n        for (int i = 0; i < m; ++i) if (i != source) {\n            int topVal = stacks[i].empty() ? INF : stacks[i].back();\n            if (topVal >= chunk_min) {\n                long long score = (long long)stacks[i].size() * 1000LL - (long long)topVal;\n                if (score < bestScore) {\n                    bestScore = score;\n                    best = i;\n                }\n            }\n        }\n        if (best != -1) return best;\n\n        int bestIdx = -1;\n        int bestTop = -1;\n        int bestHeight = INT_MAX;\n        for (int i = 0; i < m; ++i) if (i != source) {\n            if (stacks[i].empty()) continue;\n            int topVal = stacks[i].back();\n            int height = (int)stacks[i].size();\n            if (topVal > bestTop ||\n                (topVal == bestTop && height < bestHeight) ||\n                (topVal == bestTop && height == bestHeight && i < bestIdx)) {\n                bestTop = topVal;\n                bestHeight = height;\n                bestIdx = i;\n            }\n        }\n        if (bestIdx != -1) return bestIdx;\n        for (int i = 0; i < m; ++i) if (i != source) return i; // fallback\n        return source; // should not happen\n    }\n\n    void move_segment(int box, int dest) {\n        auto p = pos[box];\n        int s = p.stack;\n        int idx = p.idx;\n        if (s == -1 || dest == -1 || s == dest) return;\n        vector<int> segment;\n        segment.reserve(stacks[s].size() - idx);\n        for (int i = idx; i < (int)stacks[s].size(); ++i) segment.push_back(stacks[s][i]);\n        stacks[s].resize(idx);\n        int destStart = stacks[dest].size();\n        stacks[dest].insert(stacks[dest].end(), segment.begin(), segment.end());\n        for (int t = 0; t < (int)segment.size(); ++t) {\n            pos[segment[t]].stack = dest;\n            pos[segment[t]].idx = destStart + t;\n        }\n        operations.emplace_back(box, dest + 1); // output is 1-indexed\n        energy += (long long)segment.size() + 1;\n    }\n\n    void remove_box(int box) {\n        auto p = pos[box];\n        int s = p.stack;\n        int idx = p.idx;\n        if (s == -1) return;\n        stacks[s].pop_back();\n        pos[box].stack = -1;\n        pos[box].idx = -1;\n        operations.emplace_back(box, 0);\n    }\n\n    void solve() {\n        cin >> n >> m;\n        stacks.assign(m, {});\n        pos.assign(n + 1, {});\n        int stackLen = n / m;\n        for (int i = 0; i < m; ++i) {\n            stacks[i].resize(stackLen);\n            for (int j = 0; j < stackLen; ++j) {\n                int v; cin >> v;\n                stacks[i][j] = v;\n                pos[v].stack = i;\n                pos[v].idx = j;\n            }\n        }\n\n        for (int v = 1; v <= n; ++v) {\n            while (true) {\n                auto p = pos[v];\n                int s = p.stack;\n                if (s == -1) break; // already removed\n                int idx = p.idx;\n                if (idx == (int)stacks[s].size() - 1) {\n                    remove_box(v);\n                    break;\n                } else {\n                    int start = idx + 1;\n                    int chunk_min = INT_MAX;\n                    for (int t = start; t < (int)stacks[s].size(); ++t) {\n                        chunk_min = min(chunk_min, stacks[s][t]);\n                    }\n                    int dest = choose_destination(s, chunk_min);\n                    if (dest == s) {\n                        for (int i = 0; i < m; ++i) if (i != s) { dest = i; break; }\n                        if (dest == s) break; // should not occur unless m=1\n                    }\n                    int box_to_move = stacks[s][start];\n                    move_segment(box_to_move, dest);\n                }\n            }\n        }\n\n        for (auto [v, i] : operations) {\n            cout << v << ' ' << i << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MOVE_LIMIT = 100000;\n    static constexpr double TIME_LIMIT = 1.78;\n    const array<int,4> dr = {-1, 1, 0, 0};\n    const array<int,4> dc = {0, 0, -1, 1};\n    const array<char,4> dirChar = {'U', 'D', 'L', 'R'};\n    const array<char,4> oppChar = {'D', 'U', 'R', 'L'};\n\n    int N, totalNodes;\n    vector<string> h, v;\n    vector<vector<int>> d;\n    vector<int> d_flat;\n    vector<vector<int>> adj_base;\n    vector<array<int,4>> dirNeighbor;\n    vector<int> node_r, node_c;\n    vector<vector<int>> visitTimes;\n\n    mt19937 rng;\n    chrono::steady_clock::time_point start_time;\n\n    Solver() : rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n        read_input();\n    }\n\n    void read_input() {\n        cin >> N;\n        h.resize(max(0, N - 1));\n        for (int i = 0; i < N - 1; ++i) cin >> h[i];\n        v.resize(N);\n        for (int i = 0; i < N; ++i) cin >> v[i];\n        d.assign(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        totalNodes = N * N;\n        node_r.resize(totalNodes);\n        node_c.resize(totalNodes);\n        d_flat.resize(totalNodes);\n        adj_base.assign(totalNodes, {});\n        dirNeighbor.assign(totalNodes, array<int,4>{-1, -1, -1, -1});\n        int idx = 0;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                node_r[idx] = i;\n                node_c[idx] = j;\n                d_flat[idx] = d[i][j];\n                idx++;\n            }\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int u = i * N + j;\n                if (i + 1 < N && h[i][j] == '0') {\n                    int vIdx = (i + 1) * N + j;\n                    adj_base[u].push_back(vIdx);\n                    adj_base[vIdx].push_back(u);\n                    dirNeighbor[u][1] = vIdx;\n                    dirNeighbor[vIdx][0] = u;\n                }\n                if (j + 1 < N && v[i][j] == '0') {\n                    int vIdx = i * N + (j + 1);\n                    adj_base[u].push_back(vIdx);\n                    adj_base[vIdx].push_back(u);\n                    dirNeighbor[u][3] = vIdx;\n                    dirNeighbor[vIdx][2] = u;\n                }\n            }\n        }\n        visitTimes.assign(totalNodes, {});\n    }\n\n    vector<vector<int>> shuffled_adj() {\n        auto adj = adj_base;\n        for (auto &vec : adj) {\n            shuffle(vec.begin(), vec.end(), rng);\n        }\n        return adj;\n    }\n\n    bool shortest_path(int start, int goal, const vector<vector<int>>& adj,\n                       vector<int>& prev, vector<int>& dist, vector<int>& que,\n                       vector<int>& path) {\n        path.clear();\n        if (start == goal) {\n            path.push_back(start);\n            return true;\n        }\n        fill(dist.begin(), dist.end(), -1);\n        fill(prev.begin(), prev.end(), -1);\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        dist[start] = 0;\n        while (head < tail) {\n            int u = que[head++];\n            if (u == goal) break;\n            for (int vtx : adj[u]) {\n                if (dist[vtx] == -1) {\n                    dist[vtx] = dist[u] + 1;\n                    prev[vtx] = u;\n                    que[tail++] = vtx;\n                }\n            }\n        }\n        if (dist[goal] == -1) return false;\n        int cur = goal;\n        while (cur != -1) {\n            path.push_back(cur);\n            if (cur == start) break;\n            cur = prev[cur];\n        }\n        reverse(path.begin(), path.end());\n        return true;\n    }\n\n    bool find_nearest(int start, const vector<char>& visited, const vector<vector<int>>& adj,\n                      vector<int>& prev, vector<int>& dist, vector<int>& que,\n                      vector<int>& path) {\n        path.clear();\n        fill(dist.begin(), dist.end(), -1);\n        fill(prev.begin(), prev.end(), -1);\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        dist[start] = 0;\n        int target = -1;\n        while (head < tail) {\n            int u = que[head++];\n            if (u != start && !visited[u]) {\n                target = u;\n                break;\n            }\n            for (int nxt : adj[u]) {\n                if (dist[nxt] == -1) {\n                    dist[nxt] = dist[u] + 1;\n                    prev[nxt] = u;\n                    que[tail++] = nxt;\n                }\n            }\n        }\n        if (target == -1) return false;\n        int cur = target;\n        while (cur != -1) {\n            path.push_back(cur);\n            if (cur == start) break;\n            cur = prev[cur];\n        }\n        reverse(path.begin(), path.end());\n        return true;\n    }\n\n    char move_char(int from, int to) const {\n        int r1 = node_r[from], c1 = node_c[from];\n        int r2 = node_r[to], c2 = node_c[to];\n        if (r2 == r1 - 1 && c2 == c1) return 'U';\n        if (r2 == r1 + 1 && c2 == c1) return 'D';\n        if (r2 == r1 && c2 == c1 - 1) return 'L';\n        if (r2 == r1 && c2 == c1 + 1) return 'R';\n        return '?';\n    }\n\n    bool follow_path(const vector<int>& path, string& route,\n                     vector<char>& visited, int& visited_cnt, int& pos) {\n        for (size_t idx = 1; idx < path.size(); ++idx) {\n            int from = path[idx - 1];\n            int to = path[idx];\n            char mv = move_char(from, to);\n            if (mv == '?') return false;\n            route.push_back(mv);\n            pos = to;\n            if (!visited[pos]) {\n                visited[pos] = 1;\n                ++visited_cnt;\n            }\n            if ((int)route.size() > MOVE_LIMIT) return false;\n        }\n        return true;\n    }\n\n    string build_route_nearest(const vector<vector<int>>& adj) {\n        vector<char> visited(totalNodes, 0);\n        visited[0] = 1;\n        int visited_cnt = 1;\n        int pos = 0;\n        string route;\n        route.reserve(min(MOVE_LIMIT, max(100, totalNodes * 3)));\n\n        vector<int> dist(totalNodes, -1), prev(totalNodes, -1), que(totalNodes);\n        vector<int> path;\n        path.reserve(totalNodes);\n\n        while (visited_cnt < totalNodes) {\n            if (!find_nearest(pos, visited, adj, prev, dist, que, path)) return \"\";\n            if (!follow_path(path, route, visited, visited_cnt, pos)) return \"\";\n        }\n\n        if (!shortest_path(pos, 0, adj, prev, dist, que, path)) return \"\";\n        if (!follow_path(path, route, visited, visited_cnt, pos)) return \"\";\n        if (pos != 0) return \"\";\n        if (visited_cnt != totalNodes) return \"\";\n        return route;\n    }\n\n    vector<vector<int>> build_tree_adj(const vector<vector<int>>& adj) {\n        vector<vector<int>> tree(totalNodes);\n        vector<char> seen(totalNodes, 0);\n        vector<int> que(totalNodes);\n        int head = 0, tail = 0;\n        que[tail++] = 0;\n        seen[0] = 1;\n        while (head < tail) {\n            int u = que[head++];\n            for (int vtx : adj[u]) {\n                if (!seen[vtx]) {\n                    seen[vtx] = 1;\n                    tree[u].push_back(vtx);\n                    que[tail++] = vtx;\n                }\n            }\n        }\n        for (auto &childs : tree) {\n            shuffle(childs.begin(), childs.end(), rng);\n        }\n        return tree;\n    }\n\n    string build_route_order(const vector<vector<int>>& adj) {\n        auto tree = build_tree_adj(adj);\n        vector<int> order;\n        order.reserve(totalNodes);\n        auto dfs = [&](auto&& self, int u) -> void {\n            order.push_back(u);\n            for (int vtx : tree[u]) self(self, vtx);\n        };\n        dfs(dfs, 0);\n\n        vector<char> visited(totalNodes, 0);\n        visited[0] = 1;\n        int visited_cnt = 1;\n        int pos = 0;\n        string route;\n        route.reserve(min(MOVE_LIMIT, max(100, totalNodes * 3)));\n\n        vector<int> dist(totalNodes, -1), prev(totalNodes, -1), que(totalNodes);\n        vector<int> path;\n        path.reserve(totalNodes);\n\n        int ptr = 0;\n        while (visited_cnt < totalNodes) {\n            while (ptr < totalNodes && visited[order[ptr]]) ptr++;\n            if (ptr >= totalNodes) break;\n            int target = order[ptr];\n            if (!shortest_path(pos, target, adj, prev, dist, que, path)) return \"\";\n            if (!follow_path(path, route, visited, visited_cnt, pos)) return \"\";\n        }\n\n        if (!shortest_path(pos, 0, adj, prev, dist, que, path)) return \"\";\n        if (!follow_path(path, route, visited, visited_cnt, pos)) return \"\";\n\n        if (pos != 0) return \"\";\n        if (visited_cnt != totalNodes) return \"\";\n        return route;\n    }\n\n    int char_dir(char c) const {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        if (c == 'R') return 3;\n        return -1;\n    }\n\n    long double evaluate(const string& route) {\n        if (route.empty() || (int)route.size() > MOVE_LIMIT) return 1e100L;\n        for (auto &vec : visitTimes) vec.clear();\n        int pos = 0;\n        int stepCount = route.size();\n        for (int i = 0; i < stepCount; ++i) {\n            int dir = char_dir(route[i]);\n            if (dir == -1) return 1e100L;\n            int nxt = dirNeighbor[pos][dir];\n            if (nxt == -1) return 1e100L;\n            pos = nxt;\n            visitTimes[pos].push_back(i + 1);\n        }\n        if (pos != 0) return 1e100L;\n        long double total = 0.0L;\n        for (int idx = 0; idx < totalNodes; ++idx) {\n            auto &vec = visitTimes[idx];\n            if (vec.empty()) return 1e100L;\n            int k = vec.size();\n            for (int j = 0; j < k; ++j) {\n                long long cur = vec[j];\n                long long nxt = (j + 1 < k) ? vec[j + 1] : (long long)vec[0] + stepCount;\n                long long delta = nxt - cur;\n                total += (long double)d_flat[idx] * (long double)delta * (delta - 1) / 2.0L;\n            }\n        }\n        return total / (long double)stepCount;\n    }\n\n    string build_dfs_route() {\n        string route;\n        route.reserve(totalNodes * 2);\n        vector<vector<char>> vis(N, vector<char>(N, 0));\n        auto dfs = [&](auto&& self, int r, int c) -> void {\n            vis[r][c] = 1;\n            array<int,4> order = {1, 3, 0, 2}; // D, R, U, L preference\n            for (int t = 0; t < 4; ++t) {\n                int dir = order[t];\n                int nr = r + dr[dir];\n                int nc = c + dc[dir];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                if (dir == 0 && h[r - 1][c] == '1') continue;\n                if (dir == 1 && h[r][c] == '1') continue;\n                if (dir == 2 && v[r][c - 1] == '1') continue;\n                if (dir == 3 && v[r][c] == '1') continue;\n                if (!vis[nr][nc]) {\n                    route.push_back(dirChar[dir]);\n                    self(self, nr, nc);\n                    route.push_back(oppChar[dir]);\n                }\n            }\n        };\n        dfs(dfs, 0, 0);\n        return route;\n    }\n\n    double elapsed() const {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - start_time).count();\n    }\n\n    void solve() {\n        start_time = chrono::steady_clock::now();\n        string bestRoute = build_dfs_route();\n        long double bestScore = evaluate(bestRoute);\n        int iter = 0;\n        while (elapsed() < TIME_LIMIT) {\n            auto adj = shuffled_adj();\n            string route;\n            if (iter % 2 == 0) {\n                route = build_route_nearest(adj);\n            } else {\n                route = build_route_order(adj);\n            }\n            iter++;\n            if (route.empty()) continue;\n            long double score = evaluate(route);\n            if (score < bestScore) {\n                bestScore = score;\n                bestRoute = route;\n            }\n        }\n        cout << bestRoute << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer for time-limited heuristics\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n};\n\n// Simple xorshift RNG (deterministic seed derived from input -> deterministic result per case)\nstruct XorShift64 {\n    unsigned long long x;\n    XorShift64(unsigned long long seed = 88172645463393265ull) : x(seed) {}\n    unsigned long long next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {  // returns [0, n)\n        return static_cast<int>(next() % n);\n    }\n    double nextDouble() { // returns [0,1)\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n};\n\nint calcOverlap(const string &a, const string &b) {\n    const int L = 5;\n    for (int len = L - 1; len >= 0; --len) {\n        bool ok = true;\n        for (int k = 0; k < len; ++k) {\n            if (a[L - len + k] != b[k]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) return len;\n    }\n    return 0;\n}\n\nint computeOrderCost(const vector<int>& order, const vector<vector<int>>& cost) {\n    if (order.empty()) return 0;\n    int total = 5;\n    for (size_t i = 0; i + 1 < order.size(); ++i) {\n        total += cost[order[i]][order[i + 1]];\n    }\n    return total;\n}\n\nint swapDelta(const vector<int>& order, int i, int j, const vector<vector<int>>& cost) {\n    if (i == j) return 0;\n    if (i > j) swap(i, j);\n    int n = order.size();\n    int a = order[i];\n    int b = order[j];\n    auto edge = [&](int u, int v) -> int {\n        if (u < 0 || v < 0) return 0;\n        return cost[u][v];\n    };\n    int delta = 0;\n    if (j == i + 1) { // adjacent swap\n        int li = (i > 0) ? order[i - 1] : -1;\n        int rj = (j + 1 < n) ? order[j + 1] : -1;\n        int before = 0, after = 0;\n        if (li != -1) before += edge(li, a);\n        before += edge(a, b);\n        if (rj != -1) before += edge(b, rj);\n        if (li != -1) after += edge(li, b);\n        after += edge(b, a);\n        if (rj != -1) after += edge(a, rj);\n        delta = after - before;\n    } else {\n        int li = (i > 0) ? order[i - 1] : -1;\n        int ri = (i + 1 < n) ? order[i + 1] : -1;\n        int lj = (j > 0) ? order[j - 1] : -1;\n        int rj = (j + 1 < n) ? order[j + 1] : -1;\n        int before = 0, after = 0;\n        if (li != -1) before += edge(li, a);\n        if (ri != -1) before += edge(a, ri);\n        if (lj != -1) before += edge(lj, b);\n        if (rj != -1) before += edge(b, rj);\n        if (li != -1) after += edge(li, b);\n        if (ri != -1) after += edge(b, ri);\n        if (lj != -1) after += edge(lj, a);\n        if (rj != -1) after += edge(a, rj);\n        delta = after - before;\n    }\n    return delta;\n}\n\nvoid hillClimb(vector<int>& order, int &costVal, const vector<vector<int>>& cost) {\n    int n = order.size();\n    while (true) {\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1;\n        for (int i = 0; i < n; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                int delta = swapDelta(order, i, j, cost);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                }\n            }\n        }\n        if (bestDelta < 0) {\n            swap(order[bestI], order[bestJ]);\n            costVal += bestDelta;\n        } else break;\n    }\n}\n\nvector<int> buildInitialOrder(const vector<vector<int>>& cost, const vector<int>& sumOut, int &bestCost) {\n    int n = cost.size();\n    vector<int> bestOrder;\n    bestCost = INT_MAX;\n    vector<int> order;\n    order.reserve(n);\n    vector<char> used(n);\n    for (int start = 0; start < n; ++start) {\n        fill(used.begin(), used.end(), 0);\n        order.clear();\n        int cur = start;\n        while (true) {\n            order.push_back(cur);\n            used[cur] = 1;\n            if ((int)order.size() == n) break;\n            int bestNext = -1;\n            int bestEdge = INT_MAX;\n            for (int nxt = 0; nxt < n; ++nxt) {\n                if (used[nxt]) continue;\n                int c = cost[cur][nxt];\n                if (bestNext == -1 || c < bestEdge) {\n                    bestEdge = c;\n                    bestNext = nxt;\n                } else if (c == bestEdge) {\n                    if (sumOut[nxt] < sumOut[bestNext] || (sumOut[nxt] == sumOut[bestNext] && nxt < bestNext)) {\n                        bestNext = nxt;\n                    }\n                }\n            }\n            cur = bestNext;\n        }\n        int len = computeOrderCost(order, cost);\n        if (len < bestCost) {\n            bestCost = len;\n            bestOrder = order;\n        }\n    }\n    return bestOrder;\n}\n\nvoid simulatedAnnealing(vector<int>& bestOrder, int &bestCost, const vector<vector<int>>& costMatrix,\n                        XorShift64& rng, Timer& timer, double timeLimit) {\n    if (timeLimit <= 1e-4) return;\n    int n = bestOrder.size();\n    vector<int> currentOrder = bestOrder;\n    int currentCost = bestCost;\n    vector<int> localBestOrder = bestOrder;\n    int localBestCost = bestCost;\n    double startTime = timer.elapsed();\n    double endTime = startTime + timeLimit;\n    const double START_TEMP = 2.5;\n    const double END_TEMP = 0.05;\n    while (true) {\n        double now = timer.elapsed();\n        if (now >= endTime) break;\n        double progress = (now - startTime) / timeLimit;\n        if (progress > 1.0) progress = 1.0;\n        double temp = START_TEMP + (END_TEMP - START_TEMP) * progress;\n        if (temp < 1e-4) temp = 1e-4;\n        int i = rng.nextInt(n);\n        int j = rng.nextInt(n);\n        if (i == j) continue;\n        int delta = swapDelta(currentOrder, i, j, costMatrix);\n        bool accept = false;\n        if (delta <= 0) {\n            accept = true;\n        } else {\n            double prob = exp(-delta / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n        if (accept) {\n            swap(currentOrder[i], currentOrder[j]);\n            currentCost += delta;\n            if (currentCost < localBestCost) {\n                localBestCost = currentCost;\n                localBestOrder = currentOrder;\n            }\n        }\n    }\n    bestOrder = localBestOrder;\n    bestCost = localBestCost;\n}\n\nvector<int> buildTypingPlan(const string& S, int N, int si, int sj,\n                            const vector<vector<int>>& cellsByChar,\n                            const vector<int>& rowOfCell,\n                            const vector<int>& colOfCell) {\n    const int INF = 1e9;\n    int L = (int)S.size();\n    vector<int> charIdx(L);\n    for (int i = 0; i < L; ++i) charIdx[i] = S[i] - 'A';\n    vector<vector<int>> dp(L);\n    vector<vector<int16_t>> parent(L);\n    for (int pos = 0; pos < L; ++pos) {\n        int c = charIdx[pos];\n        const auto &cells = cellsByChar[c];\n        int m = cells.size();\n        dp[pos].assign(m, INF);\n        parent[pos].assign(m, -1);\n        if (pos == 0) {\n            for (int idx = 0; idx < m; ++idx) {\n                int cell = cells[idx];\n                dp[pos][idx] = abs(rowOfCell[cell] - si) + abs(colOfCell[cell] - sj) + 1;\n            }\n        } else {\n            int prevChar = charIdx[pos - 1];\n            const auto &prevCells = cellsByChar[prevChar];\n            for (int idx = 0; idx < m; ++idx) {\n                int cell = cells[idx];\n                int bestVal = INF;\n                int bestPrev = -1;\n                for (int p = 0; p < (int)prevCells.size(); ++p) {\n                    int prevCell = prevCells[p];\n                    int prevCost = dp[pos - 1][p];\n                    if (prevCost >= INF) continue;\n                    int dist = abs(rowOfCell[cell] - rowOfCell[prevCell]) +\n                               abs(colOfCell[cell] - colOfCell[prevCell]);\n                    int cand = prevCost + dist + 1;\n                    if (cand < bestVal) {\n                        bestVal = cand;\n                        bestPrev = p;\n                    }\n                }\n                dp[pos][idx] = bestVal;\n                parent[pos][idx] = bestPrev;\n            }\n        }\n    }\n    int lastPos = L - 1;\n    const auto &lastCells = cellsByChar[charIdx[lastPos]];\n    int bestIdx = 0;\n    int bestVal = dp[lastPos][0];\n    for (int idx = 1; idx < (int)lastCells.size(); ++idx) {\n        if (dp[lastPos][idx] < bestVal) {\n            bestVal = dp[lastPos][idx];\n            bestIdx = idx;\n        }\n    }\n    vector<int> path(L);\n    int idx = bestIdx;\n    for (int pos = L - 1; pos >= 0; --pos) {\n        const auto &cells = cellsByChar[charIdx[pos]];\n        path[pos] = cells[idx];\n        if (pos == 0) break;\n        idx = parent[pos][idx];\n        if (idx < 0) idx = 0; // should not happen, but keep safe\n    }\n    return path;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TOTAL_TIME_LIMIT = 1.90;\n    const double RESERVED_TIME = 0.15;\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n    vector<string> words(M);\n    for (int i = 0; i < M; ++i) cin >> words[i];\n\n    const int cellsCnt = N * N;\n    vector<int> rowOfCell(cellsCnt), colOfCell(cellsCnt);\n    vector<vector<int>> cellsByChar(26);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int idx = i * N + j;\n            rowOfCell[idx] = i;\n            colOfCell[idx] = j;\n            int c = grid[i][j] - 'A';\n            cellsByChar[c].push_back(idx);\n        }\n    }\n\n    // deterministic seed for RNG based on input\n    uint64_t seed = 123456789123ull;\n    seed = seed * 1000003 + si * 97 + sj * 131;\n    for (auto &row : grid) for (char c : row) seed = seed * 1000003 + (unsigned char)c;\n    for (auto &w : words) for (char c : w) seed = seed * 1000003 + (unsigned char)c;\n    XorShift64 rng(seed);\n\n    vector<vector<int>> overlap(M, vector<int>(M));\n    vector<vector<int>> cost(M, vector<int>(M, 5));\n    for (int i = 0; i < M; ++i) {\n        for (int j = 0; j < M; ++j) {\n            if (i == j) continue;\n            int ov = calcOverlap(words[i], words[j]);\n            overlap[i][j] = ov;\n            cost[i][j] = 5 - ov;\n        }\n    }\n    vector<int> sumOut(M, 0);\n    for (int i = 0; i < M; ++i) {\n        int s = 0;\n        for (int j = 0; j < M; ++j) {\n            if (i == j) continue;\n            s += cost[i][j];\n        }\n        sumOut[i] = s;\n    }\n\n    int initialCost = 0;\n    vector<int> order = buildInitialOrder(cost, sumOut, initialCost);\n    if (order.empty()) {\n        // fallback (should never happen)\n        order.resize(M);\n        iota(order.begin(), order.end(), 0);\n        initialCost = computeOrderCost(order, cost);\n    }\n    hillClimb(order, initialCost, cost);\n    vector<int> bestOrder = order;\n    int bestCost = initialCost;\n\n    double elapsed = timer.elapsed();\n    double remaining = TOTAL_TIME_LIMIT - elapsed - RESERVED_TIME;\n    if (remaining > 0.02) {\n        simulatedAnnealing(order, initialCost, cost, rng, timer, remaining);\n        hillClimb(order, initialCost, cost);\n        if (initialCost < bestCost) {\n            bestCost = initialCost;\n            bestOrder = order;\n        }\n    }\n\n    // Build final string\n    string S = words[bestOrder[0]];\n    for (int i = 1; i < M; ++i) {\n        int prv = bestOrder[i - 1];\n        int cur = bestOrder[i];\n        int ov = overlap[prv][cur];\n        S.append(words[cur], ov, string::npos);\n    }\n    if ((int)S.size() > 5000) {\n        // fallback (should never happen)\n        S.resize(5000);\n    }\n\n    vector<int> path = buildTypingPlan(S, N, si, sj, cellsByChar, rowOfCell, colOfCell);\n\n    for (int cell : path) {\n        cout << rowOfCell[cell] << ' ' << colOfCell[cell] << '\\n';\n    }\n    return 0;\n}","ahc030":"#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    double eps;\n    if (!(cin >> N >> M >> eps)) return 0;\n\n    // Read polyomino shapes (unused in this baseline strategy, but parsing is required).\n    vector<vector<pair<int,int>>> shapes(M);\n    for (int k = 0; k < M; ++k) {\n        int d;\n        cin >> d;\n        shapes[k].resize(d);\n        for (int t = 0; t < d; ++t) {\n            int i, j;\n            cin >> i >> j;\n            shapes[k][t] = {i, j};\n        }\n    }\n\n    vector<pair<int,int>> has_oil;\n    has_oil.reserve(N * N);\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cout << \"q 1 \" << i << ' ' << j << '\\n' << flush;\n            int val;\n            if (!(cin >> val)) return 0; // Safety\n            if (val > 0) has_oil.emplace_back(i, j);\n        }\n    }\n\n    cout << \"a \" << has_oil.size();\n    for (auto [i, j] : has_oil) {\n        cout << ' ' << i << ' ' << j;\n    }\n    cout << '\\n' << flush;\n\n    int verdict;\n    if (!(cin >> verdict)) return 0;\n    // Since we drilled all cells, the answer should be correct (verdict == 1).\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RectInfo {\n    int i0 = 0, j0 = 0, i1 = 1, j1 = 1;\n    long long area = 1;\n};\n\nint W, D, N;\nvector<vector<int>> demands;\nvector<long long> target_area;\nvector<RectInfo> rects;\n\nvoid build_rectangles(const vector<int>& ids, int x0, int y0, int x1, int y1) {\n    if (ids.empty()) return;\n    int h = x1 - x0;\n    int w = y1 - y0;\n    if (ids.size() == 1) {\n        RectInfo &r = rects[ids[0]];\n        r.i0 = x0; r.j0 = y0; r.i1 = x1; r.j1 = y1;\n        r.area = 1LL * (r.i1 - r.i0) * (r.j1 - r.j0);\n        return;\n    }\n\n    vector<long long> prefix(ids.size() + 1, 0);\n    long long total = 0;\n    for (int i = 0; i < (int)ids.size(); ++i) {\n        total += target_area[ids[i]];\n        prefix[i + 1] = total;\n    }\n\n    int bestMid = 1;\n    long long bestDiff = (1LL << 62);\n    for (int mid = 1; mid < (int)ids.size(); ++mid) {\n        long long leftSum = prefix[mid];\n        long long diff = llabs(leftSum * 2 - total);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestMid = mid;\n        }\n    }\n\n    vector<int> left(ids.begin(), ids.begin() + bestMid);\n    vector<int> right(ids.begin() + bestMid, ids.end());\n    long long sumLeft = prefix[bestMid];\n    long long sumRight = total - sumLeft;\n\n    bool splitHorizontal;\n    if (h >= 2 && w >= 2) splitHorizontal = (h >= w);\n    else if (h >= 2) splitHorizontal = true;\n    else splitHorizontal = false; // width >= 2 here\n\n    if (splitHorizontal) {\n        int split = (int)llround((long double)h * sumLeft / total);\n        split = max(1, min(h - 1, split));\n        long long minTop = max<long long>(1, (sumLeft + w - 1) / w);\n        long long maxTop = min<long long>(h - 1, h - max<long long>(1, (sumRight + w - 1) / w));\n        if (minTop <= maxTop) {\n            if (split < minTop) split = (int)minTop;\n            if (split > maxTop) split = (int)maxTop;\n        }\n        split = max(1, min(h - 1, split));\n        build_rectangles(left,  x0,       y0, x0 + split, y1);\n        build_rectangles(right, x0 + split, y0, x1,       y1);\n    } else {\n        int split = (int)llround((long double)w * sumLeft / total);\n        split = max(1, min(w - 1, split));\n        long long minLeft = max<long long>(1, (sumLeft + h - 1) / h);\n        long long maxLeft = min<long long>(w - 1, w - max<long long>(1, (sumRight + h - 1) / h));\n        if (minLeft <= maxLeft) {\n            if (split < minLeft) split = (int)minLeft;\n            if (split > maxLeft) split = (int)maxLeft;\n        }\n        split = max(1, min(w - 1, split));\n        build_rectangles(left,  x0, y0,       x1, y0 + split);\n        build_rectangles(right, x0, y0 + split, x1, y1);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> W >> D >> N)) return 0;\n    demands.assign(D, vector<int>(N));\n    for (int d = 0; d < D; ++d) for (int k = 0; k < N; ++k) cin >> demands[d][k];\n\n    vector<vector<int>> orderStats(N, vector<int>(D));\n    for (int j = 0; j < N; ++j) {\n        for (int d = 0; d < D; ++d) orderStats[j][d] = demands[d][N - 1 - j]; // kth largest\n        sort(orderStats[j].begin(), orderStats[j].end());\n    }\n\n    const int baseMin = 1;\n    target_area.assign(N, baseMin);\n    long long remaining = 1LL * W * W - 1LL * baseMin * N;\n\n    vector<int> idx(N, 0);\n    struct Node { int benefit; long long len; int j; };\n    struct PQCmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.benefit != b.benefit) return a.benefit < b.benefit;\n            if (a.len != b.len) return a.len < b.len;\n            return a.j > b.j;\n        }\n    };\n    priority_queue<Node, vector<Node>, PQCmp> pq;\n\n    auto pushNode = [&](int j) {\n        while (idx[j] < D && (long long)orderStats[j][idx[j]] <= target_area[j]) idx[j]++;\n        if (idx[j] >= D) return;\n        long long len = (long long)orderStats[j][idx[j]] - target_area[j];\n        if (len <= 0) return;\n        int benefit = D - idx[j];\n        if (benefit <= 0) return;\n        pq.push(Node{benefit, len, j});\n    };\n    for (int j = 0; j < N; ++j) pushNode(j);\n\n    while (remaining > 0 && !pq.empty()) {\n        Node node = pq.top(); pq.pop();\n        long long take = min(node.len, remaining);\n        target_area[node.j] += take;\n        remaining -= take;\n        node.len -= take;\n        if (node.len > 0) {\n            pq.push(node);\n        } else {\n            pushNode(node.j);\n        }\n    }\n\n    rects.assign(N, RectInfo());\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int x, int y) {\n        if (target_area[x] != target_area[y]) return target_area[x] > target_area[y];\n        return x < y;\n    });\n    build_rectangles(order, 0, 0, W, W);\n\n    for (int i = 0; i < N; ++i) {\n        rects[i].area = 1LL * (rects[i].i1 - rects[i].i0) * (rects[i].j1 - rects[i].j0);\n        if (rects[i].area <= 0) {\n            rects[i].i1 = rects[i].i0 + 1;\n            rects[i].j1 = rects[i].j0 + 1;\n            rects[i].area = 1;\n        }\n    }\n\n    vector<pair<long long, int>> rectOrder(N);\n    for (int i = 0; i < N; ++i) rectOrder[i] = {rects[i].area, i};\n    sort(rectOrder.begin(), rectOrder.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n\n    vector<vector<int>> assigned(D, vector<int>(N));\n    vector<pair<int, int>> req(N);\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) req[k] = {demands[d][k], k};\n        sort(req.begin(), req.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 t = 0; t < N; ++t) {\n            assigned[d][req[t].second] = rectOrder[t].second;\n        }\n    }\n\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) {\n            const RectInfo& r = rects[assigned[d][k]];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Operation {\n    int stamp;\n    int p, q;\n    array<int, 9> cells;\n    array<int, 9> adds;\n};\n\nstruct Solver {\n    static constexpr int MOD = 998244353;\n    int N, M, K;\n    vector<int> board_mod;\n    vector<Operation> ops;\n    vector<char> used;\n    vector<int> used_ops;\n    vector<int> pos_in_used;\n    long long current_score = 0;\n    long long best_score = 0;\n    vector<int> best_ops;\n\n    mt19937 rng;\n    uniform_real_distribution<double> dist01;\n\n    Solver() : rng(random_device{}()), dist01(0.0, 1.0) {}\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        auto global_start = chrono::steady_clock::now();\n\n        cin >> N >> M >> K;\n        vector<int> initial(N * N);\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                cin >> initial[i * N + j];\n            }\n        }\n        vector<array<array<int, 3>, 3>> stamps(M);\n        for (int m = 0; m < M; ++m) {\n            for (int i = 0; i < 3; ++i) {\n                for (int j = 0; j < 3; ++j) {\n                    cin >> stamps[m][i][j];\n                }\n            }\n        }\n\n        build_operations(stamps);\n\n        board_mod = initial;\n        used.assign(ops.size(), 0);\n        pos_in_used.assign(ops.size(), -1);\n        used_ops.clear();\n        used_ops.reserve(K);\n\n        current_score = 0;\n        for (int v : board_mod) current_score += v;\n        best_score = current_score;\n        best_ops = used_ops;\n\n        greedy_init();\n\n        constexpr double TOTAL_TIME_LIMIT = 1.90; // seconds\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n        double remaining = TOTAL_TIME_LIMIT - elapsed;\n        if (remaining > 0.05 && !ops.empty()) {\n            simulated_annealing(max(0.01, remaining - 0.01));\n        }\n\n        output_best();\n    }\n\n    void build_operations(const vector<array<array<int, 3>, 3>>& stamps) {\n        ops.clear();\n        int placements = (N - 2) * (N - 2);\n        ops.reserve(M * placements);\n        for (int m = 0; m < M; ++m) {\n            for (int p = 0; p <= N - 3; ++p) {\n                for (int q = 0; q <= N - 3; ++q) {\n                    Operation op;\n                    op.stamp = m;\n                    op.p = p;\n                    op.q = q;\n                    int idx = 0;\n                    for (int i = 0; i < 3; ++i) {\n                        for (int j = 0; j < 3; ++j) {\n                            op.cells[idx] = (p + i) * N + (q + j);\n                            op.adds[idx] = stamps[m][i][j];\n                            ++idx;\n                        }\n                    }\n                    ops.push_back(op);\n                }\n            }\n        }\n    }\n\n    long long apply_operation(int op_idx) {\n        const Operation& op = ops[op_idx];\n        long long delta = 0;\n        for (int t = 0; t < 9; ++t) {\n            int add = op.adds[t];\n            if (add == 0) continue;\n            int idx = op.cells[t];\n            int before = board_mod[idx];\n            int after = before + add;\n            if (after >= MOD) after -= MOD;\n            board_mod[idx] = after;\n            delta += after - before;\n        }\n        return delta;\n    }\n\n    long long remove_operation(int op_idx) {\n        const Operation& op = ops[op_idx];\n        long long delta = 0;\n        for (int t = 0; t < 9; ++t) {\n            int add = op.adds[t];\n            if (add == 0) continue;\n            int idx = op.cells[t];\n            int before = board_mod[idx];\n            int after = before - add;\n            if (after < 0) after += MOD;\n            board_mod[idx] = after;\n            delta += after - before;\n        }\n        return delta;\n    }\n\n    void greedy_init() {\n        for (int iter = 0; iter < K; ++iter) {\n            long long best_delta = 0;\n            int best_idx = -1;\n            for (int op_idx = 0; op_idx < (int)ops.size(); ++op_idx) {\n                if (used[op_idx]) continue;\n                const Operation& op = ops[op_idx];\n                long long delta = 0;\n                for (int t = 0; t < 9; ++t) {\n                    int add = op.adds[t];\n                    if (add == 0) continue;\n                    int idx = op.cells[t];\n                    int before = board_mod[idx];\n                    int after = before + add;\n                    if (after >= MOD) after -= MOD;\n                    delta += after - before;\n                }\n                if (delta > best_delta) {\n                    best_delta = delta;\n                    best_idx = op_idx;\n                }\n            }\n            if (best_idx == -1 || best_delta <= 0) break;\n            long long delta = apply_operation(best_idx);\n            current_score += delta;\n            used[best_idx] = 1;\n            pos_in_used[best_idx] = used_ops.size();\n            used_ops.push_back(best_idx);\n            if (current_score > best_score) {\n                best_score = current_score;\n                best_ops = used_ops;\n            }\n        }\n    }\n\n    int pick_random_unused() {\n        if ((int)used_ops.size() >= (int)ops.size()) return -1;\n        for (int attempt = 0; attempt < 32; ++attempt) {\n            int idx = rng() % ops.size();\n            if (!used[idx]) return idx;\n        }\n        for (int idx = 0; idx < (int)ops.size(); ++idx) {\n            if (!used[idx]) return idx;\n        }\n        return -1;\n    }\n\n    bool accept_move(long long delta, double temp) {\n        if (delta >= 0) return true;\n        if (temp <= 1e-9) return false;\n        double ratio = delta / temp;\n        if (ratio < -50.0) return false;\n        double prob = exp(ratio);\n        return dist01(rng) < prob;\n    }\n\n    void simulated_annealing(double time_limit) {\n        auto start = chrono::steady_clock::now();\n        auto end_time = start + chrono::duration<double>(time_limit);\n        const double START_TEMP = 5e8;\n        const double END_TEMP = 5e2;\n        double temp = START_TEMP;\n        long long iter = 0;\n\n        while (true) {\n            if ((iter & 63) == 0) {\n                auto now = chrono::steady_clock::now();\n                if (now >= end_time) break;\n                double elapsed = chrono::duration<double>(now - start).count();\n                double progress = min(1.0, max(0.0, elapsed / time_limit));\n                temp = START_TEMP + (END_TEMP - START_TEMP) * progress;\n                if (temp < 1.0) temp = 1.0;\n            }\n            ++iter;\n\n            int used_cnt = (int)used_ops.size();\n            int move_type;\n            if (used_cnt == 0) {\n                move_type = 0;\n            } else if (used_cnt >= K) {\n                move_type = (rng() & 1) ? 1 : 2;\n            } else {\n                move_type = rng() % 3;\n            }\n\n            if (move_type == 0) { // add\n                int op_idx = pick_random_unused();\n                if (op_idx == -1) continue;\n                long long delta = apply_operation(op_idx);\n                current_score += delta;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    used[op_idx] = 1;\n                    pos_in_used[op_idx] = used_ops.size();\n                    used_ops.push_back(op_idx);\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev = remove_operation(op_idx);\n                    current_score += rev;\n                }\n            } else if (move_type == 1) { // remove\n                if (used_cnt == 0) continue;\n                int pos = rng() % used_cnt;\n                int op_idx = used_ops[pos];\n                long long delta = remove_operation(op_idx);\n                current_score += delta;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    int last_op = used_ops.back();\n                    used_ops[pos] = last_op;\n                    pos_in_used[last_op] = pos;\n                    used_ops.pop_back();\n                    used[op_idx] = 0;\n                    pos_in_used[op_idx] = -1;\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev = apply_operation(op_idx);\n                    current_score += rev;\n                }\n            } else { // swap\n                if (used_cnt == 0) continue;\n                int op_add = pick_random_unused();\n                if (op_add == -1) continue;\n                int pos = rng() % used_cnt;\n                int op_remove = used_ops[pos];\n\n                long long delta_remove = remove_operation(op_remove);\n                current_score += delta_remove;\n\n                long long delta_add = apply_operation(op_add);\n                current_score += delta_add;\n\n                long long delta = delta_remove + delta_add;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    int last_op = used_ops.back();\n                    used_ops[pos] = last_op;\n                    pos_in_used[last_op] = pos;\n                    used_ops.pop_back();\n                    used[op_remove] = 0;\n                    pos_in_used[op_remove] = -1;\n\n                    used[op_add] = 1;\n                    pos_in_used[op_add] = used_ops.size();\n                    used_ops.push_back(op_add);\n\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev_add = remove_operation(op_add);\n                    current_score += rev_add;\n                    long long rev_remove = apply_operation(op_remove);\n                    current_score += rev_remove;\n                }\n            }\n        }\n    }\n\n    void output_best() const {\n        cout << best_ops.size() << '\\n';\n        for (int idx : best_ops) {\n            const Operation& op = ops[idx];\n            cout << op.stamp << ' ' << op.p << ' ' << op.q << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\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>> A(N, vector<int>(N));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) cin >> A[i][j];\n    }\n\n    vector<string> ops(N);\n    string mainOps;\n    int curR = 0, curC = 0;\n    auto move_to = [&](int tr, int tc) {\n        while (curR < tr) { mainOps.push_back('D'); ++curR; }\n        while (curR > tr) { mainOps.push_back('U'); --curR; }\n        while (curC < tc) { mainOps.push_back('R'); ++curC; }\n        while (curC > tc) { mainOps.push_back('L'); --curC; }\n    };\n\n    for (int src = 0; src < N; ++src) {\n        for (int idx = 0; idx < N; ++idx) {\n            move_to(src, 0);\n            mainOps.push_back('P');\n            int container = A[src][idx];\n            int target_row = container / N;\n            move_to(target_row, N - 1);\n            mainOps.push_back('Q');\n        }\n    }\n    if (mainOps.empty()) mainOps.push_back('.');  // safety, though not expected\n\n    ops[0] = mainOps;\n    int T = static_cast<int>(ops[0].size());\n\n    for (int i = 1; i < N; ++i) {\n        string s(max(T, 1), '.');\n        s[0] = 'B';  // bomb immediately\n        ops[i] = s;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << ops[i] << \"\\n\";\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\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    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) cin >> h[i][j];\n    }\n\n    vector<string> ops;\n    ops.reserve(120000);\n\n    int cur_r = 0, cur_c = 0;\n    long long load = 0;\n\n    auto moveTo = [&](int tr, int tc) {\n        while (cur_r < tr) { ops.emplace_back(\"D\"); ++cur_r; }\n        while (cur_r > tr) { ops.emplace_back(\"U\"); --cur_r; }\n        while (cur_c < tc) { ops.emplace_back(\"R\"); ++cur_c; }\n        while (cur_c > tc) { ops.emplace_back(\"L\"); --cur_c; }\n    };\n\n    auto hasPosNeg = [&]() -> pair<bool, bool> {\n        bool pos = false, neg = false;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (h[i][j] > 0) pos = true;\n                else if (h[i][j] < 0) neg = true;\n            }\n        }\n        return {pos, neg};\n    };\n\n    auto findNearest = [&](bool positive) -> pair<int, int> {\n        int bestDist = INT_MAX;\n        int bestAmount = -1;\n        pair<int, int> best{-1, -1};\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int val = h[i][j];\n                if (positive) {\n                    if (val <= 0) continue;\n                    int dist = abs(cur_r - i) + abs(cur_c - j);\n                    if (dist < bestDist || (dist == bestDist && val > bestAmount)) {\n                        bestDist = dist;\n                        bestAmount = val;\n                        best = {i, j};\n                    }\n                } else {\n                    if (val >= 0) continue;\n                    int need = -val;\n                    int dist = abs(cur_r - i) + abs(cur_c - j);\n                    if (dist < bestDist || (dist == bestDist && need > bestAmount)) {\n                        bestDist = dist;\n                        bestAmount = need;\n                        best = {i, j};\n                    }\n                }\n            }\n        }\n        return best;\n    };\n\n    int safety = 0;\n    const int SAFETY_LIMIT = 1000000;\n    while (safety < SAFETY_LIMIT) {\n        auto [hasPos, hasNeg] = hasPosNeg();\n        if (!hasPos && load == 0 && !hasNeg) break;\n\n        if (load == 0) {\n            if (!hasPos) break;\n            auto target = findNearest(true);\n            if (target.first == -1) break;\n            int tr = target.first, tc = target.second;\n            moveTo(tr, tc);\n            int amount = h[tr][tc];\n            if (amount <= 0) { ++safety; continue; }\n            ops.emplace_back(\"+\" + to_string(amount));\n            load += amount;\n            h[tr][tc] -= amount;\n        } else {\n            if (!hasNeg) {\n                moveTo(0, 0);\n                if (load > 0) {\n                    ops.emplace_back(\"-\" + to_string(load));\n                    h[0][0] += static_cast<int>(load);\n                    load = 0;\n                }\n                ++safety;\n                continue;\n            }\n            auto target = findNearest(false);\n            if (target.first == -1) {\n                moveTo(0, 0);\n                if (load > 0) {\n                    ops.emplace_back(\"-\" + to_string(load));\n                    h[0][0] += static_cast<int>(load);\n                    load = 0;\n                }\n                ++safety;\n                continue;\n            }\n            int tr = target.first, tc = target.second;\n            moveTo(tr, tc);\n            int need = -h[tr][tc];\n            if (need <= 0) { ++safety; continue; }\n            int amount = static_cast<int>(min<long long>(load, need));\n            if (amount <= 0) { ++safety; continue; }\n            ops.emplace_back(\"-\" + to_string(amount));\n            load -= amount;\n            h[tr][tc] += amount;\n        }\n        ++safety;\n    }\n\n    if (load > 0) {\n        moveTo(0, 0);\n        ops.emplace_back(\"-\" + to_string(load));\n        h[0][0] += static_cast<int>(load);\n        load = 0;\n    }\n\n    auto isAllZero = [&]() -> bool {\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                if (h[i][j] != 0) return false;\n        return true;\n    };\n\n    auto cleanupStep = [&]() {\n        if (load > 0) {\n            moveTo(0, 0);\n            ops.emplace_back(\"-\" + to_string(load));\n            h[0][0] += static_cast<int>(load);\n            load = 0;\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (i == 0 && j == 0) continue;\n                int val = h[i][j];\n                if (val <= 0) continue;\n                moveTo(i, j);\n                ops.emplace_back(\"+\" + to_string(val));\n                load += val;\n                h[i][j] -= val;\n                moveTo(0, 0);\n                ops.emplace_back(\"-\" + to_string(val));\n                load -= val;\n                h[0][0] += val;\n            }\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                while (h[i][j] < 0) {\n                    if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n                    int need = -h[i][j];\n                    int amount = min(need, h[0][0]);\n                    if (amount <= 0) return;\n                    ops.emplace_back(\"+\" + to_string(amount));\n                    load += amount;\n                    h[0][0] -= amount;\n                    moveTo(i, j);\n                    ops.emplace_back(\"-\" + to_string(amount));\n                    load -= amount;\n                    h[i][j] += amount;\n                }\n            }\n        }\n    };\n\n    int cleanupIter = 0;\n    while (!isAllZero() && cleanupIter < 2) {\n        cleanupStep();\n        ++cleanupIter;\n    }\n\n    if (load > 0) {\n        moveTo(0, 0);\n        ops.emplace_back(\"-\" + to_string(load));\n        h[0][0] += static_cast<int>(load);\n        load = 0;\n    }\n\n    for (const string &op : ops) cout << op << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAX_M = 15;\nconstexpr int MAX_TOTAL = 2000;  // > 15 * 100\n\nstruct Seed {\n    array<int, MAX_M> attr;\n    int value;\n    Seed() {\n        attr.fill(0);\n        value = 0;\n    }\n};\n\ndouble computePairScore(const Seed& A, const Seed& B,\n                        const vector<int>& targets,\n                        const vector<double>& weights,\n                        const vector<double>& probWeights,\n                        int M,\n                        int bestValue,\n                        double potentialWeight) {\n    static array<double, MAX_TOTAL> dp{};\n    static array<double, MAX_TOTAL> ndp{};\n    int maxSum = 0;\n    for (int l = 0; l < M; ++l) {\n        maxSum += max(A.attr[l], B.attr[l]);\n    }\n    if (maxSum + 1 > MAX_TOTAL) maxSum = MAX_TOTAL - 1;\n\n    fill(dp.begin(), dp.begin() + (maxSum + 1), 0.0);\n    dp[0] = 1.0;\n    int currentMax = 0;\n    for (int l = 0; l < M; ++l) {\n        int aVal = A.attr[l];\n        int bVal = B.attr[l];\n        int add = max(aVal, bVal);\n        int nextMax = currentMax + add;\n        if (nextMax > maxSum) nextMax = maxSum;\n        fill(ndp.begin(), ndp.begin() + (nextMax + 1), 0.0);\n        for (int s = 0; s <= currentMax; ++s) {\n            double prob = dp[s];\n            if (prob == 0.0) continue;\n            ndp[s + aVal] += prob * 0.5;\n            ndp[s + bVal] += prob * 0.5;\n        }\n        currentMax = nextMax;\n        dp.swap(ndp);\n    }\n\n    int K = targets.size();\n    if (K == 0) {\n        double potential = currentMax - bestValue;\n        return (potential > 0) ? potentialWeight * potential : 0.0;\n    }\n\n    array<double, 4> tailProb{};\n    array<double, 4> tailSum{};\n    int minTarget = targets.front();\n    if (minTarget < 0) minTarget = 0;\n    if (currentMax > minTarget) {\n        for (int s = currentMax; s > minTarget; --s) {\n            double prob = dp[s];\n            if (prob == 0.0) continue;\n            for (int idx = 0; idx < K; ++idx) {\n                if (s > targets[idx]) {\n                    tailProb[idx] += prob;\n                    tailSum[idx] += prob * s;\n                } else {\n                    break;\n                }\n            }\n        }\n    }\n\n    double total = 0.0;\n    for (int idx = 0; idx < K; ++idx) {\n        double sc = tailSum[idx] - static_cast<double>(targets[idx]) * tailProb[idx];\n        if (sc < 0) sc = 0;\n        total += weights[idx] * sc + probWeights[idx] * tailProb[idx];\n    }\n\n    double potential = currentMax - bestValue;\n    if (potential > 0) total += potentialWeight * potential;\n    return total;\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    int seedCount = 2 * N * (N - 1);\n    int selectCount = N * N;\n    vector<Seed> seeds(seedCount);\n    for (int i = 0; i < seedCount; ++i) {\n        int sum = 0;\n        for (int j = 0; j < M; ++j) {\n            int val;\n            cin >> val;\n            seeds[i].attr[j] = val;\n            sum += val;\n        }\n        for (int j = M; j < MAX_M; ++j) seeds[i].attr[j] = 0;\n        seeds[i].value = sum;\n    }\n\n    const int cellCount = selectCount;\n    vector<vector<int>> neighbors(cellCount);\n    vector<pair<int, int>> edges;\n    edges.reserve(2 * N * (N - 1));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int pos = i * N + j;\n            if (j + 1 < N) {\n                int q = pos + 1;\n                neighbors[pos].push_back(q);\n                neighbors[q].push_back(pos);\n                edges.emplace_back(pos, q);\n            }\n            if (i + 1 < N) {\n                int q = pos + N;\n                neighbors[pos].push_back(q);\n                neighbors[q].push_back(pos);\n                edges.emplace_back(pos, q);\n            }\n        }\n    }\n    vector<int> cellDegree(cellCount, 0);\n    for (int pos = 0; pos < cellCount; ++pos) {\n        sort(neighbors[pos].begin(), neighbors[pos].end());\n        neighbors[pos].erase(unique(neighbors[pos].begin(), neighbors[pos].end()), neighbors[pos].end());\n        cellDegree[pos] = (int)neighbors[pos].size();\n    }\n\n    vector<int> positionOrder(cellCount);\n    iota(positionOrder.begin(), positionOrder.end(), 0);\n    double center = (N - 1) / 2.0;\n    vector<double> cellDist(cellCount, 0.0);\n    for (int pos = 0; pos < cellCount; ++pos) {\n        int r = pos / N;\n        int c = pos % N;\n        cellDist[pos] = fabs(r - center) + fabs(c - center);\n    }\n    sort(positionOrder.begin(), positionOrder.end(), [&](int a, int b) {\n        if (fabs(cellDist[a] - cellDist[b]) > 1e-9) return cellDist[a] < cellDist[b];\n        if (cellDegree[a] != cellDegree[b]) return cellDegree[a] > cellDegree[b];\n        return a < b;\n    });\n\n    mt19937 rng(712367);\n    uniform_real_distribution<double> realDist(0.0, 1.0);\n    uniform_int_distribution<int> posDist(0, cellCount - 1);\n\n    vector<int> orderIndices(seedCount);\n    vector<int> bestAttrIndex(M);\n    vector<int> bestAttrValue(M);\n    vector<int> attrBestCount(seedCount);\n\n    for (int turn = 0; turn < T; ++turn) {\n        fill(bestAttrValue.begin(), bestAttrValue.end(), -1);\n        fill(bestAttrIndex.begin(), bestAttrIndex.end(), -1);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            for (int l = 0; l < M; ++l) {\n                int val = seeds[idx].attr[l];\n                if (val > bestAttrValue[l]) {\n                    bestAttrValue[l] = val;\n                    bestAttrIndex[l] = idx;\n                }\n            }\n        }\n        fill(attrBestCount.begin(), attrBestCount.end(), 0);\n        for (int l = 0; l < M; ++l) {\n            if (bestAttrIndex[l] != -1) attrBestCount[bestAttrIndex[l]]++;\n        }\n        int bestValue = 0;\n        for (const auto& s : seeds) bestValue = max(bestValue, s.value);\n        int targetMax = 0;\n        for (int v : bestAttrValue) targetMax += max(0, v);\n\n        vector<int> selectedIndices;\n        selectedIndices.reserve(selectCount);\n        vector<char> used(seedCount, false);\n        for (int l = 0; l < M; ++l) {\n            int idx = bestAttrIndex[l];\n            if (idx >= 0 && !used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n        iota(orderIndices.begin(), orderIndices.end(), 0);\n        sort(orderIndices.begin(), orderIndices.end(), [&](int a, int b) {\n            if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n            return a < b;\n        });\n        for (int idx : orderIndices) {\n            if ((int)selectedIndices.size() >= selectCount) break;\n            if (!used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n        for (int idx = 0; idx < seedCount && (int)selectedIndices.size() < selectCount; ++idx) {\n            if (!used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n\n        vector<int> selectedValues(selectCount);\n        vector<int> selectedAttrCount(selectCount);\n        for (int i = 0; i < selectCount; ++i) {\n            selectedValues[i] = seeds[selectedIndices[i]].value;\n            selectedAttrCount[i] = attrBestCount[selectedIndices[i]];\n        }\n\n        const int maintainMargin = 8;\n        int maintainTarget = bestValue - maintainMargin;\n        if (maintainTarget < 0) maintainTarget = 0;\n        double gap = max(0, targetMax - bestValue);\n        int improveMargin1 = max(3, (int)round(min(gap * 0.35, 40.0)));\n        int improveMargin2 = max(improveMargin1 + 3, (int)round(min(gap * 0.65, 80.0)));\n        int targetImprove1 = min(bestValue + improveMargin1, targetMax);\n        int targetImprove2 = min(bestValue + improveMargin2, targetMax);\n\n        double phase = (T <= 1) ? 1.0 : (double)turn / (T - 1);\n        double gapFactor = min(1.0, (gap + 5.0) / 60.0);\n        double improvementScale = (0.5 + 0.5 * (1.0 - phase)) * (0.4 + 0.6 * gapFactor);\n        improvementScale = clamp(improvementScale, 0.25, 1.2);\n        double maintainWeight = 0.8 + 0.5 * phase;\n        double maintainProbWeight = 0.05;\n        double improve1Weight = 4.0 * improvementScale;\n        double improve2Weight = 8.0 * improvementScale;\n        double improve1ProbWeight = 0.8 * improvementScale;\n        double improve2ProbWeight = 1.6 * improvementScale;\n        double potentialWeight = 0.02 + 0.04 * improvementScale;\n\n        vector<int> targets;\n        vector<double> weights, probWeights;\n        auto addTarget = [&](int target, double w, double pw) {\n            target = clamp(target, 0, targetMax);\n            if (targets.empty() || target > targets.back()) {\n                targets.push_back(target);\n                weights.push_back(w);\n                probWeights.push_back(pw);\n            }\n        };\n        addTarget(maintainTarget, maintainWeight, maintainProbWeight);\n        if (targetImprove1 > maintainTarget) addTarget(targetImprove1, improve1Weight, improve1ProbWeight);\n        if (targetImprove2 > targetImprove1) addTarget(targetImprove2, improve2Weight, improve2ProbWeight);\n\n        int S = selectCount;\n        vector<double> pairScore((size_t)S * S, 0.0);\n        for (int i = 0; i < S; ++i) {\n            pairScore[i * S + i] = 0.0;\n            for (int j = i + 1; j < S; ++j) {\n                double val = computePairScore(seeds[selectedIndices[i]],\n                                              seeds[selectedIndices[j]],\n                                              targets, weights, probWeights,\n                                              M, bestValue, potentialWeight);\n                pairScore[i * S + j] = val;\n                pairScore[j * S + i] = val;\n            }\n        }\n\n        vector<int> localOrder(S);\n        iota(localOrder.begin(), localOrder.end(), 0);\n        shuffle(localOrder.begin(), localOrder.end(), rng);\n        sort(localOrder.begin(), localOrder.end(), [&](int a, int b) {\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            return selectedIndices[a] < selectedIndices[b];\n        });\n\n        vector<int> assign(cellCount, -1);\n        for (int idx = 0; idx < cellCount; ++idx) {\n            assign[positionOrder[idx]] = localOrder[idx];\n        }\n\n        double edgeScore = 0.0;\n        for (auto [u, v] : edges) {\n            int su = assign[u];\n            int sv = assign[v];\n            edgeScore += pairScore[su * S + sv];\n        }\n        double degTerm = 0.0;\n        for (int pos = 0; pos < cellCount; ++pos) {\n            degTerm += cellDegree[pos] * selectedValues[assign[pos]];\n        }\n        double degWeight = 0.02 * (0.9 - 0.4 * phase);\n        double currentScore = edgeScore + degWeight * degTerm;\n        double bestScore = currentScore;\n        vector<int> bestAssign = assign;\n\n        int maxIter = 6000 + (int)(2000 * (1.0 - phase));\n        double Tstart = 1.2 * improvementScale + 0.3;\n        double Tend = 0.01;\n        array<pair<int, int>, 16> impacted{};\n\n        for (int iter = 0; iter < maxIter; ++iter) {\n            int pos1 = posDist(rng);\n            int pos2 = posDist(rng);\n            if (pos1 == pos2) continue;\n            int seed1 = assign[pos1];\n            int seed2 = assign[pos2];\n            if (seed1 == seed2) continue;\n\n            int cnt = 0;\n            auto addEdgeLocal = [&](int a, int b) {\n                if (a > b) swap(a, b);\n                for (int k = 0; k < cnt; ++k) {\n                    if (impacted[k].first == a && impacted[k].second == b) return;\n                }\n                impacted[cnt++] = {a, b};\n            };\n            for (int nb : neighbors[pos1]) addEdgeLocal(pos1, nb);\n            for (int nb : neighbors[pos2]) addEdgeLocal(pos2, nb);\n\n            double beforeEdge = 0.0;\n            for (int k = 0; k < cnt; ++k) {\n                int a = impacted[k].first;\n                int b = impacted[k].second;\n                beforeEdge += pairScore[assign[a] * S + assign[b]];\n            }\n\n            double deltaPos = degWeight * (double)(selectedValues[seed2] - selectedValues[seed1]) *\n                              (cellDegree[pos1] - cellDegree[pos2]);\n\n            swap(assign[pos1], assign[pos2]);\n\n            double afterEdge = 0.0;\n            for (int k = 0; k < cnt; ++k) {\n                int a = impacted[k].first;\n                int b = impacted[k].second;\n                afterEdge += pairScore[assign[a] * S + assign[b]];\n            }\n\n            double delta = (afterEdge - beforeEdge) + deltaPos;\n            double progress = (double)iter / maxIter;\n            double temperature = Tstart + (Tend - Tstart) * progress;\n            bool accept = false;\n            if (delta >= 0) {\n                accept = true;\n            } else if (temperature > 0) {\n                double prob = exp(delta / temperature);\n                if (realDist(rng) < prob) accept = true;\n            }\n            if (accept) {\n                currentScore += delta;\n                if (currentScore > bestScore) {\n                    bestScore = currentScore;\n                    bestAssign = assign;\n                }\n            } else {\n                swap(assign[pos1], assign[pos2]);\n            }\n        }\n\n        assign = bestAssign;\n\n        vector<vector<int>> grid(N, vector<int>(N, 0));\n        for (int pos = 0; pos < cellCount; ++pos) {\n            int r = pos / N;\n            int c = pos % N;\n            grid[r][c] = selectedIndices[assign[pos]];\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (j) cout << ' ';\n                cout << grid[i][j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        if (turn + 1 == T) break;\n        for (int i = 0; i < seedCount; ++i) {\n            int sum = 0;\n            for (int j = 0; j < M; ++j) {\n                int val;\n                cin >> val;\n                seeds[i].attr[j] = val;\n                sum += val;\n            }\n            seeds[i].value = sum;\n        }\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Cell {\n    int x, y;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, M, V;\n    if (!(cin >> N >> M >> V)) return 0;\n    vector<string> s(N), t(N);\n    for (int i = 0; i < N; ++i) cin >> s[i];\n    for (int i = 0; i < N; ++i) cin >> t[i];\n\n    vector<vector<int>> occ(N, vector<int>(N, 0));\n    vector<Cell> surplus, deficit;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int si = s[i][j] - '0';\n            int ti = t[i][j] - '0';\n            occ[i][j] = si;\n            if (si == 1 && ti == 0) surplus.push_back({i, j});\n            else if (si == 0 && ti == 1) deficit.push_back({i, j});\n        }\n    }\n\n    int root_init_x = N / 2;\n    int root_init_y = N / 2;\n    root_init_x = min(max(root_init_x, 0), N - 1);\n    root_init_y = min(max(root_init_y, 0), N - 1);\n\n    const int MAX_TURNS = 100000;\n    vector<string> ops;\n    ops.reserve(MAX_TURNS);\n    bool limit_reached = false;\n    int rx = root_init_x, ry = root_init_y;\n    bool holding = false;\n\n    auto push_move = [&](char c) {\n        if (limit_reached) return;\n        if ((int)ops.size() >= MAX_TURNS) { limit_reached = true; return; }\n        string op(2, '.');\n        op[0] = c;\n        ops.push_back(op);\n    };\n\n    auto push_action = [&](char c) {\n        if (limit_reached) return;\n        if ((int)ops.size() >= MAX_TURNS) { limit_reached = true; return; }\n        string op(2, '.');\n        op[1] = c;\n        ops.push_back(op);\n    };\n\n    auto move_to = [&](int nx, int ny) {\n        while (!limit_reached && rx < nx) { ++rx; push_move('D'); }\n        while (!limit_reached && rx > nx) { --rx; push_move('U'); }\n        while (!limit_reached && ry < ny) { ++ry; push_move('R'); }\n        while (!limit_reached && ry > ny) { --ry; push_move('L'); }\n    };\n\n    auto try_pick = [&]() -> bool {\n        if (limit_reached) return false;\n        bool ok = (!holding && occ[rx][ry] == 1);\n        if (ok) {\n            occ[rx][ry] = 0;\n            holding = true;\n            push_action('P');\n        } else {\n            push_action('.');\n        }\n        return ok;\n    };\n\n    auto try_drop = [&]() -> bool {\n        if (limit_reached) return false;\n        bool ok = (holding && occ[rx][ry] == 0);\n        if (ok) {\n            occ[rx][ry] = 1;\n            holding = false;\n            push_action('P');\n        } else {\n            push_action('.');\n        }\n        return ok;\n    };\n\n    vector<char> usedS(surplus.size(), false);\n    vector<char> usedD(deficit.size(), false);\n    int total_pairs = min(surplus.size(), deficit.size());\n    int completed = 0;\n    while (completed < total_pairs && !limit_reached) {\n        int bestS = -1;\n        int bestDist = INT_MAX;\n        for (int i = 0; i < (int)surplus.size(); ++i) if (!usedS[i]) {\n            int dist = abs(rx - surplus[i].x) + abs(ry - surplus[i].y);\n            if (dist < bestDist) { bestDist = dist; bestS = i; }\n        }\n        if (bestS == -1) break;\n        move_to(surplus[bestS].x, surplus[bestS].y);\n        if (limit_reached) break;\n        if (!try_pick()) break;\n        usedS[bestS] = true;\n\n        int bestD = -1;\n        bestDist = INT_MAX;\n        for (int i = 0; i < (int)deficit.size(); ++i) if (!usedD[i]) {\n            int dist = abs(rx - deficit[i].x) + abs(ry - deficit[i].y);\n            if (dist < bestDist) { bestDist = dist; bestD = i; }\n        }\n        if (bestD == -1) break;\n        move_to(deficit[bestD].x, deficit[bestD].y);\n        if (limit_reached) break;\n        if (!try_drop()) break;\n        usedD[bestD] = true;\n        ++completed;\n    }\n\n    if (holding && !limit_reached) {\n        int target_x = rx, target_y = ry;\n        if (occ[target_x][target_y] != 0) {\n            bool found = false;\n            for (int i = 0; i < N && !found; ++i)\n                for (int j = 0; j < N && !found; ++j)\n                    if (occ[i][j] == 0) { target_x = i; target_y = j; found = true; }\n            if (!limit_reached && (rx != target_x || ry != target_y)) move_to(target_x, target_y);\n        }\n        if (!limit_reached && occ[rx][ry] == 0) try_drop();\n    }\n\n    cout << 1 << '\\n';\n    cout << root_init_x << ' ' << root_init_y << '\\n';\n    for (const string &op : ops) cout << op << '\\n';\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAX_COORD = 100000;\nconst int NEG_INF = -1000000000;\nconstexpr double TIME_LIMIT = 1.85; // safety margin\n\nstruct Score {\n    int diff;\n    int m;\n    int s;\n};\n\nstruct RectAns {\n    int x1 = 0, x2 = 0, y1 = 0, y2 = 0;\n    Score sc = {NEG_INF, 0, 0};\n};\n\nint N;\nvector<int> xs, ys, types;\nvector<pair<int,int>> m_coords;\nRectAns best_rect;\n\nmt19937 rng(chrono::steady_clock::now().time_since_epoch().count());\nchrono::steady_clock::time_point g_start;\n\ninline double elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ninline void fix_range(int &lo, int &hi) {\n    if (lo > hi) swap(lo, hi);\n    lo = clamp(lo, 0, MAX_COORD);\n    hi = clamp(hi, 0, MAX_COORD);\n    if (lo == hi) {\n        if (hi < MAX_COORD) ++hi;\n        else if (lo > 0) --lo;\n    }\n    if (lo == hi) { // still equal only if MAX_COORD == 0 (not here), but keep safe\n        if (lo == 0 && hi < MAX_COORD) ++hi;\n        else if (lo > 0) --lo;\n    }\n}\n\ninline Score evaluate_rect(int x1, int x2, int y1, int y2) {\n    Score res{0,0,0};\n    for (size_t i = 0; i < xs.size(); ++i) {\n        int px = xs[i];\n        if (px < x1 || px > x2) continue;\n        int py = ys[i];\n        if (py < y1 || py > y2) continue;\n        int t = types[i];\n        res.diff += t;\n        if (t == 1) ++res.m;\n        else ++res.s;\n    }\n    return res;\n}\n\ninline void consider_rect(int x1, int x2, int y1, int y2) {\n    fix_range(x1, x2);\n    fix_range(y1, y2);\n    if (x2 <= x1 || y2 <= y1) return; // safety, though fix_range should avoid this\n    Score sc = evaluate_rect(x1, x2, y1, y2);\n    bool better = false;\n    if (best_rect.sc.diff == NEG_INF) better = true;\n    else if (sc.diff > best_rect.sc.diff) better = true;\n    else if (sc.diff == best_rect.sc.diff) {\n        if (sc.m > best_rect.sc.m) better = true;\n        else if (sc.m == best_rect.sc.m) {\n            if (sc.s < best_rect.sc.s) better = true;\n            else if (sc.s == best_rect.sc.s) {\n                long long area = 1LL * (x2 - x1) * (y2 - y1);\n                long long best_area = 1LL * (best_rect.x2 - best_rect.x1) * (best_rect.y2 - best_rect.y1);\n                if (area < best_area) better = true;\n            }\n        }\n    }\n    if (better) {\n        best_rect = {x1, x2, y1, y2, sc};\n    }\n}\n\nvector<int> build_lines(const vector<int>& coords, int segments) {\n    vector<int> lines;\n    int extras = segments / 3 + 2;\n    lines.reserve(segments + extras + 4);\n    lines.push_back(0);\n    if (!coords.empty()) {\n        int size = coords.size();\n        for (int i = 1; i < segments; ++i) {\n            long long idx = 1LL * size * i / segments;\n            if (idx >= size) idx = size - 1;\n            lines.push_back(coords[idx]);\n        }\n        if (size > 0) {\n            uniform_int_distribution<int> dist(0, size - 1);\n            int ex = min(extras, size);\n            for (int i = 0; i < ex; ++i) lines.push_back(coords[dist(rng)]);\n        }\n    }\n    lines.push_back(MAX_COORD + 1);\n    sort(lines.begin(), lines.end());\n    lines.erase(unique(lines.begin(), lines.end()), lines.end());\n    if (lines.front() != 0) lines.insert(lines.begin(), 0);\n    if (lines.back() != MAX_COORD + 1) lines.push_back(MAX_COORD + 1);\n    return lines;\n}\n\nvoid grid_search(int segments, const vector<int>& sorted_x, const vector<int>& sorted_y) {\n    if (elapsed() > TIME_LIMIT) return;\n    auto lines_x = build_lines(sorted_x, segments);\n    auto lines_y = build_lines(sorted_y, segments);\n    int W = (int)lines_x.size() - 1;\n    int H = (int)lines_y.size() - 1;\n    if (W <= 0 || H <= 0) return;\n\n    vector<int> grid(W * H, 0);\n    for (size_t i = 0; i < xs.size(); ++i) {\n        int cx = upper_bound(lines_x.begin(), lines_x.end(), xs[i]) - lines_x.begin() - 1;\n        int cy = upper_bound(lines_y.begin(), lines_y.end(), ys[i]) - lines_y.begin() - 1;\n        cx = clamp(cx, 0, W - 1);\n        cy = clamp(cy, 0, H - 1);\n        grid[cy * W + cx] += types[i];\n    }\n\n    vector<int> arr(W, 0);\n    int best_sum = NEG_INF;\n    int best_top = 0, best_bottom = 0, best_left = 0, best_right = 0;\n    for (int top = 0; top < H; ++top) {\n        fill(arr.begin(), arr.end(), 0);\n        for (int bottom = top; bottom < H; ++bottom) {\n            int row_offset = bottom * W;\n            for (int col = 0; col < W; ++col) arr[col] += grid[row_offset + col];\n            int cur = 0;\n            int start = 0;\n            for (int col = 0; col < W; ++col) {\n                if (cur <= 0) {\n                    cur = arr[col];\n                    start = col;\n                } else {\n                    cur += arr[col];\n                }\n                if (cur > best_sum) {\n                    best_sum = cur;\n                    best_top = top;\n                    best_bottom = bottom;\n                    best_left = start;\n                    best_right = col;\n                }\n            }\n        }\n    }\n\n    auto convert = [&](int left, int right, int top, int bottom) {\n        int x1 = lines_x[left];\n        int x2 = lines_x[right + 1] - 1;\n        int y1 = lines_y[top];\n        int y2 = lines_y[bottom + 1] - 1;\n        consider_rect(x1, x2, y1, y2);\n    };\n\n    convert(best_left, best_right, best_top, best_bottom);\n\n    array<pair<int,int>,3> top_cells;\n    int filled = 0;\n    for (int idx = 0; idx < H * W; ++idx) {\n        int val = grid[idx];\n        if (filled < 3) {\n            top_cells[filled++] = {val, idx};\n        } else {\n            int pos = 0;\n            for (int j = 1; j < 3; ++j) if (top_cells[j].first < top_cells[pos].first) pos = j;\n            if (val > top_cells[pos].first) top_cells[pos] = {val, idx};\n        }\n    }\n    for (int i = 0; i < filled; ++i) {\n        int idx = top_cells[i].second;\n        int cy = idx / W;\n        int cx = idx % W;\n        for (int rad = 0; rad <= 1; ++rad) {\n            int left = max(0, cx - rad);\n            int right = min(W - 1, cx + rad);\n            int top = max(0, cy - rad);\n            int bottom = min(H - 1, cy + rad);\n            convert(left, right, top, bottom);\n        }\n    }\n}\n\ninline int sample_half_span() {\n    static const int options[] = {0, 20, 40, 80, 150, 250, 400, 600, 900, 1300, 1800, 2500, 3400, 4500, 6000,\n                                  8000, 10500, 13500, 17000, 21000, 26000, 32000, 39000, 47000};\n    int idx = rng() % (sizeof(options) / sizeof(options[0]));\n    int base = options[idx];\n    int extra_range = base / 3 + 1;\n    if (base == 0) extra_range = 60;\n    int extra = (extra_range > 0) ? rng() % extra_range : 0;\n    return base + extra;\n}\n\ninline int sample_span() {\n    static const pair<int,int> ranges[] = {\n        {1, 400}, {200, 1200}, {800, 3200}, {2000, 7000}, {5000, 15000},\n        {12000, 30000}, {25000, 50000}, {40000, 80000}, {70000, 100000}\n    };\n    auto range = ranges[rng() % (sizeof(ranges) / sizeof(ranges[0]))];\n    int lo = range.first;\n    int hi = min(range.second, MAX_COORD);\n    if (lo > hi) lo = hi;\n    int width = lo;\n    if (hi > lo) width += rng() % (hi - lo + 1);\n    width = clamp(width, 1, MAX_COORD);\n    return width;\n}\n\nvoid random_centered(int iterations) {\n    if (m_coords.empty()) return;\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations; ++it) {\n        if (elapsed() > TIME_LIMIT) break;\n        const auto &p = m_coords[dist(rng)];\n        int dx = sample_half_span();\n        int dy = sample_half_span();\n        int x1 = p.first - dx;\n        int x2 = p.first + dx;\n        int y1 = p.second - dy;\n        int y2 = p.second + dy;\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_global(int iterations) {\n    for (int it = 0; it < iterations; ++it) {\n        if (elapsed() > TIME_LIMIT) break;\n        int width = sample_span();\n        int height = sample_span();\n        int x1_max = MAX_COORD - width;\n        int y1_max = MAX_COORD - height;\n        int x1 = (x1_max > 0) ? (int)(rng() % (x1_max + 1)) : 0;\n        int y1 = (y1_max > 0) ? (int)(rng() % (y1_max + 1)) : 0;\n        int x2 = x1 + width;\n        int y2 = y1 + height;\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_pair_rects(int iterations) {\n    if (m_coords.empty()) return;\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations; ++it) {\n        if (elapsed() > TIME_LIMIT) break;\n        const auto &a = m_coords[dist(rng)];\n        const auto &b = m_coords[dist(rng)];\n        int left = min(a.first, b.first);\n        int right = max(a.first, b.first);\n        int marginx = sample_half_span();\n        int x1 = left - marginx;\n        int x2 = right + marginx;\n\n        int y1, y2;\n        if (rng() & 1) {\n            int bottom = min(a.second, b.second);\n            int top = max(a.second, b.second);\n            int marginy = sample_half_span();\n            y1 = bottom - marginy;\n            y2 = top + marginy;\n        } else {\n            const auto &c = m_coords[dist(rng)];\n            const auto &d = m_coords[dist(rng)];\n            int bottom = min(c.second, d.second);\n            int top = max(c.second, d.second);\n            int marginy = sample_half_span();\n            y1 = bottom - marginy;\n            y2 = top + marginy;\n        }\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_cluster_rects(int iterations) {\n    if (m_coords.empty()) return;\n    vector<int> cluster_sizes = {2,3,4,5,7,9,12};\n    for (int it = 0; it < iterations; ++it) {\n        if (elapsed() > TIME_LIMIT) break;\n        int k = cluster_sizes[rng() % cluster_sizes.size()];\n        int minx = 0, maxx = 0, miny = 0, maxy = 0;\n        bool first = true;\n        for (int j = 0; j < k; ++j) {\n            const auto &p = m_coords[rng() % m_coords.size()];\n            if (first) {\n                minx = maxx = p.first;\n                miny = maxy = p.second;\n                first = false;\n            } else {\n                minx = min(minx, p.first);\n                maxx = max(maxx, p.first);\n                miny = min(miny, p.second);\n                maxy = max(maxy, p.second);\n            }\n        }\n        int marginx = sample_half_span();\n        int marginy = sample_half_span();\n        consider_rect(minx - marginx, maxx + marginx, miny - marginy, maxy + marginy);\n    }\n}\n\nvoid random_perturb_best(int iterations) {\n    if (best_rect.sc.diff == NEG_INF) return;\n    static const int perturb_options[] = {5, 15, 30, 60, 120, 250, 400, 700, 1100, 1700, 2500, 3600, 5000, 7500, 10000, 15000};\n    for (int it = 0; it < iterations; ++it) {\n        if (elapsed() > TIME_LIMIT) break;\n        int delta = perturb_options[rng() % (sizeof(perturb_options)/sizeof(perturb_options[0]))];\n        int x1 = best_rect.x1 - (int)(rng() % (delta + 1));\n        int x2 = best_rect.x2 + (int)(rng() % (delta + 1));\n        int y1 = best_rect.y1 - (int)(rng() % (delta + 1));\n        int y2 = best_rect.y2 + (int)(rng() % (delta + 1));\n        int shiftx = (int)rng() % (2 * delta + 1) - delta;\n        int shifty = (int)rng() % (2 * delta + 1) - delta;\n        x1 += shiftx; x2 += shiftx;\n        y1 += shifty; y2 += shifty;\n        if (rng() & 1) x1 += rng() % (delta + 1);\n        if (rng() & 1) x2 -= rng() % (delta + 1);\n        if (rng() & 1) y1 += rng() % (delta + 1);\n        if (rng() & 1) y2 -= rng() % (delta + 1);\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    cin >> N;\n    xs.reserve(2 * N);\n    ys.reserve(2 * N);\n    types.reserve(2 * N);\n    m_coords.reserve(N);\n\n    for (int i = 0; i < N; ++i) {\n        int x, y;\n        cin >> x >> y;\n        xs.push_back(x);\n        ys.push_back(y);\n        types.push_back(1);\n        m_coords.emplace_back(x, y);\n    }\n    for (int i = 0; i < N; ++i) {\n        int x, y;\n        cin >> x >> y;\n        xs.push_back(x);\n        ys.push_back(y);\n        types.push_back(-1);\n    }\n\n    vector<int> sorted_x = xs;\n    vector<int> sorted_y = ys;\n    sort(sorted_x.begin(), sorted_x.end());\n    sort(sorted_y.begin(), sorted_y.end());\n\n    best_rect.sc.diff = NEG_INF;\n\n    g_start = chrono::steady_clock::now();\n\n    // Basic rectangles\n    consider_rect(0, MAX_COORD, 0, MAX_COORD);\n    consider_rect(MAX_COORD/4, 3*MAX_COORD/4, MAX_COORD/4, 3*MAX_COORD/4);\n    consider_rect(0, MAX_COORD/2, 0, MAX_COORD/2);\n    consider_rect(MAX_COORD/2, MAX_COORD, 0, MAX_COORD/2);\n    consider_rect(0, MAX_COORD/2, MAX_COORD/2, MAX_COORD);\n    consider_rect(MAX_COORD/2, MAX_COORD, MAX_COORD/2, MAX_COORD);\n\n    vector<int> segments_list = {12, 18, 26, 35, 48, 64, 85, 110, 140};\n    for (int seg : segments_list) {\n        if (elapsed() > TIME_LIMIT) break;\n        grid_search(seg, sorted_x, sorted_y);\n    }\n\n    random_centered(1500);\n    random_global(1000);\n    random_pair_rects(900);\n    random_cluster_rects(800);\n    random_centered(600);\n    random_perturb_best(600);\n\n    // Output best rectangle as polygon\n    cout << 4 << '\\n';\n    cout << best_rect.x1 << ' ' << best_rect.y1 << '\\n';\n    cout << best_rect.x2 << ' ' << best_rect.y1 << '\\n';\n    cout << best_rect.x2 << ' ' << best_rect.y2 << '\\n';\n    cout << best_rect.x1 << ' ' << best_rect.y2 << '\\n';\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Profile {\n    vector<long long> widths;\n    vector<long long> heights; // monotone non-increasing as widths grow\n};\n\nstruct Solution {\n    vector<int> orientation;        // 0/1 per rectangle\n    vector<int> column_id;          // column index per rectangle\n    vector<long long> column_widths;\n    vector<long long> column_heights;\n    vector<int> anchor;             // reference rectangle for each column\n    vector<int> idx_max_width;      // rectangle index attaining column width\n    vector<pair<int,int>> ranges;   // [l,r) per column (for debugging)\n    long long total_width = 0;\n    long long total_height = 0;\n    long long score = (long long)4e18;\n    long long H_used = 0;\n};\n\nconst long long INFLL = (long long)4e18;\n\nint N, T;\nlong long sigma_val;\nvector<long long> w_obs, h_obs;\nvector<array<long long,2>> widthOpt, heightOpt;\nvector<vector<Profile>> profiles;\n\nlong long get_min_width(const Profile &prof, long long Hmax) {\n    for (size_t i = 0; i < prof.widths.size(); ++i) {\n        if (prof.heights[i] <= Hmax) return prof.widths[i];\n    }\n    return INFLL;\n}\n\nint choose_orientation(int idx, long long width_limit) {\n    int best = -1;\n    long long best_h = INFLL;\n    for (int o = 0; o < 2; ++o) {\n        if (widthOpt[idx][o] <= width_limit) {\n            long long h = heightOpt[idx][o];\n            if (best == -1 || h < best_h ||\n                (h == best_h && widthOpt[idx][o] < widthOpt[idx][best])) {\n                best = o;\n                best_h = h;\n            }\n        }\n    }\n    if (best == -1) {\n        // Should never happen, fall back to minimal height orientation\n        best = (heightOpt[idx][1] < heightOpt[idx][0]) ? 1 : 0;\n    }\n    return best;\n}\n\nbool build_solution(long long Hmax, Solution &sol) {\n    vector<long long> dp(N + 1, INFLL);\n    vector<int> prv(N + 1, -1);\n    vector<long long> width_choice(N + 1, -1);\n    dp[0] = 0;\n    for (int i = 1; i <= N; ++i) {\n        for (int j = 0; j < i; ++j) {\n            const Profile &prof = profiles[j][i];\n            long long width = get_min_width(prof, Hmax);\n            if (width >= INFLL/2) continue;\n            long long cand = dp[j] + width;\n            if (cand < dp[i]) {\n                dp[i] = cand;\n                prv[i] = j;\n                width_choice[i] = width;\n            }\n        }\n    }\n    if (dp[N] >= INFLL/2) return false;\n\n    vector<int> cuts;\n    int pos = N;\n    while (pos > 0) {\n        cuts.push_back(pos);\n        pos = prv[pos];\n        if (pos < 0) return false;\n    }\n    cuts.push_back(0);\n    reverse(cuts.begin(), cuts.end());\n    int cols = (int)cuts.size() - 1;\n\n    vector<int> orientation(N);\n    vector<int> column_id(N);\n    vector<long long> col_width(cols);\n    vector<long long> col_height(cols);\n    vector<int> idx_max(cols);\n    vector<pair<int,int>> ranges(cols);\n\n    for (int c = 0; c < cols; ++c) {\n        int l = cuts[c];\n        int r = cuts[c+1];\n        ranges[c] = {l, r};\n        long long width_limit = width_choice[r];\n        long long max_w = -1;\n        long long sum_h = 0;\n        int idx = l;\n        for (int k = l; k < r; ++k) {\n            int best_or = choose_orientation(k, width_limit);\n            orientation[k] = best_or;\n            column_id[k] = c;\n            long long w = widthOpt[k][best_or];\n            long long h = heightOpt[k][best_or];\n            sum_h += h;\n            if (w > max_w || (w == max_w && k < idx)) {\n                max_w = w;\n                idx = k;\n            }\n        }\n        if (max_w < width_limit) max_w = width_limit;\n        col_width[c] = max_w;\n        col_height[c] = sum_h;\n        idx_max[c] = idx;\n    }\n\n    vector<int> anchor(cols);\n    anchor[0] = -1;\n    for (int c = 1; c < cols; ++c) anchor[c] = idx_max[c-1];\n\n    long long total_w = 0;\n    long long total_h = 0;\n    for (auto w : col_width) total_w += w;\n    for (auto h : col_height) total_h = max(total_h, h);\n\n    sol.orientation = move(orientation);\n    sol.column_id = move(column_id);\n    sol.column_widths = move(col_width);\n    sol.column_heights = move(col_height);\n    sol.anchor = move(anchor);\n    sol.idx_max_width = move(idx_max);\n    sol.ranges = move(ranges);\n    sol.total_width = total_w;\n    sol.total_height = total_h;\n    sol.score = total_w + total_h;\n    sol.H_used = Hmax;\n    return true;\n}\n\nSolution build_row_solution() {\n    Solution sol;\n    vector<int> orientation(N);\n    vector<int> column_id(N);\n    vector<long long> col_width(N);\n    vector<long long> col_height(N);\n    vector<int> idx_max(N);\n    vector<pair<int,int>> ranges(N);\n    for (int i = 0; i < N; ++i) {\n        int best = 0;\n        if (widthOpt[i][1] < widthOpt[i][0]) best = 1;\n        else if (widthOpt[i][1] == widthOpt[i][0] && heightOpt[i][1] < heightOpt[i][0])\n            best = 1;\n        orientation[i] = best;\n        column_id[i] = i;\n        col_width[i] = widthOpt[i][best];\n        col_height[i] = heightOpt[i][best];\n        idx_max[i] = i;\n        ranges[i] = {i, i+1};\n    }\n    vector<int> anchor(N);\n    anchor[0] = -1;\n    for (int i = 1; i < N; ++i) anchor[i] = i-1;\n\n    long long total_w = accumulate(col_width.begin(), col_width.end(), 0LL);\n    long long total_h = 0;\n    for (auto h : col_height) total_h = max(total_h, h);\n\n    sol.orientation = move(orientation);\n    sol.column_id = move(column_id);\n    sol.column_widths = move(col_width);\n    sol.column_heights = move(col_height);\n    sol.anchor = move(anchor);\n    sol.idx_max_width = move(idx_max);\n    sol.ranges = move(ranges);\n    sol.total_width = total_w;\n    sol.total_height = total_h;\n    sol.score = total_w + total_h;\n    sol.H_used = -1;\n    return sol;\n}\n\nuint64_t hash_solution(const Solution &sol) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < N; ++i) {\n        uint64_t val = (uint64_t)(sol.orientation[i] & 1);\n        uint64_t cid = (uint64_t)(sol.column_id[i] & 0x3FF);\n        val |= (cid << 1);\n        h ^= val;\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T >> sigma_val;\n    w_obs.resize(N);\n    h_obs.resize(N);\n    for (int i = 0; i < N; ++i) cin >> w_obs[i] >> h_obs[i];\n\n    widthOpt.assign(N, {0,0});\n    heightOpt.assign(N, {0,0});\n    vector<long long> minHeight(N), maxHeight(N);\n    long long total_min_height = 0;\n    long long H_lower = 0, H_upper = 0;\n    for (int i = 0; i < N; ++i) {\n        widthOpt[i][0] = w_obs[i];\n        heightOpt[i][0] = h_obs[i];\n        widthOpt[i][1] = h_obs[i];\n        heightOpt[i][1] = w_obs[i];\n        minHeight[i] = min(heightOpt[i][0], heightOpt[i][1]);\n        maxHeight[i] = max(heightOpt[i][0], heightOpt[i][1]);\n        total_min_height += minHeight[i];\n        H_lower = max(H_lower, minHeight[i]);\n        H_upper += maxHeight[i];\n    }\n    if (H_upper < H_lower) H_upper = H_lower;\n\n    profiles.assign(N, vector<Profile>(N+1));\n    for (int l = 0; l < N; ++l) {\n        for (int r = l+1; r <= N; ++r) {\n            Profile prof;\n            vector<long long> widths;\n            widths.reserve(2*(r-l));\n            for (int k = l; k < r; ++k) {\n                widths.push_back(widthOpt[k][0]);\n                widths.push_back(widthOpt[k][1]);\n            }\n            sort(widths.begin(), widths.end());\n            widths.erase(unique(widths.begin(), widths.end()), widths.end());\n            vector<long long> heights(widths.size(), INFLL);\n            for (size_t idx = 0; idx < widths.size(); ++idx) {\n                long long W = widths[idx];\n                long long sumH = 0;\n                bool ok = true;\n                for (int k = l; k < r; ++k) {\n                    long long best = INFLL;\n                    for (int o = 0; o < 2; ++o)\n                        if (widthOpt[k][o] <= W)\n                            best = min(best, heightOpt[k][o]);\n                    if (best >= INFLL/2) {\n                        ok = false;\n                        break;\n                    }\n                    sumH += best;\n                }\n                heights[idx] = ok ? sumH : INFLL;\n            }\n            long long last = INFLL;\n            for (size_t idx = 0; idx < heights.size(); ++idx) {\n                if (heights[idx] < last) last = heights[idx];\n                else heights[idx] = last;\n            }\n            prof.widths = move(widths);\n            prof.heights = move(heights);\n            profiles[l][r] = move(prof);\n        }\n    }\n\n    vector<long long> candidate_values;\n    auto add_candidate = [&](long long val) {\n        val = max(H_lower, min(val, H_upper));\n        candidate_values.push_back(val);\n    };\n    add_candidate(H_lower);\n    add_candidate(H_upper);\n\n    vector<double> fudge = {0.85, 0.95, 1.0, 1.05, 1.1, 1.25, 1.4};\n    int maxCols = min(N, 25);\n    for (int c = 1; c <= maxCols; ++c) {\n        double base = (double)total_min_height / c;\n        for (double f : fudge) {\n            long long cand = llround(base * f);\n            add_candidate(cand);\n        }\n    }\n    double val = (double)H_lower;\n    while (val <= (double)H_upper) {\n        add_candidate((long long)llround(val));\n        val *= 1.08;\n        if (candidate_values.size() > 800) break;\n    }\n    int linearCount = 25;\n    if (H_upper > H_lower) {\n        for (int i = 0; i < linearCount; ++i) {\n            double ratio = (double)i / (linearCount - 1);\n            long long cand = llround(H_lower + (H_upper - H_lower) * ratio);\n            add_candidate(cand);\n        }\n    }\n\n    sort(candidate_values.begin(), candidate_values.end());\n    candidate_values.erase(unique(candidate_values.begin(), candidate_values.end()), candidate_values.end());\n\n    size_t maxCandidates = min<size_t>(120, max<size_t>(30, 3 * (size_t)T));\n    vector<long long> candidates;\n    if (candidate_values.size() <= maxCandidates || maxCandidates <= 1) {\n        candidates = candidate_values;\n    } else {\n        candidates.reserve(maxCandidates);\n        for (size_t i = 0; i < maxCandidates; ++i) {\n            size_t pos = (size_t)llround((long double)i * (candidate_values.size()-1) / (maxCandidates-1));\n            candidates.push_back(candidate_values[pos]);\n        }\n        sort(candidates.begin(), candidates.end());\n        candidates.erase(unique(candidates.begin(), candidates.end()), candidates.end());\n    }\n    if (candidates.empty()) candidates.push_back(H_lower);\n\n    vector<Solution> solutions;\n    for (long long H : candidates) {\n        Solution sol;\n        if (build_solution(H, sol)) {\n            solutions.push_back(sol);\n        }\n    }\n    solutions.push_back(build_row_solution());\n\n    sort(solutions.begin(), solutions.end(), [](const Solution &a, const Solution &b) {\n        if (a.score != b.score) return a.score < b.score;\n        if (a.total_width != b.total_width) return a.total_width < b.total_width;\n        return a.column_widths.size() < b.column_widths.size();\n    });\n\n    vector<Solution> unique_solutions;\n    unordered_set<uint64_t> seen;\n    int maxOutput = min(T, 60);\n    for (const auto &sol : solutions) {\n        uint64_t h = hash_solution(sol);\n        if (seen.insert(h).second) {\n            unique_solutions.push_back(sol);\n            if ((int)unique_solutions.size() >= maxOutput) break;\n        }\n    }\n    if (unique_solutions.empty()) unique_solutions.push_back(build_row_solution());\n\n    vector<const Solution*> plan;\n    plan.reserve(T);\n    int use = min((int)unique_solutions.size(), T);\n    for (int i = 0; i < use; ++i) plan.push_back(&unique_solutions[i]);\n    for (int i = use; i < T; ++i) plan.push_back(&unique_solutions[0]);\n\n    for (int t = 0; t < T; ++t) {\n        const Solution &sol = *plan[t];\n        cout << N << '\\n';\n        for (int i = 0; i < N; ++i) {\n            int p = i;\n            int r = sol.orientation[i];\n            char d = 'U';\n            int col = sol.column_id[i];\n            int b = sol.anchor[col];\n            cout << p << ' ' << r << ' ' << d << ' ' << b << '\\n';\n        }\n        cout.flush();\n        long long Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n    }\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct BuildParams {\n    double rootBeautyWeight;\n    double rootCenterWeight;\n    double rootRandomWeight;\n    int candidateMode;              // 0: depth + shallow/deep tie, 1: weighted sum\n    int shallowThreshold;\n    long long depthWeight;\n    long long shallowBonus;\n    long long deepBonus;\n    long long beautyWeight;\n    int candidateRandomRange;\n};\n\nstruct Solution {\n    vector<int> parent;\n    vector<int> depth;\n    long long score;\n    Solution() : score(-1) {}\n};\n\nvector<int> select_roots(const vector<vector<int>>& adj,\n                         const vector<int>& A,\n                         const vector<double>& distCenter,\n                         int H,\n                         const BuildParams& params,\n                         mt19937& rng) {\n    const int N = adj.size();\n    const int INF = 1e9;\n    vector<int> minDist(N, INF);\n    vector<double> tieValue(N, 0.0);\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n    for (int v = 0; v < N; ++v) {\n        double randPart = params.rootRandomWeight > 0 ? dist01(rng) : 0.0;\n        tieValue[v] = params.rootBeautyWeight * A[v]\n                    + params.rootCenterWeight * distCenter[v]\n                    + params.rootRandomWeight * randPart;\n    }\n\n    vector<int> dist_local(N, INF);\n    vector<int> roots;\n\n    auto add_root = [&](int start) {\n        fill(dist_local.begin(), dist_local.end(), INF);\n        queue<int> q;\n        dist_local[start] = 0;\n        q.push(start);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int d = dist_local[v];\n            if (d < minDist[v]) minDist[v] = d;\n            if (d == H) continue;\n            for (int nb : adj[v]) {\n                if (dist_local[nb] > d + 1) {\n                    dist_local[nb] = d + 1;\n                    q.push(nb);\n                }\n            }\n        }\n        roots.push_back(start);\n    };\n\n    while (true) {\n        int best = -1;\n        for (int v = 0; v < N; ++v) {\n            if (minDist[v] > H) {\n                if (best == -1 ||\n                    minDist[v] > minDist[best] ||\n                    (minDist[v] == minDist[best] && tieValue[v] < tieValue[best])) {\n                    best = v;\n                }\n            }\n        }\n        if (best == -1) break;\n        add_root(best);\n    }\n    if (roots.empty()) {\n        int best = min_element(A.begin(), A.end()) - A.begin();\n        add_root(best);\n    }\n    return roots;\n}\n\nSolution build_solution(const vector<vector<int>>& adj,\n                        const vector<int>& A,\n                        const vector<double>& distCenter,\n                        int H,\n                        const BuildParams& params,\n                        mt19937& rng) {\n    const int N = adj.size();\n    vector<int> roots = select_roots(adj, A, distCenter, H, params, rng);\n    vector<int> parent(N, -1);\n    vector<int> depth(N, -1);\n    vector<char> assigned(N, 0);\n    vector<int> bestDepth(N, -1);\n    vector<int> bestParent(N, -1);\n    vector<long long> bestKey(N, LLONG_MIN);\n\n    int threshold = clamp(params.shallowThreshold, 0, H);\n\n    auto randContribution = [&](int range) -> long long {\n        if (range <= 0) return 0LL;\n        return rng() % range;\n    };\n\n    auto computeKey = [&](int v, int d) -> long long {\n        long long key = (long long)d * params.depthWeight;\n        if (params.candidateMode == 1) {\n            key += (long long)A[v] * params.beautyWeight;\n        } else {\n            bool shallow = d <= threshold;\n            long long tieVal = shallow ? (params.shallowBonus - A[v])\n                                       : (params.deepBonus + A[v]);\n            key += tieVal;\n        }\n        key += randContribution(params.candidateRandomRange);\n        return key;\n    };\n\n    struct PQItem {\n        long long key;\n        int depth;\n        int v;\n        bool operator<(const PQItem& other) const {\n            if (key != other.key) return key < other.key;\n            if (depth != other.depth) return depth < other.depth;\n            return v > other.v;\n        }\n    };\n    priority_queue<PQItem> pq;\n\n    auto pushCandidate = [&](int child, int par) {\n        if (depth[par] < 0) return;\n        int newDepth = depth[par] + 1;\n        if (newDepth > H) return;\n        long long key = computeKey(child, newDepth);\n        if (newDepth > bestDepth[child] || (newDepth == bestDepth[child] && key > bestKey[child])) {\n            bestDepth[child] = newDepth;\n            bestParent[child] = par;\n            bestKey[child] = key;\n            pq.push({key, newDepth, child});\n        }\n    };\n\n    int assignedCount = 0;\n    for (int r : roots) {\n        if (!assigned[r]) {\n            assigned[r] = 1;\n            depth[r] = 0;\n            parent[r] = -1;\n            assignedCount++;\n        }\n    }\n    if (assignedCount == 0) {\n        int best = min_element(A.begin(), A.end()) - A.begin();\n        assigned[best] = 1;\n        depth[best] = 0;\n        parent[best] = -1;\n        assignedCount = 1;\n        roots.push_back(best);\n    }\n    for (int r : roots) {\n        for (int nb : adj[r]) if (!assigned[nb]) pushCandidate(nb, r);\n    }\n\n    while (assignedCount < N) {\n        if (pq.empty()) {\n            int newRoot = -1, bestA = INT_MAX;\n            for (int v = 0; v < N; ++v) if (!assigned[v] && A[v] < bestA) {\n                bestA = A[v];\n                newRoot = v;\n            }\n            if (newRoot == -1) break;\n            assigned[newRoot] = 1;\n            depth[newRoot] = 0;\n            parent[newRoot] = -1;\n            assignedCount++;\n            for (int nb : adj[newRoot]) if (!assigned[nb]) pushCandidate(nb, newRoot);\n            continue;\n        }\n        auto cur = pq.top(); pq.pop();\n        int v = cur.v;\n        if (assigned[v]) continue;\n        if (cur.depth != bestDepth[v]) continue;\n        if (cur.key != bestKey[v]) continue;\n        assigned[v] = 1;\n        depth[v] = cur.depth;\n        parent[v] = (bestParent[v] == -1 ? -1 : bestParent[v]);\n        assignedCount++;\n        for (int nb : adj[v]) if (!assigned[nb]) pushCandidate(nb, v);\n    }\n\n    for (int v = 0; v < N; ++v) {\n        if (depth[v] == -1) {\n            depth[v] = 0;\n            parent[v] = -1;\n        }\n    }\n    long long score = 0;\n    for (int v = 0; v < N; ++v) {\n        score += 1LL * (depth[v] + 1) * A[v];\n    }\n    Solution sol;\n    sol.parent = move(parent);\n    sol.depth = move(depth);\n    sol.score = score;\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    cin >> N >> M >> H;\n    vector<int> A(N);\n    for (int i = 0; i < N; ++i) cin >> A[i];\n\n    vector<vector<int>> adj(N);\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; ++i) cin >> xs[i] >> ys[i];\n\n    double avgX = 0.0, avgY = 0.0;\n    for (int i = 0; i < N; ++i) {\n        avgX += xs[i];\n        avgY += ys[i];\n    }\n    avgX /= N;\n    avgY /= N;\n    vector<double> distCenter(N);\n    for (int i = 0; i < N; ++i) {\n        double dx = xs[i] - avgX;\n        double dy = ys[i] - avgY;\n        distCenter[i] = sqrt(dx * dx + dy * dy);\n    }\n\n    vector<BuildParams> paramList = {\n        {1.00, 0.02, 0.50, 0, 4, 12000, 4000, 200,   0,  60},\n        {0.85, 0.05, 2.00, 0, 3, 13000, 4200, 300,   0,  80},\n        {1.20, 0.00, 0.30, 0, 5,  9500, 3600, 150,   0,  40},\n        {0.80, 0.06, 3.00, 1, 0,  8000,    0,   0, 250,  90},\n        {0.60, 0.10, 4.50, 1, 0,  6500,    0,   0, 380, 130},\n        {1.05, 0.015,1.20, 0, 2, 15000, 3300, 100,   0,  50},\n        {0.95, 0.04, 2.60, 1, 0,  7000,    0,   0, 320, 110},\n        {0.50, 0.08, 5.00, 0, 5, 11000, 4600, 600,   0,  70},\n    };\n\n    mt19937 rng(123456789);\n    Solution best;\n    for (const auto& params : paramList) {\n        Solution sol = build_solution(adj, A, distCenter, H, params, rng);\n        if (sol.score > best.score) best = sol;\n    }\n    if (best.parent.empty()) {\n        best = build_solution(adj, A, distCenter, H, paramList.front(), rng);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << best.parent[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Candidate {\n    char dir;\n    int idx;\n    int shifts;\n    int removal;\n};\n\nstruct CandidateData {\n    char dir;\n    int idx;\n    int shifts;\n    int removal;\n    int cost;\n    double ratio;\n};\n\nstruct PlanResult {\n    vector<Candidate> seq;\n    int cost = 0;\n    bool success = false;\n};\n\nint countOni(const vector<string>& board) {\n    int cnt = 0;\n    for (const auto& row : board) {\n        for (char c : row) if (c == 'x') ++cnt;\n    }\n    return cnt;\n}\n\nchar oppositeDir(char dir) {\n    if (dir == 'U') return 'D';\n    if (dir == 'D') return 'U';\n    if (dir == 'L') return 'R';\n    return 'L';\n}\n\nint removeCells(vector<string>& board, const Candidate& cand) {\n    int N = board.size();\n    int removed = 0;\n    if (cand.dir == 'U') {\n        int limit = min(cand.shifts, N);\n        for (int r = 0; r < limit; ++r) {\n            char& cell = board[r][cand.idx];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'D') {\n        int limit = min(cand.shifts, N);\n        int start = N - limit;\n        for (int r = start; r < N; ++r) {\n            char& cell = board[r][cand.idx];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'L') {\n        int limit = min(cand.shifts, N);\n        for (int c = 0; c < limit; ++c) {\n            char& cell = board[cand.idx][c];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else { // 'R'\n        int limit = min(cand.shifts, N);\n        int start = N - limit;\n        for (int c = start; c < N; ++c) {\n            char& cell = board[cand.idx][c];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    }\n    return removed;\n}\n\nPlanResult greedyPlan(const vector<string>& initial, mt19937& rng, double tolerance) {\n    int N = initial.size();\n    vector<string> board = initial;\n    int total_oni = countOni(board);\n    PlanResult result;\n    vector<Candidate> seq;\n    seq.reserve(2 * N);\n    const int LIMIT = 4 * N * N;\n\n    while (total_oni > 0) {\n        vector<CandidateData> candidates;\n        candidates.reserve(4 * N);\n        auto addCandidate = [&](char dir, int idx, int shifts, int removal) {\n            if (shifts <= 0 || removal <= 0) return;\n            CandidateData cand{dir, idx, shifts, removal, 2 * shifts,\n                               static_cast<double>(2 * shifts) / removal};\n            candidates.push_back(cand);\n        };\n\n        for (int j = 0; j < N; ++j) {\n            int firstF = N;\n            for (int r = 0; r < N; ++r) if (board[r][j] == 'o') { firstF = r; break; }\n            int removal = 0, deepest = -1;\n            for (int r = 0; r < firstF; ++r) if (board[r][j] == 'x') { ++removal; deepest = r; }\n            if (removal > 0) addCandidate('U', j, deepest + 1, removal);\n\n            int lastF = -1;\n            for (int r = N - 1; r >= 0; --r) if (board[r][j] == 'o') { lastF = r; break; }\n            removal = 0; int top = -1;\n            for (int r = N - 1; r > lastF; --r) if (board[r][j] == 'x') { ++removal; top = r; }\n            if (removal > 0) addCandidate('D', j, N - top, removal);\n        }\n\n        for (int i = 0; i < N; ++i) {\n            int firstF = N;\n            for (int j = 0; j < N; ++j) if (board[i][j] == 'o') { firstF = j; break; }\n            int removal = 0, deepest = -1;\n            for (int j = 0; j < firstF; ++j) if (board[i][j] == 'x') { ++removal; deepest = j; }\n            if (removal > 0) addCandidate('L', i, deepest + 1, removal);\n\n            int lastF = -1;\n            for (int j = N - 1; j >= 0; --j) if (board[i][j] == 'o') { lastF = j; break; }\n            removal = 0; int leftmost = -1;\n            for (int j = N - 1; j > lastF; --j) if (board[i][j] == 'x') { ++removal; leftmost = j; }\n            if (removal > 0) addCandidate('R', i, N - leftmost, removal);\n        }\n\n        if (candidates.empty()) return result;\n\n        double min_ratio = candidates.front().ratio;\n        for (const auto& cand : candidates) min_ratio = min(min_ratio, cand.ratio);\n        double threshold = min_ratio * (1.0 + tolerance);\n        vector<int> eligible;\n        eligible.reserve(candidates.size());\n        for (int idx = 0; idx < (int)candidates.size(); ++idx)\n            if (candidates[idx].ratio <= threshold + 1e-9)\n                eligible.push_back(idx);\n        if (eligible.empty()) {\n            for (int idx = 0; idx < (int)candidates.size(); ++idx)\n                if (fabs(candidates[idx].ratio - min_ratio) <= 1e-9)\n                    eligible.push_back(idx);\n            if (eligible.empty()) eligible.push_back(0);\n        }\n\n        long long totalWeight = 0;\n        for (int id : eligible) {\n            long long w = 1LL * candidates[id].removal * candidates[id].removal;\n            if (w <= 0) w = 1;\n            totalWeight += w;\n        }\n        int chosenIdx = eligible[0];\n        if (totalWeight > 0) {\n            long long pick = rng() % totalWeight;\n            for (int id : eligible) {\n                long long w = 1LL * candidates[id].removal * candidates[id].removal;\n                if (w <= 0) w = 1;\n                if (pick < w) { chosenIdx = id; break; }\n                pick -= w;\n            }\n        } else {\n            chosenIdx = eligible[rng() % eligible.size()];\n        }\n\n        const auto& bestCand = candidates[chosenIdx];\n        Candidate op{bestCand.dir, bestCand.idx, bestCand.shifts, bestCand.removal};\n        int removed = removeCells(board, op);\n        if (removed <= 0) return result;\n        op.removal = removed;\n        seq.push_back(op);\n        total_oni -= removed;\n        result.cost += bestCand.cost;\n        if (result.cost > LIMIT) return result;\n    }\n\n    result.seq = move(seq);\n    result.success = true;\n    return result;\n}\n\nPlanResult sequentialPlan(const vector<string>& initial) {\n    int N = initial.size();\n    vector<string> board = initial;\n    int total_oni = countOni(board);\n    PlanResult result;\n    vector<Candidate> seq;\n    seq.reserve(2 * N);\n    const int LIMIT = 4 * N * N;\n\n    while (total_oni > 0) {\n        Candidate best{};\n        bool found = false;\n        int best_shifts = INT_MAX;\n\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (board[i][j] != 'x') continue;\n                auto consider = [&](char dir, int shifts) {\n                    if (shifts <= 0) return;\n                    if (shifts < best_shifts) {\n                        best_shifts = shifts;\n                        best.dir = dir;\n                        best.idx = (dir == 'U' || dir == 'D') ? j : i;\n                        best.shifts = shifts;\n                        found = true;\n                    }\n                };\n                bool ok = true;\n                for (int r = 0; r < i; ++r) if (board[r][j] == 'o') { ok = false; break; }\n                if (ok) consider('U', i + 1);\n                ok = true;\n                for (int r = i + 1; r < N; ++r) if (board[r][j] == 'o') { ok = false; break; }\n                if (ok) consider('D', N - i);\n                ok = true;\n                for (int c = 0; c < j; ++c) if (board[i][c] == 'o') { ok = false; break; }\n                if (ok) consider('L', j + 1);\n                ok = true;\n                for (int c = j + 1; c < N; ++c) if (board[i][c] == 'o') { ok = false; break; }\n                if (ok) consider('R', N - j);\n            }\n        }\n\n        if (!found) break;\n        int removed = removeCells(board, best);\n        if (removed <= 0) break;\n        best.removal = removed;\n        seq.push_back(best);\n        total_oni -= removed;\n        result.cost += 2 * best.shifts;\n        if (result.cost > LIMIT) break;\n    }\n\n    if (total_oni == 0 && result.cost <= 4 * N * N) {\n        result.seq = move(seq);\n        result.success = true;\n    }\n    return result;\n}\n\nbool simulatePlan(const vector<string>& initial, const PlanResult& plan,\n                  vector<pair<char,int>>& output) {\n    if (!plan.success) return false;\n    int N = initial.size();\n    int limit = 4 * N * N;\n    if (plan.cost > limit) return false;\n\n    vector<string> board = initial;\n    output.clear();\n    output.reserve(plan.cost + 4);\n    int total_oni = countOni(board);\n\n    auto doShift = [&](char dir, int idx) -> bool {\n        if ((int)output.size() >= limit) return false;\n        output.emplace_back(dir, idx);\n        char removed = '.';\n        if (dir == 'U') {\n            removed = board[0][idx];\n            for (int r = 0; r < N - 1; ++r) board[r][idx] = board[r + 1][idx];\n            board[N - 1][idx] = '.';\n        } else if (dir == 'D') {\n            removed = board[N - 1][idx];\n            for (int r = N - 1; r >= 1; --r) board[r][idx] = board[r - 1][idx];\n            board[0][idx] = '.';\n        } else if (dir == 'L') {\n            removed = board[idx][0];\n            for (int c = 0; c < N - 1; ++c) board[idx][c] = board[idx][c + 1];\n            board[idx][N - 1] = '.';\n        } else { // 'R'\n            removed = board[idx][N - 1];\n            for (int c = N - 1; c >= 1; --c) board[idx][c] = board[idx][c - 1];\n            board[idx][0] = '.';\n        }\n        if (removed == 'x') --total_oni;\n        else if (removed == 'o') return false;\n        return true;\n    };\n\n    for (const auto& cand : plan.seq) {\n        for (int s = 0; s < cand.shifts; ++s) {\n            if (!doShift(cand.dir, cand.idx)) {\n                output.clear();\n                return false;\n            }\n        }\n        char opp = oppositeDir(cand.dir);\n        for (int s = 0; s < cand.shifts; ++s) {\n            if (!doShift(opp, cand.idx)) {\n                output.clear();\n                return false;\n            }\n        }\n    }\n    if (total_oni != 0 || (int)output.size() > limit) {\n        output.clear();\n        return false;\n    }\n    return true;\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> board(N);\n    for (int i = 0; i < N; ++i) cin >> board[i];\n\n    uint64_t seed = 1469598103934665603ULL;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < N; ++i) {\n        seed ^= 0x9e3779b97f4a7c15ULL + (uint64_t)i + (seed << 6) + (seed >> 2);\n        for (char c : board[i]) {\n            seed ^= (uint64_t)(unsigned char)c + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n    const uint64_t baseSeed = seed;\n    mt19937 rng(seed);\n\n    const int MAX_TRIALS = 200;\n    const double MAX_TOL = 0.3;\n    uniform_real_distribution<double> dist(0.0, 1.0);\n\n    PlanResult best;\n    best.cost = numeric_limits<int>::max();\n    best.success = false;\n\n    for (int t = 0; t < MAX_TRIALS; ++t) {\n        double tol = (t == 0) ? 0.0 : pow(dist(rng), 2.0) * MAX_TOL;\n        PlanResult plan = greedyPlan(board, rng, tol);\n        if (!plan.success) continue;\n        if (!best.success || plan.cost < best.cost ||\n            (plan.cost == best.cost && plan.seq.size() < best.seq.size())) {\n            best = plan;\n        }\n    }\n    if (!best.success) {\n        mt19937 det_rng(baseSeed ^ 0x9e3779b97f4a7c15ULL);\n        best = greedyPlan(board, det_rng, 0.0);\n    }\n\n    vector<pair<char,int>> ops;\n    if (!simulatePlan(board, best, ops)) {\n        mt19937 det_rng(baseSeed ^ 0x9e3779b97f4a7c15ULL);\n        PlanResult detPlan = greedyPlan(board, det_rng, 0.0);\n        if (!detPlan.success || !simulatePlan(board, detPlan, ops)) {\n            PlanResult seqPlan = sequentialPlan(board);\n            simulatePlan(board, seqPlan, ops);\n        }\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 AssignState {\n    int N = 0;\n    int totalItems = 0;\n    vector<int> src;\n    vector<int> weights;\n    vector<int> dest;\n    vector<int> itemPos;\n    vector<vector<int>> binItems;\n    vector<long long> cap;\n    vector<long long> sum;\n    vector<long long> rem;\n    vector<char> locked;\n    long long penalty = 0;\n\n    void setup(int N_, const vector<int>& target) {\n        N = N_;\n        totalItems = 2 * N;\n        src.resize(totalItems);\n        weights.resize(totalItems);\n        dest.assign(totalItems, -1);\n        itemPos.assign(totalItems, -1);\n        binItems.assign(N, {});\n        cap.resize(N);\n        sum.assign(N, 0);\n        rem.assign(N, 0);\n        locked.assign(totalItems, 0);\n        penalty = 0;\n        for (int i = 0; i < N; ++i) {\n            int w = target[i];\n            src[2 * i] = src[2 * i + 1] = i;\n            weights[2 * i] = weights[2 * i + 1] = w;\n            cap[i] = 2LL * w;\n            rem[i] = cap[i];\n        }\n    }\n};\n\ndouble elapsedSec(const chrono::steady_clock::time_point& start) {\n    return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n}\n\nvoid initialAssign(AssignState& st, mt19937& rng) {\n    for (int j = 0; j < st.N; ++j) {\n        st.binItems[j].clear();\n        st.sum[j] = 0;\n        st.rem[j] = st.cap[j];\n    }\n    fill(st.dest.begin(), st.dest.end(), -1);\n    fill(st.itemPos.begin(), st.itemPos.end(), -1);\n    fill(st.locked.begin(), st.locked.end(), 0);\n    vector<int> order(st.totalItems);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (st.weights[a] != st.weights[b]) return st.weights[a] > st.weights[b];\n        return a < b;\n    });\n    priority_queue<pair<long long,int>> pq;\n    for (int j = 0; j < st.N; ++j) pq.push({st.rem[j], j});\n    auto popValid = [&]() {\n        while (true) {\n            auto [val, idx] = pq.top();\n            pq.pop();\n            if (val == st.rem[idx]) return idx;\n        }\n    };\n    for (int item : order) {\n        int bin = popValid();\n        st.dest[item] = bin;\n        st.itemPos[item] = st.binItems[bin].size();\n        st.binItems[bin].push_back(item);\n        st.sum[bin] += st.weights[item];\n        st.rem[bin] = st.cap[bin] - st.sum[bin];\n        pq.push({st.rem[bin], bin});\n    }\n    st.penalty = 0;\n    for (int j = 0; j < st.N; ++j) st.penalty += llabs(st.rem[j]);\n}\n\nlong long penaltyDelta(const AssignState& st, int item, int newBin) {\n    int oldBin = st.dest[item];\n    if (oldBin == newBin) return 0;\n    long long w = st.weights[item];\n    long long before = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n    long long after = llabs(st.rem[oldBin] + w) + llabs(st.rem[newBin] - w);\n    return after - before;\n}\n\nvoid moveItem(AssignState& st, int item, int newBin) {\n    int oldBin = st.dest[item];\n    if (oldBin == newBin) return;\n    long long w = st.weights[item];\n    long long oldPen = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n\n    int pos = st.itemPos[item];\n    int last = st.binItems[oldBin].back();\n    st.binItems[oldBin][pos] = last;\n    st.itemPos[last] = pos;\n    st.binItems[oldBin].pop_back();\n\n    st.sum[oldBin] -= w;\n    st.rem[oldBin] += w;\n\n    st.sum[newBin] += w;\n    st.rem[newBin] -= w;\n\n    st.itemPos[item] = st.binItems[newBin].size();\n    st.binItems[newBin].push_back(item);\n    st.dest[item] = newBin;\n\n    long long newPen = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n    st.penalty += newPen - oldPen;\n}\n\nvoid balance(AssignState& st, bool respectLocked,\n             const chrono::steady_clock::time_point& start, double totalLimit) {\n    while (true) {\n        if (elapsedSec(start) > totalLimit) break;\n        vector<int> posBins;\n        for (int j = 0; j < st.N; ++j) if (st.rem[j] > 0) posBins.push_back(j);\n        if (posBins.empty()) break;\n        sort(posBins.begin(), posBins.end(),\n             [&](int a, int b) { return st.rem[a] > st.rem[b]; });\n        bool moved = false;\n        for (int pos : posBins) {\n            long long remPos = st.rem[pos];\n            long long bestDiff = 0;\n            int bestItem = -1;\n            for (int neg = 0; neg < st.N; ++neg) {\n                if (st.rem[neg] >= 0) continue;\n                long long remNeg = st.rem[neg];\n                for (int item : st.binItems[neg]) {\n                    if (respectLocked && st.locked[item]) continue;\n                    long long w = st.weights[item];\n                    long long newPos = remPos - w;\n                    long long newNeg = remNeg + w;\n                    long long diff = llabs(newPos) + llabs(newNeg)\n                                    - (llabs(remPos) + llabs(remNeg));\n                    if (diff < bestDiff) {\n                        bestDiff = diff;\n                        bestItem = item;\n                    }\n                }\n            }\n            if (bestItem != -1) {\n                moveItem(st, bestItem, pos);\n                moved = true;\n                break;\n            }\n        }\n        if (!moved) break;\n    }\n}\n\nvoid randomImprove(AssignState& st, bool respectLocked, int maxIter,\n                   const chrono::steady_clock::time_point& start, double totalLimit,\n                   mt19937& rng) {\n    for (int iter = 0; iter < maxIter; ++iter) {\n        if (elapsedSec(start) > totalLimit) break;\n        int item = rng() % st.totalItems;\n        if (respectLocked && st.locked[item]) continue;\n        int from = st.dest[item];\n        if (from < 0) continue;\n        int bestBin = -1;\n        long long bestDelta = 0;\n        for (int attempt = 0; attempt < 6; ++attempt) {\n            int cand = rng() % st.N;\n            if (cand == from) continue;\n            long long delta = penaltyDelta(st, item, cand);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestBin = cand;\n            }\n        }\n        if (bestBin == -1) continue;\n        moveItem(st, item, bestBin);\n    }\n}\n\nstruct SCCResult {\n    vector<int> comp;\n    int cnt;\n};\n\nSCCResult computeSCC(const vector<int>& a, const vector<int>& b) {\n    int N = a.size();\n    vector<vector<int>> g(N), gr(N);\n    for (int i = 0; i < N; ++i) {\n        g[i].push_back(a[i]);\n        g[i].push_back(b[i]);\n        gr[a[i]].push_back(i);\n        gr[b[i]].push_back(i);\n    }\n    vector<int> used(N, 0), order;\n    auto dfs1 = [&](auto self, int v) -> void {\n        used[v] = 1;\n        for (int to : g[v]) if (!used[to]) self(self, to);\n        order.push_back(v);\n    };\n    for (int i = 0; i < N; ++i) if (!used[i]) dfs1(dfs1, i);\n    vector<int> comp(N, -1);\n    int compId = 0;\n    auto dfs2 = [&](auto self, int v) -> void {\n        comp[v] = compId;\n        for (int to : gr[v]) if (comp[to] == -1) self(self, to);\n    };\n    for (int i = N - 1; i >= 0; --i) {\n        int v = order[i];\n        if (comp[v] == -1) {\n            dfs2(dfs2, v);\n            ++compId;\n        }\n    }\n    return {comp, compId};\n}\n\nint ensureConnectivity(AssignState& st,\n                       const chrono::steady_clock::time_point& start,\n                       double totalLimit) {\n    vector<int> a(st.N), b(st.N);\n    for (int i = 0; i < st.N; ++i) {\n        a[i] = st.dest[2 * i];\n        b[i] = st.dest[2 * i + 1];\n    }\n    auto scc = computeSCC(a, b);\n    int K = scc.cnt;\n    if (K == 1) return 0;\n    vector<vector<int>> nodesIn(K);\n    for (int i = 0; i < st.N; ++i) nodesIn[scc.comp[i]].push_back(i);\n    vector<int> order(K);\n    iota(order.begin(), order.end(), 0);\n    int lockedAdded = 0;\n    for (int idx = 0; idx < K; ++idx) {\n        if (elapsedSec(start) > totalLimit) break;\n        int fromC = order[idx];\n        int toC = order[(idx + 1) % K];\n        vector<int> existing;\n        for (int node : nodesIn[fromC]) {\n            for (int t = 0; t < 2; ++t) {\n                int item = 2 * node + t;\n                if (st.dest[item] >= 0 && scc.comp[st.dest[item]] == toC) {\n                    existing.push_back(item);\n                }\n            }\n        }\n        if (!existing.empty()) {\n            int bestEdge = existing[0];\n            for (int item : existing) {\n                if (st.weights[item] < st.weights[bestEdge]) bestEdge = item;\n            }\n            st.locked[bestEdge] = 1;\n            ++lockedAdded;\n            continue;\n        }\n        long long bestDelta = (1LL << 60);\n        int bestEdge = -1, bestDest = -1;\n        for (int node : nodesIn[fromC]) {\n            for (int t = 0; t < 2; ++t) {\n                int item = 2 * node + t;\n                if (st.locked[item]) continue;\n                for (int destNode : nodesIn[toC]) {\n                    long long delta = penaltyDelta(st, item, destNode);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestEdge = item;\n                        bestDest = destNode;\n                    }\n                }\n            }\n        }\n        if (bestEdge == -1) continue;\n        moveItem(st, bestEdge, bestDest);\n        st.locked[bestEdge] = 1;\n        ++lockedAdded;\n    }\n    return lockedAdded;\n}\n\nstruct SimResult {\n    vector<int> cnt;\n    long long error;\n};\n\nSimResult simulatePlan(const vector<int>& a, const vector<int>& b,\n                       int L, const vector<int>& target) {\n    int N = a.size();\n    vector<int> cnt(N, 0);\n    int cur = 0;\n    cnt[cur]++;\n    for (int step = 1; step < L; ++step) {\n        int nxt = (cnt[cur] & 1) ? a[cur] : b[cur];\n        cur = nxt;\n        cnt[cur]++;\n    }\n    long long err = 0;\n    for (int i = 0; i < N; ++i) err += llabs(1LL * cnt[i] - target[i]);\n    return {cnt, err};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\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    auto start = chrono::steady_clock::now();\n    const double TOTAL_LIMIT = 1.9;\n\n    AssignState st;\n    st.setup(N, T);\n    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    initialAssign(st, rng);\n    balance(st, false, start, TOTAL_LIMIT);\n    randomImprove(st, false, 250000, start, TOTAL_LIMIT, rng);\n    balance(st, false, start, TOTAL_LIMIT);\n\n    int lockedCount = ensureConnectivity(st, start, TOTAL_LIMIT);\n    if (lockedCount > 0) {\n        balance(st, true, start, TOTAL_LIMIT);\n        randomImprove(st, true, 120000, start, TOTAL_LIMIT, rng);\n        balance(st, true, start, TOTAL_LIMIT);\n    }\n\n    vector<int> a(N), b(N);\n    for (int i = 0; i < N; ++i) {\n        a[i] = st.dest[2 * i];\n        b[i] = st.dest[2 * i + 1];\n        if (a[i] < 0) a[i] = i;\n        if (b[i] < 0) b[i] = i;\n    }\n\n    // Optional: simulate to ensure the plan is evaluated (not printed)\n    auto sim = simulatePlan(a, b, L, T);\n    (void)sim;\n\n    for (int i = 0; i < N; ++i) {\n        cout << a[i] << ' ' << b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct MSTResult {\n    vector<pair<int, int>> edges;\n    double cost = 0.0;\n};\n\nlong long hilbertOrder(long long x, long long y, int pow = 15, int rot = 0) {\n    if (pow == 0) return 0;\n    long long h = 1LL << (pow - 1);\n    long long seg = ((x < h) ? 0 : 1) | ((y < h) ? 0 : 2);\n    seg = (seg + rot) & 3;\n    static const int rotateDelta[4] = {3, 0, 0, 1};\n    long long nx = x & (h - 1);\n    long long ny = y & (h - 1);\n    int nrot = (rot + rotateDelta[seg]) & 3;\n    long long subSize = 1LL << (2 * pow - 2);\n    long long add = hilbertOrder(nx, ny, pow - 1, nrot);\n    if (seg == 1 || seg == 2) {\n        return seg * subSize + add;\n    } else {\n        return seg * subSize + (subSize - add - 1);\n    }\n}\n\nvector<int> build_global_parent(const vector<double>& px, const vector<double>& py) {\n    int n = (int)px.size();\n    const double INF = 1e100;\n    vector<double> best(n, INF);\n    vector<int> parent(n, -1);\n    vector<char> used(n, 0);\n    if (n == 0) return parent;\n    best[0] = 0.0;\n    for (int it = 0; it < n; ++it) {\n        int v = -1;\n        double bv = INF;\n        for (int i = 0; i < n; ++i) {\n            if (!used[i] && best[i] < bv) {\n                bv = best[i];\n                v = i;\n            }\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        for (int u = 0; u < n; ++u) if (!used[u]) {\n            double dx = px[v] - px[u];\n            double dy = py[v] - py[u];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[u]) {\n                best[u] = dist;\n                parent[u] = v;\n            }\n        }\n    }\n    for (int i = 1; i < n; ++i) if (parent[i] == -1) parent[i] = 0;\n    return parent;\n}\n\nMSTResult build_group_mst(const vector<int>& nodes, const vector<double>& px, const vector<double>& py) {\n    MSTResult res;\n    int k = (int)nodes.size();\n    if (k <= 1) return res;\n    res.edges.reserve(k - 1);\n    const double INF = 1e100;\n    vector<double> best(k, INF);\n    vector<int> parent(k, -1);\n    vector<char> used(k, 0);\n    best[0] = 0.0;\n    for (int iter = 0; iter < k; ++iter) {\n        int v = -1;\n        double bv = INF;\n        for (int i = 0; i < k; ++i) {\n            if (!used[i] && best[i] < bv) {\n                bv = best[i];\n                v = i;\n            }\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        if (parent[v] != -1) {\n            int a = nodes[v], b = nodes[parent[v]];\n            res.edges.emplace_back(a, b);\n            double dx = px[a] - px[b];\n            double dy = py[a] - py[b];\n            double dist = dx * dx + dy * dy;\n            if (dist < 0) dist = 0;\n            res.cost += std::sqrt(dist);\n        }\n        for (int j = 0; j < k; ++j) {\n            if (used[j]) continue;\n            double dx = px[nodes[v]] - px[nodes[j]];\n            double dy = py[nodes[v]] - py[nodes[j]];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[j]) {\n                best[j] = dist;\n                parent[j] = v;\n            }\n        }\n    }\n    if ((int)res.edges.size() != k - 1) {\n        res.edges.clear();\n        res.cost = 0.0;\n        for (int i = 1; i < k; ++i) {\n            int a = nodes[i - 1], b = nodes[i];\n            res.edges.emplace_back(a, b);\n            double dx = px[a] - px[b];\n            double dy = py[a] - py[b];\n            double dist = dx * dx + dy * dy;\n            if (dist < 0) dist = 0;\n            res.cost += std::sqrt(dist);\n        }\n    }\n    return res;\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) cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n\n    vector<double> px(N), py(N);\n    vector<int> ix(N), iy(N);\n    for (int i = 0; i < N; ++i) {\n        px[i] = 0.5 * (lx[i] + rx[i]);\n        py[i] = 0.5 * (ly[i] + ry[i]);\n        ix[i] = (lx[i] + rx[i]) / 2;\n        iy[i] = (ly[i] + ry[i]) / 2;\n    }\n\n    vector<long long> hilb(N);\n    for (int i = 0; i < N; ++i) {\n        hilb[i] = hilbertOrder(ix[i], iy[i], 15, 0);\n    }\n\n    vector<int> parent = build_global_parent(px, py);\n    vector<vector<int>> adj(N);\n    for (int v = 1; v < N; ++v) {\n        int p = parent[v];\n        if (p < 0 || p >= N || p == v) p = 0;\n        adj[v].push_back(p);\n        adj[p].push_back(v);\n    }\n    for (int v = 0; v < N; ++v) {\n        auto &nbr = adj[v];\n        sort(nbr.begin(), nbr.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n        nbr.erase(unique(nbr.begin(), nbr.end()), nbr.end());\n    }\n\n    vector<int> order_mst;\n    order_mst.reserve(N);\n    vector<char> vis(N, 0);\n    auto dfs = [&](auto self, int u, int p) -> void {\n        vis[u] = 1;\n        order_mst.push_back(u);\n        for (int v : adj[u]) if (v != p && !vis[v]) self(self, v, u);\n    };\n    for (int i = 0; i < N; ++i) if (!vis[i]) dfs(dfs, i, -1);\n\n    vector<int> base(N);\n    iota(base.begin(), base.end(), 0);\n\n    uint64_t seed = 1234567;\n    seed = seed * 1000003ULL + N;\n    seed = seed * 1000003ULL + M;\n    seed = seed * 1000003ULL + Q;\n    seed = seed * 1000003ULL + L;\n    seed = seed * 1000003ULL + W;\n    for (int i = 0; i < min(N, 10); ++i) {\n        seed = seed * 1000003ULL + (uint64_t)(ix[i] + 10001);\n        seed = seed * 1000003ULL + (uint64_t)(iy[i] + 10001);\n    }\n    std::mt19937 rng(static_cast<uint32_t>(seed));\n\n    auto hash_order = [&](const vector<int>& ord) -> uint64_t {\n        uint64_t h = 0;\n        for (int v : ord) h = h * 1000003ULL + (uint64_t)(v + 1);\n        return h;\n    };\n\n    auto build_groups = [&](const vector<int>& ord, vector<vector<int>>& groups) -> bool {\n        if (ord.size() != (size_t)N) return false;\n        size_t pos = 0;\n        for (int i = 0; i < M; ++i) {\n            size_t need = (size_t)G[i];\n            if (pos + need > ord.size()) return false;\n            groups[i].assign(ord.begin() + pos, ord.begin() + pos + need);\n            pos += need;\n        }\n        return pos == ord.size();\n    };\n\n    unordered_set<uint64_t> seen;\n    seen.reserve(64);\n    seen.max_load_factor(0.7f);\n\n    vector<vector<int>> bestGroups;\n    vector<vector<pair<int,int>>> bestEdges;\n    double bestCost = 1e100;\n    bool haveBest = false;\n\n    auto add_candidate = [&](const vector<int>& ord) {\n        uint64_t h = hash_order(ord);\n        if (!seen.insert(h).second) return;\n        vector<vector<int>> groups(M);\n        if (!build_groups(ord, groups)) return;\n        vector<vector<pair<int,int>>> edges(M);\n        double total = 0.0;\n        for (int i = 0; i < M; ++i) {\n            auto res = build_group_mst(groups[i], px, py);\n            edges[i] = std::move(res.edges);\n            total += res.cost;\n        }\n        if (!haveBest || total < bestCost) {\n            haveBest = true;\n            bestCost = total;\n            bestGroups = std::move(groups);\n            bestEdges = std::move(edges);\n        }\n    };\n\n    add_candidate(base);\n    {\n        vector<int> tmp = base;\n        reverse(tmp.begin(), tmp.end());\n        add_candidate(tmp);\n    }\n    add_candidate(order_mst);\n    {\n        vector<int> tmp = order_mst;\n        reverse(tmp.begin(), tmp.end());\n        add_candidate(tmp);\n    }\n    {\n        vector<int> tmp = base;\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n        add_candidate(tmp);\n        reverse(tmp.begin(), tmp.end());\n        add_candidate(tmp);\n    }\n    auto add_sorted = [&](auto cmp) {\n        vector<int> ord = base;\n        sort(ord.begin(), ord.end(), cmp);\n        add_candidate(ord);\n    };\n    add_sorted([&](int a, int b) {\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        if (iy[a] != iy[b]) return iy[a] < iy[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        if (iy[a] != iy[b]) return iy[a] < iy[b];\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] + iy[a];\n        long long kb = (long long)ix[b] + iy[b];\n        if (ka != kb) return ka < kb;\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] - iy[a];\n        long long kb = (long long)ix[b] - iy[b];\n        if (ka != kb) return ka < kb;\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    if (N > 1) {\n        for (int iter = 0; iter < 2; ++iter) {\n            vector<int> ord = base;\n            shuffle(ord.begin(), ord.end(), rng);\n            add_candidate(ord);\n        }\n    }\n\n    if (!haveBest) {\n        vector<vector<int>> groups(M);\n        build_groups(base, groups);\n        vector<vector<pair<int,int>>> edges(M);\n        double total = 0.0;\n        for (int i = 0; i < M; ++i) {\n            auto res = build_group_mst(groups[i], px, py);\n            edges[i] = std::move(res.edges);\n            total += res.cost;\n        }\n        bestGroups = std::move(groups);\n        bestEdges = std::move(edges);\n    }\n\n    cout << \"!\\n\";\n    for (int i = 0; i < M; ++i) {\n        for (size_t j = 0; j < bestGroups[i].size(); ++j) {\n            if (j) cout << ' ';\n            cout << bestGroups[i][j];\n        }\n        cout << '\\n';\n        for (const auto& e : bestEdges[i]) {\n            cout << e.first << ' ' << e.second << '\\n';\n        }\n    }\n    cout.flush();\n    return 0;\n}","ahc046":"#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<pair<int,int>> pts(M);\n    for (int k = 0; k < M; ++k) cin >> pts[k].first >> pts[k].second;\n\n    vector<pair<char,char>> actions;\n    int r = pts[0].first, c = pts[0].second;\n\n    for (int k = 1; k < M; ++k) {\n        auto [tr, tc] = pts[k];\n        while (r < tr) { actions.emplace_back('M', 'D'); ++r; }\n        while (r > tr) { actions.emplace_back('M', 'U'); --r; }\n        while (c < tc) { actions.emplace_back('M', 'R'); ++c; }\n        while (c > tc) { actions.emplace_back('M', 'L'); --c; }\n    }\n\n    for (auto &ac : actions) {\n        cout << ac.first << ' ' << ac.second << '\\n';\n    }\n    return 0;\n}"},"2":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Rect {\n    int x1, y1, x2, y2;\n};\n\nconst int BOARD_SIZE = 10000;\nconst int GROW_ITER_PER_RECT = 7;\nconst int SHRINK_ITER_PER_RECT = 4;\nconst int EXPAND_STEP_LIMIT = 1000;\nconst int SHRINK_STEP_LIMIT = 1000;\nconst int RANDOM_SHRINK_STEP_LIMIT = 40;\nconst int STAGNATION_LIMIT = 32;\n\nlong long rect_area(const Rect &r) {\n    return 1LL * (r.x2 - r.x1) * (r.y2 - r.y1);\n}\n\narray<int, 4> compute_expand_limits(const vector<Rect> &rects, int idx) {\n    const Rect &ri = rects[idx];\n    array<int, 4> lim = {ri.x1, BOARD_SIZE - ri.x2, ri.y1, BOARD_SIZE - ri.y2};\n    int n = rects.size();\n    for (int j = 0; j < n; ++j) if (j != idx) {\n        const Rect &rj = rects[j];\n        bool overlapY = (ri.y1 < rj.y2) && (ri.y2 > rj.y1);\n        bool overlapX = (ri.x1 < rj.x2) && (ri.x2 > rj.x1);\n        if (overlapY) {\n            if (rj.x2 <= ri.x1) {\n                int gap = max(0, ri.x1 - rj.x2);\n                lim[0] = min(lim[0], gap);\n            }\n            if (rj.x1 >= ri.x2) {\n                int gap = max(0, rj.x1 - ri.x2);\n                lim[1] = min(lim[1], gap);\n            }\n        }\n        if (overlapX) {\n            if (rj.y2 <= ri.y1) {\n                int gap = max(0, ri.y1 - rj.y2);\n                lim[2] = min(lim[2], gap);\n            }\n            if (rj.y1 >= ri.y2) {\n                int gap = max(0, rj.y1 - ri.y2);\n                lim[3] = min(lim[3], gap);\n            }\n        }\n    }\n    for (int d = 0; d < 4; ++d) lim[d] = max(lim[d], 0);\n    return lim;\n}\n\nbool grow_rect(int idx, vector<Rect> &rects, const vector<int> &target, mt19937 &rng) {\n    bool changed = false;\n    int n = rects.size();\n    for (int iter = 0; iter < GROW_ITER_PER_RECT; ++iter) {\n        Rect &rc = rects[idx];\n        long long width = rc.x2 - rc.x1;\n        long long height = rc.y2 - rc.y1;\n        long long area = width * height;\n        long long def = (long long)target[idx] - area;\n        if (def <= 0) break;\n\n        auto lim = compute_expand_limits(rects, idx);\n        long long unitArea[4] = {height, height, width, width};\n        double baseW = width + 0.5;\n        double baseH = height + 0.5;\n\n        double bestScore = -1;\n        vector<int> bestDirs;\n        for (int dir = 0; dir < 4; ++dir) {\n            int max_step = lim[dir];\n            if (max_step <= 0) continue;\n            long long uArea = unitArea[dir];\n            if (uArea <= 0) continue;\n            long long potential = 1LL * max_step * uArea;\n            long long effective = min(def, potential);\n            if (effective <= 0) continue;\n            double weight = 1.0;\n            if (dir <= 1) weight = baseH / baseW;\n            else weight = baseW / baseH;\n            double score = effective * weight;\n            if (score > bestScore + 1e-6) {\n                bestScore = score;\n                bestDirs.clear();\n                bestDirs.push_back(dir);\n            } else if (fabs(score - bestScore) <= 1e-6) {\n                bestDirs.push_back(dir);\n            }\n        }\n        if (bestDirs.empty()) break;\n        int dir = bestDirs[rng() % bestDirs.size()];\n        long long uArea = unitArea[dir];\n        if (uArea <= 0) break;\n        long long needed_units = (def + uArea - 1) / uArea;\n        long long limit = lim[dir];\n        if (limit <= 0) break;\n        limit = min<long long>(limit, EXPAND_STEP_LIMIT);\n        long long w = max(1LL, min(limit, needed_units));\n        if (dir == 0) rc.x1 -= (int)w;\n        else if (dir == 1) rc.x2 += (int)w;\n        else if (dir == 2) rc.y1 -= (int)w;\n        else rc.y2 += (int)w;\n        changed = true;\n    }\n    return changed;\n}\n\nbool shrink_rect(int idx, vector<Rect> &rects, const vector<int> &target,\n                 const vector<int> &xs, const vector<int> &ys, mt19937 &rng) {\n    bool changed = false;\n    for (int iter = 0; iter < SHRINK_ITER_PER_RECT; ++iter) {\n        Rect &rc = rects[idx];\n        long long width = rc.x2 - rc.x1;\n        long long height = rc.y2 - rc.y1;\n        long long area = width * height;\n        long long def = (long long)target[idx] - area;\n        if (def >= 0) break;\n        int avail[4] = {\n            xs[idx] - rc.x1,\n            rc.x2 - (xs[idx] + 1),\n            ys[idx] - rc.y1,\n            rc.y2 - (ys[idx] + 1)\n        };\n        long long unitArea[4] = {height, height, width, width};\n        double bestScore = -1;\n        vector<int> dirs;\n        for (int dir = 0; dir < 4; ++dir) {\n            if (avail[dir] <= 0 || unitArea[dir] <= 0) continue;\n            long long potential = 1LL * avail[dir] * unitArea[dir];\n            if (potential <= 0) continue;\n            long long effective = min(-def, potential);\n            double score = effective;\n            if (score > bestScore + 1e-6) {\n                bestScore = score;\n                dirs.clear();\n                dirs.push_back(dir);\n            } else if (fabs(score - bestScore) <= 1e-6) {\n                dirs.push_back(dir);\n            }\n        }\n        if (dirs.empty()) break;\n        int dir = dirs[rng() % dirs.size()];\n        long long uArea = unitArea[dir];\n        long long need_units = (-def + uArea - 1) / uArea;\n        long long limit = min<long long>(avail[dir], SHRINK_STEP_LIMIT);\n        if (limit <= 0) break;\n        long long w = max(1LL, min(limit, need_units));\n        if (dir == 0) rc.x1 += (int)w;\n        else if (dir == 1) rc.x2 -= (int)w;\n        else if (dir == 2) rc.y1 += (int)w;\n        else rc.y2 -= (int)w;\n        changed = true;\n    }\n    return changed;\n}\n\nbool shrink_phase(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                  const vector<int> &target, mt19937 &rng) {\n    int n = rects.size();\n    vector<pair<long long, int>> overs;\n    overs.reserve(n);\n    for (int i = 0; i < n; ++i) {\n        long long def = (long long)target[i] - rect_area(rects[i]);\n        if (def < 0) overs.emplace_back(-def, i);\n    }\n    sort(overs.begin(), overs.end(), greater<>());\n    bool changed = false;\n    for (auto &p : overs) {\n        if (shrink_rect(p.second, rects, target, xs, ys, rng)) changed = true;\n    }\n    return changed;\n}\n\nbool random_shrink(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                   mt19937 &rng, int operations) {\n    int n = rects.size();\n    if (n == 0) return false;\n    bool changed = false;\n    uniform_int_distribution<int> dist_idx(0, n - 1);\n    for (int t = 0; t < operations; ++t) {\n        int idx = dist_idx(rng);\n        Rect &rc = rects[idx];\n        int avail[4] = {\n            xs[idx] - rc.x1,\n            rc.x2 - (xs[idx] + 1),\n            ys[idx] - rc.y1,\n            rc.y2 - (ys[idx] + 1)\n        };\n        vector<int> dirs;\n        for (int d = 0; d < 4; ++d) if (avail[d] > 0) dirs.push_back(d);\n        if (dirs.empty()) continue;\n        int dir = dirs[rng() % dirs.size()];\n        int cap = min(avail[dir], RANDOM_SHRINK_STEP_LIMIT);\n        if (cap <= 0) continue;\n        int amount = 1 + (cap > 1 ? rng() % cap : 0);\n        if (dir == 0) rc.x1 += amount;\n        else if (dir == 1) rc.x2 -= amount;\n        else if (dir == 2) rc.y1 += amount;\n        else rc.y2 -= amount;\n        changed = true;\n    }\n    return changed;\n}\n\ndouble compute_score(const vector<Rect> &rects, const vector<int> &target) {\n    double sum = 0.0;\n    int n = rects.size();\n    for (int i = 0; i < n; ++i) {\n        long long s = rect_area(rects[i]);\n        long long r = target[i];\n        if (s <= 0 || r <= 0) continue;\n        long long mn = min(s, r);\n        long long mx = max(s, r);\n        if (mx == 0) continue;\n        double ratio = (double)mn / (double)mx;\n        double p = 2.0 * ratio - ratio * ratio;\n        sum += p;\n    }\n    return sum;\n}\n\nbool validate_rects(const vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys) {\n    int n = rects.size();\n    for (int i = 0; i < n; ++i) {\n        const Rect &r = rects[i];\n        if (r.x1 < 0 || r.x1 >= r.x2 || r.x2 > BOARD_SIZE) return false;\n        if (r.y1 < 0 || r.y1 >= r.y2 || r.y2 > BOARD_SIZE) return false;\n        if (!(r.x1 <= xs[i] && xs[i] + 1 <= r.x2)) return false;\n        if (!(r.y1 <= ys[i] && ys[i] + 1 <= r.y2)) return false;\n    }\n    for (int i = 0; i < n; ++i) {\n        for (int j = i + 1; j < n; ++j) {\n            const Rect &a = rects[i];\n            const Rect &b = rects[j];\n            if (max(a.x1, b.x1) < min(a.x2, b.x2) &&\n                max(a.y1, b.y1) < min(a.y2, b.y2)) return false;\n        }\n    }\n    return true;\n}\n\nstruct AttemptResult {\n    vector<Rect> rects;\n    double score;\n};\n\nAttemptResult run_attempt(const vector<Rect> &start_rects, const vector<int> &xs, const vector<int> &ys,\n                          const vector<int> &target, mt19937 &rng,\n                          const chrono::steady_clock::time_point &start_time,\n                          double time_limit) {\n    vector<Rect> rects = start_rects;\n    vector<Rect> best_rect = rects;\n    double best_score = compute_score(rects, target);\n    int n = rects.size();\n    vector<long long> defs(n);\n    int stagnation = 0;\n\n    for (int pass = 0; ; ++pass) {\n        if ((pass & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n            if (elapsed >= time_limit) break;\n        }\n        for (int i = 0; i < n; ++i) defs[i] = (long long)target[i] - rect_area(rects[i]);\n\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n        bool sort_by_def = (pass % 3 != 1);\n        if (sort_by_def) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (defs[a] != defs[b]) return defs[a] > defs[b];\n                return a < b;\n            });\n        }\n\n        bool changedExp = false;\n        for (int idx : order) {\n            if (grow_rect(idx, rects, target, rng)) changedExp = true;\n        }\n\n        bool changedShrink = shrink_phase(rects, xs, ys, target, rng);\n        bool changed = changedExp || changedShrink;\n        bool randomChanged = false;\n\n        if (!changed) {\n            stagnation++;\n            if (stagnation % 3 == 0) {\n                int ops = max(1, n / 4);\n                randomChanged = random_shrink(rects, xs, ys, rng, ops);\n            }\n            if (randomChanged) {\n                changed = true;\n                stagnation = 0;\n            } else if (stagnation > STAGNATION_LIMIT) {\n                rects = best_rect;\n                bool perturbed = random_shrink(rects, xs, ys, rng, max(1, n));\n                stagnation = 0;\n                if (!perturbed) break;\n                else continue;\n            }\n        } else {\n            stagnation = 0;\n        }\n\n        double cur_score = compute_score(rects, target);\n        if (cur_score > best_score + 1e-9) {\n            best_score = cur_score;\n            best_rect = rects;\n        }\n    }\n    return {best_rect, best_score};\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> xs(n), ys(n), rs(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> xs[i] >> ys[i] >> rs[i];\n    }\n\n    vector<Rect> base(n);\n    for (int i = 0; i < n; ++i) {\n        base[i] = {xs[i], ys[i], xs[i] + 1, ys[i] + 1};\n    }\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    const double TIME_LIMIT = 4.85;\n    auto start_time = chrono::steady_clock::now();\n\n    vector<Rect> seed = base;\n    vector<Rect> best = base;\n    double best_score = compute_score(base, rs);\n\n    while (true) {\n        AttemptResult res = run_attempt(seed, xs, ys, rs, rng, start_time, TIME_LIMIT);\n        if (res.score > best_score + 1e-9) {\n            best_score = res.score;\n            best = res.rects;\n        }\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n        if (elapsed >= TIME_LIMIT - 0.2) break;\n        seed = res.rects;\n        if (!random_shrink(seed, xs, ys, rng, max(1, n / 2))) break;\n    }\n\n    if (!validate_rects(best, xs, ys)) best = base;\n\n    for (const auto &r : best) {\n        cout << r.x1 << ' ' << r.y1 << ' ' << r.x2 << ' ' << r.y2 << '\\n';\n    }\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int N2 = N * N;\n    static constexpr int MAX_TILES = 2500;\n    using VisitBitset = bitset<MAX_TILES>;\n\n    struct Neighbor {\n        int to;\n        char dir;\n    };\n    struct Node {\n        VisitBitset visited;\n        int pos = 0;\n        int score = 0;\n        int parent = -1;\n        char move = '?';\n        int depth = 0;\n    };\n    struct Candidate {\n        double eval;\n        int idx;\n    };\n    struct Features {\n        int mobility = 0;\n        int nei1 = 0;\n        int nei2 = 0;\n        int two = 0;\n    };\n\n    vector<int> tileOf;\n    vector<int> value;\n    vector<vector<Neighbor>> adj;\n    int startIdx = 0;\n\n    mt19937_64 rng;\n    chrono::steady_clock::time_point timeStart;\n    string bestPath;\n    int bestScore = 0;\n\n    const double TIME_LIMIT = 1.95;\n    const double LENGTH_WEIGHT = 8.0;\n    const double MOBILITY_WEIGHT = 16.0;\n    const double NEI1_WEIGHT = 1.1;\n    const double NEI2_WEIGHT = 0.4;\n    const double TWO_WEIGHT = 0.6;\n    const double RANDOM_WEIGHT = 0.8;\n\n    const double GREEDY_VALUE_WEIGHT = 1.0;\n    const double GREEDY_MOB_WEIGHT = 20.0;\n    const double GREEDY_NEI_WEIGHT = 0.9;\n    const double GREEDY_TWO_WEIGHT = 0.4;\n    const double GREEDY_RANDOM_WEIGHT = 0.4;\n    const int MAX_GREEDY_STEPS = 1500;\n    const int MAX_GREEDY_CANDIDATES = 3;\n\n    inline double rand01() {\n        static constexpr double INV = 1.0 / (1ULL << 53);\n        return (rng() >> 11) * INV;\n    }\n    inline double elapsed() const {\n        using namespace chrono;\n        return duration<double>(steady_clock::now() - timeStart).count();\n    }\n    inline bool timeUp() const {\n        return elapsed() > TIME_LIMIT;\n    }\n\n    Features calcFeatures(const VisitBitset &vis, int pos) const {\n        Features feat;\n        for (const auto &nb : adj[pos]) {\n            if (vis.test(tileOf[nb.to])) continue;\n            ++feat.mobility;\n            int val = value[nb.to];\n            if (val >= feat.nei1) {\n                feat.nei2 = feat.nei1;\n                feat.nei1 = val;\n            } else if (val > feat.nei2) {\n                feat.nei2 = val;\n            }\n            for (const auto &nb2 : adj[nb.to]) {\n                if (vis.test(tileOf[nb2.to])) continue;\n                int val2 = value[nb2.to];\n                if (val2 > feat.two) feat.two = val2;\n            }\n        }\n        return feat;\n    }\n\n    string buildPath(const vector<Node> &pool, int idx) const {\n        string res;\n        res.reserve(pool[idx].depth);\n        int cur = idx;\n        while (cur != -1) {\n            const Node &node = pool[cur];\n            if (node.parent == -1) break;\n            res.push_back(node.move);\n            cur = node.parent;\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    void greedyExtend(const Node &startNode, string path) {\n        VisitBitset vis = startNode.visited;\n        int pos = startNode.pos;\n        int score = startNode.score;\n        array<Neighbor, 4> moveBuf;\n        int steps = 0;\n        while (!timeUp() && steps < MAX_GREEDY_STEPS) {\n            int moveCount = 0;\n            for (const auto &nb : adj[pos]) {\n                if (vis.test(tileOf[nb.to])) continue;\n                moveBuf[moveCount++] = nb;\n            }\n            if (moveCount == 0) break;\n            double bestEval = -1e100;\n            int bestIdx = -1;\n            VisitBitset bestVis;\n            for (int i = 0; i < moveCount; ++i) {\n                VisitBitset nextVis = vis;\n                nextVis.set(tileOf[moveBuf[i].to]);\n                Features feat = calcFeatures(nextVis, moveBuf[i].to);\n                double eval = GREEDY_VALUE_WEIGHT * value[moveBuf[i].to]\n                            + GREEDY_MOB_WEIGHT * feat.mobility\n                            + GREEDY_NEI_WEIGHT * feat.nei1\n                            + GREEDY_TWO_WEIGHT * feat.two\n                            + GREEDY_RANDOM_WEIGHT * rand01();\n                if (eval > bestEval) {\n                    bestEval = eval;\n                    bestIdx = i;\n                    bestVis = nextVis;\n                }\n            }\n            if (bestIdx == -1) break;\n            const Neighbor &chosen = moveBuf[bestIdx];\n            vis = bestVis;\n            pos = chosen.to;\n            score += value[pos];\n            path.push_back(chosen.dir);\n            ++steps;\n        }\n        if (score > bestScore || (score == bestScore && path.size() > bestPath.size())) {\n            bestScore = score;\n            bestPath = std::move(path);\n        }\n    }\n\n    void runBeam(int beamWidth) {\n        if (timeUp()) return;\n        const size_t MAX_POOL_RESERVE = 220000;\n        vector<Node> pool;\n        size_t reserveSize = min<size_t>(static_cast<size_t>(beamWidth) * 900 + 1000ULL, MAX_POOL_RESERVE);\n        pool.reserve(reserveSize);\n\n        pool.emplace_back();\n        Node &root = pool.back();\n        root.visited.reset();\n        root.visited.set(tileOf[startIdx]);\n        root.pos = startIdx;\n        root.score = value[startIdx];\n        root.parent = -1;\n        root.move = '?';\n        root.depth = 0;\n\n        int runBestIdx = 0;\n        int runBestScore = root.score;\n\n        vector<int> current;\n        current.reserve(beamWidth);\n        current.push_back(0);\n\n        vector<Candidate> candBuf;\n        candBuf.reserve(beamWidth * 4 + 10);\n\n        array<Neighbor, 4> moveBuf;\n        bool forceStop = false;\n\n        while (!current.empty() && !forceStop) {\n            if (timeUp()) break;\n            candBuf.clear();\n            for (int idx : current) {\n                if (timeUp()) { forceStop = true; break; }\n                VisitBitset parentVis = pool[idx].visited;\n                int pos = pool[idx].pos;\n                int baseScore = pool[idx].score;\n                int depth = pool[idx].depth;\n\n                int moveCount = 0;\n                for (const auto &nb : adj[pos]) {\n                    if (parentVis.test(tileOf[nb.to])) continue;\n                    moveBuf[moveCount++] = nb;\n                }\n                if (moveCount == 0) continue;\n                if (moveCount > 1) {\n                    shuffle(moveBuf.begin(), moveBuf.begin() + moveCount, rng);\n                }\n                for (int mi = 0; mi < moveCount; ++mi) {\n                    if (timeUp()) { forceStop = true; break; }\n                    const Neighbor &nb = moveBuf[mi];\n                    pool.emplace_back();\n                    Node &child = pool.back();\n                    child.visited = parentVis;\n                    child.visited.set(tileOf[nb.to]);\n                    child.pos = nb.to;\n                    child.score = baseScore + value[nb.to];\n                    child.parent = idx;\n                    child.move = nb.dir;\n                    child.depth = depth + 1;\n                    int childIdx = (int)pool.size() - 1;\n\n                    Features feat = calcFeatures(child.visited, child.pos);\n                    double eval = child.score\n                                + LENGTH_WEIGHT * child.depth\n                                + MOBILITY_WEIGHT * feat.mobility\n                                + NEI1_WEIGHT * feat.nei1\n                                + NEI2_WEIGHT * feat.nei2\n                                + TWO_WEIGHT * feat.two\n                                + RANDOM_WEIGHT * rand01();\n\n                    candBuf.push_back({eval, childIdx});\n\n                    if (child.score > runBestScore ||\n                        (child.score == runBestScore && child.depth > pool[runBestIdx].depth)) {\n                        runBestScore = child.score;\n                        runBestIdx = childIdx;\n                    }\n                }\n                if (forceStop) break;\n            }\n            if (forceStop || candBuf.empty()) break;\n\n            auto cmp = [](const Candidate &a, const Candidate &b) { return a.eval > b.eval; };\n            if ((int)candBuf.size() > beamWidth) {\n                partial_sort(candBuf.begin(), candBuf.begin() + beamWidth, candBuf.end(), cmp);\n                candBuf.resize(beamWidth);\n            } else {\n                sort(candBuf.begin(), candBuf.end(), cmp);\n            }\n\n            current.clear();\n            current.reserve(candBuf.size());\n            for (const auto &cand : candBuf) current.push_back(cand.idx);\n        }\n\n        string runBestPath = buildPath(pool, runBestIdx);\n        if (runBestScore > bestScore ||\n            (runBestScore == bestScore && runBestPath.size() > bestPath.size())) {\n            bestScore = runBestScore;\n            bestPath = runBestPath;\n        }\n\n        if (!timeUp()) {\n            vector<int> greedies;\n            greedies.reserve(MAX_GREEDY_CANDIDATES);\n            greedies.push_back(runBestIdx);\n            for (int idx : current) {\n                if ((int)greedies.size() >= MAX_GREEDY_CANDIDATES) break;\n                bool dup = false;\n                for (int g : greedies) if (g == idx) { dup = true; break; }\n                if (!dup) greedies.push_back(idx);\n            }\n            for (int idx : greedies) {\n                if (timeUp()) break;\n                string path = buildPath(pool, idx);\n                greedyExtend(pool[idx], std::move(path));\n            }\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        int si, sj;\n        if (!(cin >> si >> sj)) return;\n        tileOf.resize(N2);\n        int maxTile = -1;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int t;\n                cin >> t;\n                int idx = i * N + j;\n                tileOf[idx] = t;\n                maxTile = max(maxTile, t);\n            }\n        }\n        [[maybe_unused]] int tileCount = maxTile + 1;\n        value.resize(N2);\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int p;\n                cin >> p;\n                value[i * N + j] = p;\n            }\n        }\n        startIdx = si * N + sj;\n\n        adj.assign(N2, {});\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n        const char dirChar[4] = {'U', 'D', 'L', 'R'};\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int idx = i * N + j;\n                for (int d = 0; d < 4; ++d) {\n                    int ni = i + di[d];\n                    int nj = j + dj[d];\n                    if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                    int nidx = ni * N + nj;\n                    adj[idx].push_back({nidx, dirChar[d]});\n                }\n            }\n        }\n\n        bestScore = value[startIdx];\n        bestPath.clear();\n\n        timeStart = chrono::steady_clock::now();\n        rng.seed(chrono::steady_clock::now().time_since_epoch().count());\n\n        vector<int> beamOptions = {60, 80, 100};\n        int iteration = 0;\n        while (!timeUp()) {\n            int bw = beamOptions[iteration % beamOptions.size()];\n            runBeam(bw);\n            ++iteration;\n        }\n\n        cout << bestPath << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\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    static constexpr int HOR = H * (W - 1);\n    static constexpr int VER = (H - 1) * W;\n    static constexpr int EDGE_CNT = HOR + VER;\n\n    // Estimation parameters\n    const double INIT_MEAN = 5000.0;\n    const double INIT_PERT = 200.0;\n\n    const double BASE_VAR = 1.0e7;\n    const double INFO_OFFSET = 0.5;\n    const double MIN_VAR = 1.0e4;\n    const double MAX_INFO = 600.0;\n    const double INFO_GAIN_BASE = 1.2;\n\n    const double MEAS_NOISE_COEFF = (0.2 * 0.2) / 12.0; // variance of multiplicative noise\n    const double MEAS_VAR_FLOOR = 1e5;\n\n    const double MIN_EDGE_WEIGHT = 900.0;\n    const double MAX_EDGE_WEIGHT = 9200.0;\n    const double MIN_SEARCH_WEIGHT = 1.0;\n\n    const double ALPHA_MIN = 0.05;\n    const double ALPHA_MAX = 0.9;\n\n    // Exploration\n    const double USE_EXPLORE_COEFF = 520.0;\n    const double INFO_EXPLORE_COEFF = 360.0;\n    const double EXPLORE_BASE = 1.0;\n\n    // Smoothing parameters\n    const double SMOOTH_SELF_BIAS = 0.6;\n    const double SMOOTH_NEIGH_BIAS = 1.5;\n    const double SMOOTH_PULL = 0.55;\n    const double SMOOTH_DENOM = 0.8;\n    const double SMOOTH_MAX_PUSH = 0.45;\n\n    vector<double> edgeWeight;\n    vector<int> edgeUse;\n    vector<double> edgeInfo;\n\n    vector<double> dist;\n    vector<int> prevNode;\n    vector<int> prevEdge;\n    vector<char> prevMove;\n\n    vector<double> tmpHor;\n    vector<double> tmpVer;\n\n    mt19937 rng;\n\n    Solver()\n        : edgeWeight(EDGE_CNT),\n          edgeUse(EDGE_CNT, 0),\n          edgeInfo(EDGE_CNT, 0.0),\n          dist(N),\n          prevNode(N),\n          prevEdge(N),\n          prevMove(N),\n          tmpHor(HOR),\n          tmpVer(VER) {\n        rng.seed(chrono::steady_clock::now().time_since_epoch().count());\n        uniform_real_distribution<double> pert(-INIT_PERT, INIT_PERT);\n        for (int i = 0; i < EDGE_CNT; ++i) {\n            edgeWeight[i] = INIT_MEAN + pert(rng);\n        }\n    }\n\n    inline int nodeId(int i, int j) const { return i * W + j; }\n    inline int horId(int i, int j) const { return i * (W - 1) + j; }\n    inline int verId(int i, int j) const { return HOR + i * W + j; }\n\n    inline double clampWeight(double v) const {\n        if (v < MIN_EDGE_WEIGHT) return MIN_EDGE_WEIGHT;\n        if (v > MAX_EDGE_WEIGHT) return MAX_EDGE_WEIGHT;\n        return v;\n    }\n\n    double edgeCostForSearch(int eid) const {\n        double useBias = USE_EXPLORE_COEFF / sqrt(edgeUse[eid] + EXPLORE_BASE);\n        double infoBias = INFO_EXPLORE_COEFF / sqrt(edgeInfo[eid] + 1.0);\n        double w = edgeWeight[eid] - useBias - infoBias;\n        if (w < MIN_SEARCH_WEIGHT) w = MIN_SEARCH_WEIGHT;\n        return w;\n    }\n\n    void buildFallback(int si, int sj, int ti, int tj, string &path, vector<int> &pathEdges) {\n        path.clear();\n        pathEdges.clear();\n        int ci = si, cj = sj;\n        auto pushStep = [&](char mv) {\n            path.push_back(mv);\n            if (mv == 'U') {\n                pathEdges.push_back(verId(ci - 1, cj));\n                --ci;\n            } else if (mv == 'D') {\n                pathEdges.push_back(verId(ci, cj));\n                ++ci;\n            } else if (mv == 'L') {\n                pathEdges.push_back(horId(ci, cj - 1));\n                --cj;\n            } else { // 'R'\n                pathEdges.push_back(horId(ci, cj));\n                ++cj;\n            }\n        };\n        while (ci < ti) pushStep('D');\n        while (ci > ti) pushStep('U');\n        while (cj < tj) pushStep('R');\n        while (cj > tj) pushStep('L');\n    }\n\n    void computePath(int si, int sj, int ti, int tj, string &path, vector<int> &pathEdges) {\n        path.clear();\n        pathEdges.clear();\n        int start = nodeId(si, sj);\n        int target = nodeId(ti, tj);\n        const double INF = 1e100;\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevNode.begin(), prevNode.end(), -1);\n        fill(prevEdge.begin(), prevEdge.end(), -1);\n        fill(prevMove.begin(), prevMove.end(), 0);\n\n        struct PQNode {\n            double dist;\n            int node;\n            bool operator<(const PQNode &o) const { return dist > o.dist; }\n        };\n\n        priority_queue<PQNode> pq;\n        dist[start] = 0.0;\n        pq.push({0.0, start});\n\n        while (!pq.empty()) {\n            auto cur = pq.top();\n            pq.pop();\n            if (cur.dist > dist[cur.node]) continue;\n            if (cur.node == target) break;\n            int i = cur.node / W;\n            int j = cur.node % W;\n\n            if (i > 0) {\n                int nb = cur.node - W;\n                int eid = verId(i - 1, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'U';\n                    pq.push({nd, nb});\n                }\n            }\n            if (i + 1 < H) {\n                int nb = cur.node + W;\n                int eid = verId(i, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'D';\n                    pq.push({nd, nb});\n                }\n            }\n            if (j > 0) {\n                int nb = cur.node - 1;\n                int eid = horId(i, j - 1);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'L';\n                    pq.push({nd, nb});\n                }\n            }\n            if (j + 1 < W) {\n                int nb = cur.node + 1;\n                int eid = horId(i, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'R';\n                    pq.push({nd, nb});\n                }\n            }\n        }\n\n        if (start != target && prevEdge[target] == -1) {\n            buildFallback(si, sj, ti, tj, path, pathEdges);\n            return;\n        }\n        int cur = target;\n        while (cur != start) {\n            int pe = prevEdge[cur];\n            if (pe == -1) {\n                buildFallback(si, sj, ti, tj, path, pathEdges);\n                return;\n            }\n            path.push_back(prevMove[cur]);\n            pathEdges.push_back(pe);\n            cur = prevNode[cur];\n        }\n        reverse(path.begin(), path.end());\n        reverse(pathEdges.begin(), pathEdges.end());\n    }\n\n    void smoothHorizontal() {\n        for (int i = 0; i < H; ++i) {\n            for (int j = 0; j < W - 1; ++j) {\n                int eid = horId(i, j);\n                double sum = (edgeInfo[eid] + SMOOTH_SELF_BIAS) * edgeWeight[eid];\n                double denom = edgeInfo[eid] + SMOOTH_SELF_BIAS;\n\n                if (j > 0) {\n                    int left = horId(i, j - 1);\n                    double w = edgeInfo[left] + SMOOTH_NEIGH_BIAS;\n                    sum += w * edgeWeight[left];\n                    denom += w;\n                }\n                if (j + 1 < W - 1) {\n                    int right = horId(i, j + 1);\n                    double w = edgeInfo[right] + SMOOTH_NEIGH_BIAS;\n                    sum += w * edgeWeight[right];\n                    denom += w;\n                }\n\n                double avg = sum / denom;\n                double push = SMOOTH_PULL / (edgeInfo[eid] + SMOOTH_DENOM);\n                if (push > SMOOTH_MAX_PUSH) push = SMOOTH_MAX_PUSH;\n                double newVal = edgeWeight[eid] + push * (avg - edgeWeight[eid]);\n                tmpHor[eid] = clampWeight(newVal);\n            }\n        }\n        for (int i = 0; i < HOR; ++i) edgeWeight[i] = tmpHor[i];\n    }\n\n    void smoothVertical() {\n        for (int j = 0; j < W; ++j) {\n            for (int i = 0; i < H - 1; ++i) {\n                int local = i * W + j;\n                int eid = verId(i, j);\n                double sum = (edgeInfo[eid] + SMOOTH_SELF_BIAS) * edgeWeight[eid];\n                double denom = edgeInfo[eid] + SMOOTH_SELF_BIAS;\n\n                if (i > 0) {\n                    int up = verId(i - 1, j);\n                    double w = edgeInfo[up] + SMOOTH_NEIGH_BIAS;\n                    sum += w * edgeWeight[up];\n                    denom += w;\n                }\n                if (i + 1 < H - 1) {\n                    int down = verId(i + 1, j);\n                    double w = edgeInfo[down] + SMOOTH_NEIGH_BIAS;\n                    sum += w * edgeWeight[down];\n                    denom += w;\n                }\n\n                double avg = sum / denom;\n                double push = SMOOTH_PULL / (edgeInfo[eid] + SMOOTH_DENOM);\n                if (push > SMOOTH_MAX_PUSH) push = SMOOTH_MAX_PUSH;\n                double newVal = edgeWeight[eid] + push * (avg - edgeWeight[eid]);\n                tmpVer[local] = clampWeight(newVal);\n            }\n        }\n        for (int i = 0; i < VER; ++i) edgeWeight[HOR + i] = tmpVer[i];\n    }\n\n    void smoothEstimates() {\n        smoothHorizontal();\n        smoothVertical();\n    }\n\n    void update(const vector<int> &pathEdges, double measurement) {\n        if (pathEdges.empty()) return;\n        size_t m = pathEdges.size();\n        vector<double> vars;\n        vars.reserve(m);\n\n        double predicted = 0.0;\n        double sumVar = 0.0;\n        for (int eid : pathEdges) {\n            predicted += edgeWeight[eid];\n            double var = BASE_VAR / (edgeInfo[eid] + INFO_OFFSET);\n            if (var < MIN_VAR) var = MIN_VAR;\n            vars.push_back(var);\n            sumVar += var;\n        }\n        if (sumVar <= 0.0) sumVar = MIN_VAR;\n\n        double residual = measurement - predicted;\n        double safePred = max(predicted, 1.0);\n        double measurementVar = MEAS_NOISE_COEFF * safePred * safePred + MEAS_VAR_FLOOR;\n        double alpha = sumVar / (sumVar + measurementVar);\n        if (alpha < ALPHA_MIN) alpha = ALPHA_MIN;\n        if (alpha > ALPHA_MAX) alpha = ALPHA_MAX;\n\n        double scale = alpha * residual / sumVar;\n        for (size_t idx = 0; idx < m; ++idx) {\n            int eid = pathEdges[idx];\n            double delta = vars[idx] * scale;\n            edgeWeight[eid] = clampWeight(edgeWeight[eid] + delta);\n        }\n\n        double invSumVar = 1.0 / sumVar;\n        for (size_t idx = 0; idx < m; ++idx) {\n            int eid = pathEdges[idx];\n            double infoGain = INFO_GAIN_BASE * vars[idx] * invSumVar;\n            edgeInfo[eid] = min(edgeInfo[eid] + infoGain, MAX_INFO);\n            edgeUse[eid] = min(edgeUse[eid] + 1, 1000000000);\n        }\n\n        smoothEstimates();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    string path;\n    path.reserve(128);\n    vector<int> pathEdges;\n    pathEdges.reserve(128);\n\n    for (int q = 0; q < 1000; ++q) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        solver.computePath(si, sj, ti, tj, path, pathEdges);\n        cout << path << '\\n' << flush;\n\n        int measurement;\n        if (!(cin >> measurement)) return 0;\n        if (measurement < 0) return 0;\n\n        solver.update(pathEdges, static_cast<double>(measurement));\n    }\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 20;\nconstexpr int MAXLEN = 12;\nconstexpr int ORIENT = 2;\nconstexpr int PL_PER_ORIENT = N * N;\nconstexpr int PL = ORIENT * PL_PER_ORIENT;\nconstexpr uint8_t EMPTY = 0xFF;\nconst double TIME_LIMIT = 2.9;\nconst double LOCAL_SEARCH_MARGIN = 0.6;\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 Placement {\n    array<uint8_t, MAXLEN> rows;\n    array<uint8_t, MAXLEN> cols;\n    array<int, MAXLEN> cellIndex;\n};\n\nstruct Read {\n    string s;\n    vector<uint8_t> codes;\n    int len;\n};\n\nusing Grid = array<array<uint8_t, N>, N>;\n\nvector<Placement> build_placements() {\n    vector<Placement> placements(PL);\n    int idx = 0;\n    for (int ori = 0; ori < ORIENT; ++ori) {\n        for (int fixed = 0; fixed < N; ++fixed) {\n            for (int start = 0; start < N; ++start) {\n                Placement &p = placements[idx++];\n                for (int t = 0; t < MAXLEN; ++t) {\n                    int r, c;\n                    if (ori == 0) {\n                        r = fixed;\n                        c = (start + t) % N;\n                    } else {\n                        r = (start + t) % N;\n                        c = fixed;\n                    }\n                    p.rows[t] = static_cast<uint8_t>(r);\n                    p.cols[t] = static_cast<uint8_t>(c);\n                    p.cellIndex[t] = ((r * N + c) << 3);\n                }\n            }\n        }\n    }\n    return placements;\n}\n\nGrid seed_grid(const vector<Read> &reads, const vector<Placement> &placements, mt19937_64 &rng) {\n    Grid grid;\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            grid[i][j] = EMPTY;\n\n    vector<int> order(reads.size());\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (reads[a].len != reads[b].len) return reads[a].len > reads[b].len;\n        return a < b;\n    });\n\n    for (int idx : order) {\n        const Read &rd = reads[idx];\n        int len = rd.len;\n        int chosen = -1;\n        int cnt = 0;\n        for (int pid = 0; pid < PL; ++pid) {\n            bool ok = true;\n            const auto &prow = placements[pid].rows;\n            const auto &pcol = placements[pid].cols;\n            for (int t = 0; t < len; ++t) {\n                uint8_t cur = grid[prow[t]][pcol[t]];\n                if (cur != EMPTY && cur != rd.codes[t]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) {\n                ++cnt;\n                if ((uint64_t)rng() % cnt == 0) chosen = pid;\n            }\n        }\n        if (chosen != -1) {\n            const auto &prow = placements[chosen].rows;\n            const auto &pcol = placements[chosen].cols;\n            for (int t = 0; t < len; ++t) {\n                grid[prow[t]][pcol[t]] = rd.codes[t];\n            }\n        }\n    }\n\n    uniform_int_distribution<int> dist(0, 7);\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            if (grid[i][j] == EMPTY)\n                grid[i][j] = static_cast<uint8_t>(dist(rng));\n    return grid;\n}\n\nint compute_delta(int iter, int total) {\n    if (total <= 4) return 1;\n    if (iter * 3 >= total * 2) return 1;\n    if (iter * 3 >= total) return 2;\n    return 3;\n}\n\nvoid run_em(Grid &grid, int iterations, const vector<Read> &reads,\n            const vector<Placement> &placements, vector<double> &counts,\n            array<uint8_t, PL> &matchBuf, const vector<double> &weights,\n            double inertia, Timer &timer) {\n    for (int iter = 0; iter < iterations; ++iter) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n        fill(counts.begin(), counts.end(), 0.0);\n        int delta = compute_delta(iter, iterations);\n\n        for (const Read &rd : reads) {\n            const uint8_t *codes = rd.codes.data();\n            int len = rd.len;\n            int best = 0;\n            for (int pid = 0; pid < PL; ++pid) {\n                const auto &prow = placements[pid].rows;\n                const auto &pcol = placements[pid].cols;\n                int match = 0;\n                for (int t = 0; t < len; ++t)\n                    if (grid[prow[t]][pcol[t]] == codes[t]) ++match;\n                matchBuf[pid] = static_cast<uint8_t>(match);\n                if (match > best) best = match;\n            }\n            if (best == 0) continue;\n            int threshold = max(0, best - delta);\n            double totalWeight = 0.0;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = matchBuf[pid];\n                if (match < threshold) continue;\n                totalWeight += weights[match];\n            }\n            if (totalWeight <= 0) continue;\n            double inv = 1.0 / totalWeight;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = matchBuf[pid];\n                if (match < threshold) continue;\n                double w = weights[match];\n                if (w <= 0) continue;\n                double scaled = w * inv;\n                const auto &cellIdx = placements[pid].cellIndex;\n                for (int t = 0; t < len; ++t)\n                    counts[cellIdx[t] + codes[t]] += scaled;\n            }\n        }\n\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                counts[((r * N + c) << 3) + grid[r][c]] += inertia;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int base = ((r * N + c) << 3);\n                double bestVal = -1e100;\n                int bestLetter = grid[r][c];\n                for (int letter = 0; letter < 8; ++letter) {\n                    double v = counts[base + letter];\n                    if (v > bestVal) {\n                        bestVal = v;\n                        bestLetter = letter;\n                    }\n                }\n                grid[r][c] = static_cast<uint8_t>(bestLetter);\n            }\n        }\n    }\n}\n\nint compute_best_matches(const Grid &grid, const vector<Read> &reads,\n                         const vector<Placement> &placements,\n                         vector<int> &bestPid, vector<uint8_t> &bestMatch,\n                         vector<uint8_t> *sat = nullptr) {\n    int M = reads.size();\n    if ((int)bestPid.size() != M) bestPid.assign(M, 0);\n    if ((int)bestMatch.size() != M) bestMatch.assign(M, 0);\n    if (sat && (int)sat->size() != M) sat->assign(M, 0);\n\n    int satisfied = 0;\n    for (int i = 0; i < M; ++i) {\n        const Read &rd = reads[i];\n        int len = rd.len;\n        int best = -1;\n        int bestPlacement = 0;\n        for (int pid = 0; pid < PL; ++pid) {\n            const Placement &pl = placements[pid];\n            int match = 0;\n            for (int t = 0; t < len; ++t) {\n                if (grid[pl.rows[t]][pl.cols[t]] == rd.codes[t]) ++match;\n            }\n            if (match > best) {\n                best = match;\n                bestPlacement = pid;\n                if (match == len) break;\n            }\n        }\n        bestPid[i] = bestPlacement;\n        bestMatch[i] = static_cast<uint8_t>(best);\n        bool ok = (best == len);\n        if (sat) (*sat)[i] = static_cast<uint8_t>(ok);\n        if (ok) ++satisfied;\n    }\n    return satisfied;\n}\n\nvoid repair_grid(Grid &grid, const vector<Read> &reads, const vector<Placement> &placements,\n                 Timer &timer, const vector<int> &bestPid, const vector<uint8_t> &bestMatch,\n                 int threshold) {\n    int M = reads.size();\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        int ma = reads[a].len - bestMatch[a];\n        int mb = reads[b].len - bestMatch[b];\n        if (ma != mb) return ma < mb;\n        return reads[a].len > reads[b].len;\n    });\n    for (int idx : order) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n        int mismatch = reads[idx].len - bestMatch[idx];\n        if (mismatch <= 0 || mismatch > threshold) continue;\n        int pid = bestPid[idx];\n        if (pid < 0) continue;\n        const Placement &pl = placements[pid];\n        for (int t = 0; t < reads[idx].len; ++t)\n            grid[pl.rows[t]][pl.cols[t]] = reads[idx].codes[t];\n    }\n}\n\nvoid local_search(Grid &grid, const vector<Read> &reads,\n                  const vector<Placement> &placements, Timer &timer,\n                  Grid &globalBest, int &globalBestScore, mt19937_64 &rng) {\n    int M = reads.size();\n    vector<int> curBestPid(M), tmpBestPid(M);\n    vector<uint8_t> curBestMatch(M), tmpBestMatch(M);\n    vector<uint8_t> curSat(M), tmpSat(M);\n\n    int curScore = compute_best_matches(grid, reads, placements, curBestPid, curBestMatch, &curSat);\n    if (curScore > globalBestScore) {\n        globalBestScore = curScore;\n        globalBest = grid;\n    }\n\n    array<vector<int>, MAXLEN + 1> buckets;\n    uniform_real_distribution<double> uni(0.0, 1.0);\n\n    const int maxIter = 140;\n    for (int iter = 0; iter < maxIter; ++iter) {\n        if (timer.elapsed() > TIME_LIMIT - 0.02) break;\n\n        for (auto &vec : buckets) vec.clear();\n        for (int i = 0; i < M; ++i) {\n            if (curSat[i]) continue;\n            int mismatch = reads[i].len - curBestMatch[i];\n            if (mismatch < 1) mismatch = 1;\n            if (mismatch > MAXLEN) mismatch = MAXLEN;\n            buckets[mismatch].push_back(i);\n        }\n        int chosen = -1;\n        for (int mis = 1; mis <= MAXLEN; ++mis) {\n            if (!buckets[mis].empty()) {\n                chosen = buckets[mis][rng() % buckets[mis].size()];\n                break;\n            }\n        }\n        if (chosen == -1) break;\n\n        int pid = curBestPid[chosen];\n        if (pid < 0) continue;\n        const Placement &pl = placements[pid];\n        int len = reads[chosen].len;\n\n        array<uint8_t, MAXLEN> backup;\n        for (int t = 0; t < len; ++t) {\n            int r = pl.rows[t], c = pl.cols[t];\n            backup[t] = grid[r][c];\n            if (grid[r][c] != reads[chosen].codes[t])\n                grid[r][c] = reads[chosen].codes[t];\n        }\n\n        int newScore = compute_best_matches(grid, reads, placements, tmpBestPid, tmpBestMatch, &tmpSat);\n        int diff = newScore - curScore;\n        double progress = max(0.0, min(1.0, static_cast<double>(iter) / max(1, maxIter - 1)));\n        double temp = 2.5 + (0.35 - 2.5) * progress;\n        bool accept = (diff >= 0);\n        if (!accept) {\n            double prob = exp(diff / temp);\n            if (prob > uni(rng)) accept = true;\n        }\n\n        if (accept) {\n            curScore = newScore;\n            swap(curBestPid, tmpBestPid);\n            swap(curBestMatch, tmpBestMatch);\n            swap(curSat, tmpSat);\n            if (newScore > globalBestScore) {\n                globalBestScore = newScore;\n                globalBest = grid;\n            }\n        } else {\n            for (int t = 0; t < len; ++t)\n                grid[pl.rows[t]][pl.cols[t]] = backup[t];\n        }\n    }\n}\n\nvoid run_restart(Grid &bestGrid, int &bestScore, const vector<Read> &reads,\n                 const vector<Placement> &placements, vector<double> &counts,\n                 array<uint8_t, PL> &matchBuf, const vector<double> &weights,\n                 Timer &timer, mt19937_64 &rng,\n                 vector<int> &workBestPid, vector<uint8_t> &workBestMatch) {\n    Grid grid = seed_grid(reads, placements, rng);\n    run_em(grid, 30, reads, placements, counts, matchBuf, weights, 0.35, timer);\n    int score = compute_best_matches(grid, reads, placements, workBestPid, workBestMatch);\n    if (score > bestScore) {\n        bestScore = score;\n        bestGrid = grid;\n    }\n    if (TIME_LIMIT - timer.elapsed() > 0.35) {\n        repair_grid(grid, reads, placements, timer, workBestPid, workBestMatch, 1);\n        run_em(grid, 8, reads, placements, counts, matchBuf, weights, 0.25, timer);\n        score = compute_best_matches(grid, reads, placements, workBestPid, workBestMatch);\n        if (score > bestScore) {\n            bestScore = score;\n            bestGrid = grid;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N_input, M;\n    if (!(cin >> N_input >> M)) return 0;\n    vector<Read> reads(M);\n    for (int i = 0; i < M; ++i) {\n        string s;\n        cin >> s;\n        reads[i].s = s;\n        reads[i].len = s.size();\n        reads[i].codes.resize(s.size());\n        for (int j = 0; j < (int)s.size(); ++j)\n            reads[i].codes[j] = static_cast<uint8_t>(s[j] - 'A');\n    }\n\n    auto placements = build_placements();\n    vector<double> counts(N * N * 8, 0.0);\n    array<uint8_t, PL> matchBuf{};\n    vector<double> weights(MAXLEN + 1, 0.0);\n    weights[1] = 0.05;\n    double w = 1.0;\n    for (int m = 2; m <= MAXLEN; ++m) {\n        weights[m] = w;\n        w *= 1.75;\n    }\n\n    Timer timer;\n    mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    Grid bestGrid;\n    int bestScore = -1;\n    vector<int> workBestPid(M);\n    vector<uint8_t> workBestMatch(M);\n\n    int restarts = 0;\n    while (timer.elapsed() < TIME_LIMIT - LOCAL_SEARCH_MARGIN) {\n        run_restart(bestGrid, bestScore, reads, placements, counts, matchBuf, weights,\n                    timer, rng, workBestPid, workBestMatch);\n        ++restarts;\n        if (timer.elapsed() > TIME_LIMIT - LOCAL_SEARCH_MARGIN) break;\n    }\n    if (restarts == 0) {\n        run_restart(bestGrid, bestScore, reads, placements, counts, matchBuf, weights,\n                    timer, rng, workBestPid, workBestMatch);\n    }\n\n    Grid candidate = bestGrid;\n    local_search(candidate, reads, placements, timer, bestGrid, bestScore, rng);\n\n    for (int i = 0; i < N; ++i) {\n        string line(N, 'A');\n        for (int j = 0; j < N; ++j)\n            line[j] = static_cast<char>('A' + bestGrid[i][j]);\n        cout << line << '\\n';\n    }\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int di[4] = {-1, 1, 0, 0};\nconst int dj[4] = {0, 0, -1, 1};\n\nstruct Dinic {\n    struct Edge {\n        int to;\n        long long cap;\n        int rev;\n    };\n    int N;\n    vector<vector<Edge>> G;\n    Dinic(int n = 0) { init(n); }\n    void init(int n) {\n        N = n;\n        G.assign(n, {});\n    }\n    void add_edge(int fr, int to, long long cap) {\n        Edge f{to, cap, (int)G[to].size()};\n        Edge b{fr, 0, (int)G[fr].size()};\n        G[fr].push_back(f);\n        G[to].push_back(b);\n    }\n    long long max_flow(int s, int t) {\n        const long long INF = (1LL << 60);\n        long long flow = 0;\n        vector<int> level(N), it(N);\n        while (true) {\n            fill(level.begin(), level.end(), -1);\n            queue<int> q;\n            level[s] = 0;\n            q.push(s);\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                for (const auto &e : G[v]) {\n                    if (e.cap > 0 && level[e.to] < 0) {\n                        level[e.to] = level[v] + 1;\n                        q.push(e.to);\n                    }\n                }\n            }\n            if (level[t] < 0) break;\n            fill(it.begin(), it.end(), 0);\n            function<long long(int,long long)> dfs = [&](int v, long long f) -> long long {\n                if (v == t) return f;\n                for (int &i = it[v]; i < (int)G[v].size(); ++i) {\n                    Edge &e = G[v][i];\n                    if (e.cap > 0 && level[v] < level[e.to]) {\n                        long long d = dfs(e.to, min(f, e.cap));\n                        if (d > 0) {\n                            e.cap -= d;\n                            G[e.to][e.rev].cap += d;\n                            return d;\n                        }\n                    }\n                }\n                return 0;\n            };\n            long long f;\n            while ((f = dfs(s, INF)) > 0) flow += f;\n        }\n        return flow;\n    }\n};\n\nstruct Plan {\n    vector<int> targets;\n    long long approx;\n};\n\nchar dir_char(int from, int to, int N) {\n    int fi = from / N, fj = from % N;\n    int ti = to / N, tj = to % N;\n    if (ti == fi - 1 && tj == fj) return 'U';\n    if (ti == fi + 1 && tj == fj) return 'D';\n    if (tj == fj - 1 && ti == fi) return 'L';\n    if (tj == fj + 1 && ti == fi) return 'R';\n    return 'U';\n}\n\nbool buildSteinerTree(const vector<int>& targets, vector<vector<int>>& treeAdj,\n                      int start_id, const vector<int>& cost, int N) {\n    int total = (int)cost.size();\n    vector<char> need(total, 0);\n    int uniqueTargets = 0;\n    for (int cell : targets) {\n        if (!need[cell]) {\n            need[cell] = 1;\n            ++uniqueTargets;\n        }\n    }\n    int remaining = uniqueTargets;\n    vector<char> in_tree(total, 0);\n    vector<int> treeNodes;\n    treeNodes.reserve(total);\n    in_tree[start_id] = 1;\n    treeNodes.push_back(start_id);\n    if (need[start_id]) {\n        need[start_id] = 0;\n        --remaining;\n    }\n    if (remaining <= 0) return true;\n    const long long INFLL = (1LL << 60);\n    vector<long long> dist(total, INFLL);\n    vector<int> parent(total, -1);\n    while (remaining > 0) {\n        fill(dist.begin(), dist.end(), INFLL);\n        fill(parent.begin(), parent.end(), -1);\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        for (int node : treeNodes) {\n            dist[node] = 0;\n            parent[node] = -1;\n            pq.emplace(0, node);\n        }\n        int best = -1;\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (need[u]) {\n                best = u;\n                break;\n            }\n            int ui = u / N, uj = u % N;\n            for (int dir = 0; dir < 4; ++dir) {\n                int vi = ui + di[dir];\n                int vj = uj + dj[dir];\n                if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n                int v = vi * N + vj;\n                if (cost[v] == -1) continue;\n                long long nd = d + cost[v];\n                if (nd < dist[v]) {\n                    dist[v] = nd;\n                    parent[v] = u;\n                    pq.emplace(nd, v);\n                }\n            }\n        }\n        if (best == -1) return false;\n        need[best] = 0;\n        --remaining;\n        if (in_tree[best]) continue;\n        vector<int> path;\n        int cur = best;\n        while (!in_tree[cur]) {\n            path.push_back(cur);\n            cur = parent[cur];\n            if (cur == -1) return false;\n        }\n        int prev = cur;\n        for (int i = (int)path.size() - 1; i >= 0; --i) {\n            int node = path[i];\n            treeAdj[node].push_back(prev);\n            treeAdj[prev].push_back(node);\n            if (!in_tree[node]) {\n                in_tree[node] = 1;\n                treeNodes.push_back(node);\n            }\n            if (need[node]) {\n                need[node] = 0;\n                --remaining;\n            }\n            prev = node;\n        }\n    }\n    return true;\n}\n\nvoid buildTreeSP(const vector<int>& targets, vector<vector<int>>& treeAdj,\n                 int start_id, const vector<int>& parent, int total) {\n    vector<char> required(total, 0);\n    required[start_id] = 1;\n    for (int cell : targets) {\n        int cur = cell;\n        while (!required[cur]) {\n            required[cur] = 1;\n            if (cur == start_id) break;\n            int p = parent[cur];\n            if (p == -1) break;\n            cur = p;\n        }\n    }\n    for (int v = 0; v < total; ++v) {\n        if (!required[v]) continue;\n        int p = parent[v];\n        if (p == -1) continue;\n        if (!required[p]) continue;\n        treeAdj[v].push_back(p);\n        treeAdj[p].push_back(v);\n    }\n}\n\nstring buildRoute(const vector<vector<int>>& treeAdj, int start_id, int N) {\n    string route;\n    route.reserve(treeAdj.size() * 2);\n    struct Frame { int node, parent, idx; };\n    vector<Frame> st;\n    st.push_back({start_id, -1, 0});\n    while (!st.empty()) {\n        Frame &fr = st.back();\n        if (fr.idx == (int)treeAdj[fr.node].size()) {\n            st.pop_back();\n            if (fr.parent != -1) route.push_back(dir_char(fr.node, fr.parent, N));\n            continue;\n        }\n        int nxt = treeAdj[fr.node][fr.idx++];\n        if (nxt == fr.parent) continue;\n        route.push_back(dir_char(fr.node, nxt, N));\n        st.push_back({nxt, fr.node, 0});\n    }\n    return route;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, si, sj;\n    if (!(cin >> N >> si >> sj)) return 0;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n    int total = N * N;\n    auto idx = [&](int i, int j) { return i * N + j; };\n    vector<int> cost(total, -1);\n    vector<int> road_cells;\n    road_cells.reserve(total);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (grid[i][j] != '#') {\n                int id = idx(i, j);\n                cost[id] = grid[i][j] - '0';\n                road_cells.push_back(id);\n            }\n        }\n    }\n    int start_id = idx(si, sj);\n\n    // Row segments\n    vector<int> row_id(total, -1);\n    vector<vector<int>> row_cells;\n    for (int i = 0; i < N; ++i) {\n        int j = 0;\n        while (j < N) {\n            if (grid[i][j] == '#') { ++j; continue; }\n            int seg = (int)row_cells.size();\n            vector<int> cells;\n            while (j < N && grid[i][j] != '#') {\n                int id = idx(i, j);\n                row_id[id] = seg;\n                cells.push_back(id);\n                ++j;\n            }\n            row_cells.push_back(cells);\n        }\n    }\n    int R = (int)row_cells.size();\n\n    // Column segments\n    vector<int> col_id(total, -1);\n    vector<vector<int>> col_cells;\n    for (int j = 0; j < N; ++j) {\n        int i = 0;\n        while (i < N) {\n            if (grid[i][j] == '#') { ++i; continue; }\n            int seg = (int)col_cells.size();\n            vector<int> cells;\n            while (i < N && grid[i][j] != '#') {\n                int id = idx(i, j);\n                col_id[id] = seg;\n                cells.push_back(id);\n                ++i;\n            }\n            col_cells.push_back(cells);\n        }\n    }\n    int C = (int)col_cells.size();\n\n    vector<vector<int>> row_adj(R);\n    for (int cell : road_cells) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && c >= 0) row_adj[r].push_back(c);\n    }\n    for (auto &vec : row_adj) {\n        sort(vec.begin(), vec.end());\n        vec.erase(unique(vec.begin(), vec.end()), vec.end());\n    }\n\n    // Dijkstra from start\n    const long long INFLL = (1LL << 60);\n    vector<long long> distStart(total, INFLL);\n    vector<int> parentStart(total, -1);\n    using P = pair<long long,int>;\n    priority_queue<P, vector<P>, greater<P>> pq;\n    distStart[start_id] = 0;\n    pq.emplace(0, start_id);\n    while (!pq.empty()) {\n        auto [d, u] = pq.top(); pq.pop();\n        if (d != distStart[u]) continue;\n        int ui = u / N, uj = u % N;\n        for (int dir = 0; dir < 4; ++dir) {\n            int vi = ui + di[dir];\n            int vj = uj + dj[dir];\n            if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n            int v = idx(vi, vj);\n            if (cost[v] == -1) continue;\n            long long nd = d + cost[v];\n            if (nd < distStart[v]) {\n                distStart[v] = nd;\n                parentStart[v] = u;\n                pq.emplace(nd, v);\n            }\n        }\n    }\n\n    vector<int> best_row_cell(R, -1);\n    vector<long long> best_row_dist(R, INFLL);\n    for (int r = 0; r < R; ++r) {\n        for (int cell : row_cells[r]) {\n            long long d = distStart[cell];\n            if (d < best_row_dist[r]) {\n                best_row_dist[r] = d;\n                best_row_cell[r] = cell;\n            }\n        }\n        if (best_row_cell[r] == -1 && !row_cells[r].empty()) {\n            best_row_cell[r] = row_cells[r][0];\n            best_row_dist[r] = distStart[row_cells[r][0]];\n        }\n    }\n    vector<int> best_col_cell(C, -1);\n    vector<long long> best_col_dist(C, INFLL);\n    for (int c = 0; c < C; ++c) {\n        for (int cell : col_cells[c]) {\n            long long d = distStart[cell];\n            if (d < best_col_dist[c]) {\n                best_col_dist[c] = d;\n                best_col_cell[c] = cell;\n            }\n        }\n        if (best_col_cell[c] == -1 && !col_cells[c].empty()) {\n            best_col_cell[c] = col_cells[c][0];\n            best_col_dist[c] = distStart[col_cells[c][0]];\n        }\n    }\n\n    // Unweighted vertex cover via maximum matching\n    vector<int> matchRow(R, -1), matchCol(C, -1);\n    vector<char> seen(C, 0);\n    function<bool(int)> dfs_match = [&](int u) -> bool {\n        for (int v : row_adj[u]) {\n            if (seen[v]) continue;\n            seen[v] = 1;\n            if (matchCol[v] == -1 || dfs_match(matchCol[v])) {\n                matchRow[u] = v;\n                matchCol[v] = u;\n                return true;\n            }\n        }\n        return false;\n    };\n    for (int u = 0; u < R; ++u) {\n        fill(seen.begin(), seen.end(), 0);\n        dfs_match(u);\n    }\n    vector<char> visRow(R, 0), visCol(C, 0);\n    queue<int> q;\n    for (int u = 0; u < R; ++u) if (matchRow[u] == -1) {\n        visRow[u] = 1;\n        q.push(u);\n    }\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        for (int v : row_adj[u]) {\n            if (matchRow[u] == v) continue;\n            if (visCol[v]) continue;\n            visCol[v] = 1;\n            int mu = matchCol[v];\n            if (mu != -1 && !visRow[mu]) {\n                visRow[mu] = 1;\n                q.push(mu);\n            }\n        }\n    }\n    vector<char> row_cover_un(R, 0), col_cover_un(C, 0);\n    for (int r = 0; r < R; ++r) row_cover_un[r] = !visRow[r];\n    for (int c = 0; c < C; ++c) col_cover_un[c] = visCol[c];\n\n    // Weighted vertex cover via flow\n    const long long base_weight = 25;\n    vector<long long> w_row(R, base_weight), w_col(C, base_weight);\n    for (int r = 0; r < R; ++r) {\n        long long w = best_row_dist[r];\n        if (w >= INFLL / 4) w = (long long)1e9;\n        w_row[r] = w + base_weight;\n    }\n    for (int c = 0; c < C; ++c) {\n        long long w = best_col_dist[c];\n        if (w >= INFLL / 4) w = (long long)1e9;\n        w_col[c] = w + base_weight;\n    }\n    Dinic din(R + C + 2);\n    int SRC = 0;\n    int SNK = R + C + 1;\n    const long long INF_CAP = (1LL << 55);\n    for (int r = 0; r < R; ++r) din.add_edge(SRC, 1 + r, w_row[r]);\n    for (int c = 0; c < C; ++c) din.add_edge(1 + R + c, SNK, w_col[c]);\n    for (int cell : road_cells) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && c >= 0)\n            din.add_edge(1 + r, 1 + R + c, INF_CAP);\n    }\n    din.max_flow(SRC, SNK);\n    vector<int> visited(din.N, 0);\n    queue<int> q2;\n    q2.push(SRC);\n    visited[SRC] = 1;\n    while (!q2.empty()) {\n        int v = q2.front(); q2.pop();\n        for (auto &e : din.G[v]) if (e.cap > 0 && !visited[e.to]) {\n            visited[e.to] = 1;\n            q2.push(e.to);\n        }\n    }\n    vector<char> row_cover_w(R, 0), col_cover_w(C, 0);\n    for (int r = 0; r < R; ++r) row_cover_w[r] = !visited[1 + r];\n    for (int c = 0; c < C; ++c) col_cover_w[c] = visited[1 + R + c];\n\n    vector<int> sorted_cells = road_cells;\n    sort(sorted_cells.begin(), sorted_cells.end(), [&](int a, int b) {\n        if (distStart[a] != distStart[b]) return distStart[a] < distStart[b];\n        return a < b;\n    });\n\n    const long long TARGET_PENALTY = 30;\n    auto build_plan = [&](const vector<char>& row_cover, const vector<char>& col_cover) -> Plan {\n        vector<char> row_need = row_cover;\n        vector<char> col_need = col_cover;\n        vector<int> targets;\n        vector<char> is_target(total, 0);\n        auto add_target = [&](int cell) {\n            if (cell < 0) return;\n            if (!is_target[cell]) {\n                is_target[cell] = 1;\n                targets.push_back(cell);\n            }\n        };\n        for (int cell : sorted_cells) {\n            int r = row_id[cell];\n            int c = col_id[cell];\n            if (r >= 0 && c >= 0 && row_need[r] && col_need[c]) {\n                add_target(cell);\n                row_need[r] = 0;\n                col_need[c] = 0;\n            }\n        }\n        for (int r = 0; r < R; ++r) if (row_need[r]) {\n            int cell = best_row_cell[r];\n            if (cell == -1 && !row_cells[r].empty()) cell = row_cells[r][0];\n            add_target(cell);\n            row_need[r] = 0;\n        }\n        for (int c = 0; c < C; ++c) if (col_need[c]) {\n            int cell = best_col_cell[c];\n            if (cell == -1 && !col_cells[c].empty()) cell = col_cells[c][0];\n            add_target(cell);\n            col_need[c] = 0;\n        }\n        if (targets.empty()) add_target(start_id);\n        long long sumDist = 0;\n        for (int cell : targets) {\n            long long d = distStart[cell];\n            if (d >= INFLL / 4) d = INFLL / 4;\n            sumDist += d;\n        }\n        long long approx = sumDist + TARGET_PENALTY * (long long)targets.size();\n        return {targets, approx};\n    };\n\n    Plan plan_w = build_plan(row_cover_w, col_cover_w);\n    Plan plan_un = build_plan(row_cover_un, col_cover_un);\n    Plan chosen = plan_w;\n    if (plan_un.approx < plan_w.approx) chosen = plan_un;\n\n    vector<vector<int>> treeAdj(total);\n    bool ok = buildSteinerTree(chosen.targets, treeAdj, start_id, cost, N);\n    if (!ok) {\n        treeAdj.assign(total, {});\n        buildTreeSP(chosen.targets, treeAdj, start_id, parentStart, total);\n    }\n    string route = buildRoute(treeAdj, start_id, N);\n    cout << route << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Node {\n    long long priority;\n    int task;\n    bool operator<(const Node& other) const {\n        if (priority != other.priority) return priority < other.priority; // max-heap\n        return task > other.task;\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>> req(N, vector<int>(K));\n    for (int i = 0; i < N; ++i)\n        for (int k = 0; k < K; ++k)\n            cin >> req[i][k];\n\n    vector<vector<int>> adj(N);\n    vector<int> indeg(N, 0);\n    for (int i = 0; i < R; ++i) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        adj[u].push_back(v);\n        indeg[v]++;\n    }\n\n    vector<int> sum_d(N, 0), max_d(N, 0);\n    for (int i = 0; i < N; ++i) {\n        int s = 0, m = 0;\n        for (int k = 0; k < K; ++k) {\n            s += req[i][k];\n            m = max(m, req[i][k]);\n        }\n        sum_d[i] = s;\n        max_d[i] = m;\n    }\n\n    // Longest distance to sink (since u<v we can walk backwards).\n    vector<int> level(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        int best = 0;\n        for (int v : adj[i]) best = max(best, level[v] + 1);\n        level[i] = best;\n    }\n\n    auto calc_priority = [&](int i) -> long long {\n        long long val = 0;\n        val += 1'000'000LL * level[i];\n        val += 1'000LL * sum_d[i];\n        val += 10LL * (int)adj[i].size();\n        val += (1000 - i); // small tie breaker\n        return val;\n    };\n\n    priority_queue<Node> pq;\n    vector<int> task_state(N, 0); // 0 not ready, 1 ready, 2 in progress, 3 done\n    for (int i = 0; i < N; ++i) {\n        if (indeg[i] == 0) {\n            task_state[i] = 1;\n            pq.push({calc_priority(i), i});\n        }\n    }\n\n    vector<int> worker_task(M, -1);\n    vector<int> worker_start(M, -1);\n    vector<double> worker_ability(M, 1.0);\n    const double ability_alpha = 0.3;\n    int completed_tasks = 0;\n    int day = 1;\n\n    while (true) {\n        // prepare worker order\n        vector<int> idle_workers;\n        idle_workers.reserve(M);\n        for (int j = 0; j < M; ++j)\n            if (worker_task[j] == -1)\n                idle_workers.push_back(j);\n\n        sort(idle_workers.begin(), idle_workers.end(),\n             [&](int a, int b) {\n                 if (fabs(worker_ability[a] - worker_ability[b]) > 1e-9)\n                     return worker_ability[a] > worker_ability[b];\n                 return a < b;\n             });\n\n        // fetch tasks\n        vector<Node> fetched;\n        if (!idle_workers.empty()) {\n            fetched.reserve(idle_workers.size());\n            while (fetched.size() < idle_workers.size() && !pq.empty()) {\n                Node cur = pq.top(); pq.pop();\n                if (task_state[cur.task] != 1) continue; // stale entry\n                fetched.push_back(cur);\n            }\n        }\n\n        vector<int> task_order(fetched.size());\n        iota(task_order.begin(), task_order.end(), 0);\n        sort(task_order.begin(), task_order.end(),\n             [&](int lhs, int rhs) {\n                 int t1 = fetched[lhs].task;\n                 int t2 = fetched[rhs].task;\n                 if (sum_d[t1] != sum_d[t2]) return sum_d[t1] > sum_d[t2];\n                 if (level[t1] != level[t2]) return level[t1] > level[t2];\n                 return t1 < t2;\n             });\n\n        size_t assign_cnt = min(fetched.size(), idle_workers.size());\n        vector<bool> task_used(fetched.size(), false);\n        vector<pair<int,int>> outputs;\n        outputs.reserve(assign_cnt);\n\n        for (size_t idx = 0; idx < assign_cnt; ++idx) {\n            int worker = idle_workers[idx];\n            int task_idx = task_order[idx];\n            Node item = fetched[task_idx];\n            int task = item.task;\n\n            worker_task[worker] = task;\n            worker_start[worker] = day;\n            task_state[task] = 2;\n            task_used[task_idx] = true;\n            outputs.emplace_back(worker, task);\n        }\n\n        // push back unused ready tasks (safety net)\n        for (size_t i = 0; i < fetched.size(); ++i) {\n            if (!task_used[i]) {\n                pq.push(fetched[i]);\n            }\n        }\n\n        // output for this day\n        cout << outputs.size();\n        for (auto &p : outputs) {\n            cout << ' ' << (p.first + 1) << ' ' << (p.second + 1);\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int n_finish;\n        if (!(cin >> n_finish)) return 0;\n        if (n_finish == -1) break;\n\n        vector<int> finished_workers(n_finish);\n        for (int i = 0; i < n_finish; ++i) {\n            cin >> finished_workers[i];\n            finished_workers[i]--; // to 0-index\n        }\n\n        for (int w : finished_workers) {\n            if (w < 0 || w >= M) continue;\n            int task = worker_task[w];\n            if (task == -1) continue;\n            int duration = day - worker_start[w] + 1;\n            if (duration <= 0) duration = 1;\n            double difficulty = max(1, sum_d[task]);\n            double ratio = difficulty / duration;\n            worker_ability[w] = worker_ability[w] * (1.0 - ability_alpha) + ratio * ability_alpha;\n            if (worker_ability[w] < 1e-6) worker_ability[w] = 1e-6;\n\n            worker_task[w] = -1;\n            worker_start[w] = -1;\n\n            task_state[task] = 3;\n            completed_tasks++;\n\n            for (int nxt : adj[task]) {\n                indeg[nxt]--;\n                if (indeg[nxt] == 0 && task_state[nxt] == 0) {\n                    task_state[nxt] = 1;\n                    pq.push({calc_priority(nxt), nxt});\n                }\n            }\n        }\n\n        day++;\n        if (day > 2100) break; // safety\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int ORDER_COUNT = 1000;\nconst int K = 50;\nconst int OFFICE = 400;\n\nstruct Order {\n    int ax, ay, cx, cy;\n    int len;\n    int base;\n    int officeScore;\n};\n\nstruct Node {\n    int order;\n    int type; // 0: pickup, 1: drop\n};\n\ninline int manhattan(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\nstruct XorShift {\n    uint64_t state;\n    XorShift(uint64_t seed = 88172645463393265ULL) {\n        if (seed == 0) seed = 88172645463393265ULL;\n        state = seed;\n    }\n    inline uint64_t nextU64() {\n        state ^= state << 7;\n        state ^= state >> 9;\n        return state;\n    }\n    inline int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nvector<int> buildInitialRoute(const vector<int>& selected, const vector<Order>& orders, XorShift& rng) {\n    vector<int> remaining = selected;\n    vector<int> route;\n    route.reserve(selected.size());\n    int curX = OFFICE, curY = OFFICE;\n    while (!remaining.empty()) {\n        int bestIdx = 0;\n        int bestDist = INT_MAX;\n        for (int i = 0; i < (int)remaining.size(); ++i) {\n            int id = remaining[i];\n            int dist = manhattan(curX, curY, orders[id].ax, orders[id].ay);\n            if (dist < bestDist ||\n                (dist == bestDist && orders[id].len < orders[remaining[bestIdx]].len) ||\n                (dist == bestDist && orders[id].len == orders[remaining[bestIdx]].len && rng.nextInt(2))) {\n                bestDist = dist;\n                bestIdx = i;\n            }\n        }\n        int chosen = remaining[bestIdx];\n        route.push_back(chosen);\n        curX = orders[chosen].cx;\n        curY = orders[chosen].cy;\n        remaining[bestIdx] = remaining.back();\n        remaining.pop_back();\n    }\n    return route;\n}\n\nlong long calcOrderRouteCost(const vector<int>& sequence, const vector<Order>& orders) {\n    int curX = OFFICE, curY = OFFICE;\n    long long cost = 0;\n    for (int id : sequence) {\n        const Order& ord = orders[id];\n        cost += manhattan(curX, curY, ord.ax, ord.ay);\n        cost += manhattan(ord.ax, ord.ay, ord.cx, ord.cy);\n        curX = ord.cx;\n        curY = ord.cy;\n    }\n    cost += manhattan(curX, curY, OFFICE, OFFICE);\n    return cost;\n}\n\nlong long twoOptImprove(vector<int>& route, const vector<Order>& orders) {\n    int n = route.size();\n    if (n <= 1) return calcOrderRouteCost(route, orders);\n    long long bestCost = calcOrderRouteCost(route, orders);\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int i = 0; i < n - 1; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                reverse(route.begin() + i, route.begin() + j + 1);\n                long long newCost = calcOrderRouteCost(route, orders);\n                if (newCost < bestCost) {\n                    bestCost = newCost;\n                    improved = true;\n                } else {\n                    reverse(route.begin() + i, route.begin() + j + 1);\n                }\n            }\n        }\n    }\n    return bestCost;\n}\n\nvector<Node> buildNodesFromSequence(const vector<int>& sequence) {\n    vector<Node> nodes;\n    nodes.reserve(sequence.size() * 2);\n    for (int id : sequence) {\n        nodes.push_back({id, 0});\n        nodes.push_back({id, 1});\n    }\n    return nodes;\n}\n\nlong long calcNodeRouteCost(const vector<Node>& nodes, const vector<Order>& orders) {\n    int curX = OFFICE, curY = OFFICE;\n    long long cost = 0;\n    for (const Node& node : nodes) {\n        const Order& ord = orders[node.order];\n        int nx = (node.type == 0) ? ord.ax : ord.cx;\n        int ny = (node.type == 0) ? ord.ay : ord.cy;\n        cost += manhattan(curX, curY, nx, ny);\n        curX = nx;\n        curY = ny;\n    }\n    cost += manhattan(curX, curY, OFFICE, OFFICE);\n    return cost;\n}\n\nvoid recomputePositions(const vector<Node>& nodes, const vector<int>& selected,\n                        vector<int>& pickPos, vector<int>& dropPos) {\n    for (int id : selected) {\n        pickPos[id] = -1;\n        dropPos[id] = -1;\n    }\n    for (int i = 0; i < (int)nodes.size(); ++i) {\n        if (nodes[i].type == 0) pickPos[nodes[i].order] = i;\n        else dropPos[nodes[i].order] = i;\n    }\n}\n\nbool tryMoveSingleNode(vector<Node>& nodes,\n                       vector<int>& pickPos, vector<int>& dropPos,\n                       const vector<int>& selected,\n                       const vector<Order>& orders,\n                       long long& currCost, long long& bestCost,\n                       vector<Node>& bestNodes,\n                       double temp, XorShift& rng) {\n    int L = nodes.size();\n    if (L <= 1) return false;\n    int origPos = rng.nextInt(L);\n    Node node = nodes[origPos];\n    int orderId = node.order;\n    nodes.erase(nodes.begin() + origPos);\n    int n = nodes.size();\n    if (n == 0) {\n        nodes.insert(nodes.begin() + origPos, node);\n        return false;\n    }\n    int insertPos = rng.nextInt(n + 1);\n    bool feasible = true;\n    if (node.type == 0) {\n        int dropIdx = dropPos[orderId];\n        if (dropIdx == -1) feasible = false;\n        else {\n            if (dropIdx > origPos) dropIdx--;\n            if (insertPos > dropIdx) feasible = false;\n        }\n    } else {\n        int pickIdx = pickPos[orderId];\n        if (pickIdx == -1) feasible = false;\n        else {\n            if (pickIdx >= origPos) pickIdx = pickIdx; // unchanged\n            if (insertPos <= pickIdx) feasible = false;\n        }\n    }\n    if (!feasible) {\n        nodes.insert(nodes.begin() + origPos, node);\n        return false;\n    }\n    nodes.insert(nodes.begin() + insertPos, node);\n    long long newCost = calcNodeRouteCost(nodes, orders);\n    bool accept = false;\n    if (newCost <= currCost) accept = true;\n    else {\n        double prob = exp((double)(currCost - newCost) / temp);\n        if (prob > rng.nextDouble()) accept = true;\n    }\n    if (accept) {\n        currCost = newCost;\n        if (newCost < bestCost) {\n            bestCost = newCost;\n            bestNodes = nodes;\n        }\n        recomputePositions(nodes, selected, pickPos, dropPos);\n    } else {\n        nodes.erase(nodes.begin() + insertPos);\n        nodes.insert(nodes.begin() + origPos, node);\n    }\n    return true;\n}\n\nbool tryMovePair(vector<Node>& nodes,\n                 vector<int>& pickPos, vector<int>& dropPos,\n                 const vector<int>& selected,\n                 const vector<Order>& orders,\n                 long long& currCost, long long& bestCost,\n                 vector<Node>& bestNodes,\n                 double temp, XorShift& rng) {\n    if (selected.empty()) return false;\n    int orderId = selected[rng.nextInt(selected.size())];\n    int posPick = pickPos[orderId];\n    int posDrop = dropPos[orderId];\n    if (posPick == -1 || posDrop == -1) return false;\n    if (posPick > posDrop) swap(posPick, posDrop);\n    Node pickNode = nodes[posPick];\n    Node dropNode = nodes[posDrop];\n    nodes.erase(nodes.begin() + posDrop);\n    nodes.erase(nodes.begin() + posPick);\n    int n = nodes.size();\n    int insertPick = rng.nextInt(n + 1);\n    nodes.insert(nodes.begin() + insertPick, pickNode);\n    int nAfterPick = n + 1;\n    int insertDrop = rng.nextInt(nAfterPick - insertPick) + insertPick + 1;\n    nodes.insert(nodes.begin() + insertDrop, dropNode);\n    long long newCost = calcNodeRouteCost(nodes, orders);\n    bool accept = false;\n    if (newCost <= currCost) accept = true;\n    else {\n        double prob = exp((double)(currCost - newCost) / temp);\n        if (prob > rng.nextDouble()) accept = true;\n    }\n    if (accept) {\n        currCost = newCost;\n        if (newCost < bestCost) {\n            bestCost = newCost;\n            bestNodes = nodes;\n        }\n        recomputePositions(nodes, selected, pickPos, dropPos);\n    } else {\n        nodes.erase(nodes.begin() + insertDrop);\n        nodes.erase(nodes.begin() + insertPick);\n        nodes.insert(nodes.begin() + posPick, pickNode);\n        nodes.insert(nodes.begin() + posDrop, dropNode);\n    }\n    return true;\n}\n\nlong long runNodeSA(vector<Node>& nodes,\n                    const vector<int>& selected,\n                    const vector<Order>& orders,\n                    double timeLimit,\n                    XorShift& rng,\n                    chrono::steady_clock::time_point globalStart,\n                    double globalLimit) {\n    long long currCost = calcNodeRouteCost(nodes, orders);\n    long long bestCost = currCost;\n    vector<Node> bestNodes = nodes;\n    vector<int> pickPos(ORDER_COUNT, -1), dropPos(ORDER_COUNT, -1);\n    recomputePositions(nodes, selected, pickPos, dropPos);\n    if (timeLimit <= 1e-6) {\n        nodes = bestNodes;\n        return bestCost;\n    }\n    const double START_TEMP = 2000.0;\n    const double END_TEMP = 5.0;\n    const double LOG_RATIO = std::log(END_TEMP / START_TEMP);\n    auto localStart = chrono::steady_clock::now();\n    double temp = START_TEMP;\n    long long iter = 0;\n    while (true) {\n        if ((iter & 0x3FFLL) == 0) {\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - localStart).count();\n            double globalElapsed = chrono::duration<double>(now - globalStart).count();\n            if (elapsed > timeLimit || globalElapsed > globalLimit) break;\n            double progress = min(1.0, elapsed / timeLimit);\n            temp = START_TEMP * exp(LOG_RATIO * progress);\n        }\n        ++iter;\n        int op = rng.nextInt(100);\n        if (op < 70) {\n            tryMoveSingleNode(nodes, pickPos, dropPos, selected, orders, currCost, bestCost, bestNodes, temp, rng);\n        } else {\n            tryMovePair(nodes, pickPos, dropPos, selected, orders, currCost, bestCost, bestNodes, temp, rng);\n        }\n    }\n    nodes = bestNodes;\n    return bestCost;\n}\n\nvector<pair<int, int>> buildPathFromNodes(const vector<Node>& nodes, const vector<Order>& orders) {\n    vector<pair<int, int>> path;\n    path.reserve(nodes.size() + 2);\n    path.emplace_back(OFFICE, OFFICE);\n    for (const Node& node : nodes) {\n        const Order& ord = orders[node.order];\n        if (node.type == 0) path.emplace_back(ord.ax, ord.ay);\n        else path.emplace_back(ord.cx, ord.cy);\n    }\n    path.emplace_back(OFFICE, OFFICE);\n    return path;\n}\n\nstruct RouteSolution {\n    vector<int> selectedOrders;\n    vector<Node> nodes;\n    long long cost = (1LL << 60);\n};\n\nRouteSolution optimizeSet(const vector<int>& selected,\n                          double saTime,\n                          const vector<Order>& orders,\n                          XorShift& rng,\n                          chrono::steady_clock::time_point globalStart,\n                          double globalLimit) {\n    RouteSolution sol;\n    sol.selectedOrders = selected;\n    vector<int> route = buildInitialRoute(selected, orders, rng);\n    twoOptImprove(route, orders);\n    vector<Node> nodes = buildNodesFromSequence(route);\n    long long cost = calcNodeRouteCost(nodes, orders);\n    cost = runNodeSA(nodes, selected, orders, saTime, rng, globalStart, globalLimit);\n    sol.cost = cost;\n    sol.nodes = nodes;\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    vector<Order> orders(ORDER_COUNT);\n    for (int i = 0; i < ORDER_COUNT; ++i) {\n        cin >> orders[i].ax >> orders[i].ay >> orders[i].cx >> orders[i].cy;\n        orders[i].len = manhattan(orders[i].ax, orders[i].ay, orders[i].cx, orders[i].cy);\n        orders[i].base = manhattan(OFFICE, OFFICE, orders[i].ax, orders[i].ay) +\n                         orders[i].len +\n                         manhattan(orders[i].cx, orders[i].cy, OFFICE, OFFICE);\n        orders[i].officeScore = manhattan(OFFICE, OFFICE, orders[i].ax, orders[i].ay) +\n                                manhattan(OFFICE, OFFICE, orders[i].cx, orders[i].cy);\n    }\n    vector<int> idx(ORDER_COUNT);\n    iota(idx.begin(), idx.end(), 0);\n    vector<int> byBase = idx;\n    sort(byBase.begin(), byBase.end(), [&](int a, int b) {\n        if (orders[a].base != orders[b].base) return orders[a].base < orders[b].base;\n        return a < b;\n    });\n    vector<int> byOffice = idx;\n    sort(byOffice.begin(), byOffice.end(), [&](int a, int b) {\n        if (orders[a].officeScore != orders[b].officeScore) return orders[a].officeScore < orders[b].officeScore;\n        return a < b;\n    });\n    vector<int> byLen = idx;\n    sort(byLen.begin(), byLen.end(), [&](int a, int b) {\n        if (orders[a].len != orders[b].len) return orders[a].len < orders[b].len;\n        return a < b;\n    });\n\n    auto firstK = [](const vector<int>& arr) {\n        vector<int> res;\n        for (int i = 0; i < K; ++i) res.push_back(arr[i]);\n        return res;\n    };\n\n    XorShift rng(chrono::steady_clock::now().time_since_epoch().count());\n    vector<vector<int>> candidateSets;\n    candidateSets.push_back(firstK(byBase));\n    candidateSets.push_back(firstK(byOffice));\n    candidateSets.push_back(firstK(byLen));\n\n    auto makeRandomSet = [&](const vector<int>& pool, int noiseRange) -> vector<int> {\n        vector<pair<long long, int>> tmp;\n        tmp.reserve(pool.size());\n        for (int id : pool) {\n            long long noise = (long long)(rng.nextU64() % (noiseRange + 1));\n            long long score = (long long)orders[id].base + noise;\n            tmp.emplace_back(score, id);\n        }\n        sort(tmp.begin(), tmp.end());\n        vector<int> res;\n        for (int i = 0; i < K && i < (int)tmp.size(); ++i) res.push_back(tmp[i].second);\n        return res;\n    };\n\n    vector<int> poolTop;\n    int poolTopSize = min(300, ORDER_COUNT);\n    for (int i = 0; i < poolTopSize; ++i) poolTop.push_back(byBase[i]);\n    if (!poolTop.empty()) candidateSets.push_back(makeRandomSet(poolTop, 4000));\n    candidateSets.push_back(makeRandomSet(idx, 8000));\n\n    int maxSets = min(5, (int)candidateSets.size());\n    RouteSolution bestSolution;\n    auto globalStart = chrono::steady_clock::now();\n    const double GLOBAL_LIMIT = 1.90;\n    for (int setIdx = 0; setIdx < maxSets; ++setIdx) {\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - globalStart).count();\n        double remaining = GLOBAL_LIMIT - elapsed;\n        if (remaining <= 0.02) break;\n        int setsLeft = maxSets - setIdx;\n        double reserve = 0.03 * (setsLeft - 1);\n        double available = max(0.0, remaining - reserve);\n        double saTime = available / setsLeft;\n        saTime = min(saTime, 0.6);\n        if (saTime < 0.02) saTime = 0.02;\n        RouteSolution sol = optimizeSet(candidateSets[setIdx], saTime, orders, rng, globalStart, GLOBAL_LIMIT);\n        if (sol.cost < bestSolution.cost) bestSolution = sol;\n    }\n    if (bestSolution.cost == (1LL << 60)) {\n        bestSolution = optimizeSet(candidateSets[0], 0.1, orders, rng, globalStart, GLOBAL_LIMIT);\n    }\n\n    vector<int> orderOutput;\n    vector<char> seen(ORDER_COUNT, 0);\n    for (const Node& node : bestSolution.nodes) {\n        if (node.type == 0 && !seen[node.order]) {\n            seen[node.order] = 1;\n            orderOutput.push_back(node.order);\n        }\n    }\n    for (int id : bestSolution.selectedOrders) {\n        if ((int)orderOutput.size() == K) break;\n        if (!seen[id]) {\n            seen[id] = 1;\n            orderOutput.push_back(id);\n        }\n    }\n    orderOutput.resize(K);\n\n    vector<pair<int, int>> path = buildPathFromNodes(bestSolution.nodes, orders);\n    cout << K;\n    for (int id : orderOutput) cout << ' ' << (id + 1);\n    cout << '\\n';\n    cout << path.size();\n    for (auto [x, y] : path) cout << ' ' << x << ' ' << y;\n    cout << '\\n';\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 400;\nconstexpr int M = 1995;\nconstexpr int LIGHT_LIMIT = 135;\n\nstruct Edge {\n    int u, v;\n    int d;\n    bool in_ref = false;\n};\n\nstruct DSU {\n    vector<int> parent;\n    vector<int> sz;\n    int comp;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        parent.resize(n);\n        sz.assign(n, 1);\n        iota(parent.begin(), parent.end(), 0);\n        comp = n;\n    }\n    int find(int x) {\n        if (parent[x] == x) return x;\n        return parent[x] = find(parent[x]);\n    }\n    int root_size(int r) const { return sz[r]; }\n    int merge_roots(int a, int b, int &loser) {\n        a = find(a);\n        b = find(b);\n        if (a == b) {\n            loser = -1;\n            return a;\n        }\n        if (sz[a] < sz[b]) swap(a, b);\n        parent[b] = a;\n        sz[a] += sz[b];\n        sz[b] = 0;\n        comp--;\n        loser = b;\n        return a;\n    }\n};\n\nstruct CompStats {\n    int best_d;\n    int second_d;\n    int light_cnt;\n    int total;\n};\n\nint rounded_distance(const pair<int,int>& A, const pair<int,int>& B) {\n    long long dx = (long long)A.first - B.first;\n    long long dy = (long long)A.second - B.second;\n    double dist = std::sqrt((double)dx * dx + (double)dy * dy);\n    return (int)std::llround(dist);\n}\n\nvoid remove_future_edge(int ru, int rv,\n                        vector<vector<int>>& adj, vector<int>& out_deg) {\n    if (ru == rv) return;\n    if (adj[ru][rv] > 0) {\n        --adj[ru][rv];\n        --adj[rv][ru];\n    } else {\n        adj[ru][rv] = adj[rv][ru] = 0;\n    }\n    if (out_deg[ru] > 0) --out_deg[ru];\n    if (out_deg[rv] > 0) --out_deg[rv];\n}\n\nvoid merge_adj(int keep, int lose,\n               vector<vector<int>>& adj, vector<int>& out_deg) {\n    if (lose < 0 || keep == lose) return;\n    int between = adj[keep][lose];\n    adj[keep][lose] = adj[lose][keep] = 0;\n    out_deg[keep] = max(0, out_deg[keep] + out_deg[lose] - 2 * between);\n    out_deg[lose] = 0;\n    for (int c = 0; c < N; ++c) {\n        if (c == keep || c == lose) continue;\n        int add = adj[lose][c];\n        if (!add) continue;\n        adj[keep][c] += add;\n        adj[c][keep] = adj[keep][c];\n        adj[lose][c] = adj[c][lose] = 0;\n    }\n    adj[keep][keep] = 0;\n}\n\nvoid merge_edge_lists(int keep, int lose, vector<vector<int>>& comp_edges) {\n    if (lose < 0 || keep == lose) return;\n    if (comp_edges[keep].size() < comp_edges[lose].size())\n        comp_edges[keep].swap(comp_edges[lose]);\n    comp_edges[keep].insert(comp_edges[keep].end(),\n                            comp_edges[lose].begin(),\n                            comp_edges[lose].end());\n    vector<int>().swap(comp_edges[lose]);\n}\n\nCompStats get_comp_stats(int root, DSU &dsu,\n                         const vector<Edge>& edges,\n                         const vector<char>& processed,\n                         const vector<vector<int>>& comp_edges) {\n    const int INF_D = 1e9;\n    int best = INF_D;\n    int second = INF_D;\n    int lights = 0;\n    int total = 0;\n    for (int idx : comp_edges[root]) {\n        if (processed[idx]) continue;\n        const Edge &e = edges[idx];\n        int a = dsu.find(e.u);\n        int b = dsu.find(e.v);\n        if (a == b) continue;\n        if (a != root && b != root) continue;\n        ++total;\n        int d = e.d;\n        if (d < best) {\n            second = best;\n            best = d;\n        } else if (d < second) {\n            second = d;\n        }\n        if (d <= LIGHT_LIMIT) ++lights;\n    }\n    return {best, second, lights, total};\n}\n\ndouble compute_threshold(double progress, double comp_frac,\n                         const Edge& edge, double len,\n                         int sizeA, int sizeB,\n                         int outA, int outB,\n                         const CompStats& statsA,\n                         const CompStats& statsB,\n                         int direct_remaining) {\n    using std::clamp;\n    using std::pow;\n\n    constexpr double BASE_START = 1.03;\n    constexpr double BASE_END = 2.08;\n    constexpr double BASE_POWER = 0.78;\n    constexpr double COMP_COEFF = 0.32;\n    constexpr double COMP_POWER = 0.82;\n    constexpr double LAG_COEFF = 0.44;\n    constexpr double LEAD_COEFF = 0.11;\n    constexpr double SIZE_COEFF = 0.28;\n    constexpr double SIZE_POWER = 0.62;\n    constexpr double SMALLD_LIMIT = 150.0;\n    constexpr double SMALLD_COEFF = 0.30;\n    constexpr double LARGE_LIMIT = 260.0;\n    constexpr double LARGE_SPAN = 360.0;\n    constexpr double LARGE_COEFF = 0.11;\n    constexpr double REF_BONUS = 0.22;\n    constexpr double DENSITY_TARGET = 1.8;\n    constexpr double DENSITY_COEFF = 0.42;\n    constexpr double OUT_TARGET = 8.0;\n    constexpr double OUT_COEFF = 0.30;\n    constexpr double LEN_REFERENCE = 200.0;\n    constexpr double LEN_COEFF = 0.16;\n    constexpr double SCARCITY_COEFF = 0.17;\n    constexpr double LIGHT_NONE_BONUS = 0.18;\n    constexpr double LIGHT_FEW_BONUS = 0.09;\n    constexpr double LIGHT_MANY_BONUS = 0.06;\n    constexpr double FUTURE_COEFF = 0.38;\n    constexpr double NO_FUTURE_BONUS = 0.35;\n    constexpr double GAP_COEFF = 0.12;\n    constexpr double GAP_WINDOW = 60.0;\n    constexpr double DIRECT_BONUS = 0.16;\n    constexpr double DIRECT_PENALTY = 0.02;\n    constexpr double MIN_THRESHOLD = 0.98;\n    constexpr double MAX_THRESHOLD = 2.55;\n    constexpr int INF_D = 1e9;\n\n    progress = clamp(progress, 0.0, 1.0);\n    comp_frac = clamp(comp_frac, 0.0, 1.0);\n\n    double base = BASE_START + (BASE_END - BASE_START) * pow(progress, BASE_POWER);\n    base += COMP_COEFF * pow(comp_frac, COMP_POWER);\n    double lag = clamp(progress - comp_frac, 0.0, 1.0);\n    double lead = clamp(comp_frac - progress, 0.0, 1.0);\n    base += LAG_COEFF * lag;\n    base -= LEAD_COEFF * lead;\n\n    double thr = base;\n    double size_frac = double(sizeA + sizeB) / double(N);\n    thr += SIZE_COEFF * pow(size_frac, SIZE_POWER);\n\n    double small_factor = clamp((SMALLD_LIMIT - double(edge.d)) / SMALLD_LIMIT, -1.0, 1.0);\n    thr += SMALLD_COEFF * small_factor;\n    double large_factor = clamp((double(edge.d) - LARGE_LIMIT) / LARGE_SPAN, 0.0, 1.0);\n    thr -= LARGE_COEFF * large_factor;\n\n    if (edge.in_ref) thr += REF_BONUS;\n\n    double densityA = sizeA > 0 ? double(outA) / double(sizeA) : 0.0;\n    double densityB = sizeB > 0 ? double(outB) / double(sizeB) : 0.0;\n    double density = min(densityA, densityB);\n    double density_need = clamp((DENSITY_TARGET - density) / DENSITY_TARGET, 0.0, 1.5);\n    thr += DENSITY_COEFF * density_need;\n\n    int min_out = min(outA, outB);\n    double scarcity = clamp((OUT_TARGET - double(min_out)) / OUT_TARGET, 0.0, 1.5);\n    thr += OUT_COEFF * scarcity;\n\n    double len_effect = clamp((LEN_REFERENCE - len) / LEN_REFERENCE, -1.0, 1.0);\n    thr += LEN_COEFF * len_effect;\n\n    if (statsA.total <= 2) thr += SCARCITY_COEFF;\n    if (statsB.total <= 2) thr += SCARCITY_COEFF;\n\n    int light_total = statsA.light_cnt + statsB.light_cnt;\n    if (light_total == 0) thr += LIGHT_NONE_BONUS;\n    else if (light_total <= 2) thr += LIGHT_FEW_BONUS;\n    else if (light_total >= 7) thr -= LIGHT_MANY_BONUS;\n\n    int best_future = min(statsA.best_d, statsB.best_d);\n    if (best_future >= INF_D / 2) {\n        thr += NO_FUTURE_BONUS;\n    } else {\n        double future_rel = (double(best_future) - double(edge.d)) /\n                            max(60.0, double(edge.d));\n        thr += FUTURE_COEFF * future_rel;\n    }\n\n    auto gap_value = [&](const CompStats& st) -> double {\n        if (st.second_d >= INF_D / 2 || st.best_d >= INF_D / 2) return GAP_WINDOW;\n        return double(st.second_d - st.best_d);\n    };\n    double gap = min(gap_value(statsA), gap_value(statsB));\n    if (gap < GAP_WINDOW) {\n        double gap_term = clamp((GAP_WINDOW - gap) / GAP_WINDOW, 0.0, 1.0);\n        thr += GAP_COEFF * gap_term;\n    }\n\n    if (direct_remaining == 0) {\n        thr += DIRECT_BONUS * (0.6 + 0.4 * size_frac);\n    } else {\n        thr -= DIRECT_PENALTY * min(direct_remaining, 4);\n    }\n\n    return clamp(thr, MIN_THRESHOLD, MAX_THRESHOLD);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<pair<int,int>> pos(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> pos[i].first >> pos[i].second;\n    }\n\n    vector<Edge> edges(M);\n    vector<vector<int>> adj(N, vector<int>(N, 0));\n    vector<int> out_deg(N, 0);\n    vector<vector<int>> comp_edges(N);\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        edges[i].d = rounded_distance(pos[u], pos[v]);\n        adj[u][v] += 1;\n        adj[v][u] += 1;\n        out_deg[u] += 1;\n        out_deg[v] += 1;\n        comp_edges[u].push_back(i);\n        comp_edges[v].push_back(i);\n    }\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n    DSU mst_dsu(N);\n    int need = N - 1;\n    for (int idx : order) {\n        int loser;\n        mst_dsu.merge_roots(edges[idx].u, edges[idx].v, loser);\n        if (loser != -1) {\n            edges[idx].in_ref = true;\n            if (--need == 0) break;\n        }\n    }\n\n    DSU dsu(N);\n    vector<char> processed(M, false);\n    std::mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n    std::uniform_real_distribution<double> noise_dist(-0.015, 0.015);\n\n    for (int i = 0; i < M; ++i) {\n        int len;\n        if (!(cin >> len)) return 0;\n        Edge &edge = edges[i];\n        int ru = dsu.find(edge.u);\n        int rv = dsu.find(edge.v);\n        processed[i] = true;\n\n        if (ru == rv) {\n            cout << 0 << '\\n' << flush;\n            continue;\n        }\n\n        remove_future_edge(ru, rv, adj, out_deg);\n        int direct_after = adj[ru][rv];\n\n        bool accept = false;\n        if (out_deg[ru] == 0 || out_deg[rv] == 0) {\n            accept = true;\n        }\n\n        CompStats statsA{}, statsB{};\n        if (!accept) {\n            statsA = get_comp_stats(ru, dsu, edges, processed, comp_edges);\n            statsB = get_comp_stats(rv, dsu, edges, processed, comp_edges);\n\n            int sizeA = dsu.root_size(ru);\n            int sizeB = dsu.root_size(rv);\n            int outA = out_deg[ru];\n            int outB = out_deg[rv];\n            double progress = double(i) / double(M);\n            double comp_frac = double(N - dsu.comp) / double(N - 1);\n\n            double threshold = compute_threshold(progress, comp_frac, edge, double(len),\n                                                 sizeA, sizeB, outA, outB,\n                                                 statsA, statsB, direct_after);\n            threshold += noise_dist(rng);\n            threshold = std::clamp(threshold, 0.95, 2.60);\n\n            double ratio = double(len) / double(max(edge.d, 1));\n            if (ratio <= threshold) accept = true;\n            if (!accept) {\n                int future_edges = M - i - 1;\n                int need_edges = dsu.comp - 1;\n                if (future_edges <= need_edges) accept = true;\n            }\n        }\n\n        if (accept) {\n            cout << 1 << '\\n' << flush;\n            int loser;\n            int keep = dsu.merge_roots(ru, rv, loser);\n            merge_adj(keep, loser, adj, out_deg);\n            merge_edge_lists(keep, loser, comp_edges);\n        } else {\n            cout << 0 << '\\n' << flush;\n        }\n    }\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int x, y;\n};\n\nstruct BlockCell {\n    int x, y;\n    char action; // 'u','d','l','r'\n};\n\nstruct Candidate {\n    Point pos;\n    vector<BlockCell> blocks;\n};\n\nconst int H = 30;\nconst int W = 30;\nconst int DX[4] = {-1, 1, 0, 0}; // U, D, L, R\nconst int DY[4] = {0, 0, -1, 1};\nconst char MOVE_CH[4] = {'U', 'D', 'L', 'R'};\nconst int DIST_WEIGHT = 10;\nconst int PET_RADIUS = 6;\nconst int PET_WEIGHT = 50;\nconst int REASSIGN_WAIT = 45;\nconst int REASSIGN_BUFFER = 6;\nconst int MIN_REMAINING_FOR_REASSIGN = 60;\nconst int MAX_REASSIGN = 1;\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < H && 0 <= y && y < W;\n}\n\nint dir_from_char(char c) {\n    if (c == 'U' || c == 'u') return 0;\n    if (c == 'D' || c == 'd') return 1;\n    if (c == 'L' || c == 'l') return 2;\n    if (c == 'R' || c == 'r') return 3;\n    return -1;\n}\n\nint bfs_next_dir(const vector<vector<int>>& impassable, const Point& start, const Point& goal) {\n    if (start.x == goal.x && start.y == goal.y) return -1;\n    array<array<int, W>, H> dist;\n    array<array<int, W>, H> parent_dir;\n    for (int i = 0; i < H; ++i) {\n        dist[i].fill(-1);\n        parent_dir[i].fill(-1);\n    }\n    queue<Point> q;\n    dist[start.x][start.y] = 0;\n    q.push(start);\n    while (!q.empty()) {\n        Point cur = q.front(); q.pop();\n        for (int d = 0; d < 4; ++d) {\n            int nx = cur.x + DX[d];\n            int ny = cur.y + DY[d];\n            if (!inside(nx, ny)) continue;\n            if (impassable[nx][ny]) continue;\n            if (dist[nx][ny] != -1) continue;\n            dist[nx][ny] = dist[cur.x][cur.y] + 1;\n            parent_dir[nx][ny] = d;\n            q.push({nx, ny});\n        }\n    }\n    if (dist[goal.x][goal.y] == -1) return -1;\n    int gx = goal.x, gy = goal.y;\n    int dir = -1;\n    while (!(gx == start.x && gy == start.y)) {\n        int d = parent_dir[gx][gy];\n        dir = d;\n        gx -= DX[d];\n        gy -= DY[d];\n    }\n    return dir;\n}\n\nvector<int> hungarian(const vector<vector<int>>& a) {\n    int n = (int)a.size();\n    int m = (int)a[0].size();\n    const int INF = 1e9;\n    vector<int> u(n + 1), v(m + 1), p(m + 1), way(m + 1);\n    for (int i = 1; i <= n; ++i) {\n        p[0] = i;\n        vector<int> minv(m + 1, INF);\n        vector<char> used(m + 1, false);\n        int j0 = 0;\n        do {\n            used[j0] = true;\n            int i0 = p[j0], delta = INF, j1 = 0;\n            for (int j = 1; j <= m; ++j) if (!used[j]) {\n                int cur = a[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= m; ++j) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    v[j] -= delta;\n                } else {\n                    minv[j] -= delta;\n                }\n            }\n            j0 = j1;\n        } while (p[j0] != 0);\n        do {\n            int j1 = way[j0];\n            p[j0] = p[j1];\n            j0 = j1;\n        } while (j0);\n    }\n    vector<int> ans(n, -1);\n    for (int j = 1; j <= m; ++j) if (p[j]) ans[p[j] - 1] = j - 1;\n    return ans;\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<Point> pets(N);\n    vector<int> pet_type(N);\n    for (int i = 0; i < N; ++i) {\n        int px, py, pt;\n        cin >> px >> py >> pt;\n        pets[i] = {px - 1, py - 1};\n        pet_type[i] = pt;\n    }\n    int M;\n    cin >> M;\n    vector<Point> humans(M);\n    for (int i = 0; i < M; ++i) {\n        int hx, hy;\n        cin >> hx >> hy;\n        humans[i] = {hx - 1, hy - 1};\n    }\n\n    vector<vector<int>> blocked(H, vector<int>(W, 0));\n    vector<vector<int>> pet_count(H, vector<int>(W, 0));\n    for (auto &p : pets) pet_count[p.x][p.y]++;\n\n    vector<int> edge_pos = {2, 6, 10, 14, 18, 22, 26}; // 0-based\n    vector<Candidate> candidates;\n    for (int y : edge_pos) {\n        Candidate c;\n        c.pos = {0, y};\n        c.blocks = {{1, y, 'd'}, {0, y - 1, 'l'}, {0, y + 1, 'r'}};\n        candidates.push_back(c);\n    }\n    for (int y : edge_pos) {\n        Candidate c;\n        c.pos = {H - 1, y};\n        c.blocks = {{H - 2, y, 'u'}, {H - 1, y - 1, 'l'}, {H - 1, y + 1, 'r'}};\n        candidates.push_back(c);\n    }\n    for (int x : edge_pos) {\n        Candidate c;\n        c.pos = {x, 0};\n        c.blocks = {{x, 1, 'r'}, {x - 1, 0, 'u'}, {x + 1, 0, 'd'}};\n        candidates.push_back(c);\n    }\n    for (int x : edge_pos) {\n        Candidate c;\n        c.pos = {x, W - 1};\n        c.blocks = {{x, W - 2, 'l'}, {x - 1, W - 1, 'u'}, {x + 1, W - 1, 'd'}};\n        candidates.push_back(c);\n    }\n    int C = (int)candidates.size();\n    assert(C >= M);\n\n    vector<int> candidate_penalty(C, 0);\n    auto update_penalty = [&]() {\n        fill(candidate_penalty.begin(), candidate_penalty.end(), 0);\n        for (int j = 0; j < C; ++j) {\n            int pen = 0;\n            for (auto &p : pets) {\n                int dist = abs(p.x - candidates[j].pos.x) + abs(p.y - candidates[j].pos.y);\n                if (dist < PET_RADIUS) pen += (PET_RADIUS - dist) * PET_WEIGHT;\n            }\n            candidate_penalty[j] = pen;\n        }\n    };\n    update_penalty();\n\n    vector<vector<int>> cost(M, vector<int>(C));\n    for (int i = 0; i < M; ++i) {\n        for (int j = 0; j < C; ++j) {\n            int dist = abs(humans[i].x - candidates[j].pos.x) + abs(humans[i].y - candidates[j].pos.y);\n            cost[i][j] = dist * DIST_WEIGHT + candidate_penalty[j];\n        }\n    }\n    vector<int> assign = hungarian(cost);\n\n    vector<int> candidate_owner(C, -1);\n    vector<int> human_target_idx(M, -1);\n    vector<Point> targets(M);\n    vector<vector<BlockCell>> human_block_cells(M);\n    vector<vector<int>> human_block_done(M);\n    vector<int> stage(M, 0); // 0 moving, 1 blocking, 2 done\n    vector<int> idle_block_turns(M, 0);\n    vector<int> reassign_count(M, 0);\n\n    auto is_complete = [&](int i) -> bool {\n        for (int done : human_block_done[i]) if (!done) return false;\n        return true;\n    };\n\n    auto set_candidate = [&](int human_idx, int cand_idx) {\n        human_target_idx[human_idx] = cand_idx;\n        targets[human_idx] = candidates[cand_idx].pos;\n        human_block_cells[human_idx] = candidates[cand_idx].blocks;\n        human_block_done[human_idx].assign(human_block_cells[human_idx].size(), 0);\n        for (int k = 0; k < (int)human_block_cells[human_idx].size(); ++k) {\n            auto &bc = human_block_cells[human_idx][k];\n            if (blocked[bc.x][bc.y]) human_block_done[human_idx][k] = 1;\n        }\n        idle_block_turns[human_idx] = 0;\n        if (humans[human_idx].x == targets[human_idx].x && humans[human_idx].y == targets[human_idx].y) {\n            stage[human_idx] = is_complete(human_idx) ? 2 : 1;\n        } else {\n            stage[human_idx] = 0;\n        }\n    };\n\n    for (int i = 0; i < M; ++i) {\n        candidate_owner[assign[i]] = i;\n        set_candidate(i, assign[i]);\n    }\n\n    auto try_reassign = [&](int idx, int remaining_turns) -> bool {\n        if (reassign_count[idx] >= MAX_REASSIGN) return false;\n        int old = human_target_idx[idx];\n        if (old < 0) return false;\n        int old_owner = candidate_owner[old];\n        candidate_owner[old] = -1;\n        int best = -1;\n        int best_cost = INT_MAX;\n        for (int j = 0; j < C; ++j) {\n            if (candidate_owner[j] != -1) continue;\n            if (j == old) continue;\n            int dist = abs(humans[idx].x - candidates[j].pos.x) + abs(humans[idx].y - candidates[j].pos.y);\n            if (dist + REASSIGN_BUFFER > remaining_turns) continue;\n            int cur_cost = dist * DIST_WEIGHT + candidate_penalty[j];\n            if (cur_cost < best_cost) {\n                best_cost = cur_cost;\n                best = j;\n            }\n        }\n        if (best == -1) {\n            candidate_owner[old] = old_owner;\n            return false;\n        }\n        candidate_owner[best] = idx;\n        human_target_idx[idx] = best;\n        targets[idx] = candidates[best].pos;\n        human_block_cells[idx] = candidates[best].blocks;\n        human_block_done[idx].assign(human_block_cells[idx].size(), 0);\n        for (int k = 0; k < (int)human_block_cells[idx].size(); ++k) {\n            auto &bc = human_block_cells[idx][k];\n            if (blocked[bc.x][bc.y]) human_block_done[idx][k] = 1;\n        }\n        idle_block_turns[idx] = 0;\n        if (humans[idx].x == targets[idx].x && humans[idx].y == targets[idx].y) {\n            stage[idx] = is_complete(idx) ? 2 : 1;\n        } else {\n            stage[idx] = 0;\n        }\n        reassign_count[idx]++;\n        return true;\n    };\n\n    for (int turn = 0; turn < 300; ++turn) {\n        for (int i = 0; i < M; ++i) {\n            for (int k = 0; k < (int)human_block_cells[i].size(); ++k) {\n                if (!human_block_done[i][k]) {\n                    auto &bc = human_block_cells[i][k];\n                    if (blocked[bc.x][bc.y]) human_block_done[i][k] = 1;\n                }\n            }\n            if (stage[i] == 0 && humans[i].x == targets[i].x && humans[i].y == targets[i].y) {\n                stage[i] = is_complete(i) ? 2 : 1;\n            }\n            if (stage[i] == 1 && is_complete(i)) {\n                stage[i] = 2;\n                idle_block_turns[i] = 0;\n            }\n        }\n\n        vector<vector<int>> humans_here(H, vector<int>(W, 0));\n        for (auto &h : humans) humans_here[h.x][h.y]++;\n\n        vector<int> planned_block_index(M, -1);\n        string actions(M, '.');\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] != 1) continue;\n            if (is_complete(i)) continue;\n            for (int idx = 0; idx < (int)human_block_cells[i].size(); ++idx) {\n                if (human_block_done[i][idx]) continue;\n                auto &bc = human_block_cells[i][idx];\n                if (blocked[bc.x][bc.y]) {\n                    human_block_done[i][idx] = 1;\n                    continue;\n                }\n                if (pet_count[bc.x][bc.y] > 0) continue;\n                bool adj_pet = false;\n                for (int d = 0; d < 4; ++d) {\n                    int ax = bc.x + DX[d];\n                    int ay = bc.y + DY[d];\n                    if (inside(ax, ay) && pet_count[ax][ay] > 0) {\n                        adj_pet = true;\n                        break;\n                    }\n                }\n                if (adj_pet) continue;\n                if (humans_here[bc.x][bc.y] > 0) continue;\n                planned_block_index[i] = idx;\n                actions[i] = bc.action;\n                break;\n            }\n        }\n\n        vector<vector<int>> temp_blocked = blocked;\n        for (int i = 0; i < M; ++i) {\n            int idx = planned_block_index[i];\n            if (idx != -1) {\n                auto &bc = human_block_cells[i][idx];\n                temp_blocked[bc.x][bc.y] = 1;\n            }\n        }\n\n        for (int i = 0; i < M; ++i) {\n            if (actions[i] != '.') continue;\n            if (stage[i] != 0) continue;\n            if (humans[i].x == targets[i].x && humans[i].y == targets[i].y) {\n                stage[i] = is_complete(i) ? 2 : 1;\n                continue;\n            }\n            int dir = bfs_next_dir(temp_blocked, humans[i], targets[i]);\n            if (dir != -1) actions[i] = MOVE_CH[dir];\n        }\n\n        cout << actions << endl;\n\n        vector<Point> start_pos = humans;\n        for (int i = 0; i < M; ++i) {\n            char act = actions[i];\n            int dir = dir_from_char(act);\n            if (act == '.' || dir == -1) continue;\n            if ('A' <= act && act <= 'Z') {\n                humans[i].x += DX[dir];\n                humans[i].y += DY[dir];\n            } else {\n                int nx = start_pos[i].x + DX[dir];\n                int ny = start_pos[i].y + DY[dir];\n                if (inside(nx, ny)) {\n                    blocked[nx][ny] = 1;\n                    int idx = planned_block_index[i];\n                    if (idx != -1) human_block_done[i][idx] = 1;\n                }\n            }\n        }\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 1) {\n                if (is_complete(i)) {\n                    stage[i] = 2;\n                    idle_block_turns[i] = 0;\n                } else if (planned_block_index[i] != -1 && actions[i] == human_block_cells[i][planned_block_index[i]].action) {\n                    idle_block_turns[i] = 0;\n                } else {\n                    idle_block_turns[i]++;\n                }\n            }\n        }\n\n        vector<string> pet_moves(N);\n        for (int i = 0; i < N; ++i) cin >> pet_moves[i];\n        for (int i = 0; i < N; ++i) {\n            for (char c : pet_moves[i]) {\n                int dir = dir_from_char(c);\n                if (dir == -1) continue;\n                pets[i].x += DX[dir];\n                pets[i].y += DY[dir];\n            }\n        }\n        for (int x = 0; x < H; ++x) fill(pet_count[x].begin(), pet_count[x].end(), 0);\n        for (auto &p : pets) pet_count[p.x][p.y]++;\n        update_penalty();\n\n        int remaining = 300 - (turn + 1);\n        if (remaining > 0) {\n            for (int i = 0; i < M; ++i) {\n                if (stage[i] == 1 && !is_complete(i)) {\n                    if (idle_block_turns[i] >= REASSIGN_WAIT && remaining >= MIN_REMAINING_FOR_REASSIGN) {\n                        try_reassign(i, remaining);\n                    }\n                }\n            }\n        }\n    }\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int H = 20;\nconstexpr int W = 20;\nconstexpr int N = H * W;\nconstexpr int MAX_L = 200;\nconstexpr int MAX_SEG_LEN = 40;\nconst char DIR_CHARS[4] = {'U', 'D', 'L', 'R'};\nconstexpr double TIME_LIMIT = 1.95;\nconstexpr double IMPROVE_EPS = 1e-9;\n\nstruct StepResult {\n    double score;\n    double reachProb;\n};\n\ninline StepResult apply_transition_raw(const double* from, double* to, int dir, int step,\n                                       double forgetProb, double moveProb,\n                                       const array<array<int, N>, 4>& neighbor,\n                                       int targetIdx) {\n    StepResult res{0.0, 0.0};\n    fill(to, to + N, 0.0);\n    const double rewardFactor = 401.0 - (step + 1);\n    for (int idx = 0; idx < N; ++idx) {\n        double prob = from[idx];\n        if (prob <= 1e-15) continue;\n        double stayProb = prob * forgetProb;\n        int nxt = neighbor[dir][idx];\n        double move = prob * moveProb;\n        if (nxt == idx) {\n            stayProb += move;\n        } else if (nxt == targetIdx) {\n            res.score += rewardFactor * move;\n            res.reachProb += move;\n        } else {\n            to[nxt] += move;\n        }\n        to[idx] += stayProb;\n    }\n    return res;\n}\n\ninline double dot_product_raw(const double* a, const double* b) {\n    double sum = 0.0;\n    for (int i = 0; i < N; ++i) sum += a[i] * b[i];\n    return sum;\n}\n\ninline double expected_distance_raw(const double* dist, const double* distTarget) {\n    double sum = 0.0;\n    for (int idx = 0; idx < N; ++idx) sum += dist[idx] * distTarget[idx];\n    return sum;\n}\n\nvector<int> compute_distances(const array<array<int, N>, 4>& neighbor, int targetIdx) {\n    const int INF = 1e9;\n    vector<int> dist(N, INF);\n    queue<int> q;\n    dist[targetIdx] = 0;\n    q.push(targetIdx);\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        for (int dir = 0; dir < 4; ++dir) {\n            int v = neighbor[dir][u];\n            if (v == u) continue;\n            if (dist[v] > dist[u] + 1) {\n                dist[v] = dist[u] + 1;\n                q.push(v);\n            }\n        }\n    }\n    return dist;\n}\n\nvector<int> build_bfs_candidate(int startIdx, int targetIdx,\n                                const array<array<int, N>, 4>& neighbor) {\n    vector<int> parent(N, -1);\n    vector<int> parentDir(N, -1);\n    queue<int> q;\n    q.push(startIdx);\n    parent[startIdx] = startIdx;\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        if (u == targetIdx) break;\n        for (int dir = 0; dir < 4; ++dir) {\n            int v = neighbor[dir][u];\n            if (v == u) continue;\n            if (parent[v] != -1) continue;\n            parent[v] = u;\n            parentDir[v] = dir;\n            q.push(v);\n        }\n    }\n    vector<int> path;\n    if (parent[targetIdx] != -1) {\n        int cur = targetIdx;\n        while (cur != startIdx) {\n            int dir = parentDir[cur];\n            path.push_back(dir);\n            cur = parent[cur];\n        }\n        reverse(path.begin(), path.end());\n    }\n    vector<int> seq(MAX_L, 1);\n    int pos = 0;\n    for (int dir : path) {\n        if (pos >= MAX_L) break;\n        seq[pos++] = dir;\n    }\n    const int filler[4] = {1, 3, 1, 3};\n    int fpos = 0;\n    while (pos < MAX_L) {\n        seq[pos++] = filler[fpos];\n        fpos = (fpos + 1) % 4;\n    }\n    return seq;\n}\n\nstruct BeamParam {\n    double weight;\n    double noise;\n    int width;\n};\n\nstruct BeamResult {\n    vector<int> seq;\n    double score;\n};\n\nBeamResult run_beam(const BeamParam& param,\n                    const array<array<int, N>, 4>& neighbor,\n                    const vector<double>& distTarget,\n                    int startIdx, int targetIdx,\n                    double forgetProb,\n                    mt19937& rng) {\n    const double moveProb = 1.0 - forgetProb;\n    struct Candidate {\n        array<double, N> dist;\n        double score;\n        double heuristic;\n        array<uint8_t, MAX_L> path;\n        int len;\n    };\n    vector<Candidate> beam, next;\n    beam.reserve(param.width);\n    next.reserve(param.width * 4);\n\n    Candidate init;\n    init.dist.fill(0.0);\n    init.dist[startIdx] = 1.0;\n    init.score = 0.0;\n    init.len = 0;\n    init.path.fill(0);\n    init.heuristic = 0.0;\n    beam.push_back(init);\n\n    uniform_real_distribution<double> noiseDist(-param.noise, param.noise);\n    auto cmp = [](const Candidate& a, const Candidate& b) {\n        return a.heuristic > b.heuristic;\n    };\n\n    for (int step = 0; step < MAX_L; ++step) {\n        next.clear();\n        for (const Candidate& cand : beam) {\n            for (int dir = 0; dir < 4; ++dir) {\n                Candidate child;\n                child.path = cand.path;\n                child.path[cand.len] = static_cast<uint8_t>(dir);\n                child.len = cand.len + 1;\n                StepResult sr = apply_transition_raw(cand.dist.data(), child.dist.data(),\n                                                     dir, step, forgetProb, moveProb,\n                                                     neighbor, targetIdx);\n                child.score = cand.score + sr.score;\n                double expDist = expected_distance_raw(child.dist.data(), distTarget.data());\n                double noise = (param.noise > 0) ? noiseDist(rng) : 0.0;\n                child.heuristic = child.score - param.weight * expDist + noise;\n                next.push_back(std::move(child));\n            }\n        }\n        if (next.empty()) break;\n        int width = min(param.width, static_cast<int>(next.size()));\n        partial_sort(next.begin(), next.begin() + width, next.end(), cmp);\n        next.resize(width);\n        beam.swap(next);\n    }\n\n    Candidate best = beam[0];\n    for (const Candidate& cand : beam) if (cand.score > best.score) best = cand;\n    vector<int> seq(MAX_L);\n    for (int i = 0; i < MAX_L; ++i) seq[i] = best.path[i];\n    return {seq, best.score};\n}\n\nstruct Evaluator {\n    const array<array<int, N>, 4>& neighbor;\n    int startIdx;\n    int targetIdx;\n    double forgetProb;\n    double moveProb;\n    vector<double> cur, nxt;\n    Evaluator(const array<array<int, N>, 4>& neighbor_, int s, int t, double p)\n        : neighbor(neighbor_), startIdx(s), targetIdx(t), forgetProb(p), moveProb(1.0 - p),\n          cur(N, 0.0), nxt(N, 0.0) {}\n\n    double evaluate(const vector<int>& seq) {\n        fill(cur.begin(), cur.end(), 0.0);\n        cur[startIdx] = 1.0;\n        double total = 0.0;\n        for (int step = 0; step < (int)seq.size(); ++step) {\n            StepResult sr = apply_transition_raw(cur.data(), nxt.data(), seq[step], step,\n                                                 forgetProb, moveProb, neighbor, targetIdx);\n            total += sr.score;\n            cur.swap(nxt);\n            bool empty = true;\n            for (double v : cur) if (v > 1e-15) { empty = false; break; }\n            if (empty) break;\n        }\n        return total;\n    }\n};\n\nvoid recompute_forward_from(int startStep,\n                            const vector<int>& seq,\n                            vector<array<double, N>>& forward,\n                            vector<double>& prefixScore,\n                            vector<double>& aliveProb,\n                            double forgetProb, double moveProb,\n                            const array<array<int, N>, 4>& neighbor,\n                            int targetIdx, int startIdx) {\n    if (startStep <= 0) {\n        startStep = 0;\n        forward[0].fill(0.0);\n        forward[0][startIdx] = 1.0;\n        prefixScore[0] = 0.0;\n        aliveProb[0] = 1.0;\n    }\n    for (int step = startStep; step < MAX_L; ++step) {\n        StepResult sr = apply_transition_raw(forward[step].data(), forward[step + 1].data(),\n                                             seq[step], step, forgetProb, moveProb,\n                                             neighbor, targetIdx);\n        prefixScore[step + 1] = prefixScore[step] + sr.score;\n        double alive = aliveProb[step] - sr.reachProb;\n        if (alive < 0.0) alive = 0.0;\n        aliveProb[step + 1] = alive;\n    }\n}\n\nvoid recompute_backward_up_to(int uptoStep,\n                              const vector<int>& seq,\n                              vector<array<double, N>>& value,\n                              double forgetProb, double moveProb,\n                              const array<array<int, N>, 4>& neighbor,\n                              int targetIdx) {\n    if (uptoStep >= MAX_L - 1) uptoStep = MAX_L - 1;\n    for (int step = uptoStep; step >= 0; --step) {\n        auto& cur = value[step];\n        auto& nxt = value[step + 1];\n        int dir = seq[step];\n        double rewardFactor = 401.0 - (step + 1);\n        for (int idx = 0; idx < N; ++idx) {\n            double val = forgetProb * nxt[idx];\n            int nextIdx = neighbor[dir][idx];\n            if (nextIdx == idx) {\n                val += moveProb * nxt[idx];\n            } else if (nextIdx == targetIdx) {\n                val += moveProb * rewardFactor;\n            } else {\n                val += moveProb * nxt[nextIdx];\n            }\n            cur[idx] = val;\n        }\n        cur[targetIdx] = 0.0;\n    }\n}\n\nstruct SegmentParam {\n    double weight;\n    double noise;\n    int width;\n    double futureCoeff;\n};\n\nstruct SegmentResult {\n    bool success;\n    vector<int> path;\n    double totalContribution;\n};\n\nSegmentResult run_segment_beam(const array<double, N>& distPre,\n                               const array<double, N>& suffixValue,\n                               int len, int stepOffset,\n                               const array<array<int, N>, 4>& neighbor,\n                               double forgetProb, double moveProb,\n                               const vector<double>& distTarget,\n                               const SegmentParam& param,\n                               mt19937& rng,\n                               int targetIdx) {\n    SegmentResult result{false, {}, -1e300};\n    if (len <= 0 || len > MAX_SEG_LEN) return result;\n    struct Node {\n        array<double, N> dist;\n        double score;\n        double heuristic;\n        array<uint8_t, MAX_SEG_LEN> path;\n        int len;\n    };\n    vector<Node> beam;\n    vector<Node> next;\n    beam.reserve(param.width);\n    next.reserve(param.width * 4);\n    Node init;\n    init.dist = distPre;\n    init.score = 0.0;\n    init.len = 0;\n    init.heuristic = dot_product_raw(distPre.data(), suffixValue.data());\n    init.path.fill(0);\n    beam.push_back(init);\n\n    uniform_real_distribution<double> noiseDist(-param.noise, param.noise);\n    auto cmp = [](const Node& a, const Node& b) {\n        return a.heuristic > b.heuristic;\n    };\n\n    for (int step = 0; step < len; ++step) {\n        next.clear();\n        for (const Node& cand : beam) {\n            for (int dir = 0; dir < 4; ++dir) {\n                Node child;\n                child.path = cand.path;\n                child.path[cand.len] = static_cast<uint8_t>(dir);\n                child.len = cand.len + 1;\n                StepResult sr = apply_transition_raw(cand.dist.data(), child.dist.data(),\n                                                     dir, stepOffset + step,\n                                                     forgetProb, moveProb,\n                                                     neighbor, targetIdx);\n                child.score = cand.score + sr.score;\n                double expDist = expected_distance_raw(child.dist.data(), distTarget.data());\n                double futureEst = dot_product_raw(child.dist.data(), suffixValue.data());\n                double noise = (param.noise > 0) ? noiseDist(rng) : 0.0;\n                child.heuristic = child.score + param.futureCoeff * futureEst\n                                - param.weight * expDist + noise;\n                next.push_back(std::move(child));\n            }\n        }\n        if (next.empty()) return result;\n        int width = min(param.width, static_cast<int>(next.size()));\n        partial_sort(next.begin(), next.begin() + width, next.end(), cmp);\n        next.resize(width);\n        beam.swap(next);\n    }\n\n    double bestTotal = -1e300;\n    int bestIdx = 0;\n    for (int i = 0; i < (int)beam.size(); ++i) {\n        double total = beam[i].score + dot_product_raw(beam[i].dist.data(), suffixValue.data());\n        if (total > bestTotal) {\n            bestTotal = total;\n            bestIdx = i;\n        }\n    }\n    result.success = true;\n    result.totalContribution = bestTotal;\n    result.path.resize(len);\n    for (int i = 0; i < len; ++i) result.path[i] = beam[bestIdx].path[i];\n    return result;\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    cin >> si >> sj >> ti >> tj >> p;\n    vector<string> h(H), v(H - 1);\n    for (int i = 0; i < H; ++i) cin >> h[i];\n    for (int i = 0; i < H - 1; ++i) cin >> v[i];\n\n    array<array<int, N>, 4> neighbor;\n    auto idx = [&](int r, int c) { return r * W + c; };\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int id = idx(i, j);\n            neighbor[0][id] = (i > 0 && v[i - 1][j] == '0') ? idx(i - 1, j) : id;\n            neighbor[1][id] = (i < H - 1 && v[i][j] == '0') ? idx(i + 1, j) : id;\n            neighbor[2][id] = (j > 0 && h[i][j - 1] == '0') ? idx(i, j - 1) : id;\n            neighbor[3][id] = (j < W - 1 && h[i][j] == '0') ? idx(i, j + 1) : id;\n        }\n    }\n\n    int startIdx = idx(si, sj);\n    int targetIdx = idx(ti, tj);\n\n    vector<int> distInt = compute_distances(neighbor, targetIdx);\n    vector<double> distTarget(N);\n    for (int i = 0; i < N; ++i) distTarget[i] = (distInt[i] >= 1e8) ? 100.0 : (double)distInt[i];\n\n    mt19937 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n\n    vector<vector<int>> candidates;\n    candidates.push_back(build_bfs_candidate(startIdx, targetIdx, neighbor));\n\n    vector<BeamParam> beamParams;\n    double factor = 0.6 + 0.8 * p;\n    beamParams.push_back({0.8 * factor, 3e-4, 10});\n    beamParams.push_back({1.1 * factor, 2e-4, 12});\n    beamParams.push_back({1.5 * factor, 1e-4, 14});\n    beamParams.push_back({2.1 * factor, 5e-5, 16});\n    beamParams.push_back({2.9 * factor, 2e-5, 18});\n    beamParams.push_back({3.6 * factor, 1e-5, 20});\n\n    double beamTimeLimit = min(0.65, TIME_LIMIT * 0.45);\n    size_t paramIdx = 0;\n    while (elapsed() < beamTimeLimit && paramIdx < beamParams.size()) {\n        BeamResult res = run_beam(beamParams[paramIdx], neighbor, distTarget,\n                                  startIdx, targetIdx, p, rng);\n        candidates.push_back(std::move(res.seq));\n        ++paramIdx;\n    }\n\n    Evaluator evaluator(neighbor, startIdx, targetIdx, p);\n    double bestScore = -1.0;\n    vector<int> bestSeq;\n    for (const auto& seq : candidates) {\n        double sc = evaluator.evaluate(seq);\n        if (sc > bestScore + IMPROVE_EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n    }\n    if (bestSeq.empty()) bestSeq = candidates.front();\n\n    vector<array<double, N>> forward(MAX_L + 1), value(MAX_L + 1);\n    for (auto& arr : forward) arr.fill(0.0);\n    for (auto& arr : value) arr.fill(0.0);\n    vector<double> prefixScore(MAX_L + 1, 0.0);\n    vector<double> aliveProb(MAX_L + 1, 0.0);\n\n    forward[0][startIdx] = 1.0;\n    aliveProb[0] = 1.0;\n    recompute_forward_from(0, bestSeq, forward, prefixScore, aliveProb,\n                           p, 1.0 - p, neighbor, targetIdx, startIdx);\n    value[MAX_L].fill(0.0);\n    recompute_backward_up_to(MAX_L - 1, bestSeq, value,\n                             p, 1.0 - p, neighbor, targetIdx);\n    bestScore = prefixScore[MAX_L];\n\n    double coordLimit = min(1.25, TIME_LIMIT * 0.78);\n    bool improved = true;\n    int cdPass = 0;\n    array<double, N> tempDist;\n    while (improved && elapsed() < coordLimit && cdPass < 3) {\n        ++cdPass;\n        improved = false;\n        for (int step = 0; step < MAX_L && elapsed() < coordLimit; ++step) {\n            if (aliveProb[step] < 1e-9) continue;\n            auto& distIn = forward[step];\n            auto& suffixVal = value[step + 1];\n            double bestVal = -1e300;\n            double currentVal = -1e300;\n            int bestDir = bestSeq[step];\n            for (int dir = 0; dir < 4; ++dir) {\n                StepResult sr = apply_transition_raw(distIn.data(), tempDist.data(),\n                                                     dir, step, p, 1.0 - p,\n                                                     neighbor, targetIdx);\n                double candVal = sr.score + dot_product_raw(tempDist.data(), suffixVal.data());\n                if (dir == bestSeq[step]) currentVal = candVal;\n                if (candVal > bestVal) {\n                    bestVal = candVal;\n                    bestDir = dir;\n                }\n            }\n            if (bestVal > currentVal + IMPROVE_EPS && bestDir != bestSeq[step]) {\n                bestSeq[step] = bestDir;\n                recompute_forward_from(step, bestSeq, forward, prefixScore, aliveProb,\n                                       p, 1.0 - p, neighbor, targetIdx, startIdx);\n                recompute_backward_up_to(step, bestSeq, value,\n                                         p, 1.0 - p, neighbor, targetIdx);\n                bestScore = prefixScore[MAX_L];\n                improved = true;\n            }\n        }\n    }\n\n    SegmentParam segParam;\n    segParam.weight = 1.0 + 1.2 * p;\n    segParam.noise = 3e-5;\n    segParam.futureCoeff = 0.6;\n    segParam.width = 18 + (int)(10 * p);\n    vector<int> segLens = {4, 6, 8, 10, 12, 16, 20, 24, 28, 32, 36, 40};\n    uniform_int_distribution<int> lenDist(0, (int)segLens.size() - 1);\n\n    double lnsLimit = TIME_LIMIT * 0.985;\n    while (elapsed() < lnsLimit) {\n        int len = segLens[lenDist(rng)];\n        if (len > MAX_L) continue;\n        int maxStart = MAX_L - len;\n        if (maxStart < 0) continue;\n        int start = (maxStart == 0) ? 0 : uniform_int_distribution<int>(0, maxStart)(rng);\n        if (aliveProb[start] < 1e-8) continue;\n        SegmentResult segRes = run_segment_beam(forward[start], value[start + len],\n                                                len, start, neighbor, p, 1.0 - p,\n                                                distTarget, segParam, rng, targetIdx);\n        if (!segRes.success) continue;\n        double candidateScore = prefixScore[start] + segRes.totalContribution;\n        if (candidateScore > bestScore + IMPROVE_EPS) {\n            for (int i = 0; i < len; ++i) bestSeq[start + i] = segRes.path[i];\n            recompute_forward_from(start, bestSeq, forward, prefixScore, aliveProb,\n                                   p, 1.0 - p, neighbor, targetIdx, startIdx);\n            recompute_backward_up_to(start + len - 1, bestSeq, value,\n                                     p, 1.0 - p, neighbor, targetIdx);\n            bestScore = prefixScore[MAX_L];\n        }\n    }\n\n    string answer(MAX_L, 'U');\n    for (int i = 0; i < MAX_L; ++i) answer[i] = DIR_CHARS[bestSeq[i]];\n    cout << answer << '\\n';\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int H = 30;\nconstexpr int W = 30;\nconstexpr int N = H * W;\nconstexpr int DIR = 4;\nconstexpr int STATE = N * DIR;\n\nconstexpr int di[4] = {0, -1, 0, 1};   // left, up, right, down\nconstexpr int dj[4] = {-1, 0, 1, 0};\n\nconstexpr int TO_TABLE[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\nconstexpr int ROT_NEXT[8] = {1, 2, 3, 0, 5, 4, 7, 6};\n\nstruct EvalResult {\n    long long score;\n    int l1;\n    int l2;\n    int loopCnt;\n};\n\nstruct Evaluator {\n    array<int, STATE> visitedStamp{};\n    array<int, STATE> pathStamp{};\n    array<int, STATE> pathPos{};\n    int visitedToken = 0;\n    int pathToken = 0;\n    vector<int> pathList;\n\n    Evaluator() { pathList.reserve(STATE); }\n\n    EvalResult operator()(const vector<int>& finalType) {\n        ++visitedToken;\n        int token = visitedToken;\n\n        for (int cell = 0; cell < N; ++cell) {\n            int type = finalType[cell];\n            for (int d = 0; d < DIR; ++d) {\n                if (TO_TABLE[type][d] == -1) {\n                    visitedStamp[(cell << 2) | d] = token;\n                }\n            }\n        }\n\n        long long best1 = 0, best2 = 0;\n        int loops = 0;\n\n        for (int cell = 0; cell < N; ++cell) {\n            for (int d = 0; d < DIR; ++d) {\n                int stateIdx = (cell << 2) | d;\n                if (visitedStamp[stateIdx] == token) continue;\n\n                ++pathToken;\n                int pathTok = pathToken;\n                pathList.clear();\n\n                int curCell = cell;\n                int curDir = d;\n                int i = curCell / W;\n                int j = curCell % W;\n                int length = 0;\n\n                while (true) {\n                    int idx = (curCell << 2) | curDir;\n                    if (visitedStamp[idx] == token) break;\n\n                    if (pathStamp[idx] == pathTok) {\n                        int loopLen = length - pathPos[idx];\n                        if (loopLen > 0) {\n                            ++loops;\n                            if (loopLen >= best1) {\n                                best2 = best1;\n                                best1 = loopLen;\n                            } else if (loopLen > best2) {\n                                best2 = loopLen;\n                            }\n                        }\n                        break;\n                    }\n\n                    pathStamp[idx] = pathTok;\n                    pathPos[idx] = length;\n                    pathList.push_back(idx);\n\n                    int type = finalType[curCell];\n                    int nextDir = TO_TABLE[type][curDir];\n                    if (nextDir == -1) break;\n\n                    int ni = i + di[nextDir];\n                    int nj = j + dj[nextDir];\n                    if (ni < 0 || ni >= H || nj < 0 || nj >= W) break;\n\n                    i = ni;\n                    j = nj;\n                    curCell = ni * W + nj;\n                    curDir = (nextDir + 2) & 3;\n                    ++length;\n                }\n\n                for (int idx2 : pathList) {\n                    visitedStamp[idx2] = token;\n                }\n            }\n        }\n\n        long long total = (loops >= 2) ? best1 * best2 : 0LL;\n        return {total, (int)best1, (int)best2, loops};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> base(N);\n    for (int i = 0; i < H; ++i) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < W; ++j) {\n            base[i * W + j] = s[j] - '0';\n        }\n    }\n\n    int ROT_TABLE[8][4];\n    int ROT_INV[8][8];\n    memset(ROT_INV, -1, sizeof(ROT_INV));\n    for (int t = 0; t < 8; ++t) {\n        ROT_TABLE[t][0] = t;\n        for (int r = 1; r < 4; ++r) {\n            ROT_TABLE[t][r] = ROT_NEXT[ROT_TABLE[t][r - 1]];\n        }\n        for (int r = 0; r < 4; ++r) {\n            int type = ROT_TABLE[t][r];\n            if (ROT_INV[t][type] == -1) ROT_INV[t][type] = r;\n        }\n    }\n\n    vector<array<int, 4>> neighbors(N);\n    for (int cell = 0; cell < N; ++cell) {\n        int i = cell / W;\n        int j = cell % W;\n        for (int d = 0; d < DIR; ++d) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= H || nj < 0 || nj >= W) neighbors[cell][d] = -1;\n            else neighbors[cell][d] = ni * W + nj;\n        }\n    }\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    vector<int> rot(N, 0);\n    vector<int> finalType(N);\n\n    const int MATCH_BONUS = 7;\n    const int OPEN_PENALTY = -3;\n    const int BORDER_PENALTY = -6;\n\n    auto startTime = chrono::steady_clock::now();\n    auto nowTime = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n    const double TIME_LIMIT = 1.9;\n\n    // Initial orientation: prefer keeping rails inside the board\n    for (int cell = 0; cell < N; ++cell) {\n        int baseState = base[cell];\n        int bestR = 0;\n        int bestVal = -1e9;\n        array<char, 8> used{};\n        for (int r = 0; r < 4; ++r) {\n            int type = ROT_TABLE[baseState][r];\n            if (used[type]) continue;\n            used[type] = 1;\n            int val = 0;\n            for (int d = 0; d < DIR; ++d) {\n                if (TO_TABLE[type][d] == -1) continue;\n                int nb = neighbors[cell][d];\n                if (nb == -1) val += BORDER_PENALTY;\n                else val += MATCH_BONUS / 2;\n            }\n            if (val > bestVal || (val == bestVal && (rng() & 1))) {\n                bestVal = val;\n                bestR = r;\n            }\n        }\n        rot[cell] = bestR;\n        finalType[cell] = ROT_TABLE[baseState][bestR];\n    }\n\n    vector<int> openEnds(N, 0);\n    vector<int> badPos(N, -1);\n    vector<int> badCells;\n    badCells.reserve(N);\n\n    auto setBadState = [&](int cell, bool bad) {\n        if (bad) {\n            if (badPos[cell] == -1) {\n                badPos[cell] = (int)badCells.size();\n                badCells.push_back(cell);\n            }\n        } else if (badPos[cell] != -1) {\n            int idx = badPos[cell];\n            int last = badCells.back();\n            badCells[idx] = last;\n            badPos[last] = idx;\n            badCells.pop_back();\n            badPos[cell] = -1;\n        }\n    };\n\n    struct LocalResult {\n        int score;\n        int open;\n    };\n\n    auto localEval = [&](int cell, int type) -> LocalResult {\n        LocalResult res{0, 0};\n        const auto& nbList = neighbors[cell];\n        for (int d = 0; d < DIR; ++d) {\n            if (TO_TABLE[type][d] == -1) continue;\n            int nb = nbList[d];\n            if (nb == -1) {\n                res.score += BORDER_PENALTY;\n                res.open += 1;\n            } else {\n                int nbType = finalType[nb];\n                if (TO_TABLE[nbType][(d + 2) & 3] != -1) {\n                    res.score += MATCH_BONUS;\n                } else {\n                    res.score += OPEN_PENALTY;\n                    res.open += 1;\n                }\n            }\n        }\n        return res;\n    };\n\n    auto updateOne = [&](int cell) {\n        if (cell < 0) return;\n        LocalResult res = localEval(cell, finalType[cell]);\n        openEnds[cell] = res.open;\n        setBadState(cell, res.open > 0);\n    };\n\n    auto updateAround = [&](int cell) {\n        updateOne(cell);\n        for (int d = 0; d < DIR; ++d) {\n            int nb = neighbors[cell][d];\n            if (nb != -1) updateOne(nb);\n        }\n    };\n\n    auto recomputeAll = [&]() {\n        badCells.clear();\n        fill(badPos.begin(), badPos.end(), -1);\n        for (int cell = 0; cell < N; ++cell) updateOne(cell);\n    };\n\n    recomputeAll();\n\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    double greedyLimit = min(0.45, TIME_LIMIT * 0.35);\n\n    while (nowTime() < greedyLimit) {\n        bool improved = false;\n        shuffle(order.begin(), order.end(), rng);\n        for (int cell : order) {\n            if (nowTime() > greedyLimit) break;\n            int baseState = base[cell];\n            int curType = finalType[cell];\n            LocalResult curRes = localEval(cell, curType);\n            pair<int, int> bestMetric = {curRes.score, -curRes.open};\n            int bestType = curType;\n            int bestRot = rot[cell];\n\n            array<char, 8> used{};\n            for (int r = 0; r < 4; ++r) {\n                int candType = ROT_TABLE[baseState][r];\n                if (used[candType]) continue;\n                used[candType] = 1;\n                LocalResult candRes = localEval(cell, candType);\n                pair<int, int> candMetric = {candRes.score, -candRes.open};\n                if (candMetric > bestMetric ||\n                    (candMetric == bestMetric && (rng() & 1))) {\n                    bestMetric = candMetric;\n                    bestType = candType;\n                    bestRot = r;\n                }\n            }\n\n            if (bestType != curType) {\n                finalType[cell] = bestType;\n                rot[cell] = bestRot;\n                improved = true;\n                updateAround(cell);\n            }\n        }\n        if (!improved) break;\n    }\n\n    recomputeAll();\n\n    Evaluator evaluator;\n    EvalResult curEval = evaluator(finalType);\n    long long currentScore = curEval.score;\n    long long bestScore = currentScore;\n    vector<int> bestRot = rot;\n    vector<int> bestType = finalType;\n\n    double saStart = nowTime();\n    double saEnd = min(TIME_LIMIT - 0.05, TIME_LIMIT * 0.98);\n    if (saEnd < saStart + 1e-3) saEnd = min(TIME_LIMIT - 1e-3, saStart + 1e-3);\n    double span = max(1e-9, saEnd - saStart);\n\n    const double T0 = 4.0;\n    const double T1 = 0.05;\n\n    while (nowTime() < saEnd) {\n        double progress = (nowTime() - saStart) / span;\n        if (progress < 0) progress = 0;\n        if (progress > 1) progress = 1;\n        double temp = T0 + (T1 - T0) * progress;\n\n        int cell;\n        if (!badCells.empty() && dist01(rng) < 0.85) {\n            cell = badCells[rng() % badCells.size()];\n        } else {\n            cell = rng() % N;\n        }\n\n        int baseState = base[cell];\n        int oldRot = rot[cell];\n        int oldType = finalType[cell];\n\n        int newRot = oldRot;\n        int newType = oldType;\n        bool changed = false;\n        for (int tries = 0; tries < 4; ++tries) {\n            int diff = rng() % 3 + 1;\n            int candRot = (oldRot + diff) & 3;\n            int candType = ROT_TABLE[baseState][candRot];\n            if (candType != oldType) {\n                newRot = candRot;\n                newType = candType;\n                changed = true;\n                break;\n            }\n        }\n        if (!changed) {\n            for (int r = 0; r < 4; ++r) {\n                int candType = ROT_TABLE[baseState][r];\n                if (candType != oldType) {\n                    newRot = r;\n                    newType = candType;\n                    changed = true;\n                    break;\n                }\n            }\n        }\n        if (!changed) continue;\n\n        finalType[cell] = newType;\n        rot[cell] = newRot;\n\n        EvalResult newEval = evaluator(finalType);\n        long long delta = newEval.score - currentScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else if (exp(delta / temp) > dist01(rng)) accept = true;\n\n        if (accept) {\n            currentScore = newEval.score;\n            updateAround(cell);\n            if (newEval.score > bestScore) {\n                bestScore = newEval.score;\n                bestRot = rot;\n                bestType = finalType;\n            }\n        } else {\n            finalType[cell] = oldType;\n            rot[cell] = oldRot;\n        }\n    }\n\n    rot = bestRot;\n    finalType = bestType;\n\n    string answer;\n    answer.reserve(N);\n    for (int idx = 0; idx < N; ++idx) {\n        answer.push_back(char('0' + rot[idx]));\n    }\n    cout << answer << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAX_N = 10;\nconst int MAX_CELLS = MAX_N * MAX_N;\n\nint N, T;\nint total_cells, total_tiles;\n\nuint64_t zobrist[MAX_CELLS][16];\nuint8_t visited_buf[MAX_CELLS];\nint queue_buf[MAX_CELLS];\n\nconst int CONN_DX[4] = {0, -1, 0, 1};     // left, up, right, down\nconst int CONN_DY[4] = {-1, 0, 1, 0};\nconst int CONN_BIT[4] = {1, 2, 4, 8};\nconst int CONN_OPP[4] = {2, 3, 0, 1};\n\nconst int BLANK_DX[4] = {-1, 1, 0, 0};    // U, D, L, R (blank movement)\nconst int BLANK_DY[4] = {0, 0, -1, 1};\nconst char MOVE_CHAR[4] = {'U', 'D', 'L', 'R'};\n\nstruct EvalResult {\n    int matched_edges;\n    int largest_tree;\n    int largest_component;\n};\n\ninline bool evalBetter(const EvalResult& a, const EvalResult& b) {\n    if (a.largest_tree != b.largest_tree) return a.largest_tree > b.largest_tree;\n    if (a.largest_component != b.largest_component) return a.largest_component > b.largest_component;\n    if (a.matched_edges != b.matched_edges) return a.matched_edges > b.matched_edges;\n    return false;\n}\n\ninline bool evalEqual(const EvalResult& a, const EvalResult& b) {\n    return a.largest_tree == b.largest_tree &&\n           a.largest_component == b.largest_component &&\n           a.matched_edges == b.matched_edges;\n}\n\nEvalResult evaluateBoard(const uint8_t* board) {\n    EvalResult res{0, 0, 0};\n    for (int i = 0; i < N; ++i) {\n        int base = i * N;\n        for (int j = 0; j < N; ++j) {\n            int idx = base + j;\n            uint8_t val = board[idx];\n            if (!val) continue;\n            if (j + 1 < N) {\n                uint8_t nb = board[idx + 1];\n                if (nb && (val & 4) && (nb & 1)) res.matched_edges++;\n            }\n            if (i + 1 < N) {\n                uint8_t nb = board[idx + N];\n                if (nb && (val & 8) && (nb & 2)) res.matched_edges++;\n            }\n        }\n    }\n    fill(visited_buf, visited_buf + total_cells, 0);\n    for (int idx = 0; idx < total_cells; ++idx) {\n        uint8_t val = board[idx];\n        if (!val || visited_buf[idx]) continue;\n        int head = 0, tail = 0;\n        queue_buf[tail++] = idx;\n        visited_buf[idx] = 1;\n        int nodes = 0;\n        int edges = 0;\n        while (head < tail) {\n            int cur = queue_buf[head++];\n            nodes++;\n            int cx = cur / N;\n            int cy = cur % N;\n            uint8_t curv = board[cur];\n            for (int d = 0; d < 4; ++d) {\n                if (!(curv & CONN_BIT[d])) continue;\n                int nx = cx + CONN_DX[d];\n                int ny = cy + CONN_DY[d];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                int nidx = nx * N + ny;\n                uint8_t nval = board[nidx];\n                if (!nval) continue;\n                if (!(nval & CONN_BIT[CONN_OPP[d]])) continue;\n                if (cur < nidx) edges++;\n                if (!visited_buf[nidx]) {\n                    visited_buf[nidx] = 1;\n                    queue_buf[tail++] = nidx;\n                }\n            }\n        }\n        res.largest_component = max(res.largest_component, nodes);\n        if (edges == nodes - 1) res.largest_tree = max(res.largest_tree, nodes);\n    }\n    return res;\n}\n\nuint64_t computeHash(const array<uint8_t, MAX_CELLS>& board) {\n    uint64_t h = 0;\n    for (int i = 0; i < total_cells; ++i) {\n        h ^= zobrist[i][board[i]];\n    }\n    return h;\n}\n\nstruct NodeInfo {\n    int parent;\n    char move;\n};\n\nstruct SearchState {\n    array<uint8_t, MAX_CELLS> tiles;\n    uint16_t blank = 0;\n    uint64_t hash = 0;\n    EvalResult eval{};\n    uint16_t depth = 0;\n    int node_id = 0;\n    uint32_t rand_key = 0;\n};\n\nstruct AttemptResult {\n    EvalResult eval;\n    int depth;\n    string sequence;\n};\n\nAttemptResult runAttempt(const array<uint8_t, MAX_CELLS>& initial_tiles,\n                         int blank_pos,\n                         int beam_width,\n                         double time_limit,\n                         const chrono::steady_clock::time_point& start_time,\n                         mt19937& rng) {\n    vector<NodeInfo> nodes;\n    nodes.reserve(1 + beam_width * T * 4);\n    nodes.push_back({-1, '?'});\n\n    unordered_map<uint64_t, uint16_t> visited;\n    visited.reserve(static_cast<size_t>(beam_width) * T * 2 + 10);\n\n    vector<SearchState> beam;\n    vector<SearchState> candidates;\n    beam.reserve(beam_width);\n    candidates.reserve(beam_width * 4 + 10);\n\n    SearchState init;\n    init.tiles = initial_tiles;\n    init.blank = blank_pos;\n    init.hash = computeHash(initial_tiles);\n    init.eval = evaluateBoard(init.tiles.data());\n    init.depth = 0;\n    init.node_id = 0;\n    init.rand_key = rng();\n    beam.push_back(init);\n    visited.emplace(init.hash, init.depth);\n\n    EvalResult best_eval = init.eval;\n    int best_depth = 0;\n    int best_node = 0;\n\n    if (best_eval.largest_tree == total_tiles) {\n        return {best_eval, best_depth, \"\"};\n    }\n\n    auto stateComparator = [](const SearchState& a, const SearchState& b) {\n        if (evalBetter(a.eval, b.eval)) return true;\n        if (evalBetter(b.eval, a.eval)) return false;\n        if (a.depth != b.depth) return a.depth < b.depth;\n        return a.rand_key < b.rand_key;\n    };\n\n    int current_depth = 0;\n    bool terminate = false;\n\n    while (!beam.empty() && current_depth < T && !terminate) {\n        if ((current_depth & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n            if (elapsed > time_limit) break;\n        }\n        candidates.clear();\n        for (size_t si = 0; si < beam.size() && !terminate; ++si) {\n            if ((si & 3) == 0) {\n                double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n                if (elapsed > time_limit) {\n                    terminate = true;\n                    break;\n                }\n            }\n            const SearchState& state = beam[si];\n            int blank = state.blank;\n            int bx = blank / N;\n            int by = blank % N;\n            int dir_order[4] = {0, 1, 2, 3};\n            for (int i = 3; i > 0; --i) {\n                int j = rng() % (i + 1);\n                swap(dir_order[i], dir_order[j]);\n            }\n            for (int k = 0; k < 4; ++k) {\n                int dir = dir_order[k];\n                int nx = bx + BLANK_DX[dir];\n                int ny = by + BLANK_DY[dir];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                int nidx = nx * N + ny;\n                if (state.tiles[nidx] == 0) continue;\n                SearchState child = state;\n                uint8_t tile_to_move = state.tiles[nidx];\n                child.tiles[blank] = tile_to_move;\n                child.tiles[nidx] = 0;\n                child.blank = nidx;\n                child.depth = state.depth + 1;\n                if (child.depth > T) continue;\n                child.hash ^= zobrist[blank][0];\n                child.hash ^= zobrist[nidx][tile_to_move];\n                child.hash ^= zobrist[blank][tile_to_move];\n                child.hash ^= zobrist[nidx][0];\n                auto it = visited.find(child.hash);\n                if (it != visited.end()) {\n                    if (child.depth >= it->second) continue;\n                    it->second = child.depth;\n                } else {\n                    visited.emplace(child.hash, child.depth);\n                }\n                child.node_id = static_cast<int>(nodes.size());\n                nodes.push_back({state.node_id, MOVE_CHAR[dir]});\n                child.eval = evaluateBoard(child.tiles.data());\n                child.rand_key = rng();\n                if (evalBetter(child.eval, best_eval) ||\n                    (evalEqual(child.eval, best_eval) && child.depth < best_depth)) {\n                    best_eval = child.eval;\n                    best_depth = child.depth;\n                    best_node = child.node_id;\n                    if (best_eval.largest_tree == total_tiles) {\n                        terminate = true;\n                        candidates.emplace_back(std::move(child));\n                        break;\n                    }\n                }\n                candidates.emplace_back(std::move(child));\n            }\n        }\n        if (terminate || candidates.empty()) break;\n        sort(candidates.begin(), candidates.end(), stateComparator);\n        if (static_cast<int>(candidates.size()) > beam_width) {\n            candidates.resize(beam_width);\n        }\n        beam.swap(candidates);\n        current_depth++;\n    }\n\n    string seq;\n    seq.reserve(best_depth);\n    int node = best_node;\n    while (node != 0) {\n        seq.push_back(nodes[node].move);\n        node = nodes[node].parent;\n    }\n    reverse(seq.begin(), seq.end());\n    return {best_eval, best_depth, seq};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T;\n    total_cells = N * N;\n    total_tiles = total_cells - 1;\n\n    array<uint8_t, MAX_CELLS> initial_tiles{};\n    int blank_pos = -1;\n    for (int i = 0; i < N; ++i) {\n        string row;\n        cin >> row;\n        for (int j = 0; j < N; ++j) {\n            char c = row[j];\n            int val = (c <= '9') ? c - '0' : 10 + (c - 'a');\n            int idx = i * N + j;\n            initial_tiles[idx] = static_cast<uint8_t>(val);\n            if (val == 0) blank_pos = idx;\n        }\n    }\n\n    mt19937_64 rng64(chrono::steady_clock::now().time_since_epoch().count());\n    for (int i = 0; i < MAX_CELLS; ++i) {\n        for (int v = 0; v < 16; ++v) {\n            uint64_t x = rng64();\n            if (x == 0) x = 1;\n            zobrist[i][v] = x;\n        }\n    }\n    mt19937 rng(static_cast<uint32_t>(rng64()));\n\n    EvalResult initial_eval = evaluateBoard(initial_tiles.data());\n    string best_sequence = \"\";\n    EvalResult global_best_eval = initial_eval;\n    int global_best_depth = 0;\n\n    const double TIME_LIMIT = 2.80;\n    auto start_time = chrono::steady_clock::now();\n\n    int base_width = 80 - 4 * N;\n    base_width = max(12, min(base_width, 80));\n\n    int attempt = 0;\n    while (true) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n        if (elapsed > TIME_LIMIT) break;\n        int width = base_width;\n        int mod = attempt % 3;\n        if (mod == 1) width += 6;\n        else if (mod == 2) width -= 6;\n        width = max(8, min(width, 90));\n        AttemptResult res = runAttempt(initial_tiles, blank_pos, width, TIME_LIMIT, start_time, rng);\n        if (evalBetter(res.eval, global_best_eval) ||\n            (evalEqual(res.eval, global_best_eval) && res.depth < global_best_depth)) {\n            global_best_eval = res.eval;\n            global_best_depth = res.depth;\n            best_sequence = std::move(res.sequence);\n        }\n        attempt++;\n    }\n\n    cout << best_sequence << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int x, y;\n};\nstruct Line {\n    long long A, B, C;\n};\nstruct Key {\n    unsigned long long lo, hi;\n};\nusing CountArr = array<int, 11>;\n\nconst long long COORD_LIMIT = 1'000'000'000LL;\nconst double TIME_LIMIT = 2.8;\nconst int DIR_LIMIT = 1000;\nconst int GENERATE_LINE_ATTEMPTS = 80;\nconst int DIR_SAMPLE_PER_ATTEMPT = 12;\n\nint N, K;\narray<int, 11> demand{};\nvector<Point> points;\n\nvector<unsigned long long> pattern_lo, pattern_hi;\nvector<Key> tmp_keys;\nvector<int> order_idx;\nvector<long long> proj_values;\nvector<int> gap_indices;\nvector<Line> lines_current;\n\nint bits_used = 0;\n\nmt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\nchrono::steady_clock::time_point start_time;\nbool time_up = false;\n\ninline long long absll(long long x) { return x >= 0 ? x : -x; }\n\nlong long floor_div(long long a, long long b) {\n    assert(b != 0);\n    if (b < 0) { a = -a; b = -b; }\n    if (a >= 0) return a / b;\n    return -(( -a + b - 1 ) / b);\n}\nlong long ceil_div(long long a, long long b) {\n    assert(b != 0);\n    if (b < 0) { a = -a; b = -b; }\n    if (a >= 0) return (a + b - 1) / b;\n    return -((-a) / b);\n}\n\nlong long ext_gcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) {\n        x = (a >= 0) ? 1 : -1;\n        y = 0;\n        return absll(a);\n    }\n    long long x1, y1;\n    long long g = ext_gcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\ninline bool check_time() {\n    if (time_up) return true;\n    double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    if (elapsed > TIME_LIMIT) time_up = true;\n    return time_up;\n}\n\nvoid reset_state() {\n    fill(pattern_lo.begin(), pattern_lo.end(), 0ULL);\n    fill(pattern_hi.begin(), pattern_hi.end(), 0ULL);\n    lines_current.clear();\n    lines_current.reserve(K);\n    bits_used = 0;\n}\n\nint score_from_counts(const CountArr &cnt) {\n    int sc = 0;\n    for (int d = 1; d <= 10; ++d) sc += min(demand[d], cnt[d]);\n    return sc;\n}\n\nint recompute_current(CountArr &out_cnt) {\n    out_cnt.fill(0);\n    for (int i = 0; i < N; ++i) {\n        tmp_keys[i] = {pattern_lo[i], pattern_hi[i]};\n        order_idx[i] = i;\n    }\n    auto cmp = [&](int lhs, int rhs) {\n        const Key &a = tmp_keys[lhs];\n        const Key &b = tmp_keys[rhs];\n        if (a.hi != b.hi) return a.hi < b.hi;\n        return a.lo < b.lo;\n    };\n    sort(order_idx.begin(), order_idx.end(), cmp);\n    int idx = 0;\n    while (idx < N) {\n        int j = idx + 1;\n        while (j < N) {\n            const Key &ka = tmp_keys[order_idx[idx]];\n            const Key &kb = tmp_keys[order_idx[j]];\n            if (ka.lo != kb.lo || ka.hi != kb.hi) break;\n            ++j;\n        }\n        int cnt = j - idx;\n        if (cnt <= 10) out_cnt[cnt]++;\n        idx = j;\n    }\n    return score_from_counts(out_cnt);\n}\n\nint evaluate_candidate(const Line &line) {\n    if (bits_used >= 128) return -1;\n    for (int i = 0; i < N; ++i) {\n        long long val = line.A * points[i].x + line.B * points[i].y - line.C;\n        if (val == 0) return -1;\n        unsigned long long bit = (val > 0) ? 1ULL : 0ULL;\n        unsigned long long lo = pattern_lo[i];\n        unsigned long long hi = pattern_hi[i];\n        if (bits_used < 64) lo |= bit << bits_used;\n        else hi |= bit << (bits_used - 64);\n        tmp_keys[i] = {lo, hi};\n        order_idx[i] = i;\n    }\n    auto cmp = [&](int lhs, int rhs) {\n        const Key &a = tmp_keys[lhs];\n        const Key &b = tmp_keys[rhs];\n        if (a.hi != b.hi) return a.hi < b.hi;\n        return a.lo < b.lo;\n    };\n    sort(order_idx.begin(), order_idx.end(), cmp);\n    CountArr cnt;\n    cnt.fill(0);\n    int idx = 0;\n    while (idx < N) {\n        int j = idx + 1;\n        while (j < N) {\n            const Key &ka = tmp_keys[order_idx[idx]];\n            const Key &kb = tmp_keys[order_idx[j]];\n            if (ka.lo != kb.lo || ka.hi != kb.hi) break;\n            ++j;\n        }\n        int c = j - idx;\n        if (c <= 10) cnt[c]++;\n        idx = j;\n    }\n    return score_from_counts(cnt);\n}\n\ninline long long rand_ll(long long l, long long r) {\n    unsigned long long range = (unsigned long long)(r - l + 1);\n    return l + (long long)(rng() % range);\n}\n\nint pick_gap_index(const vector<int> &gaps) {\n    int sz = (int)gaps.size();\n    int type = (int)(rng() % 4);\n    if (type == 0) return gaps[(int)(rng() % sz)];\n    if (type == 1) {\n        int limit = min(sz, 15);\n        return gaps[(int)(rng() % limit)];\n    }\n    if (type == 2) {\n        int limit = min(sz, 15);\n        return gaps[sz - 1 - (int)(rng() % limit)];\n    }\n    int width = min(sz, 25);\n    int center = sz / 2;\n    int offset = (int)(rng() % max(1, width));\n    int idx = center + offset - width / 2;\n    idx = max(0, min(sz - 1, idx));\n    return gaps[idx];\n}\n\nbool sample_direction_line(Line &line) {\n    static const pair<int,int> preset[4] = {{1,0},{0,1},{1,1},{1,-1}};\n    for (int iter = 0; iter < DIR_SAMPLE_PER_ATTEMPT; ++iter) {\n        long long a = 0, b = 0;\n        int mode = rng() % 6;\n        if (mode < 4) {\n            a = preset[mode].first;\n            b = preset[mode].second;\n        } else {\n            do {\n                a = rand_ll(-DIR_LIMIT, DIR_LIMIT);\n                b = rand_ll(-DIR_LIMIT, DIR_LIMIT);\n            } while (a == 0 && b == 0);\n        }\n        long long g = std::gcd(absll(a), absll(b));\n        if (g == 0) continue;\n        a /= g; b /= g;\n        if (a < 0 || (a == 0 && b < 0)) { a = -a; b = -b; }\n        for (int i = 0; i < N; ++i) {\n            proj_values[i] = a * points[i].x + b * points[i].y;\n        }\n        sort(proj_values.begin(), proj_values.end());\n        gap_indices.clear();\n        for (int i = 1; i < N; ++i) {\n            if (proj_values[i] - proj_values[i - 1] >= 2) gap_indices.push_back(i);\n        }\n        if (gap_indices.empty()) continue;\n        int pos = pick_gap_index(gap_indices);\n        long long left = proj_values[pos - 1];\n        long long right = proj_values[pos];\n        long long c = rand_ll(left + 1, right - 1);\n        line = {a, b, c};\n        return true;\n    }\n    return false;\n}\n\nbool sample_pair_line(Line &line) {\n    if (N < 2) return false;\n    int i = rng() % N;\n    int j = rng() % N;\n    if (i == j) return false;\n    long long dx = points[j].x - points[i].x;\n    long long dy = points[j].y - points[i].y;\n    long long g = std::gcd(absll(dx), absll(dy));\n    if (g == 0) return false;\n    long long a = dx / g;\n    long long b = dy / g;\n    if (a < 0 || (a == 0 && b < 0)) { a = -a; b = -b; }\n    long long vi = a * points[i].x + b * points[i].y;\n    long long vj = a * points[j].x + b * points[j].y;\n    if (vi == vj) return false;\n    long long lo = min(vi, vj);\n    long long hi = max(vi, vj);\n    if (hi - lo < 2) return false;\n    long long c = rand_ll(lo + 1, hi - 1);\n    line = {a, b, c};\n    return true;\n}\n\nbool generate_candidate_line(Line &line) {\n    for (int attempt = 0; attempt < GENERATE_LINE_ATTEMPTS; ++attempt) {\n        bool use_pair = (N >= 2) && (rng() % 6 == 0);\n        bool ok = use_pair ? sample_pair_line(line) : sample_direction_line(line);\n        if (!ok) continue;\n        return true;\n    }\n    return false;\n}\n\nvoid apply_line(const Line &line) {\n    for (int i = 0; i < N; ++i) {\n        long long val = line.A * points[i].x + line.B * points[i].y - line.C;\n        if (val == 0) val = 1;\n        unsigned long long bit = (val > 0) ? 1ULL : 0ULL;\n        if (bits_used < 64) pattern_lo[i] |= bit << bits_used;\n        else pattern_hi[i] |= bit << (bits_used - 64);\n    }\n    lines_current.push_back(line);\n    ++bits_used;\n}\n\nint candidate_trials(int iter) {\n    if (iter < 10) return 45;\n    if (iter < 25) return 35;\n    if (iter < 50) return 28;\n    if (iter < 80) return 22;\n    return 18;\n}\n\nstruct AttemptResult {\n    int score;\n    vector<Line> lines;\n};\n\nAttemptResult run_attempt(const vector<Line> &base_lines) {\n    reset_state();\n    CountArr current_counts;\n    for (const auto &ln : base_lines) {\n        if (check_time()) break;\n        if ((int)lines_current.size() >= K) break;\n        apply_line(ln);\n    }\n    int current_score = recompute_current(current_counts);\n    int best_score_local = current_score;\n    vector<Line> best_lines_local = lines_current;\n\n    while ((int)lines_current.size() < K && !check_time()) {\n        int trials = candidate_trials((int)lines_current.size());\n        Line chosen{};\n        int chosen_score = INT_MIN;\n        bool found = false;\n        for (int t = 0; t < trials && !check_time(); ++t) {\n            Line cand;\n            if (!generate_candidate_line(cand)) continue;\n            int sc = evaluate_candidate(cand);\n            if (sc < 0) continue;\n            if (!found || sc > chosen_score) {\n                found = true;\n                chosen_score = sc;\n                chosen = cand;\n            }\n        }\n        if (!found) break;\n        apply_line(chosen);\n        current_score = recompute_current(current_counts);\n        if (current_score > best_score_local) {\n            best_score_local = current_score;\n            best_lines_local = lines_current;\n        }\n    }\n    return {best_score_local, best_lines_local};\n}\n\nbool line_to_points(const Line &line, array<long long,4> &out) {\n    long long A = line.A, B = line.B, C = line.C;\n    if (A == 0 && B == 0) return false;\n    if (B == 0) {\n        long long x = C / A;\n        long long y1 = -COORD_LIMIT + 1;\n        long long y2 = y1 + 1;\n        out = {x, y1, x, y2};\n        return true;\n    }\n    if (A == 0) {\n        long long y = C / B;\n        long long x1 = -COORD_LIMIT + 1;\n        long long x2 = x1 + 1;\n        out = {x1, y, x2, y};\n        return true;\n    }\n    long long x0, y0;\n    long long g = ext_gcd(A, B, x0, y0);\n    if (g == 0 || C % g != 0) return false;\n    long long mult = C / g;\n    x0 *= mult;\n    y0 *= mult;\n    auto range_for = [&](long long base, long long coeff) -> pair<long long,long long> {\n        const long long INF = (1LL << 60);\n        if (coeff == 0) {\n            if (absll(base) > COORD_LIMIT) return {1, 0};\n            return {-INF, INF};\n        }\n        long long low = -INF, high = INF;\n        if (coeff > 0) {\n            low = max(low, ceil_div(-COORD_LIMIT - base, coeff));\n            high = min(high, floor_div(COORD_LIMIT - base, coeff));\n        } else {\n            high = min(high, floor_div(-COORD_LIMIT - base, coeff));\n            low = max(low, ceil_div(COORD_LIMIT - base, coeff));\n        }\n        return {low, high};\n    };\n    auto rx = range_for(x0, B);\n    auto ry = range_for(y0, -A);\n    long long low = max(rx.first, ry.first);\n    long long high = min(rx.second, ry.second);\n    if (low > high) return false;\n    auto point_from = [&](long long k) -> pair<long long,long long> {\n        return {x0 + B * k, y0 - A * k};\n    };\n    long long k0 = min(max(0LL, low), high);\n    auto P = point_from(k0);\n    if (absll(P.first) > COORD_LIMIT || absll(P.second) > COORD_LIMIT) {\n        P = point_from(low);\n        k0 = low;\n    }\n    long long qk = (k0 < high) ? k0 + 1 : k0 - 1;\n    auto Q = point_from(qk);\n    if (absll(Q.first) > COORD_LIMIT || absll(Q.second) > COORD_LIMIT || (Q.first == P.first && Q.second == P.second)) {\n        bool found = false;\n        for (long long delta = 1; delta <= 200000 && !found; ++delta) {\n            if (k0 + delta <= high) {\n                auto cand = point_from(k0 + delta);\n                if (absll(cand.first) <= COORD_LIMIT && absll(cand.second) <= COORD_LIMIT && (cand.first != P.first || cand.second != P.second)) {\n                    Q = cand;\n                    found = true;\n                    break;\n                }\n            }\n            if (k0 - delta >= low) {\n                auto cand = point_from(k0 - delta);\n                if (absll(cand.first) <= COORD_LIMIT && absll(cand.second) <= COORD_LIMIT && (cand.first != P.first || cand.second != P.second)) {\n                    Q = cand;\n                    found = true;\n                    break;\n                }\n            }\n        }\n        if (!found) return false;\n    }\n    out = {P.first, P.second, Q.first, Q.second};\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K;\n    for (int d = 1; d <= 10; ++d) cin >> demand[d];\n    points.resize(N);\n    for (int i = 0; i < N; ++i) cin >> points[i].x >> points[i].y;\n\n    pattern_lo.assign(N, 0ULL);\n    pattern_hi.assign(N, 0ULL);\n    tmp_keys.resize(N);\n    order_idx.resize(N);\n    proj_values.resize(N);\n    gap_indices.reserve(N);\n    lines_current.reserve(K);\n\n    start_time = chrono::steady_clock::now();\n\n    int global_best_score = -1;\n    vector<Line> global_best_lines;\n    vector<Line> base_prefix;\n    base_prefix.reserve(K);\n\n    while (!check_time()) {\n        base_prefix.clear();\n        if (!global_best_lines.empty()) {\n            int mode = rng() % 5;\n            if (mode <= 2) {\n                int drop = rng() % (global_best_lines.size() + 1);\n                int keep = (int)global_best_lines.size() - drop;\n                keep = min(keep, K);\n                base_prefix.insert(base_prefix.end(), global_best_lines.begin(), global_best_lines.begin() + keep);\n            } else {\n                int keep_percent = 55 + (rng() % 36); // 55..90\n                for (const auto &ln : global_best_lines) {\n                    if ((int)base_prefix.size() >= K) break;\n                    if ((int)(rng() % 100) < keep_percent) base_prefix.push_back(ln);\n                }\n            }\n            if (K > 0 && (int)base_prefix.size() >= K) base_prefix.resize(K - 1);\n        }\n\n        AttemptResult res = run_attempt(base_prefix);\n        if (res.score > global_best_score) {\n            global_best_score = res.score;\n            global_best_lines = res.lines;\n        }\n        if (check_time()) break;\n    }\n\n    vector<array<long long,4>> output;\n    output.reserve(global_best_lines.size());\n    for (const auto &ln : global_best_lines) {\n        array<long long,4> pts;\n        if (!line_to_points(ln, pts)) {\n            pts = {-COORD_LIMIT + 1, -COORD_LIMIT + 1, -COORD_LIMIT + 2, -COORD_LIMIT + 1};\n        }\n        output.push_back(pts);\n    }\n\n    cout << output.size() << '\\n';\n    for (auto &v : output) {\n        cout << v[0] << ' ' << v[1] << ' ' << v[2] << ' ' << v[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    struct Candidate {\n        array<int, 8> pts{}; // D,B,A,C (new dot first)\n    };\n    struct NeighborInfo {\n        bool exists = false;\n        bool edgeFree = false;\n        int x = 0;\n        int y = 0;\n    };\n\n    static constexpr double TIME_LIMIT = 4.8;\n\n    int N{}, M{};\n    int center{};\n    int diagOffset{};\n    vector<vector<int>> rowDots, colDots;\n    vector<vector<int>> diagPosDots, diagNegDots;\n    vector<vector<char>> hasDot;\n    vector<vector<int>> weight;\n    vector<vector<char>> usedH, usedV, usedDiagPos, usedDiagNeg;\n    vector<array<int, 8>> operations;\n    chrono::steady_clock::time_point startTime;\n\n    double elapsed() const {\n        using namespace chrono;\n        return duration<double>(steady_clock::now() - startTime).count();\n    }\n\n    pair<int, int> uvToXY(int u, int v) const {\n        int x = (u + v) / 2;\n        int y = (u - v) / 2;\n        return {x, y};\n    }\n\n    void insertSorted(vector<int> &vec, int val) {\n        vec.insert(lower_bound(vec.begin(), vec.end(), val), val);\n    }\n\n    void addDot(int x, int y) {\n        if (hasDot[x][y]) return;\n        hasDot[x][y] = 1;\n        insertSorted(rowDots[y], x);\n        insertSorted(colDots[x], y);\n        int vVal = x - y;\n        insertSorted(diagPosDots[vVal + diagOffset], x + y);\n        insertSorted(diagNegDots[x + y], vVal);\n    }\n\n    bool horizontalSegmentUnused(int y, int x1, int x2) const {\n        if (x1 == x2 || y < 0 || y >= N) return false;\n        int l = min(x1, x2);\n        int r = max(x1, x2);\n        for (int x = l; x < r; ++x) {\n            if (usedH[y][x]) return false;\n        }\n        return true;\n    }\n\n    void markHorizontal(int y, int x1, int x2) {\n        if (y < 0 || y >= N) return;\n        int l = min(x1, x2);\n        int r = max(x1, x2);\n        for (int x = l; x < r; ++x) usedH[y][x] = 1;\n    }\n\n    bool verticalSegmentUnused(int x, int y1, int y2) const {\n        if (y1 == y2 || x < 0 || x >= N) return false;\n        int l = min(y1, y2);\n        int r = max(y1, y2);\n        for (int y = l; y < r; ++y) {\n            if (usedV[x][y]) return false;\n        }\n        return true;\n    }\n\n    void markVertical(int x, int y1, int y2) {\n        if (x < 0 || x >= N) return;\n        int l = min(y1, y2);\n        int r = max(y1, y2);\n        for (int y = l; y < r; ++y) usedV[x][y] = 1;\n    }\n\n    bool diagPosSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return false;\n        if (x2 - x1 != y2 - y1) return false;\n        if (x2 < x1) return diagPosSegmentsUnused(x2, y2, x1, y1);\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            if (usedDiagPos[x1 + i][y1 + i]) return false;\n        }\n        return true;\n    }\n\n    void markDiagPos(int x1, int y1, int x2, int y2) {\n        if (x2 - x1 != y2 - y1) return;\n        if (x2 < x1) {\n            markDiagPos(x2, y2, x1, y1);\n            return;\n        }\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            usedDiagPos[x1 + i][y1 + i] = 1;\n        }\n    }\n\n    bool diagNegSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return false;\n        if ((x2 - x1) != -(y2 - y1)) return false;\n        if (x2 < x1) return diagNegSegmentsUnused(x2, y2, x1, y1);\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            int y = y1 - i;\n            if (y <= 0 || y > N - 1) return false;\n            if (usedDiagNeg[x1 + i][y - 1]) return false;\n        }\n        return true;\n    }\n\n    void markDiagNeg(int x1, int y1, int x2, int y2) {\n        if ((x2 - x1) != -(y2 - y1)) return;\n        if (x2 < x1) {\n            markDiagNeg(x2, y2, x1, y1);\n            return;\n        }\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            int y = y1 - i;\n            usedDiagNeg[x1 + i][y - 1] = 1;\n        }\n    }\n\n    bool edgeSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return verticalSegmentUnused(x1, y1, y2);\n        if (y1 == y2) return horizontalSegmentUnused(y1, x1, x2);\n        if (x2 - x1 == y2 - y1) return diagPosSegmentsUnused(x1, y1, x2, y2);\n        if (x2 - x1 == -(y2 - y1)) return diagNegSegmentsUnused(x1, y1, x2, y2);\n        return false;\n    }\n\n    void markEdge(int x1, int y1, int x2, int y2) {\n        if (x1 == x2) {\n            markVertical(x1, y1, y2);\n        } else if (y1 == y2) {\n            markHorizontal(y1, x1, x2);\n        } else if (x2 - x1 == y2 - y1) {\n            markDiagPos(x1, y1, x2, y2);\n        } else if (x2 - x1 == -(y2 - y1)) {\n            markDiagNeg(x1, y1, x2, y2);\n        }\n    }\n\n    bool edgeInteriorClear(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2 && y1 == y2) return false;\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n        int steps = max(abs(dx), abs(dy));\n        if (steps <= 1) return true;\n        int sx = (dx > 0) - (dx < 0);\n        int sy = (dy > 0) - (dy < 0);\n        int cx = x1 + sx;\n        int cy = y1 + sy;\n        for (int i = 1; i < steps; ++i) {\n            if (cx < 0 || cx >= N || cy < 0 || cy >= N) return false;\n            if (hasDot[cx][cy]) return false;\n            cx += sx;\n            cy += sy;\n        }\n        return true;\n    }\n\n    bool findBestCandidate(Candidate &best, bool &timeoutFlag) {\n        bool found = false;\n        long long bestScore = -1;\n        int bestLen = INT_MAX;\n        timeoutFlag = false;\n        bool stop = false;\n        int processed = 0;\n\n        auto updateBest = [&](const array<int, 8> &seq, long long score, int len) {\n            if (!found || score > bestScore || (score == bestScore && len < bestLen)) {\n                found = true;\n                bestScore = score;\n                bestLen = len;\n                best.pts = seq;\n            }\n        };\n\n        for (int y = 0; y < N && !stop; ++y) {\n            const auto &row = rowDots[y];\n            int rowSize = (int)row.size();\n            for (int idx = 0; idx < rowSize; ++idx) {\n                if ((processed & 63) == 0 && elapsed() > TIME_LIMIT) {\n                    timeoutFlag = true;\n                    stop = true;\n                    break;\n                }\n                ++processed;\n                int ax = row[idx];\n                int ay = y;\n\n                NeighborInfo left, right, up, down, ne, sw, nw, se;\n\n                if (idx > 0) {\n                    left.exists = true;\n                    left.x = row[idx - 1];\n                    left.y = ay;\n                    left.edgeFree = edgeSegmentsUnused(ax, ay, left.x, left.y);\n                }\n                if (idx + 1 < rowSize) {\n                    right.exists = true;\n                    right.x = row[idx + 1];\n                    right.y = ay;\n                    right.edgeFree = edgeSegmentsUnused(ax, ay, right.x, right.y);\n                }\n\n                const auto &col = colDots[ax];\n                auto itCol = lower_bound(col.begin(), col.end(), ay);\n                if (itCol == col.end() || *itCol != ay) continue;\n                int posCol = int(itCol - col.begin());\n                if (posCol > 0) {\n                    down.exists = true;\n                    down.x = ax;\n                    down.y = col[posCol - 1];\n                    down.edgeFree = edgeSegmentsUnused(ax, ay, down.x, down.y);\n                }\n                if (posCol + 1 < (int)col.size()) {\n                    up.exists = true;\n                    up.x = ax;\n                    up.y = col[posCol + 1];\n                    up.edgeFree = edgeSegmentsUnused(ax, ay, up.x, up.y);\n                }\n\n                int uVal = ax + ay;\n                int vVal = ax - ay;\n\n                auto &diagV = diagPosDots[vVal + diagOffset];\n                auto itV = lower_bound(diagV.begin(), diagV.end(), uVal);\n                if (itV != diagV.end() && *itV == uVal) {\n                    int posV = int(itV - diagV.begin());\n                    if (posV > 0) {\n                        int uNeighbor = diagV[posV - 1];\n                        auto [nx, ny] = uvToXY(uNeighbor, vVal);\n                        sw.exists = true;\n                        sw.x = nx;\n                        sw.y = ny;\n                        sw.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                    if (posV + 1 < (int)diagV.size()) {\n                        int uNeighbor = diagV[posV + 1];\n                        auto [nx, ny] = uvToXY(uNeighbor, vVal);\n                        ne.exists = true;\n                        ne.x = nx;\n                        ne.y = ny;\n                        ne.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                }\n\n                auto &diagU = diagNegDots[uVal];\n                auto itU = lower_bound(diagU.begin(), diagU.end(), vVal);\n                if (itU != diagU.end() && *itU == vVal) {\n                    int posU = int(itU - diagU.begin());\n                    if (posU > 0) {\n                        int vNeighbor = diagU[posU - 1];\n                        auto [nx, ny] = uvToXY(uVal, vNeighbor);\n                        nw.exists = true;\n                        nw.x = nx;\n                        nw.y = ny;\n                        nw.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                    if (posU + 1 < (int)diagU.size()) {\n                        int vNeighbor = diagU[posU + 1];\n                        auto [nx, ny] = uvToXY(uVal, vNeighbor);\n                        se.exists = true;\n                        se.x = nx;\n                        se.y = ny;\n                        se.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                }\n\n                auto considerAxis = [&](const NeighborInfo &vert, const NeighborInfo &horiz) {\n                    if (!vert.exists || !horiz.exists) return;\n                    if (!vert.edgeFree || !horiz.edgeFree) return;\n                    int dx = horiz.x;\n                    int dy = vert.y;\n                    if (dx < 0 || dx >= N || dy < 0 || dy >= N) return;\n                    if (hasDot[dx][dy]) return;\n                    if (!edgeInteriorClear(vert.x, vert.y, dx, dy)) return;\n                    if (!edgeInteriorClear(horiz.x, horiz.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(vert.x, vert.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(horiz.x, horiz.y, dx, dy)) return;\n                    array<int, 8> seq = {dx, dy,\n                                         vert.x, vert.y,\n                                         ax, ay,\n                                         horiz.x, horiz.y};\n                    long long score = weight[dx][dy];\n                    int len = abs(vert.y - ay) + abs(horiz.x - ax);\n                    updateBest(seq, score, len);\n                };\n\n                considerAxis(up, right);\n                considerAxis(up, left);\n                considerAxis(down, right);\n                considerAxis(down, left);\n\n                auto considerDiag = [&](const NeighborInfo &diagP, const NeighborInfo &diagN) {\n                    if (!diagP.exists || !diagN.exists) return;\n                    if (!diagP.edgeFree || !diagN.edgeFree) return;\n                    int dx = diagP.x + (diagN.x - ax);\n                    int dy = diagP.y + (diagN.y - ay);\n                    if (dx < 0 || dx >= N || dy < 0 || dy >= N) return;\n                    if (hasDot[dx][dy]) return;\n                    if (!edgeInteriorClear(diagP.x, diagP.y, dx, dy)) return;\n                    if (!edgeInteriorClear(diagN.x, diagN.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(diagP.x, diagP.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(diagN.x, diagN.y, dx, dy)) return;\n                    array<int, 8> seq = {dx, dy,\n                                         diagP.x, diagP.y,\n                                         ax, ay,\n                                         diagN.x, diagN.y};\n                    long long score = weight[dx][dy];\n                    int len = abs(diagP.x - ax) + abs(diagP.y - ay) +\n                              abs(diagN.x - ax) + abs(diagN.y - ay);\n                    updateBest(seq, score, len);\n                };\n\n                considerDiag(ne, nw);\n                considerDiag(ne, se);\n                considerDiag(sw, nw);\n                considerDiag(sw, se);\n            }\n        }\n\n        return found;\n    }\n\n    void applyCandidate(const Candidate &cand) {\n        const auto &pts = cand.pts;\n        for (int i = 0; i < 4; ++i) {\n            int j = (i + 1) & 3;\n            markEdge(pts[2 * i], pts[2 * i + 1], pts[2 * j], pts[2 * j + 1]);\n        }\n        addDot(pts[0], pts[1]);\n        operations.push_back(pts);\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M)) return;\n        rowDots.assign(N, {});\n        colDots.assign(N, {});\n        diagOffset = N - 1;\n        int diagSize = 2 * N - 1;\n        diagPosDots.assign(diagSize, {});\n        diagNegDots.assign(diagSize, {});\n        hasDot.assign(N, vector<char>(N, 0));\n        weight.assign(N, vector<int>(N, 0));\n        int seg = max(N - 1, 0);\n        usedH.assign(N, vector<char>(seg, 0));\n        usedV.assign(N, vector<char>(seg, 0));\n        usedDiagPos.assign(seg, vector<char>(seg, 0));\n        usedDiagNeg.assign(seg, vector<char>(seg, 0));\n        operations.clear();\n        operations.reserve(N * N);\n\n        center = (N - 1) / 2;\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                int dx = x - center;\n                int dy = y - center;\n                weight[x][y] = dx * dx + dy * dy + 1;\n            }\n        }\n\n        for (int i = 0; i < M; ++i) {\n            int x, y;\n            cin >> x >> y;\n            addDot(x, y);\n        }\n\n        startTime = chrono::steady_clock::now();\n        while (true) {\n            if (elapsed() > TIME_LIMIT) break;\n            Candidate cand;\n            bool timeout = false;\n            if (!findBestCandidate(cand, timeout)) break;\n            applyCandidate(cand);\n            if (timeout) break;\n        }\n\n        cout << operations.size() << '\\n';\n        for (auto &op : operations) {\n            for (int i = 0; i < 8; ++i) {\n                if (i) cout << ' ';\n                cout << op[i];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev, cap, cost;\n    };\n    int N;\n    vector<vector<Edge>> graph;\n    MinCostFlow(int n = 0) : N(n), graph(n) {}\n    void add_edge(int fr, int to, int cap, int cost) {\n        Edge f{to, (int)graph[to].size(), cap, cost};\n        Edge b{fr, (int)graph[fr].size(), 0, -cost};\n        graph[fr].push_back(f);\n        graph[to].push_back(b);\n    }\n    pair<int, long long> min_cost_flow(int s, int t, int maxf) {\n        const long long INF = (1LL << 60);\n        vector<long long> h(N, 0), dist(N);\n        vector<int> prevv(N), preve(N);\n        long long cost = 0;\n        int flow = 0;\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INF);\n            dist[s] = 0;\n            priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;\n            pq.emplace(0LL, s);\n            while (!pq.empty()) {\n                auto [d, v] = pq.top();\n                pq.pop();\n                if (dist[v] < d) continue;\n                for (int i = 0; i < (int)graph[v].size(); ++i) {\n                    const Edge &e = graph[v][i];\n                    if (e.cap <= 0) continue;\n                    long long nd = dist[v] + e.cost + h[v] - h[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        prevv[e.to] = v;\n                        preve[e.to] = i;\n                        pq.emplace(nd, e.to);\n                    }\n                }\n            }\n            if (dist[t] == INF) break;\n            for (int v = 0; v < N; ++v) {\n                if (dist[v] < INF) h[v] += dist[v];\n            }\n            int d = maxf - flow;\n            for (int v = t; v != s; v = prevv[v]) {\n                d = min(d, graph[prevv[v]][preve[v]].cap);\n            }\n            flow += d;\n            cost += 1LL * d * h[t];\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                e.cap -= d;\n                graph[v][e.rev].cap += d;\n            }\n        }\n        return {flow, cost};\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 10;\n    using Grid = array<array<uint8_t, N>, N>;\n    static constexpr char DIRS[4] = {'F', 'B', 'L', 'R'};\n    static constexpr int DR[4] = {-1, 1, 0, 0};\n    static constexpr int DC[4] = {0, 0, -1, 1};\n\n    static constexpr double ZONE_ALPHA = 0.35;\n    static constexpr double W_COMPONENT = 1.0;\n    static constexpr double W_ADJ_SAME = 18.0;\n    static constexpr double W_ADJ_DIFF = 13.0;\n    static constexpr double W_ZONE_CENTROID = 40.0;\n    static constexpr double W_LARGEST = 12.0;\n    static constexpr double W_COMP_COUNT = 20.0;\n    static constexpr double W_ZONE_ALIGN = 5.0;\n    static constexpr double W_ZONE_DIST = 1.2;\n    static constexpr double LOOKAHEAD_WEIGHT = 0.35;\n    static constexpr double W_DIR_REV = 1.6;\n    static constexpr double W_DIR_CHANGE = 0.25;\n\n    vector<int> flavors;\n    array<int, 3> totalCounts{};\n    Grid board{};\n    int placed = 0;\n    mt19937 rng;\n    array<array<int8_t, N>, N> targetZone{};\n    array<array<array<uint8_t, N>, N>, 3> zoneDistance{};\n    array<int, 3> zoneCellCount{};\n    array<pair<int, int>, N * N> cellOrder{};\n    bool hasLastMove = false;\n    char lastMove = 'F';\n\n    Solver() : flavors(100) {\n        for (int idx = 0; idx < N * N; ++idx) {\n            cellOrder[idx] = {idx / N, idx % N};\n        }\n    }\n\n    bool readInput() {\n        totalCounts.fill(0);\n        for (int i = 0; i < 100; ++i) {\n            if (!(cin >> flavors[i])) return false;\n            int f = flavors[i];\n            if (1 <= f && f <= 3) totalCounts[f - 1]++;\n        }\n        uint32_t seed = 712387u;\n        for (int i = 0; i < 100; ++i) {\n            seed = seed * 1000003u + static_cast<uint32_t>(flavors[i]) * 911382323u + i;\n        }\n        rng.seed(seed);\n        computeZones();\n        return true;\n    }\n\n    void solve() {\n        for (auto &row : board) row.fill(0);\n        placed = 0;\n        hasLastMove = false;\n        lastMove = 'F';\n        for (int t = 0; t < 100; ++t) {\n            int p;\n            if (!(cin >> p)) return;\n            placeCandy(p, flavors[t]);\n            ++placed;\n            Decision dec = chooseMove(placed);\n            board = dec.board;\n            lastMove = dec.dir;\n            hasLastMove = true;\n            cout << dec.dir << endl;\n        }\n    }\n\n    void placeCandy(int idx, int flavor) {\n        int target = idx;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (board[r][c] == 0) {\n                    if (--target == 0) {\n                        board[r][c] = static_cast<uint8_t>(flavor);\n                        return;\n                    }\n                }\n            }\n        }\n    }\n\n    void applyTilt(Grid &g, char dir) const {\n        if (dir == 'F') {\n            for (int c = 0; c < N; ++c) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int r = 0; r < N; ++r) if (g[r][c]) tmp[k++] = g[r][c];\n                for (int r = 0; r < N; ++r) g[r][c] = (r < k ? tmp[r] : 0);\n            }\n        } else if (dir == 'B') {\n            for (int c = 0; c < N; ++c) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int r = 0; r < N; ++r) if (g[r][c]) tmp[k++] = g[r][c];\n                int idx = k - 1;\n                for (int r = N - 1; r >= 0; --r) g[r][c] = (idx >= 0 ? tmp[idx--] : 0);\n            }\n        } else if (dir == 'L') {\n            for (int r = 0; r < N; ++r) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int c = 0; c < N; ++c) if (g[r][c]) tmp[k++] = g[r][c];\n                for (int c = 0; c < N; ++c) g[r][c] = (c < k ? tmp[c] : 0);\n            }\n        } else { // 'R'\n            for (int r = 0; r < N; ++r) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int c = 0; c < N; ++c) if (g[r][c]) tmp[k++] = g[r][c];\n                int idx = k - 1;\n                for (int c = N - 1; c >= 0; --c) g[r][c] = (idx >= 0 ? tmp[idx--] : 0);\n            }\n        }\n    }\n\n    struct Decision {\n        char dir = 'F';\n        Grid board{};\n    };\n\n    Decision chooseMove(int filled) {\n        Decision best;\n        bool first = true;\n        double bestScore = -1e100;\n        for (char dir : DIRS) {\n            Grid cand = board;\n            applyTilt(cand, dir);\n            double score = evaluateWithLookahead(cand, filled);\n            if (hasLastMove) {\n                if (isOpposite(dir, lastMove)) score -= W_DIR_REV;\n                else if (dir != lastMove) score -= W_DIR_CHANGE;\n            }\n            score += randomNoise();\n            if (first || score > bestScore) {\n                first = false;\n                bestScore = score;\n                best.dir = dir;\n                best.board = cand;\n            }\n        }\n        return best;\n    }\n\n    bool isOpposite(char a, char b) const {\n        return (a == 'F' && b == 'B') || (a == 'B' && b == 'F') ||\n               (a == 'L' && b == 'R') || (a == 'R' && b == 'L');\n    }\n\n    double evaluateWithLookahead(const Grid &state, int filled) {\n        double base = evaluate(state, filled);\n        if (filled >= 100 || LOOKAHEAD_WEIGHT <= 1e-9) return base;\n        int nextIdx = filled;\n        if (nextIdx >= (int)flavors.size()) return base;\n\n        int emptiesIdx[N * N];\n        int emptiesSz = 0;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (state[r][c] == 0) emptiesIdx[emptiesSz++] = r * N + c;\n            }\n        }\n        if (emptiesSz == 0) return base;\n\n        int limit = getSampleLimit(filled);\n        if (limit <= 0) limit = 1;\n        int sampleCount = min(limit, emptiesSz);\n        for (int i = 0; i < sampleCount; ++i) {\n            int span = emptiesSz - i;\n            int j = i + (int)(rng() % span);\n            swap(emptiesIdx[i], emptiesIdx[j]);\n        }\n\n        const int nextFlavor = flavors[nextIdx];\n        double accum = 0.0;\n        for (int i = 0; i < sampleCount; ++i) {\n            int idx = emptiesIdx[i];\n            int r = idx / N;\n            int c = idx % N;\n            Grid tmp = state;\n            tmp[r][c] = static_cast<uint8_t>(nextFlavor);\n\n            double bestNext = -1e100;\n            for (char dir : DIRS) {\n                Grid fut = tmp;\n                applyTilt(fut, dir);\n                double val = evaluate(fut, filled + 1);\n                if (val > bestNext) bestNext = val;\n            }\n            accum += bestNext;\n        }\n        double avg = accum / sampleCount;\n\n        double fillRatio = static_cast<double>(filled) / 100.0;\n        double adapt = 0.3 + 0.7 * (1.0 - fillRatio);\n        double coverage = (emptiesSz <= sampleCount) ? 1.0\n                         : static_cast<double>(sampleCount) / emptiesSz;\n        double coverageFactor = sqrt(max(1e-9, coverage));\n        double lookFactor = LOOKAHEAD_WEIGHT * adapt * coverageFactor;\n        if (lookFactor > 0.5) lookFactor = 0.5;\n\n        return base * (1.0 - lookFactor) + avg * lookFactor;\n    }\n\n    int getSampleLimit(int filled) const {\n        if (filled < 25) return 24;\n        if (filled < 50) return 18;\n        if (filled < 75) return 12;\n        if (filled < 90) return 9;\n        return 6;\n    }\n\n    double evaluate(const Grid &g, int filled) const {\n        array<int, 3> cnt = {0, 0, 0};\n        array<double, 3> sumR = {0.0, 0.0, 0.0};\n        array<double, 3> sumC = {0.0, 0.0, 0.0};\n        double sameAdj = 0.0;\n        double diffAdj = 0.0;\n        int zoneHit = 0;\n        double zoneDistSum = 0.0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int val = g[r][c];\n                if (!val) continue;\n                int idx = val - 1;\n                cnt[idx]++;\n                sumR[idx] += r;\n                sumC[idx] += c;\n                int tz = targetZone[r][c];\n                if (tz == idx) zoneHit++;\n                zoneDistSum += zoneDistance[idx][r][c];\n                if (r + 1 < N && g[r + 1][c]) {\n                    if (g[r + 1][c] == val) sameAdj += 1.0;\n                    else diffAdj += 1.0;\n                }\n                if (c + 1 < N && g[r][c + 1]) {\n                    if (g[r][c + 1] == val) sameAdj += 1.0;\n                    else diffAdj += 1.0;\n                }\n            }\n        }\n\n        array<double, 3> meanR = {0.0, 0.0, 0.0}, meanC = {0.0, 0.0, 0.0};\n        for (int i = 0; i < 3; ++i) {\n            if (cnt[i]) {\n                meanR[i] = sumR[i] / cnt[i];\n                meanC[i] = sumC[i] / cnt[i];\n            }\n        }\n\n        double centroidScore = 0.0;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int val = g[r][c];\n                if (!val) continue;\n                int idx = val - 1;\n                double dr = r - meanR[idx];\n                double dc = c - meanC[idx];\n                double dist2 = dr * dr + dc * dc;\n                centroidScore += 1.0 / (1.0 + ZONE_ALPHA * dist2);\n            }\n        }\n\n        array<array<uint8_t, N>, N> vis{};\n        array<int, 3> compCounts = {0, 0, 0};\n        array<int, 3> largest = {0, 0, 0};\n        double compScore = 0.0;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!g[r][c] || vis[r][c]) continue;\n                int color = g[r][c];\n                queue<pair<int, int>> q;\n                q.emplace(r, c);\n                vis[r][c] = 1;\n                int sz = 0;\n                while (!q.empty()) {\n                    auto [cr, cc] = q.front();\n                    q.pop();\n                    ++sz;\n                    for (int d = 0; d < 4; ++d) {\n                        int nr = cr + DR[d];\n                        int nc = cc + DC[d];\n                        if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                        if (vis[nr][nc] || g[nr][nc] != color) continue;\n                        vis[nr][nc] = 1;\n                        q.emplace(nr, nc);\n                    }\n                }\n                compScore += 1.0 * sz * sz;\n                int idx = color - 1;\n                compCounts[idx]++;\n                largest[idx] = max(largest[idx], sz);\n            }\n        }\n\n        int compCountSum = compCounts[0] + compCounts[1] + compCounts[2];\n        int largestSum = largest[0] + largest[1] + largest[2];\n        double fillRatio = (filled <= 0 ? 0.0 : static_cast<double>(filled) / 100.0);\n\n        double centroidWeight = W_ZONE_CENTROID * (0.4 + 0.6 * (1.0 - fillRatio));\n        double adjFactor = 0.4 + 0.6 * fillRatio;\n        double adjSameWeight = W_ADJ_SAME * adjFactor;\n        double adjDiffWeight = W_ADJ_DIFF * adjFactor;\n        double compCountWeight = W_COMP_COUNT * fillRatio * fillRatio;\n        double zoneAlignWeight = W_ZONE_ALIGN * (0.8 + 0.2 * fillRatio);\n        double zoneDistWeight = W_ZONE_DIST * (0.6 + 0.4 * (1.0 - fillRatio));\n\n        double score = W_COMPONENT * compScore\n                     + adjSameWeight * sameAdj\n                     - adjDiffWeight * diffAdj\n                     + centroidWeight * centroidScore\n                     + W_LARGEST * largestSum\n                     - compCountWeight * compCountSum\n                     + zoneAlignWeight * zoneHit\n                     - zoneDistWeight * zoneDistSum;\n\n        return score;\n    }\n\n    double randomNoise() {\n        return (static_cast<double>(rng() & 0xffffu) / 65535.0 - 0.5) * 1e-3;\n    }\n\n    void computeZones() {\n        bool ok = buildBestZone();\n        if (!ok) fallbackZone();\n\n        zoneCellCount.fill(0);\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int val = targetZone[r][c];\n                if (val < 0 || val >= 3) val = (val % 3 + 3) % 3;\n                targetZone[r][c] = static_cast<int8_t>(val);\n                zoneCellCount[val]++;\n            }\n        }\n        computeZoneDistances();\n    }\n\n    bool buildBestZone() {\n        vector<array<pair<int, int>, 3>> anchorSets;\n        auto addSet = [&](initializer_list<pair<int, int>> pts) {\n            if (pts.size() != 3) return;\n            array<pair<int, int>, 3> arr{};\n            int idx = 0;\n            for (auto pt : pts) arr[idx++] = pt;\n            anchorSets.push_back(arr);\n        };\n        addSet({{1, 1}, {1, 8}, {7, 4}});\n        addSet({{1, 1}, {8, 1}, {4, 8}});\n        addSet({{1, 8}, {8, 8}, {4, 1}});\n        addSet({{8, 1}, {8, 8}, {1, 4}});\n        addSet({{2, 2}, {2, 7}, {7, 5}});\n        addSet({{2, 2}, {7, 2}, {5, 7}});\n        addSet({{1, 1}, {8, 8}, {5, 5}});\n        addSet({{8, 1}, {1, 8}, {5, 5}});\n        addSet({{0, 0}, {0, 9}, {9, 4}});\n        addSet({{0, 0}, {9, 0}, {4, 9}});\n        addSet({{0, 4}, {9, 4}, {4, 9}});\n        addSet({{4, 0}, {4, 9}, {8, 5}});\n\n        bool success = false;\n        long long bestCost = (1LL << 60);\n        array<array<int8_t, N>, N> bestZone{};\n\n        for (const auto &set : anchorSets) {\n            array<int, 3> perm = {0, 1, 2};\n            do {\n                array<pair<int, int>, 3> anchors{};\n                for (int i = 0; i < 3; ++i) anchors[perm[i]] = set[i];\n                array<array<int8_t, N>, N> zoneCand{};\n                long long cost = 0;\n                if (!buildZoneForAnchors(anchors, zoneCand, cost)) continue;\n                if (!success || cost < bestCost) {\n                    success = true;\n                    bestCost = cost;\n                    bestZone = zoneCand;\n                }\n            } while (next_permutation(perm.begin(), perm.end()));\n        }\n\n        if (success) targetZone = bestZone;\n        return success;\n    }\n\n    bool buildZoneForAnchors(const array<pair<int, int>, 3> &anchors,\n                             array<array<int8_t, N>, N> &outZone,\n                             long long &outCost) {\n        const int totalCells = N * N;\n        const int SRC = 0;\n        const int COLOR_BASE = 1;\n        const int CELL_BASE = COLOR_BASE + 3;\n        const int SINK = CELL_BASE + totalCells;\n        MinCostFlow mcf(SINK + 1);\n\n        int totalCandy = totalCounts[0] + totalCounts[1] + totalCounts[2];\n        if (totalCandy == 0) return false;\n\n        for (int color = 0; color < 3; ++color) {\n            int cap = totalCounts[color];\n            mcf.add_edge(SRC, COLOR_BASE + color, cap, 0);\n        }\n        for (int color = 0; color < 3; ++color) {\n            if (totalCounts[color] == 0) continue;\n            auto [ar, ac] = anchors[color];\n            ar = clamp(ar, 0, N - 1);\n            ac = clamp(ac, 0, N - 1);\n            for (int idx = 0; idx < totalCells; ++idx) {\n                auto [r, c] = cellOrder[idx];\n                int cost = abs(r - ar) + abs(c - ac);\n                mcf.add_edge(COLOR_BASE + color, CELL_BASE + idx, 1, cost);\n            }\n        }\n        for (int idx = 0; idx < totalCells; ++idx) {\n            mcf.add_edge(CELL_BASE + idx, SINK, 1, 0);\n        }\n\n        auto res = mcf.min_cost_flow(SRC, SINK, totalCandy);\n        if (res.first != totalCandy) return false;\n        outCost = res.second;\n\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                outZone[r][c] = -1;\n\n        for (int idx = 0; idx < totalCells; ++idx) {\n            int node = CELL_BASE + idx;\n            int assigned = -1;\n            for (const auto &e : mcf.graph[node]) {\n                if (e.to >= COLOR_BASE && e.to < COLOR_BASE + 3 && e.cap > 0) {\n                    assigned = e.to - COLOR_BASE;\n                    break;\n                }\n            }\n            if (assigned == -1) {\n                int bestColor = 0;\n                long long best = (1LL << 60);\n                for (int color = 0; color < 3; ++color) {\n                    if (totalCounts[color] == 0) continue;\n                    auto [ar, ac] = anchors[color];\n                    long long dist = abs(cellOrder[idx].first - ar) + abs(cellOrder[idx].second - ac);\n                    if (dist < best) {\n                        best = dist;\n                        bestColor = color;\n                    }\n                }\n                assigned = bestColor;\n            }\n            auto [r, c] = cellOrder[idx];\n            outZone[r][c] = static_cast<int8_t>(assigned);\n        }\n        return true;\n    }\n\n    void fallbackZone() {\n        array<int, 3> remaining = totalCounts;\n        int color = 0;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                while (color < 3 && remaining[color] == 0) ++color;\n                if (color >= 3) color = 2;\n                targetZone[r][c] = static_cast<int8_t>(color);\n                if (remaining[color] > 0) --remaining[color];\n            }\n        }\n    }\n\n    void computeZoneDistances() {\n        const int INF = 1e9;\n        for (int color = 0; color < 3; ++color) {\n            if (zoneCellCount[color] == 0) {\n                for (int r = 0; r < N; ++r)\n                    for (int c = 0; c < N; ++c)\n                        zoneDistance[color][r][c] = 0;\n                continue;\n            }\n            array<array<int, N>, N> dist;\n            for (int r = 0; r < N; ++r)\n                for (int c = 0; c < N; ++c)\n                    dist[r][c] = INF;\n            queue<pair<int, int>> q;\n            for (int r = 0; r < N; ++r) {\n                for (int c = 0; c < N; ++c) {\n                    if (targetZone[r][c] == color) {\n                        dist[r][c] = 0;\n                        q.emplace(r, c);\n                    }\n                }\n            }\n            while (!q.empty()) {\n                auto [r, c] = q.front();\n                q.pop();\n                for (int d = 0; d < 4; ++d) {\n                    int nr = r + DR[d];\n                    int nc = c + DC[d];\n                    if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                    if (dist[nr][nc] > dist[r][c] + 1) {\n                        dist[nr][nc] = dist[r][c] + 1;\n                        q.emplace(nr, nc);\n                    }\n                }\n            }\n            for (int r = 0; r < N; ++r) {\n                for (int c = 0; c < N; ++c) {\n                    int d = dist[r][c];\n                    if (d == INF) d = 250;\n                    if (d > 250) d = 250;\n                    zoneDistance[color][r][c] = static_cast<uint8_t>(d);\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver solver;\n    if (!solver.readInput()) return 0;\n    solver.solve();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Designer {\n    int N = 60;\n    int A = 32;\n    int P;\n    int payloadEdges;\n    int payloadWords;\n    vector<vector<int>> anchorAdj; // A x A\n    vector<uint64_t> anchorAdjMask; // per anchor bitmask\n    vector<uint64_t> payloadAnchorMask; // per payload row mask\n    vector<int> degAA_can, degAP_can;\n    vector<vector<uint64_t>> graphCodes; // per graph payload bits\n    vector<pair<int,int>> payloadPairs;\n    vector<vector<int>> payloadPairIdx;\n    mt19937_64 rng;\n    Designer() {\n        P = N - A;\n        payloadEdges = P*(P-1)/2;\n        payloadWords = (payloadEdges + 63) / 64;\n        payloadPairIdx.assign(P, vector<int>(P, -1));\n        int idx = 0;\n        for(int u=0;u<P;u++) for(int v=u+1; v<P; v++) {\n            payloadPairIdx[u][v] = idx++;\n            payloadPairs.push_back({u,v});\n        }\n    }\n    uint64_t randMask(int bits) {\n        uint64_t mask = 0;\n        for(int i=0;i<bits;i+=64) mask |= (rng() << i);\n        if(bits<64) mask &= ((1ULL<<bits)-1);\n        else if(bits % 64) mask &= ((1ULL<<(bits%64))-1) << (bits/64*64);\n        return mask;\n    }\n    void generateAnchorAdj(double prob=0.8) {\n        anchorAdj.assign(A, vector<int>(A,0));\n        anchorAdjMask.assign(A,0);\n        for(int i=0;i<A;i++){\n            for(int j=i+1;j<A;j++){\n                bool edge = (rng() % 1000) < int(prob*1000);\n                anchorAdj[i][j]=anchorAdj[j][i]=edge;\n            }\n        }\n        for(int i=0;i<A;i++){\n            uint64_t mask=0;\n            for(int j=0;j<A;j++) if(anchorAdj[i][j]) mask |= (1ULL<<j);\n            anchorAdjMask[i]=mask;\n        }\n        degAA_can.assign(A,0);\n        for(int i=0;i<A;i++){\n            for(int j=0;j<A;j++) if(anchorAdj[i][j]) degAA_can[i]++;\n        }\n    }\n    void generatePayloadRows(int minWeight=10, int maxWeight=22, int minDist=8) {\n        payloadAnchorMask.clear();\n        while((int)payloadAnchorMask.size()<P){\n            uint64_t mask = 0;\n            for(int b=0;b<A;b++){\n                if(rng()&1) mask |= (1ULL<<b);\n            }\n            int weight = __builtin_popcountll(mask);\n            if(weight<minWeight || weight>maxWeight) continue;\n            bool ok=true;\n            for(auto &prev: payloadAnchorMask){\n                int dist = __builtin_popcountll(mask ^ prev);\n                if(dist < minDist){ ok=false; break; }\n            }\n            if(ok) payloadAnchorMask.push_back(mask);\n        }\n        degAP_can.assign(A,0);\n        for(auto &mask: payloadAnchorMask){\n            for(int b=0;b<A;b++) if((mask>>b)&1ULL) degAP_can[b]++;\n        }\n    }\n    vector<uint64_t> randomPayloadBits() {\n        vector<uint64_t> bits(payloadWords,0);\n        for(int w=0;w<payloadWords;w++) bits[w]=rng();\n        if(payloadEdges % 64){\n            uint64_t mask = (1ULL<<(payloadEdges%64))-1;\n            bits.back() &= mask;\n        }\n        return bits;\n    }\n    int hamming(const vector<uint64_t>&a,const vector<uint64_t>&b){\n        int s=0; for(size_t i=0;i<a.size();i++) s+=__builtin_popcountll(a[i]^b[i]); return s;\n    }\n    void generateGraphCodes(int M, int minDist=120){\n        graphCodes.clear();\n        while((int)graphCodes.size()<M){\n            auto cand = randomPayloadBits();\n            bool ok=true;\n            for(auto &exist: graphCodes){\n                if(hamming(cand,exist)<minDist){ ok=false; break; }\n            }\n            if(ok) graphCodes.push_back(cand);\n        }\n    }\n    void build(int M, int epsInt){\n        uint64_t seed = 1234567ULL + 10007ULL*M + 7919ULL*epsInt;\n        rng.seed(seed);\n        generateAnchorAdj();\n        generatePayloadRows();\n        generateGraphCodes(M);\n    }\n    string graphString(int k){\n        string s;\n        s.reserve(N*(N-1)/2);\n        auto &code = graphCodes[k];\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                bool val=false;\n                if(i<A && j<A){\n                    val = anchorAdj[i][j];\n                }else if(i<A && j>=A){\n                    int p = j-A;\n                    val = (payloadAnchorMask[p]>>i)&1ULL;\n                }else{\n                    int u = i-A;\n                    int v = j-A;\n                    int idx = payloadPairIdx[u][v];\n                    val = (code[idx>>6] >> (idx&63)) & 1ULL;\n                }\n                s.push_back(val?'1':'0');\n            }\n        }\n        return s;\n    }\n};\n\nstruct Hungarian {\n    int n;\n    vector<vector<int>> cost;\n    vector<int> assignment;\n    Hungarian(int n=0):n(n){\n        cost.assign(n, vector<int>(n,0));\n        assignment.assign(n,-1);\n    }\n    void resize(int m){\n        n=m;\n        cost.assign(n, vector<int>(n,0));\n        assignment.assign(n,-1);\n    }\n    void solve(){\n        const int INF = 1e9;\n        vector<int> u(n+1,0), v(n+1,0), p(n+1,0), way(n+1,0);\n        for(int i=1;i<=n;i++){\n            p[0]=i;\n            vector<int> minv(n+1, INF);\n            vector<char> used(n+1,false);\n            int j0=0;\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> ans(n,-1);\n        for(int j=1;j<=n;j++) if(p[j]>0) ans[p[j]-1]=j-1;\n        assignment=ans;\n    }\n};\n\nstruct Decoder {\n    Designer *des;\n    int N,A,P;\n    Decoder(Designer* d):des(d){\n        N=d->N; A=d->A; P=d->P;\n    }\n    vector<uint64_t> parse(const string &s){\n        vector<uint64_t> adj(N,0);\n        int pos=0;\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                if(s[pos++]=='1'){\n                    adj[i]|=(1ULL<<j);\n                    adj[j]|=(1ULL<<i);\n                }\n            }\n        }\n        return adj;\n    }\n    vector<int> selectAnchors(const vector<uint64_t>&adj){\n        vector<int> deg(N);\n        for(int i=0;i<N;i++) deg[i]=__builtin_popcountll(adj[i]);\n        vector<int> order(N);\n        iota(order.begin(), order.end(),0);\n        sort(order.begin(), order.end(), [&](int x,int y){\n            if(deg[x]!=deg[y]) return deg[x]>deg[y];\n            return x<y;\n        });\n        vector<int> anchors(order.begin(), order.begin()+A);\n        vector<char> in(N,false);\n        uint64_t mask=0;\n        for(int v: anchors){ in[v]=true; mask|=(1ULL<<v); }\n        for(int iter=0;iter<4;iter++){\n            bool improved=false;\n            vector<int> degIn(N,0);\n            for(int v=0;v<N;v++){\n                degIn[v]=__builtin_popcountll(adj[v]&mask);\n                if(in[v]) degIn[v]--;\n            }\n            int bestGain=0, bestU=-1, bestV=-1;\n            for(int u: anchors){\n                for(int v=0;v<N;v++) if(!in[v]){\n                    int gain = degIn[v]-degIn[u];\n                    if(gain>bestGain){\n                        bestGain=gain; bestU=u; bestV=v;\n                    }\n                }\n            }\n            if(bestGain>0){\n                in[bestU]=false; in[bestV]=true;\n                mask ^= (1ULL<<bestU);\n                mask |= (1ULL<<bestV);\n                for(auto &x: anchors) if(x==bestU){ x=bestV; break; }\n                improved=true;\n            }\n            if(!improved) break;\n        }\n        sort(anchors.begin(), anchors.end());\n        return anchors;\n    }\n    pair<vector<int>, vector<int>> mapAnchors(const vector<uint64_t>&adj, const vector<int>&anchors){\n        vector<int> payloads;\n        vector<char> isAnchor(N,false);\n        for(int v:anchors) isAnchor[v]=true;\n        for(int i=0;i<N;i++) if(!isAnchor[i]) payloads.push_back(i);\n        vector<vector<int>> obsAA(A, vector<int>(A,0));\n        vector<int> degAA_obs(A,0), degAP_obs(A,0);\n        for(int i=0;i<A;i++){\n            for(int j=i+1;j<A;j++){\n                bool bit = (adj[anchors[i]]>>anchors[j]) & 1ULL;\n                obsAA[i][j]=obsAA[j][i]=bit;\n            }\n            degAA_obs[i]=0;\n            for(int j=0;j<A;j++) if(obsAA[i][j]) degAA_obs[i]++;\n            uint64_t payloadMask=0;\n            for(int v: payloads) payloadMask|=(1ULL<<v);\n            degAP_obs[i]=__builtin_popcountll(adj[anchors[i]] & payloadMask);\n        }\n        vector<int> orderCan(A), orderObs(A);\n        iota(orderCan.begin(), orderCan.end(),0);\n        iota(orderObs.begin(), orderObs.end(),0);\n        sort(orderCan.begin(), orderCan.end(), [&](int x,int y){\n            if(des->degAA_can[x]!=des->degAA_can[y])\n                return des->degAA_can[x]>des->degAA_can[y];\n            if(des->degAP_can[x]!=des->degAP_can[y])\n                return des->degAP_can[x]>des->degAP_can[y];\n            return x<y;\n        });\n        sort(orderObs.begin(), orderObs.end(), [&](int x,int y){\n            if(degAA_obs[x]!=degAA_obs[y])\n                return degAA_obs[x]>degAA_obs[y];\n            if(degAP_obs[x]!=degAP_obs[y])\n                return degAP_obs[x]>degAP_obs[y];\n            return x<y;\n        });\n        vector<int> assign(A);\n        for(int i=0;i<A;i++) assign[orderCan[i]]=orderObs[i];\n        auto calcCost=[&](const vector<int>&perm){\n            int cost=0;\n            for(int i=0;i<A;i++){\n                for(int j=i+1;j<A;j++){\n                    cost += des->anchorAdj[i][j] ^ obsAA[perm[i]][perm[j]];\n                }\n            }\n            return cost;\n        };\n        int currentCost = calcCost(assign);\n        vector<int> best=assign; int bestCost=currentCost;\n        uniform_int_distribution<int> dist(0,A-1);\n        double temp=5.0;\n        for(int iter=0;iter<5000;iter++){\n            int i=dist(des->rng), j=dist(des->rng);\n            if(i==j) continue;\n            if(i>j) swap(i,j);\n            int ai=assign[i], aj=assign[j];\n            int delta=0;\n            for(int k=0;k<A;k++){\n                if(k==i || k==j) continue;\n                int ak=assign[k];\n                delta += (des->anchorAdj[i][k] ^ obsAA[aj][ak]) - (des->anchorAdj[i][k] ^ obsAA[ai][ak]);\n                delta += (des->anchorAdj[j][k] ^ obsAA[ai][ak]) - (des->anchorAdj[j][k] ^ obsAA[aj][ak]);\n            }\n            delta += (des->anchorAdj[i][j] ^ obsAA[aj][ai]) - (des->anchorAdj[i][j] ^ obsAA[ai][aj]);\n            if(delta < 0 || (temp>1e-9 && uniform_real_distribution<double>(0.0,1.0)(des->rng) < exp(-delta/temp))){\n                swap(assign[i], assign[j]);\n                currentCost += delta;\n                if(currentCost < bestCost){\n                    bestCost=currentCost;\n                    best=assign;\n                }\n            }\n            temp *= 0.995;\n        }\n        vector<int> actualAnchor(A);\n        for(int i=0;i<A;i++) actualAnchor[i]=anchors[best[i]];\n        return {actualAnchor, payloads};\n    }\n    vector<int> mapPayloads(const vector<uint64_t>&adj, const vector<int>&anchorVertices, const vector<int>&payloads){\n        int payloadCount=P;\n        vector<uint64_t> anchorMaskPerPayload(payloadCount,0);\n        vector<int> anchorPos(N,-1);\n        for(int i=0;i<A;i++) anchorPos[anchorVertices[i]]=i;\n        for(int idx=0; idx<payloadCount; idx++){\n            uint64_t mask=0;\n            int v=payloads[idx];\n            for(int i=0;i<A;i++){\n                if((adj[v]>>anchorVertices[i]) & 1ULL) mask |= (1ULL<<i);\n            }\n            anchorMaskPerPayload[idx]=mask;\n        }\n        Hungarian hung(payloadCount);\n        for(int i=0;i<payloadCount;i++){\n            for(int j=0;j<payloadCount;j++){\n                int dist = __builtin_popcountll(anchorMaskPerPayload[i] ^ des->payloadAnchorMask[j]);\n                hung.cost[i][j]=dist;\n            }\n        }\n        hung.solve();\n        vector<int> actual(P);\n        for(int j=0;j<payloadCount;j++){\n            int idx=-1;\n            for(int i=0;i<payloadCount;i++){\n                if(hung.assignment[i]==j){ idx=i; break; }\n            }\n            actual[j]=payloads[idx];\n        }\n        return actual;\n    }\n    vector<uint64_t> observedPayloadBits(const vector<uint64_t>&adj, const vector<int>&payloadMap){\n        vector<uint64_t> bits(des->payloadWords,0);\n        int idx=0;\n        for(int u=0;u<P;u++){\n            for(int v=u+1; v<P; v++){\n                int realU=payloadMap[u];\n                int realV=payloadMap[v];\n                bool bit = (adj[realU]>>realV)&1ULL;\n                if(bit) bits[idx>>6] |= (1ULL<<(idx&63));\n                idx++;\n            }\n        }\n        return bits;\n    }\n    int decode(const string &s){\n        auto adj = parse(s);\n        auto anchors = selectAnchors(adj);\n        auto [anchorMap, payloadList] = mapAnchors(adj, anchors);\n        auto payloadMap = mapPayloads(adj, anchorMap, payloadList);\n        auto obsBits = observedPayloadBits(adj, payloadMap);\n        int best=-1, bestDist=1e9;\n        for(int k=0;k<(int)des->graphCodes.size();k++){\n            int dist = des->hamming(obsBits, des->graphCodes[k]);\n            if(dist < bestDist){\n                bestDist = dist;\n                best = k;\n            }\n        }\n        if(best==-1) best=0;\n        return best;\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int M;\n    double eps;\n    if(!(cin>>M>>eps)) return 0;\n    int epsInt = int(round(eps*100+1e-9));\n    Designer designer;\n    designer.build(M, epsInt);\n    cout<<designer.N<<\"\\n\";\n    for(int k=0;k<M;k++){\n        string g = designer.graphString(k);\n        cout<<g<<\"\\n\";\n    }\n    cout.flush();\n    Decoder decoder(&designer);\n    for(int q=0;q<100;q++){\n        string H;\n        cin>>H;\n        int ans = decoder.decode(H);\n        cout<<ans<<\"\\n\";\n        cout.flush();\n    }\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n};\n\nstruct DSU {\n    int n;\n    vector<int> parent, sz;\n    int components;\n    DSU(int n=0){ if(n) init(n); }\n    void init(int n_) {\n        n = n_;\n        parent.resize(n);\n        sz.resize(n);\n        reset();\n    }\n    void reset() {\n        components = n;\n        iota(parent.begin(), parent.end(), 0);\n        fill(sz.begin(), sz.end(), 1);\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    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        parent[b]=a;\n        sz[a]+=sz[b];\n        --components;\n        return true;\n    }\n};\n\nconst double TOTAL_TIME_LIMIT = 5.8;\nconst double CENTRALITY_LIMIT = 3.2;\nconst double LOCAL_SEARCH_LIMIT = 5.45;\nconst double MOVE_EPS = 1e-9;\nconst double VERTEX_COEFF = 0.18;\nconst double DAYCOUNT_COEFF = 0.035;\nconst double LENGTH_COEFF_RATIO = 0.05;\n\nint N,M,D,K;\nvector<int> U,V,W;\nvector<vector<pair<int,int>>> graphAdj;\n\nvector<double> edgeScore;\nvector<int> assignment;\nvector<vector<int>> dayEdges;\nvector<int> edgePos;\nvector<double> dayScore;\nvector<int> dayCount;\nvector<int> vertexDayCount;\n\nmt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\n\ndouble alphaCoeff, betaCoeff;\n\nvector<double> compute_edge_scores(Timer &timer){\n    const long long INF = (1LL<<60);\n    vector<double> score(M, 0.0);\n    vector<long long> dist(N);\n    vector<double> sigma(N), delta(N);\n    vector<vector<int>> preds(N);\n    for(int i=0;i<N;i++) preds[i].reserve(graphAdj[i].size());\n    vector<int> order;\n    order.reserve(N);\n    vector<int> nodes(N);\n    iota(nodes.begin(), nodes.end(), 0);\n    shuffle(nodes.begin(), nodes.end(), rng);\n    int processed = 0;\n    for(int idx=0; idx<N; ++idx){\n        if(timer.elapsed() > CENTRALITY_LIMIT) break;\n        int s = nodes[idx];\n        fill(dist.begin(), dist.end(), INF);\n        fill(sigma.begin(), sigma.end(), 0.0);\n        fill(delta.begin(), delta.end(), 0.0);\n        for(int i=0;i<N;++i) preds[i].clear();\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        dist[s] = 0;\n        sigma[s] = 1.0;\n        pq.emplace(0LL, s);\n        order.clear();\n        while(!pq.empty()){\n            auto [d,v] = pq.top();\n            pq.pop();\n            if(d != dist[v]) continue;\n            order.push_back(v);\n            for(auto [to,eid] : graphAdj[v]){\n                long long nd = d + W[eid];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    pq.emplace(nd, to);\n                    sigma[to] = sigma[v];\n                    preds[to].clear();\n                    preds[to].push_back(eid);\n                }else if(nd == dist[to]){\n                    sigma[to] += sigma[v];\n                    preds[to].push_back(eid);\n                }\n            }\n        }\n        while(!order.empty()){\n            int w = order.back();\n            order.pop_back();\n            if(sigma[w] <= 0.0) continue;\n            double coeff = (1.0 + delta[w]) / sigma[w];\n            for(int eid : preds[w]){\n                int v = (U[eid]==w) ? V[eid] : U[eid];\n                double contrib = sigma[v] * coeff;\n                delta[v] += contrib;\n                score[eid] += contrib;\n            }\n        }\n        ++processed;\n    }\n    if(processed == 0) processed = 1;\n    if(processed < N){\n        double scale = (double)N / processed;\n        for(double &x : score) x *= scale;\n    }\n    double totalScore = 0.0;\n    for(double s : score) totalScore += s;\n    if(totalScore <= 0) totalScore = 1.0;\n    long double baseScale = (long double)totalScore * totalScore;\n    baseScale /= max(1, M);\n    baseScale /= max(1, D);\n    alphaCoeff = (double)(baseScale * VERTEX_COEFF);\n    betaCoeff  = (double)(baseScale * DAYCOUNT_COEFF);\n    if(!isfinite(alphaCoeff) || alphaCoeff < 1e-9) alphaCoeff = 1e-9;\n    if(!isfinite(betaCoeff)  || betaCoeff  < 1e-9) betaCoeff  = 1e-9;\n    alphaCoeff = min(alphaCoeff, 1e18);\n    betaCoeff  = min(betaCoeff , 1e18);\n\n    long long sumW = 0;\n    for(int w : W) sumW += w;\n    double avgScore = totalScore / M;\n    double avgW = (double)sumW / M;\n    double lengthCoeff = 0.0;\n    if(avgW > 0) lengthCoeff = LENGTH_COEFF_RATIO * avgScore / avgW;\n\n    for(int i=0;i<M;++i){\n        score[i] += lengthCoeff * W[i];\n        if(score[i] <= 0) score[i] = 1e-9;\n    }\n    return score;\n}\n\nvoid move_edge(int eid, int newDay){\n    int oldDay = assignment[eid];\n    if(oldDay == newDay) return;\n    if(oldDay != -1){\n        vector<int> &vec = dayEdges[oldDay];\n        int pos = edgePos[eid];\n        int last = vec.back();\n        if(pos != (int)vec.size()-1){\n            vec[pos] = last;\n            edgePos[last] = pos;\n        }\n        vec.pop_back();\n        dayScore[oldDay] -= edgeScore[eid];\n        dayCount[oldDay]--;\n        vertexDayCount[U[eid]*D + oldDay]--;\n        vertexDayCount[V[eid]*D + oldDay]--;\n    }\n    assignment[eid] = newDay;\n    if(newDay != -1){\n        vector<int> &vec = dayEdges[newDay];\n        edgePos[eid] = vec.size();\n        vec.push_back(eid);\n        dayScore[newDay] += edgeScore[eid];\n        dayCount[newDay]++;\n        vertexDayCount[U[eid]*D + newDay]++;\n        vertexDayCount[V[eid]*D + newDay]++;\n    }else{\n        edgePos[eid] = -1;\n    }\n}\n\ndouble move_delta(int eid, int fromDay, int toDay){\n    double s = edgeScore[eid];\n    double delta = s * (dayScore[toDay] - dayScore[fromDay]);\n    int u = U[eid], v = V[eid];\n    delta += alphaCoeff * ((vertexDayCount[u*D + toDay] + vertexDayCount[v*D + toDay])\n                         - (vertexDayCount[u*D + fromDay] + vertexDayCount[v*D + fromDay]));\n    delta += betaCoeff * (dayCount[toDay] - dayCount[fromDay]);\n    return delta;\n}\n\nbool is_day_connected_with_extra(int day, int extraEdge){\n    DSU dsu(N);\n    for(int eid=0; eid<M; ++eid){\n        if(assignment[eid] == day) continue;\n        if(eid == extraEdge) continue;\n        dsu.unite(U[eid], V[eid]);\n    }\n    return dsu.components == 1;\n}\n\nbool is_day_connected_plain(int day){\n    return is_day_connected_with_extra(day, -1);\n}\n\nint build_components_without_day(int day, vector<int> &comp){\n    DSU dsu(N);\n    for(int eid=0; eid<M; ++eid){\n        if(assignment[eid] == day) continue;\n        dsu.unite(U[eid], V[eid]);\n    }\n    if((int)comp.size() != N) comp.assign(N, 0);\n    vector<int> rootId(N, -1);\n    int comps = 0;\n    for(int i=0;i<N;++i){\n        int r = dsu.find(i);\n        if(rootId[r] == -1){\n            rootId[r] = comps++;\n        }\n        comp[i] = rootId[r];\n    }\n    return comps;\n}\n\nint pick_low_score_edge(int day){\n    if(dayEdges[day].empty()) return -1;\n    int best = dayEdges[day][0];\n    double bestScore = edgeScore[best];\n    for(int eid : dayEdges[day]){\n        if(edgeScore[eid] < bestScore){\n            bestScore = edgeScore[eid];\n            best = eid;\n        }\n    }\n    return best;\n}\n\nbool attempt_swap_move(int eid, int targetDay, bool enforceConnectivity){\n    int fromDay = assignment[eid];\n    int swapEdge = pick_low_score_edge(targetDay);\n    if(swapEdge == -1) return false;\n    move_edge(eid, -1);\n    move_edge(swapEdge, fromDay);\n    move_edge(eid, targetDay);\n    if(enforceConnectivity && !is_day_connected_plain(targetDay)){\n        move_edge(eid, -1);\n        move_edge(swapEdge, targetDay);\n        move_edge(eid, fromDay);\n        return false;\n    }\n    return true;\n}\n\nbool try_move_edge_from_day(int eid, int day){\n    vector<pair<double,int>> withSlot;\n    vector<pair<double,int>> noSlot;\n    for(int d=0; d<D; ++d){\n        if(d == day) continue;\n        double delta = move_delta(eid, day, d);\n        if(dayCount[d] < K){\n            withSlot.emplace_back(delta, d);\n        }else{\n            noSlot.emplace_back(delta, d);\n        }\n    }\n    sort(withSlot.begin(), withSlot.end());\n    for(auto [delta, d] : withSlot){\n        if(is_day_connected_with_extra(d, eid)){\n            move_edge(eid, d);\n            return true;\n        }\n    }\n    for(auto [delta, d] : withSlot){\n        move_edge(eid, d);\n        return true;\n    }\n    sort(noSlot.begin(), noSlot.end());\n    for(auto [delta, d] : noSlot){\n        if(attempt_swap_move(eid, d, true)) return true;\n    }\n    for(auto [delta, d] : noSlot){\n        if(attempt_swap_move(eid, d, false)) return true;\n    }\n    return false;\n}\n\nvoid enforce_connectivity(Timer &timer){\n    vector<int> comp(N);\n    int outerGuard = 0;\n    while(timer.elapsed() < TOTAL_TIME_LIMIT - 0.4 && outerGuard < 4*D){\n        bool changed_any = false;\n        for(int day=0; day<D; ++day){\n            if(timer.elapsed() > TOTAL_TIME_LIMIT - 0.5) return;\n            int guard = 0;\n            while(guard < M){\n                int comps = build_components_without_day(day, comp);\n                if(comps <= 1) break;\n                vector<int> critical;\n                for(int eid : dayEdges[day]){\n                    if(comp[U[eid]] != comp[V[eid]]) critical.push_back(eid);\n                }\n                if(critical.empty()) break;\n                sort(critical.begin(), critical.end(), [&](int a, int b){\n                    if(edgeScore[a] != edgeScore[b]) return edgeScore[a] > edgeScore[b];\n                    return a < b;\n                });\n                bool moved = false;\n                for(int eid : critical){\n                    if(try_move_edge_from_day(eid, day)){\n                        changed_any = true;\n                        moved = true;\n                        break;\n                    }\n                }\n                if(!moved) break;\n                ++guard;\n            }\n        }\n        if(!changed_any) break;\n        ++outerGuard;\n    }\n}\n\nvoid greedy_initial_assignment(){\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b){\n        if(edgeScore[a] != edgeScore[b]) return edgeScore[a] > edgeScore[b];\n        return a < b;\n    });\n    for(int eid : order){\n        double bestVal = numeric_limits<double>::infinity();\n        int bestDay = -1;\n        double s = edgeScore[eid];\n        int u = U[eid], v = V[eid];\n        int baseU = u*D, baseV = v*D;\n        for(int day=0; day<D; ++day){\n            if(dayCount[day] >= K) continue;\n            double val = dayScore[day] * s\n                       + alphaCoeff * (vertexDayCount[baseU + day] + vertexDayCount[baseV + day])\n                       + betaCoeff  * dayCount[day];\n            if(val < bestVal - 1e-12){\n                bestVal = val;\n                bestDay = day;\n            }\n        }\n        if(bestDay == -1){\n            bestDay = min_element(dayCount.begin(), dayCount.end()) - dayCount.begin();\n        }\n        move_edge(eid, bestDay);\n    }\n}\n\nvoid local_search(Timer &timer){\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    bool improved = true;\n    while(improved && timer.elapsed() < LOCAL_SEARCH_LIMIT){\n        improved = false;\n        shuffle(idx.begin(), idx.end(), rng);\n        for(int eid : idx){\n            if(timer.elapsed() > LOCAL_SEARCH_LIMIT) return;\n            int oldDay = assignment[eid];\n            vector<pair<double,int>> cand;\n            cand.reserve(D-1);\n            for(int day=0; day<D; ++day){\n                if(day == oldDay) continue;\n                if(dayCount[day] >= K) continue;\n                double delta = move_delta(eid, oldDay, day);\n                cand.emplace_back(delta, day);\n            }\n            sort(cand.begin(), cand.end());\n            for(auto [delta, day] : cand){\n                if(delta >= -MOVE_EPS) break;\n                if(!is_day_connected_with_extra(day, eid)) continue;\n                move_edge(eid, day);\n                improved = true;\n                break;\n            }\n        }\n    }\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Timer timer;\n    if(!(cin >> N >> M >> D >> K)) return 0;\n    U.resize(M);\n    V.resize(M);\n    W.resize(M);\n    graphAdj.assign(N, {});\n    for(int i=0;i<M;++i){\n        int u,v,w;\n        cin >> u >> v >> w;\n        --u; --v;\n        U[i]=u; V[i]=v; W[i]=w;\n        graphAdj[u].push_back({v,i});\n        graphAdj[v].push_back({u,i});\n    }\n    for(int i=0;i<N;++i){\n        int x,y;\n        cin >> x >> y;\n        (void)x; (void)y;\n    }\n\n    edgeScore = compute_edge_scores(timer);\n\n    assignment.assign(M, -1);\n    dayEdges.assign(D, {});\n    edgePos.assign(M, -1);\n    dayScore.assign(D, 0.0);\n    dayCount.assign(D, 0);\n    vertexDayCount.assign(N*D, 0);\n\n    greedy_initial_assignment();\n    enforce_connectivity(timer);\n    local_search(timer);\n    enforce_connectivity(timer);\n\n    for(int day=0; day<D; ++day){\n        if(!is_day_connected_plain(day)){\n            // fallback: ensure by moving critical edges greedily\n            vector<int> comp(N);\n            while(true){\n                int comps = build_components_without_day(day, comp);\n                if(comps <= 1) break;\n                vector<int> critical;\n                for(int eid : dayEdges[day]){\n                    if(comp[U[eid]] != comp[V[eid]]) critical.push_back(eid);\n                }\n                if(critical.empty()) break;\n                sort(critical.begin(), critical.end(), [&](int a, int b){\n                    if(edgeScore[a] != edgeScore[b]) return edgeScore[a] > edgeScore[b];\n                    return a < b;\n                });\n                bool moved = false;\n                for(int eid : critical){\n                    if(try_move_edge_from_day(eid, day)){\n                        moved = true;\n                        break;\n                    }\n                }\n                if(!moved) break;\n            }\n        }\n    }\n\n    for(int eid=0; eid<M; ++eid){\n        if(assignment[eid] == -1){\n            int bestDay = min_element(dayCount.begin(), dayCount.end()) - dayCount.begin();\n            move_edge(eid, bestDay);\n        }\n    }\n\n    for(int day=0; day<D; ++day){\n        dayCount[day] = dayEdges[day].size();\n    }\n\n    for(int i=0;i<M;++i){\n        if(i) cout << ' ';\n        cout << assignment[i] + 1;\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Segment {\n    int x, y;\n    int z0;\n    int len;\n};\n\nstruct Builder {\n    bool active = false;\n    int start = 0;\n    int len = 0;\n};\n\nstruct LayerAssign {\n    vector<pair<int, int>> pairs;\n    vector<int> assigned_y_for_x;\n    vector<int> assigned_x_for_y;\n};\n\nLayerAssign assign_x_major(\n        int D,\n        const vector<int>& X,\n        const vector<int>& Y,\n        const vector<int>& prev_y_for_x,\n        const vector<int>& prev_x_for_y) {\n\n    LayerAssign res;\n    res.assigned_y_for_x.assign(D, -1);\n    res.assigned_x_for_y.assign(D, -1);\n    vector<char> x_present(D, 0), y_present(D, 0);\n    for (int x : X) x_present[x] = 1;\n    for (int y : Y) y_present[y] = 1;\n\n    vector<char> x_assigned(D, 0);\n\n    auto choose_x_with_prev = [&](int target_y) -> int {\n        for (int x : X) if (!x_assigned[x] && prev_y_for_x[x] == target_y) return x;\n        return -1;\n    };\n    auto choose_any_x = [&]() -> int {\n        for (int x : X) if (!x_assigned[x]) return x;\n        return -1;\n    };\n\n    for (int y : Y) {\n        int x = choose_x_with_prev(y);\n        if (x == -1) x = choose_any_x();\n        if (x == -1) x = X.front(); // safety\n        x_assigned[x] = 1;\n        res.assigned_y_for_x[x] = y;\n        res.assigned_x_for_y[y] = x;\n        res.pairs.emplace_back(x, y);\n    }\n\n    if (!Y.empty()) {\n        size_t ptr = 0;\n        for (int x : X) {\n            if (x_assigned[x]) continue;\n            int y = -1;\n            if (prev_y_for_x[x] != -1 && y_present[prev_y_for_x[x]]) {\n                y = prev_y_for_x[x];\n            } else {\n                y = Y[ptr];\n                ptr = (ptr + 1) % Y.size();\n            }\n            x_assigned[x] = 1;\n            res.assigned_y_for_x[x] = y;\n            res.assigned_x_for_y[y] = x;\n            res.pairs.emplace_back(x, y);\n        }\n    }\n\n    return res;\n}\n\nLayerAssign assign_y_major(\n        int D,\n        const vector<int>& X,\n        const vector<int>& Y,\n        const vector<int>& prev_y_for_x,\n        const vector<int>& prev_x_for_y) {\n\n    LayerAssign res;\n    res.assigned_y_for_x.assign(D, -1);\n    res.assigned_x_for_y.assign(D, -1);\n    vector<char> x_present(D, 0), y_present(D, 0);\n    for (int x : X) x_present[x] = 1;\n    for (int y : Y) y_present[y] = 1;\n\n    vector<char> y_assigned(D, 0);\n\n    auto choose_y_with_prev = [&](int target_x) -> int {\n        for (int y : Y) if (!y_assigned[y] && prev_x_for_y[y] == target_x) return y;\n        return -1;\n    };\n    auto choose_any_y = [&]() -> int {\n        for (int y : Y) if (!y_assigned[y]) return y;\n        return -1;\n    };\n\n    for (int x : X) {\n        int y = choose_y_with_prev(x);\n        if (y == -1) y = choose_any_y();\n        if (y == -1) y = Y.front(); // safety\n        y_assigned[y] = 1;\n        res.assigned_y_for_x[x] = y;\n        res.assigned_x_for_y[y] = x;\n        res.pairs.emplace_back(x, y);\n    }\n\n    if (!X.empty()) {\n        size_t ptr = 0;\n        for (int y : Y) {\n            if (y_assigned[y]) continue;\n            int x = -1;\n            if (prev_x_for_y[y] != -1 && x_present[prev_x_for_y[y]]) {\n                x = prev_x_for_y[y];\n            } else {\n                x = X[ptr];\n                ptr = (ptr + 1) % X.size();\n            }\n            y_assigned[y] = 1;\n            res.assigned_x_for_y[y] = x;\n            res.assigned_y_for_x[x] = y;\n            res.pairs.emplace_back(x, y);\n        }\n    }\n\n    return res;\n}\n\nvector<Segment> build_segments(int D, const vector<string>& front, const vector<string>& right) {\n    vector<Segment> segments;\n    vector<vector<Builder>> builder(D, vector<Builder>(D));\n    vector<vector<char>> stay(D, vector<char>(D, 0));\n    vector<int> prev_y_for_x(D, -1), prev_x_for_y(D, -1);\n\n    for (int z = 0; z < D; ++z) {\n        vector<int> X, Y;\n        for (int x = 0; x < D; ++x) if (front[z][x] == '1') X.push_back(x);\n        for (int y = 0; y < D; ++y) if (right[z][y] == '1') Y.push_back(y);\n\n        LayerAssign assign = (X.size() >= Y.size())\n                             ? assign_x_major(D, X, Y, prev_y_for_x, prev_x_for_y)\n                             : assign_y_major(D, X, Y, prev_y_for_x, prev_x_for_y);\n\n        for (int x = 0; x < D; ++x) fill(stay[x].begin(), stay[x].end(), 0);\n        for (auto [x, y] : assign.pairs) {\n            if (!builder[x][y].active) {\n                builder[x][y].active = true;\n                builder[x][y].start = z;\n                builder[x][y].len = 0;\n            }\n            builder[x][y].len++;\n            stay[x][y] = 1;\n        }\n\n        for (int x = 0; x < D; ++x) {\n            for (int y = 0; y < D; ++y) {\n                if (builder[x][y].active && !stay[x][y]) {\n                    segments.push_back({x, y, builder[x][y].start, builder[x][y].len});\n                    builder[x][y].active = false;\n                }\n            }\n        }\n\n        prev_y_for_x = assign.assigned_y_for_x;\n        prev_x_for_y = assign.assigned_x_for_y;\n    }\n\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            if (builder[x][y].active) {\n                segments.push_back({x, y, builder[x][y].start, builder[x][y].len});\n                builder[x][y].active = false;\n            }\n        }\n    }\n    return segments;\n}\n\nstruct MatchResult {\n    vector<int> block_id0;\n    vector<int> block_id1;\n    int total_blocks;\n};\n\nstruct PQNode {\n    int len;\n    int idx;\n};\nstruct PQCmp {\n    bool operator()(const PQNode& a, const PQNode& b) const {\n        return a.len < b.len; // max-heap\n    }\n};\n\nPQNode pop_valid(priority_queue<PQNode, vector<PQNode>, PQCmp>& pq,\n                 const vector<Segment>& segs,\n                 const vector<int>& blockId) {\n    while (!pq.empty()) {\n        PQNode node = pq.top();\n        pq.pop();\n        if (node.idx >= (int)segs.size()) continue;\n        if (blockId[node.idx] != -1) continue;\n        if (segs[node.idx].len != node.len) {\n            pq.push({segs[node.idx].len, node.idx});\n            continue;\n        }\n        return node;\n    }\n    return {-1, -1};\n}\n\nMatchResult match_segments(vector<Segment>& seg0, vector<Segment>& seg1) {\n    vector<int> blockId0(seg0.size(), -1), blockId1(seg1.size(), -1);\n    priority_queue<PQNode, vector<PQNode>, PQCmp> pq0, pq1;\n    for (int i = 0; i < (int)seg0.size(); ++i) pq0.push({seg0[i].len, i});\n    for (int i = 0; i < (int)seg1.size(); ++i) pq1.push({seg1[i].len, i});\n    int nextId = 1;\n\n    auto split_segment = [&](vector<Segment>& segs, vector<int>& blockId, int idx, int take_len) -> int {\n        Segment& seg = segs[idx];\n        Segment newSeg{seg.x, seg.y, seg.z0, take_len};\n        seg.z0 += take_len;\n        seg.len -= take_len;\n        int newIdx = segs.size();\n        segs.push_back(newSeg);\n        blockId.push_back(-1);\n        return newIdx;\n    };\n\n    while (true) {\n        PQNode node0 = pop_valid(pq0, seg0, blockId0);\n        if (node0.idx == -1) break;\n        PQNode node1 = pop_valid(pq1, seg1, blockId1);\n        if (node1.idx == -1) {\n            pq0.push({seg0[node0.idx].len, node0.idx});\n            break;\n        }\n        int idx0 = node0.idx, idx1 = node1.idx;\n        int len0 = node0.len, len1 = node1.len;\n        if (len0 == len1) {\n            blockId0[idx0] = blockId1[idx1] = nextId++;\n        } else if (len0 > len1) {\n            int newIdx = split_segment(seg0, blockId0, idx0, len1);\n            blockId0[newIdx] = blockId1[idx1] = nextId++;\n            pq0.push({seg0[idx0].len, idx0});\n        } else {\n            int newIdx = split_segment(seg1, blockId1, idx1, len0);\n            blockId0[idx0] = blockId1[newIdx] = nextId++;\n            pq1.push({seg1[idx1].len, idx1});\n        }\n    }\n\n    for (int i = 0; i < (int)seg0.size(); ++i) {\n        if (blockId0[i] == -1) blockId0[i] = nextId++;\n    }\n    for (int i = 0; i < (int)seg1.size(); ++i) {\n        if (blockId1[i] == -1) blockId1[i] = nextId++;\n    }\n\n    return {blockId0, blockId1, nextId - 1};\n}\n\nbool verify(int D, const vector<int>& grid,\n            const vector<string>& front, const vector<string>& right) {\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n    for (int z = 0; z < D; ++z) {\n        for (int x = 0; x < D; ++x) {\n            bool occ = false;\n            for (int y = 0; y < D; ++y) if (grid[idx(x, y, z)]) { occ = true; break; }\n            if (occ != (front[z][x] == '1')) return false;\n        }\n        for (int y = 0; y < D; ++y) {\n            bool occ = false;\n            for (int x = 0; x < D; ++x) if (grid[idx(x, y, z)]) { occ = true; break; }\n            if (occ != (right[z][y] == '1')) return false;\n        }\n    }\n    return true;\n}\n\nstruct Cell { int x, y, z; };\n\nvector<Cell> build_min_cells(int D, const vector<string>& front, const vector<string>& right) {\n    vector<Cell> cells;\n    for (int z = 0; z < D; ++z) {\n        vector<int> xs, ys;\n        for (int x = 0; x < D; ++x) if (front[z][x] == '1') xs.push_back(x);\n        for (int y = 0; y < D; ++y) if (right[z][y] == '1') ys.push_back(y);\n        if (xs.empty()) xs.push_back(0);\n        if (ys.empty()) ys.push_back(0);\n        if ((int)xs.size() >= (int)ys.size()) {\n            for (size_t i = 0; i < xs.size(); ++i)\n                cells.push_back({xs[i], ys[i % ys.size()], z});\n        } else {\n            for (size_t i = 0; i < ys.size(); ++i)\n                cells.push_back({xs[i % xs.size()], ys[i], z});\n        }\n    }\n    return cells;\n}\n\ntuple<int, vector<int>, vector<int>> baseline_solution(\n        int D,\n        const vector<string>& f0, const vector<string>& r0,\n        const vector<string>& f1, const vector<string>& r1) {\n    vector<Cell> c0 = build_min_cells(D, f0, r0);\n    vector<Cell> c1 = build_min_cells(D, f1, r1);\n    int n = max(c0.size(), c1.size());\n    vector<int> grid0(D * D * D, 0), grid1(D * D * D, 0);\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n    for (size_t i = 0; i < c0.size(); ++i) grid0[idx(c0[i].x, c0[i].y, c0[i].z)] = i + 1;\n    for (size_t i = 0; i < c1.size(); ++i) grid1[idx(c1[i].x, c1[i].y, c1[i].z)] = i + 1;\n    return {n, grid0, grid1};\n}\n\nbool build_advanced(\n        int D,\n        const vector<string>& f0, const vector<string>& r0,\n        const vector<string>& f1, const vector<string>& r1,\n        int& n,\n        vector<int>& grid0,\n        vector<int>& grid1) {\n\n    vector<Segment> seg0 = build_segments(D, f0, r0);\n    vector<Segment> seg1 = build_segments(D, f1, r1);\n\n    MatchResult match = match_segments(seg0, seg1);\n    n = match.total_blocks;\n    grid0.assign(D * D * D, 0);\n    grid1.assign(D * D * D, 0);\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n\n    for (int i = 0; i < (int)seg0.size(); ++i) {\n        int bid = match.block_id0[i];\n        for (int dz = 0; dz < seg0[i].len; ++dz) {\n            int z = seg0[i].z0 + dz;\n            grid0[idx(seg0[i].x, seg0[i].y, z)] = bid;\n        }\n    }\n    for (int i = 0; i < (int)seg1.size(); ++i) {\n        int bid = match.block_id1[i];\n        for (int dz = 0; dz < seg1[i].len; ++dz) {\n            int z = seg1[i].z0 + dz;\n            grid1[idx(seg1[i].x, seg1[i].y, z)] = bid;\n        }\n    }\n    if (!verify(D, grid0, f0, r0)) return false;\n    if (!verify(D, grid1, f1, r1)) return false;\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int D;\n    if (!(cin >> D)) return 0;\n    vector<vector<string>> front(2, vector<string>(D));\n    vector<vector<string>> right(2, vector<string>(D));\n    for (int i = 0; i < 2; ++i) {\n        for (int z = 0; z < D; ++z) cin >> front[i][z];\n        for (int z = 0; z < D; ++z) cin >> right[i][z];\n    }\n\n    int n;\n    vector<int> grid0, grid1;\n    if (!build_advanced(D, front[0], right[0], front[1], right[1], n, grid0, grid1)) {\n        tie(n, grid0, grid1) = baseline_solution(D, front[0], right[0], front[1], right[1]);\n    }\n\n    cout << n << '\\n';\n    for (int i = 0; i < D * D * D; ++i) {\n        if (i) cout << ' ';\n        cout << grid0[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < D * D * D; ++i) {\n        if (i) cout << ' ';\n        cout << grid1[i];\n    }\n    cout << '\\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};\nstruct AdjEdge {\n    int to;\n    long long w;\n    int id;\n};\nstruct Candidate {\n    long long dist;\n    int to;\n};\n\nstruct Solver {\n    int N, M, K;\n    vector<long long> xs, ys;\n    vector<long long> ax, ay;\n    vector<Edge> edges;\n    vector<vector<AdjEdge>> graph;\n\n    const long long INF64 = (1LL << 60);\n    const long long MAX_RAD_SQ = 5000LL * 5000LL;\n\n    vector<vector<long long>> distMat;\n    vector<vector<int>> parentEdge;\n    vector<vector<int>> parentVertex;\n\n    vector<vector<Candidate>> resCandidates;\n\n    vector<int> assignStation;\n    vector<long long> distAssigned;\n\n    vector<vector<int>> residentsOfStation;\n    vector<long long> maxDist;\n    vector<int> P;\n    vector<char> broadcast;\n\n    long long currentPcost = 0;\n    long long currentTreeCost = 0;\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M >> K)) return;\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; ++i) cin >> xs[i] >> ys[i];\n        edges.resize(M);\n        graph.assign(N, {});\n        for (int j = 0; j < M; ++j) {\n            int u, v;\n            long long w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[j] = {u, v, w};\n            graph[u].push_back({v, w, j});\n            graph[v].push_back({u, w, j});\n        }\n        ax.resize(K);\n        ay.resize(K);\n        for (int i = 0; i < K; ++i) cin >> ax[i] >> ay[i];\n\n        computeAllPairs();\n        buildResidentCandidates();\n        initialAssignment();\n\n        residentsOfStation.assign(N, {});\n        maxDist.assign(N, 0);\n        P.assign(N, 0);\n        broadcast.assign(N, false);\n\n        rebuildAll();\n        optimize();\n\n        vector<int> edgeOn(M, 0);\n        buildFinalEdges(edgeOn);\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << P[i];\n        }\n        cout << '\\n';\n        for (int j = 0; j < M; ++j) {\n            if (j) cout << ' ';\n            cout << edgeOn[j];\n        }\n        cout << '\\n';\n    }\n\n    void computeAllPairs() {\n        distMat.assign(N, vector<long long>(N, INF64));\n        parentEdge.assign(N, vector<int>(N, -1));\n        parentVertex.assign(N, vector<int>(N, -1));\n        for (int s = 0; s < N; ++s) {\n            vector<long long> dist(N, INF64);\n            vector<int> prevE(N, -1), prevV(N, -1);\n            dist[s] = 0;\n            using Node = pair<long long, int>;\n            priority_queue<Node, vector<Node>, greater<Node>> pq;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [d, v] = pq.top();\n                pq.pop();\n                if (d != dist[v]) continue;\n                for (const auto &ed : graph[v]) {\n                    int to = ed.to;\n                    long long nd = d + ed.w;\n                    if (nd < dist[to]) {\n                        dist[to] = nd;\n                        prevE[to] = ed.id;\n                        prevV[to] = v;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n            distMat[s] = dist;\n            parentEdge[s] = prevE;\n            parentVertex[s] = prevV;\n        }\n    }\n\n    void buildResidentCandidates() {\n        resCandidates.assign(K, {});\n        vector<pair<long long, int>> tmp;\n        tmp.reserve(N);\n        for (int k = 0; k < K; ++k) {\n            tmp.clear();\n            for (int i = 0; i < N; ++i) {\n                long long dx = xs[i] - ax[k];\n                long long dy = ys[i] - ay[k];\n                long long d = dx * dx + dy * dy;\n                tmp.emplace_back(d, i);\n            }\n            sort(tmp.begin(), tmp.end());\n            vector<Candidate> cand;\n            cand.reserve(N);\n            bool hasWithin = false;\n            for (auto &p : tmp) {\n                if (p.first <= MAX_RAD_SQ) {\n                    cand.push_back({p.first, p.second});\n                    hasWithin = true;\n                } else if (hasWithin) {\n                    break;\n                }\n            }\n            if (cand.empty()) cand.push_back({tmp[0].first, tmp[0].second});\n            resCandidates[k] = move(cand);\n        }\n    }\n\n    void initialAssignment() {\n        assignStation.assign(K, 0);\n        distAssigned.assign(K, 0);\n        for (int k = 0; k < K; ++k) {\n            if (resCandidates[k].empty()) {\n                assignStation[k] = 0;\n                distAssigned[k] = 0;\n            } else {\n                assignStation[k] = resCandidates[k][0].to;\n                long long d = resCandidates[k][0].dist;\n                if (d > MAX_RAD_SQ) d = MAX_RAD_SQ;\n                distAssigned[k] = d;\n            }\n        }\n    }\n\n    int ceil_sqrt_ll(long long v) const {\n        if (v <= 0) return 0;\n        long double r = sqrt((long double)v);\n        long long x = (long long)r;\n        while (x * x < v) ++x;\n        while (x > 0 && (x - 1) * (x - 1) >= v) --x;\n        if (x > 5000) x = 5000;\n        return (int)x;\n    }\n\n    void rebuildAll() {\n        for (int i = 0; i < N; ++i) {\n            residentsOfStation[i].clear();\n            maxDist[i] = 0;\n        }\n        for (int k = 0; k < K; ++k) {\n            int st = assignStation[k];\n            residentsOfStation[st].push_back(k);\n            if (distAssigned[k] > maxDist[st]) maxDist[st] = distAssigned[k];\n        }\n        currentPcost = 0;\n        for (int i = 0; i < N; ++i) {\n            if (!residentsOfStation[i].empty()) {\n                broadcast[i] = 1;\n                P[i] = ceil_sqrt_ll(maxDist[i]);\n            } else {\n                broadcast[i] = 0;\n                maxDist[i] = 0;\n                P[i] = 0;\n            }\n            currentPcost += 1LL * P[i] * P[i];\n        }\n        currentTreeCost = computeCurrentMST();\n    }\n\n    long long computeMSTNodes(const vector<int> &nodes) {\n        if (nodes.size() <= 1) return 0;\n        vector<long long> key(nodes.size(), INF64);\n        vector<int> parent(nodes.size(), -1);\n        vector<char> used(nodes.size(), false);\n        key[0] = 0;\n        long long total = 0;\n        for (size_t it = 0; it < nodes.size(); ++it) {\n            int u = -1;\n            long long best = INF64;\n            for (size_t i = 0; i < nodes.size(); ++i) {\n                if (!used[i] && key[i] < best) {\n                    best = key[i];\n                    u = (int)i;\n                }\n            }\n            if (u == -1) break;\n            used[u] = true;\n            total += key[u];\n            for (size_t v = 0; v < nodes.size(); ++v) {\n                if (used[v]) continue;\n                long long d = distMat[nodes[u]][nodes[v]];\n                if (d < key[v]) {\n                    key[v] = d;\n                    parent[v] = u;\n                }\n            }\n        }\n        return total;\n    }\n\n    long long computeCurrentMST() {\n        vector<int> nodes;\n        nodes.reserve(N);\n        nodes.push_back(0);\n        for (int i = 1; i < N; ++i) {\n            if (broadcast[i]) nodes.push_back(i);\n        }\n        return computeMSTNodes(nodes);\n    }\n\n    bool tryRemove(int s) {\n        if (!broadcast[s]) return false;\n        vector<int> resList = residentsOfStation[s];\n        if (resList.empty()) return false;\n\n        int R = resList.size();\n        vector<long long> firstAlt(R, INF64);\n        for (int idx = 0; idx < R; ++idx) {\n            int rid = resList[idx];\n            for (const auto &cand : resCandidates[rid]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                if (cand.to == s) continue;\n                if (!broadcast[cand.to]) continue;\n                firstAlt[idx] = cand.dist;\n                break;\n            }\n            if (firstAlt[idx] == INF64) return false;\n        }\n\n        vector<int> order(R);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (firstAlt[a] != firstAlt[b]) return firstAlt[a] > firstAlt[b];\n            return resList[a] < resList[b];\n        });\n\n        vector<long long> tempMax = maxDist;\n        vector<int> tempP = P;\n        vector<int> chosenStation(R, -1);\n        vector<long long> chosenDist(R, 0);\n\n        for (int ordIdx : order) {\n            int idx = ordIdx;\n            int rid = resList[idx];\n            long long bestDelta = INF64;\n            int bestT = -1;\n            long long bestD = 0;\n            int bestNewP = 0;\n            long long bestNewMax = INF64;\n            for (const auto &cand : resCandidates[rid]) {\n                long long dist = cand.dist;\n                if (dist > MAX_RAD_SQ) break;\n                int t = cand.to;\n                if (t == s) continue;\n                if (!broadcast[t]) continue;\n                long long curMax = tempMax[t];\n                int curP = tempP[t];\n                long long newMax = curMax;\n                int newP = curP;\n                if (dist > newMax) {\n                    newMax = dist;\n                    newP = ceil_sqrt_ll(newMax);\n                }\n                long long delta = 1LL * newP * newP - 1LL * curP * curP;\n                if (bestT == -1 || delta < bestDelta || (delta == bestDelta && newMax < bestNewMax)) {\n                    bestDelta = delta;\n                    bestT = t;\n                    bestD = dist;\n                    bestNewP = newP;\n                    bestNewMax = newMax;\n                }\n            }\n            if (bestT == -1) return false;\n            chosenStation[idx] = bestT;\n            chosenDist[idx] = bestD;\n            tempMax[bestT] = bestNewMax;\n            tempP[bestT] = bestNewP;\n        }\n\n        tempMax[s] = 0;\n        tempP[s] = 0;\n\n        long long newPcost = 0;\n        vector<int> nodesAfter;\n        nodesAfter.reserve(N);\n        nodesAfter.push_back(0);\n        for (int i = 0; i < N; ++i) {\n            newPcost += 1LL * tempP[i] * tempP[i];\n            if (i > 0 && tempP[i] > 0) nodesAfter.push_back(i);\n        }\n        long long newTreeCost = computeMSTNodes(nodesAfter);\n        long long currentTotal = currentPcost + currentTreeCost;\n        long long newTotal = newPcost + newTreeCost;\n        if (newTotal >= currentTotal) return false;\n\n        for (int idx = 0; idx < R; ++idx) {\n            int rid = resList[idx];\n            assignStation[rid] = chosenStation[idx];\n            distAssigned[rid] = chosenDist[idx];\n        }\n        rebuildAll();\n        return true;\n    }\n\n    bool tryReassignAll() {\n        vector<int> newAssign(K);\n        vector<long long> newDist(K);\n        bool changed = false;\n        for (int r = 0; r < K; ++r) {\n            int bestStation = -1;\n            long long bestDist = 0;\n            for (const auto &cand : resCandidates[r]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                if (!broadcast[cand.to]) continue;\n                bestStation = cand.to;\n                bestDist = cand.dist;\n                break;\n            }\n            if (bestStation == -1) return false;\n            newAssign[r] = bestStation;\n            newDist[r] = bestDist;\n            if (bestStation != assignStation[r]) changed = true;\n        }\n        if (!changed) return false;\n\n        vector<long long> newMax(N, 0);\n        vector<int> counts(N, 0);\n        for (int r = 0; r < K; ++r) {\n            int st = newAssign[r];\n            ++counts[st];\n            if (newDist[r] > newMax[st]) newMax[st] = newDist[r];\n        }\n        vector<int> newP(N, 0);\n        vector<char> newBroadcast(N, 0);\n        long long newPcost = 0;\n        for (int i = 0; i < N; ++i) {\n            if (counts[i] > 0) {\n                newBroadcast[i] = 1;\n                newP[i] = ceil_sqrt_ll(newMax[i]);\n            } else {\n                newBroadcast[i] = 0;\n                newP[i] = 0;\n            }\n            newPcost += 1LL * newP[i] * newP[i];\n        }\n        vector<int> nodesAfter;\n        nodesAfter.reserve(N);\n        nodesAfter.push_back(0);\n        for (int i = 1; i < N; ++i) if (newBroadcast[i]) nodesAfter.push_back(i);\n        long long newTreeCost = computeMSTNodes(nodesAfter);\n        long long currentTotal = currentPcost + currentTreeCost;\n        long long newTotal = newPcost + newTreeCost;\n        if (newTotal >= currentTotal) return false;\n\n        assignStation.swap(newAssign);\n        distAssigned.swap(newDist);\n        rebuildAll();\n        return true;\n    }\n\n    bool improveSingleFarMove() {\n        vector<int> order;\n        order.reserve(N);\n        for (int i = 0; i < N; ++i) if (broadcast[i]) order.push_back(i);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (P[a] != P[b]) return P[a] > P[b];\n            return residentsOfStation[a].size() > residentsOfStation[b].size();\n        });\n        for (int s : order) {\n            if ((int)residentsOfStation[s].size() <= 1) continue;\n            int farRes = -1;\n            long long farDist = -1;\n            for (int r : residentsOfStation[s]) {\n                if (distAssigned[r] > farDist) {\n                    farDist = distAssigned[r];\n                    farRes = r;\n                }\n            }\n            if (farRes == -1) continue;\n            long long newMaxS = 0;\n            for (int r : residentsOfStation[s]) {\n                if (r == farRes) continue;\n                if (distAssigned[r] > newMaxS) newMaxS = distAssigned[r];\n            }\n            int newPs = ceil_sqrt_ll(newMaxS);\n            int oldPs = P[s];\n            long long bestDelta = 0;\n            int bestTarget = -1;\n            long long bestDist = 0;\n            for (const auto &cand : resCandidates[farRes]) {\n                long long dist = cand.dist;\n                if (dist > MAX_RAD_SQ) break;\n                int t = cand.to;\n                if (t == s) continue;\n                if (!broadcast[t]) continue;\n                long long newMaxT = max(maxDist[t], dist);\n                int newPt = ceil_sqrt_ll(newMaxT);\n                long long delta = 1LL * newPs * newPs + 1LL * newPt * newPt - (1LL * oldPs * oldPs + 1LL * P[t] * P[t]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestTarget = t;\n                    bestDist = dist;\n                }\n            }\n            if (bestTarget != -1) {\n                assignStation[farRes] = bestTarget;\n                distAssigned[farRes] = bestDist;\n                rebuildAll();\n                return true;\n            }\n        }\n        return false;\n    }\n\n    void optimize() {\n        while (true) {\n            bool changed = false;\n            while (true) {\n                vector<int> order;\n                order.reserve(N);\n                for (int i = 0; i < N; ++i) if (broadcast[i]) order.push_back(i);\n                sort(order.begin(), order.end(), [&](int a, int b) {\n                    if (residentsOfStation[a].size() != residentsOfStation[b].size())\n                        return residentsOfStation[a].size() < residentsOfStation[b].size();\n                    if (P[a] != P[b]) return P[a] < P[b];\n                    return a < b;\n                });\n                bool removed = false;\n                for (int s : order) {\n                    if (tryRemove(s)) {\n                        changed = true;\n                        removed = true;\n                        break;\n                    }\n                }\n                if (!removed) break;\n            }\n            if (tryReassignAll()) {\n                changed = true;\n                continue;\n            }\n            if (improveSingleFarMove()) {\n                changed = true;\n                continue;\n            }\n            if (!changed) break;\n        }\n    }\n\n    void recomputeSP(int s) {\n        vector<long long> dist(N, INF64);\n        vector<int> prevE(N, -1), prevV(N, -1);\n        dist[s] = 0;\n        using Node = pair<long long, int>;\n        priority_queue<Node, vector<Node>, greater<Node>> pq;\n        pq.push({0, s});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            for (const auto &ed : graph[v]) {\n                int to = ed.to;\n                long long nd = d + ed.w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    prevE[to] = ed.id;\n                    prevV[to] = v;\n                    pq.push({nd, to});\n                }\n            }\n        }\n        distMat[s] = dist;\n        parentEdge[s] = prevE;\n        parentVertex[s] = prevV;\n    }\n\n    void addPath(int s, int t, vector<int> &edgeOn) {\n        if (s == t) return;\n        int cur = t;\n        while (cur != s) {\n            int e = parentEdge[s][cur];\n            int pv = parentVertex[s][cur];\n            if (e == -1 || pv == -1) {\n                recomputeSP(s);\n                e = parentEdge[s][cur];\n                pv = parentVertex[s][cur];\n                if (e == -1 || pv == -1) break;\n            }\n            edgeOn[e] = 1;\n            cur = pv;\n        }\n    }\n\n    void buildFinalEdges(vector<int> &edgeOn) {\n        fill(edgeOn.begin(), edgeOn.end(), 0);\n        vector<int> nodes;\n        nodes.reserve(N);\n        nodes.push_back(0);\n        for (int i = 1; i < N; ++i) if (broadcast[i]) nodes.push_back(i);\n        if (nodes.size() <= 1) return;\n        int T = nodes.size();\n        vector<long long> key(T, INF64);\n        vector<int> parent(T, -1);\n        vector<char> used(T, false);\n        key[0] = 0;\n        for (int iter = 0; iter < T; ++iter) {\n            int u = -1;\n            long long best = INF64;\n            for (int i = 0; i < T; ++i) {\n                if (!used[i] && key[i] < best) {\n                    best = key[i];\n                    u = i;\n                }\n            }\n            if (u == -1) break;\n            used[u] = true;\n            if (parent[u] != -1) {\n                addPath(nodes[u], nodes[parent[u]], edgeOn);\n            }\n            for (int v = 0; v < T; ++v) {\n                if (used[v]) continue;\n                long long d = distMat[nodes[u]][nodes[v]];\n                if (d < key[v]) {\n                    key[v] = d;\n                    parent[v] = u;\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    constexpr 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) {\n            if (!(cin >> a[x][y])) return 0;\n        }\n    }\n\n    vector<array<int, 4>> ops;\n    ops.reserve(5000);\n\n    auto swapBall = [&](int x1, int y1, int x2, int y2) {\n        ops.push_back({x1, y1, x2, y2});\n        swap(a[x1][y1], a[x2][y2]);\n    };\n\n    for (int x = N - 2; x >= 0; --x) {\n        for (int y = 0; y <= x; ++y) {\n            int cx = x, cy = y;\n            while (cx < N - 1) {\n                int bestY = cy;\n                int bestVal = a[cx + 1][cy];\n                int rightVal = a[cx + 1][cy + 1];\n                if (rightVal < bestVal) {\n                    bestVal = rightVal;\n                    bestY = cy + 1;\n                }\n                if (a[cx][cy] <= bestVal) break;\n                swapBall(cx, cy, cx + 1, bestY);\n                ++cx;\n                cy = bestY;\n            }\n        }\n    }\n\n    assert(ops.size() <= 10000);\n\n    cout << ops.size() << '\\n';\n    for (auto &op : ops) {\n        cout << op[0] << ' ' << op[1] << ' ' << op[2] << ' ' << op[3] << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int DX[4] = {1, -1, 0, 0};\nconst int DY[4] = {0, 0, 1, -1};\n\nconst int EMPTY     = -1;\nconst int ENTRANCE  = -2;\nconst int OBSTACLE  = -3;\nconst int TEMPBLOCK = -4;\n\nint D;\nint entrance_i, entrance_j;\nvector<vector<int>> grid;\nvector<vector<int>> dist_from_entrance;\nvector<pair<int,int>> target_order;          // preferred retrieval order (near entrance first)\nvector<vector<int>> target_rank;             // index inside target_order\nint total_cells = 0;\nint empty_cells_remaining = 0;\nlong long tie_counter = 0;\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < D && 0 <= y && y < D;\n}\n\nvector<vector<int>> compute_dist(const vector<vector<int>>& base_grid) {\n    const int INF = 1e9;\n    vector<vector<int>> dist(D, vector<int>(D, INF));\n    queue<pair<int,int>> q;\n    q.push({entrance_i, entrance_j});\n    dist[entrance_i][entrance_j] = 0;\n    while (!q.empty()) {\n        auto [x, y] = q.front(); q.pop();\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = x + DX[dir];\n            int ny = y + DY[dir];\n            if (!inside(nx, ny)) continue;\n            if (base_grid[nx][ny] == OBSTACLE) continue;\n            if (dist[nx][ny] != INF) continue;\n            dist[nx][ny] = dist[x][y] + 1;\n            q.push({nx, ny});\n        }\n    }\n    return dist;\n}\n\nbool is_safe_offline(vector<vector<int>>& state, int x, int y, int remain) {\n    if (state[x][y] != 0) return false;\n    state[x][y] = -1;\n    queue<int> q;\n    vector<char> visited(D * D, 0);\n    int start = entrance_i * D + entrance_j;\n    q.push(start);\n    visited[start] = 1;\n    int reachable = 0;\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int cx = v / D;\n        int cy = v % D;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = cx + DX[dir];\n            int ny = cy + DY[dir];\n            if (!inside(nx, ny)) continue;\n            int nid = nx * D + ny;\n            if (visited[nid]) continue;\n            if (state[nx][ny] == -1) continue;\n            visited[nid] = 1;\n            q.push(nid);\n            if (state[nx][ny] == 0) ++reachable;\n        }\n    }\n    state[x][y] = 0;\n    return reachable == remain - 1;\n}\n\nvector<pair<int,int>> compute_target_order(const vector<vector<int>>& base_grid) {\n    vector<vector<int>> state(D, vector<int>(D, -1));\n    int remain = 0;\n    for (int i = 0; i < D; ++i) {\n        for (int j = 0; j < D; ++j) {\n            if (base_grid[i][j] == OBSTACLE) continue;\n            if (i == entrance_i && j == entrance_j) {\n                state[i][j] = -2;              // entrance\n            } else {\n                state[i][j] = 0;\n                ++remain;\n            }\n        }\n    }\n\n    vector<pair<int,int>> elimination;\n    elimination.reserve(remain);\n\n    while (remain > 0) {\n        pair<int,int> best = {-1, -1};\n        int bestScore = INT_MIN;\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (state[i][j] != 0) continue;\n                if (!is_safe_offline(state, i, j, remain)) continue;\n                int score = dist_from_entrance[i][j] * 1000 - (abs(i - entrance_i) + abs(j - entrance_j));\n                if (score > bestScore) {\n                    bestScore = score;\n                    best = {i, j};\n                }\n            }\n        }\n        if (best.first == -1) {\n            // Should not happen, but fall back to any available cell.\n            for (int i = 0; i < D && best.first == -1; ++i) {\n                for (int j = 0; j < D; ++j) {\n                    if (state[i][j] == 0) {\n                        best = {i, j};\n                        break;\n                    }\n                }\n            }\n        }\n        elimination.push_back(best);\n        state[best.first][best.second] = -1;\n        --remain;\n    }\n\n    vector<pair<int,int>> retrieval = elimination;\n    reverse(retrieval.begin(), retrieval.end());\n    return retrieval;\n}\n\nbool is_safe_cell(int x, int y) {\n    grid[x][y] = TEMPBLOCK;\n    queue<int> q;\n    vector<char> visited(D * D, 0);\n    int start = entrance_i * D + entrance_j;\n    q.push(start);\n    visited[start] = 1;\n    int reachable = 0;\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int cx = v / D;\n        int cy = v % D;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = cx + DX[dir];\n            int ny = cy + DY[dir];\n            if (!inside(nx, ny)) continue;\n            int nid = nx * D + ny;\n            if (visited[nid]) continue;\n            int val = grid[nx][ny];\n            if (val == OBSTACLE || val == TEMPBLOCK) continue;\n            if (val >= 0) continue;                       // occupied container\n            visited[nid] = 1;\n            q.push(nid);\n            if (val == EMPTY) ++reachable;\n        }\n    }\n    grid[x][y] = EMPTY;\n    return reachable == empty_cells_remaining - 1;\n}\n\npair<int,int> choose_cell(int number) {\n    const long long DIFF_WEIGHT = 100000LL;\n    const long long DIST_WEIGHT = 500LL;\n    const long long DEGREE_WEIGHT = 200LL;\n    const long long NEG_EXTRA = 20000LL;\n\n    long long bestCost = (1LL << 60);\n    pair<int,int> best = {-1, -1};\n\n    for (int i = 0; i < D; ++i) {\n        for (int j = 0; j < D; ++j) {\n            if (grid[i][j] != EMPTY) continue;\n            if (!is_safe_cell(i, j)) continue;\n            int tr = target_rank[i][j];\n            if (tr < 0) continue;\n\n            int diff = tr - number;\n            int absdiff = abs(diff);\n            long long cost = (long long)absdiff * DIFF_WEIGHT;\n            if (diff < 0) cost += (long long)(-diff) * NEG_EXTRA;\n            cost += (long long)dist_from_entrance[i][j] * DIST_WEIGHT;\n\n            int degree = 0;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + DX[dir];\n                int nj = j + DY[dir];\n                if (!inside(ni, nj)) continue;\n                if (grid[ni][nj] == EMPTY) ++degree;\n            }\n            cost += (long long)degree * DEGREE_WEIGHT;\n            cost = (cost << 4) + (tie_counter++ & 15);\n\n            if (cost < bestCost) {\n                bestCost = cost;\n                best = {i, j};\n            }\n        }\n    }\n\n    if (best.first == -1) {\n        // Emergency fallback: find any safe cell.\n        for (int i = 0; i < D && best.first == -1; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (grid[i][j] == EMPTY && is_safe_cell(i, j)) {\n                    best = {i, j};\n                    break;\n                }\n            }\n        }\n    }\n    return best;\n}\n\nvector<pair<int,int>> build_retrieval_order() {\n    vector<pair<int,int>> order;\n    order.reserve(total_cells);\n    vector<vector<char>> cleared(D, vector<char>(D, 0));\n    vector<vector<char>> in_queue(D, vector<char>(D, 0));\n    cleared[entrance_i][entrance_j] = 1;\n\n    struct Node {\n        int value;\n        int rank;\n        long long tie;\n        int x, y;\n    };\n    struct Cmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.value != b.value) return a.value > b.value;\n            if (a.rank != b.rank)   return a.rank > b.rank;\n            return a.tie > b.tie;\n        }\n    };\n\n    priority_queue<Node, vector<Node>, Cmp> pq;\n\n    auto push_node = [&](int x, int y) {\n        if (!inside(x, y)) return;\n        if (cleared[x][y]) return;\n        if (grid[x][y] < 0) return;                 // not a container\n        if (in_queue[x][y]) return;\n        pq.push(Node{grid[x][y], target_rank[x][y], tie_counter++, x, y});\n        in_queue[x][y] = 1;\n    };\n\n    for (int dir = 0; dir < 4; ++dir)\n        push_node(entrance_i + DX[dir], entrance_j + DY[dir]);\n\n    auto refill = [&]() {\n        if (!pq.empty()) return;\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (grid[i][j] < 0 || cleared[i][j] || in_queue[i][j]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + DX[dir];\n                    int nj = j + DY[dir];\n                    if (!inside(ni, nj)) continue;\n                    if (cleared[ni][nj]) {\n                        push_node(i, j);\n                        break;\n                    }\n                }\n            }\n        }\n    };\n\n    while ((int)order.size() < total_cells) {\n        refill();\n        if (pq.empty()) break;                     // should not happen\n        Node cur = pq.top(); pq.pop();\n        if (cleared[cur.x][cur.y]) continue;\n        order.push_back({cur.x, cur.y});\n        cleared[cur.x][cur.y] = 1;\n        grid[cur.x][cur.y] = EMPTY;\n        for (int dir = 0; dir < 4; ++dir)\n            push_node(cur.x + DX[dir], cur.y + DY[dir]);\n    }\n    return order;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> D >> N)) return 0;\n    entrance_i = 0;\n    entrance_j = (D - 1) / 2;\n\n    grid.assign(D, vector<int>(D, EMPTY));\n    for (int k = 0; k < N; ++k) {\n        int r, c; cin >> r >> c;\n        grid[r][c] = OBSTACLE;\n    }\n    grid[entrance_i][entrance_j] = ENTRANCE;\n\n    vector<vector<int>> base_grid = grid;\n\n    dist_from_entrance = compute_dist(base_grid);\n    target_order = compute_target_order(base_grid);\n    total_cells = (int)target_order.size();\n    target_rank.assign(D, vector<int>(D, -1));\n    for (int idx = 0; idx < (int)target_order.size(); ++idx) {\n        auto [x, y] = target_order[idx];\n        target_rank[x][y] = idx;\n    }\n\n    empty_cells_remaining = total_cells;\n    int total_containers = total_cells;\n\n    for (int step = 0; step < total_containers; ++step) {\n        int t; cin >> t;\n        auto cell = choose_cell(t);\n        grid[cell.first][cell.second] = t;\n        --empty_cells_remaining;\n        cout << cell.first << ' ' << cell.second << '\\n' << flush;\n    }\n\n    auto retrieval = build_retrieval_order();\n    for (auto [x, y] : retrieval)\n        cout << x << ' ' << y << '\\n';\n    cout.flush();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr double TIME_LIMIT = 1.9;  // seconds\n    int n, m, m1, N;\n    vector<int> initialBoard;\n    vector<int> initialColorCount;\n    vector<int> baseAdjCount;\n    vector<char> canTouchZero;\n    vector<int> bestBoard;\n    int bestZero = -1;\n\n    chrono::steady_clock::time_point startTime;\n    mt19937_64 rng;\n\n    const array<int, 4> di = {-1, 1, 0, 0};\n    const array<int, 4> dj = {0, 0, -1, 1};\n\n    void readInput() {\n        cin >> n >> m;\n        m1 = m + 1;\n        N = n * n;\n        initialBoard.resize(N);\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int c;\n                cin >> c;\n                initialBoard[i * n + j] = c;\n            }\n        }\n    }\n\n    inline int adjIndex(int a, int b) const {\n        return a * m1 + b;\n    }\n\n    void precompute() {\n        initialColorCount.assign(m1, 0);\n        for (int v : initialBoard) {\n            initialColorCount[v]++;\n        }\n        baseAdjCount.assign(m1 * m1, 0);\n        auto addEdge = [&](int a, int b) {\n            if (a == b) return;\n            int idx1 = adjIndex(a, b);\n            int idx2 = adjIndex(b, a);\n            baseAdjCount[idx1] += 1;\n            baseAdjCount[idx2] += 1;\n        };\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int idx = i * n + j;\n                int c = initialBoard[idx];\n                if (i + 1 < n) addEdge(c, initialBoard[(i + 1) * n + j]);\n                if (j + 1 < n) addEdge(c, initialBoard[i * n + j + 1]);\n                if (i == 0) addEdge(c, 0);\n                if (i == n - 1) addEdge(c, 0);\n                if (j == 0) addEdge(c, 0);\n                if (j == n - 1) addEdge(c, 0);\n            }\n        }\n        canTouchZero.assign(m1, 0);\n        canTouchZero[0] = 1;\n        for (int c = 1; c < m1; ++c) {\n            if (baseAdjCount[adjIndex(0, c)] > 0) {\n                canTouchZero[c] = 1;\n            }\n        }\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    inline int getAdj(const vector<int>& adj, int a, int b) const {\n        return adj[adjIndex(a, b)];\n    }\n\n    inline void changeAdj(vector<int>& adj, int a, int b, int delta) const {\n        if (a == b || delta == 0) return;\n        adj[adjIndex(a, b)] += delta;\n        adj[adjIndex(b, a)] += delta;\n    }\n\n    bool checkConnectivity(int removeIdx, int color, const vector<int>& board,\n                           const vector<int>& colorCount, vector<int>& visitStamp,\n                           int& visitToken) const {\n        int remaining = colorCount[color] - 1;\n        if (remaining <= 0) return false;\n        int start = -1;\n        int ri = removeIdx / n;\n        int rj = removeIdx % n;\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = ri + di[dir];\n            int nj = rj + dj[dir];\n            if (0 <= ni && ni < n && 0 <= nj && nj < n) {\n                int nidx = ni * n + nj;\n                if (board[nidx] == color) {\n                    start = nidx;\n                    break;\n                }\n            }\n        }\n        if (start == -1) {\n            for (int idx = 0; idx < N; ++idx) {\n                if (idx == removeIdx) continue;\n                if (board[idx] == color) {\n                    start = idx;\n                    break;\n                }\n            }\n            if (start == -1) return false;\n        }\n        visitToken++;\n        if (visitToken == INT_MAX) {\n            fill(visitStamp.begin(), visitStamp.end(), 0);\n            visitToken = 1;\n            visitStamp[start] = visitToken;\n        } else {\n            visitStamp[start] = visitToken;\n        }\n        queue<int> q;\n        q.push(start);\n        int reached = 0;\n        while (!q.empty()) {\n            int cur = q.front();\n            q.pop();\n            reached++;\n            if (reached == remaining) return true;\n            int ci = cur / n;\n            int cj = cur % n;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = ci + di[dir];\n                int nj = cj + dj[dir];\n                if (!(0 <= ni && ni < n && 0 <= nj && nj < n)) continue;\n                int nidx = ni * n + nj;\n                if (nidx == removeIdx) continue;\n                if (board[nidx] == color && visitStamp[nidx] != visitToken) {\n                    visitStamp[nidx] = visitToken;\n                    q.push(nidx);\n                }\n            }\n        }\n        return reached == remaining;\n    }\n\n    bool tryRemove(int idx, vector<int>& board, vector<int>& colorCount,\n                   vector<int>& adjCount, vector<int>& visitStamp, int& visitToken) const {\n        int c = board[idx];\n        if (c == 0) return false;\n        if (!canTouchZero[c]) return false;\n        if (colorCount[c] <= 1) return false;\n        int i = idx / n;\n        int j = idx % n;\n\n        int zeroEdges = 0;\n        int sameNeighbors = 0;\n        int neighborColors[4];\n        int neighborEdges[4];\n        int neighborKinds = 0;\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (!(0 <= ni && ni < n && 0 <= nj && nj < n)) {\n                zeroEdges++;\n                continue;\n            }\n            int nidx = ni * n + nj;\n            int d = board[nidx];\n            if (d == 0) {\n                zeroEdges++;\n            } else if (d == c) {\n                sameNeighbors++;\n            } else {\n                if (!canTouchZero[d]) return false;\n                bool found = false;\n                for (int t = 0; t < neighborKinds; ++t) {\n                    if (neighborColors[t] == d) {\n                        neighborEdges[t]++;\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) {\n                    neighborColors[neighborKinds] = d;\n                    neighborEdges[neighborKinds] = 1;\n                    neighborKinds++;\n                }\n            }\n        }\n\n        if (zeroEdges == 0) return false;\n        if (getAdj(adjCount, c, 0) <= zeroEdges) return false;\n        for (int t = 0; t < neighborKinds; ++t) {\n            int d = neighborColors[t];\n            if (getAdj(adjCount, c, d) <= neighborEdges[t]) return false;\n        }\n\n        if (sameNeighbors >= 2) {\n            if (!checkConnectivity(idx, c, board, colorCount, visitStamp, visitToken)) {\n                return false;\n            }\n        }\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (!(0 <= ni && ni < n && 0 <= nj && nj < n)) {\n                changeAdj(adjCount, c, 0, -1);\n                continue;\n            }\n            int nidx = ni * n + nj;\n            int d = board[nidx];\n            if (d == c) continue;\n            changeAdj(adjCount, c, d, -1);\n        }\n\n        board[idx] = 0;\n        colorCount[c]--;\n        colorCount[0]++;\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (!(0 <= ni && ni < n && 0 <= nj && nj < n)) continue;\n            int nidx = ni * n + nj;\n            int d = board[nidx];\n            if (d == 0) continue;\n            changeAdj(adjCount, 0, d, +1);\n        }\n\n        return true;\n    }\n\n    struct IterationResult {\n        vector<int> board;\n        int zeroCount;\n    };\n\n    IterationResult runIteration() {\n        vector<int> board = initialBoard;\n        vector<int> colorCount = initialColorCount;\n        vector<int> adjCount = baseAdjCount;\n        vector<int> visitStamp(N, 0);\n        int visitToken = 1;\n\n        vector<int> frontier;\n        frontier.reserve(N);\n        vector<char> inFrontier(N, 0);\n\n        auto addFrontier = [&](int idx) {\n            if (idx < 0 || idx >= N) return;\n            if (board[idx] == 0) return;\n            if (!canTouchZero[board[idx]]) return;\n            if (inFrontier[idx]) return;\n            inFrontier[idx] = 1;\n            frontier.push_back(idx);\n        };\n\n        for (int i = 0; i < n; ++i) {\n            addFrontier(i * n);\n            addFrontier(i * n + (n - 1));\n        }\n        for (int j = 0; j < n; ++j) {\n            addFrontier(j);\n            addFrontier((n - 1) * n + j);\n        }\n\n        while (!frontier.empty()) {\n            if (elapsed() > TIME_LIMIT) break;\n            size_t pos = rng() % frontier.size();\n            int idx = frontier[pos];\n            frontier[pos] = frontier.back();\n            frontier.pop_back();\n            inFrontier[idx] = 0;\n            if (board[idx] == 0) continue;\n            if (!canTouchZero[board[idx]]) continue;\n            if (tryRemove(idx, board, colorCount, adjCount, visitStamp, visitToken)) {\n                int i = idx / n;\n                int j = idx % n;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + di[dir];\n                    int nj = j + dj[dir];\n                    if (0 <= ni && ni < n && 0 <= nj && nj < n) {\n                        addFrontier(ni * n + nj);\n                    }\n                }\n            }\n        }\n\n        return {std::move(board), colorCount[0]};\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        readInput();\n        precompute();\n\n        bestBoard = initialBoard;\n        bestZero = 0;\n\n        startTime = chrono::steady_clock::now();\n        uint64_t seed = startTime.time_since_epoch().count();\n        rng.seed(seed);\n\n        int iterations = 0;\n        while (true) {\n            if (iterations > 0 && elapsed() > TIME_LIMIT) break;\n            IterationResult res = runIteration();\n            if (res.zeroCount > bestZero) {\n                bestZero = res.zeroCount;\n                bestBoard = std::move(res.board);\n            }\n            iterations++;\n            if (elapsed() > TIME_LIMIT) break;\n        }\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                if (j) cout << ' ';\n                cout << bestBoard[i * n + j];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Query {\n    vector<int> idx;\n    vector<int8_t> coeff;\n    double scale = 1.0;\n    double invScale = 1.0;\n    double invScaleSq = 1.0;\n    int result = 0; // 1: L>R, -1: L<R, 0: equal\n};\n\nvector<double> estimate_weights(const vector<Query>& queries, int N, mt19937& rng) {\n    vector<double> w(N, 1.0);\n    if (queries.empty()) return w;\n    const double minW = 1e-6;\n    const double lr_main = 0.05;\n    const double lr_eq = 0.04;\n    const double reg = 1e-4;\n    uniform_int_distribution<int> qdist(0, (int)queries.size() - 1);\n    int iterations = min(200000, max(20000, 30 * (int)queries.size()));\n\n    for (int iter = 0; iter < iterations; ++iter) {\n        const Query& qu = queries[qdist(rng)];\n        if (qu.idx.empty()) continue;\n        double diff = 0.0;\n        for (size_t k = 0; k < qu.idx.size(); ++k) diff += w[qu.idx[k]] * qu.coeff[k];\n\n        if (qu.result == 0) {\n            double grad_base = diff * qu.invScaleSq;\n            for (size_t k = 0; k < qu.idx.size(); ++k) {\n                int idx = qu.idx[k];\n                double grad = grad_base * qu.coeff[k] + reg * w[idx];\n                w[idx] -= lr_eq * grad;\n                if (w[idx] < minW) w[idx] = minW;\n            }\n        } else {\n            int y = qu.result;\n            double score = diff * qu.invScale;\n            double s = y * score;\n            double sigma;\n            if (s >= 0) {\n                double e = exp(-s);\n                sigma = e / (1.0 + e);\n            } else {\n                double e = exp(s);\n                sigma = 1.0 / (1.0 + e);\n            }\n            double grad_base = -y * sigma * qu.invScale;\n            for (size_t k = 0; k < qu.idx.size(); ++k) {\n                int idx = qu.idx[k];\n                double grad = grad_base * qu.coeff[k] + reg * w[idx];\n                w[idx] -= lr_main * grad;\n                if (w[idx] < minW) w[idx] = minW;\n            }\n        }\n\n        if ((iter & 255) == 0) {\n            double mean = 0.0;\n            for (double val : w) mean += val;\n            mean /= N;\n            if (mean > 0) for (double &val : w) val /= mean;\n        }\n    }\n\n    double perceptron_lr = 0.02;\n    for (int pass = 0; pass < 2; ++pass) {\n        for (const Query& qu : queries) {\n            if (qu.idx.empty()) continue;\n            double diff = 0.0;\n            for (size_t k = 0; k < qu.idx.size(); ++k) diff += w[qu.idx[k]] * qu.coeff[k];\n            double margin = 0.05 * qu.scale;\n            bool violation = false;\n            if (qu.result == 1) {\n                if (diff < margin) violation = true;\n            } else if (qu.result == -1) {\n                if (diff > -margin) violation = true;\n            } else {\n                if (fabs(diff) > margin) violation = true;\n            }\n            if (!violation) continue;\n\n            if (qu.result == 0) {\n                double grad_base = diff * qu.invScaleSq;\n                for (size_t k = 0; k < qu.idx.size(); ++k) {\n                    int idx = qu.idx[k];\n                    w[idx] -= perceptron_lr * grad_base * qu.coeff[k];\n                    if (w[idx] < minW) w[idx] = minW;\n                }\n            } else {\n                for (size_t k = 0; k < qu.idx.size(); ++k) {\n                    int idx = qu.idx[k];\n                    w[idx] += perceptron_lr * qu.result * qu.coeff[k];\n                    if (w[idx] < minW) w[idx] = minW;\n                }\n            }\n        }\n        double mean = 0.0;\n        for (double val : w) mean += val;\n        mean /= N;\n        if (mean > 0) for (double &val : w) val /= mean;\n    }\n\n    double sum = 0.0;\n    for (double val : w) sum += val;\n    if (sum > 0) {\n        double factor = (double)N / sum;\n        for (double &val : w) val *= factor;\n    }\n    return w;\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    vector<Query> queries;\n    queries.reserve(Q);\n    vector<double> biasScore(N, 0.0);\n\n    mt19937 rng(\n        (uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> uniform01(0.0, 1.0);\n\n    auto ask = [&](const vector<int>& L, const vector<int>& R) -> int {\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string resp;\n        if (!(cin >> resp)) exit(0);\n        int res = 0;\n        if (!resp.empty()) {\n            if (resp[0] == '>') res = 1;\n            else if (resp[0] == '<') res = -1;\n        }\n\n        Query q;\n        q.result = res;\n        q.idx.reserve(L.size() + R.size());\n        q.coeff.reserve(L.size() + R.size());\n        for (int x : L) { q.idx.push_back(x); q.coeff.push_back(1); }\n        for (int x : R) { q.idx.push_back(x); q.coeff.push_back(-1); }\n        int len = (int)q.idx.size();\n        if (len == 0) len = 1;\n        q.scale = sqrt((double)len);\n        q.invScale = 1.0 / q.scale;\n        q.invScaleSq = q.invScale * q.invScale;\n        queries.push_back(std::move(q));\n\n        if (res == 1) {\n            for (int x : L) biasScore[x] += 1.0;\n            for (int x : R) biasScore[x] -= 1.0;\n        } else if (res == -1) {\n            for (int x : L) biasScore[x] -= 1.0;\n            for (int x : R) biasScore[x] += 1.0;\n        }\n        return res;\n    };\n\n    int champion = 0;\n    for (int i = 1; i < N && (int)queries.size() < Q; ++i) {\n        vector<int> L = {champion};\n        vector<int> R = {i};\n        int res = ask(L, R);\n        if (res == -1) champion = i;\n    }\n\n    while ((int)queries.size() < Q) {\n        vector<int> L, R;\n        int type = rng() % 3;\n        if (type == 0) {\n            int a = rng() % N;\n            int b = rng() % N;\n            while (b == a) b = rng() % N;\n            L = {a};\n            R = {b};\n        } else if (type == 1) {\n            vector<int> picks;\n            picks.reserve(4);\n            while ((int)picks.size() < 4) {\n                int x = rng() % N;\n                bool ok = true;\n                for (int y : picks) if (y == x) { ok = false; break; }\n                if (ok) picks.push_back(x);\n            }\n            L = {picks[0], picks[1]};\n            R = {picks[2], picks[3]};\n        } else {\n            double density = 0.18 + 0.22 * (double)N / 100.0;\n            density = min(0.35, max(0.18, density));\n            for (int i = 0; i < N; ++i) {\n                double v = uniform01(rng);\n                if (v < density) L.push_back(i);\n                else if (v < 2.0 * density) R.push_back(i);\n            }\n            if (L.empty() && !R.empty()) {\n                L.push_back(R.back());\n                R.pop_back();\n            }\n            if (R.empty() && !L.empty()) {\n                R.push_back(L.back());\n                L.pop_back();\n            }\n            if (L.empty() || R.empty()) {\n                int a = rng() % N;\n                int b = rng() % N;\n                while (b == a) b = rng() % N;\n                L = {a};\n                R = {b};\n            }\n        }\n        ask(L, R);\n    }\n\n    vector<double> weights = estimate_weights(queries, N, rng);\n\n    double maxAbs = 0.0;\n    for (double s : biasScore) maxAbs = max(maxAbs, fabs(s));\n    if (maxAbs < 1e-9) maxAbs = 1.0;\n    const double alpha = 0.4;\n    for (int i = 0; i < N; ++i) {\n        double factor = 1.0 + alpha * (biasScore[i] / maxAbs);\n        weights[i] *= factor;\n        if (weights[i] < 1e-6) weights[i] = 1e-6;\n    }\n\n    double sum = 0.0;\n    for (double v : weights) sum += v;\n    if (sum > 0.0) {\n        double factor = (double)N / sum;\n        for (double &v : weights) v *= factor;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        double noise = 0.98 + 0.04 * uniform01(rng);\n        weights[i] *= noise;\n    }\n    sum = 0.0;\n    for (double v : weights) sum += v;\n    if (sum > 0.0) {\n        double factor = (double)N / sum;\n        for (double &v : weights) v *= factor;\n    }\n\n    double mean = 0.0;\n    for (double v : weights) mean += v;\n    mean /= N;\n    double var = 0.0;\n    for (double v : weights) {\n        double diff = v - mean;\n        var += diff * diff;\n    }\n    var /= N;\n    if (var < 1e-4) {\n        for (int i = 0; i < N; ++i) {\n            double factor = 1.0 + 0.5 * (biasScore[i] / maxAbs);\n            weights[i] = max(1e-6, factor);\n        }\n        sum = 0.0;\n        for (double v : weights) sum += v;\n        if (sum > 0.0) {\n            double factor = (double)N / sum;\n            for (double &v : weights) v *= factor;\n        }\n    }\n\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(),\n         [&](int a, int b) {\n             if (weights[a] != weights[b]) return weights[a] > weights[b];\n             return a < b;\n         });\n\n    vector<int> assignment(N, 0);\n    vector<double> bucket_sum(D, 0.0);\n    vector<int> bucket_size(D, 0);\n\n    for (int idx : order) {\n        int best = 0;\n        for (int d = 1; d < D; ++d) {\n            if (bucket_sum[d] + 1e-9 < bucket_sum[best]) best = d;\n            else if (fabs(bucket_sum[d] - bucket_sum[best]) <= 1e-9 &&\n                     bucket_size[d] < bucket_size[best]) best = d;\n        }\n        assignment[idx] = best;\n        bucket_sum[best] += weights[idx];\n        bucket_size[best] += 1;\n    }\n\n    double total = 0.0;\n    for (double s : bucket_sum) total += s;\n    double target = total / D;\n\n    if (D > 1) {\n        int LS_ITERS = 10000 + 200 * N;\n        uniform_int_distribution<int> distItem(0, N - 1);\n        uniform_int_distribution<int> distBucket(0, D - 1);\n        for (int iter = 0; iter < LS_ITERS; ++iter) {\n            if (rng() & 1) {\n                int i = distItem(rng);\n                int from = assignment[i];\n                int to = distBucket(rng);\n                if (from == to) continue;\n                double wi = weights[i];\n                double sa = bucket_sum[from];\n                double sb = bucket_sum[to];\n                double oldScore = (sa - target) * (sa - target) +\n                                  (sb - target) * (sb - target);\n                double na = sa - wi;\n                double nb = sb + wi;\n                double newScore = (na - target) * (na - target) +\n                                  (nb - target) * (nb - target);\n                if (newScore + 1e-9 < oldScore) {\n                    assignment[i] = to;\n                    bucket_sum[from] = na;\n                    bucket_sum[to] = nb;\n                    bucket_size[from]--;\n                    bucket_size[to]++;\n                }\n            } else {\n                int i = distItem(rng);\n                int j = distItem(rng);\n                if (assignment[i] == assignment[j]) continue;\n                int a = assignment[i];\n                int b = assignment[j];\n                double wi = weights[i];\n                double wj = weights[j];\n                double sa = bucket_sum[a];\n                double sb = bucket_sum[b];\n                double oldScore = (sa - target) * (sa - target) +\n                                  (sb - target) * (sb - target);\n                double na = sa - wi + wj;\n                double nb = sb - wj + wi;\n                double newScore = (na - target) * (na - target) +\n                                  (nb - target) * (nb - target);\n                if (newScore + 1e-9 < oldScore) {\n                    assignment[i] = b;\n                    assignment[j] = a;\n                    bucket_sum[a] = na;\n                    bucket_sum[b] = nb;\n                }\n            }\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << assignment[i];\n    }\n    cout << '\\n' << flush;\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int n, m;\n    struct Pos {\n        int stack = -1;\n        int idx = -1;\n    };\n    vector<vector<int>> stacks;\n    vector<Pos> pos;\n    vector<pair<int,int>> operations;\n    long long energy = 0;\n\n    int choose_destination(int source, int chunk_min) {\n        const int INF = 1e9;\n        int best = -1;\n        long long bestScore = (1LL << 62);\n        for (int i = 0; i < m; ++i) if (i != source) {\n            int topVal = stacks[i].empty() ? INF : stacks[i].back();\n            if (topVal >= chunk_min) {\n                long long score = (long long)stacks[i].size() * 1000LL - (long long)topVal;\n                if (score < bestScore) {\n                    bestScore = score;\n                    best = i;\n                }\n            }\n        }\n        if (best != -1) return best;\n\n        int bestIdx = -1;\n        int bestTop = -1;\n        int bestHeight = INT_MAX;\n        for (int i = 0; i < m; ++i) if (i != source) {\n            if (stacks[i].empty()) continue;\n            int topVal = stacks[i].back();\n            int height = (int)stacks[i].size();\n            if (topVal > bestTop ||\n                (topVal == bestTop && height < bestHeight) ||\n                (topVal == bestTop && height == bestHeight && i < bestIdx)) {\n                bestTop = topVal;\n                bestHeight = height;\n                bestIdx = i;\n            }\n        }\n        if (bestIdx != -1) return bestIdx;\n        for (int i = 0; i < m; ++i) if (i != source) return i; // fallback\n        return source; // should not happen\n    }\n\n    void move_segment(int box, int dest) {\n        auto p = pos[box];\n        int s = p.stack;\n        int idx = p.idx;\n        if (s == -1 || dest == -1 || s == dest) return;\n        vector<int> segment;\n        segment.reserve(stacks[s].size() - idx);\n        for (int i = idx; i < (int)stacks[s].size(); ++i) segment.push_back(stacks[s][i]);\n        stacks[s].resize(idx);\n        int destStart = stacks[dest].size();\n        stacks[dest].insert(stacks[dest].end(), segment.begin(), segment.end());\n        for (int t = 0; t < (int)segment.size(); ++t) {\n            pos[segment[t]].stack = dest;\n            pos[segment[t]].idx = destStart + t;\n        }\n        operations.emplace_back(box, dest + 1); // output is 1-indexed\n        energy += (long long)segment.size() + 1;\n    }\n\n    void remove_box(int box) {\n        auto p = pos[box];\n        int s = p.stack;\n        int idx = p.idx;\n        if (s == -1) return;\n        stacks[s].pop_back();\n        pos[box].stack = -1;\n        pos[box].idx = -1;\n        operations.emplace_back(box, 0);\n    }\n\n    void solve() {\n        cin >> n >> m;\n        stacks.assign(m, {});\n        pos.assign(n + 1, {});\n        int stackLen = n / m;\n        for (int i = 0; i < m; ++i) {\n            stacks[i].resize(stackLen);\n            for (int j = 0; j < stackLen; ++j) {\n                int v; cin >> v;\n                stacks[i][j] = v;\n                pos[v].stack = i;\n                pos[v].idx = j;\n            }\n        }\n\n        for (int v = 1; v <= n; ++v) {\n            while (true) {\n                auto p = pos[v];\n                int s = p.stack;\n                if (s == -1) break; // already removed\n                int idx = p.idx;\n                if (idx == (int)stacks[s].size() - 1) {\n                    remove_box(v);\n                    break;\n                } else {\n                    int start = idx + 1;\n                    int chunk_min = INT_MAX;\n                    for (int t = start; t < (int)stacks[s].size(); ++t) {\n                        chunk_min = min(chunk_min, stacks[s][t]);\n                    }\n                    int dest = choose_destination(s, chunk_min);\n                    if (dest == s) {\n                        for (int i = 0; i < m; ++i) if (i != s) { dest = i; break; }\n                        if (dest == s) break; // should not occur unless m=1\n                    }\n                    int box_to_move = stacks[s][start];\n                    move_segment(box_to_move, dest);\n                }\n            }\n        }\n\n        for (auto [v, i] : operations) {\n            cout << v << ' ' << i << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MOVE_LIMIT = 100000;\n    static constexpr double TIME_LIMIT = 1.95;\n\n    int N;\n    int totalNodes;\n    vector<string> h, v;\n    vector<vector<int>> d;\n    vector<int> d_flat;\n    vector<vector<int>> adj;\n    vector<array<int, 4>> dirNeighbor;\n    vector<int> node_r, node_c;\n    vector<uint16_t> dist_all;\n    vector<uint16_t> next_all;\n    vector<vector<int>> visitTimes;\n    array<int, 4> dr = {-1, 1, 0, 0};\n    array<int, 4> dc = {0, 0, -1, 1};\n    array<char, 4> dirChar = {'U', 'D', 'L', 'R'};\n    mt19937 rng;\n    chrono::steady_clock::time_point start_time;\n\n    Solver() : rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n        read_input();\n    }\n\n    void read_input() {\n        cin >> N;\n        h.resize(max(0, N - 1));\n        for (int i = 0; i < N - 1; ++i) cin >> h[i];\n        v.resize(N);\n        for (int i = 0; i < N; ++i) cin >> v[i];\n        d.assign(N, vector<int>(N));\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                cin >> d[i][j];\n\n        totalNodes = N * N;\n        node_r.resize(totalNodes);\n        node_c.resize(totalNodes);\n        d_flat.resize(totalNodes);\n        int idx = 0;\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j, ++idx) {\n                node_r[idx] = i;\n                node_c[idx] = j;\n                d_flat[idx] = d[i][j];\n            }\n\n        adj.assign(totalNodes, {});\n        dirNeighbor.assign(totalNodes, array<int, 4>{-1, -1, -1, -1});\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int u = i * N + j;\n                if (i + 1 < N && h[i][j] == '0') {\n                    int w = (i + 1) * N + j;\n                    adj[u].push_back(w);\n                    adj[w].push_back(u);\n                    dirNeighbor[u][1] = w;\n                    dirNeighbor[w][0] = u;\n                }\n                if (j + 1 < N && v[i][j] == '0') {\n                    int w = i * N + (j + 1);\n                    adj[u].push_back(w);\n                    adj[w].push_back(u);\n                    dirNeighbor[u][3] = w;\n                    dirNeighbor[w][2] = u;\n                }\n            }\n        }\n        visitTimes.assign(totalNodes, {});\n    }\n\n    void solve() {\n        start_time = chrono::steady_clock::now();\n\n        string bestRoute = build_dfs_route();\n        long double bestScore = evaluate(bestRoute);\n        vector<int> bestPerm;\n        long long bestPermCost = (long long)4e18;\n\n        precompute_all_pairs();\n\n        vector<vector<int>> orders;\n        orders.reserve(10);\n        orders.push_back(order_snake_rows());\n        orders.push_back(order_snake_cols());\n        orders.push_back(order_bfs(false));\n        orders.push_back(order_bfs(true));\n        orders.push_back(order_dfs(false));\n        orders.push_back(order_dfs(true));\n        orders.push_back(order_nearest());\n        orders.push_back(order_sorted_d());\n        orders.push_back(order_morton());\n        orders.push_back(order_random());\n\n        vector<int> searchPerm;\n        long long searchCost = (long long)4e18;\n\n        for (auto &perm : orders) {\n            if ((int)perm.size() != totalNodes) continue;\n            long long cost = tour_cost(perm);\n            if (cost < searchCost) {\n                searchCost = cost;\n                searchPerm = perm;\n            }\n            string route;\n            if (!build_route_from_perm(perm, route)) continue;\n            long double score = evaluate(route);\n            if (score < bestScore) {\n                bestScore = score;\n                bestRoute = route;\n                bestPerm = perm;\n                bestPermCost = cost;\n            }\n        }\n\n        vector<int> startPerm;\n        long long startCost = 0;\n        if (!bestPerm.empty()) {\n            startPerm = bestPerm;\n            startCost = bestPermCost;\n        } else if (!searchPerm.empty()) {\n            startPerm = searchPerm;\n            startCost = searchCost;\n        }\n\n        if (!startPerm.empty() && elapsed() < TIME_LIMIT - 0.05) {\n            random_two_opt_search(startPerm, startCost, bestPerm, bestPermCost, bestRoute, bestScore);\n        }\n\n        cout << bestRoute << '\\n';\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    string build_dfs_route() {\n        string route;\n        route.reserve(totalNodes * 2);\n        vector<char> visited(totalNodes, 0);\n        auto dfs = [&](auto &&self, int u) -> void {\n            visited[u] = 1;\n            for (int dir = 0; dir < 4; ++dir) {\n                int vtx = dirNeighbor[u][dir];\n                if (vtx == -1 || visited[vtx]) continue;\n                route.push_back(dirChar[dir]);\n                self(self, vtx);\n                route.push_back(dirChar[dir ^ 1]);\n            }\n        };\n        dfs(dfs, 0);\n        return route;\n    }\n\n    void precompute_all_pairs() {\n        dist_all.assign((size_t)totalNodes * totalNodes, 0);\n        next_all.assign((size_t)totalNodes * totalNodes, 0);\n        vector<int> dist(totalNodes);\n        vector<int> parent(totalNodes);\n        vector<int> order(totalNodes);\n        vector<int> rootChild(totalNodes);\n        vector<int> que(totalNodes);\n\n        for (int s = 0; s < totalNodes; ++s) {\n            fill(dist.begin(), dist.end(), -1);\n            fill(parent.begin(), parent.end(), -1);\n            int head = 0, tail = 0;\n            que[tail++] = s;\n            dist[s] = 0;\n            int ord_sz = 0;\n            while (head < tail) {\n                int u = que[head++];\n                order[ord_sz++] = u;\n                for (int vtx : adj[u]) {\n                    if (dist[vtx] != -1) continue;\n                    dist[vtx] = dist[u] + 1;\n                    parent[vtx] = u;\n                    que[tail++] = vtx;\n                }\n            }\n            rootChild[s] = s;\n            for (int idx = 1; idx < ord_sz; ++idx) {\n                int u = order[idx];\n                int p = parent[u];\n                rootChild[u] = (p == s) ? u : rootChild[p];\n            }\n            size_t base = (size_t)s * totalNodes;\n            for (int t = 0; t < totalNodes; ++t) {\n                dist_all[base + t] = static_cast<uint16_t>(dist[t]);\n                next_all[base + t] = static_cast<uint16_t>(t == s ? s : rootChild[t]);\n            }\n        }\n    }\n\n    inline int dist_idx(int a, int b) const {\n        return static_cast<int>(dist_all[(size_t)a * totalNodes + b]);\n    }\n    inline int next_idx(int a, int b) const {\n        return static_cast<int>(next_all[(size_t)a * totalNodes + b]);\n    }\n\n    bool append_path(int from, int to, string &route) const {\n        if (from == to) return true;\n        int safety = totalNodes * 4;\n        while (from != to && safety-- > 0) {\n            int nxt = next_idx(from, to);\n            if (nxt == from) return false;\n            char mv = move_char(from, nxt);\n            if (mv == '?') return false;\n            route.push_back(mv);\n            from = nxt;\n            if ((int)route.size() > MOVE_LIMIT) return false;\n        }\n        return from == to;\n    }\n\n    bool build_route_from_perm(const vector<int> &perm, string &route) const {\n        if (perm.empty() || perm[0] != 0) return false;\n        route.clear();\n        route.reserve(totalNodes * 4);\n        int cur = 0;\n        for (size_t idx = 1; idx < perm.size(); ++idx) {\n            if (!append_path(cur, perm[idx], route)) return false;\n            cur = perm[idx];\n        }\n        if (!append_path(cur, perm[0], route)) return false;\n        return (int)route.size() <= MOVE_LIMIT;\n    }\n\n    long double evaluate(const string &route) {\n        if (route.empty() || (int)route.size() > MOVE_LIMIT) return 1e100L;\n        for (auto &vec : visitTimes) vec.clear();\n        int pos = 0;\n        for (int t = 0; t < (int)route.size(); ++t) {\n            int dir = char_dir(route[t]);\n            if (dir == -1) return 1e100L;\n            int nxt = dirNeighbor[pos][dir];\n            if (nxt == -1) return 1e100L;\n            pos = nxt;\n            visitTimes[pos].push_back(t + 1);\n        }\n        if (pos != 0) return 1e100L;\n\n        long double total = 0.0L;\n        long double L = (long double)route.size();\n        for (int idx = 0; idx < totalNodes; ++idx) {\n            auto &times = visitTimes[idx];\n            if (times.empty()) return 1e100L;\n            size_t m = times.size();\n            for (size_t j = 0; j < m; ++j) {\n                long long cur = times[j];\n                long long nxt = (j + 1 < m) ? times[j + 1] : (long long)times[0] + (long long)L;\n                long long delta = nxt - cur;\n                total += (long double)d_flat[idx] * (long double)delta * (delta - 1) / 2.0L;\n            }\n        }\n        return total / L;\n    }\n\n    char move_char(int from, int to) const {\n        int r1 = node_r[from], c1 = node_c[from];\n        int r2 = node_r[to], c2 = node_c[to];\n        if (r2 == r1 - 1 && c2 == c1) return 'U';\n        if (r2 == r1 + 1 && c2 == c1) return 'D';\n        if (r2 == r1 && c2 == c1 - 1) return 'L';\n        if (r2 == r1 && c2 == c1 + 1) return 'R';\n        return '?';\n    }\n\n    int char_dir(char c) const {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        if (c == 'R') return 3;\n        return -1;\n    }\n\n    long long tour_cost(const vector<int> &perm) const {\n        if (perm.empty()) return (long long)4e18;\n        long long cost = 0;\n        for (size_t i = 0; i + 1 < perm.size(); ++i)\n            cost += dist_idx(perm[i], perm[i + 1]);\n        cost += dist_idx(perm.back(), perm[0]);\n        return cost;\n    }\n\n    void normalize_order(vector<int> &perm) const {\n        if (perm.empty() || perm[0] == 0) return;\n        auto it = find(perm.begin(), perm.end(), 0);\n        if (it == perm.end()) return;\n        rotate(perm.begin(), it, perm.end());\n    }\n\n    vector<int> order_snake_rows() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        for (int i = 0; i < N; ++i) {\n            if (i % 2 == 0) {\n                for (int j = 0; j < N; ++j) perm.push_back(i * N + j);\n            } else {\n                for (int j = N - 1; j >= 0; --j) perm.push_back(i * N + j);\n            }\n        }\n        return perm;\n    }\n\n    vector<int> order_snake_cols() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        for (int j = 0; j < N; ++j) {\n            if (j % 2 == 0) {\n                for (int i = 0; i < N; ++i) perm.push_back(i * N + j);\n            } else {\n                for (int i = N - 1; i >= 0; --i) perm.push_back(i * N + j);\n            }\n        }\n        return perm;\n    }\n\n    vector<int> order_bfs(bool randomize) {\n        vector<int> order;\n        order.reserve(totalNodes);\n        vector<char> visited(totalNodes, 0);\n        queue<int> q;\n        q.push(0);\n        visited[0] = 1;\n        vector<int> neighbors;\n        neighbors.reserve(4);\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            order.push_back(u);\n            neighbors.assign(adj[u].begin(), adj[u].end());\n            if (randomize) shuffle(neighbors.begin(), neighbors.end(), rng);\n            for (int vtx : neighbors) {\n                if (visited[vtx]) continue;\n                visited[vtx] = 1;\n                q.push(vtx);\n            }\n        }\n        normalize_order(order);\n        return order;\n    }\n\n    vector<int> order_dfs(bool randomize) {\n        vector<int> order;\n        order.reserve(totalNodes);\n        vector<char> visited(totalNodes, 0);\n        vector<int> stack;\n        stack.push_back(0);\n        vector<int> neighbors;\n        neighbors.reserve(4);\n        while (!stack.empty()) {\n            int u = stack.back();\n            stack.pop_back();\n            if (visited[u]) continue;\n            visited[u] = 1;\n            order.push_back(u);\n            neighbors.assign(adj[u].begin(), adj[u].end());\n            if (randomize) shuffle(neighbors.begin(), neighbors.end(), rng);\n            for (int k = (int)neighbors.size() - 1; k >= 0; --k) {\n                int vtx = neighbors[k];\n                if (!visited[vtx]) stack.push_back(vtx);\n            }\n        }\n        normalize_order(order);\n        return order;\n    }\n\n    vector<int> order_nearest() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        vector<char> used(totalNodes, 0);\n        int cur = 0;\n        perm.push_back(cur);\n        used[cur] = 1;\n        for (int left = totalNodes - 1; left > 0; --left) {\n            int best = -1;\n            int bestDist = INT_MAX;\n            for (int vtx = 0; vtx < totalNodes; ++vtx) if (!used[vtx]) {\n                int dd = dist_idx(cur, vtx);\n                if (best == -1 || dd < bestDist || (dd == bestDist && d_flat[vtx] > d_flat[best])) {\n                    bestDist = dd;\n                    best = vtx;\n                }\n            }\n            if (best == -1) break;\n            perm.push_back(best);\n            used[best] = 1;\n            cur = best;\n        }\n        return perm;\n    }\n\n    vector<int> order_sorted_d() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        vector<int> rest;\n        rest.reserve(totalNodes - 1);\n        for (int idx = 1; idx < totalNodes; ++idx) rest.push_back(idx);\n        sort(rest.begin(), rest.end(), [&](int a, int b) {\n            if (d_flat[a] != d_flat[b]) return d_flat[a] > d_flat[b];\n            return a < b;\n        });\n        perm.insert(perm.end(), rest.begin(), rest.end());\n        return perm;\n    }\n\n    uint32_t morton_code(int r, int c) const {\n        uint32_t code = 0;\n        for (int i = 0; i < 6; ++i) {\n            code |= ((uint32_t)((r >> i) & 1)) << (2 * i + 1);\n            code |= ((uint32_t)((c >> i) & 1)) << (2 * i);\n        }\n        return code;\n    }\n\n    vector<int> order_morton() const {\n        vector<pair<uint32_t, int>> nodes;\n        nodes.reserve(totalNodes - 1);\n        for (int idx = 1; idx < totalNodes; ++idx) {\n            nodes.emplace_back(morton_code(node_r[idx], node_c[idx]), idx);\n        }\n        sort(nodes.begin(), nodes.end());\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        for (auto &p : nodes) perm.push_back(p.second);\n        return perm;\n    }\n\n    vector<int> order_random() {\n        vector<int> perm(totalNodes);\n        iota(perm.begin(), perm.end(), 0);\n        if (totalNodes > 1) shuffle(perm.begin() + 1, perm.end(), rng);\n        return perm;\n    }\n\n    void random_two_opt_search(const vector<int> &startPerm, long long startCost,\n                               vector<int> &bestPerm, long long &bestPermCost,\n                               string &bestRoute, long double &bestScore) {\n        if ((int)startPerm.size() <= 3) return;\n        vector<int> perm = startPerm;\n        long long cost = startCost;\n        int n = perm.size();\n        while (elapsed() < TIME_LIMIT - 0.02) {\n            bool applied = false;\n            for (int tries = 0; tries < 200 && elapsed() < TIME_LIMIT - 0.02; ++tries) {\n                int i = rng() % (n - 1) + 1;\n                int j = rng() % (n - 1) + 1;\n                if (i == j) continue;\n                if (i > j) swap(i, j);\n                if (j >= n) continue;\n                if (i == 0) continue;\n                if (j - i <= 0) continue;\n                int a = perm[i - 1];\n                int b = perm[i];\n                int c = perm[j];\n                int d = (j + 1 < n) ? perm[j + 1] : perm[0];\n                long long delta = (long long)dist_idx(a, c) + dist_idx(b, d) -\n                                  dist_idx(a, b) - dist_idx(c, d);\n                if (delta < 0) {\n                    reverse(perm.begin() + i, perm.begin() + j + 1);\n                    cost += delta;\n                    applied = true;\n                    break;\n                }\n            }\n            if (!applied) break;\n            string route;\n            if (!build_route_from_perm(perm, route)) continue;\n            long double score = evaluate(route);\n            if (score < bestScore) {\n                bestScore = score;\n                bestRoute = route;\n                bestPerm = perm;\n                bestPermCost = cost;\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\n// Timer for time-limited heuristics\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n};\n\n// Simple xorshift RNG (deterministic seed derived from input -> deterministic result per case)\nstruct XorShift64 {\n    unsigned long long x;\n    XorShift64(unsigned long long seed = 88172645463393265ull) : x(seed) {}\n    unsigned long long next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {  // returns [0, n)\n        return static_cast<int>(next() % n);\n    }\n    double nextDouble() { // returns [0,1)\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n};\n\nint calcOverlap(const string &a, const string &b) {\n    const int L = 5;\n    for (int len = L - 1; len >= 0; --len) {\n        bool ok = true;\n        for (int k = 0; k < len; ++k) {\n            if (a[L - len + k] != b[k]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) return len;\n    }\n    return 0;\n}\n\nint computeOrderCost(const vector<int>& order, const vector<vector<int>>& cost) {\n    if (order.empty()) return 0;\n    int total = 5;\n    for (size_t i = 0; i + 1 < order.size(); ++i) {\n        total += cost[order[i]][order[i + 1]];\n    }\n    return total;\n}\n\nint swapDelta(const vector<int>& order, int i, int j, const vector<vector<int>>& cost) {\n    if (i == j) return 0;\n    if (i > j) swap(i, j);\n    int n = order.size();\n    int a = order[i];\n    int b = order[j];\n    auto edge = [&](int u, int v) -> int {\n        if (u < 0 || v < 0) return 0;\n        return cost[u][v];\n    };\n    int delta = 0;\n    if (j == i + 1) { // adjacent swap\n        int li = (i > 0) ? order[i - 1] : -1;\n        int rj = (j + 1 < n) ? order[j + 1] : -1;\n        int before = 0, after = 0;\n        if (li != -1) before += edge(li, a);\n        before += edge(a, b);\n        if (rj != -1) before += edge(b, rj);\n        if (li != -1) after += edge(li, b);\n        after += edge(b, a);\n        if (rj != -1) after += edge(a, rj);\n        delta = after - before;\n    } else {\n        int li = (i > 0) ? order[i - 1] : -1;\n        int ri = (i + 1 < n) ? order[i + 1] : -1;\n        int lj = (j > 0) ? order[j - 1] : -1;\n        int rj = (j + 1 < n) ? order[j + 1] : -1;\n        int before = 0, after = 0;\n        if (li != -1) before += edge(li, a);\n        if (ri != -1) before += edge(a, ri);\n        if (lj != -1) before += edge(lj, b);\n        if (rj != -1) before += edge(b, rj);\n        if (li != -1) after += edge(li, b);\n        if (ri != -1) after += edge(b, ri);\n        if (lj != -1) after += edge(lj, a);\n        if (rj != -1) after += edge(a, rj);\n        delta = after - before;\n    }\n    return delta;\n}\n\nvoid hillClimb(vector<int>& order, int &costVal, const vector<vector<int>>& cost) {\n    int n = order.size();\n    while (true) {\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1;\n        for (int i = 0; i < n; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                int delta = swapDelta(order, i, j, cost);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                }\n            }\n        }\n        if (bestDelta < 0) {\n            swap(order[bestI], order[bestJ]);\n            costVal += bestDelta;\n        } else break;\n    }\n}\n\nvector<int> buildInitialOrder(const vector<vector<int>>& cost, const vector<int>& sumOut, int &bestCost) {\n    int n = cost.size();\n    vector<int> bestOrder;\n    bestCost = INT_MAX;\n    vector<int> order;\n    order.reserve(n);\n    vector<char> used(n);\n    for (int start = 0; start < n; ++start) {\n        fill(used.begin(), used.end(), 0);\n        order.clear();\n        int cur = start;\n        while (true) {\n            order.push_back(cur);\n            used[cur] = 1;\n            if ((int)order.size() == n) break;\n            int bestNext = -1;\n            int bestEdge = INT_MAX;\n            for (int nxt = 0; nxt < n; ++nxt) {\n                if (used[nxt]) continue;\n                int c = cost[cur][nxt];\n                if (bestNext == -1 || c < bestEdge) {\n                    bestEdge = c;\n                    bestNext = nxt;\n                } else if (c == bestEdge) {\n                    if (sumOut[nxt] < sumOut[bestNext] || (sumOut[nxt] == sumOut[bestNext] && nxt < bestNext)) {\n                        bestNext = nxt;\n                    }\n                }\n            }\n            cur = bestNext;\n        }\n        int len = computeOrderCost(order, cost);\n        if (len < bestCost) {\n            bestCost = len;\n            bestOrder = order;\n        }\n    }\n    return bestOrder;\n}\n\nvoid simulatedAnnealing(vector<int>& bestOrder, int &bestCost, const vector<vector<int>>& costMatrix,\n                        XorShift64& rng, Timer& timer, double timeLimit) {\n    if (timeLimit <= 1e-4) return;\n    int n = bestOrder.size();\n    vector<int> currentOrder = bestOrder;\n    int currentCost = bestCost;\n    vector<int> localBestOrder = bestOrder;\n    int localBestCost = bestCost;\n    double startTime = timer.elapsed();\n    double endTime = startTime + timeLimit;\n    const double START_TEMP = 2.5;\n    const double END_TEMP = 0.05;\n    while (true) {\n        double now = timer.elapsed();\n        if (now >= endTime) break;\n        double progress = (now - startTime) / timeLimit;\n        if (progress > 1.0) progress = 1.0;\n        double temp = START_TEMP + (END_TEMP - START_TEMP) * progress;\n        if (temp < 1e-4) temp = 1e-4;\n        int i = rng.nextInt(n);\n        int j = rng.nextInt(n);\n        if (i == j) continue;\n        int delta = swapDelta(currentOrder, i, j, costMatrix);\n        bool accept = false;\n        if (delta <= 0) {\n            accept = true;\n        } else {\n            double prob = exp(-delta / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n        if (accept) {\n            swap(currentOrder[i], currentOrder[j]);\n            currentCost += delta;\n            if (currentCost < localBestCost) {\n                localBestCost = currentCost;\n                localBestOrder = currentOrder;\n            }\n        }\n    }\n    bestOrder = localBestOrder;\n    bestCost = localBestCost;\n}\n\nvector<int> buildTypingPlan(const string& S, int N, int si, int sj,\n                            const vector<vector<int>>& cellsByChar,\n                            const vector<int>& rowOfCell,\n                            const vector<int>& colOfCell) {\n    const int INF = 1e9;\n    int L = (int)S.size();\n    vector<int> charIdx(L);\n    for (int i = 0; i < L; ++i) charIdx[i] = S[i] - 'A';\n    vector<vector<int>> dp(L);\n    vector<vector<int16_t>> parent(L);\n    for (int pos = 0; pos < L; ++pos) {\n        int c = charIdx[pos];\n        const auto &cells = cellsByChar[c];\n        int m = cells.size();\n        dp[pos].assign(m, INF);\n        parent[pos].assign(m, -1);\n        if (pos == 0) {\n            for (int idx = 0; idx < m; ++idx) {\n                int cell = cells[idx];\n                dp[pos][idx] = abs(rowOfCell[cell] - si) + abs(colOfCell[cell] - sj) + 1;\n            }\n        } else {\n            int prevChar = charIdx[pos - 1];\n            const auto &prevCells = cellsByChar[prevChar];\n            for (int idx = 0; idx < m; ++idx) {\n                int cell = cells[idx];\n                int bestVal = INF;\n                int bestPrev = -1;\n                for (int p = 0; p < (int)prevCells.size(); ++p) {\n                    int prevCell = prevCells[p];\n                    int prevCost = dp[pos - 1][p];\n                    if (prevCost >= INF) continue;\n                    int dist = abs(rowOfCell[cell] - rowOfCell[prevCell]) +\n                               abs(colOfCell[cell] - colOfCell[prevCell]);\n                    int cand = prevCost + dist + 1;\n                    if (cand < bestVal) {\n                        bestVal = cand;\n                        bestPrev = p;\n                    }\n                }\n                dp[pos][idx] = bestVal;\n                parent[pos][idx] = bestPrev;\n            }\n        }\n    }\n    int lastPos = L - 1;\n    const auto &lastCells = cellsByChar[charIdx[lastPos]];\n    int bestIdx = 0;\n    int bestVal = dp[lastPos][0];\n    for (int idx = 1; idx < (int)lastCells.size(); ++idx) {\n        if (dp[lastPos][idx] < bestVal) {\n            bestVal = dp[lastPos][idx];\n            bestIdx = idx;\n        }\n    }\n    vector<int> path(L);\n    int idx = bestIdx;\n    for (int pos = L - 1; pos >= 0; --pos) {\n        const auto &cells = cellsByChar[charIdx[pos]];\n        path[pos] = cells[idx];\n        if (pos == 0) break;\n        idx = parent[pos][idx];\n        if (idx < 0) idx = 0; // should not happen, but keep safe\n    }\n    return path;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TOTAL_TIME_LIMIT = 1.90;\n    const double RESERVED_TIME = 0.15;\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n    vector<string> words(M);\n    for (int i = 0; i < M; ++i) cin >> words[i];\n\n    const int cellsCnt = N * N;\n    vector<int> rowOfCell(cellsCnt), colOfCell(cellsCnt);\n    vector<vector<int>> cellsByChar(26);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int idx = i * N + j;\n            rowOfCell[idx] = i;\n            colOfCell[idx] = j;\n            int c = grid[i][j] - 'A';\n            cellsByChar[c].push_back(idx);\n        }\n    }\n\n    // deterministic seed for RNG based on input\n    uint64_t seed = 123456789123ull;\n    seed = seed * 1000003 + si * 97 + sj * 131;\n    for (auto &row : grid) for (char c : row) seed = seed * 1000003 + (unsigned char)c;\n    for (auto &w : words) for (char c : w) seed = seed * 1000003 + (unsigned char)c;\n    XorShift64 rng(seed);\n\n    vector<vector<int>> overlap(M, vector<int>(M));\n    vector<vector<int>> cost(M, vector<int>(M, 5));\n    for (int i = 0; i < M; ++i) {\n        for (int j = 0; j < M; ++j) {\n            if (i == j) continue;\n            int ov = calcOverlap(words[i], words[j]);\n            overlap[i][j] = ov;\n            cost[i][j] = 5 - ov;\n        }\n    }\n    vector<int> sumOut(M, 0);\n    for (int i = 0; i < M; ++i) {\n        int s = 0;\n        for (int j = 0; j < M; ++j) {\n            if (i == j) continue;\n            s += cost[i][j];\n        }\n        sumOut[i] = s;\n    }\n\n    int initialCost = 0;\n    vector<int> order = buildInitialOrder(cost, sumOut, initialCost);\n    if (order.empty()) {\n        // fallback (should never happen)\n        order.resize(M);\n        iota(order.begin(), order.end(), 0);\n        initialCost = computeOrderCost(order, cost);\n    }\n    hillClimb(order, initialCost, cost);\n    vector<int> bestOrder = order;\n    int bestCost = initialCost;\n\n    double elapsed = timer.elapsed();\n    double remaining = TOTAL_TIME_LIMIT - elapsed - RESERVED_TIME;\n    if (remaining > 0.02) {\n        simulatedAnnealing(order, initialCost, cost, rng, timer, remaining);\n        hillClimb(order, initialCost, cost);\n        if (initialCost < bestCost) {\n            bestCost = initialCost;\n            bestOrder = order;\n        }\n    }\n\n    // Build final string\n    string S = words[bestOrder[0]];\n    for (int i = 1; i < M; ++i) {\n        int prv = bestOrder[i - 1];\n        int cur = bestOrder[i];\n        int ov = overlap[prv][cur];\n        S.append(words[cur], ov, string::npos);\n    }\n    if ((int)S.size() > 5000) {\n        // fallback (should never happen)\n        S.resize(5000);\n    }\n\n    vector<int> path = buildTypingPlan(S, N, si, sj, cellsByChar, rowOfCell, colOfCell);\n\n    for (int cell : path) {\n        cout << rowOfCell[cell] << ' ' << colOfCell[cell] << '\\n';\n    }\n    return 0;\n}","ahc030":"#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    double eps;\n    if (!(cin >> N >> M >> eps)) return 0;\n\n    // Read polyomino shapes (unused in this baseline strategy, but parsing is required).\n    vector<vector<pair<int,int>>> shapes(M);\n    for (int k = 0; k < M; ++k) {\n        int d;\n        cin >> d;\n        shapes[k].resize(d);\n        for (int t = 0; t < d; ++t) {\n            int i, j;\n            cin >> i >> j;\n            shapes[k][t] = {i, j};\n        }\n    }\n\n    vector<pair<int,int>> has_oil;\n    has_oil.reserve(N * N);\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cout << \"q 1 \" << i << ' ' << j << '\\n' << flush;\n            int val;\n            if (!(cin >> val)) return 0; // Safety\n            if (val > 0) has_oil.emplace_back(i, j);\n        }\n    }\n\n    cout << \"a \" << has_oil.size();\n    for (auto [i, j] : has_oil) {\n        cout << ' ' << i << ' ' << j;\n    }\n    cout << '\\n' << flush;\n\n    int verdict;\n    if (!(cin >> verdict)) return 0;\n    // Since we drilled all cells, the answer should be correct (verdict == 1).\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RectInfo {\n    int i0 = 0, j0 = 0, i1 = 1, j1 = 1;\n    long long area = 1;\n};\n\nint W, D, N;\nvector<vector<int>> demands;\nvector<long long> target_area;\nvector<RectInfo> rects;\n\nvoid build_rectangles(const vector<int>& ids, int x0, int y0, int x1, int y1) {\n    if (ids.empty()) return;\n    int h = x1 - x0;\n    int w = y1 - y0;\n    if (ids.size() == 1) {\n        RectInfo &r = rects[ids[0]];\n        r.i0 = x0; r.j0 = y0; r.i1 = x1; r.j1 = y1;\n        r.area = 1LL * (r.i1 - r.i0) * (r.j1 - r.j0);\n        return;\n    }\n\n    vector<long long> prefix(ids.size() + 1, 0);\n    long long total = 0;\n    for (int i = 0; i < (int)ids.size(); ++i) {\n        total += target_area[ids[i]];\n        prefix[i + 1] = total;\n    }\n\n    int bestMid = 1;\n    long long bestDiff = (1LL << 62);\n    for (int mid = 1; mid < (int)ids.size(); ++mid) {\n        long long leftSum = prefix[mid];\n        long long diff = llabs(leftSum * 2 - total);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestMid = mid;\n        }\n    }\n\n    vector<int> left(ids.begin(), ids.begin() + bestMid);\n    vector<int> right(ids.begin() + bestMid, ids.end());\n    long long sumLeft = prefix[bestMid];\n    long long sumRight = total - sumLeft;\n\n    bool splitHorizontal;\n    if (h >= 2 && w >= 2) splitHorizontal = (h >= w);\n    else if (h >= 2) splitHorizontal = true;\n    else splitHorizontal = false; // width >= 2 here\n\n    if (splitHorizontal) {\n        int split = (int)llround((long double)h * sumLeft / total);\n        split = max(1, min(h - 1, split));\n        long long minTop = max<long long>(1, (sumLeft + w - 1) / w);\n        long long maxTop = min<long long>(h - 1, h - max<long long>(1, (sumRight + w - 1) / w));\n        if (minTop <= maxTop) {\n            if (split < minTop) split = (int)minTop;\n            if (split > maxTop) split = (int)maxTop;\n        }\n        split = max(1, min(h - 1, split));\n        build_rectangles(left,  x0,       y0, x0 + split, y1);\n        build_rectangles(right, x0 + split, y0, x1,       y1);\n    } else {\n        int split = (int)llround((long double)w * sumLeft / total);\n        split = max(1, min(w - 1, split));\n        long long minLeft = max<long long>(1, (sumLeft + h - 1) / h);\n        long long maxLeft = min<long long>(w - 1, w - max<long long>(1, (sumRight + h - 1) / h));\n        if (minLeft <= maxLeft) {\n            if (split < minLeft) split = (int)minLeft;\n            if (split > maxLeft) split = (int)maxLeft;\n        }\n        split = max(1, min(w - 1, split));\n        build_rectangles(left,  x0, y0,       x1, y0 + split);\n        build_rectangles(right, x0, y0 + split, x1, y1);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> W >> D >> N)) return 0;\n    demands.assign(D, vector<int>(N));\n    for (int d = 0; d < D; ++d) for (int k = 0; k < N; ++k) cin >> demands[d][k];\n\n    vector<vector<int>> orderStats(N, vector<int>(D));\n    for (int j = 0; j < N; ++j) {\n        for (int d = 0; d < D; ++d) orderStats[j][d] = demands[d][N - 1 - j]; // kth largest\n        sort(orderStats[j].begin(), orderStats[j].end());\n    }\n\n    const int baseMin = 1;\n    target_area.assign(N, baseMin);\n    long long remaining = 1LL * W * W - 1LL * baseMin * N;\n\n    vector<int> idx(N, 0);\n    struct Node { int benefit; long long len; int j; };\n    struct PQCmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.benefit != b.benefit) return a.benefit < b.benefit;\n            if (a.len != b.len) return a.len < b.len;\n            return a.j > b.j;\n        }\n    };\n    priority_queue<Node, vector<Node>, PQCmp> pq;\n\n    auto pushNode = [&](int j) {\n        while (idx[j] < D && (long long)orderStats[j][idx[j]] <= target_area[j]) idx[j]++;\n        if (idx[j] >= D) return;\n        long long len = (long long)orderStats[j][idx[j]] - target_area[j];\n        if (len <= 0) return;\n        int benefit = D - idx[j];\n        if (benefit <= 0) return;\n        pq.push(Node{benefit, len, j});\n    };\n    for (int j = 0; j < N; ++j) pushNode(j);\n\n    while (remaining > 0 && !pq.empty()) {\n        Node node = pq.top(); pq.pop();\n        long long take = min(node.len, remaining);\n        target_area[node.j] += take;\n        remaining -= take;\n        node.len -= take;\n        if (node.len > 0) {\n            pq.push(node);\n        } else {\n            pushNode(node.j);\n        }\n    }\n\n    rects.assign(N, RectInfo());\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int x, int y) {\n        if (target_area[x] != target_area[y]) return target_area[x] > target_area[y];\n        return x < y;\n    });\n    build_rectangles(order, 0, 0, W, W);\n\n    for (int i = 0; i < N; ++i) {\n        rects[i].area = 1LL * (rects[i].i1 - rects[i].i0) * (rects[i].j1 - rects[i].j0);\n        if (rects[i].area <= 0) {\n            rects[i].i1 = rects[i].i0 + 1;\n            rects[i].j1 = rects[i].j0 + 1;\n            rects[i].area = 1;\n        }\n    }\n\n    vector<pair<long long, int>> rectOrder(N);\n    for (int i = 0; i < N; ++i) rectOrder[i] = {rects[i].area, i};\n    sort(rectOrder.begin(), rectOrder.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n\n    vector<vector<int>> assigned(D, vector<int>(N));\n    vector<pair<int, int>> req(N);\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) req[k] = {demands[d][k], k};\n        sort(req.begin(), req.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 t = 0; t < N; ++t) {\n            assigned[d][req[t].second] = rectOrder[t].second;\n        }\n    }\n\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) {\n            const RectInfo& r = rects[assigned[d][k]];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Operation {\n    int stamp;\n    int p, q;\n    array<int, 9> cells;\n    array<int, 9> adds;\n};\n\nstruct Solver {\n    static constexpr int MOD = 998244353;\n    int N, M, K;\n    vector<int> board_mod;\n    vector<Operation> ops;\n    vector<char> used;\n    vector<int> used_ops;\n    vector<int> pos_in_used;\n    long long current_score = 0;\n    long long best_score = 0;\n    vector<int> best_ops;\n\n    mt19937 rng;\n    uniform_real_distribution<double> dist01;\n\n    Solver() : rng(random_device{}()), dist01(0.0, 1.0) {}\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        auto global_start = chrono::steady_clock::now();\n\n        cin >> N >> M >> K;\n        vector<int> initial(N * N);\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                cin >> initial[i * N + j];\n            }\n        }\n        vector<array<array<int, 3>, 3>> stamps(M);\n        for (int m = 0; m < M; ++m) {\n            for (int i = 0; i < 3; ++i) {\n                for (int j = 0; j < 3; ++j) {\n                    cin >> stamps[m][i][j];\n                }\n            }\n        }\n\n        build_operations(stamps);\n\n        board_mod = initial;\n        used.assign(ops.size(), 0);\n        pos_in_used.assign(ops.size(), -1);\n        used_ops.clear();\n        used_ops.reserve(K);\n\n        current_score = 0;\n        for (int v : board_mod) current_score += v;\n        best_score = current_score;\n        best_ops = used_ops;\n\n        greedy_init();\n\n        constexpr double TOTAL_TIME_LIMIT = 1.90; // seconds\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n        double remaining = TOTAL_TIME_LIMIT - elapsed;\n        if (remaining > 0.05 && !ops.empty()) {\n            simulated_annealing(max(0.01, remaining - 0.01));\n        }\n\n        output_best();\n    }\n\n    void build_operations(const vector<array<array<int, 3>, 3>>& stamps) {\n        ops.clear();\n        int placements = (N - 2) * (N - 2);\n        ops.reserve(M * placements);\n        for (int m = 0; m < M; ++m) {\n            for (int p = 0; p <= N - 3; ++p) {\n                for (int q = 0; q <= N - 3; ++q) {\n                    Operation op;\n                    op.stamp = m;\n                    op.p = p;\n                    op.q = q;\n                    int idx = 0;\n                    for (int i = 0; i < 3; ++i) {\n                        for (int j = 0; j < 3; ++j) {\n                            op.cells[idx] = (p + i) * N + (q + j);\n                            op.adds[idx] = stamps[m][i][j];\n                            ++idx;\n                        }\n                    }\n                    ops.push_back(op);\n                }\n            }\n        }\n    }\n\n    long long apply_operation(int op_idx) {\n        const Operation& op = ops[op_idx];\n        long long delta = 0;\n        for (int t = 0; t < 9; ++t) {\n            int add = op.adds[t];\n            if (add == 0) continue;\n            int idx = op.cells[t];\n            int before = board_mod[idx];\n            int after = before + add;\n            if (after >= MOD) after -= MOD;\n            board_mod[idx] = after;\n            delta += after - before;\n        }\n        return delta;\n    }\n\n    long long remove_operation(int op_idx) {\n        const Operation& op = ops[op_idx];\n        long long delta = 0;\n        for (int t = 0; t < 9; ++t) {\n            int add = op.adds[t];\n            if (add == 0) continue;\n            int idx = op.cells[t];\n            int before = board_mod[idx];\n            int after = before - add;\n            if (after < 0) after += MOD;\n            board_mod[idx] = after;\n            delta += after - before;\n        }\n        return delta;\n    }\n\n    void greedy_init() {\n        for (int iter = 0; iter < K; ++iter) {\n            long long best_delta = 0;\n            int best_idx = -1;\n            for (int op_idx = 0; op_idx < (int)ops.size(); ++op_idx) {\n                if (used[op_idx]) continue;\n                const Operation& op = ops[op_idx];\n                long long delta = 0;\n                for (int t = 0; t < 9; ++t) {\n                    int add = op.adds[t];\n                    if (add == 0) continue;\n                    int idx = op.cells[t];\n                    int before = board_mod[idx];\n                    int after = before + add;\n                    if (after >= MOD) after -= MOD;\n                    delta += after - before;\n                }\n                if (delta > best_delta) {\n                    best_delta = delta;\n                    best_idx = op_idx;\n                }\n            }\n            if (best_idx == -1 || best_delta <= 0) break;\n            long long delta = apply_operation(best_idx);\n            current_score += delta;\n            used[best_idx] = 1;\n            pos_in_used[best_idx] = used_ops.size();\n            used_ops.push_back(best_idx);\n            if (current_score > best_score) {\n                best_score = current_score;\n                best_ops = used_ops;\n            }\n        }\n    }\n\n    int pick_random_unused() {\n        if ((int)used_ops.size() >= (int)ops.size()) return -1;\n        for (int attempt = 0; attempt < 32; ++attempt) {\n            int idx = rng() % ops.size();\n            if (!used[idx]) return idx;\n        }\n        for (int idx = 0; idx < (int)ops.size(); ++idx) {\n            if (!used[idx]) return idx;\n        }\n        return -1;\n    }\n\n    bool accept_move(long long delta, double temp) {\n        if (delta >= 0) return true;\n        if (temp <= 1e-9) return false;\n        double ratio = delta / temp;\n        if (ratio < -50.0) return false;\n        double prob = exp(ratio);\n        return dist01(rng) < prob;\n    }\n\n    void simulated_annealing(double time_limit) {\n        auto start = chrono::steady_clock::now();\n        auto end_time = start + chrono::duration<double>(time_limit);\n        const double START_TEMP = 5e8;\n        const double END_TEMP = 5e2;\n        double temp = START_TEMP;\n        long long iter = 0;\n\n        while (true) {\n            if ((iter & 63) == 0) {\n                auto now = chrono::steady_clock::now();\n                if (now >= end_time) break;\n                double elapsed = chrono::duration<double>(now - start).count();\n                double progress = min(1.0, max(0.0, elapsed / time_limit));\n                temp = START_TEMP + (END_TEMP - START_TEMP) * progress;\n                if (temp < 1.0) temp = 1.0;\n            }\n            ++iter;\n\n            int used_cnt = (int)used_ops.size();\n            int move_type;\n            if (used_cnt == 0) {\n                move_type = 0;\n            } else if (used_cnt >= K) {\n                move_type = (rng() & 1) ? 1 : 2;\n            } else {\n                move_type = rng() % 3;\n            }\n\n            if (move_type == 0) { // add\n                int op_idx = pick_random_unused();\n                if (op_idx == -1) continue;\n                long long delta = apply_operation(op_idx);\n                current_score += delta;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    used[op_idx] = 1;\n                    pos_in_used[op_idx] = used_ops.size();\n                    used_ops.push_back(op_idx);\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev = remove_operation(op_idx);\n                    current_score += rev;\n                }\n            } else if (move_type == 1) { // remove\n                if (used_cnt == 0) continue;\n                int pos = rng() % used_cnt;\n                int op_idx = used_ops[pos];\n                long long delta = remove_operation(op_idx);\n                current_score += delta;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    int last_op = used_ops.back();\n                    used_ops[pos] = last_op;\n                    pos_in_used[last_op] = pos;\n                    used_ops.pop_back();\n                    used[op_idx] = 0;\n                    pos_in_used[op_idx] = -1;\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev = apply_operation(op_idx);\n                    current_score += rev;\n                }\n            } else { // swap\n                if (used_cnt == 0) continue;\n                int op_add = pick_random_unused();\n                if (op_add == -1) continue;\n                int pos = rng() % used_cnt;\n                int op_remove = used_ops[pos];\n\n                long long delta_remove = remove_operation(op_remove);\n                current_score += delta_remove;\n\n                long long delta_add = apply_operation(op_add);\n                current_score += delta_add;\n\n                long long delta = delta_remove + delta_add;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    int last_op = used_ops.back();\n                    used_ops[pos] = last_op;\n                    pos_in_used[last_op] = pos;\n                    used_ops.pop_back();\n                    used[op_remove] = 0;\n                    pos_in_used[op_remove] = -1;\n\n                    used[op_add] = 1;\n                    pos_in_used[op_add] = used_ops.size();\n                    used_ops.push_back(op_add);\n\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev_add = remove_operation(op_add);\n                    current_score += rev_add;\n                    long long rev_remove = apply_operation(op_remove);\n                    current_score += rev_remove;\n                }\n            }\n        }\n    }\n\n    void output_best() const {\n        cout << best_ops.size() << '\\n';\n        for (int idx : best_ops) {\n            const Operation& op = ops[idx];\n            cout << op.stamp << ' ' << op.p << ' ' << op.q << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\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>> A(N, vector<int>(N));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) cin >> A[i][j];\n    }\n\n    vector<string> ops(N);\n    string mainOps;\n    int curR = 0, curC = 0;\n    auto move_to = [&](int tr, int tc) {\n        while (curR < tr) { mainOps.push_back('D'); ++curR; }\n        while (curR > tr) { mainOps.push_back('U'); --curR; }\n        while (curC < tc) { mainOps.push_back('R'); ++curC; }\n        while (curC > tc) { mainOps.push_back('L'); --curC; }\n    };\n\n    for (int src = 0; src < N; ++src) {\n        for (int idx = 0; idx < N; ++idx) {\n            move_to(src, 0);\n            mainOps.push_back('P');\n            int container = A[src][idx];\n            int target_row = container / N;\n            move_to(target_row, N - 1);\n            mainOps.push_back('Q');\n        }\n    }\n    if (mainOps.empty()) mainOps.push_back('.');  // safety, though not expected\n\n    ops[0] = mainOps;\n    int T = static_cast<int>(ops[0].size());\n\n    for (int i = 1; i < N; ++i) {\n        string s(max(T, 1), '.');\n        s[0] = 'B';  // bomb immediately\n        ops[i] = s;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << ops[i] << \"\\n\";\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\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    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) cin >> h[i][j];\n    }\n\n    vector<string> ops;\n    ops.reserve(120000);\n\n    int cur_r = 0, cur_c = 0;\n    long long load = 0;\n\n    auto moveTo = [&](int tr, int tc) {\n        while (cur_r < tr) { ops.emplace_back(\"D\"); ++cur_r; }\n        while (cur_r > tr) { ops.emplace_back(\"U\"); --cur_r; }\n        while (cur_c < tc) { ops.emplace_back(\"R\"); ++cur_c; }\n        while (cur_c > tc) { ops.emplace_back(\"L\"); --cur_c; }\n    };\n\n    auto hasPosNeg = [&]() -> pair<bool, bool> {\n        bool pos = false, neg = false;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (h[i][j] > 0) pos = true;\n                else if (h[i][j] < 0) neg = true;\n            }\n        }\n        return {pos, neg};\n    };\n\n    auto findNearest = [&](bool positive) -> pair<int, int> {\n        int bestDist = INT_MAX;\n        int bestAmount = -1;\n        pair<int, int> best{-1, -1};\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int val = h[i][j];\n                if (positive) {\n                    if (val <= 0) continue;\n                    int dist = abs(cur_r - i) + abs(cur_c - j);\n                    if (dist < bestDist || (dist == bestDist && val > bestAmount)) {\n                        bestDist = dist;\n                        bestAmount = val;\n                        best = {i, j};\n                    }\n                } else {\n                    if (val >= 0) continue;\n                    int need = -val;\n                    int dist = abs(cur_r - i) + abs(cur_c - j);\n                    if (dist < bestDist || (dist == bestDist && need > bestAmount)) {\n                        bestDist = dist;\n                        bestAmount = need;\n                        best = {i, j};\n                    }\n                }\n            }\n        }\n        return best;\n    };\n\n    int safety = 0;\n    const int SAFETY_LIMIT = 1000000;\n    while (safety < SAFETY_LIMIT) {\n        auto [hasPos, hasNeg] = hasPosNeg();\n        if (!hasPos && load == 0 && !hasNeg) break;\n\n        if (load == 0) {\n            if (!hasPos) break;\n            auto target = findNearest(true);\n            if (target.first == -1) break;\n            int tr = target.first, tc = target.second;\n            moveTo(tr, tc);\n            int amount = h[tr][tc];\n            if (amount <= 0) { ++safety; continue; }\n            ops.emplace_back(\"+\" + to_string(amount));\n            load += amount;\n            h[tr][tc] -= amount;\n        } else {\n            if (!hasNeg) {\n                moveTo(0, 0);\n                if (load > 0) {\n                    ops.emplace_back(\"-\" + to_string(load));\n                    h[0][0] += static_cast<int>(load);\n                    load = 0;\n                }\n                ++safety;\n                continue;\n            }\n            auto target = findNearest(false);\n            if (target.first == -1) {\n                moveTo(0, 0);\n                if (load > 0) {\n                    ops.emplace_back(\"-\" + to_string(load));\n                    h[0][0] += static_cast<int>(load);\n                    load = 0;\n                }\n                ++safety;\n                continue;\n            }\n            int tr = target.first, tc = target.second;\n            moveTo(tr, tc);\n            int need = -h[tr][tc];\n            if (need <= 0) { ++safety; continue; }\n            int amount = static_cast<int>(min<long long>(load, need));\n            if (amount <= 0) { ++safety; continue; }\n            ops.emplace_back(\"-\" + to_string(amount));\n            load -= amount;\n            h[tr][tc] += amount;\n        }\n        ++safety;\n    }\n\n    if (load > 0) {\n        moveTo(0, 0);\n        ops.emplace_back(\"-\" + to_string(load));\n        h[0][0] += static_cast<int>(load);\n        load = 0;\n    }\n\n    auto isAllZero = [&]() -> bool {\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                if (h[i][j] != 0) return false;\n        return true;\n    };\n\n    auto cleanupStep = [&]() {\n        if (load > 0) {\n            moveTo(0, 0);\n            ops.emplace_back(\"-\" + to_string(load));\n            h[0][0] += static_cast<int>(load);\n            load = 0;\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (i == 0 && j == 0) continue;\n                int val = h[i][j];\n                if (val <= 0) continue;\n                moveTo(i, j);\n                ops.emplace_back(\"+\" + to_string(val));\n                load += val;\n                h[i][j] -= val;\n                moveTo(0, 0);\n                ops.emplace_back(\"-\" + to_string(val));\n                load -= val;\n                h[0][0] += val;\n            }\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                while (h[i][j] < 0) {\n                    if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n                    int need = -h[i][j];\n                    int amount = min(need, h[0][0]);\n                    if (amount <= 0) return;\n                    ops.emplace_back(\"+\" + to_string(amount));\n                    load += amount;\n                    h[0][0] -= amount;\n                    moveTo(i, j);\n                    ops.emplace_back(\"-\" + to_string(amount));\n                    load -= amount;\n                    h[i][j] += amount;\n                }\n            }\n        }\n    };\n\n    int cleanupIter = 0;\n    while (!isAllZero() && cleanupIter < 2) {\n        cleanupStep();\n        ++cleanupIter;\n    }\n\n    if (load > 0) {\n        moveTo(0, 0);\n        ops.emplace_back(\"-\" + to_string(load));\n        h[0][0] += static_cast<int>(load);\n        load = 0;\n    }\n\n    for (const string &op : ops) cout << op << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAX_M = 15;\nconstexpr int MAX_TOTAL = 2000;\nconstexpr int MAX_TARGETS = 5;\n\nstruct Seed {\n    array<int, MAX_M> attr;\n    int value;\n    Seed() {\n        attr.fill(0);\n        value = 0;\n    }\n};\n\ndouble computePairScore(const Seed& A, const Seed& B,\n                        const vector<int>& targets,\n                        const vector<double>& weights,\n                        const vector<double>& probWeights,\n                        int M,\n                        int bestValue,\n                        double potentialWeight,\n                        const vector<int>& attrTargets,\n                        const vector<double>& attrWeights,\n                        double attrComponentScale) {\n    static array<double, MAX_TOTAL> dp{};\n    static array<double, MAX_TOTAL> ndp{};\n\n    double attrScore = 0.0;\n    if (!attrWeights.empty()) {\n        for (int l = 0; l < M; ++l) {\n            double w = attrWeights[l];\n            if (w <= 1e-9) continue;\n            int target = attrTargets[l];\n            bool aGood = A.attr[l] >= target;\n            bool bGood = B.attr[l] >= target;\n            if (!aGood && !bGood) continue;\n            attrScore += (aGood && bGood) ? w : (w * 0.5);\n        }\n    }\n    double total = attrScore * attrComponentScale;\n\n    int maxSum = 0;\n    for (int l = 0; l < M; ++l) {\n        maxSum += max(A.attr[l], B.attr[l]);\n    }\n    if (maxSum + 1 > MAX_TOTAL) maxSum = MAX_TOTAL - 1;\n\n    fill(dp.begin(), dp.begin() + (maxSum + 1), 0.0);\n    dp[0] = 1.0;\n    int currentMax = 0;\n    for (int l = 0; l < M; ++l) {\n        int aVal = A.attr[l];\n        int bVal = B.attr[l];\n        int add = max(aVal, bVal);\n        int nextMax = currentMax + add;\n        if (nextMax > MAX_TOTAL - 1) nextMax = MAX_TOTAL - 1;\n        fill(ndp.begin(), ndp.begin() + (nextMax + 1), 0.0);\n        for (int s = 0; s <= currentMax; ++s) {\n            double prob = dp[s];\n            if (prob == 0.0) continue;\n            if (s + aVal <= nextMax) ndp[s + aVal] += prob * 0.5;\n            if (s + bVal <= nextMax) ndp[s + bVal] += prob * 0.5;\n        }\n        currentMax = nextMax;\n        dp.swap(ndp);\n    }\n\n    int K = targets.size();\n    if (K == 0) {\n        double potential = currentMax - bestValue;\n        if (potential > 0) total += potentialWeight * potential;\n        return total;\n    }\n\n    array<double, MAX_TARGETS> tailProb{};\n    array<double, MAX_TARGETS> tailSum{};\n    int minTarget = targets.front();\n    if (minTarget < 0) minTarget = 0;\n    if (currentMax > minTarget) {\n        for (int s = currentMax; s > minTarget; --s) {\n            double prob = dp[s];\n            if (prob == 0.0) continue;\n            for (int idx = 0; idx < K; ++idx) {\n                if (s > targets[idx]) {\n                    tailProb[idx] += prob;\n                    tailSum[idx] += prob * s;\n                } else {\n                    break;\n                }\n            }\n        }\n    }\n\n    for (int idx = 0; idx < K; ++idx) {\n        double sc = tailSum[idx] - static_cast<double>(targets[idx]) * tailProb[idx];\n        if (sc < 0) sc = 0;\n        total += weights[idx] * sc + probWeights[idx] * tailProb[idx];\n    }\n\n    double potential = currentMax - bestValue;\n    if (potential > 0) total += potentialWeight * potential;\n    return total;\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    int seedCount = 2 * N * (N - 1);\n    int selectCount = N * N;\n    vector<Seed> seeds(seedCount);\n    for (int i = 0; i < seedCount; ++i) {\n        int sum = 0;\n        for (int j = 0; j < M; ++j) {\n            int val;\n            cin >> val;\n            seeds[i].attr[j] = val;\n            sum += val;\n        }\n        for (int j = M; j < MAX_M; ++j) seeds[i].attr[j] = 0;\n        seeds[i].value = sum;\n    }\n\n    const int cellCount = selectCount;\n    vector<vector<int>> neighbors(cellCount);\n    vector<pair<int, int>> edges;\n    edges.reserve(2 * N * (N - 1));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int pos = i * N + j;\n            if (j + 1 < N) {\n                int q = pos + 1;\n                neighbors[pos].push_back(q);\n                neighbors[q].push_back(pos);\n                edges.emplace_back(pos, q);\n            }\n            if (i + 1 < N) {\n                int q = pos + N;\n                neighbors[pos].push_back(q);\n                neighbors[q].push_back(pos);\n                edges.emplace_back(pos, q);\n            }\n        }\n    }\n    vector<int> cellDegree(cellCount, 0);\n    for (int pos = 0; pos < cellCount; ++pos) {\n        sort(neighbors[pos].begin(), neighbors[pos].end());\n        neighbors[pos].erase(unique(neighbors[pos].begin(), neighbors[pos].end()), neighbors[pos].end());\n        cellDegree[pos] = (int)neighbors[pos].size();\n    }\n\n    vector<int> positionOrder(cellCount);\n    iota(positionOrder.begin(), positionOrder.end(), 0);\n    double center = (N - 1) / 2.0;\n    vector<double> cellDist(cellCount, 0.0);\n    for (int pos = 0; pos < cellCount; ++pos) {\n        int r = pos / N;\n        int c = pos % N;\n        cellDist[pos] = fabs(r - center) + fabs(c - center);\n    }\n    sort(positionOrder.begin(), positionOrder.end(), [&](int a, int b) {\n        if (fabs(cellDist[a] - cellDist[b]) > 1e-9) return cellDist[a] < cellDist[b];\n        if (cellDegree[a] != cellDegree[b]) return cellDegree[a] > cellDegree[b];\n        return a < b;\n    });\n\n    mt19937 rng(712367);\n    uniform_real_distribution<double> realDist(0.0, 1.0);\n    uniform_int_distribution<int> posDist(0, cellCount - 1);\n\n    vector<int> orderIndices(seedCount);\n\n    for (int turn = 0; turn < T; ++turn) {\n        vector<int> bestAttrValue(M, -1);\n        vector<int> secondAttrValue(M, -1);\n        vector<int> bestAttrIndex(M, -1);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            for (int l = 0; l < M; ++l) {\n                int val = seeds[idx].attr[l];\n                if (val > bestAttrValue[l]) {\n                    secondAttrValue[l] = bestAttrValue[l];\n                    bestAttrValue[l] = val;\n                    bestAttrIndex[l] = idx;\n                } else if (val == bestAttrValue[l]) {\n                    if (bestAttrIndex[l] == -1 || seeds[idx].value > seeds[bestAttrIndex[l]].value) {\n                        secondAttrValue[l] = bestAttrValue[l];\n                        bestAttrValue[l] = val;\n                        bestAttrIndex[l] = idx;\n                    } else if (val > secondAttrValue[l]) {\n                        secondAttrValue[l] = val;\n                    }\n                } else if (val > secondAttrValue[l]) {\n                    secondAttrValue[l] = val;\n                }\n            }\n        }\n\n        vector<int> seedChampionCount(seedCount, 0);\n        vector<int> attrTopCount(M, 0);\n        for (int l = 0; l < M; ++l) {\n            if (bestAttrValue[l] < 0) continue;\n            for (int idx = 0; idx < seedCount; ++idx) {\n                if (seeds[idx].attr[l] == bestAttrValue[l]) {\n                    ++attrTopCount[l];\n                    ++seedChampionCount[idx];\n                }\n            }\n        }\n\n        int bestValue = 0;\n        for (const auto& s : seeds) bestValue = max(bestValue, s.value);\n\n        int targetMax = 0;\n        for (int l = 0; l < M; ++l) targetMax += max(0, bestAttrValue[l]);\n\n        vector<int> selectedIndices;\n        selectedIndices.reserve(selectCount);\n        vector<char> used(seedCount, false);\n        for (int l = 0; l < M; ++l) {\n            int idx = bestAttrIndex[l];\n            if (idx >= 0 && !used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n        iota(orderIndices.begin(), orderIndices.end(), 0);\n        sort(orderIndices.begin(), orderIndices.end(), [&](int a, int b) {\n            if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n            return a < b;\n        });\n        for (int idx : orderIndices) {\n            if ((int)selectedIndices.size() >= selectCount) break;\n            if (!used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n        for (int idx = 0; idx < seedCount && (int)selectedIndices.size() < selectCount; ++idx) {\n            if (!used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n\n        vector<int> selectedValues(selectCount);\n        vector<int> selectedAttrCount(selectCount);\n        for (int i = 0; i < selectCount; ++i) {\n            selectedValues[i] = seeds[selectedIndices[i]].value;\n            selectedAttrCount[i] = seedChampionCount[selectedIndices[i]];\n        }\n\n        const int maintainMargin = 8;\n        int maintainTarget = max(0, bestValue - maintainMargin);\n        int gap = max(0, targetMax - bestValue);\n        double phase = (T <= 1) ? 1.0 : (double)turn / (T - 1);\n        double gapFactor = min(1.0, (gap + 5.0) / 60.0);\n        int improveMargin1 = max(3, (int)round(min(gap * 0.35, 40.0)));\n        int improveMargin2 = max(improveMargin1 + 3, (int)round(min(gap * 0.65, 80.0)));\n        int targetImprove1 = min(bestValue + improveMargin1, targetMax);\n        int targetImprove2 = min(bestValue + improveMargin2, targetMax);\n\n        double improvementScale = (0.5 + 0.5 * (1.0 - phase)) * (0.4 + 0.6 * gapFactor);\n        improvementScale = clamp(improvementScale, 0.25, 1.2);\n        double maintainWeight = 0.8 + 0.5 * phase;\n        double maintainProbWeight = 0.05;\n        double improve1Weight = 4.0 * improvementScale;\n        double improve2Weight = 8.0 * improvementScale;\n        double improve1ProbWeight = 0.8 * improvementScale;\n        double improve2ProbWeight = 1.6 * improvementScale;\n        double potentialWeight = 0.02 + 0.04 * improvementScale;\n\n        vector<int> targets;\n        vector<double> weights, probWeights;\n        targets.reserve(MAX_TARGETS);\n        weights.reserve(MAX_TARGETS);\n        probWeights.reserve(MAX_TARGETS);\n        auto addTarget = [&](int target, double w, double pw) {\n            target = clamp(target, 0, targetMax);\n            if (!targets.empty() && target <= targets.back()) return;\n            if ((int)targets.size() >= MAX_TARGETS) return;\n            targets.push_back(target);\n            weights.push_back(w);\n            probWeights.push_back(pw);\n        };\n        addTarget(maintainTarget, maintainWeight, maintainProbWeight);\n        if (targetImprove1 > maintainTarget) addTarget(targetImprove1, improve1Weight, improve1ProbWeight);\n        if (targetImprove2 > targetImprove1) addTarget(targetImprove2, improve2Weight, improve2ProbWeight);\n\n        vector<int> attrTargets(M, 0);\n        vector<double> attrWeights(M, 0.0);\n        for (int l = 0; l < M; ++l) {\n            int bestVal = bestAttrValue[l];\n            if (bestVal <= 8) {\n                attrTargets[l] = bestVal + 1;\n                attrWeights[l] = 0.0;\n                continue;\n            }\n            int secondVal = max(0, secondAttrValue[l]);\n            int gapAttr = max(0, bestVal - secondVal);\n            int approx = (bestVal * 92 + 50) / 100;\n            int margin = max(1, gapAttr / 2);\n            int target = bestVal - margin;\n            target = max(target, approx);\n            target = max(target, bestVal - 6);\n            target = min(target, bestVal);\n            attrTargets[l] = max(0, target);\n            int bestCount = max(1, attrTopCount[l]);\n            double rarity = 1.0;\n            if (bestVal >= 90) rarity += 0.3;\n            else if (bestVal >= 80) rarity += 0.2;\n            if (gapAttr >= 5) rarity += 0.25;\n            if (gapAttr >= 10) rarity += 0.25;\n            if (bestCount <= 3) rarity += 0.25;\n            if (bestCount == 1) rarity += 0.35;\n            attrWeights[l] = rarity;\n        }\n        double attrComponentScale = (4.0 + 3.0 * (1.0 - phase)) * (0.85 + 0.25 * gapFactor);\n\n        int S = selectCount;\n        vector<double> pairScore((size_t)S * S, 0.0);\n        for (int i = 0; i < S; ++i) {\n            pairScore[i * S + i] = 0.0;\n            for (int j = i + 1; j < S; ++j) {\n                double val = computePairScore(seeds[selectedIndices[i]],\n                                              seeds[selectedIndices[j]],\n                                              targets, weights, probWeights,\n                                              M, bestValue, potentialWeight,\n                                              attrTargets, attrWeights, attrComponentScale);\n                pairScore[i * S + j] = val;\n                pairScore[j * S + i] = val;\n            }\n        }\n\n        vector<int> localOrder(S);\n        iota(localOrder.begin(), localOrder.end(), 0);\n        shuffle(localOrder.begin(), localOrder.end(), rng);\n        sort(localOrder.begin(), localOrder.end(), [&](int a, int b) {\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            return selectedIndices[a] < selectedIndices[b];\n        });\n\n        vector<int> assign(cellCount, -1);\n        for (int idx = 0; idx < cellCount; ++idx) {\n            assign[positionOrder[idx]] = localOrder[idx];\n        }\n\n        double edgeScore = 0.0;\n        for (auto [u, v] : edges) {\n            int su = assign[u];\n            int sv = assign[v];\n            edgeScore += pairScore[su * S + sv];\n        }\n        double degTerm = 0.0;\n        for (int pos = 0; pos < cellCount; ++pos) {\n            degTerm += cellDegree[pos] * selectedValues[assign[pos]];\n        }\n        double degWeight = 0.02 * (0.9 - 0.4 * phase);\n        double currentScore = edgeScore + degWeight * degTerm;\n        double bestScore = currentScore;\n        vector<int> bestAssign = assign;\n\n        int maxIter = 6000 + (int)(2000 * (1.0 - phase));\n        double Tstart = 1.2 * improvementScale + 0.3;\n        double Tend = 0.01;\n        array<pair<int, int>, 16> impacted{};\n\n        for (int iter = 0; iter < maxIter; ++iter) {\n            int pos1 = posDist(rng);\n            int pos2 = posDist(rng);\n            if (pos1 == pos2) continue;\n            int seed1 = assign[pos1];\n            int seed2 = assign[pos2];\n            if (seed1 == seed2) continue;\n\n            int cnt = 0;\n            auto addEdgeLocal = [&](int a, int b) {\n                if (a > b) swap(a, b);\n                for (int k = 0; k < cnt; ++k) {\n                    if (impacted[k].first == a && impacted[k].second == b) return;\n                }\n                impacted[cnt++] = {a, b};\n            };\n            for (int nb : neighbors[pos1]) addEdgeLocal(pos1, nb);\n            for (int nb : neighbors[pos2]) addEdgeLocal(pos2, nb);\n\n            double beforeEdge = 0.0;\n            for (int k = 0; k < cnt; ++k) {\n                int a = impacted[k].first;\n                int b = impacted[k].second;\n                beforeEdge += pairScore[assign[a] * S + assign[b]];\n            }\n\n            double deltaPos = degWeight * (double)(selectedValues[seed2] - selectedValues[seed1]) *\n                              (cellDegree[pos1] - cellDegree[pos2]);\n\n            swap(assign[pos1], assign[pos2]);\n\n            double afterEdge = 0.0;\n            for (int k = 0; k < cnt; ++k) {\n                int a = impacted[k].first;\n                int b = impacted[k].second;\n                afterEdge += pairScore[assign[a] * S + assign[b]];\n            }\n\n            double delta = (afterEdge - beforeEdge) + deltaPos;\n            double progress = (double)iter / maxIter;\n            double temperature = Tstart + (Tend - Tstart) * progress;\n            bool accept = false;\n            if (delta >= 0) {\n                accept = true;\n            } else if (temperature > 0) {\n                double prob = exp(delta / temperature);\n                if (realDist(rng) < prob) accept = true;\n            }\n            if (accept) {\n                currentScore += delta;\n                if (currentScore > bestScore) {\n                    bestScore = currentScore;\n                    bestAssign = assign;\n                }\n            } else {\n                swap(assign[pos1], assign[pos2]);\n            }\n        }\n\n        assign = bestAssign;\n\n        vector<vector<int>> grid(N, vector<int>(N, 0));\n        for (int pos = 0; pos < cellCount; ++pos) {\n            int r = pos / N;\n            int c = pos % N;\n            grid[r][c] = selectedIndices[assign[pos]];\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (j) cout << ' ';\n                cout << grid[i][j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        if (turn + 1 == T) break;\n        for (int i = 0; i < seedCount; ++i) {\n            int sum = 0;\n            for (int j = 0; j < M; ++j) {\n                int val;\n                cin >> val;\n                seeds[i].attr[j] = val;\n                sum += val;\n            }\n            seeds[i].value = sum;\n        }\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Cell {\n    int x, y;\n};\n\nvector<int> hungarian(const vector<vector<int>>& a) {\n    int n = (int)a.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        vector<int> minv(n + 1, INF);\n        vector<char> used(n + 1, false);\n        int j0 = 0;\n        do {\n            used[j0] = true;\n            int i0 = p[j0];\n            int delta = INF, j1 = 0;\n            for (int j = 1; j <= n; ++j) if (!used[j]) {\n                int cur = a[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= n; ++j) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    v[j] -= delta;\n                } else {\n                    minv[j] -= delta;\n                }\n            }\n            j0 = j1;\n        } while (p[j0] != 0);\n        do {\n            int j1 = way[j0];\n            p[j0] = p[j1];\n            j0 = j1;\n        } while (j0);\n    }\n    vector<int> match(n, -1);\n    for (int j = 1; j <= n; ++j) {\n        if (p[j] != 0) {\n            match[p[j] - 1] = j - 1;\n        }\n    }\n    return match;\n}\n\nuint64_t hilbertOrder(int x, int y, int pow2) {\n    uint64_t d = 0;\n    for (int s = pow2 / 2; s > 0; s >>= 1) {\n        int rx = (x & s) ? 1 : 0;\n        int ry = (y & s) ? 1 : 0;\n        d += (uint64_t)s * s * ((3 * rx) ^ ry);\n        if (ry == 0) {\n            if (rx == 1) {\n                x = pow2 - 1 - x;\n                y = pow2 - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n    return d;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, V;\n    cin >> N >> M >> V;\n    vector<string> s(N), t(N);\n    for (int i = 0; i < N; ++i) cin >> s[i];\n    for (int i = 0; i < N; ++i) cin >> t[i];\n\n    vector<vector<int>> occ(N, vector<int>(N, 0));\n    vector<Cell> surplus, deficit;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            occ[i][j] = s[i][j] - '0';\n            int ti = t[i][j] - '0';\n            if (occ[i][j] == 1 && ti == 0) surplus.push_back({i, j});\n            else if (occ[i][j] == 0 && ti == 1) deficit.push_back({i, j});\n        }\n    }\n\n    int K = surplus.size();\n    vector<int> match;\n    if (K > 0) {\n        vector<vector<int>> cost(K, vector<int>(K));\n        for (int i = 0; i < K; ++i) {\n            for (int j = 0; j < K; ++j) {\n                cost[i][j] = abs(surplus[i].x - deficit[j].x) + abs(surplus[i].y - deficit[j].y);\n            }\n        }\n        match = hungarian(cost);\n    }\n\n    int pow2 = 1;\n    while (pow2 < N) pow2 <<= 1;\n\n    vector<int> order(K);\n    iota(order.begin(), order.end(), 0);\n    vector<uint64_t> hilb(K, 0);\n    for (int i = 0; i < K; ++i) hilb[i] = hilbertOrder(surplus[i].x, surplus[i].y, pow2);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        return hilb[a] < hilb[b];\n    });\n\n    int root_x = (K > 0) ? surplus[order[0]].x : 0;\n    int root_y = (K > 0) ? surplus[order[0]].y : 0;\n\n    cout << 1 << '\\n';\n    cout << root_x << ' ' << root_y << '\\n';\n\n    if (K == 0) return 0;\n\n    const int LIMIT = 100000;\n    vector<string> ops;\n    ops.reserve(200000);\n    bool limitReached = false;\n    int rx = root_x, ry = root_y;\n    bool holding = false;\n\n    auto emit = [&](char moveChar, char actionChar) -> bool {\n        if ((int)ops.size() >= LIMIT) {\n            limitReached = true;\n            return false;\n        }\n        string op(2, '.');\n        op[0] = moveChar;\n        op[1] = actionChar;\n        ops.push_back(op);\n        if (moveChar == 'U') --rx;\n        else if (moveChar == 'D') ++rx;\n        else if (moveChar == 'L') --ry;\n        else if (moveChar == 'R') ++ry;\n        return true;\n    };\n\n    auto move_with_action = [&](int tx, int ty, bool doAction, bool isPick) {\n        if (limitReached) return;\n        vector<char> path;\n        int cx = rx, cy = ry;\n        while (cx < tx) { path.push_back('D'); ++cx; }\n        while (cx > tx) { path.push_back('U'); --cx; }\n        while (cy < ty) { path.push_back('R'); ++cy; }\n        while (cy > ty) { path.push_back('L'); --cy; }\n\n        if (path.empty()) {\n            if (doAction) emit('.', 'P');\n        } else {\n            for (size_t i = 0; i < path.size(); ++i) {\n                bool last = (i + 1 == path.size());\n                char actChar = (last && doAction) ? 'P' : '.';\n                if (!emit(path[i], actChar)) return;\n            }\n        }\n        if (doAction && !limitReached) {\n            if (isPick) {\n                assert(!holding);\n                assert(occ[tx][ty] == 1);\n                occ[tx][ty] = 0;\n                holding = true;\n            } else {\n                assert(holding);\n                assert(occ[tx][ty] == 0);\n                occ[tx][ty] = 1;\n                holding = false;\n            }\n        }\n    };\n\n    for (int idx : order) {\n        if (limitReached) break;\n        Cell sCell = surplus[idx];\n        Cell dCell = deficit[match[idx]];\n        move_with_action(sCell.x, sCell.y, true, true);\n        if (limitReached) break;\n        move_with_action(dCell.x, dCell.y, true, false);\n    }\n\n    for (const string &line : ops) cout << line << '\\n';\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAX_COORD = 100000;\nconst int NEG_INF = -1000000000;\nconstexpr double TIME_LIMIT = 1.92;\n\nstruct Score {\n    int diff;\n    int m;\n    int s;\n};\n\nstruct RectAns {\n    int x1 = 0, x2 = 0, y1 = 0, y2 = 0;\n    Score sc{NEG_INF, 0, 0};\n};\n\nstruct BIT2D {\n    int n = 0;\n    vector<int> xs_sorted;\n    vector<vector<int>> ys;\n    vector<vector<int>> bitM, bitS;\n\n    void build(const vector<int>& px, const vector<int>& py, const vector<int>& type) {\n        xs_sorted = px;\n        sort(xs_sorted.begin(), xs_sorted.end());\n        xs_sorted.erase(unique(xs_sorted.begin(), xs_sorted.end()), xs_sorted.end());\n        n = xs_sorted.size();\n        ys.assign(n + 1, {});\n        for (size_t idx = 0; idx < px.size(); ++idx) {\n            int xi = lower_bound(xs_sorted.begin(), xs_sorted.end(), px[idx]) - xs_sorted.begin() + 1;\n            for (int i = xi; i <= n; i += i & -i) ys[i].push_back(py[idx]);\n        }\n        bitM.assign(n + 1, {});\n        bitS.assign(n + 1, {});\n        for (int i = 1; i <= n; ++i) {\n            auto &vec = ys[i];\n            sort(vec.begin(), vec.end());\n            vec.erase(unique(vec.begin(), vec.end()), vec.end());\n            bitM[i].assign(vec.size() + 1, 0);\n            bitS[i].assign(vec.size() + 1, 0);\n        }\n        for (size_t idx = 0; idx < px.size(); ++idx) {\n            int xi = lower_bound(xs_sorted.begin(), xs_sorted.end(), px[idx]) - xs_sorted.begin() + 1;\n            int y = py[idx];\n            int deltaM = type[idx] == 1 ? 1 : 0;\n            int deltaS = type[idx] == -1 ? 1 : 0;\n            for (int i = xi; i <= n; i += i & -i) {\n                if (ys[i].empty()) continue;\n                int yi = lower_bound(ys[i].begin(), ys[i].end(), y) - ys[i].begin() + 1;\n                if (deltaM) {\n                    for (int j = yi; j < (int)bitM[i].size(); j += j & -j) bitM[i][j] += deltaM;\n                }\n                if (deltaS) {\n                    for (int j = yi; j < (int)bitS[i].size(); j += j & -j) bitS[i][j] += deltaS;\n                }\n            }\n        }\n    }\n\n    pair<int,int> prefix(int xVal, int yVal) const {\n        if (n == 0) return {0,0};\n        int xi = upper_bound(xs_sorted.begin(), xs_sorted.end(), xVal) - xs_sorted.begin();\n        int sumM = 0, sumS = 0;\n        for (int i = xi; i > 0; i -= i & -i) {\n            const auto &vec = ys[i];\n            if (vec.empty()) continue;\n            int yi = upper_bound(vec.begin(), vec.end(), yVal) - vec.begin();\n            for (int j = yi; j > 0; j -= j & -j) {\n                sumM += bitM[i][j];\n                sumS += bitS[i][j];\n            }\n        }\n        return {sumM, sumS};\n    }\n};\n\nBIT2D bit2d;\nint N;\nvector<int> xs, ys, types;\nvector<pair<int,int>> m_coords;\nRectAns best_rect;\nvector<RectAns> top_rects;\nconst int TOP_LIMIT = 16;\n\nmt19937 rng(chrono::steady_clock::now().time_since_epoch().count());\nchrono::steady_clock::time_point start_time;\n\ninline double elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n}\n\ninline bool normalize_rect(int &x1, int &x2, int &y1, int &y2) {\n    if (x1 > x2) swap(x1, x2);\n    if (y1 > y2) swap(y1, y2);\n    x1 = clamp(x1, 0, MAX_COORD);\n    x2 = clamp(x2, 0, MAX_COORD);\n    y1 = clamp(y1, 0, MAX_COORD);\n    y2 = clamp(y2, 0, MAX_COORD);\n    if (x1 == x2) {\n        if (x2 < MAX_COORD) ++x2;\n        else if (x1 > 0) --x1;\n    }\n    if (y1 == y2) {\n        if (y2 < MAX_COORD) ++y2;\n        else if (y1 > 0) --y1;\n    }\n    return x1 != x2 && y1 != y2;\n}\n\ninline long long rect_area(int x1, int x2, int y1, int y2) {\n    return 1LL * (x2 - x1) * (y2 - y1);\n}\n\nbool better_rect(const RectAns &a, const RectAns &b) {\n    if (b.sc.diff == NEG_INF) return true;\n    if (a.sc.diff != b.sc.diff) return a.sc.diff > b.sc.diff;\n    if (a.sc.m != b.sc.m) return a.sc.m > b.sc.m;\n    if (a.sc.s != b.sc.s) return a.sc.s < b.sc.s;\n    return rect_area(a.x1,a.x2,a.y1,a.y2) < rect_area(b.x1,b.x2,b.y1,b.y2);\n}\n\nvoid record_candidate(const RectAns &cand) {\n    for (auto &r : top_rects) {\n        if (r.x1 == cand.x1 && r.x2 == cand.x2 && r.y1 == cand.y1 && r.y2 == cand.y2) {\n            if (better_rect(cand, r)) r = cand;\n            return;\n        }\n    }\n    auto it = top_rects.begin();\n    while (it != top_rects.end() && !better_rect(cand, *it)) ++it;\n    top_rects.insert(it, cand);\n    if ((int)top_rects.size() > TOP_LIMIT) top_rects.pop_back();\n}\n\nScore compute_score(int x1, int x2, int y1, int y2) {\n    auto A = bit2d.prefix(x2, y2);\n    auto B = bit2d.prefix(x1 - 1, y2);\n    auto C = bit2d.prefix(x2, y1 - 1);\n    auto D = bit2d.prefix(x1 - 1, y1 - 1);\n    int m = A.first - B.first - C.first + D.first;\n    int s = A.second - B.second - C.second + D.second;\n    return {m - s, m, s};\n}\n\nvoid push_candidate(int x1, int x2, int y1, int y2, const Score &sc) {\n    RectAns cand{x1,x2,y1,y2,sc};\n    if (better_rect(cand, best_rect)) best_rect = cand;\n    record_candidate(cand);\n}\n\nvoid consider_rect(int x1, int x2, int y1, int y2) {\n    if (!normalize_rect(x1,x2,y1,y2)) return;\n    Score sc = compute_score(x1,x2,y1,y2);\n    push_candidate(x1,x2,y1,y2,sc);\n}\n\nint sample_half_span() {\n    static const int options[] = {0, 20, 40, 80, 150, 250, 400, 600, 900, 1300, 1800,\n                                  2500, 3400, 4500, 6000, 8000, 10500, 13500, 17000,\n                                  21000, 26000, 32000, 39000, 47000};\n    static const int SZ = sizeof(options)/sizeof(int);\n    int base = options[rng() % SZ];\n    int extra_range = base / 3 + 1;\n    if (base == 0) extra_range = 60;\n    int extra = rng() % extra_range;\n    return base + extra;\n}\n\nint sample_span() {\n    static const pair<int,int> ranges[] = {\n        {1, 400}, {200, 1200}, {800, 3200}, {2000, 7000}, {5000, 15000},\n        {12000, 30000}, {25000, 50000}, {40000, 80000}, {70000, 100000}\n    };\n    static const int SZ = sizeof(ranges)/sizeof(ranges[0]);\n    auto [lo, hi] = ranges[rng() % SZ];\n    hi = min(hi, MAX_COORD);\n    lo = min(lo, hi);\n    int width = lo;\n    if (hi > lo) width += rng() % (hi - lo + 1);\n    return max(1, width);\n}\n\nvector<int> build_lines(const vector<int>& coords, int segments) {\n    vector<int> lines;\n    int extras = segments / 3 + 2;\n    lines.reserve(segments + extras + 4);\n    lines.push_back(0);\n    if (!coords.empty()) {\n        int size = coords.size();\n        for (int i = 1; i < segments; ++i) {\n            long long idx = 1LL * size * i / segments;\n            idx = min<long long>(idx, size - 1);\n            lines.push_back(coords[idx]);\n        }\n        uniform_int_distribution<int> dist(0, size - 1);\n        int extra = min(extras, size);\n        for (int i = 0; i < extra; ++i) lines.push_back(coords[dist(rng)]);\n    }\n    lines.push_back(MAX_COORD + 1);\n    sort(lines.begin(), lines.end());\n    lines.erase(unique(lines.begin(), lines.end()), lines.end());\n    if (lines.front() != 0) lines.insert(lines.begin(), 0);\n    if (lines.back() != MAX_COORD + 1) lines.push_back(MAX_COORD + 1);\n    return lines;\n}\n\nvoid grid_search(int segments, const vector<int>& sorted_x, const vector<int>& sorted_y) {\n    if (elapsed() > TIME_LIMIT) return;\n    auto lines_x = build_lines(sorted_x, segments);\n    auto lines_y = build_lines(sorted_y, segments);\n    int W = (int)lines_x.size() - 1;\n    int H = (int)lines_y.size() - 1;\n    if (W <= 0 || H <= 0) return;\n\n    vector<int> grid(W * H, 0);\n    for (size_t i = 0; i < xs.size(); ++i) {\n        int cx = upper_bound(lines_x.begin(), lines_x.end(), xs[i]) - lines_x.begin() - 1;\n        int cy = upper_bound(lines_y.begin(), lines_y.end(), ys[i]) - lines_y.begin() - 1;\n        cx = clamp(cx, 0, W - 1);\n        cy = clamp(cy, 0, H - 1);\n        grid[cy * W + cx] += types[i];\n    }\n\n    vector<int> arr(W, 0);\n    int best_sum = NEG_INF;\n    int best_top = 0, best_bottom = 0, best_left = 0, best_right = 0;\n    for (int top = 0; top < H; ++top) {\n        fill(arr.begin(), arr.end(), 0);\n        for (int bottom = top; bottom < H; ++bottom) {\n            int row_offset = bottom * W;\n            for (int col = 0; col < W; ++col) arr[col] += grid[row_offset + col];\n            int cur = 0, start = 0;\n            for (int col = 0; col < W; ++col) {\n                if (cur <= 0) {\n                    cur = arr[col];\n                    start = col;\n                } else {\n                    cur += arr[col];\n                }\n                if (cur > best_sum) {\n                    best_sum = cur;\n                    best_top = top;\n                    best_bottom = bottom;\n                    best_left = start;\n                    best_right = col;\n                }\n            }\n        }\n    }\n\n    auto convert = [&](int left, int right, int top, int bottom) {\n        int x1 = lines_x[left];\n        int x2 = lines_x[right + 1] - 1;\n        int y1 = lines_y[top];\n        int y2 = lines_y[bottom + 1] - 1;\n        consider_rect(x1, x2, y1, y2);\n    };\n\n    convert(best_left, best_right, best_top, best_bottom);\n\n    array<pair<int,int>,3> top_cells;\n    int filled = 0;\n    for (int idx = 0; idx < H * W; ++idx) {\n        int val = grid[idx];\n        if (filled < 3) {\n            top_cells[filled++] = {val, idx};\n        } else {\n            int pos = 0;\n            for (int j = 1; j < 3; ++j) if (top_cells[j].first < top_cells[pos].first) pos = j;\n            if (val > top_cells[pos].first) top_cells[pos] = {val, idx};\n        }\n    }\n    for (int i = 0; i < filled; ++i) {\n        int idx = top_cells[i].second;\n        int cy = idx / W;\n        int cx = idx % W;\n        for (int rad = 0; rad <= 1; ++rad) {\n            int left = max(0, cx - rad);\n            int right = min(W - 1, cx + rad);\n            int top = max(0, cy - rad);\n            int bottom = min(H - 1, cy + rad);\n            convert(left, right, top, bottom);\n        }\n    }\n}\n\nvoid random_centered(int iterations) {\n    if (m_coords.empty()) return;\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        const auto &p = m_coords[dist(rng)];\n        int dx = sample_half_span();\n        int dy = sample_half_span();\n        consider_rect(p.first - dx, p.first + dx, p.second - dy, p.second + dy);\n    }\n}\n\nvoid random_global(int iterations) {\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int width = sample_span();\n        int height = sample_span();\n        int x1_max = max(0, MAX_COORD - width);\n        int y1_max = max(0, MAX_COORD - height);\n        int x1 = x1_max ? (int)(rng() % (x1_max + 1)) : 0;\n        int y1 = y1_max ? (int)(rng() % (y1_max + 1)) : 0;\n        consider_rect(x1, x1 + width, y1, y1 + height);\n    }\n}\n\nvoid random_pair_rects(int iterations) {\n    if (m_coords.empty()) return;\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        const auto &a = m_coords[dist(rng)];\n        const auto &b = m_coords[dist(rng)];\n        int x1 = min(a.first, b.first) - sample_half_span();\n        int x2 = max(a.first, b.first) + sample_half_span();\n        const auto &c = m_coords[dist(rng)];\n        const auto &d = m_coords[dist(rng)];\n        int y1 = min(c.second, d.second) - sample_half_span();\n        int y2 = max(c.second, d.second) + sample_half_span();\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_cluster_rects(int iterations) {\n    if (m_coords.empty()) return;\n    vector<int> cluster_sizes = {2,3,4,5,7,9,12,16};\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int k = cluster_sizes[rng() % cluster_sizes.size()];\n        k = min(k, (int)m_coords.size());\n        if (k == 0) break;\n        int minx = INT_MAX, miny = INT_MAX;\n        int maxx = INT_MIN, maxy = INT_MIN;\n        for (int j = 0; j < k; ++j) {\n            const auto &p = m_coords[rng() % m_coords.size()];\n            minx = min(minx, p.first);\n            maxx = max(maxx, p.first);\n            miny = min(miny, p.second);\n            maxy = max(maxy, p.second);\n        }\n        int marginx = sample_half_span();\n        int marginy = sample_half_span();\n        consider_rect(minx - marginx, maxx + marginx, miny - marginy, maxy + marginy);\n    }\n}\n\nvoid quantile_rects(int iterations, const vector<int>& sorted_x, const vector<int>& sorted_y) {\n    if (sorted_x.empty() || sorted_y.empty()) return;\n    uniform_int_distribution<int> dist_x(0, (int)sorted_x.size() - 1);\n    uniform_int_distribution<int> dist_y(0, (int)sorted_y.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int li = dist_x(rng);\n        int ri = dist_x(rng);\n        if (li > ri) swap(li, ri);\n        int marginx = sample_half_span() / 2 + rng() % 200;\n        int x1 = sorted_x[li] - marginx;\n        int x2 = sorted_x[ri] + marginx;\n        int lj = dist_y(rng);\n        int rj = dist_y(rng);\n        if (lj > rj) swap(lj, rj);\n        int marginy = sample_half_span() / 2 + rng() % 200;\n        int y1 = sorted_y[lj] - marginy;\n        int y2 = sorted_y[rj] + marginy;\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid slender_rects(int iterations) {\n    if (m_coords.empty()) return;\n    static const int widths[] = {150, 300, 600, 1000, 1600, 2500, 4000, 6000, 9000};\n    static const int SZ = sizeof(widths)/sizeof(int);\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        bool vertical = (rng() & 1);\n        const auto &center = m_coords[dist(rng)];\n        int span = widths[rng() % SZ];\n        int half = span / 2;\n        if (vertical) {\n            int x1 = center.first - half;\n            int x2 = center.first + half;\n            int height = sample_span();\n            int y_mid = rng() % (MAX_COORD + 1);\n            int y1 = y_mid - height / 2;\n            int y2 = y1 + height;\n            consider_rect(x1, x2, y1, y2);\n        } else {\n            int y1 = center.second - half;\n            int y2 = center.second + half;\n            int width = sample_span();\n            int x_mid = rng() % (MAX_COORD + 1);\n            int x1 = x_mid - width / 2;\n            int x2 = x1 + width;\n            consider_rect(x1, x2, y1, y2);\n        }\n    }\n}\n\nstatic const int BIG_PERTURB[] = {5, 15, 30, 60, 120, 250, 400, 700, 1100, 1700,\n                                  2500, 3600, 5000, 7500, 10000, 13500, 17000};\nstatic const int SMALL_PERTURB[] = {2,4,8,16,32,64,128,256,512,1024,2048,3072,4096};\nconst int BIG_PSZ = sizeof(BIG_PERTURB)/sizeof(int);\nconst int SMALL_PSZ = sizeof(SMALL_PERTURB)/sizeof(int);\n\nvoid random_perturb_rect(const RectAns &base, int iterations, const int *options, int opt_sz) {\n    if (base.sc.diff == NEG_INF) return;\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int delta = options[rng() % opt_sz];\n        int x1 = base.x1 - (int)(rng() % (delta + 1));\n        int x2 = base.x2 + (int)(rng() % (delta + 1));\n        int y1 = base.y1 - (int)(rng() % (delta + 1));\n        int y2 = base.y2 + (int)(rng() % (delta + 1));\n        int shiftx = delta ? (int)(rng() % (2 * delta + 1)) - delta : 0;\n        int shifty = delta ? (int)(rng() % (2 * delta + 1)) - delta : 0;\n        x1 += shiftx; x2 += shiftx;\n        y1 += shifty; y2 += shifty;\n        if (rng() & 1) x1 += rng() % (delta + 1);\n        if (rng() & 1) x2 -= rng() % (delta + 1);\n        if (rng() & 1) y1 += rng() % (delta + 1);\n        if (rng() & 1) y2 -= rng() % (delta + 1);\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_perturb_best(int iterations) {\n    random_perturb_rect(best_rect, iterations, BIG_PERTURB, BIG_PSZ);\n}\n\nvoid random_around_top_rects(int iterations_each) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min<int>(seeds.size(), 6);\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        random_perturb_rect(seeds[i], iterations_each, SMALL_PERTURB, SMALL_PSZ);\n    }\n}\n\nstatic const int LOCAL_STEPS[] = {1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946};\nconst int LOCAL_SZ = sizeof(LOCAL_STEPS)/sizeof(int);\n\nvoid local_search_from(const RectAns &seed, int iterations) {\n    if (seed.sc.diff == NEG_INF) return;\n    RectAns current = seed;\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int step = LOCAL_STEPS[rng() % LOCAL_SZ];\n        int op = rng() % 12;\n        int x1 = current.x1;\n        int x2 = current.x2;\n        int y1 = current.y1;\n        int y2 = current.y2;\n        switch (op) {\n            case 0: x1 -= step; break;\n            case 1: x1 += step; break;\n            case 2: x2 += step; break;\n            case 3: x2 -= step; break;\n            case 4: y1 -= step; break;\n            case 5: y1 += step; break;\n            case 6: y2 += step; break;\n            case 7: y2 -= step; break;\n            case 8: { int shift = (int)(rng() % (2 * step + 1)) - step; x1 += shift; x2 += shift; break; }\n            case 9: { int shift = (int)(rng() % (2 * step + 1)) - step; y1 += shift; y2 += shift; break; }\n            case 10: x1 -= step; x2 += step; break;\n            case 11: y1 -= step; y2 += step; break;\n        }\n        if (!normalize_rect(x1,x2,y1,y2)) continue;\n        Score sc = compute_score(x1,x2,y1,y2);\n        push_candidate(x1,x2,y1,y2,sc);\n        RectAns cand{x1,x2,y1,y2,sc};\n        if (better_rect(cand, current)) current = cand;\n        if ((it & 63) == 63 && better_rect(best_rect, current)) current = best_rect;\n    }\n}\n\nvoid run_local_search_pool(int iterations_per_seed) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min<int>(seeds.size(), 4);\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        local_search_from(seeds[i], iterations_per_seed);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    start_time = chrono::steady_clock::now();\n\n    cin >> N;\n    xs.reserve(2 * N);\n    ys.reserve(2 * N);\n    types.reserve(2 * N);\n    m_coords.reserve(N);\n\n    for (int i = 0; i < N; ++i) {\n        int x,y; cin >> x >> y;\n        xs.push_back(x); ys.push_back(y); types.push_back(1);\n        m_coords.emplace_back(x,y);\n    }\n    for (int i = 0; i < N; ++i) {\n        int x,y; cin >> x >> y;\n        xs.push_back(x); ys.push_back(y); types.push_back(-1);\n    }\n\n    vector<int> sorted_x = xs;\n    vector<int> sorted_y = ys;\n    sort(sorted_x.begin(), sorted_x.end());\n    sort(sorted_y.begin(), sorted_y.end());\n\n    bit2d.build(xs, ys, types);\n    best_rect.sc.diff = NEG_INF;\n    top_rects.clear();\n\n    consider_rect(0, MAX_COORD, 0, MAX_COORD);\n    int half = MAX_COORD / 2;\n    consider_rect(0, half, 0, half);\n    consider_rect(half, MAX_COORD, 0, half);\n    consider_rect(0, half, half, MAX_COORD);\n    consider_rect(half, MAX_COORD, half, MAX_COORD);\n    consider_rect(MAX_COORD/4, 3*MAX_COORD/4, MAX_COORD/4, 3*MAX_COORD/4);\n\n    vector<int> segments = {12, 18, 26, 35, 48, 64, 85, 110, 140};\n    for (int seg : segments) {\n        if (elapsed() > TIME_LIMIT) break;\n        grid_search(seg, sorted_x, sorted_y);\n    }\n\n    random_centered(2500);\n    random_pair_rects(2200);\n    random_cluster_rects(1500);\n    random_global(2000);\n    quantile_rects(1800, sorted_x, sorted_y);\n    slender_rects(1200);\n    random_perturb_best(2500);\n    random_around_top_rects(400);\n    run_local_search_pool(400);\n    random_around_top_rects(300);\n\n    if (best_rect.sc.diff == NEG_INF) {\n        consider_rect(0, MAX_COORD, 0, MAX_COORD);\n    }\n\n    cout << 4 << '\\n';\n    cout << best_rect.x1 << ' ' << best_rect.y1 << '\\n';\n    cout << best_rect.x2 << ' ' << best_rect.y1 << '\\n';\n    cout << best_rect.x2 << ' ' << best_rect.y2 << '\\n';\n    cout << best_rect.x1 << ' ' << best_rect.y2 << '\\n';\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Profile {\n    vector<long long> widths;\n    vector<long long> heights; // monotone non-increasing as widths grow\n};\n\nstruct Solution {\n    vector<int> orientation;        // 0/1 per rectangle\n    vector<int> column_id;          // column index per rectangle\n    vector<long long> column_widths;\n    vector<long long> column_heights;\n    vector<int> anchor;             // reference rectangle for each column\n    vector<int> idx_max_width;      // rectangle index attaining column width\n    vector<pair<int,int>> ranges;   // [l,r) per column (for debugging)\n    long long total_width = 0;\n    long long total_height = 0;\n    long long score = (long long)4e18;\n    long long H_used = 0;\n};\n\nconst long long INFLL = (long long)4e18;\n\nint N, T;\nlong long sigma_val;\nvector<long long> w_obs, h_obs;\nvector<array<long long,2>> widthOpt, heightOpt;\nvector<vector<Profile>> profiles;\n\nlong long get_min_width(const Profile &prof, long long Hmax) {\n    for (size_t i = 0; i < prof.widths.size(); ++i) {\n        if (prof.heights[i] <= Hmax) return prof.widths[i];\n    }\n    return INFLL;\n}\n\nint choose_orientation(int idx, long long width_limit) {\n    int best = -1;\n    long long best_h = INFLL;\n    for (int o = 0; o < 2; ++o) {\n        if (widthOpt[idx][o] <= width_limit) {\n            long long h = heightOpt[idx][o];\n            if (best == -1 || h < best_h ||\n                (h == best_h && widthOpt[idx][o] < widthOpt[idx][best])) {\n                best = o;\n                best_h = h;\n            }\n        }\n    }\n    if (best == -1) {\n        // Should never happen, fall back to minimal height orientation\n        best = (heightOpt[idx][1] < heightOpt[idx][0]) ? 1 : 0;\n    }\n    return best;\n}\n\nbool build_solution(long long Hmax, Solution &sol) {\n    vector<long long> dp(N + 1, INFLL);\n    vector<int> prv(N + 1, -1);\n    vector<long long> width_choice(N + 1, -1);\n    dp[0] = 0;\n    for (int i = 1; i <= N; ++i) {\n        for (int j = 0; j < i; ++j) {\n            const Profile &prof = profiles[j][i];\n            long long width = get_min_width(prof, Hmax);\n            if (width >= INFLL/2) continue;\n            long long cand = dp[j] + width;\n            if (cand < dp[i]) {\n                dp[i] = cand;\n                prv[i] = j;\n                width_choice[i] = width;\n            }\n        }\n    }\n    if (dp[N] >= INFLL/2) return false;\n\n    vector<int> cuts;\n    int pos = N;\n    while (pos > 0) {\n        cuts.push_back(pos);\n        pos = prv[pos];\n        if (pos < 0) return false;\n    }\n    cuts.push_back(0);\n    reverse(cuts.begin(), cuts.end());\n    int cols = (int)cuts.size() - 1;\n\n    vector<int> orientation(N);\n    vector<int> column_id(N);\n    vector<long long> col_width(cols);\n    vector<long long> col_height(cols);\n    vector<int> idx_max(cols);\n    vector<pair<int,int>> ranges(cols);\n\n    for (int c = 0; c < cols; ++c) {\n        int l = cuts[c];\n        int r = cuts[c+1];\n        ranges[c] = {l, r};\n        long long width_limit = width_choice[r];\n        long long max_w = -1;\n        long long sum_h = 0;\n        int idx = l;\n        for (int k = l; k < r; ++k) {\n            int best_or = choose_orientation(k, width_limit);\n            orientation[k] = best_or;\n            column_id[k] = c;\n            long long w = widthOpt[k][best_or];\n            long long h = heightOpt[k][best_or];\n            sum_h += h;\n            if (w > max_w || (w == max_w && k < idx)) {\n                max_w = w;\n                idx = k;\n            }\n        }\n        if (max_w < width_limit) max_w = width_limit;\n        col_width[c] = max_w;\n        col_height[c] = sum_h;\n        idx_max[c] = idx;\n    }\n\n    vector<int> anchor(cols);\n    anchor[0] = -1;\n    for (int c = 1; c < cols; ++c) anchor[c] = idx_max[c-1];\n\n    long long total_w = 0;\n    long long total_h = 0;\n    for (auto w : col_width) total_w += w;\n    for (auto h : col_height) total_h = max(total_h, h);\n\n    sol.orientation = move(orientation);\n    sol.column_id = move(column_id);\n    sol.column_widths = move(col_width);\n    sol.column_heights = move(col_height);\n    sol.anchor = move(anchor);\n    sol.idx_max_width = move(idx_max);\n    sol.ranges = move(ranges);\n    sol.total_width = total_w;\n    sol.total_height = total_h;\n    sol.score = total_w + total_h;\n    sol.H_used = Hmax;\n    return true;\n}\n\nSolution build_row_solution() {\n    Solution sol;\n    vector<int> orientation(N);\n    vector<int> column_id(N);\n    vector<long long> col_width(N);\n    vector<long long> col_height(N);\n    vector<int> idx_max(N);\n    vector<pair<int,int>> ranges(N);\n    for (int i = 0; i < N; ++i) {\n        int best = 0;\n        if (widthOpt[i][1] < widthOpt[i][0]) best = 1;\n        else if (widthOpt[i][1] == widthOpt[i][0] && heightOpt[i][1] < heightOpt[i][0])\n            best = 1;\n        orientation[i] = best;\n        column_id[i] = i;\n        col_width[i] = widthOpt[i][best];\n        col_height[i] = heightOpt[i][best];\n        idx_max[i] = i;\n        ranges[i] = {i, i+1};\n    }\n    vector<int> anchor(N);\n    anchor[0] = -1;\n    for (int i = 1; i < N; ++i) anchor[i] = i-1;\n\n    long long total_w = accumulate(col_width.begin(), col_width.end(), 0LL);\n    long long total_h = 0;\n    for (auto h : col_height) total_h = max(total_h, h);\n\n    sol.orientation = move(orientation);\n    sol.column_id = move(column_id);\n    sol.column_widths = move(col_width);\n    sol.column_heights = move(col_height);\n    sol.anchor = move(anchor);\n    sol.idx_max_width = move(idx_max);\n    sol.ranges = move(ranges);\n    sol.total_width = total_w;\n    sol.total_height = total_h;\n    sol.score = total_w + total_h;\n    sol.H_used = -1;\n    return sol;\n}\n\nuint64_t hash_solution(const Solution &sol) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < N; ++i) {\n        uint64_t val = (uint64_t)(sol.orientation[i] & 1);\n        uint64_t cid = (uint64_t)(sol.column_id[i] & 0x3FF);\n        val |= (cid << 1);\n        h ^= val;\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T >> sigma_val;\n    w_obs.resize(N);\n    h_obs.resize(N);\n    for (int i = 0; i < N; ++i) cin >> w_obs[i] >> h_obs[i];\n\n    widthOpt.assign(N, {0,0});\n    heightOpt.assign(N, {0,0});\n    vector<long long> minHeight(N), maxHeight(N);\n    long long total_min_height = 0;\n    long long H_lower = 0, H_upper = 0;\n    for (int i = 0; i < N; ++i) {\n        widthOpt[i][0] = w_obs[i];\n        heightOpt[i][0] = h_obs[i];\n        widthOpt[i][1] = h_obs[i];\n        heightOpt[i][1] = w_obs[i];\n        minHeight[i] = min(heightOpt[i][0], heightOpt[i][1]);\n        maxHeight[i] = max(heightOpt[i][0], heightOpt[i][1]);\n        total_min_height += minHeight[i];\n        H_lower = max(H_lower, minHeight[i]);\n        H_upper += maxHeight[i];\n    }\n    if (H_upper < H_lower) H_upper = H_lower;\n\n    profiles.assign(N, vector<Profile>(N+1));\n    for (int l = 0; l < N; ++l) {\n        for (int r = l+1; r <= N; ++r) {\n            Profile prof;\n            vector<long long> widths;\n            widths.reserve(2*(r-l));\n            for (int k = l; k < r; ++k) {\n                widths.push_back(widthOpt[k][0]);\n                widths.push_back(widthOpt[k][1]);\n            }\n            sort(widths.begin(), widths.end());\n            widths.erase(unique(widths.begin(), widths.end()), widths.end());\n            vector<long long> heights(widths.size(), INFLL);\n            for (size_t idx = 0; idx < widths.size(); ++idx) {\n                long long W = widths[idx];\n                long long sumH = 0;\n                bool ok = true;\n                for (int k = l; k < r; ++k) {\n                    long long best = INFLL;\n                    for (int o = 0; o < 2; ++o)\n                        if (widthOpt[k][o] <= W)\n                            best = min(best, heightOpt[k][o]);\n                    if (best >= INFLL/2) {\n                        ok = false;\n                        break;\n                    }\n                    sumH += best;\n                }\n                heights[idx] = ok ? sumH : INFLL;\n            }\n            long long last = INFLL;\n            for (size_t idx = 0; idx < heights.size(); ++idx) {\n                if (heights[idx] < last) last = heights[idx];\n                else heights[idx] = last;\n            }\n            prof.widths = move(widths);\n            prof.heights = move(heights);\n            profiles[l][r] = move(prof);\n        }\n    }\n\n    vector<long long> candidate_values;\n    auto add_candidate = [&](long long val) {\n        val = max(H_lower, min(val, H_upper));\n        candidate_values.push_back(val);\n    };\n    add_candidate(H_lower);\n    add_candidate(H_upper);\n\n    vector<double> fudge = {0.85, 0.95, 1.0, 1.05, 1.1, 1.25, 1.4};\n    int maxCols = min(N, 25);\n    for (int c = 1; c <= maxCols; ++c) {\n        double base = (double)total_min_height / c;\n        for (double f : fudge) {\n            long long cand = llround(base * f);\n            add_candidate(cand);\n        }\n    }\n    double val = (double)H_lower;\n    while (val <= (double)H_upper) {\n        add_candidate((long long)llround(val));\n        val *= 1.08;\n        if (candidate_values.size() > 800) break;\n    }\n    int linearCount = 25;\n    if (H_upper > H_lower) {\n        for (int i = 0; i < linearCount; ++i) {\n            double ratio = (double)i / (linearCount - 1);\n            long long cand = llround(H_lower + (H_upper - H_lower) * ratio);\n            add_candidate(cand);\n        }\n    }\n\n    sort(candidate_values.begin(), candidate_values.end());\n    candidate_values.erase(unique(candidate_values.begin(), candidate_values.end()), candidate_values.end());\n\n    size_t maxCandidates = min<size_t>(120, max<size_t>(30, 3 * (size_t)T));\n    vector<long long> candidates;\n    if (candidate_values.size() <= maxCandidates || maxCandidates <= 1) {\n        candidates = candidate_values;\n    } else {\n        candidates.reserve(maxCandidates);\n        for (size_t i = 0; i < maxCandidates; ++i) {\n            size_t pos = (size_t)llround((long double)i * (candidate_values.size()-1) / (maxCandidates-1));\n            candidates.push_back(candidate_values[pos]);\n        }\n        sort(candidates.begin(), candidates.end());\n        candidates.erase(unique(candidates.begin(), candidates.end()), candidates.end());\n    }\n    if (candidates.empty()) candidates.push_back(H_lower);\n\n    vector<Solution> solutions;\n    for (long long H : candidates) {\n        Solution sol;\n        if (build_solution(H, sol)) {\n            solutions.push_back(sol);\n        }\n    }\n    solutions.push_back(build_row_solution());\n\n    sort(solutions.begin(), solutions.end(), [](const Solution &a, const Solution &b) {\n        if (a.score != b.score) return a.score < b.score;\n        if (a.total_width != b.total_width) return a.total_width < b.total_width;\n        return a.column_widths.size() < b.column_widths.size();\n    });\n\n    vector<Solution> unique_solutions;\n    unordered_set<uint64_t> seen;\n    int maxOutput = min(T, 60);\n    for (const auto &sol : solutions) {\n        uint64_t h = hash_solution(sol);\n        if (seen.insert(h).second) {\n            unique_solutions.push_back(sol);\n            if ((int)unique_solutions.size() >= maxOutput) break;\n        }\n    }\n    if (unique_solutions.empty()) unique_solutions.push_back(build_row_solution());\n\n    vector<const Solution*> plan;\n    plan.reserve(T);\n    int use = min((int)unique_solutions.size(), T);\n    for (int i = 0; i < use; ++i) plan.push_back(&unique_solutions[i]);\n    for (int i = use; i < T; ++i) plan.push_back(&unique_solutions[0]);\n\n    for (int t = 0; t < T; ++t) {\n        const Solution &sol = *plan[t];\n        cout << N << '\\n';\n        for (int i = 0; i < N; ++i) {\n            int p = i;\n            int r = sol.orientation[i];\n            char d = 'U';\n            int col = sol.column_id[i];\n            int b = sol.anchor[col];\n            cout << p << ' ' << r << ' ' << d << ' ' << b << '\\n';\n        }\n        cout.flush();\n        long long Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n    }\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct BuildParams {\n    double rootBeautyWeight;\n    double rootCenterWeight;\n    double rootRandomWeight;\n    int candidateMode;\n    int shallowThreshold;\n    long long depthWeight;\n    long long shallowBonus;\n    long long deepBonus;\n    long long beautyWeight;\n    int candidateRandomRange;\n};\n\nstruct Solution {\n    vector<int> parent;\n    vector<int> depth;\n    long long score;\n    Solution() : score(-(1LL << 60)) {}\n};\n\nlong long compute_score(const vector<int>& depth, const vector<int>& A) {\n    long long sum = 0;\n    for (size_t i = 0; i < depth.size(); ++i) {\n        sum += 1LL * (depth[i] + 1) * A[i];\n    }\n    return sum;\n}\n\ndouble randDouble(mt19937& rng, double low, double high) {\n    uniform_real_distribution<double> dist(low, high);\n    return dist(rng);\n}\n\nint randInt(mt19937& rng, int low, int high) {\n    uniform_int_distribution<int> dist(low, high);\n    return dist(rng);\n}\n\nBuildParams random_params(mt19937& rng, int H) {\n    BuildParams p;\n    p.rootBeautyWeight = randDouble(rng, 0.25, 1.35);\n    p.rootCenterWeight = randDouble(rng, -0.05, 0.12);\n    p.rootRandomWeight = randDouble(rng, 0.0, 4.0);\n    p.candidateMode = rng() % 2;\n\n    if (p.candidateMode == 0) {\n        int lowThr = max(1, H / 4);\n        int highThr = max(lowThr, H - 2);\n        p.shallowThreshold = randInt(rng, lowThr, highThr);\n        p.depthWeight = randInt(rng, 9000, 17000);\n        p.shallowBonus = randInt(rng, 2500, 6000);\n        p.deepBonus = randInt(rng, 100, 700);\n        p.beautyWeight = 0;\n    } else {\n        p.shallowThreshold = 0;\n        p.depthWeight = randInt(rng, 5000, 11000);\n        p.shallowBonus = 0;\n        p.deepBonus = 0;\n        p.beautyWeight = randInt(rng, 300, 450);\n    }\n    p.candidateRandomRange = randInt(rng, 30, 200);\n    return p;\n}\n\nvector<int> select_roots(const vector<vector<int>>& adj,\n                         const vector<int>& A,\n                         const vector<double>& distCenter,\n                         int H,\n                         const BuildParams& params,\n                         mt19937& rng) {\n    const int N = adj.size();\n    const int INF = 1e9;\n    vector<int> minDist(N, INF);\n    vector<double> tieValue(N, 0.0);\n    uniform_real_distribution<double> rand01(0.0, 1.0);\n\n    for (int v = 0; v < N; ++v) {\n        double rnd = (params.rootRandomWeight > 0.0) ? rand01(rng) : 0.0;\n        tieValue[v] = params.rootBeautyWeight * A[v]\n                    + params.rootCenterWeight * distCenter[v]\n                    + params.rootRandomWeight * rnd;\n    }\n\n    vector<int> dist_local(N, INF);\n    vector<int> touched;\n    touched.reserve(N);\n    vector<int> roots;\n\n    auto add_root = [&](int start) {\n        queue<int> q;\n        touched.clear();\n        dist_local[start] = 0;\n        touched.push_back(start);\n        q.push(start);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int d = dist_local[v];\n            if (d < minDist[v]) minDist[v] = d;\n            if (d == H) continue;\n            for (int nb : adj[v]) {\n                if (dist_local[nb] != INF) continue;\n                int nd = d + 1;\n                if (nd > H) continue;\n                dist_local[nb] = nd;\n                touched.push_back(nb);\n                q.push(nb);\n            }\n        }\n        for (int v : touched) dist_local[v] = INF;\n    };\n\n    while (true) {\n        int best = -1;\n        for (int v = 0; v < N; ++v) {\n            if (minDist[v] > H) {\n                if (best == -1 || minDist[v] > minDist[best] ||\n                    (minDist[v] == minDist[best] && tieValue[v] < tieValue[best])) {\n                    best = v;\n                }\n            }\n        }\n        if (best == -1) break;\n        add_root(best);\n        roots.push_back(best);\n    }\n    if (roots.empty()) {\n        int best = min_element(A.begin(), A.end()) - A.begin();\n        add_root(best);\n        roots.push_back(best);\n    }\n    return roots;\n}\n\nSolution build_solution(const vector<vector<int>>& adj,\n                        const vector<int>& A,\n                        const vector<double>& distCenter,\n                        int H,\n                        const BuildParams& params,\n                        mt19937& rng) {\n    const int N = adj.size();\n    Solution sol;\n    sol.parent.assign(N, -1);\n    sol.depth.assign(N, -1);\n\n    vector<int> roots = select_roots(adj, A, distCenter, H, params, rng);\n\n    vector<char> assigned(N, 0);\n    vector<int> bestDepth(N, -1);\n    vector<int> bestParent(N, -1);\n    vector<long long> bestKey(N, numeric_limits<long long>::min());\n\n    struct Candidate {\n        long long key;\n        int depth;\n        int node;\n        bool operator<(const Candidate& other) const {\n            if (key != other.key) return key < other.key;\n            if (depth != other.depth) return depth < other.depth;\n            return node > other.node;\n        }\n    };\n    priority_queue<Candidate> pq;\n\n    auto randContribution = [&](int range) -> long long {\n        if (range <= 0) return 0LL;\n        return static_cast<long long>(rng() % range);\n    };\n\n    int threshold = params.shallowThreshold;\n    threshold = max(0, min(threshold, H));\n\n    auto computeKey = [&](int v, int depth) -> long long {\n        long long key = 1LL * depth * params.depthWeight;\n        if (params.candidateMode == 0) {\n            if (depth <= threshold) key += params.shallowBonus - A[v];\n            else key += params.deepBonus + A[v];\n        } else {\n            key += 1LL * A[v] * params.beautyWeight;\n        }\n        key += randContribution(params.candidateRandomRange);\n        return key;\n    };\n\n    auto pushCandidate = [&](int child, int par) {\n        if (assigned[child]) return;\n        int parentDepth = sol.depth[par];\n        if (parentDepth < 0) return;\n        int newDepth = parentDepth + 1;\n        if (newDepth > H) return;\n        long long key = computeKey(child, newDepth);\n        if (newDepth > bestDepth[child] || (newDepth == bestDepth[child] && key > bestKey[child])) {\n            bestDepth[child] = newDepth;\n            bestParent[child] = par;\n            bestKey[child] = key;\n            pq.push({key, newDepth, child});\n        }\n    };\n\n    int assignedCount = 0;\n    for (int r : roots) {\n        if (!assigned[r]) {\n            assigned[r] = 1;\n            sol.depth[r] = 0;\n            sol.parent[r] = -1;\n            assignedCount++;\n        }\n    }\n    if (assignedCount == 0) {\n        int best = min_element(A.begin(), A.end()) - A.begin();\n        assigned[best] = 1;\n        sol.depth[best] = 0;\n        sol.parent[best] = -1;\n        assignedCount = 1;\n        roots.push_back(best);\n    }\n    for (int r : roots) {\n        for (int nb : adj[r]) if (!assigned[nb]) pushCandidate(nb, r);\n    }\n\n    while (assignedCount < N) {\n        if (pq.empty()) {\n            int choice = -1;\n            int bestBeauty = INT_MAX;\n            for (int v = 0; v < N; ++v) {\n                if (!assigned[v] && A[v] < bestBeauty) {\n                    bestBeauty = A[v];\n                    choice = v;\n                }\n            }\n            if (choice == -1) break;\n            assigned[choice] = 1;\n            sol.depth[choice] = 0;\n            sol.parent[choice] = -1;\n            assignedCount++;\n            for (int nb : adj[choice]) if (!assigned[nb]) pushCandidate(nb, choice);\n            continue;\n        }\n        Candidate cur = pq.top(); pq.pop();\n        int v = cur.node;\n        if (assigned[v]) continue;\n        if (cur.depth != bestDepth[v]) continue;\n        if (cur.key != bestKey[v]) continue;\n        int par = bestParent[v];\n        if (par == -1) {\n            assigned[v] = 1;\n            sol.depth[v] = 0;\n            sol.parent[v] = -1;\n        } else {\n            assigned[v] = 1;\n            sol.depth[v] = cur.depth;\n            sol.parent[v] = par;\n        }\n        assignedCount++;\n        for (int nb : adj[v]) if (!assigned[nb]) pushCandidate(nb, v);\n    }\n\n    for (int v = 0; v < N; ++v) {\n        if (sol.depth[v] < 0) {\n            sol.depth[v] = 0;\n            sol.parent[v] = -1;\n        }\n    }\n    sol.score = compute_score(sol.depth, A);\n    return sol;\n}\n\nvoid improve_leaves(const vector<vector<int>>& adj,\n                    const vector<int>& A,\n                    int H,\n                    const vector<int>& beautyOrder,\n                    Solution& sol,\n                    int maxIterations = 8) {\n    const int N = adj.size();\n    vector<int> childCnt(N, 0);\n    for (int v = 0; v < N; ++v) {\n        int p = sol.parent[v];\n        if (p >= 0) childCnt[p]++;\n    }\n\n    for (int iter = 0; iter < maxIterations; ++iter) {\n        bool changed = false;\n        for (int v : beautyOrder) {\n            if (childCnt[v] != 0) continue;\n            int curDepth = sol.depth[v];\n            int bestParent = -1;\n            int bestDepth = curDepth;\n            for (int nb : adj[v]) {\n                int parentDepth = sol.depth[nb];\n                if (parentDepth < 0) continue;\n                int newDepth = parentDepth + 1;\n                if (newDepth > H) continue;\n                if (newDepth > bestDepth) {\n                    bestDepth = newDepth;\n                    bestParent = nb;\n                } else if (newDepth == bestDepth && bestParent >= 0 && A[nb] > A[bestParent]) {\n                    bestParent = nb;\n                }\n            }\n            if (bestParent >= 0 && bestDepth > curDepth) {\n                int oldParent = sol.parent[v];\n                if (oldParent >= 0) childCnt[oldParent]--;\n                sol.parent[v] = bestParent;\n                sol.depth[v] = bestDepth;\n                childCnt[bestParent]++;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n    sol.score = compute_score(sol.depth, A);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    cin >> N >> M >> H;\n    vector<int> A(N);\n    for (int i = 0; i < N; ++i) cin >> A[i];\n\n    vector<vector<int>> adj(N);\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; ++i) cin >> xs[i] >> ys[i];\n\n    double cx = 0.0, cy = 0.0;\n    for (int i = 0; i < N; ++i) {\n        cx += xs[i];\n        cy += ys[i];\n    }\n    cx /= N;\n    cy /= N;\n\n    vector<double> distCenter(N, 0.0);\n    for (int i = 0; i < N; ++i) {\n        double dx = xs[i] - cx;\n        double dy = ys[i] - cy;\n        distCenter[i] = sqrt(dx * dx + dy * dy);\n    }\n\n    vector<int> beautyOrder(N);\n    iota(beautyOrder.begin(), beautyOrder.end(), 0);\n    sort(beautyOrder.begin(), beautyOrder.end(), [&](int lhs, int rhs) {\n        if (A[lhs] != A[rhs]) return A[lhs] > A[rhs];\n        return lhs < rhs;\n    });\n\n    vector<BuildParams> baseParams = {\n        {1.00,  0.02, 0.80, 0, 4, 15000, 4500, 350,   0,  80},\n        {0.80,  0.08, 2.50, 0, 5, 12000, 4200, 600,   0, 110},\n        {1.20, -0.02, 0.40, 0, 3, 17000, 5200, 250,   0,  70},\n        {0.60,  0.10, 3.00, 1, 0,  7000,    0,   0, 360, 120},\n        {0.45, -0.03, 4.40, 1, 0,  6200,    0,   0, 420, 150},\n        {0.95,  0.05, 1.50, 0, 2, 14000, 3600, 500,   0,  60}\n    };\n\n    mt19937 rng(123456789);\n    auto start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.80;\n\n    Solution best;\n    bool hasBest = false;\n\n    auto runAttempt = [&](const BuildParams& params) {\n        Solution sol = build_solution(adj, A, distCenter, H, params, rng);\n        improve_leaves(adj, A, H, beautyOrder, sol);\n        if (!hasBest || sol.score > best.score) {\n            best = sol;\n            hasBest = true;\n        }\n    };\n\n    for (const auto& params : baseParams) {\n        runAttempt(params);\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        if (elapsed > TIME_LIMIT) break;\n    }\n\n    while (chrono::duration<double>(chrono::steady_clock::now() - start).count() < TIME_LIMIT) {\n        BuildParams params = random_params(rng, H);\n        runAttempt(params);\n    }\n\n    if (!hasBest) {\n        BuildParams fallback = baseParams.front();\n        Solution sol = build_solution(adj, A, distCenter, H, fallback, rng);\n        improve_leaves(adj, A, H, beautyOrder, sol);\n        best = sol;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << best.parent[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Candidate {\n    char dir;\n    int idx;\n    int shifts;\n    int removal;\n};\n\nstruct CandidateData {\n    char dir;\n    int idx;\n    int shifts;\n    int removal;\n    double value;\n    int cost;\n    double ratio;\n};\n\nstruct PlanResult {\n    vector<Candidate> seq;\n    int cost = 0;\n    bool success = false;\n};\n\nint N;\nint LIMIT_OPS;\nvector<int> rowFirstO, rowLastO, colFirstO, colLastO;\nvector<vector<double>> cellWeight;\nconst double EPS = 1e-9;\n\nint countOni(const vector<string>& board) {\n    int cnt = 0;\n    for (const auto& row : board) {\n        for (char c : row) if (c == 'x') ++cnt;\n    }\n    return cnt;\n}\n\nchar oppositeDir(char dir) {\n    if (dir == 'U') return 'D';\n    if (dir == 'D') return 'U';\n    if (dir == 'L') return 'R';\n    return 'L';\n}\n\nint removeCells(vector<string>& board, const Candidate& cand) {\n    int removed = 0;\n    int n = board.size();\n    if (cand.dir == 'U') {\n        int limit = min(cand.shifts, n);\n        for (int r = 0; r < limit; ++r) {\n            char& cell = board[r][cand.idx];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'D') {\n        int limit = min(cand.shifts, n);\n        int start = n - limit;\n        for (int r = start; r < n; ++r) {\n            char& cell = board[r][cand.idx];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'L') {\n        int limit = min(cand.shifts, n);\n        for (int c = 0; c < limit; ++c) {\n            char& cell = board[cand.idx][c];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'R') {\n        int limit = min(cand.shifts, n);\n        int start = n - limit;\n        for (int c = start; c < n; ++c) {\n            char& cell = board[cand.idx][c];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    }\n    return removed;\n}\n\nvoid precomputeEdgeInfo(const vector<string>& board) {\n    rowFirstO.assign(N, N);\n    rowLastO.assign(N, -1);\n    colFirstO.assign(N, N);\n    colLastO.assign(N, -1);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (board[i][j] == 'o') {\n                rowFirstO[i] = min(rowFirstO[i], j);\n                rowLastO[i] = max(rowLastO[i], j);\n                colFirstO[j] = min(colFirstO[j], i);\n                colLastO[j] = max(colLastO[j], i);\n            }\n        }\n    }\n}\n\nvector<vector<double>> buildCellWeights(const vector<string>& initial) {\n    vector<vector<double>> weight(N, vector<double>(N, 0.0));\n    const double BASE = 1.0;\n    const double DEG_COEF = 0.65;\n    const double DIST_COEF = 0.03;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (initial[i][j] != 'x') continue;\n            int deg = 0;\n            int minShift = INT_MAX;\n            if (colFirstO[j] >= i) {\n                ++deg;\n                minShift = min(minShift, i + 1);\n            }\n            if (colLastO[j] <= i) {\n                ++deg;\n                minShift = min(minShift, N - i);\n            }\n            if (rowFirstO[i] >= j) {\n                ++deg;\n                minShift = min(minShift, j + 1);\n            }\n            if (rowLastO[i] <= j) {\n                ++deg;\n                minShift = min(minShift, N - j);\n            }\n            if (deg == 0) deg = 1;\n            if (minShift == INT_MAX) {\n                int fallback = std::min({i + 1, N - i, j + 1, N - j});\n                minShift = fallback;\n            }\n            double w = BASE + DEG_COEF / deg + DIST_COEF * minShift;\n            weight[i][j] = w;\n        }\n    }\n    return weight;\n}\n\nPlanResult greedyPlanFrom(const vector<string>& startBoard, mt19937& rng,\n                          double tolerance, int costLimit, bool deterministic = false) {\n    PlanResult result;\n    if (costLimit < 0) return result;\n    vector<string> board = startBoard;\n    int remainingOni = countOni(board);\n    if (remainingOni == 0) {\n        result.success = true;\n        return result;\n    }\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    while (remainingOni > 0) {\n        int budget = costLimit - result.cost;\n        if (budget <= 0) return PlanResult();\n\n        vector<CandidateData> candidates;\n        candidates.reserve(4 * N);\n\n        auto addCandidate = [&](char dir, int idx, int shifts, int removal, double value) {\n            if (shifts <= 0 || removal <= 0) return;\n            if (value <= EPS) value = removal;\n            int cost = shifts * 2;\n            if (cost > budget) return;\n            CandidateData cand{dir, idx, shifts, removal, value, cost, cost / value};\n            candidates.push_back(cand);\n        };\n\n        for (int j = 0; j < N; ++j) {\n            int limit = min(colFirstO[j], N);\n            int removal = 0;\n            double value = 0.0;\n            int deepest = -1;\n            for (int r = 0; r < limit; ++r) {\n                if (board[r][j] == 'x') {\n                    ++removal;\n                    value += cellWeight[r][j];\n                    deepest = r;\n                }\n            }\n            if (removal > 0) addCandidate('U', j, deepest + 1, removal, value);\n\n            int start = colLastO[j];\n            if (start < N - 1) {\n                int removal2 = 0;\n                double value2 = 0.0;\n                int topmost = N;\n                for (int r = N - 1; r > start; --r) {\n                    if (board[r][j] == 'x') {\n                        ++removal2;\n                        value2 += cellWeight[r][j];\n                        topmost = min(topmost, r);\n                    }\n                }\n                if (removal2 > 0) addCandidate('D', j, N - topmost, removal2, value2);\n            }\n        }\n\n        for (int i = 0; i < N; ++i) {\n            int limit = min(rowFirstO[i], N);\n            int removal = 0;\n            double value = 0.0;\n            int farthest = -1;\n            for (int c = 0; c < limit; ++c) {\n                if (board[i][c] == 'x') {\n                    ++removal;\n                    value += cellWeight[i][c];\n                    farthest = c;\n                }\n            }\n            if (removal > 0) addCandidate('L', i, farthest + 1, removal, value);\n\n            int start = rowLastO[i];\n            if (start < N - 1) {\n                int removal2 = 0;\n                double value2 = 0.0;\n                int leftmost = N;\n                for (int c = N - 1; c > start; --c) {\n                    if (board[i][c] == 'x') {\n                        ++removal2;\n                        value2 += cellWeight[i][c];\n                        leftmost = min(leftmost, c);\n                    }\n                }\n                if (removal2 > 0) addCandidate('R', i, N - leftmost, removal2, value2);\n            }\n        }\n\n        if (candidates.empty()) return PlanResult();\n\n        int chosenIdx = -1;\n        if (deterministic) {\n            chosenIdx = 0;\n            for (int i = 1; i < (int)candidates.size(); ++i) {\n                const auto& cur = candidates[i];\n                const auto& best = candidates[chosenIdx];\n                if (cur.ratio + EPS < best.ratio) {\n                    chosenIdx = i;\n                } else if (fabs(cur.ratio - best.ratio) <= EPS) {\n                    if (cur.cost < best.cost) chosenIdx = i;\n                    else if (cur.cost == best.cost && cur.removal > best.removal) chosenIdx = i;\n                    else if (cur.cost == best.cost && cur.removal == best.removal && cur.value > best.value + EPS) chosenIdx = i;\n                }\n            }\n        } else {\n            double minRatio = candidates.front().ratio;\n            for (const auto& cand : candidates) minRatio = min(minRatio, cand.ratio);\n            double threshold = minRatio * (1.0 + tolerance);\n            vector<int> eligible;\n            eligible.reserve(candidates.size());\n            for (int i = 0; i < (int)candidates.size(); ++i) {\n                if (candidates[i].ratio <= threshold + 1e-9) eligible.push_back(i);\n            }\n            if (eligible.empty()) {\n                int bestIdx = 0;\n                for (int i = 1; i < (int)candidates.size(); ++i)\n                    if (candidates[i].ratio + EPS < candidates[bestIdx].ratio)\n                        bestIdx = i;\n                eligible.push_back(bestIdx);\n            }\n            if (eligible.size() == 1) {\n                chosenIdx = eligible[0];\n            } else {\n                vector<double> weights;\n                weights.reserve(eligible.size());\n                double totalWeight = 0.0;\n                for (int idx : eligible) {\n                    double w = max(candidates[idx].value, 1e-9);\n                    w *= w;\n                    weights.push_back(w);\n                    totalWeight += w;\n                }\n                double pick = dist01(rng) * totalWeight;\n                double acc = 0.0;\n                for (int k = 0; k < (int)eligible.size(); ++k) {\n                    acc += weights[k];\n                    if (pick <= acc + 1e-12) {\n                        chosenIdx = eligible[k];\n                        break;\n                    }\n                }\n                if (chosenIdx == -1) chosenIdx = eligible.back();\n            }\n        }\n\n        const auto& chosen = candidates[chosenIdx];\n        Candidate op{chosen.dir, chosen.idx, chosen.shifts, chosen.removal};\n        int removed = removeCells(board, op);\n        if (removed <= 0) return PlanResult();\n        op.removal = removed;\n        result.seq.push_back(op);\n        result.cost += chosen.cost;\n        remainingOni -= removed;\n    }\n    result.success = true;\n    return result;\n}\n\nPlanResult sequentialPlan(const vector<string>& initial) {\n    vector<string> board = initial;\n    PlanResult res;\n    int total = countOni(board);\n    while (total > 0) {\n        Candidate best{};\n        int bestShift = INT_MAX;\n        bool found = false;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (board[i][j] != 'x') continue;\n                auto update = [&](char dir, int shifts, int idx) {\n                    if (shifts <= 0) return;\n                    if (shifts < bestShift) {\n                        bestShift = shifts;\n                        best = Candidate{dir, idx, shifts, 0};\n                        found = true;\n                    }\n                };\n                if (colFirstO[j] >= i) update('U', i + 1, j);\n                if (colLastO[j] <= i) update('D', N - i, j);\n                if (rowFirstO[i] >= j) update('L', j + 1, i);\n                if (rowLastO[i] <= j) update('R', N - j, i);\n            }\n        }\n        if (!found) break;\n        int removed = removeCells(board, best);\n        if (removed <= 0) break;\n        best.removal = removed;\n        res.seq.push_back(best);\n        res.cost += 2 * best.shifts;\n        total -= removed;\n        if (res.cost > LIMIT_OPS) break;\n    }\n    if (total == 0 && res.cost <= LIMIT_OPS) res.success = true;\n    return res;\n}\n\nbool applyPrefix(const vector<string>& initial, const vector<Candidate>& seq, int keep,\n                 vector<string>& boardOut, int& costOut) {\n    boardOut = initial;\n    costOut = 0;\n    for (int i = 0; i < keep; ++i) {\n        costOut += 2 * seq[i].shifts;\n        if (costOut > LIMIT_OPS) return false;\n        int removed = removeCells(boardOut, seq[i]);\n        if (removed < 0) return false;\n    }\n    return true;\n}\n\nvoid localSearch(const vector<string>& initial, PlanResult& best, mt19937& rng,\n                 int iterations, double maxTol) {\n    if (!best.success) return;\n    if (best.seq.empty()) return;\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n    vector<string> board;\n    int prefixCost = 0;\n\n    for (int iter = 0; iter < iterations; ++iter) {\n        int sz = (int)best.seq.size();\n        if (sz == 0) break;\n        int keep = 0;\n        if (sz > 1) {\n            double r = dist01(rng);\n            if (r < 0.25) keep = 0;\n            else if (r < 0.5) keep = rng() % min(sz, 4);\n            else if (r < 0.8) keep = rng() % (sz / 2 + 1);\n            else keep = rng() % sz;\n            if (keep >= sz) keep = sz - 1;\n        }\n        if (!applyPrefix(initial, best.seq, keep, board, prefixCost)) continue;\n        int remainingBudget = LIMIT_OPS - prefixCost;\n        if (remainingBudget < 0) continue;\n        double tol = pow(dist01(rng), 1.7) * maxTol;\n        PlanResult tail = greedyPlanFrom(board, rng, tol, remainingBudget);\n        if (!tail.success) continue;\n        PlanResult candidate;\n        candidate.seq.reserve(keep + tail.seq.size());\n        candidate.seq.insert(candidate.seq.end(), best.seq.begin(), best.seq.begin() + keep);\n        candidate.seq.insert(candidate.seq.end(), tail.seq.begin(), tail.seq.end());\n        candidate.cost = prefixCost + tail.cost;\n        candidate.success = true;\n        if (!best.success || candidate.cost < best.cost ||\n            (candidate.cost == best.cost && candidate.seq.size() < best.seq.size())) {\n            best = move(candidate);\n        }\n    }\n}\n\nbool simulatePlan(const vector<string>& initial, const PlanResult& plan,\n                  vector<pair<char,int>>& output) {\n    if (!plan.success) return false;\n    if (plan.cost > LIMIT_OPS) return false;\n    vector<string> board = initial;\n    int remaining = countOni(board);\n    output.clear();\n    output.reserve(plan.cost + 5);\n\n    auto doShift = [&](char dir, int idx) -> bool {\n        if ((int)output.size() >= LIMIT_OPS) return false;\n        output.emplace_back(dir, idx);\n        if (dir == 'U') {\n            char removed = board[0][idx];\n            for (int r = 0; r < N - 1; ++r) board[r][idx] = board[r + 1][idx];\n            board[N - 1][idx] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else if (dir == 'D') {\n            char removed = board[N - 1][idx];\n            for (int r = N - 1; r >= 1; --r) board[r][idx] = board[r - 1][idx];\n            board[0][idx] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else if (dir == 'L') {\n            char removed = board[idx][0];\n            for (int c = 0; c < N - 1; ++c) board[idx][c] = board[idx][c + 1];\n            board[idx][N - 1] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else {\n            char removed = board[idx][N - 1];\n            for (int c = N - 1; c >= 1; --c) board[idx][c] = board[idx][c - 1];\n            board[idx][0] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        }\n        return true;\n    };\n\n    for (const auto& cand : plan.seq) {\n        for (int i = 0; i < cand.shifts; ++i)\n            if (!doShift(cand.dir, cand.idx)) { output.clear(); return false; }\n        char opp = oppositeDir(cand.dir);\n        for (int i = 0; i < cand.shifts; ++i)\n            if (!doShift(opp, cand.idx)) { output.clear(); return false; }\n    }\n    if (remaining != 0) { output.clear(); return false; }\n    if ((int)output.size() > LIMIT_OPS) { output.clear(); return false; }\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N)) return 0;\n    vector<string> board(N);\n    for (int i = 0; i < N; ++i) cin >> board[i];\n    LIMIT_OPS = 4 * N * N;\n\n    precomputeEdgeInfo(board);\n    cellWeight = buildCellWeights(board);\n\n    uint64_t seed = 1469598103934665603ULL;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < N; ++i) {\n        for (char c : board[i]) {\n            seed ^= (uint64_t)(unsigned char)c + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n    mt19937 rng(seed);\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    const int MAX_TRIALS = 100;\n    const double MAX_TOL = 0.4;\n    PlanResult best;\n\n    for (int t = 0; t < MAX_TRIALS; ++t) {\n        double tol = (t == 0) ? 0.0 : pow(dist01(rng), 1.5) * MAX_TOL;\n        PlanResult plan = greedyPlanFrom(board, rng, tol, LIMIT_OPS);\n        if (!plan.success) continue;\n        if (!best.success || plan.cost < best.cost ||\n            (plan.cost == best.cost && plan.seq.size() < best.seq.size())) {\n            best = plan;\n        }\n    }\n\n    if (!best.success) {\n        mt19937 det_rng(seed ^ 0x9e3779b97f4a7c15ULL);\n        PlanResult det = greedyPlanFrom(board, det_rng, 0.0, LIMIT_OPS, true);\n        if (det.success) best = det;\n    }\n    if (!best.success) {\n        PlanResult seqPlan = sequentialPlan(board);\n        if (seqPlan.success) best = seqPlan;\n    }\n    if (best.success) {\n        localSearch(board, best, rng, 80, 0.35);\n    }\n\n    vector<pair<char,int>> ops;\n    if (!simulatePlan(board, best, ops)) {\n        mt19937 det_rng(seed ^ 0x123456789abcdefULL);\n        PlanResult det = greedyPlanFrom(board, det_rng, 0.0, LIMIT_OPS, true);\n        if (!det.success || !simulatePlan(board, det, ops)) {\n            PlanResult seqPlan = sequentialPlan(board);\n            simulatePlan(board, seqPlan, ops);\n        }\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 AssignState {\n    int N = 0;\n    int totalItems = 0;\n    vector<int> src;\n    vector<int> weights;\n    vector<int> dest;\n    vector<int> itemPos;\n    vector<vector<int>> binItems;\n    vector<long long> cap;\n    vector<long long> sum;\n    vector<long long> rem;\n    vector<char> locked;\n    long long penalty = 0;\n\n    void setup(int N_, const vector<int>& target) {\n        N = N_;\n        totalItems = 2 * N;\n        src.resize(totalItems);\n        weights.resize(totalItems);\n        dest.assign(totalItems, -1);\n        itemPos.assign(totalItems, -1);\n        binItems.assign(N, {});\n        cap.resize(N);\n        sum.assign(N, 0);\n        rem.assign(N, 0);\n        locked.assign(totalItems, 0);\n        penalty = 0;\n        for (int i = 0; i < N; ++i) {\n            int w = target[i];\n            src[2 * i] = src[2 * i + 1] = i;\n            weights[2 * i] = weights[2 * i + 1] = w;\n            cap[i] = 2LL * w;\n            rem[i] = cap[i];\n        }\n    }\n};\n\ndouble elapsedSec(const chrono::steady_clock::time_point& start) {\n    return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n}\n\nvoid initialAssign(AssignState& st, mt19937& rng) {\n    for (int j = 0; j < st.N; ++j) {\n        st.binItems[j].clear();\n        st.sum[j] = 0;\n        st.rem[j] = st.cap[j];\n    }\n    fill(st.dest.begin(), st.dest.end(), -1);\n    fill(st.itemPos.begin(), st.itemPos.end(), -1);\n    fill(st.locked.begin(), st.locked.end(), 0);\n    vector<int> order(st.totalItems);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (st.weights[a] != st.weights[b]) return st.weights[a] > st.weights[b];\n        return a < b;\n    });\n    priority_queue<pair<long long,int>> pq;\n    for (int j = 0; j < st.N; ++j) pq.push({st.rem[j], j});\n    auto popValid = [&]() {\n        while (true) {\n            auto [val, idx] = pq.top();\n            pq.pop();\n            if (val == st.rem[idx]) return idx;\n        }\n    };\n    for (int item : order) {\n        int bin = popValid();\n        st.dest[item] = bin;\n        st.itemPos[item] = st.binItems[bin].size();\n        st.binItems[bin].push_back(item);\n        st.sum[bin] += st.weights[item];\n        st.rem[bin] = st.cap[bin] - st.sum[bin];\n        pq.push({st.rem[bin], bin});\n    }\n    st.penalty = 0;\n    for (int j = 0; j < st.N; ++j) st.penalty += llabs(st.rem[j]);\n}\n\nlong long penaltyDelta(const AssignState& st, int item, int newBin) {\n    int oldBin = st.dest[item];\n    if (oldBin == newBin) return 0;\n    long long w = st.weights[item];\n    long long before = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n    long long after = llabs(st.rem[oldBin] + w) + llabs(st.rem[newBin] - w);\n    return after - before;\n}\n\nvoid moveItem(AssignState& st, int item, int newBin) {\n    int oldBin = st.dest[item];\n    if (oldBin == newBin) return;\n    long long w = st.weights[item];\n    long long oldPen = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n\n    int pos = st.itemPos[item];\n    int last = st.binItems[oldBin].back();\n    st.binItems[oldBin][pos] = last;\n    st.itemPos[last] = pos;\n    st.binItems[oldBin].pop_back();\n\n    st.sum[oldBin] -= w;\n    st.rem[oldBin] += w;\n\n    st.sum[newBin] += w;\n    st.rem[newBin] -= w;\n\n    st.itemPos[item] = st.binItems[newBin].size();\n    st.binItems[newBin].push_back(item);\n    st.dest[item] = newBin;\n\n    long long newPen = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n    st.penalty += newPen - oldPen;\n}\n\nvoid balance(AssignState& st, bool respectLocked,\n             const chrono::steady_clock::time_point& start, double totalLimit) {\n    while (true) {\n        if (elapsedSec(start) > totalLimit) break;\n        vector<int> posBins;\n        for (int j = 0; j < st.N; ++j) if (st.rem[j] > 0) posBins.push_back(j);\n        if (posBins.empty()) break;\n        sort(posBins.begin(), posBins.end(),\n             [&](int a, int b) { return st.rem[a] > st.rem[b]; });\n        bool moved = false;\n        for (int pos : posBins) {\n            long long remPos = st.rem[pos];\n            long long bestDiff = 0;\n            int bestItem = -1;\n            for (int neg = 0; neg < st.N; ++neg) {\n                if (st.rem[neg] >= 0) continue;\n                long long remNeg = st.rem[neg];\n                for (int item : st.binItems[neg]) {\n                    if (respectLocked && st.locked[item]) continue;\n                    long long w = st.weights[item];\n                    long long newPos = remPos - w;\n                    long long newNeg = remNeg + w;\n                    long long diff = llabs(newPos) + llabs(newNeg)\n                                    - (llabs(remPos) + llabs(remNeg));\n                    if (diff < bestDiff) {\n                        bestDiff = diff;\n                        bestItem = item;\n                    }\n                }\n            }\n            if (bestItem != -1) {\n                moveItem(st, bestItem, pos);\n                moved = true;\n                break;\n            }\n        }\n        if (!moved) break;\n    }\n}\n\nvoid randomImprove(AssignState& st, bool respectLocked, int maxIter,\n                   const chrono::steady_clock::time_point& start, double totalLimit,\n                   mt19937& rng) {\n    for (int iter = 0; iter < maxIter; ++iter) {\n        if (elapsedSec(start) > totalLimit) break;\n        int item = rng() % st.totalItems;\n        if (respectLocked && st.locked[item]) continue;\n        int from = st.dest[item];\n        if (from < 0) continue;\n        int bestBin = -1;\n        long long bestDelta = 0;\n        for (int attempt = 0; attempt < 6; ++attempt) {\n            int cand = rng() % st.N;\n            if (cand == from) continue;\n            long long delta = penaltyDelta(st, item, cand);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestBin = cand;\n            }\n        }\n        if (bestBin == -1) continue;\n        moveItem(st, item, bestBin);\n    }\n}\n\nstruct SCCResult {\n    vector<int> comp;\n    int cnt;\n};\n\nSCCResult computeSCC(const vector<int>& a, const vector<int>& b) {\n    int N = a.size();\n    vector<vector<int>> g(N), gr(N);\n    for (int i = 0; i < N; ++i) {\n        g[i].push_back(a[i]);\n        g[i].push_back(b[i]);\n        gr[a[i]].push_back(i);\n        gr[b[i]].push_back(i);\n    }\n    vector<int> used(N, 0), order;\n    auto dfs1 = [&](auto self, int v) -> void {\n        used[v] = 1;\n        for (int to : g[v]) if (!used[to]) self(self, to);\n        order.push_back(v);\n    };\n    for (int i = 0; i < N; ++i) if (!used[i]) dfs1(dfs1, i);\n    vector<int> comp(N, -1);\n    int compId = 0;\n    auto dfs2 = [&](auto self, int v) -> void {\n        comp[v] = compId;\n        for (int to : gr[v]) if (comp[to] == -1) self(self, to);\n    };\n    for (int i = N - 1; i >= 0; --i) {\n        int v = order[i];\n        if (comp[v] == -1) {\n            dfs2(dfs2, v);\n            ++compId;\n        }\n    }\n    return {comp, compId};\n}\n\nint ensureConnectivity(AssignState& st,\n                       const chrono::steady_clock::time_point& start,\n                       double totalLimit) {\n    vector<int> a(st.N), b(st.N);\n    for (int i = 0; i < st.N; ++i) {\n        a[i] = st.dest[2 * i];\n        b[i] = st.dest[2 * i + 1];\n    }\n    auto scc = computeSCC(a, b);\n    int K = scc.cnt;\n    if (K == 1) return 0;\n    vector<vector<int>> nodesIn(K);\n    for (int i = 0; i < st.N; ++i) nodesIn[scc.comp[i]].push_back(i);\n    vector<int> order(K);\n    iota(order.begin(), order.end(), 0);\n    int lockedAdded = 0;\n    for (int idx = 0; idx < K; ++idx) {\n        if (elapsedSec(start) > totalLimit) break;\n        int fromC = order[idx];\n        int toC = order[(idx + 1) % K];\n        vector<int> existing;\n        for (int node : nodesIn[fromC]) {\n            for (int t = 0; t < 2; ++t) {\n                int item = 2 * node + t;\n                if (st.dest[item] >= 0 && scc.comp[st.dest[item]] == toC) {\n                    existing.push_back(item);\n                }\n            }\n        }\n        if (!existing.empty()) {\n            int bestEdge = existing[0];\n            for (int item : existing) {\n                if (st.weights[item] < st.weights[bestEdge]) bestEdge = item;\n            }\n            st.locked[bestEdge] = 1;\n            ++lockedAdded;\n            continue;\n        }\n        long long bestDelta = (1LL << 60);\n        int bestEdge = -1, bestDest = -1;\n        for (int node : nodesIn[fromC]) {\n            for (int t = 0; t < 2; ++t) {\n                int item = 2 * node + t;\n                if (st.locked[item]) continue;\n                for (int destNode : nodesIn[toC]) {\n                    long long delta = penaltyDelta(st, item, destNode);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestEdge = item;\n                        bestDest = destNode;\n                    }\n                }\n            }\n        }\n        if (bestEdge == -1) continue;\n        moveItem(st, bestEdge, bestDest);\n        st.locked[bestEdge] = 1;\n        ++lockedAdded;\n    }\n    return lockedAdded;\n}\n\nstruct SimResult {\n    vector<int> cnt;\n    long long error;\n};\n\nSimResult simulatePlan(const vector<int>& a, const vector<int>& b,\n                       int L, const vector<int>& target) {\n    int N = a.size();\n    vector<int> cnt(N, 0);\n    int cur = 0;\n    cnt[cur]++;\n    for (int step = 1; step < L; ++step) {\n        int nxt = (cnt[cur] & 1) ? a[cur] : b[cur];\n        cur = nxt;\n        cnt[cur]++;\n    }\n    long long err = 0;\n    for (int i = 0; i < N; ++i) err += llabs(1LL * cnt[i] - target[i]);\n    return {cnt, err};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\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    auto start = chrono::steady_clock::now();\n    const double TOTAL_LIMIT = 1.9;\n\n    AssignState st;\n    st.setup(N, T);\n    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    initialAssign(st, rng);\n    balance(st, false, start, TOTAL_LIMIT);\n    randomImprove(st, false, 250000, start, TOTAL_LIMIT, rng);\n    balance(st, false, start, TOTAL_LIMIT);\n\n    int lockedCount = ensureConnectivity(st, start, TOTAL_LIMIT);\n    if (lockedCount > 0) {\n        balance(st, true, start, TOTAL_LIMIT);\n        randomImprove(st, true, 120000, start, TOTAL_LIMIT, rng);\n        balance(st, true, start, TOTAL_LIMIT);\n    }\n\n    vector<int> a(N), b(N);\n    for (int i = 0; i < N; ++i) {\n        a[i] = st.dest[2 * i];\n        b[i] = st.dest[2 * i + 1];\n        if (a[i] < 0) a[i] = i;\n        if (b[i] < 0) b[i] = i;\n    }\n\n    // Optional: simulate to ensure the plan is evaluated (not printed)\n    auto sim = simulatePlan(a, b, L, T);\n    (void)sim;\n\n    for (int i = 0; i < N; ++i) {\n        cout << a[i] << ' ' << b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nlong long hilbertOrder(long long x, long long y, int pow = 15, int rot = 0) {\n    if (pow == 0) return 0;\n    long long h = 1LL << (pow - 1);\n    long long seg = ((x < h) ? 0 : 1) | ((y < h) ? 0 : 2);\n    seg = (seg + rot) & 3;\n    static const int rotateDelta[4] = {3, 0, 0, 1};\n    long long nx = x & (h - 1);\n    long long ny = y & (h - 1);\n    int nrot = (rot + rotateDelta[seg]) & 3;\n    long long subSize = 1LL << (2 * pow - 2);\n    long long add = hilbertOrder(nx, ny, pow - 1, nrot);\n    if (seg == 1 || seg == 2) {\n        return seg * subSize + add;\n    } else {\n        return seg * subSize + (subSize - add - 1);\n    }\n}\n\nvector<int> build_global_parent(const vector<double>& px, const vector<double>& py) {\n    int n = (int)px.size();\n    const double INF = 1e100;\n    vector<double> best(n, INF);\n    vector<int> parent(n, -1);\n    vector<char> used(n, 0);\n    best[0] = 0.0;\n    for (int it = 0; it < n; ++it) {\n        int v = -1;\n        double bv = INF;\n        for (int i = 0; i < n; ++i) {\n            if (!used[i] && best[i] < bv) {\n                bv = best[i];\n                v = i;\n            }\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        for (int u = 0; u < n; ++u) if (!used[u]) {\n            double dx = px[v] - px[u];\n            double dy = py[v] - py[u];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[u]) {\n                best[u] = dist;\n                parent[u] = v;\n            }\n        }\n    }\n    for (int i = 1; i < n; ++i) if (parent[i] == -1) parent[i] = 0;\n    return parent;\n}\n\ndouble group_cost(const vector<int>& nodes, const vector<double>& px, const vector<double>& py) {\n    int k = (int)nodes.size();\n    if (k <= 1) return 0.0;\n    const double INF = 1e100;\n    static vector<double> best;\n    static vector<char> used;\n    best.assign(k, INF);\n    used.assign(k, 0);\n    best[0] = 0.0;\n    double total = 0.0;\n    for (int iter = 0; iter < k; ++iter) {\n        int v = -1;\n        double bv = INF;\n        for (int i = 0; i < k; ++i) {\n            if (!used[i] && best[i] < bv) {\n                bv = best[i];\n                v = i;\n            }\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        if (iter > 0) total += sqrt(max(0.0, bv));\n        for (int j = 0; j < k; ++j) if (!used[j]) {\n            double dx = px[nodes[v]] - px[nodes[j]];\n            double dy = py[nodes[v]] - py[nodes[j]];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[j]) best[j] = dist;\n        }\n    }\n    return total;\n}\n\nvector<pair<int,int>> build_group_mst(const vector<int>& nodes,\n                                      const vector<double>& px,\n                                      const vector<double>& py) {\n    int k = (int)nodes.size();\n    vector<pair<int,int>> edges;\n    if (k <= 1) return edges;\n    const double INF = 1e100;\n    vector<double> best(k, INF);\n    vector<int> parent(k, -1);\n    vector<char> used(k, 0);\n    best[0] = 0.0;\n    for (int iter = 0; iter < k; ++iter) {\n        int v = -1;\n        double bv = INF;\n        for (int i = 0; i < k; ++i) {\n            if (!used[i] && best[i] < bv) {\n                bv = best[i];\n                v = i;\n            }\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        if (parent[v] != -1) edges.emplace_back(nodes[v], nodes[parent[v]]);\n        for (int j = 0; j < k; ++j) if (!used[j]) {\n            double dx = px[nodes[v]] - px[nodes[j]];\n            double dy = py[nodes[v]] - py[nodes[j]];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[j]) {\n                best[j] = dist;\n                parent[j] = v;\n            }\n        }\n    }\n    if ((int)edges.size() != k - 1) {\n        edges.clear();\n        for (int i = 1; i < k; ++i) {\n            edges.emplace_back(nodes[i - 1], nodes[i]);\n        }\n    }\n    return edges;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    auto global_start = chrono::steady_clock::now();\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) cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n\n    vector<double> px(N), py(N);\n    vector<int> ix(N), iy(N);\n    for (int i = 0; i < N; ++i) {\n        px[i] = 0.5 * (lx[i] + rx[i]);\n        py[i] = 0.5 * (ly[i] + ry[i]);\n        ix[i] = (lx[i] + rx[i]) / 2;\n        iy[i] = (ly[i] + ry[i]) / 2;\n    }\n\n    vector<long long> hilb(N);\n    for (int i = 0; i < N; ++i) {\n        hilb[i] = hilbertOrder(ix[i], iy[i], 15, 0);\n    }\n\n    vector<int> parent = build_global_parent(px, py);\n    vector<vector<int>> adj(N);\n    for (int v = 1; v < N; ++v) {\n        int p = parent[v];\n        if (p < 0 || p >= N || p == v) p = 0;\n        adj[v].push_back(p);\n        adj[p].push_back(v);\n    }\n    for (int v = 0; v < N; ++v) {\n        auto &nbr = adj[v];\n        sort(nbr.begin(), nbr.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n        nbr.erase(unique(nbr.begin(), nbr.end()), nbr.end());\n    }\n    vector<int> order_mst;\n    order_mst.reserve(N);\n    vector<char> vis(N, 0);\n    auto dfs = [&](auto self, int u, int p) -> void {\n        vis[u] = 1;\n        order_mst.push_back(u);\n        for (int v : adj[u]) if (v != p && !vis[v]) self(self, v, u);\n    };\n    for (int i = 0; i < N; ++i) if (!vis[i]) dfs(dfs, i, -1);\n\n    vector<int> base(N);\n    iota(base.begin(), base.end(), 0);\n\n    uint64_t seed = 123456789;\n    seed = seed * 1000003ULL + N;\n    seed = seed * 1000003ULL + M;\n    seed = seed * 1000003ULL + Q;\n    seed = seed * 1000003ULL + L;\n    seed = seed * 1000003ULL + W;\n    for (int i = 0; i < min(N, 20); ++i) {\n        seed = seed * 1000003ULL + (uint64_t)(ix[i] + 10001);\n        seed = seed * 1000003ULL + (uint64_t)(iy[i] + 10001);\n    }\n    mt19937 rng(static_cast<uint32_t>(seed));\n\n    auto hash_order = [&](const vector<int>& ord) -> uint64_t {\n        uint64_t h = 0;\n        for (int v : ord) h = h * 1000003ULL + (uint64_t)(v + 1);\n        return h;\n    };\n\n    auto build_groups = [&](const vector<int>& ord, vector<vector<int>>& groups) -> bool {\n        if ((int)ord.size() != N) return false;\n        size_t pos = 0;\n        for (int i = 0; i < M; ++i) {\n            size_t need = (size_t)G[i];\n            if (pos + need > ord.size()) return false;\n            groups[i].assign(ord.begin() + pos, ord.begin() + pos + need);\n            pos += need;\n        }\n        return pos == ord.size();\n    };\n\n    unordered_set<uint64_t> seen;\n    seen.reserve(128);\n    seen.max_load_factor(0.7f);\n\n    vector<vector<int>> bestGroups;\n    double bestCost = 1e100;\n    bool haveBest = false;\n\n    auto evaluate_candidate = [&](const vector<int>& ord) {\n        uint64_t h = hash_order(ord);\n        if (!seen.insert(h).second) return;\n        vector<vector<int>> groups(M);\n        if (!build_groups(ord, groups)) return;\n        double total = 0.0;\n        for (int i = 0; i < M; ++i) total += group_cost(groups[i], px, py);\n        if (!haveBest || total < bestCost) {\n            haveBest = true;\n            bestCost = total;\n            bestGroups = std::move(groups);\n        }\n    };\n\n    evaluate_candidate(base);\n    {\n        vector<int> tmp = base;\n        reverse(tmp.begin(), tmp.end());\n        evaluate_candidate(tmp);\n    }\n    evaluate_candidate(order_mst);\n    {\n        vector<int> tmp = order_mst;\n        reverse(tmp.begin(), tmp.end());\n        evaluate_candidate(tmp);\n    }\n    {\n        vector<int> tmp = base;\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n        evaluate_candidate(tmp);\n        reverse(tmp.begin(), tmp.end());\n        evaluate_candidate(tmp);\n    }\n    auto add_sorted = [&](auto cmp) {\n        vector<int> ord = base;\n        sort(ord.begin(), ord.end(), cmp);\n        evaluate_candidate(ord);\n    };\n    add_sorted([&](int a, int b) {\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        if (iy[a] != iy[b]) return iy[a] < iy[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        if (iy[a] != iy[b]) return iy[a] < iy[b];\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] + iy[a];\n        long long kb = (long long)ix[b] + iy[b];\n        if (ka != kb) return ka < kb;\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] - iy[a];\n        long long kb = (long long)ix[b] - iy[b];\n        if (ka != kb) return ka < kb;\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    for (int iter = 0; iter < 5; ++iter) {\n        vector<int> ord = base;\n        shuffle(ord.begin(), ord.end(), rng);\n        evaluate_candidate(ord);\n    }\n\n    if (!haveBest) {\n        vector<vector<int>> groups(M);\n        build_groups(base, groups);\n        bestGroups = groups;\n        bestCost = 0.0;\n        for (int i = 0; i < M; ++i) bestCost += group_cost(bestGroups[i], px, py);\n    }\n\n    vector<vector<int>> groups = bestGroups;\n    vector<double> groupCost(M, 0.0);\n    vector<double> sum_x(M, 0.0), sum_y(M, 0.0);\n    double totalCost = 0.0;\n    for (int i = 0; i < M; ++i) {\n        groupCost[i] = group_cost(groups[i], px, py);\n        totalCost += groupCost[i];\n        for (int v : groups[i]) {\n            sum_x[i] += px[v];\n            sum_y[i] += py[v];\n        }\n    }\n\n    const double TOTAL_LIMIT = 1.8;\n    auto deadline = global_start + chrono::duration<double>(TOTAL_LIMIT);\n    if (M > 1) {\n        while (chrono::steady_clock::now() < deadline) {\n            int g = rng() % M;\n            auto choose_partner = [&](int gidx) -> int {\n                if (M <= 1) return gidx;\n                int best = -1;\n                double bestd = 1e300;\n                int samples = min(M - 1, 6);\n                double cgx = sum_x[gidx] / groups[gidx].size();\n                double cgy = sum_y[gidx] / groups[gidx].size();\n                for (int t = 0; t < samples; ++t) {\n                    int cand = rng() % M;\n                    if (cand == gidx) continue;\n                    double csx = sum_x[cand] / groups[cand].size();\n                    double csy = sum_y[cand] / groups[cand].size();\n                    double dx = cgx - csx;\n                    double dy = cgy - csy;\n                    double dist = dx * dx + dy * dy;\n                    if (dist < bestd) {\n                        bestd = dist;\n                        best = cand;\n                    }\n                }\n                if (best == -1) {\n                    best = (gidx + 1 + (rng() % (M - 1))) % M;\n                }\n                return best;\n            };\n            int h = choose_partner(g);\n            if (h == g) continue;\n\n            auto pick_index = [&](int grp) -> int {\n                int sz = groups[grp].size();\n                if (sz <= 1) return 0;\n                if ((rng() & 1) == 0) return rng() % sz;\n                double cx = sum_x[grp] / sz;\n                double cy = sum_y[grp] / sz;\n                int bestIdx = rng() % sz;\n                double bestScore = -1.0;\n                int samples = min(sz, 5);\n                for (int t = 0; t < samples; ++t) {\n                    int idx = rng() % sz;\n                    double dx = px[groups[grp][idx]] - cx;\n                    double dy = py[groups[grp][idx]] - cy;\n                    double sc = dx * dx + dy * dy;\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestIdx = idx;\n                    }\n                }\n                return bestIdx;\n            };\n\n            int idx_g = pick_index(g);\n            int idx_h = pick_index(h);\n            if (groups[g].empty() || groups[h].empty()) continue;\n            int node_g = groups[g][idx_g];\n            int node_h = groups[h][idx_h];\n            if (node_g == node_h) continue;\n\n            swap(groups[g][idx_g], groups[h][idx_h]);\n            double newCostG = group_cost(groups[g], px, py);\n            double newCostH = group_cost(groups[h], px, py);\n            double delta = (newCostG + newCostH) - (groupCost[g] + groupCost[h]);\n            if (delta < -1e-9) {\n                groupCost[g] = newCostG;\n                groupCost[h] = newCostH;\n                totalCost += delta;\n                sum_x[g] += px[node_h] - px[node_g];\n                sum_y[g] += py[node_h] - py[node_g];\n                sum_x[h] += px[node_g] - px[node_h];\n                sum_y[h] += py[node_g] - py[node_h];\n            } else {\n                swap(groups[g][idx_g], groups[h][idx_h]);\n            }\n        }\n    }\n\n    vector<vector<pair<int,int>>> edges(M);\n    for (int i = 0; i < M; ++i) {\n        edges[i] = build_group_mst(groups[i], px, py);\n    }\n\n    cout << \"!\\n\";\n    for (int i = 0; i < M; ++i) {\n        for (size_t j = 0; j < groups[i].size(); ++j) {\n            if (j) cout << ' ';\n            cout << groups[i][j];\n        }\n        cout << '\\n';\n        for (auto &e : edges[i]) {\n            cout << e.first << ' ' << e.second << '\\n';\n        }\n    }\n    cout.flush();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge {\n    int to;\n    char act;  // 'M' or 'S'\n    char dir;  // 'U', 'D', 'L', 'R'\n};\n\nstruct PrevInfo {\n    int prev;\n    char act;\n    char dir;\n    PrevInfo(int p = -1, char a = 0, char d = 0) : prev(p), act(a), dir(d) {}\n};\n\nbool shortest_path(int start, int goal, const vector<vector<Edge>>& graph,\n                   vector<pair<char,char>>& path) {\n    int node_count = graph.size();\n    vector<int> dist(node_count, -1);\n    vector<PrevInfo> prv(node_count);\n    queue<int> q;\n    dist[start] = 0;\n    q.push(start);\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        if (v == goal) break;\n        for (const auto& e : graph[v]) {\n            if (dist[e.to] != -1) continue;\n            dist[e.to] = dist[v] + 1;\n            prv[e.to] = PrevInfo(v, e.act, e.dir);\n            q.push(e.to);\n        }\n    }\n\n    if (dist[goal] == -1) return false;\n\n    path.clear();\n    for (int cur = goal; cur != start; cur = prv[cur].prev) {\n        path.emplace_back(prv[cur].act, prv[cur].dir);\n    }\n    reverse(path.begin(), path.end());\n    return true;\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>> pts(M);\n    for (int k = 0; k < M; ++k) cin >> pts[k].first >> pts[k].second;\n\n    const int node_count = N * N;\n    vector<vector<Edge>> graph(node_count);\n\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n    const char dirc[4] = {'U', 'D', 'L', 'R'};\n\n    auto idx = [N](int r, int c) { return r * N + c; };\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int id = idx(r, c);\n            // Move edges\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + dr[d];\n                int nc = c + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                    graph[id].push_back({idx(nr, nc), 'M', dirc[d]});\n                }\n            }\n            // Slide edges\n            if (r > 0) graph[id].push_back({idx(0, c), 'S', 'U'});\n            if (r < N - 1) graph[id].push_back({idx(N - 1, c), 'S', 'D'});\n            if (c > 0) graph[id].push_back({idx(r, 0), 'S', 'L'});\n            if (c < N - 1) graph[id].push_back({idx(r, N - 1), 'S', 'R'});\n        }\n    }\n\n    vector<pair<char,char>> actions;\n    vector<pair<char,char>> path;\n\n    for (int k = 1; k < M; ++k) {\n        int start_idx = idx(pts[k - 1].first, pts[k - 1].second);\n        int goal_idx = idx(pts[k].first, pts[k].second);\n\n        if (!shortest_path(start_idx, goal_idx, graph, path)) {\n            // Fallback: simple Manhattan moves (should not happen)\n            auto [sr, sc] = pts[k - 1];\n            auto [tr, tc] = pts[k];\n            while (sr < tr) { actions.emplace_back('M', 'D'); ++sr; }\n            while (sr > tr) { actions.emplace_back('M', 'U'); --sr; }\n            while (sc < tc) { actions.emplace_back('M', 'R'); ++sc; }\n            while (sc > tc) { actions.emplace_back('M', 'L'); --sc; }\n        } else {\n            actions.insert(actions.end(), path.begin(), path.end());\n        }\n    }\n\n    for (const auto& [a, d] : actions) {\n        cout << a << ' ' << d << '\\n';\n    }\n    return 0;\n}"},"4":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Rect {\n    int x1, y1, x2, y2;\n};\n\nconst int BOARD_SIZE = 10000;\nconst int GROW_ITER_PER_RECT = 7;\nconst int SHRINK_ITER_PER_RECT = 4;\nconst int EXPAND_STEP_LIMIT = 1000;\nconst int SHRINK_STEP_LIMIT = 1000;\nconst int RANDOM_SHRINK_STEP_LIMIT = 40;\nconst int STAGNATION_LIMIT = 32;\n\nlong long rect_area(const Rect &r) {\n    return 1LL * (r.x2 - r.x1) * (r.y2 - r.y1);\n}\n\narray<int, 4> compute_expand_limits(const vector<Rect> &rects, int idx) {\n    const Rect &ri = rects[idx];\n    array<int, 4> lim = {ri.x1, BOARD_SIZE - ri.x2, ri.y1, BOARD_SIZE - ri.y2};\n    int n = rects.size();\n    for (int j = 0; j < n; ++j) if (j != idx) {\n        const Rect &rj = rects[j];\n        bool overlapY = (ri.y1 < rj.y2) && (ri.y2 > rj.y1);\n        bool overlapX = (ri.x1 < rj.x2) && (ri.x2 > rj.x1);\n        if (overlapY) {\n            if (rj.x2 <= ri.x1) {\n                int gap = max(0, ri.x1 - rj.x2);\n                lim[0] = min(lim[0], gap);\n            }\n            if (rj.x1 >= ri.x2) {\n                int gap = max(0, rj.x1 - ri.x2);\n                lim[1] = min(lim[1], gap);\n            }\n        }\n        if (overlapX) {\n            if (rj.y2 <= ri.y1) {\n                int gap = max(0, ri.y1 - rj.y2);\n                lim[2] = min(lim[2], gap);\n            }\n            if (rj.y1 >= ri.y2) {\n                int gap = max(0, rj.y1 - ri.y2);\n                lim[3] = min(lim[3], gap);\n            }\n        }\n    }\n    for (int d = 0; d < 4; ++d) lim[d] = max(lim[d], 0);\n    return lim;\n}\n\nbool grow_rect(int idx, vector<Rect> &rects, const vector<int> &target, mt19937 &rng) {\n    bool changed = false;\n    int n = rects.size();\n    for (int iter = 0; iter < GROW_ITER_PER_RECT; ++iter) {\n        Rect &rc = rects[idx];\n        long long width = rc.x2 - rc.x1;\n        long long height = rc.y2 - rc.y1;\n        long long area = width * height;\n        long long def = (long long)target[idx] - area;\n        if (def <= 0) break;\n\n        auto lim = compute_expand_limits(rects, idx);\n        long long unitArea[4] = {height, height, width, width};\n        double baseW = width + 0.5;\n        double baseH = height + 0.5;\n\n        double bestScore = -1;\n        vector<int> bestDirs;\n        for (int dir = 0; dir < 4; ++dir) {\n            int max_step = lim[dir];\n            if (max_step <= 0) continue;\n            long long uArea = unitArea[dir];\n            if (uArea <= 0) continue;\n            long long potential = 1LL * max_step * uArea;\n            long long effective = min(def, potential);\n            if (effective <= 0) continue;\n            double weight = 1.0;\n            if (dir <= 1) weight = baseH / baseW;\n            else weight = baseW / baseH;\n            double score = effective * weight;\n            if (score > bestScore + 1e-6) {\n                bestScore = score;\n                bestDirs.clear();\n                bestDirs.push_back(dir);\n            } else if (fabs(score - bestScore) <= 1e-6) {\n                bestDirs.push_back(dir);\n            }\n        }\n        if (bestDirs.empty()) break;\n        int dir = bestDirs[rng() % bestDirs.size()];\n        long long uArea = unitArea[dir];\n        if (uArea <= 0) break;\n        long long needed_units = (def + uArea - 1) / uArea;\n        long long limit = lim[dir];\n        if (limit <= 0) break;\n        limit = min<long long>(limit, EXPAND_STEP_LIMIT);\n        long long w = max(1LL, min(limit, needed_units));\n        if (dir == 0) rc.x1 -= (int)w;\n        else if (dir == 1) rc.x2 += (int)w;\n        else if (dir == 2) rc.y1 -= (int)w;\n        else rc.y2 += (int)w;\n        changed = true;\n    }\n    return changed;\n}\n\nbool shrink_rect(int idx, vector<Rect> &rects, const vector<int> &target,\n                 const vector<int> &xs, const vector<int> &ys, mt19937 &rng) {\n    bool changed = false;\n    for (int iter = 0; iter < SHRINK_ITER_PER_RECT; ++iter) {\n        Rect &rc = rects[idx];\n        long long width = rc.x2 - rc.x1;\n        long long height = rc.y2 - rc.y1;\n        long long area = width * height;\n        long long def = (long long)target[idx] - area;\n        if (def >= 0) break;\n        int avail[4] = {\n            xs[idx] - rc.x1,\n            rc.x2 - (xs[idx] + 1),\n            ys[idx] - rc.y1,\n            rc.y2 - (ys[idx] + 1)\n        };\n        long long unitArea[4] = {height, height, width, width};\n        double bestScore = -1;\n        vector<int> dirs;\n        for (int dir = 0; dir < 4; ++dir) {\n            if (avail[dir] <= 0 || unitArea[dir] <= 0) continue;\n            long long potential = 1LL * avail[dir] * unitArea[dir];\n            if (potential <= 0) continue;\n            long long effective = min(-def, potential);\n            double score = effective;\n            if (score > bestScore + 1e-6) {\n                bestScore = score;\n                dirs.clear();\n                dirs.push_back(dir);\n            } else if (fabs(score - bestScore) <= 1e-6) {\n                dirs.push_back(dir);\n            }\n        }\n        if (dirs.empty()) break;\n        int dir = dirs[rng() % dirs.size()];\n        long long uArea = unitArea[dir];\n        long long need_units = (-def + uArea - 1) / uArea;\n        long long limit = min<long long>(avail[dir], SHRINK_STEP_LIMIT);\n        if (limit <= 0) break;\n        long long w = max(1LL, min(limit, need_units));\n        if (dir == 0) rc.x1 += (int)w;\n        else if (dir == 1) rc.x2 -= (int)w;\n        else if (dir == 2) rc.y1 += (int)w;\n        else rc.y2 -= (int)w;\n        changed = true;\n    }\n    return changed;\n}\n\nbool shrink_phase(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                  const vector<int> &target, mt19937 &rng) {\n    int n = rects.size();\n    vector<pair<long long, int>> overs;\n    overs.reserve(n);\n    for (int i = 0; i < n; ++i) {\n        long long def = (long long)target[i] - rect_area(rects[i]);\n        if (def < 0) overs.emplace_back(-def, i);\n    }\n    sort(overs.begin(), overs.end(), greater<>());\n    bool changed = false;\n    for (auto &p : overs) {\n        if (shrink_rect(p.second, rects, target, xs, ys, rng)) changed = true;\n    }\n    return changed;\n}\n\nbool random_shrink(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                   mt19937 &rng, int operations) {\n    int n = rects.size();\n    if (n == 0) return false;\n    bool changed = false;\n    uniform_int_distribution<int> dist_idx(0, n - 1);\n    for (int t = 0; t < operations; ++t) {\n        int idx = dist_idx(rng);\n        Rect &rc = rects[idx];\n        int avail[4] = {\n            xs[idx] - rc.x1,\n            rc.x2 - (xs[idx] + 1),\n            ys[idx] - rc.y1,\n            rc.y2 - (ys[idx] + 1)\n        };\n        vector<int> dirs;\n        for (int d = 0; d < 4; ++d) if (avail[d] > 0) dirs.push_back(d);\n        if (dirs.empty()) continue;\n        int dir = dirs[rng() % dirs.size()];\n        int cap = min(avail[dir], RANDOM_SHRINK_STEP_LIMIT);\n        if (cap <= 0) continue;\n        int amount = 1 + (cap > 1 ? rng() % cap : 0);\n        if (dir == 0) rc.x1 += amount;\n        else if (dir == 1) rc.x2 -= amount;\n        else if (dir == 2) rc.y1 += amount;\n        else rc.y2 -= amount;\n        changed = true;\n    }\n    return changed;\n}\n\ndouble compute_score(const vector<Rect> &rects, const vector<int> &target) {\n    double sum = 0.0;\n    int n = rects.size();\n    for (int i = 0; i < n; ++i) {\n        long long s = rect_area(rects[i]);\n        long long r = target[i];\n        if (s <= 0 || r <= 0) continue;\n        long long mn = min(s, r);\n        long long mx = max(s, r);\n        if (mx == 0) continue;\n        double ratio = (double)mn / (double)mx;\n        double p = 2.0 * ratio - ratio * ratio;\n        sum += p;\n    }\n    return sum;\n}\n\nbool validate_rects(const vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys) {\n    int n = rects.size();\n    for (int i = 0; i < n; ++i) {\n        const Rect &r = rects[i];\n        if (r.x1 < 0 || r.x1 >= r.x2 || r.x2 > BOARD_SIZE) return false;\n        if (r.y1 < 0 || r.y1 >= r.y2 || r.y2 > BOARD_SIZE) return false;\n        if (!(r.x1 <= xs[i] && xs[i] + 1 <= r.x2)) return false;\n        if (!(r.y1 <= ys[i] && ys[i] + 1 <= r.y2)) return false;\n    }\n    for (int i = 0; i < n; ++i) {\n        for (int j = i + 1; j < n; ++j) {\n            const Rect &a = rects[i];\n            const Rect &b = rects[j];\n            if (max(a.x1, b.x1) < min(a.x2, b.x2) &&\n                max(a.y1, b.y1) < min(a.y2, b.y2)) return false;\n        }\n    }\n    return true;\n}\n\nstruct AttemptResult {\n    vector<Rect> rects;\n    double score;\n};\n\nAttemptResult run_attempt(const vector<Rect> &start_rects, const vector<int> &xs, const vector<int> &ys,\n                          const vector<int> &target, mt19937 &rng,\n                          const chrono::steady_clock::time_point &start_time,\n                          double time_limit) {\n    vector<Rect> rects = start_rects;\n    vector<Rect> best_rect = rects;\n    double best_score = compute_score(rects, target);\n    int n = rects.size();\n    vector<long long> defs(n);\n    int stagnation = 0;\n\n    for (int pass = 0; ; ++pass) {\n        if ((pass & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n            if (elapsed >= time_limit) break;\n        }\n        for (int i = 0; i < n; ++i) defs[i] = (long long)target[i] - rect_area(rects[i]);\n\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n        bool sort_by_def = (pass % 3 != 1);\n        if (sort_by_def) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (defs[a] != defs[b]) return defs[a] > defs[b];\n                return a < b;\n            });\n        }\n\n        bool changedExp = false;\n        for (int idx : order) {\n            if (grow_rect(idx, rects, target, rng)) changedExp = true;\n        }\n\n        bool changedShrink = shrink_phase(rects, xs, ys, target, rng);\n        bool changed = changedExp || changedShrink;\n        bool randomChanged = false;\n\n        if (!changed) {\n            stagnation++;\n            if (stagnation % 3 == 0) {\n                int ops = max(1, n / 4);\n                randomChanged = random_shrink(rects, xs, ys, rng, ops);\n            }\n            if (randomChanged) {\n                changed = true;\n                stagnation = 0;\n            } else if (stagnation > STAGNATION_LIMIT) {\n                rects = best_rect;\n                bool perturbed = random_shrink(rects, xs, ys, rng, max(1, n));\n                stagnation = 0;\n                if (!perturbed) break;\n                else continue;\n            }\n        } else {\n            stagnation = 0;\n        }\n\n        double cur_score = compute_score(rects, target);\n        if (cur_score > best_score + 1e-9) {\n            best_score = cur_score;\n            best_rect = rects;\n        }\n    }\n    return {best_rect, best_score};\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> xs(n), ys(n), rs(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> xs[i] >> ys[i] >> rs[i];\n    }\n\n    vector<Rect> base(n);\n    for (int i = 0; i < n; ++i) {\n        base[i] = {xs[i], ys[i], xs[i] + 1, ys[i] + 1};\n    }\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    const double TIME_LIMIT = 4.85;\n    auto start_time = chrono::steady_clock::now();\n\n    vector<Rect> seed = base;\n    vector<Rect> best = base;\n    double best_score = compute_score(base, rs);\n\n    while (true) {\n        AttemptResult res = run_attempt(seed, xs, ys, rs, rng, start_time, TIME_LIMIT);\n        if (res.score > best_score + 1e-9) {\n            best_score = res.score;\n            best = res.rects;\n        }\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n        if (elapsed >= TIME_LIMIT - 0.2) break;\n        seed = res.rects;\n        if (!random_shrink(seed, xs, ys, rng, max(1, n / 2))) break;\n    }\n\n    if (!validate_rects(best, xs, ys)) best = base;\n\n    for (const auto &r : best) {\n        cout << r.x1 << ' ' << r.y1 << ' ' << r.x2 << ' ' << r.y2 << '\\n';\n    }\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int N2 = N * N;\n    static constexpr int MAX_TILES = 2500;\n    using VisitBitset = bitset<MAX_TILES>;\n\n    struct Neighbor {\n        int to;\n        char dir;\n    };\n    struct Node {\n        VisitBitset visited;\n        int pos = 0;\n        int score = 0;\n        int parent = -1;\n        char move = '?';\n        int depth = 0;\n    };\n    struct Candidate {\n        double eval;\n        int idx;\n    };\n    struct Features {\n        int mobility = 0;\n        int nei1 = 0;\n        int nei2 = 0;\n        int two = 0;\n    };\n\n    vector<int> tileOf;\n    vector<int> value;\n    vector<vector<Neighbor>> adj;\n    int startIdx = 0;\n\n    mt19937_64 rng;\n    chrono::steady_clock::time_point timeStart;\n    string bestPath;\n    int bestScore = 0;\n\n    const double TIME_LIMIT = 1.95;\n    const double LENGTH_WEIGHT = 8.0;\n    const double MOBILITY_WEIGHT = 16.0;\n    const double NEI1_WEIGHT = 1.1;\n    const double NEI2_WEIGHT = 0.4;\n    const double TWO_WEIGHT = 0.6;\n    const double RANDOM_WEIGHT = 0.8;\n\n    const double GREEDY_VALUE_WEIGHT = 1.0;\n    const double GREEDY_MOB_WEIGHT = 20.0;\n    const double GREEDY_NEI_WEIGHT = 0.9;\n    const double GREEDY_TWO_WEIGHT = 0.4;\n    const double GREEDY_RANDOM_WEIGHT = 0.4;\n    const int MAX_GREEDY_STEPS = 1500;\n    const int MAX_GREEDY_CANDIDATES = 3;\n\n    inline double rand01() {\n        static constexpr double INV = 1.0 / (1ULL << 53);\n        return (rng() >> 11) * INV;\n    }\n    inline double elapsed() const {\n        using namespace chrono;\n        return duration<double>(steady_clock::now() - timeStart).count();\n    }\n    inline bool timeUp() const {\n        return elapsed() > TIME_LIMIT;\n    }\n\n    Features calcFeatures(const VisitBitset &vis, int pos) const {\n        Features feat;\n        for (const auto &nb : adj[pos]) {\n            if (vis.test(tileOf[nb.to])) continue;\n            ++feat.mobility;\n            int val = value[nb.to];\n            if (val >= feat.nei1) {\n                feat.nei2 = feat.nei1;\n                feat.nei1 = val;\n            } else if (val > feat.nei2) {\n                feat.nei2 = val;\n            }\n            for (const auto &nb2 : adj[nb.to]) {\n                if (vis.test(tileOf[nb2.to])) continue;\n                int val2 = value[nb2.to];\n                if (val2 > feat.two) feat.two = val2;\n            }\n        }\n        return feat;\n    }\n\n    string buildPath(const vector<Node> &pool, int idx) const {\n        string res;\n        res.reserve(pool[idx].depth);\n        int cur = idx;\n        while (cur != -1) {\n            const Node &node = pool[cur];\n            if (node.parent == -1) break;\n            res.push_back(node.move);\n            cur = node.parent;\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    void greedyExtend(const Node &startNode, string path) {\n        VisitBitset vis = startNode.visited;\n        int pos = startNode.pos;\n        int score = startNode.score;\n        array<Neighbor, 4> moveBuf;\n        int steps = 0;\n        while (!timeUp() && steps < MAX_GREEDY_STEPS) {\n            int moveCount = 0;\n            for (const auto &nb : adj[pos]) {\n                if (vis.test(tileOf[nb.to])) continue;\n                moveBuf[moveCount++] = nb;\n            }\n            if (moveCount == 0) break;\n            double bestEval = -1e100;\n            int bestIdx = -1;\n            VisitBitset bestVis;\n            for (int i = 0; i < moveCount; ++i) {\n                VisitBitset nextVis = vis;\n                nextVis.set(tileOf[moveBuf[i].to]);\n                Features feat = calcFeatures(nextVis, moveBuf[i].to);\n                double eval = GREEDY_VALUE_WEIGHT * value[moveBuf[i].to]\n                            + GREEDY_MOB_WEIGHT * feat.mobility\n                            + GREEDY_NEI_WEIGHT * feat.nei1\n                            + GREEDY_TWO_WEIGHT * feat.two\n                            + GREEDY_RANDOM_WEIGHT * rand01();\n                if (eval > bestEval) {\n                    bestEval = eval;\n                    bestIdx = i;\n                    bestVis = nextVis;\n                }\n            }\n            if (bestIdx == -1) break;\n            const Neighbor &chosen = moveBuf[bestIdx];\n            vis = bestVis;\n            pos = chosen.to;\n            score += value[pos];\n            path.push_back(chosen.dir);\n            ++steps;\n        }\n        if (score > bestScore || (score == bestScore && path.size() > bestPath.size())) {\n            bestScore = score;\n            bestPath = std::move(path);\n        }\n    }\n\n    void runBeam(int beamWidth) {\n        if (timeUp()) return;\n        const size_t MAX_POOL_RESERVE = 220000;\n        vector<Node> pool;\n        size_t reserveSize = min<size_t>(static_cast<size_t>(beamWidth) * 900 + 1000ULL, MAX_POOL_RESERVE);\n        pool.reserve(reserveSize);\n\n        pool.emplace_back();\n        Node &root = pool.back();\n        root.visited.reset();\n        root.visited.set(tileOf[startIdx]);\n        root.pos = startIdx;\n        root.score = value[startIdx];\n        root.parent = -1;\n        root.move = '?';\n        root.depth = 0;\n\n        int runBestIdx = 0;\n        int runBestScore = root.score;\n\n        vector<int> current;\n        current.reserve(beamWidth);\n        current.push_back(0);\n\n        vector<Candidate> candBuf;\n        candBuf.reserve(beamWidth * 4 + 10);\n\n        array<Neighbor, 4> moveBuf;\n        bool forceStop = false;\n\n        while (!current.empty() && !forceStop) {\n            if (timeUp()) break;\n            candBuf.clear();\n            for (int idx : current) {\n                if (timeUp()) { forceStop = true; break; }\n                VisitBitset parentVis = pool[idx].visited;\n                int pos = pool[idx].pos;\n                int baseScore = pool[idx].score;\n                int depth = pool[idx].depth;\n\n                int moveCount = 0;\n                for (const auto &nb : adj[pos]) {\n                    if (parentVis.test(tileOf[nb.to])) continue;\n                    moveBuf[moveCount++] = nb;\n                }\n                if (moveCount == 0) continue;\n                if (moveCount > 1) {\n                    shuffle(moveBuf.begin(), moveBuf.begin() + moveCount, rng);\n                }\n                for (int mi = 0; mi < moveCount; ++mi) {\n                    if (timeUp()) { forceStop = true; break; }\n                    const Neighbor &nb = moveBuf[mi];\n                    pool.emplace_back();\n                    Node &child = pool.back();\n                    child.visited = parentVis;\n                    child.visited.set(tileOf[nb.to]);\n                    child.pos = nb.to;\n                    child.score = baseScore + value[nb.to];\n                    child.parent = idx;\n                    child.move = nb.dir;\n                    child.depth = depth + 1;\n                    int childIdx = (int)pool.size() - 1;\n\n                    Features feat = calcFeatures(child.visited, child.pos);\n                    double eval = child.score\n                                + LENGTH_WEIGHT * child.depth\n                                + MOBILITY_WEIGHT * feat.mobility\n                                + NEI1_WEIGHT * feat.nei1\n                                + NEI2_WEIGHT * feat.nei2\n                                + TWO_WEIGHT * feat.two\n                                + RANDOM_WEIGHT * rand01();\n\n                    candBuf.push_back({eval, childIdx});\n\n                    if (child.score > runBestScore ||\n                        (child.score == runBestScore && child.depth > pool[runBestIdx].depth)) {\n                        runBestScore = child.score;\n                        runBestIdx = childIdx;\n                    }\n                }\n                if (forceStop) break;\n            }\n            if (forceStop || candBuf.empty()) break;\n\n            auto cmp = [](const Candidate &a, const Candidate &b) { return a.eval > b.eval; };\n            if ((int)candBuf.size() > beamWidth) {\n                partial_sort(candBuf.begin(), candBuf.begin() + beamWidth, candBuf.end(), cmp);\n                candBuf.resize(beamWidth);\n            } else {\n                sort(candBuf.begin(), candBuf.end(), cmp);\n            }\n\n            current.clear();\n            current.reserve(candBuf.size());\n            for (const auto &cand : candBuf) current.push_back(cand.idx);\n        }\n\n        string runBestPath = buildPath(pool, runBestIdx);\n        if (runBestScore > bestScore ||\n            (runBestScore == bestScore && runBestPath.size() > bestPath.size())) {\n            bestScore = runBestScore;\n            bestPath = runBestPath;\n        }\n\n        if (!timeUp()) {\n            vector<int> greedies;\n            greedies.reserve(MAX_GREEDY_CANDIDATES);\n            greedies.push_back(runBestIdx);\n            for (int idx : current) {\n                if ((int)greedies.size() >= MAX_GREEDY_CANDIDATES) break;\n                bool dup = false;\n                for (int g : greedies) if (g == idx) { dup = true; break; }\n                if (!dup) greedies.push_back(idx);\n            }\n            for (int idx : greedies) {\n                if (timeUp()) break;\n                string path = buildPath(pool, idx);\n                greedyExtend(pool[idx], std::move(path));\n            }\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        int si, sj;\n        if (!(cin >> si >> sj)) return;\n        tileOf.resize(N2);\n        int maxTile = -1;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int t;\n                cin >> t;\n                int idx = i * N + j;\n                tileOf[idx] = t;\n                maxTile = max(maxTile, t);\n            }\n        }\n        [[maybe_unused]] int tileCount = maxTile + 1;\n        value.resize(N2);\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int p;\n                cin >> p;\n                value[i * N + j] = p;\n            }\n        }\n        startIdx = si * N + sj;\n\n        adj.assign(N2, {});\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n        const char dirChar[4] = {'U', 'D', 'L', 'R'};\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int idx = i * N + j;\n                for (int d = 0; d < 4; ++d) {\n                    int ni = i + di[d];\n                    int nj = j + dj[d];\n                    if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                    int nidx = ni * N + nj;\n                    adj[idx].push_back({nidx, dirChar[d]});\n                }\n            }\n        }\n\n        bestScore = value[startIdx];\n        bestPath.clear();\n\n        timeStart = chrono::steady_clock::now();\n        rng.seed(chrono::steady_clock::now().time_since_epoch().count());\n\n        vector<int> beamOptions = {60, 80, 100};\n        int iteration = 0;\n        while (!timeUp()) {\n            int bw = beamOptions[iteration % beamOptions.size()];\n            runBeam(bw);\n            ++iteration;\n        }\n\n        cout << bestPath << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\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    static constexpr int HOR = H * (W - 1);\n    static constexpr int VER = (H - 1) * W;\n    static constexpr int EDGE_CNT = HOR + VER;\n\n    // Estimation parameters\n    const double INIT_MEAN = 5000.0;\n    const double INIT_PERT = 200.0;\n\n    const double BASE_VAR = 1.0e7;\n    const double INFO_OFFSET = 0.5;\n    const double MIN_VAR = 1.0e4;\n    const double MAX_INFO = 600.0;\n    const double INFO_GAIN_BASE = 1.2;\n\n    const double MEAS_NOISE_COEFF = (0.2 * 0.2) / 12.0;\n    const double MEAS_VAR_FLOOR = 1e5;\n\n    const double MIN_EDGE_WEIGHT = 900.0;\n    const double MAX_EDGE_WEIGHT = 9200.0;\n    const double MIN_SEARCH_WEIGHT = 1.0;\n\n    const double ALPHA_MIN = 0.05;\n    const double ALPHA_MAX = 0.9;\n\n    // Exploration\n    const double USE_EXPLORE_COEFF = 520.0;\n    const double INFO_EXPLORE_COEFF = 360.0;\n    const double EXPLORE_BASE = 1.0;\n\n    // Smoothing parameters\n    const double SMOOTH_SELF_BIAS = 0.6;\n    const double SMOOTH_NEIGH_BIAS = 1.5;\n    const double SMOOTH_PULL = 0.55;\n    const double SMOOTH_DENOM = 0.8;\n    const double SMOOTH_MAX_PUSH = 0.45;\n    const double GLOBAL_SMOOTH_SCALE = 800.0;\n    const double GLOBAL_SMOOTH_MIN = 0.25;\n    const double SMOOTH_INFO_REQ = 1.0;\n    const int ROUGH_MIN_COUNT = 80;\n    const double LOCAL_DIFF_SCALE = 900.0;\n    const double MIN_LOCAL_GATE = 0.08;\n    const double LOW_INFO_THRESHOLD = 0.25;\n    const double LOW_INFO_MULT = 1.35;\n\n    vector<double> edgeWeight;\n    vector<int> edgeUse;\n    vector<double> edgeInfo;\n\n    vector<double> dist;\n    vector<int> prevNode;\n    vector<int> prevEdge;\n    vector<char> prevMove;\n\n    vector<double> tmpHor;\n    vector<double> tmpVer;\n\n    mt19937 rng;\n\n    Solver()\n        : edgeWeight(EDGE_CNT),\n          edgeUse(EDGE_CNT, 0),\n          edgeInfo(EDGE_CNT, 0.0),\n          dist(N),\n          prevNode(N),\n          prevEdge(N),\n          prevMove(N),\n          tmpHor(HOR),\n          tmpVer(VER) {\n        rng.seed(chrono::steady_clock::now().time_since_epoch().count());\n        uniform_real_distribution<double> pert(-INIT_PERT, INIT_PERT);\n        for (int i = 0; i < EDGE_CNT; ++i) {\n            edgeWeight[i] = INIT_MEAN + pert(rng);\n        }\n    }\n\n    inline int nodeId(int i, int j) const { return i * W + j; }\n    inline int horId(int i, int j) const { return i * (W - 1) + j; }\n    inline int verId(int i, int j) const { return HOR + i * W + j; }\n\n    inline double clampWeight(double v) const {\n        if (v < MIN_EDGE_WEIGHT) return MIN_EDGE_WEIGHT;\n        if (v > MAX_EDGE_WEIGHT) return MAX_EDGE_WEIGHT;\n        return v;\n    }\n\n    double edgeCostForSearch(int eid) const {\n        double useBias = USE_EXPLORE_COEFF / sqrt(edgeUse[eid] + EXPLORE_BASE);\n        double infoBias = INFO_EXPLORE_COEFF / sqrt(edgeInfo[eid] + 1.0);\n        double w = edgeWeight[eid] - useBias - infoBias;\n        if (w < MIN_SEARCH_WEIGHT) w = MIN_SEARCH_WEIGHT;\n        return w;\n    }\n\n    void buildFallback(int si, int sj, int ti, int tj, string &path, vector<int> &pathEdges) {\n        path.clear();\n        pathEdges.clear();\n        int ci = si, cj = sj;\n        auto pushStep = [&](char mv) {\n            path.push_back(mv);\n            if (mv == 'U') {\n                pathEdges.push_back(verId(ci - 1, cj));\n                --ci;\n            } else if (mv == 'D') {\n                pathEdges.push_back(verId(ci, cj));\n                ++ci;\n            } else if (mv == 'L') {\n                pathEdges.push_back(horId(ci, cj - 1));\n                --cj;\n            } else {\n                pathEdges.push_back(horId(ci, cj));\n                ++cj;\n            }\n        };\n        while (ci < ti) pushStep('D');\n        while (ci > ti) pushStep('U');\n        while (cj < tj) pushStep('R');\n        while (cj > tj) pushStep('L');\n    }\n\n    void computePath(int si, int sj, int ti, int tj, string &path, vector<int> &pathEdges) {\n        path.clear();\n        pathEdges.clear();\n        int start = nodeId(si, sj);\n        int target = nodeId(ti, tj);\n        const double INF = 1e100;\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevNode.begin(), prevNode.end(), -1);\n        fill(prevEdge.begin(), prevEdge.end(), -1);\n        fill(prevMove.begin(), prevMove.end(), 0);\n\n        struct PQNode {\n            double dist;\n            int node;\n            bool operator<(const PQNode &o) const { return dist > o.dist; }\n        };\n\n        priority_queue<PQNode> pq;\n        dist[start] = 0.0;\n        pq.push({0.0, start});\n\n        while (!pq.empty()) {\n            auto cur = pq.top();\n            pq.pop();\n            if (cur.dist > dist[cur.node]) continue;\n            if (cur.node == target) break;\n            int i = cur.node / W;\n            int j = cur.node % W;\n\n            if (i > 0) {\n                int nb = cur.node - W;\n                int eid = verId(i - 1, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'U';\n                    pq.push({nd, nb});\n                }\n            }\n            if (i + 1 < H) {\n                int nb = cur.node + W;\n                int eid = verId(i, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'D';\n                    pq.push({nd, nb});\n                }\n            }\n            if (j > 0) {\n                int nb = cur.node - 1;\n                int eid = horId(i, j - 1);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'L';\n                    pq.push({nd, nb});\n                }\n            }\n            if (j + 1 < W) {\n                int nb = cur.node + 1;\n                int eid = horId(i, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'R';\n                    pq.push({nd, nb});\n                }\n            }\n        }\n\n        if (start != target && prevEdge[target] == -1) {\n            buildFallback(si, sj, ti, tj, path, pathEdges);\n            return;\n        }\n        int cur = target;\n        while (cur != start) {\n            int pe = prevEdge[cur];\n            if (pe == -1) {\n                buildFallback(si, sj, ti, tj, path, pathEdges);\n                return;\n            }\n            path.push_back(prevMove[cur]);\n            pathEdges.push_back(pe);\n            cur = prevNode[cur];\n        }\n        reverse(path.begin(), path.end());\n        reverse(pathEdges.begin(), pathEdges.end());\n    }\n\n    double computeSmoothFactor() const {\n        double sumDiff = 0.0;\n        int cnt = 0;\n\n        for (int i = 0; i < H; ++i) {\n            for (int j = 1; j < W - 1; ++j) {\n                int eid = horId(i, j);\n                int left = horId(i, j - 1);\n                double minInfo = min(edgeInfo[eid], edgeInfo[left]);\n                if (minInfo < SMOOTH_INFO_REQ) continue;\n                sumDiff += fabs(edgeWeight[eid] - edgeWeight[left]);\n                ++cnt;\n            }\n        }\n        for (int j = 0; j < W; ++j) {\n            for (int i = 1; i < H - 1; ++i) {\n                int eid = verId(i, j);\n                int up = verId(i - 1, j);\n                double minInfo = min(edgeInfo[eid], edgeInfo[up]);\n                if (minInfo < SMOOTH_INFO_REQ) continue;\n                sumDiff += fabs(edgeWeight[eid] - edgeWeight[up]);\n                ++cnt;\n            }\n        }\n\n        if (cnt < ROUGH_MIN_COUNT) return 1.0;\n        double avg = sumDiff / cnt;\n        double factor = 1.0 / (1.0 + avg / GLOBAL_SMOOTH_SCALE);\n        if (factor < GLOBAL_SMOOTH_MIN) factor = GLOBAL_SMOOTH_MIN;\n        if (factor > 1.0) factor = 1.0;\n        return factor;\n    }\n\n    void smoothHorizontal(double globalFactor) {\n        for (int i = 0; i < H; ++i) {\n            for (int j = 0; j < W - 1; ++j) {\n                int eid = horId(i, j);\n                double sum = (edgeInfo[eid] + SMOOTH_SELF_BIAS) * edgeWeight[eid];\n                double denom = edgeInfo[eid] + SMOOTH_SELF_BIAS;\n\n                auto addNeighbor = [&](int nj) {\n                    int nid = horId(i, nj);\n                    double diff = fabs(edgeWeight[eid] - edgeWeight[nid]);\n                    double gate = 1.0 / (1.0 + diff / LOCAL_DIFF_SCALE);\n                    if (gate < MIN_LOCAL_GATE) gate = MIN_LOCAL_GATE;\n                    double w = (edgeInfo[nid] + SMOOTH_NEIGH_BIAS) * gate;\n                    sum += w * edgeWeight[nid];\n                    denom += w;\n                };\n\n                if (j > 0) addNeighbor(j - 1);\n                if (j + 1 < W - 1) addNeighbor(j + 1);\n\n                double avg = sum / denom;\n                double push = SMOOTH_PULL / (edgeInfo[eid] + SMOOTH_DENOM);\n                if (edgeInfo[eid] < LOW_INFO_THRESHOLD) push *= LOW_INFO_MULT;\n                push = min(push, SMOOTH_MAX_PUSH);\n                push *= globalFactor;\n\n                double newVal = edgeWeight[eid] + push * (avg - edgeWeight[eid]);\n                tmpHor[eid] = clampWeight(newVal);\n            }\n        }\n        for (int i = 0; i < HOR; ++i) edgeWeight[i] = tmpHor[i];\n    }\n\n    void smoothVertical(double globalFactor) {\n        for (int j = 0; j < W; ++j) {\n            for (int i = 0; i < H - 1; ++i) {\n                int eid = verId(i, j);\n                double sum = (edgeInfo[eid] + SMOOTH_SELF_BIAS) * edgeWeight[eid];\n                double denom = edgeInfo[eid] + SMOOTH_SELF_BIAS;\n\n                auto addNeighbor = [&](int ni) {\n                    int nid = verId(ni, j);\n                    double diff = fabs(edgeWeight[eid] - edgeWeight[nid]);\n                    double gate = 1.0 / (1.0 + diff / LOCAL_DIFF_SCALE);\n                    if (gate < MIN_LOCAL_GATE) gate = MIN_LOCAL_GATE;\n                    double w = (edgeInfo[nid] + SMOOTH_NEIGH_BIAS) * gate;\n                    sum += w * edgeWeight[nid];\n                    denom += w;\n                };\n\n                if (i > 0) addNeighbor(i - 1);\n                if (i + 1 < H - 1) addNeighbor(i + 1);\n\n                double avg = sum / denom;\n                double push = SMOOTH_PULL / (edgeInfo[eid] + SMOOTH_DENOM);\n                if (edgeInfo[eid] < LOW_INFO_THRESHOLD) push *= LOW_INFO_MULT;\n                push = min(push, SMOOTH_MAX_PUSH);\n                push *= globalFactor;\n\n                double newVal = edgeWeight[eid] + push * (avg - edgeWeight[eid]);\n                int idx = i * W + j;\n                tmpVer[idx] = clampWeight(newVal);\n            }\n        }\n        for (int i = 0; i < VER; ++i) edgeWeight[HOR + i] = tmpVer[i];\n    }\n\n    void smoothEstimates() {\n        double factor = computeSmoothFactor();\n        smoothHorizontal(factor);\n        smoothVertical(factor);\n    }\n\n    void update(const vector<int> &pathEdges, double measurement) {\n        if (pathEdges.empty()) return;\n\n        size_t m = pathEdges.size();\n        vector<double> vars;\n        vars.reserve(m);\n\n        double predicted = 0.0;\n        double sumVar = 0.0;\n        for (int eid : pathEdges) {\n            predicted += edgeWeight[eid];\n            double var = BASE_VAR / (edgeInfo[eid] + INFO_OFFSET);\n            if (var < MIN_VAR) var = MIN_VAR;\n            vars.push_back(var);\n            sumVar += var;\n        }\n        if (sumVar <= 0.0) sumVar = MIN_VAR;\n\n        double residual = measurement - predicted;\n        double safePred = max(predicted, 1.0);\n        double measurementVar = MEAS_NOISE_COEFF * safePred * safePred + MEAS_VAR_FLOOR;\n        double alpha = sumVar / (sumVar + measurementVar);\n        if (alpha < ALPHA_MIN) alpha = ALPHA_MIN;\n        if (alpha > ALPHA_MAX) alpha = ALPHA_MAX;\n\n        double scale = alpha * residual / sumVar;\n        for (size_t idx = 0; idx < m; ++idx) {\n            int eid = pathEdges[idx];\n            double delta = vars[idx] * scale;\n            edgeWeight[eid] = clampWeight(edgeWeight[eid] + delta);\n        }\n\n        double invSumVar = 1.0 / sumVar;\n        for (size_t idx = 0; idx < m; ++idx) {\n            int eid = pathEdges[idx];\n            double infoGain = INFO_GAIN_BASE * vars[idx] * invSumVar;\n            edgeInfo[eid] = min(edgeInfo[eid] + infoGain, MAX_INFO);\n            edgeUse[eid] = min(edgeUse[eid] + 1, 1000000000);\n        }\n\n        smoothEstimates();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    string path;\n    path.reserve(128);\n    vector<int> pathEdges;\n    pathEdges.reserve(128);\n\n    for (int q = 0; q < 1000; ++q) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        solver.computePath(si, sj, ti, tj, path, pathEdges);\n        cout << path << '\\n' << flush;\n\n        int measurement;\n        if (!(cin >> measurement)) return 0;\n        if (measurement < 0) return 0;\n\n        solver.update(pathEdges, static_cast<double>(measurement));\n    }\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 20;\nconstexpr int MAXLEN = 12;\nconstexpr int ORIENT = 2;\nconstexpr int PL_PER_ORIENT = N * N;\nconstexpr int PL = ORIENT * PL_PER_ORIENT;\nconstexpr uint8_t EMPTY = 0xFF;\nconst double TIME_LIMIT = 2.9;\nconst double LOCAL_SEARCH_MARGIN = 0.6;\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 Placement {\n    array<uint8_t, MAXLEN> rows;\n    array<uint8_t, MAXLEN> cols;\n    array<int, MAXLEN> cellIndex;\n};\n\nstruct Read {\n    string s;\n    vector<uint8_t> codes;\n    int len;\n};\n\nusing Grid = array<array<uint8_t, N>, N>;\n\nstruct Candidate {\n    Grid grid;\n    int score;\n};\n\ninline double vote_weight(int match, int len) {\n    if (match <= 0) return 0.0;\n    if (match >= len) return 6.5;\n    if (match == len - 1) return 2.3;\n    if (match == len - 2) return 0.9;\n    if (match >= len - 3) return 0.4;\n    if (match * 2 >= len) return 0.12;\n    return 0.03;\n}\n\nvector<Placement> build_placements() {\n    vector<Placement> placements(PL);\n    int idx = 0;\n    for (int ori = 0; ori < ORIENT; ++ori) {\n        for (int fixed = 0; fixed < N; ++fixed) {\n            for (int start = 0; start < N; ++start) {\n                Placement &p = placements[idx++];\n                for (int t = 0; t < MAXLEN; ++t) {\n                    int r, c;\n                    if (ori == 0) {\n                        r = fixed;\n                        c = (start + t) % N;\n                    } else {\n                        r = (start + t) % N;\n                        c = fixed;\n                    }\n                    p.rows[t] = static_cast<uint8_t>(r);\n                    p.cols[t] = static_cast<uint8_t>(c);\n                    p.cellIndex[t] = ((r * N + c) << 3);\n                }\n            }\n        }\n    }\n    return placements;\n}\n\nGrid seed_grid(const vector<Read> &reads, const vector<Placement> &placements, mt19937_64 &rng) {\n    Grid grid;\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            grid[i][j] = EMPTY;\n\n    vector<int> order(reads.size());\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (reads[a].len != reads[b].len) return reads[a].len > reads[b].len;\n        return a < b;\n    });\n\n    for (int idx : order) {\n        const Read &rd = reads[idx];\n        int len = rd.len;\n        int chosen = -1;\n        int cnt = 0;\n        for (int pid = 0; pid < PL; ++pid) {\n            bool ok = true;\n            for (int t = 0; t < len; ++t) {\n                uint8_t cur = grid[placements[pid].rows[t]][placements[pid].cols[t]];\n                if (cur != EMPTY && cur != rd.codes[t]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) {\n                ++cnt;\n                if ((uint64_t)rng() % cnt == 0) chosen = pid;\n            }\n        }\n        if (chosen != -1) {\n            for (int t = 0; t < len; ++t) {\n                grid[placements[chosen].rows[t]][placements[chosen].cols[t]] = rd.codes[t];\n            }\n        }\n    }\n\n    uniform_int_distribution<int> dist(0, 7);\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            if (grid[i][j] == EMPTY)\n                grid[i][j] = static_cast<uint8_t>(dist(rng));\n    return grid;\n}\n\nint compute_delta(int iter, int total) {\n    if (total <= 4) return 1;\n    if (iter * 3 >= total * 2) return 1;\n    if (iter * 3 >= total) return 2;\n    return 3;\n}\n\nvoid run_em(Grid &grid, int iterations, const vector<Read> &reads,\n            const vector<Placement> &placements, vector<double> &counts,\n            array<uint8_t, PL> &matchBuf, const vector<double> &weights,\n            double inertia, Timer &timer) {\n    for (int iter = 0; iter < iterations; ++iter) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n        fill(counts.begin(), counts.end(), 0.0);\n        int delta = compute_delta(iter, iterations);\n\n        for (const Read &rd : reads) {\n            const uint8_t *codes = rd.codes.data();\n            int len = rd.len;\n            int best = 0;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = 0;\n                for (int t = 0; t < len; ++t)\n                    if (grid[placements[pid].rows[t]][placements[pid].cols[t]] == codes[t]) ++match;\n                matchBuf[pid] = static_cast<uint8_t>(match);\n                if (match > best) best = match;\n            }\n            if (best == 0) continue;\n            int threshold = max(0, best - delta);\n            double totalWeight = 0.0;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = matchBuf[pid];\n                if (match < threshold) continue;\n                totalWeight += weights[match];\n            }\n            if (totalWeight <= 0) continue;\n            double inv = 1.0 / totalWeight;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = matchBuf[pid];\n                if (match < threshold) continue;\n                double w = weights[match];\n                if (w <= 0) continue;\n                double scaled = w * inv;\n                for (int t = 0; t < len; ++t)\n                    counts[placements[pid].cellIndex[t] + codes[t]] += scaled;\n            }\n        }\n\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                counts[((r * N + c) << 3) + grid[r][c]] += inertia;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int base = ((r * N + c) << 3);\n                double bestVal = counts[base];\n                int bestLetter = 0;\n                for (int letter = 1; letter < 8; ++letter) {\n                    double v = counts[base + letter];\n                    if (v > bestVal) {\n                        bestVal = v;\n                        bestLetter = letter;\n                    }\n                }\n                grid[r][c] = static_cast<uint8_t>(bestLetter);\n            }\n        }\n    }\n}\n\nint compute_best_matches(const Grid &grid, const vector<Read> &reads,\n                         vector<int> &bestPid, vector<uint8_t> &bestMatch,\n                         vector<uint8_t> *sat = nullptr) {\n    array<array<uint8_t, N * 2>, N> rowBuf, colBuf;\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            uint8_t val = grid[r][c];\n            rowBuf[r][c] = val;\n            rowBuf[r][c + N] = val;\n            colBuf[c][r] = val;\n            colBuf[c][r + N] = val;\n        }\n    }\n\n    int M = reads.size();\n    if ((int)bestPid.size() != M) bestPid.assign(M, 0);\n    if ((int)bestMatch.size() != M) bestMatch.assign(M, 0);\n    if (sat && (int)sat->size() != M) sat->assign(M, 0);\n\n    int satisfied = 0;\n    for (int idx = 0; idx < M; ++idx) {\n        const Read &rd = reads[idx];\n        const uint8_t *codes = rd.codes.data();\n        int len = rd.len;\n        int best = -1;\n        int bestPlacement = 0;\n        bool perfect = false;\n\n        for (int r = 0; r < N && !perfect; ++r) {\n            const uint8_t *rowPtr = rowBuf[r].data();\n            for (int start = 0; start < N; ++start) {\n                const uint8_t *seg = rowPtr + start;\n                int match = 0;\n                for (int t = 0; t < len; ++t)\n                    match += (seg[t] == codes[t]);\n                if (match > best) {\n                    best = match;\n                    bestPlacement = r * N + start;\n                    if (match == len) { perfect = true; break; }\n                }\n            }\n        }\n        if (!perfect) {\n            for (int c = 0; c < N && !perfect; ++c) {\n                const uint8_t *colPtr = colBuf[c].data();\n                for (int start = 0; start < N; ++start) {\n                    const uint8_t *seg = colPtr + start;\n                    int match = 0;\n                    for (int t = 0; t < len; ++t)\n                        match += (seg[t] == codes[t]);\n                    if (match > best) {\n                        best = match;\n                        bestPlacement = PL_PER_ORIENT + c * N + start;\n                        if (match == len) { perfect = true; break; }\n                    }\n                }\n            }\n        }\n        if (best < 0) best = 0;\n        bestPid[idx] = bestPlacement;\n        bestMatch[idx] = static_cast<uint8_t>(best);\n        bool satFlag = (best == len);\n        if (sat) (*sat)[idx] = static_cast<uint8_t>(satFlag);\n        if (satFlag) ++satisfied;\n    }\n    return satisfied;\n}\n\nvoid repair_grid(Grid &grid, const vector<Read> &reads, const vector<Placement> &placements,\n                 Timer &timer, const vector<int> &bestPid, const vector<uint8_t> &bestMatch,\n                 int threshold) {\n    int M = reads.size();\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        int ma = reads[a].len - bestMatch[a];\n        int mb = reads[b].len - bestMatch[b];\n        if (ma != mb) return ma < mb;\n        return reads[a].len > reads[b].len;\n    });\n    for (int idx : order) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n        int mismatch = reads[idx].len - bestMatch[idx];\n        if (mismatch <= 0 || mismatch > threshold) continue;\n        int pid = bestPid[idx];\n        if (pid < 0 || pid >= PL) continue;\n        const Placement &pl = placements[pid];\n        const Read &rd = reads[idx];\n        for (int t = 0; t < rd.len; ++t) {\n            grid[pl.rows[t]][pl.cols[t]] = rd.codes[t];\n        }\n    }\n}\n\nvoid local_search(Grid &grid, const vector<Read> &reads,\n                  const vector<Placement> &placements, Timer &timer,\n                  Grid &globalBest, int &globalBestScore, mt19937_64 &rng,\n                  int maxIter = 220) {\n    int M = reads.size();\n    vector<int> curBestPid(M), tmpBestPid(M);\n    vector<uint8_t> curBestMatch(M), tmpBestMatch(M);\n    vector<uint8_t> curSat(M), tmpSat(M);\n\n    int curScore = compute_best_matches(grid, reads, curBestPid, curBestMatch, &curSat);\n    if (curScore > globalBestScore) {\n        globalBestScore = curScore;\n        globalBest = grid;\n    }\n\n    array<vector<int>, MAXLEN + 1> buckets;\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    for (int iter = 0; iter < maxIter; ++iter) {\n        if (timer.elapsed() > TIME_LIMIT - 0.02) break;\n        if (curScore == M) break;\n\n        for (auto &vec : buckets) vec.clear();\n        for (int i = 0; i < M; ++i) {\n            if (curSat[i]) continue;\n            int mismatch = reads[i].len - curBestMatch[i];\n            if (mismatch < 1) mismatch = 1;\n            if (mismatch > MAXLEN) mismatch = MAXLEN;\n            buckets[mismatch].push_back(i);\n        }\n        int chosenMis = -1;\n        for (int mis = 1; mis <= MAXLEN; ++mis) {\n            if (!buckets[mis].empty()) { chosenMis = mis; break; }\n        }\n        if (chosenMis == -1) break;\n        int range = min(MAXLEN, chosenMis + 3);\n        for (int mis = chosenMis + 1; mis <= range; ++mis) {\n            if (!buckets[mis].empty() && uni01(rng) < 0.25) {\n                chosenMis = mis;\n                break;\n            }\n        }\n        const vector<int> &bucket = buckets[chosenMis];\n        int pick = bucket[rng() % bucket.size()];\n        int pid = curBestPid[pick];\n        if (pid < 0 || pid >= PL) continue;\n        const Placement &pl = placements[pid];\n        const Read &rd = reads[pick];\n        array<uint8_t, MAXLEN> backup;\n        bool changed = false;\n        for (int t = 0; t < rd.len; ++t) {\n            int r = pl.rows[t], c = pl.cols[t];\n            backup[t] = grid[r][c];\n            uint8_t desired = rd.codes[t];\n            if (grid[r][c] != desired) {\n                grid[r][c] = desired;\n                changed = true;\n            }\n        }\n        if (!changed) continue;\n\n        int newScore = compute_best_matches(grid, reads, tmpBestPid, tmpBestMatch, &tmpSat);\n        double progress = max(0.0, min(1.0, static_cast<double>(iter) / max(1, maxIter - 1)));\n        double temp = 2.8 + (0.25 - 2.8) * progress;\n        int diff = newScore - curScore;\n        bool accept = diff >= 0;\n        if (!accept) {\n            double prob = exp(diff / temp);\n            if (prob > uni01(rng)) accept = true;\n        }\n\n        if (accept) {\n            curScore = newScore;\n            swap(curBestPid, tmpBestPid);\n            swap(curBestMatch, tmpBestMatch);\n            swap(curSat, tmpSat);\n            if (curScore > globalBestScore) {\n                globalBestScore = curScore;\n                globalBest = grid;\n            }\n        } else {\n            for (int t = 0; t < rd.len; ++t)\n                grid[pl.rows[t]][pl.cols[t]] = backup[t];\n        }\n    }\n}\n\nint placement_vote_refine(Grid &grid, const vector<Read> &reads,\n                          const vector<Placement> &placements,\n                          vector<int> &bestPid, vector<uint8_t> &bestMatch,\n                          vector<double> &counts, Timer &timer, int iterations) {\n    int currentScore = compute_best_matches(grid, reads, bestPid, bestMatch);\n    Grid bestGrid = grid;\n    int bestScore = currentScore;\n\n    int M = reads.size();\n    for (int it = 0; it < iterations; ++it) {\n        if (timer.elapsed() > TIME_LIMIT - 0.02) break;\n        fill(counts.begin(), counts.end(), 0.0);\n\n        for (int i = 0; i < M; ++i) {\n            int match = bestMatch[i];\n            double weight = vote_weight(match, reads[i].len);\n            if (weight <= 0) continue;\n            int pid = bestPid[i];\n            if (pid < 0 || pid >= PL) continue;\n            const Placement &pl = placements[pid];\n            const Read &rd = reads[i];\n            for (int t = 0; t < rd.len; ++t) {\n                counts[pl.cellIndex[t] + rd.codes[t]] += weight;\n            }\n        }\n\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                counts[((r * N + c) << 3) + grid[r][c]] += 0.25;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int base = ((r * N + c) << 3);\n                double bestVal = counts[base];\n                int bestLetter = 0;\n                for (int letter = 1; letter < 8; ++letter) {\n                    double v = counts[base + letter];\n                    if (v > bestVal) {\n                        bestVal = v;\n                        bestLetter = letter;\n                    }\n                }\n                grid[r][c] = static_cast<uint8_t>(bestLetter);\n            }\n        }\n\n        currentScore = compute_best_matches(grid, reads, bestPid, bestMatch);\n        if (currentScore > bestScore) {\n            bestScore = currentScore;\n            bestGrid = grid;\n        }\n    }\n\n    grid = bestGrid;\n    return bestScore;\n}\n\nvoid run_restart(Grid &bestGrid, int &bestScore, const vector<Read> &reads,\n                 const vector<Placement> &placements, vector<double> &counts,\n                 array<uint8_t, PL> &matchBuf, const vector<double> &weights,\n                 Timer &timer, mt19937_64 &rng,\n                 vector<int> &workBestPid, vector<uint8_t> &workBestMatch,\n                 vector<Candidate> &candidates) {\n    Grid grid = seed_grid(reads, placements, rng);\n    run_em(grid, 30, reads, placements, counts, matchBuf, weights, 0.35, timer);\n    int score = compute_best_matches(grid, reads, workBestPid, workBestMatch);\n    candidates.push_back({grid, score});\n    if (score > bestScore) {\n        bestScore = score;\n        bestGrid = grid;\n    }\n\n    if (TIME_LIMIT - timer.elapsed() > 0.35) {\n        repair_grid(grid, reads, placements, timer, workBestPid, workBestMatch, 2);\n        run_em(grid, 8, reads, placements, counts, matchBuf, weights, 0.25, timer);\n        score = compute_best_matches(grid, reads, workBestPid, workBestMatch);\n        candidates.push_back({grid, score});\n        if (score > bestScore) {\n            bestScore = score;\n            bestGrid = grid;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N_input, M;\n    if (!(cin >> N_input >> M)) return 0;\n    vector<Read> reads(M);\n    for (int i = 0; i < M; ++i) {\n        string s; cin >> s;\n        reads[i].s = s;\n        reads[i].len = s.size();\n        reads[i].codes.resize(s.size());\n        for (int j = 0; j < (int)s.size(); ++j)\n            reads[i].codes[j] = static_cast<uint8_t>(s[j] - 'A');\n    }\n\n    auto placements = build_placements();\n    vector<double> counts(N * N * 8, 0.0);\n    array<uint8_t, PL> matchBuf{};\n    vector<double> weights(MAXLEN + 1, 0.0);\n    weights[1] = 0.05;\n    double w = 1.0;\n    for (int m = 2; m <= MAXLEN; ++m) {\n        weights[m] = w;\n        w *= 1.75;\n    }\n\n    Timer timer;\n    mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    Grid bestGrid{};\n    int bestScore = -1;\n    vector<int> workBestPid(M);\n    vector<uint8_t> workBestMatch(M);\n    vector<Candidate> candidates;\n\n    int restarts = 0;\n    while (timer.elapsed() < TIME_LIMIT - LOCAL_SEARCH_MARGIN) {\n        run_restart(bestGrid, bestScore, reads, placements, counts, matchBuf, weights,\n                    timer, rng, workBestPid, workBestMatch, candidates);\n        ++restarts;\n        if (timer.elapsed() > TIME_LIMIT - LOCAL_SEARCH_MARGIN) break;\n    }\n    if (restarts == 0) {\n        run_restart(bestGrid, bestScore, reads, placements, counts, matchBuf, weights,\n                    timer, rng, workBestPid, workBestMatch, candidates);\n    }\n    if (candidates.empty()) candidates.push_back({bestGrid, bestScore});\n    sort(candidates.begin(), candidates.end(), [](const Candidate &a, const Candidate &b) {\n        return a.score > b.score;\n    });\n    if (bestScore < 0) {\n        bestGrid = candidates[0].grid;\n        bestScore = candidates[0].score;\n    }\n\n    const int MAX_LOCAL_CANDS = 4;\n    int localRuns = min(MAX_LOCAL_CANDS, (int)candidates.size());\n    for (int i = 0; i < localRuns; ++i) {\n        if (timer.elapsed() > TIME_LIMIT - 0.08) break;\n        Grid start = candidates[i].grid;\n        int iter = max(120, 220 - i * 30);\n        local_search(start, reads, placements, timer, bestGrid, bestScore, rng, iter);\n    }\n\n    if (timer.elapsed() < TIME_LIMIT - 0.08) {\n        Grid candidate = bestGrid;\n        int refinedScore = placement_vote_refine(candidate, reads, placements,\n                                                 workBestPid, workBestMatch,\n                                                 counts, timer, 2);\n        if (refinedScore > bestScore) {\n            bestScore = refinedScore;\n            bestGrid = candidate;\n        }\n    }\n\n    if (timer.elapsed() < TIME_LIMIT - 0.03) {\n        Grid start = bestGrid;\n        local_search(start, reads, placements, timer, bestGrid, bestScore, rng, 110);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        string line(N, 'A');\n        for (int j = 0; j < N; ++j)\n            line[j] = static_cast<char>('A' + bestGrid[i][j]);\n        cout << line << '\\n';\n    }\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst long long INFLL = (1LL << 60);\nconst long long INF_CAP = (1LL << 55);\nconst long long MAX_WEIGHT = (1LL << 50);\nconst int PLAN_KEEP = 6;\nconst int TSP_PLAN_LIMIT = 4;\nconst int TSP_TARGET_LIMIT = 220;\n\nconst int di[4] = {-1, 1, 0, 0};\nconst int dj[4] = {0, 0, -1, 1};\n\nstruct Dinic {\n    struct Edge { int to; long long cap; int rev; };\n    int N;\n    vector<vector<Edge>> G;\n    vector<int> level, prog;\n    Dinic(int n = 0) { init(n); }\n    void init(int n) {\n        N = n;\n        G.assign(n, {});\n    }\n    void add_edge(int fr, int to, long long cap) {\n        Edge f{to, cap, (int)G[to].size()};\n        Edge b{fr, 0, (int)G[fr].size()};\n        G[fr].push_back(f);\n        G[to].push_back(b);\n    }\n    bool bfs(int s, int t) {\n        level.assign(N, -1);\n        queue<int> q;\n        level[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            for (const auto &e : G[v]) if (e.cap > 0 && level[e.to] < 0) {\n                level[e.to] = level[v] + 1;\n                q.push(e.to);\n            }\n        }\n        return level[t] >= 0;\n    }\n    long long dfs(int v, int t, long long f) {\n        if (v == t) return f;\n        for (int &i = prog[v]; i < (int)G[v].size(); ++i) {\n            Edge &e = G[v][i];\n            if (e.cap > 0 && level[v] < level[e.to]) {\n                long long d = dfs(e.to, t, min(f, e.cap));\n                if (d > 0) {\n                    e.cap -= d;\n                    G[e.to][e.rev].cap += d;\n                    return d;\n                }\n            }\n        }\n        return 0;\n    }\n    long long max_flow(int s, int t) {\n        long long flow = 0;\n        while (bfs(s, t)) {\n            prog.assign(N, 0);\n            while (true) {\n                long long f = dfs(s, t, (1LL << 60));\n                if (!f) break;\n                flow += f;\n            }\n        }\n        return flow;\n    }\n};\n\nstruct Plan {\n    vector<int> targets;\n    long long approx;\n};\n\nstruct CandidatePlan {\n    long long cost;\n    vector<int> targets;\n};\n\nchar dir_char(int from, int to, int N) {\n    int fi = from / N, fj = from % N;\n    int ti = to / N, tj = to % N;\n    if (ti == fi - 1 && tj == fj) return 'U';\n    if (ti == fi + 1 && tj == fj) return 'D';\n    if (tj == fj - 1 && ti == fi) return 'L';\n    if (tj == fj + 1 && ti == fi) return 'R';\n    return 'U';\n}\n\nvoid run_dijkstra(int source, const vector<int> &cost, int N,\n                  vector<long long> &dist, vector<int> *parent) {\n    int total = N * N;\n    dist.assign(total, INFLL);\n    if (parent) parent->assign(total, -1);\n    using P = pair<long long,int>;\n    priority_queue<P, vector<P>, greater<P>> pq;\n    dist[source] = 0;\n    pq.emplace(0, source);\n    while (!pq.empty()) {\n        auto [d, u] = pq.top(); pq.pop();\n        if (d != dist[u]) continue;\n        int ui = u / N, uj = u % N;\n        for (int dir = 0; dir < 4; ++dir) {\n            int vi = ui + di[dir];\n            int vj = uj + dj[dir];\n            if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n            int v = vi * N + vj;\n            if (cost[v] < 0) continue;\n            long long nd = d + cost[v];\n            if (nd < dist[v]) {\n                dist[v] = nd;\n                if (parent) (*parent)[v] = u;\n                pq.emplace(nd, v);\n            }\n        }\n    }\n}\n\nstruct Cover {\n    vector<char> row_cover;\n    vector<char> col_cover;\n};\n\nvoid add_candidate_plan(const vector<int> &targets, long long cost,\n                        vector<CandidatePlan> &plans) {\n    plans.push_back({cost, targets});\n    sort(plans.begin(), plans.end(), [](const CandidatePlan &a, const CandidatePlan &b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return a.targets.size() < b.targets.size();\n    });\n    if ((int)plans.size() > PLAN_KEEP) plans.resize(PLAN_KEEP);\n}\n\nstruct SPCache {\n    int N, total;\n    const vector<int> &cost;\n    unordered_map<int,int> idx;\n    vector<vector<long long>> dist;\n    vector<vector<int>> parent;\n    SPCache(int N, const vector<int> &cost) : N(N), total(N * N), cost(cost) {\n        idx.reserve(512);\n    }\n    int get(int root) {\n        auto it = idx.find(root);\n        if (it != idx.end()) return it->second;\n        vector<long long> d(total);\n        vector<int> p(total);\n        run_dijkstra(root, cost, N, d, &p);\n        int id = dist.size();\n        idx[root] = id;\n        dist.push_back(move(d));\n        parent.push_back(move(p));\n        return id;\n    }\n};\n\nbool append_shortest_path(int from, int to, string &route,\n                          SPCache &cache, int N) {\n    if (from == to) return true;\n    int idx = cache.get(from);\n    const auto &parent = cache.parent[idx];\n    int cur = to;\n    vector<int> rev;\n    while (cur != from) {\n        if (cur < 0) return false;\n        int p = parent[cur];\n        if (p == -1) return false;\n        rev.push_back(cur);\n        cur = p;\n    }\n    int prev = from;\n    for (int k = (int)rev.size() - 1; k >= 0; --k) {\n        int node = rev[k];\n        route.push_back(dir_char(prev, node, N));\n        prev = node;\n    }\n    return true;\n}\n\nvoid buildTreeSP(const vector<int> &targets, vector<vector<int>> &treeAdj,\n                 int start_id, const vector<int> &parentStart, int total) {\n    vector<char> required(total, 0);\n    required[start_id] = 1;\n    for (int cell : targets) {\n        int cur = cell;\n        while (cur != -1 && !required[cur]) {\n            required[cur] = 1;\n            if (cur == start_id) break;\n            cur = parentStart[cur];\n        }\n    }\n    for (int v = 0; v < total; ++v) {\n        if (!required[v]) continue;\n        int p = parentStart[v];\n        if (p == -1 || !required[p]) continue;\n        treeAdj[v].push_back(p);\n        treeAdj[p].push_back(v);\n    }\n}\n\nbool buildSteinerTree(const vector<int> &targets, vector<vector<int>> &treeAdj,\n                      int start_id, const vector<int> &cost, int N) {\n    int total = (int)cost.size();\n    vector<char> need(total, 0);\n    int remaining = 0;\n    for (int cell : targets) if (!need[cell]) {\n        need[cell] = 1;\n        ++remaining;\n    }\n    vector<char> in_tree(total, 0);\n    vector<int> treeNodes;\n    treeNodes.reserve(total);\n    in_tree[start_id] = 1;\n    treeNodes.push_back(start_id);\n    if (need[start_id]) { need[start_id] = 0; --remaining; }\n    vector<long long> dist(total, INFLL);\n    vector<int> parent(total, -1);\n    while (remaining > 0) {\n        fill(dist.begin(), dist.end(), INFLL);\n        fill(parent.begin(), parent.end(), -1);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        for (int node : treeNodes) {\n            dist[node] = 0;\n            parent[node] = -1;\n            pq.emplace(0, node);\n        }\n        int best = -1;\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (need[u]) { best = u; break; }\n            int ui = u / N, uj = u % N;\n            for (int dir = 0; dir < 4; ++dir) {\n                int vi = ui + di[dir];\n                int vj = uj + dj[dir];\n                if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n                int v = vi * N + vj;\n                if (cost[v] < 0) continue;\n                long long nd = d + cost[v];\n                if (nd < dist[v]) {\n                    dist[v] = nd;\n                    parent[v] = u;\n                    pq.emplace(nd, v);\n                }\n            }\n        }\n        if (best == -1) return false;\n        need[best] = 0;\n        --remaining;\n        if (in_tree[best]) continue;\n        vector<int> path;\n        int cur = best;\n        while (!in_tree[cur]) {\n            path.push_back(cur);\n            cur = parent[cur];\n            if (cur == -1) return false;\n        }\n        int prev = cur;\n        for (int i = (int)path.size() - 1; i >= 0; --i) {\n            int node = path[i];\n            treeAdj[node].push_back(prev);\n            treeAdj[prev].push_back(node);\n            if (!in_tree[node]) {\n                in_tree[node] = 1;\n                treeNodes.push_back(node);\n            }\n            if (need[node]) {\n                need[node] = 0;\n                --remaining;\n            }\n            prev = node;\n        }\n    }\n    return true;\n}\n\nstring buildRoute(const vector<vector<int>> &treeAdj, int start_id, int N) {\n    string route;\n    route.reserve(treeAdj.size() * 2);\n    struct Frame { int node, parent, idx; };\n    vector<Frame> st;\n    st.push_back({start_id, -1, 0});\n    while (!st.empty()) {\n        Frame &fr = st.back();\n        if (fr.idx == (int)treeAdj[fr.node].size()) {\n            st.pop_back();\n            if (fr.parent != -1) route.push_back(dir_char(fr.node, fr.parent, N));\n            continue;\n        }\n        int nxt = treeAdj[fr.node][fr.idx++];\n        if (nxt == fr.parent) continue;\n        route.push_back(dir_char(fr.node, nxt, N));\n        st.push_back({nxt, fr.node, 0});\n    }\n    return route;\n}\n\nlong long simulateRoute(const string &route, const vector<int> &cost, int N, int si, int sj) {\n    int i = si, j = sj;\n    long long total = 0;\n    for (char mv : route) {\n        if (mv == 'U') --i;\n        else if (mv == 'D') ++i;\n        else if (mv == 'L') --j;\n        else if (mv == 'R') ++j;\n        if (i < 0 || i >= N || j < 0 || j >= N) return INFLL;\n        int id = i * N + j;\n        if (cost[id] < 0) return INFLL;\n        total += cost[id];\n    }\n    if (i != si || j != sj) return INFLL;\n    return total;\n}\n\nint nearestRoadByManhattan(int ti, int tj, const vector<int> &road_cells, int N) {\n    int best = -1;\n    int bestDist = INT_MAX;\n    for (int cell : road_cells) {\n        int ci = cell / N, cj = cell % N;\n        int d = abs(ci - ti) + abs(cj - tj);\n        if (d < bestDist) {\n            bestDist = d;\n            best = cell;\n        }\n    }\n    if (best == -1 && !road_cells.empty()) best = road_cells[0];\n    return best;\n}\n\nbool try_tsp_route(const vector<int> &planTargets, int start_id, const vector<int> &cost,\n                   int N, int si, int sj, string &best_route, long long &best_cost,\n                   SPCache &cache) {\n    vector<int> nodes = planTargets;\n    nodes.push_back(start_id);\n    sort(nodes.begin(), nodes.end());\n    nodes.erase(unique(nodes.begin(), nodes.end()), nodes.end());\n    int start_pos = find(nodes.begin(), nodes.end(), start_id) - nodes.begin();\n    if (start_pos != 0) swap(nodes[0], nodes[start_pos]);\n    int T = nodes.size();\n    if (T <= 1) {\n        if (0 < best_cost) {\n            best_cost = 0;\n            best_route.clear();\n        }\n        return true;\n    }\n    if (T > TSP_TARGET_LIMIT) return false;\n    vector<vector<long long>> dist(T, vector<long long>(T, INFLL));\n    for (int i = 0; i < T; ++i) {\n        int idx = cache.get(nodes[i]);\n        const auto &d = cache.dist[idx];\n        for (int j = 0; j < T; ++j) dist[i][j] = d[nodes[j]];\n    }\n    for (int i = 0; i < T; ++i)\n        for (int j = 0; j < T; ++j)\n            if (dist[i][j] >= INFLL / 4) return false;\n    vector<int> order(T, -1);\n    vector<char> used(T, 0);\n    order[0] = 0;\n    used[0] = 1;\n    for (int pos = 1; pos < T; ++pos) {\n        int prev = order[pos - 1];\n        long long bestd = INFLL;\n        int best = -1;\n        for (int j = 1; j < T; ++j) if (!used[j]) {\n            long long d = dist[prev][j];\n            if (d < bestd) {\n                bestd = d;\n                best = j;\n            }\n        }\n        if (best == -1) return false;\n        order[pos] = best;\n        used[best] = 1;\n    }\n    bool improved = true;\n    int iter = 0;\n    while (improved && iter < 25) {\n        improved = false;\n        ++iter;\n        for (int i = 1; i < T - 1; ++i) {\n            for (int j = i + 1; j < T; ++j) {\n                int a = order[i - 1];\n                int b = order[i];\n                int c = order[j];\n                int d = order[(j + 1) % T];\n                long long delta = (dist[a][c] + dist[b][d]) - (dist[a][b] + dist[c][d]);\n                if (delta < 0) {\n                    reverse(order.begin() + i, order.begin() + j + 1);\n                    improved = true;\n                }\n            }\n        }\n    }\n    long long cycleLength = 0;\n    for (int i = 0; i < T; ++i) {\n        long long d = dist[order[i]][order[(i + 1) % T]];\n        cycleLength += d;\n       if (cycleLength >= best_cost && best_cost < INFLL / 4) return false;\n    }\n    string route;\n    route.reserve((size_t)cycleLength + 16);\n    for (int i = 0; i < T; ++i) {\n        int a = nodes[order[i]];\n        int b = nodes[order[(i + 1) % T]];\n        if (!append_shortest_path(a, b, route, cache, N)) return false;\n    }\n    long long travel = simulateRoute(route, cost, N, si, sj);\n    if (travel < best_cost) {\n        best_cost = travel;\n        best_route = route;\n        return true;\n    }\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, si, sj;\n    if (!(cin >> N >> si >> sj)) return 0;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n    int total = N * N;\n    auto idx = [&](int i, int j) { return i * N + j; };\n    vector<int> cost(total, -1);\n    vector<int> road_cells;\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            if (grid[i][j] != '#') {\n                int id = idx(i, j);\n                cost[id] = grid[i][j] - '0';\n                road_cells.push_back(id);\n            }\n    int start_id = idx(si, sj);\n\n    vector<int> row_id(total, -1);\n    vector<vector<int>> row_cells;\n    for (int i = 0; i < N; ++i) {\n        int j = 0;\n        while (j < N) {\n            if (grid[i][j] == '#') { ++j; continue; }\n            vector<int> cells;\n            while (j < N && grid[i][j] != '#') {\n                int cell = idx(i, j);\n                row_id[cell] = (int)row_cells.size();\n                cells.push_back(cell);\n                ++j;\n            }\n            row_cells.push_back(move(cells));\n        }\n    }\n    int R = (int)row_cells.size();\n\n    vector<int> col_id(total, -1);\n    vector<vector<int>> col_cells;\n    for (int j = 0; j < N; ++j) {\n        int i = 0;\n        while (i < N) {\n            if (grid[i][j] == '#') { ++i; continue; }\n            vector<int> cells;\n            while (i < N && grid[i][j] != '#') {\n                int cell = idx(i, j);\n                col_id[cell] = (int)col_cells.size();\n                cells.push_back(cell);\n                ++i;\n            }\n            col_cells.push_back(move(cells));\n        }\n    }\n    int C = (int)col_cells.size();\n\n    vector<vector<int>> row_adj(R);\n    for (int cell : road_cells) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && c >= 0) row_adj[r].push_back(c);\n    }\n    for (auto &vec : row_adj) {\n        sort(vec.begin(), vec.end());\n        vec.erase(unique(vec.begin(), vec.end()), vec.end());\n    }\n    vector<int> row_len(R), col_len(C);\n    for (int r = 0; r < R; ++r) row_len[r] = (int)row_cells[r].size();\n    for (int c = 0; c < C; ++c) col_len[c] = (int)col_cells[c].size();\n\n    vector<long long> distStart(total, INFLL);\n    vector<int> parentStart(total, -1);\n    run_dijkstra(start_id, cost, N, distStart, &parentStart);\n\n    vector<int> sorted_cells = road_cells;\n    sort(sorted_cells.begin(), sorted_cells.end(), [&](int a, int b) {\n        if (distStart[a] != distStart[b]) return distStart[a] < distStart[b];\n        return a < b;\n    });\n\n    vector<int> best_row_cell(R, -1), best_col_cell(C, -1);\n    vector<long long> best_row_dist(R, INFLL), best_col_dist(C, INFLL);\n    for (int r = 0; r < R; ++r)\n        for (int cell : row_cells[r])\n            if (distStart[cell] < best_row_dist[r]) {\n                best_row_dist[r] = distStart[cell];\n                best_row_cell[r] = cell;\n            }\n    for (int c = 0; c < C; ++c)\n        for (int cell : col_cells[c])\n            if (distStart[cell] < best_col_dist[c]) {\n                best_col_dist[c] = distStart[cell];\n                best_col_cell[c] = cell;\n            }\n\n    vector<int> anchor_cells;\n    anchor_cells.push_back(start_id);\n    vector<pair<int,int>> points = {\n        {N/2, N/2}, {0, 0}, {0, N-1}, {N-1, 0}, {N-1, N-1}\n    };\n    for (auto [pi, pj] : points) {\n        int cell = nearestRoadByManhattan(pi, pj, road_cells, N);\n        if (cell == -1) continue;\n        if (find(anchor_cells.begin(), anchor_cells.end(), cell) == anchor_cells.end())\n            anchor_cells.push_back(cell);\n    }\n    mt19937 rng(712367 + N * 131 + si * 37 + sj);\n    while ((int)anchor_cells.size() < 7 && (int)anchor_cells.size() < (int)road_cells.size()) {\n        int cell = road_cells[rng() % road_cells.size()];\n        if (find(anchor_cells.begin(), anchor_cells.end(), cell) == anchor_cells.end())\n            anchor_cells.push_back(cell);\n    }\n\n    int numAnchors = (int)anchor_cells.size();\n    vector<vector<long long>> distAnchors;\n    distAnchors.reserve(numAnchors);\n    distAnchors.push_back(distStart);\n    for (int a = 1; a < numAnchors; ++a) {\n        vector<long long> dist(total, INFLL);\n        run_dijkstra(anchor_cells[a], cost, N, dist, nullptr);\n        distAnchors.push_back(dist);\n    }\n\n    vector<vector<long long>> bestRowDistAnchor(numAnchors, vector<long long>(R, INFLL));\n    vector<vector<long long>> bestColDistAnchor(numAnchors, vector<long long>(C, INFLL));\n    for (int a = 0; a < numAnchors; ++a) {\n        const auto &dist = distAnchors[a];\n        for (int r = 0; r < R; ++r) {\n            long long best = INFLL;\n            for (int cell : row_cells[r]) best = min(best, dist[cell]);\n            bestRowDistAnchor[a][r] = best;\n        }\n        for (int c = 0; c < C; ++c) {\n            long long best = INFLL;\n            for (int cell : col_cells[c]) best = min(best, dist[cell]);\n            bestColDistAnchor[a][c] = best;\n        }\n    }\n\n    vector<long long> w_row(R), w_col(C);\n\n    auto assign_weights = [&](auto &param, const vector<vector<long long>> &bestDistByAnchor,\n                              const vector<int> &lengths, vector<long long> &weights, mt19937 &rng) {\n        uniform_int_distribution<int> noiseDist(0, max(0, param.noiseRange));\n        int S = weights.size();\n        for (int s = 0; s < S; ++s) {\n            long long w = param.base;\n            auto addDist = [&](int anchor, long long coeff) {\n                if (anchor < 0 || coeff == 0) return;\n                long long d = bestDistByAnchor[anchor][s];\n                if (d >= INFLL / 4) d = INFLL / 4;\n                w += coeff * d;\n            };\n            addDist(0, param.coeffStart);\n            addDist(param.anchor1, param.coeffAnchor1);\n            addDist(param.anchor2, param.coeffAnchor2);\n            w += param.lenFactor * (long long)lengths[s];\n            if (param.noiseRange > 0) w += noiseDist(rng);\n            if (w < 1) w = 1;\n            if (w > MAX_WEIGHT) w = MAX_WEIGHT;\n            weights[s] = w;\n        }\n    };\n\n    auto solve_weighted_cover = [&](const vector<vector<int>> &adj,\n                                    const vector<long long> &wr,\n                                    const vector<long long> &wc) -> Cover {\n        int R = wr.size(), C = wc.size();\n        Dinic din(R + C + 2);\n        int SRC = 0, SNK = R + C + 1;\n        for (int r = 0; r < R; ++r) din.add_edge(SRC, 1 + r, min(MAX_WEIGHT, wr[r]));\n        for (int r = 0; r < R; ++r)\n            for (int c : adj[r]) din.add_edge(1 + r, 1 + R + c, INF_CAP);\n        for (int c = 0; c < C; ++c) din.add_edge(1 + R + c, SNK, min(MAX_WEIGHT, wc[c]));\n        din.max_flow(SRC, SNK);\n        vector<char> vis(din.N, 0);\n        queue<int> q;\n        q.push(SRC);\n        vis[SRC] = 1;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            for (auto &e : din.G[v]) if (e.cap > 0 && !vis[e.to]) {\n                vis[e.to] = 1;\n                q.push(e.to);\n            }\n        }\n        vector<char> row_cover(R, 0), col_cover(C, 0);\n        for (int r = 0; r < R; ++r) row_cover[r] = !vis[1 + r];\n        for (int c = 0; c < C; ++c) col_cover[c] = vis[1 + R + c];\n        return {row_cover, col_cover};\n    };\n\n    auto build_plan = [&](const vector<char> &row_cover, const vector<char> &col_cover) -> Plan {\n        vector<char> row_need = row_cover;\n        vector<char> col_need = col_cover;\n        vector<char> is_target(total, 0);\n        vector<int> targets;\n        auto add_target = [&](int cell) {\n            if (cell < 0) return;\n            if (!is_target[cell]) {\n                is_target[cell] = 1;\n                targets.push_back(cell);\n            }\n        };\n        for (int cell : sorted_cells) {\n            int r = row_id[cell], c = col_id[cell];\n            if (r >= 0 && c >= 0 && row_need[r] && col_need[c]) {\n                add_target(cell);\n                row_need[r] = 0;\n                col_need[c] = 0;\n            }\n        }\n        for (int r = 0; r < R; ++r) if (row_need[r]) {\n            int cell = best_row_cell[r];\n            if (cell == -1 && !row_cells[r].empty()) cell = row_cells[r][0];\n            add_target(cell);\n            row_need[r] = 0;\n        }\n        for (int c = 0; c < C; ++c) if (col_need[c]) {\n            int cell = best_col_cell[c];\n            if (cell == -1 && !col_cells[c].empty()) cell = col_cells[c][0];\n            add_target(cell);\n            col_need[c] = 0;\n        }\n        vector<char> row_hit(R, 0), col_hit(C, 0);\n        for (int cell : targets) {\n            int r = row_id[cell], c = col_id[cell];\n            if (r >= 0) row_hit[r] = 1;\n            if (c >= 0) col_hit[c] = 1;\n        }\n        for (int r = 0; r < R; ++r) if (row_cover[r] && !row_hit[r]) {\n            int cell = best_row_cell[r];\n            if (cell == -1 && !row_cells[r].empty()) cell = row_cells[r][0];\n            add_target(cell);\n            row_hit[r] = 1;\n            int c = col_id[cell];\n            if (c >= 0) col_hit[c] = 1;\n        }\n        for (int c = 0; c < C; ++c) if (col_cover[c] && !col_hit[c]) {\n            int cell = best_col_cell[c];\n            if (cell == -1 && !col_cells[c].empty()) cell = col_cells[c][0];\n            add_target(cell);\n            col_hit[c] = 1;\n            int r = row_id[cell];\n            if (r >= 0) row_hit[r] = 1;\n        }\n        if (targets.empty()) add_target(start_id);\n        long long approx = 0;\n        for (int cell : targets) {\n            long long d = distStart[cell];\n            if (d >= INFLL / 4) d = INFLL / 4;\n            approx += d;\n        }\n        approx += 20LL * targets.size();\n        return {targets, approx};\n    };\n\n    auto base_weight_param = [&]() {\n        struct Side { long long base, coeffStart, coeffAnchor1, coeffAnchor2; int anchor1, anchor2, lenFactor, noiseRange; };\n        struct WeightParam { Side row, col; };\n        WeightParam spec;\n        spec.row = {40, 1, 0, 0, -1, -1, 0, 0};\n        spec.col = spec.row;\n        return spec;\n    };\n\n    auto uniform_weight_param = [&]() {\n        struct Side { long long base, coeffStart, coeffAnchor1, coeffAnchor2; int anchor1, anchor2, lenFactor, noiseRange; };\n        struct WeightParam { Side row, col; };\n        WeightParam spec;\n        spec.row = {1, 0, 0, 0, -1, -1, 0, 0};\n        spec.col = spec.row;\n        return spec;\n    };\n\n    struct SideParam {\n        long long base = 10;\n        long long coeffStart = 1;\n        int anchor1 = -1;\n        long long coeffAnchor1 = 0;\n        int anchor2 = -1;\n        long long coeffAnchor2 = 0;\n        long long lenFactor = 0;\n        int noiseRange = 0;\n    };\n    struct WeightParamFull {\n        SideParam row;\n        SideParam col;\n    };\n\n    auto random_side = [&](int numAnchors, mt19937 &rng) {\n        SideParam sp;\n        uniform_int_distribution<int> baseDist(15, 120);\n        uniform_int_distribution<int> coeffStartDist(0, 2);\n        uniform_int_distribution<int> lenDist(-4, 4);\n        uniform_int_distribution<int> noiseDist(0, 80);\n        sp.base = baseDist(rng);\n        sp.coeffStart = coeffStartDist(rng);\n        sp.lenFactor = lenDist(rng);\n        sp.noiseRange = noiseDist(rng);\n        if (numAnchors >= 2 && uniform_int_distribution<int>(0, 99)(rng) < 70) {\n            sp.anchor1 = uniform_int_distribution<int>(0, numAnchors - 1)(rng);\n            sp.coeffAnchor1 = uniform_int_distribution<int>(1, 3)(rng);\n        }\n        if (numAnchors >= 3 && uniform_int_distribution<int>(0, 99)(rng) < 35) {\n            do {\n                sp.anchor2 = uniform_int_distribution<int>(0, numAnchors - 1)(rng);\n            } while (sp.anchor2 == sp.anchor1);\n            sp.coeffAnchor2 = uniform_int_distribution<int>(1, 2)(rng);\n        }\n        return sp;\n    };\n\n    auto random_weight_param = [&](int numAnchors, mt19937 &rng) {\n        WeightParamFull spec;\n        spec.row = random_side(numAnchors, rng);\n        spec.col = random_side(numAnchors, rng);\n        int bias = uniform_int_distribution<int>(0, 2)(rng);\n        if (bias == 0) {\n            spec.row.base = max(5LL, spec.row.base / 2);\n            spec.col.base += 30;\n        } else if (bias == 1) {\n            spec.col.base = max(5LL, spec.col.base / 2);\n            spec.row.base += 30;\n        }\n        return spec;\n    };\n\n    vector<int> matchRow(R, -1), matchCol(C, -1);\n    vector<char> seen(C, 0);\n    function<bool(int)> dfs_match = [&](int u) -> bool {\n        for (int v : row_adj[u]) {\n            if (seen[v]) continue;\n            seen[v] = 1;\n            if (matchCol[v] == -1 || dfs_match(matchCol[v])) {\n                matchRow[u] = v;\n                matchCol[v] = u;\n                return true;\n            }\n        }\n        return false;\n    };\n    for (int u = 0; u < R; ++u) {\n        fill(seen.begin(), seen.end(), 0);\n        dfs_match(u);\n    }\n    vector<char> visRow(R, 0), visCol(C, 0);\n    queue<int> q;\n    for (int u = 0; u < R; ++u) if (matchRow[u] == -1) {\n        visRow[u] = 1;\n        q.push(u);\n    }\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        for (int v : row_adj[u]) {\n            if (matchRow[u] == v) continue;\n            if (visCol[v]) continue;\n            visCol[v] = 1;\n            int mu = matchCol[v];\n            if (mu != -1 && !visRow[mu]) {\n                visRow[mu] = 1;\n                q.push(mu);\n            }\n        }\n    }\n    vector<char> row_cover_un(R, 0), col_cover_un(C, 0);\n    for (int r = 0; r < R; ++r) row_cover_un[r] = !visRow[r];\n    for (int c = 0; c < C; ++c) col_cover_un[c] = visCol[c];\n\n    auto baseSpec = WeightParamFull{SideParam{40,1,-1,0,-1,0,0,0},\n                                    SideParam{40,1,-1,0,-1,0,0,0}};\n    auto unweightedSpec = WeightParamFull{SideParam{1,0,-1,0,-1,0,0,0},\n                                          SideParam{1,0,-1,0,-1,0,0,0}};\n\n    auto assign_from_spec = [&](const SideParam &param,\n                                const vector<vector<long long>> &bestDistByAnchor,\n                                const vector<int> &lengths,\n                                vector<long long> &weights) {\n        uniform_int_distribution<int> noiseDist(0, max(0, param.noiseRange));\n        for (int s = 0; s < (int)weights.size(); ++s) {\n            long long w = param.base;\n            auto add = [&](int anchor, long long coeff) {\n                if (anchor < 0 || coeff == 0) return;\n                long long d = bestDistByAnchor[anchor][s];\n                if (d >= INFLL / 4) d = INFLL / 4;\n                w += coeff * d;\n            };\n            add(0, param.coeffStart);\n            add(param.anchor1, param.coeffAnchor1);\n            add(param.anchor2, param.coeffAnchor2);\n            w += param.lenFactor * (long long)lengths[s];\n            if (param.noiseRange > 0) w += noiseDist(rng);\n            if (w < 1) w = 1;\n            if (w > MAX_WEIGHT) w = MAX_WEIGHT;\n            weights[s] = w;\n        }\n    };\n\n    auto randomSpec = [&](int numAnchors, mt19937 &rng) {\n        WeightParamFull spec;\n        spec.row = random_side(numAnchors, rng);\n        spec.col = random_side(numAnchors, rng);\n        int bias = uniform_int_distribution<int>(0, 2)(rng);\n        if (bias == 0) {\n            spec.row.base = max(5LL, spec.row.base / 2);\n            spec.col.base += 30;\n        } else if (bias == 1) {\n            spec.col.base = max(5LL, spec.col.base / 2);\n            spec.row.base += 30;\n        }\n        return spec;\n    };\n\n    vector<long long> wRow(R), wCol(C);\n    auto apply_spec = [&](const WeightParamFull &spec) {\n        assign_from_spec(spec.row, bestRowDistAnchor, row_len, wRow);\n        assign_from_spec(spec.col, bestColDistAnchor, col_len, wCol);\n    };\n\n    vector<CandidatePlan> planStore;\n    planStore.reserve(PLAN_KEEP + 5);\n\n    long long best_cost = INFLL;\n    string best_route;\n\n    auto evaluate_spec = [&](const WeightParamFull &spec) {\n        apply_spec(spec);\n        Cover cover = solve_weighted_cover(row_adj, wRow, wCol);\n        Plan plan = build_plan(cover.row_cover, cover.col_cover);\n        if (best_cost < INFLL / 4 && plan.approx > best_cost * 3 + 50000) return;\n        vector<vector<int>> treeAdj(total);\n        if (!buildSteinerTree(plan.targets, treeAdj, start_id, cost, N)) {\n            treeAdj.assign(total, {});\n            buildTreeSP(plan.targets, treeAdj, start_id, parentStart, total);\n        }\n        string route = buildRoute(treeAdj, start_id, N);\n        long long travel = simulateRoute(route, cost, N, si, sj);\n        if (travel >= INFLL / 2) return;\n        add_candidate_plan(plan.targets, travel, planStore);\n        if (travel < best_cost) {\n            best_cost = travel;\n            best_route = route;\n        }\n    };\n\n    auto startClock = chrono::steady_clock::now();\n    const double RANDOM_TIME_LIMIT = 2.7;\n\n    evaluate_spec(baseSpec);\n    evaluate_spec(unweightedSpec);\n\n    int randomIter = 0;\n    const int MAX_RANDOM = 40;\n    while (randomIter < MAX_RANDOM) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startClock).count();\n        if (elapsed > RANDOM_TIME_LIMIT) break;\n        WeightParamFull spec = randomSpec(numAnchors, rng);\n        evaluate_spec(spec);\n        ++randomIter;\n    }\n\n    SPCache spCache(N, cost);\n    const double TSP_LIMIT = 2.95;\n    for (int i = 0; i < (int)planStore.size() && i < TSP_PLAN_LIMIT; ++i) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startClock).count();\n        if (elapsed > TSP_LIMIT) break;\n        try_tsp_route(planStore[i].targets, start_id, cost, N, si, sj,\n                      best_route, best_cost, spCache);\n    }\n\n    if (best_route.empty()) {\n        vector<int> fallbackTargets = road_cells;\n        vector<vector<int>> treeAdj(total);\n        buildTreeSP(fallbackTargets, treeAdj, start_id, parentStart, total);\n        best_route = buildRoute(treeAdj, start_id, N);\n    }\n    cout << best_route << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Node {\n    long long priority;\n    int task;\n    bool operator<(const Node& other) const {\n        if (priority != other.priority) return priority < other.priority; // max-heap\n        return task > other.task;\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>> req(N, vector<int>(K));\n    for (int i = 0; i < N; ++i)\n        for (int k = 0; k < K; ++k) cin >> req[i][k];\n\n    vector<vector<int>> adj(N);\n    vector<int> indeg(N, 0), outdeg(N, 0);\n    for (int i = 0; i < R; ++i) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        adj[u].push_back(v);\n        indeg[v]++;\n        outdeg[u]++;\n    }\n\n    vector<int> sum_d(N, 0), max_d(N, 0);\n    long long total_diff = 0;\n    for (int i = 0; i < N; ++i) {\n        int s = 0, m = 0;\n        for (int k = 0; k < K; ++k) {\n            s += req[i][k];\n            m = max(m, req[i][k]);\n        }\n        sum_d[i] = s;\n        max_d[i] = m;\n        total_diff += s;\n    }\n\n    vector<int> level(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        int best = 0;\n        for (int v : adj[i]) best = max(best, level[v] + 1);\n        level[i] = best;\n    }\n\n    vector<int> ready_since(N, (int)1e9);\n    vector<int> task_state(N, 0); // 0: not ready, 1: ready, 2: running, 3: done\n    priority_queue<Node> pq;\n\n    auto calc_priority = [&](int task, int cur_day) -> long long {\n        long long wait = max(0, cur_day - ready_since[task]);\n        long long val = 2'000'000LL * level[task];\n        val += 15'000LL * outdeg[task];\n        val += 12'000LL * wait;\n        val += 180LL * sum_d[task];\n        val += 800LL * max_d[task];\n        val += (1000 - task);\n        return val;\n    };\n\n    auto push_task = [&](int task, int cur_day) {\n        pq.push({calc_priority(task, cur_day), task});\n    };\n\n    for (int i = 0; i < N; ++i) {\n        if (indeg[i] == 0) {\n            task_state[i] = 1;\n            ready_since[i] = 1;\n            push_task(i, 1);\n        }\n    }\n\n    vector<int> worker_task(M, -1), worker_start(M, -1);\n    double avg_diff = (double)total_diff / max(1, N);\n    double baseAbility = max(1.0, avg_diff / 8.0);\n    const double MIN_ABILITY = 0.2;\n    const double MAX_ABILITY = 400.0;\n    vector<double> worker_ability(M, baseAbility);\n    const double ability_alpha = 0.35;\n\n    vector<char> assignedFlag(N, 0);\n    vector<int> assignedList;\n\n    int day = 1;\n    while (true) {\n        vector<int> idle_workers;\n        for (int j = 0; j < M; ++j)\n            if (worker_task[j] == -1)\n                idle_workers.push_back(j);\n\n        vector<int> readyTasks;\n        if (!idle_workers.empty()) {\n            int limit = max(25, (int)idle_workers.size() * 4);\n            limit = min(limit, 200);\n            readyTasks.reserve(limit);\n            while ((int)readyTasks.size() < limit && !pq.empty()) {\n                Node cur = pq.top();\n                int task = cur.task;\n                long long real = calc_priority(task, day);\n                if (cur.priority != real) {\n                    pq.pop();\n                    if (task_state[task] == 1)\n                        pq.push({real, task});\n                    continue;\n                }\n                pq.pop();\n                if (task_state[task] != 1) continue;\n                readyTasks.push_back(task);\n            }\n        }\n\n        vector<int> task_order = readyTasks;\n        sort(task_order.begin(), task_order.end(), [&](int a, int b) {\n            if (level[a] != level[b]) return level[a] > level[b];\n            int waitA = max(0, day - ready_since[a]);\n            int waitB = max(0, day - ready_since[b]);\n            if (waitA != waitB) return waitA > waitB;\n            if (outdeg[a] != outdeg[b]) return outdeg[a] > outdeg[b];\n            if (sum_d[a] != sum_d[b]) return sum_d[a] > sum_d[b];\n            return a < b;\n        });\n\n        vector<char> workerUsed(M, 0);\n        vector<pair<int,int>> assignments;\n        assignedList.clear();\n\n        int remaining = idle_workers.size();\n        for (int task : task_order) {\n            if (remaining == 0) break;\n            double bestScore = 1e100;\n            int bestWorker = -1;\n            for (int w : idle_workers) {\n                if (workerUsed[w]) continue;\n                double ability = max(worker_ability[w], MIN_ABILITY);\n                double predicted = max(1.0, sum_d[task] / ability);\n                predicted += 0.18 * max(0, level[task] - 3);\n                predicted += 0.04 * max(0, day - ready_since[task]);\n                if (predicted + 1e-9 < bestScore ||\n                    (fabs(predicted - bestScore) <= 1e-9 &&\n                     (bestWorker == -1 || worker_ability[w] > worker_ability[bestWorker]))) {\n                    bestScore = predicted;\n                    bestWorker = w;\n                }\n            }\n            if (bestWorker != -1) {\n                worker_task[bestWorker] = task;\n                worker_start[bestWorker] = day;\n                task_state[task] = 2;\n                workerUsed[bestWorker] = 1;\n                assignments.emplace_back(bestWorker, task);\n                assignedFlag[task] = 1;\n                assignedList.push_back(task);\n                remaining--;\n            }\n        }\n\n        for (int task : readyTasks) {\n            if (!assignedFlag[task]) {\n                push_task(task, day);\n            }\n        }\n        for (int task : assignedList) assignedFlag[task] = 0;\n\n        cout << assignments.size();\n        for (auto &p : assignments) {\n            cout << ' ' << p.first + 1 << ' ' << p.second + 1;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int n_finish;\n        if (!(cin >> n_finish)) return 0;\n        if (n_finish == -1) break;\n\n        vector<int> finished_workers(n_finish);\n        for (int i = 0; i < n_finish; ++i) {\n            cin >> finished_workers[i];\n            finished_workers[i]--;\n        }\n\n        for (int w : finished_workers) {\n            if (w < 0 || w >= M) continue;\n            int task = worker_task[w];\n            if (task == -1) continue;\n            int duration = day - worker_start[w] + 1;\n            duration = max(duration, 1);\n            double difficulty = max(1, sum_d[task]);\n            double ratio = difficulty / duration;\n            worker_ability[w] = worker_ability[w] * (1.0 - ability_alpha) + ratio * ability_alpha;\n            worker_ability[w] = min(max(worker_ability[w], MIN_ABILITY), MAX_ABILITY);\n\n            worker_task[w] = -1;\n            worker_start[w] = -1;\n            task_state[task] = 3;\n\n            for (int nxt : adj[task]) {\n                if (--indeg[nxt] == 0) {\n                    task_state[nxt] = 1;\n                    ready_since[nxt] = day + 1;\n                    push_task(nxt, day + 1);\n                }\n            }\n        }\n\n        day++;\n        if (day > 2100) break; // safety\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int ORDER_COUNT = 1000;\nconst int K = 50;\nconst int OFFICE = 400;\n\nstruct Order {\n    int ax, ay, cx, cy;\n    int len;\n    int base;\n    int officeScore;\n};\n\nstruct Node {\n    int order;\n    int type; // 0: pickup, 1: drop\n};\n\nstruct Point {\n    int x, y;\n};\n\ninline int manhattan(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\ninline int manhattan(const Point& a, const Point& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nconst Point OFFICE_POINT{OFFICE, OFFICE};\n\nstruct XorShift {\n    uint64_t state;\n    XorShift(uint64_t seed = 88172645463393265ULL) {\n        if (seed == 0) seed = 88172645463393265ULL;\n        state = seed;\n    }\n    inline uint64_t nextU64() {\n        state ^= state << 7;\n        state ^= state >> 9;\n        return state;\n    }\n    inline int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nPoint nodePoint(const Node& node, const vector<Order>& orders) {\n    const Order& ord = orders[node.order];\n    if (node.type == 0) return {ord.ax, ord.ay};\n    return {ord.cx, ord.cy};\n}\n\nlong long calcCostFromCoords(const vector<Point>& coords) {\n    Point cur = OFFICE_POINT;\n    long long cost = 0;\n    for (const Point& p : coords) {\n        cost += manhattan(cur, p);\n        cur = p;\n    }\n    cost += manhattan(cur, OFFICE_POINT);\n    return cost;\n}\n\nlong long calcNodeRouteCost(const vector<Node>& nodes, const vector<Order>& orders) {\n    vector<Point> coords;\n    coords.reserve(nodes.size());\n    for (const Node& node : nodes) coords.push_back(nodePoint(node, orders));\n    return calcCostFromCoords(coords);\n}\n\nvector<int> buildInitialRoute(const vector<int>& selected, const vector<Order>& orders, XorShift& rng) {\n    vector<int> remaining = selected;\n    vector<int> route;\n    route.reserve(selected.size());\n    Point cur = OFFICE_POINT;\n    while (!remaining.empty()) {\n        int bestIdx = 0;\n        int bestDist = INT_MAX;\n        for (int i = 0; i < (int)remaining.size(); ++i) {\n            int id = remaining[i];\n            int dist = manhattan(cur.x, cur.y, orders[id].ax, orders[id].ay);\n            if (dist < bestDist ||\n                (dist == bestDist && orders[id].len < orders[remaining[bestIdx]].len) ||\n                (dist == bestDist && orders[id].len == orders[remaining[bestIdx]].len && rng.nextInt(2))) {\n                bestDist = dist;\n                bestIdx = i;\n            }\n        }\n        int chosen = remaining[bestIdx];\n        route.push_back(chosen);\n        cur = {orders[chosen].cx, orders[chosen].cy};\n        remaining[bestIdx] = remaining.back();\n        remaining.pop_back();\n    }\n    return route;\n}\n\nlong long calcOrderRouteCost(const vector<int>& sequence, const vector<Order>& orders) {\n    Point cur = OFFICE_POINT;\n    long long cost = 0;\n    for (int id : sequence) {\n        const Order& ord = orders[id];\n        Point pick{ord.ax, ord.ay};\n        Point drop{ord.cx, ord.cy};\n        cost += manhattan(cur, pick);\n        cost += manhattan(pick, drop);\n        cur = drop;\n    }\n    cost += manhattan(cur, OFFICE_POINT);\n    return cost;\n}\n\nlong long twoOptImprove(vector<int>& route, const vector<Order>& orders) {\n    int n = route.size();\n    if (n <= 1) return calcOrderRouteCost(route, orders);\n    long long bestCost = calcOrderRouteCost(route, orders);\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int i = 0; i < n - 1; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                reverse(route.begin() + i, route.begin() + j + 1);\n                long long newCost = calcOrderRouteCost(route, orders);\n                if (newCost < bestCost) {\n                    bestCost = newCost;\n                    improved = true;\n                } else {\n                    reverse(route.begin() + i, route.begin() + j + 1);\n                }\n            }\n        }\n    }\n    return bestCost;\n}\n\nvector<Node> buildNodesFromSequence(const vector<int>& sequence) {\n    vector<Node> nodes;\n    nodes.reserve(sequence.size() * 2);\n    for (int id : sequence) {\n        nodes.push_back({id, 0});\n        nodes.push_back({id, 1});\n    }\n    return nodes;\n}\n\nvoid recomputePositions(const vector<Node>& nodes,\n                        const vector<int>& selected,\n                        vector<int>& pickPos,\n                        vector<int>& dropPos) {\n    for (int id : selected) {\n        pickPos[id] = -1;\n        dropPos[id] = -1;\n    }\n    for (int i = 0; i < (int)nodes.size(); ++i) {\n        if (nodes[i].type == 0) pickPos[nodes[i].order] = i;\n        else dropPos[nodes[i].order] = i;\n    }\n}\n\ninline void removeNode(vector<Node>& nodes, vector<Point>& coords, int pos, long long& cost) {\n    int sz = coords.size();\n    Point prev = (pos == 0 ? OFFICE_POINT : coords[pos - 1]);\n    Point curr = coords[pos];\n    Point next = (pos + 1 == sz ? OFFICE_POINT : coords[pos + 1]);\n    cost += manhattan(prev, next) - manhattan(prev, curr) - manhattan(curr, next);\n    nodes.erase(nodes.begin() + pos);\n    coords.erase(coords.begin() + pos);\n}\n\ninline void insertNode(vector<Node>& nodes, vector<Point>& coords, int pos,\n                       const Node& node, const Point& point, long long& cost) {\n    Point prev = (pos == 0 ? OFFICE_POINT : coords[pos - 1]);\n    Point next = (pos == (int)coords.size() ? OFFICE_POINT : coords[pos]);\n    cost += -manhattan(prev, next) + manhattan(prev, point) + manhattan(point, next);\n    nodes.insert(nodes.begin() + pos, node);\n    coords.insert(coords.begin() + pos, point);\n}\n\nbool saMoveSingle(vector<Node>& nodes,\n                  vector<Point>& coords,\n                  vector<int>& pickPos,\n                  vector<int>& dropPos,\n                  const vector<int>& selected,\n                  long long& currCost,\n                  long long& bestCost,\n                  vector<Node>& bestNodes,\n                  vector<Point>& bestCoords,\n                  double temp,\n                  XorShift& rng) {\n    int L = nodes.size();\n    if (L <= 1) return false;\n    int origPos = rng.nextInt(L);\n    Node node = nodes[origPos];\n    Point point = coords[origPos];\n    long long prevCost = currCost;\n\n    removeNode(nodes, coords, origPos, currCost);\n    int n = nodes.size();\n    int insertPos = rng.nextInt(n + 1);\n\n    bool feasible = true;\n    if (node.type == 0) {\n        int dropIdx = dropPos[node.order];\n        if (dropIdx == -1) feasible = false;\n        else {\n            if (dropIdx > origPos) dropIdx--;\n            if (insertPos > dropIdx) feasible = false;\n        }\n    } else {\n        int pickIdx = pickPos[node.order];\n        if (pickIdx == -1) feasible = false;\n        else {\n            if (pickIdx > origPos) pickIdx--;\n            if (insertPos <= pickIdx) feasible = false;\n        }\n    }\n\n    if (!feasible) {\n        insertNode(nodes, coords, origPos, node, point, currCost);\n        currCost = prevCost;\n        return false;\n    }\n\n    insertNode(nodes, coords, insertPos, node, point, currCost);\n    long long newCost = currCost;\n    bool accept = false;\n    if (newCost <= prevCost) accept = true;\n    else {\n        double prob = exp((double)(prevCost - newCost) / temp);\n        if (prob > rng.nextDouble()) accept = true;\n    }\n    if (accept) {\n        if (newCost < bestCost) {\n            bestCost = newCost;\n            bestNodes = nodes;\n            bestCoords = coords;\n        }\n        recomputePositions(nodes, selected, pickPos, dropPos);\n    } else {\n        removeNode(nodes, coords, insertPos, currCost);\n        insertNode(nodes, coords, origPos, node, point, currCost);\n        currCost = prevCost;\n    }\n    return true;\n}\n\nbool saMovePair(vector<Node>& nodes,\n                vector<Point>& coords,\n                vector<int>& pickPos,\n                vector<int>& dropPos,\n                const vector<int>& selected,\n                long long& currCost,\n                long long& bestCost,\n                vector<Node>& bestNodes,\n                vector<Point>& bestCoords,\n                double temp,\n                XorShift& rng) {\n    if (selected.empty()) return false;\n    int orderId = selected[rng.nextInt(selected.size())];\n    int posPick = pickPos[orderId];\n    int posDrop = dropPos[orderId];\n    if (posPick == -1 || posDrop == -1) return false;\n    if (posPick > posDrop) swap(posPick, posDrop);\n\n    Node pickNode = nodes[posPick];\n    Point pickPoint = coords[posPick];\n    Node dropNode = nodes[posDrop];\n    Point dropPoint = coords[posDrop];\n    long long prevCost = currCost;\n\n    removeNode(nodes, coords, posDrop, currCost);\n    removeNode(nodes, coords, posPick, currCost);\n\n    int n = nodes.size();\n    int insertPick = rng.nextInt(n + 1);\n    insertNode(nodes, coords, insertPick, pickNode, pickPoint, currCost);\n\n    int sizeAfterPick = nodes.size();\n    int insertDrop = rng.nextInt(sizeAfterPick - insertPick) + insertPick + 1;\n    insertNode(nodes, coords, insertDrop, dropNode, dropPoint, currCost);\n\n    long long newCost = currCost;\n    bool accept = false;\n    if (newCost <= prevCost) accept = true;\n    else {\n        double prob = exp((double)(prevCost - newCost) / temp);\n        if (prob > rng.nextDouble()) accept = true;\n    }\n    if (accept) {\n        if (newCost < bestCost) {\n            bestCost = newCost;\n            bestNodes = nodes;\n            bestCoords = coords;\n        }\n        recomputePositions(nodes, selected, pickPos, dropPos);\n    } else {\n        removeNode(nodes, coords, insertDrop, currCost);\n        removeNode(nodes, coords, insertPick, currCost);\n        insertNode(nodes, coords, posPick, pickNode, pickPoint, currCost);\n        insertNode(nodes, coords, posDrop, dropNode, dropPoint, currCost);\n        currCost = prevCost;\n    }\n    return true;\n}\n\nlong long runNodeSA(vector<Node>& nodes,\n                    const vector<int>& selected,\n                    const vector<Order>& orders,\n                    double timeLimit,\n                    XorShift& rng,\n                    chrono::steady_clock::time_point globalStart,\n                    double globalLimit) {\n    vector<Point> coords(nodes.size());\n    for (int i = 0; i < (int)nodes.size(); ++i) coords[i] = nodePoint(nodes[i], orders);\n    long long currCost = calcCostFromCoords(coords);\n    long long bestCost = currCost;\n    vector<Node> bestNodes = nodes;\n    vector<Point> bestCoords = coords;\n\n    vector<int> pickPos(ORDER_COUNT, -1), dropPos(ORDER_COUNT, -1);\n    recomputePositions(nodes, selected, pickPos, dropPos);\n\n    if (timeLimit <= 1e-6) {\n        nodes = bestNodes;\n        return bestCost;\n    }\n\n    const double START_TEMP = 2000.0;\n    const double END_TEMP = 5.0;\n    const double LOG_RATIO = std::log(END_TEMP / START_TEMP);\n    auto localStart = chrono::steady_clock::now();\n    double temp = START_TEMP;\n    long long iter = 0;\n    while (true) {\n        if ((iter & 0x3FFLL) == 0) {\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - localStart).count();\n            double globalElapsed = chrono::duration<double>(now - globalStart).count();\n            if (elapsed > timeLimit || globalElapsed > globalLimit) break;\n            double progress = min(1.0, elapsed / timeLimit);\n            temp = START_TEMP * exp(LOG_RATIO * progress);\n        }\n        ++iter;\n        int op = rng.nextInt(100);\n        if (op < 70) {\n            saMoveSingle(nodes, coords, pickPos, dropPos, selected,\n                         currCost, bestCost, bestNodes, bestCoords, temp, rng);\n        } else {\n            saMovePair(nodes, coords, pickPos, dropPos, selected,\n                       currCost, bestCost, bestNodes, bestCoords, temp, rng);\n        }\n    }\n    nodes = bestNodes;\n    return bestCost;\n}\n\nvector<pair<int, int>> buildPathFromNodes(const vector<Node>& nodes, const vector<Order>& orders) {\n    vector<pair<int, int>> path;\n    path.reserve(nodes.size() + 2);\n    path.emplace_back(OFFICE_POINT.x, OFFICE_POINT.y);\n    for (const Node& node : nodes) {\n        Point p = nodePoint(node, orders);\n        path.emplace_back(p.x, p.y);\n    }\n    path.emplace_back(OFFICE_POINT.x, OFFICE_POINT.y);\n    return path;\n}\n\nstruct RouteSolution {\n    vector<int> selectedOrders;\n    vector<Node> nodes;\n    long long cost = (1LL << 60);\n};\n\nvector<int> extractSelectedOrders(const vector<Node>& nodes) {\n    vector<int> res;\n    vector<char> seen(ORDER_COUNT, 0);\n    for (const Node& node : nodes) {\n        if (node.type == 0 && !seen[node.order]) {\n            seen[node.order] = 1;\n            res.push_back(node.order);\n        }\n    }\n    return res;\n}\n\nRouteSolution optimizeSet(const vector<int>& selected,\n                          double saTime,\n                          const vector<Order>& orders,\n                          XorShift& rng,\n                          chrono::steady_clock::time_point globalStart,\n                          double globalLimit) {\n    RouteSolution sol;\n    sol.selectedOrders = selected;\n    vector<int> route = buildInitialRoute(selected, orders, rng);\n    twoOptImprove(route, orders);\n    vector<Node> nodes = buildNodesFromSequence(route);\n    long long cost = runNodeSA(nodes, selected, orders, saTime, rng, globalStart, globalLimit);\n    sol.cost = cost;\n    sol.nodes = nodes;\n    return sol;\n}\n\nstruct PosDelta {\n    int pos;\n    int delta;\n};\n\nvector<PosDelta> enumerateInsertOptions(const vector<Point>& coords,\n                                        const Point& insertPoint,\n                                        int startPos,\n                                        int limit,\n                                        int randomExtra,\n                                        XorShift& rng) {\n    int M = coords.size();\n    startPos = max(0, min(startPos, M));\n    vector<PosDelta> opts;\n    opts.reserve(M - startPos + 1);\n    for (int pos = startPos; pos <= M; ++pos) {\n        const Point& prev = (pos == 0 ? OFFICE_POINT : coords[pos - 1]);\n        const Point& next = (pos == M ? OFFICE_POINT : coords[pos]);\n        int delta = manhattan(prev, insertPoint) + manhattan(insertPoint, next) - manhattan(prev, next);\n        opts.push_back({pos, delta});\n    }\n    sort(opts.begin(), opts.end(), [](const PosDelta& a, const PosDelta& b) {\n        if (a.delta != b.delta) return a.delta < b.delta;\n        return a.pos < b.pos;\n    });\n    vector<PosDelta> res;\n    int take = min(limit, (int)opts.size());\n    for (int i = 0; i < take; ++i) res.push_back(opts[i]);\n    int attempts = randomExtra;\n    while (attempts-- > 0 && (int)res.size() < (int)opts.size()) {\n        int idx = rng.nextInt(opts.size());\n        int pos = opts[idx].pos;\n        bool exist = false;\n        for (const auto& pd : res) if (pd.pos == pos) { exist = true; break; }\n        if (!exist) res.push_back(opts[idx]);\n    }\n    return res;\n}\n\ntemplate <class T>\nvoid shuffleWithRNG(vector<T>& vec, XorShift& rng) {\n    for (int i = (int)vec.size() - 1; i > 0; --i) {\n        int j = rng.nextInt(i + 1);\n        swap(vec[i], vec[j]);\n    }\n}\n\nvoid swapImprove(RouteSolution& sol,\n                 const vector<Order>& orders,\n                 const vector<int>& ranking,\n                 double timeLimit,\n                 chrono::steady_clock::time_point globalStart,\n                 double globalLimit,\n                 XorShift& rng) {\n    if (timeLimit <= 1e-4) return;\n    auto localStart = chrono::steady_clock::now();\n    vector<Node>& bestNodes = sol.nodes;\n    long long bestCost = sol.cost;\n\n    vector<int> selectedOrders = extractSelectedOrders(bestNodes);\n    vector<char> inSelected(ORDER_COUNT, 0);\n    for (int id : selectedOrders) inSelected[id] = 1;\n\n    const int CAND_LIMIT = 100;\n    const int PICK_LIMIT = 10;\n    const int DROP_LIMIT = 12;\n    const int RANDOM_PICK = 3;\n    const int RANDOM_DROP = 3;\n\n    auto timeExceeded = [&]() -> bool {\n        auto now = chrono::steady_clock::now();\n        double localElapsed = chrono::duration<double>(now - localStart).count();\n        double globalElapsed = chrono::duration<double>(now - globalStart).count();\n        return (localElapsed > timeLimit) || (globalElapsed > globalLimit);\n    };\n\n    bool timeup = false;\n    while (!timeup) {\n        if (timeExceeded()) break;\n        vector<int> candidatePool;\n        candidatePool.reserve(CAND_LIMIT);\n        for (int idx : ranking) {\n            if (!inSelected[idx]) {\n                candidatePool.push_back(idx);\n                if ((int)candidatePool.size() >= CAND_LIMIT) break;\n            }\n        }\n        if (candidatePool.empty()) break;\n        shuffleWithRNG(candidatePool, rng);\n        vector<int> removalOrder = selectedOrders;\n        shuffleWithRNG(removalOrder, rng);\n\n        bool improvement = false;\n\n        for (int removeId : removalOrder) {\n            if (timeExceeded()) { timeup = true; break; }\n\n            vector<Node> baseNodes;\n            baseNodes.reserve(bestNodes.size() - 2);\n            for (const Node& node : bestNodes) {\n                if (node.order == removeId) continue;\n                baseNodes.push_back(node);\n            }\n            if ((int)baseNodes.size() != (int)bestNodes.size() - 2) continue;\n\n            long long baseCost = calcNodeRouteCost(baseNodes, orders);\n\n            vector<Point> baseCoords;\n            baseCoords.reserve(baseNodes.size());\n            for (const Node& node : baseNodes) {\n                baseCoords.push_back(nodePoint(node, orders));\n            }\n\n            for (int candId : candidatePool) {\n                if (inSelected[candId]) continue;\n                if (timeExceeded()) { timeup = true; break; }\n\n                Point pickPoint{orders[candId].ax, orders[candId].ay};\n                auto pickOptions = enumerateInsertOptions(baseCoords, pickPoint, 0, PICK_LIMIT, RANDOM_PICK, rng);\n                if (pickOptions.empty()) continue;\n\n                for (const auto& pickOpt : pickOptions) {\n                    if (timeExceeded()) { timeup = true; break; }\n\n                    int pickPos = pickOpt.pos;\n                    int deltaPick = pickOpt.delta;\n\n                    vector<Point> coordsWithPick = baseCoords;\n                    coordsWithPick.insert(coordsWithPick.begin() + pickPos, pickPoint);\n\n                    Point dropPoint{orders[candId].cx, orders[candId].cy};\n                    auto dropOptions = enumerateInsertOptions(coordsWithPick, dropPoint, pickPos + 1, DROP_LIMIT, RANDOM_DROP, rng);\n                    if (dropOptions.empty()) continue;\n\n                    if ((long long)baseCost + deltaPick + dropOptions[0].delta >= bestCost) continue;\n\n                    for (const auto& dropOpt : dropOptions) {\n                        long long candidateCost = (long long)baseCost + deltaPick + dropOpt.delta;\n                        if (candidateCost >= bestCost) continue;\n\n                        vector<Node> improved = baseNodes;\n                        improved.insert(improved.begin() + pickPos, Node{candId, 0});\n                        improved.insert(improved.begin() + dropOpt.pos, Node{candId, 1});\n\n                        bestNodes = move(improved);\n                        bestCost = candidateCost;\n                        inSelected[removeId] = 0;\n                        inSelected[candId] = 1;\n                        for (int& x : selectedOrders) if (x == removeId) { x = candId; break; }\n                        improvement = true;\n                        break;\n                    }\n                    if (timeExceeded()) { timeup = true; break; }\n                    if (improvement) break;\n                }\n                if (timeExceeded()) { timeup = true; break; }\n                if (improvement) break;\n            }\n            if (timeExceeded()) { timeup = true; break; }\n            if (improvement) break;\n        }\n        if (timeExceeded()) break;\n        if (!improvement) break;\n    }\n\n    sol.nodes = bestNodes;\n    sol.cost = calcNodeRouteCost(sol.nodes, orders);\n    sol.selectedOrders = extractSelectedOrders(sol.nodes);\n}\n\nvector<pair<int, int>> pathFromNodes(const vector<Node>& nodes, const vector<Order>& orders) {\n    return buildPathFromNodes(nodes, orders);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<Order> orders(ORDER_COUNT);\n    for (int i = 0; i < ORDER_COUNT; ++i) {\n        cin >> orders[i].ax >> orders[i].ay >> orders[i].cx >> orders[i].cy;\n        orders[i].len = manhattan(orders[i].ax, orders[i].ay, orders[i].cx, orders[i].cy);\n        orders[i].base = manhattan(OFFICE, OFFICE, orders[i].ax, orders[i].ay) +\n                         orders[i].len +\n                         manhattan(orders[i].cx, orders[i].cy, OFFICE, OFFICE);\n        orders[i].officeScore = manhattan(OFFICE, OFFICE, orders[i].ax, orders[i].ay) +\n                                manhattan(OFFICE, OFFICE, orders[i].cx, orders[i].cy);\n    }\n\n    vector<int> idx(ORDER_COUNT);\n    iota(idx.begin(), idx.end(), 0);\n\n    vector<int> byBase = idx;\n    sort(byBase.begin(), byBase.end(), [&](int a, int b) {\n        if (orders[a].base != orders[b].base) return orders[a].base < orders[b].base;\n        return a < b;\n    });\n    vector<int> byOffice = idx;\n    sort(byOffice.begin(), byOffice.end(), [&](int a, int b) {\n        if (orders[a].officeScore != orders[b].officeScore) return orders[a].officeScore < orders[b].officeScore;\n        return a < b;\n    });\n    vector<int> byLen = idx;\n    sort(byLen.begin(), byLen.end(), [&](int a, int b) {\n        if (orders[a].len != orders[b].len) return orders[a].len < orders[b].len;\n        return a < b;\n    });\n\n    auto firstK = [&](const vector<int>& arr) {\n        vector<int> res;\n        for (int i = 0; i < K; ++i) res.push_back(arr[i]);\n        return res;\n    };\n\n    XorShift rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    vector<vector<int>> candidateSets;\n    candidateSets.push_back(firstK(byBase));\n    candidateSets.push_back(firstK(byOffice));\n    candidateSets.push_back(firstK(byLen));\n\n    auto makeRandomSet = [&](const vector<int>& pool, int noiseRange) -> vector<int> {\n        vector<pair<long long, int>> tmp;\n        tmp.reserve(pool.size());\n        for (int id : pool) {\n            long long noise = (long long)(rng.nextU64() % (noiseRange + 1));\n            long long score = (long long)orders[id].base + noise;\n            tmp.emplace_back(score, id);\n        }\n        sort(tmp.begin(), tmp.end());\n        vector<int> res;\n        for (int i = 0; i < K && i < (int)tmp.size(); ++i) res.push_back(tmp[i].second);\n        return res;\n    };\n\n    vector<int> poolTop;\n    int poolTopSize = min(300, ORDER_COUNT);\n    for (int i = 0; i < poolTopSize; ++i) poolTop.push_back(byBase[i]);\n    if (!poolTop.empty()) candidateSets.push_back(makeRandomSet(poolTop, 4000));\n    candidateSets.push_back(makeRandomSet(idx, 8000));\n\n    auto globalStart = chrono::steady_clock::now();\n    const double GLOBAL_LIMIT = 1.95;\n    const double STAGE1_LIMIT = 1.35;\n\n    int maxSets = min(5, (int)candidateSets.size());\n    RouteSolution bestSolution;\n    for (int setIdx = 0; setIdx < maxSets; ++setIdx) {\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - globalStart).count();\n        if (elapsed >= STAGE1_LIMIT || elapsed >= GLOBAL_LIMIT - 0.4) break;\n        double remainingStage = STAGE1_LIMIT - elapsed;\n        double globalRemaining = GLOBAL_LIMIT - elapsed;\n        if (remainingStage <= 0.05 || globalRemaining <= 0.4) break;\n        int setsLeft = maxSets - setIdx;\n        double saTime = min(0.35, remainingStage / setsLeft);\n        saTime = max(saTime, 0.02);\n        RouteSolution sol = optimizeSet(candidateSets[setIdx], saTime, orders, rng, globalStart, GLOBAL_LIMIT);\n        if (sol.cost < bestSolution.cost) bestSolution = sol;\n    }\n    if (bestSolution.cost == (1LL << 60)) {\n        bestSolution = optimizeSet(candidateSets[0], 0.2, orders, rng, globalStart, GLOBAL_LIMIT);\n    }\n\n    auto ensureSelectedOrders = [&]() {\n        bestSolution.selectedOrders = extractSelectedOrders(bestSolution.nodes);\n    };\n    ensureSelectedOrders();\n    bestSolution.cost = calcNodeRouteCost(bestSolution.nodes, orders);\n\n    auto now = chrono::steady_clock::now();\n    double elapsed = chrono::duration<double>(now - globalStart).count();\n    double remaining = GLOBAL_LIMIT - elapsed;\n\n    if (remaining > 0.1) {\n        double swapTime = min(0.45, remaining - 0.05);\n        swapImprove(bestSolution, orders, byBase, swapTime, globalStart, GLOBAL_LIMIT, rng);\n        ensureSelectedOrders();\n    }\n\n    now = chrono::steady_clock::now();\n    elapsed = chrono::duration<double>(now - globalStart).count();\n    remaining = GLOBAL_LIMIT - elapsed;\n    if (remaining > 0.08) {\n        double finalTime = min(0.2, remaining - 0.03);\n        if (finalTime > 0.0) {\n            vector<int> selected = extractSelectedOrders(bestSolution.nodes);\n            long long newCost = runNodeSA(bestSolution.nodes, selected, orders, finalTime, rng, globalStart, GLOBAL_LIMIT);\n            bestSolution.cost = newCost;\n            ensureSelectedOrders();\n        }\n    }\n\n    vector<int> orderOutput = extractSelectedOrders(bestSolution.nodes);\n    orderOutput.resize(K);\n\n    vector<pair<int, int>> path = buildPathFromNodes(bestSolution.nodes, orders);\n\n    cout << K;\n    for (int id : orderOutput) cout << ' ' << (id + 1);\n    cout << '\\n';\n    cout << path.size();\n    for (auto [x, y] : path) cout << ' ' << x << ' ' << y;\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 400;\nconstexpr int M = 1995;\nconstexpr int LIGHT_LIMIT = 135;\n\nstruct Edge {\n    int u, v;\n    int d;\n    bool in_ref = false;\n};\n\nstruct DSU {\n    vector<int> parent;\n    vector<int> sz;\n    int comp;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        parent.resize(n);\n        sz.assign(n, 1);\n        iota(parent.begin(), parent.end(), 0);\n        comp = n;\n    }\n    int find(int x) {\n        if (parent[x] == x) return x;\n        return parent[x] = find(parent[x]);\n    }\n    int root_size(int r) const { return sz[r]; }\n    int merge_roots(int a, int b, int &loser) {\n        a = find(a);\n        b = find(b);\n        if (a == b) {\n            loser = -1;\n            return a;\n        }\n        if (sz[a] < sz[b]) swap(a, b);\n        parent[b] = a;\n        sz[a] += sz[b];\n        sz[b] = 0;\n        comp--;\n        loser = b;\n        return a;\n    }\n};\n\nstruct CompStats {\n    int best_d;\n    int second_d;\n    int light_cnt;\n    int total;\n};\n\nint rounded_distance(const pair<int,int>& A, const pair<int,int>& B) {\n    long long dx = (long long)A.first - B.first;\n    long long dy = (long long)A.second - B.second;\n    double dist = std::sqrt((double)dx * dx + (double)dy * dy);\n    return (int)std::llround(dist);\n}\n\nvoid remove_future_edge(int ru, int rv,\n                        vector<vector<int>>& adj, vector<int>& out_deg) {\n    if (ru == rv) return;\n    if (adj[ru][rv] > 0) {\n        --adj[ru][rv];\n        --adj[rv][ru];\n    } else {\n        adj[ru][rv] = adj[rv][ru] = 0;\n    }\n    if (out_deg[ru] > 0) --out_deg[ru];\n    if (out_deg[rv] > 0) --out_deg[rv];\n}\n\nvoid merge_adj(int keep, int lose,\n               vector<vector<int>>& adj, vector<int>& out_deg) {\n    if (lose < 0 || keep == lose) return;\n    int between = adj[keep][lose];\n    adj[keep][lose] = adj[lose][keep] = 0;\n    out_deg[keep] = max(0, out_deg[keep] + out_deg[lose] - 2 * between);\n    out_deg[lose] = 0;\n    for (int c = 0; c < N; ++c) {\n        if (c == keep || c == lose) continue;\n        int add = adj[lose][c];\n        if (!add) continue;\n        adj[keep][c] += add;\n        adj[c][keep] = adj[keep][c];\n        adj[lose][c] = adj[c][lose] = 0;\n    }\n    adj[keep][keep] = 0;\n}\n\nvoid merge_edge_lists(int keep, int lose, vector<vector<int>>& comp_edges) {\n    if (lose < 0 || keep == lose) return;\n    if (comp_edges[keep].size() < comp_edges[lose].size())\n        comp_edges[keep].swap(comp_edges[lose]);\n    comp_edges[keep].insert(comp_edges[keep].end(),\n                            comp_edges[lose].begin(),\n                            comp_edges[lose].end());\n    vector<int>().swap(comp_edges[lose]);\n}\n\nCompStats get_comp_stats(int root, DSU &dsu,\n                         const vector<Edge>& edges,\n                         const vector<char>& processed,\n                         const vector<vector<int>>& comp_edges,\n                         int target = -1,\n                         int* best_cross = nullptr,\n                         int* cross_light = nullptr) {\n    const int INF_D = 1e9;\n    if (best_cross) *best_cross = INF_D;\n    if (cross_light) *cross_light = 0;\n\n    int best = INF_D;\n    int second = INF_D;\n    int lights = 0;\n    int total = 0;\n\n    for (int idx : comp_edges[root]) {\n        if (processed[idx]) continue;\n        const Edge &e = edges[idx];\n        int a = dsu.find(e.u);\n        int b = dsu.find(e.v);\n        if (a == b) continue;\n        if (a != root && b != root) continue;\n\n        ++total;\n        int d = e.d;\n        if (d < best) {\n            second = best;\n            best = d;\n        } else if (d < second) {\n            second = d;\n        }\n        if (d <= LIGHT_LIMIT) ++lights;\n\n        if (target != -1 && best_cross) {\n            int other = (a == root) ? b : a;\n            if (other == target) {\n                if (d < *best_cross) *best_cross = d;\n                if (cross_light && d <= LIGHT_LIMIT) ++(*cross_light);\n            }\n        }\n    }\n    if (best == INF_D) second = INF_D;\n    return {best, second, lights, total};\n}\n\ndouble compute_threshold(double progress, double comp_frac,\n                         const Edge& edge, double len,\n                         int sizeA, int sizeB,\n                         int outA, int outB,\n                         const CompStats& statsA,\n                         const CompStats& statsB,\n                         int best_cross, int cross_light,\n                         int direct_remaining) {\n    using std::clamp;\n    using std::pow;\n\n    constexpr double BASE_START = 1.02;\n    constexpr double BASE_END = 2.05;\n    constexpr double BASE_POWER = 0.80;\n    constexpr double COMP_COEFF = 0.34;\n    constexpr double COMP_POWER = 0.84;\n    constexpr double LAG_COEFF = 0.46;\n    constexpr double LEAD_COEFF = 0.12;\n    constexpr double SIZE_COEFF = 0.28;\n    constexpr double SIZE_POWER = 0.62;\n    constexpr double SMALLD_LIMIT = 150.0;\n    constexpr double SMALLD_COEFF = 0.30;\n    constexpr double LARGE_LIMIT = 260.0;\n    constexpr double LARGE_SPAN = 360.0;\n    constexpr double LARGE_COEFF = 0.11;\n    constexpr double REF_BONUS = 0.22;\n    constexpr double DENSITY_TARGET = 1.8;\n    constexpr double DENSITY_COEFF = 0.42;\n    constexpr double OUT_TARGET = 8.0;\n    constexpr double OUT_COEFF = 0.31;\n    constexpr double LEN_REFERENCE = 200.0;\n    constexpr double LEN_COEFF = 0.15;\n    constexpr double SCARCITY_COEFF = 0.17;\n    constexpr double LIGHT_NONE_BONUS = 0.18;\n    constexpr double LIGHT_FEW_BONUS = 0.09;\n    constexpr double LIGHT_MANY_PENALTY = 0.06;\n    constexpr double FUTURE_COEFF = 0.35;\n    constexpr double NO_FUTURE_BONUS = 0.33;\n    constexpr double GAP_COEFF = 0.13;\n    constexpr double GAP_WINDOW = 60.0;\n    constexpr double DIRECT_BONUS = 0.18;\n    constexpr double DIRECT_PENALTY = 0.03;\n    constexpr double CROSS_NONE_BONUS = 0.28;\n    constexpr double CROSS_ADV_COEFF = 0.33;\n    constexpr double CROSS_SUP_COEFF = 0.11;\n    constexpr double CROSS_LIGHT_COEFF = 0.05;\n    constexpr double MIN_THRESHOLD = 0.92;\n    constexpr double MAX_THRESHOLD = 2.65;\n    constexpr int INF_D = 1e9;\n\n    progress = clamp(progress, 0.0, 1.0);\n    comp_frac = clamp(comp_frac, 0.0, 1.0);\n\n    double base = BASE_START + (BASE_END - BASE_START) * pow(progress, BASE_POWER);\n    base += COMP_COEFF * pow(comp_frac, COMP_POWER);\n    double lag = clamp(progress - comp_frac, 0.0, 1.0);\n    double lead = clamp(comp_frac - progress, 0.0, 1.0);\n    base += LAG_COEFF * lag;\n    base -= LEAD_COEFF * lead;\n\n    double thr = base;\n    double size_frac = double(sizeA + sizeB) / double(N);\n    thr += SIZE_COEFF * pow(size_frac, SIZE_POWER);\n\n    double small_factor = clamp((SMALLD_LIMIT - double(edge.d)) / SMALLD_LIMIT, -1.0, 1.0);\n    thr += SMALLD_COEFF * small_factor;\n    double large_factor = clamp((double(edge.d) - LARGE_LIMIT) / LARGE_SPAN, 0.0, 1.0);\n    thr -= LARGE_COEFF * large_factor;\n\n    if (edge.in_ref) thr += REF_BONUS;\n\n    double densityA = sizeA > 0 ? double(outA) / double(sizeA) : 0.0;\n    double densityB = sizeB > 0 ? double(outB) / double(sizeB) : 0.0;\n    double density = min(densityA, densityB);\n    double density_need = clamp((DENSITY_TARGET - density) / DENSITY_TARGET, 0.0, 1.5);\n    thr += DENSITY_COEFF * density_need;\n\n    int min_out = min(outA, outB);\n    double scarcity = clamp((OUT_TARGET - double(min_out)) / OUT_TARGET, 0.0, 1.5);\n    thr += OUT_COEFF * scarcity;\n\n    double len_effect = clamp((LEN_REFERENCE - len) / LEN_REFERENCE, -1.0, 1.0);\n    thr += LEN_COEFF * len_effect;\n\n    if (statsA.total <= 2) thr += SCARCITY_COEFF;\n    if (statsB.total <= 2) thr += SCARCITY_COEFF;\n\n    int light_total = statsA.light_cnt + statsB.light_cnt;\n    if (light_total == 0) thr += LIGHT_NONE_BONUS;\n    else if (light_total <= 2) thr += LIGHT_FEW_BONUS;\n    else if (light_total >= 7) thr -= LIGHT_MANY_PENALTY;\n\n    int best_future = min(statsA.best_d, statsB.best_d);\n    if (best_future >= INF_D / 2) {\n        thr += NO_FUTURE_BONUS;\n    } else {\n        double future_rel = (double(best_future) - double(edge.d)) /\n                            max(60.0, double(edge.d));\n        thr += FUTURE_COEFF * future_rel;\n    }\n\n    auto gap_value = [&](const CompStats& st) -> double {\n        if (st.second_d >= INF_D / 2 || st.best_d >= INF_D / 2) return GAP_WINDOW;\n        return double(st.second_d - st.best_d);\n    };\n    double gap = min(gap_value(statsA), gap_value(statsB));\n    if (gap < GAP_WINDOW) {\n        double gap_term = clamp((GAP_WINDOW - gap) / GAP_WINDOW, 0.0, 1.0);\n        thr -= GAP_COEFF * gap_term;  // wait more when several similar edges exist\n    }\n\n    if (best_cross >= INF_D / 2) {\n        thr += CROSS_NONE_BONUS;\n    } else {\n        double diff = double(edge.d) - double(best_cross);\n        if (diff > 0) {\n            double norm = clamp(diff / max(40.0, double(edge.d)), 0.0, 1.5);\n            thr -= CROSS_ADV_COEFF * norm;\n            if (cross_light > 0) {\n                thr -= CROSS_LIGHT_COEFF * min(3, cross_light);\n            }\n        } else if (diff < 0) {\n            double norm = clamp((-diff) / max(40.0, double(edge.d)), 0.0, 1.0);\n            thr += CROSS_SUP_COEFF * norm;\n        }\n    }\n\n    if (direct_remaining == 0) {\n        thr += DIRECT_BONUS * (0.6 + 0.4 * size_frac);\n    } else {\n        thr -= DIRECT_PENALTY * min(direct_remaining, 4);\n    }\n\n    return clamp(thr, MIN_THRESHOLD, MAX_THRESHOLD);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<pair<int,int>> pos(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> pos[i].first >> pos[i].second;\n    }\n\n    vector<Edge> edges(M);\n    vector<vector<int>> adj(N, vector<int>(N, 0));\n    vector<int> out_deg(N, 0);\n    vector<vector<int>> comp_edges(N);\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        edges[i].d = rounded_distance(pos[u], pos[v]);\n        adj[u][v] += 1;\n        adj[v][u] += 1;\n        out_deg[u] += 1;\n        out_deg[v] += 1;\n        comp_edges[u].push_back(i);\n        comp_edges[v].push_back(i);\n    }\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n    DSU mst_dsu(N);\n    int need = N - 1;\n    for (int idx : order) {\n        int loser;\n        mst_dsu.merge_roots(edges[idx].u, edges[idx].v, loser);\n        if (loser != -1) {\n            edges[idx].in_ref = true;\n            if (--need == 0) break;\n        }\n    }\n\n    DSU dsu(N);\n    vector<char> processed(M, false);\n    std::mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n    std::uniform_real_distribution<double> noise_dist(-0.012, 0.012);\n\n    for (int i = 0; i < M; ++i) {\n        int len;\n        if (!(cin >> len)) return 0;\n        Edge &edge = edges[i];\n        int ru = dsu.find(edge.u);\n        int rv = dsu.find(edge.v);\n        processed[i] = true;\n\n        if (ru == rv) {\n            cout << 0 << '\\n' << flush;\n            continue;\n        }\n\n        remove_future_edge(ru, rv, adj, out_deg);\n        int direct_after = adj[ru][rv];\n\n        bool accept = false;\n        if (out_deg[ru] == 0 || out_deg[rv] == 0) {\n            accept = true;\n        }\n\n        CompStats statsA{}, statsB{};\n        int best_cross = 1e9;\n        int cross_light = 0;\n\n        if (!accept) {\n            statsA = get_comp_stats(ru, dsu, edges, processed, comp_edges,\n                                    rv, &best_cross, &cross_light);\n            statsB = get_comp_stats(rv, dsu, edges, processed, comp_edges);\n\n            int sizeA = dsu.root_size(ru);\n            int sizeB = dsu.root_size(rv);\n            int outA = out_deg[ru];\n            int outB = out_deg[rv];\n            double progress = double(i) / double(M);\n            double comp_frac = double(N - dsu.comp) / double(N - 1);\n\n            double threshold = compute_threshold(progress, comp_frac, edge, double(len),\n                                                 sizeA, sizeB, outA, outB,\n                                                 statsA, statsB,\n                                                 best_cross, cross_light,\n                                                 direct_after);\n            threshold += noise_dist(rng);\n            threshold = std::clamp(threshold, 0.90, 2.70);\n\n            double ratio = double(len) / double(max(edge.d, 1));\n            if (ratio <= threshold) accept = true;\n\n            if (!accept) {\n                int future_edges = M - i - 1;\n                int need_edges = dsu.comp - 1;\n                if (future_edges <= need_edges) accept = true;\n            }\n        }\n\n        if (accept) {\n            cout << 1 << '\\n' << flush;\n            int loser;\n            int keep = dsu.merge_roots(ru, rv, loser);\n            merge_adj(keep, loser, adj, out_deg);\n            merge_edge_lists(keep, loser, comp_edges);\n        } else {\n            cout << 0 << '\\n' << flush;\n        }\n    }\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int x, y;\n};\n\nstruct BlockCell {\n    int x, y;\n    char action;\n};\n\nstruct Candidate {\n    Point pos;\n    vector<BlockCell> blocks;\n    vector<Point> escape_nodes; // includes home at index 0\n    int final_block_index;\n};\n\nconst int H = 30;\nconst int W = 30;\nconst int DX[4] = {-1, 1, 0, 0};\nconst int DY[4] = {0, 0, -1, 1};\nconst char MOVE_CH[4] = {'U', 'D', 'L', 'R'};\n\nconst int DIST_WEIGHT = 10;\nconst int PET_RADIUS = 6;\nconst int PET_WEIGHT = 50;\nconst int REASSIGN_WAIT = 25;\nconst int REASSIGN_BUFFER = 6;\nconst int MIN_REMAINING_FOR_REASSIGN = 50;\nconst int MAX_REASSIGN = 3;\nconst int PET_ON_ME_WAIT = 12;\nconst int MOVE_STUCK_WAIT = 12;\nconst int CAND_COOLDOWN = 18;\n\nconst int LURE_TRIGGER = 8;\nconst int LURE_COOLDOWN = 15;\nconst int ESCAPE_WAIT_TURNS = 6;\nconst int PET_ON_ME_ESCAPE = 6;\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < H && 0 <= y && y < W;\n}\n\nint dir_from_char(char c) {\n    if (c == 'U' || c == 'u') return 0;\n    if (c == 'D' || c == 'd') return 1;\n    if (c == 'L' || c == 'l') return 2;\n    if (c == 'R' || c == 'r') return 3;\n    return -1;\n}\n\nchar step_char(const Point& from, const Point& to) {\n    if (from.x + 1 == to.x && from.y == to.y) return 'D';\n    if (from.x - 1 == to.x && from.y == to.y) return 'U';\n    if (from.x == to.x && from.y + 1 == to.y) return 'R';\n    if (from.x == to.x && from.y - 1 == to.y) return 'L';\n    return '.';\n}\n\nint bfs_next_dir(const vector<vector<int>>& impassable, const Point& start, const Point& goal) {\n    if (start.x == goal.x && start.y == goal.y) return -1;\n    array<array<int, W>, H> dist;\n    for (int i = 0; i < H; ++i) dist[i].fill(-1);\n    array<array<Point, W>, H> parent;\n    for (int i = 0; i < H; ++i)\n        for (int j = 0; j < W; ++j)\n            parent[i][j] = {-1, -1};\n    queue<Point> q;\n    dist[start.x][start.y] = 0;\n    q.push(start);\n    while (!q.empty()) {\n        Point cur = q.front(); q.pop();\n        for (int d = 0; d < 4; ++d) {\n            int nx = cur.x + DX[d];\n            int ny = cur.y + DY[d];\n            if (!inside(nx, ny) || impassable[nx][ny] || dist[nx][ny] != -1) continue;\n            dist[nx][ny] = dist[cur.x][cur.y] + 1;\n            parent[nx][ny] = cur;\n            q.push({nx, ny});\n        }\n    }\n    if (dist[goal.x][goal.y] == -1) return -1;\n    Point cur = goal;\n    while (!(parent[cur.x][cur.y].x == start.x && parent[cur.x][cur.y].y == start.y)) {\n        cur = parent[cur.x][cur.y];\n    }\n    if (cur.x == start.x + 1 && cur.y == start.y) return 1;\n    if (cur.x == start.x - 1 && cur.y == start.y) return 0;\n    if (cur.x == start.x && cur.y == start.y + 1) return 3;\n    if (cur.x == start.x && cur.y == start.y - 1) return 2;\n    return -1;\n}\n\nvector<int> hungarian(const vector<vector<int>>& a) {\n    int n = (int)a.size();\n    int m = (int)a[0].size();\n    const int INF = 1e9;\n    vector<int> u(n + 1), v(m + 1), p(m + 1), way(m + 1);\n    for (int i = 1; i <= n; ++i) {\n        p[0] = i;\n        vector<int> minv(m + 1, INF);\n        vector<char> used(m + 1, false);\n        int j0 = 0;\n        do {\n            used[j0] = true;\n            int i0 = p[j0], delta = INF, j1 = 0;\n            for (int j = 1; j <= m; ++j) if (!used[j]) {\n                int cur = a[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= m; ++j) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    v[j] -= delta;\n                } else {\n                    minv[j] -= delta;\n                }\n            }\n            j0 = j1;\n        } while (p[j0]);\n        do {\n            int j1 = way[j0];\n            p[j0] = p[j1];\n            j0 = j1;\n        } while (j0);\n    }\n    vector<int> ans(n, -1);\n    for (int j = 1; j <= m; ++j) if (p[j]) ans[p[j] - 1] = j - 1;\n    return ans;\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<Point> pets(N);\n    vector<int> pet_type(N);\n    for (int i = 0; i < N; ++i) {\n        int px, py, pt;\n        cin >> px >> py >> pt;\n        pets[i] = {px - 1, py - 1};\n        pet_type[i] = pt;\n    }\n    int M;\n    cin >> M;\n    vector<Point> humans(M);\n    for (int i = 0; i < M; ++i) {\n        int hx, hy;\n        cin >> hx >> hy;\n        humans[i] = {hx - 1, hy - 1};\n    }\n\n    vector<vector<int>> blocked(H, vector<int>(W, 0));\n    vector<vector<int>> pet_count(H, vector<int>(W, 0));\n    for (auto &p : pets) if (inside(p.x, p.y)) pet_count[p.x][p.y]++;\n\n    vector<int> edge = {2, 6, 10, 14, 18, 22, 26};\n    vector<Candidate> candidates;\n\n    auto add_top = [&](int y) {\n        Candidate c;\n        c.pos = {0, y};\n        c.blocks = {{0, y - 1, 'l'}, {0, y + 1, 'r'}, {1, y, 'd'}};\n        c.final_block_index = 2;\n        c.escape_nodes = {{0, y}, {1, y}, {2, y}};\n        candidates.push_back(c);\n    };\n    auto add_bottom = [&](int y) {\n        Candidate c;\n        c.pos = {H - 1, y};\n        c.blocks = {{H - 1, y - 1, 'l'}, {H - 1, y + 1, 'r'}, {H - 2, y, 'u'}};\n        c.final_block_index = 2;\n        c.escape_nodes = {{H - 1, y}, {H - 2, y}, {H - 3, y}};\n        candidates.push_back(c);\n    };\n    auto add_left = [&](int x) {\n        Candidate c;\n        c.pos = {x, 0};\n        c.blocks = {{x - 1, 0, 'u'}, {x + 1, 0, 'd'}, {x, 1, 'r'}};\n        c.final_block_index = 2;\n        c.escape_nodes = {{x, 0}, {x, 1}, {x, 2}};\n        candidates.push_back(c);\n    };\n    auto add_right = [&](int x) {\n        Candidate c;\n        c.pos = {x, W - 1};\n        c.blocks = {{x - 1, W - 1, 'u'}, {x + 1, W - 1, 'd'}, {x, W - 2, 'l'}};\n        c.final_block_index = 2;\n        c.escape_nodes = {{x, W - 1}, {x, W - 2}, {x, W - 3}};\n        candidates.push_back(c);\n    };\n\n    for (int y : edge) add_top(y);\n    for (int y : edge) add_bottom(y);\n    for (int x : edge) add_left(x);\n    for (int x : edge) add_right(x);\n\n    int C = (int)candidates.size();\n    vector<int> candidate_penalty(C, 0);\n    array<int, 6> type_weight = {0, 1, 1, 1, 3, 2};\n\n    auto update_penalty = [&]() {\n        fill(candidate_penalty.begin(), candidate_penalty.end(), 0);\n        for (int j = 0; j < C; ++j) {\n            int pen = 0;\n            for (int i = 0; i < N; ++i) {\n                int dist = abs(pets[i].x - candidates[j].pos.x) + abs(pets[i].y - candidates[j].pos.y);\n                if (dist < PET_RADIUS) {\n                    pen += (PET_RADIUS - dist) * PET_WEIGHT * type_weight[pet_type[i]];\n                }\n            }\n            candidate_penalty[j] = pen;\n        }\n    };\n    update_penalty();\n\n    vector<vector<int>> cost(M, vector<int>(C));\n    for (int i = 0; i < M; ++i) {\n        for (int j = 0; j < C; ++j) {\n            int dist = abs(humans[i].x - candidates[j].pos.x) + abs(humans[i].y - candidates[j].pos.y);\n            cost[i][j] = dist * DIST_WEIGHT + candidate_penalty[j];\n        }\n    }\n    vector<int> assign = hungarian(cost);\n\n    vector<int> candidate_owner(C, -1);\n    vector<int> candidate_block_until(C, -1000);\n\n    vector<int> human_target_idx(M, -1);\n    vector<Point> targets(M);\n    vector<vector<BlockCell>> human_block_cells(M);\n    vector<vector<int>> human_block_done(M);\n    vector<vector<Point>> human_escape_nodes(M);\n    vector<int> final_block_index(M, -1);\n\n    vector<int> stage(M, 0);\n    vector<int> idle_block_turns(M, 0);\n    vector<int> stuck_move_turns(M, 0);\n    vector<int> pet_on_me_turns(M, 0);\n    vector<int> block_reason(M, 0);\n    vector<int> reassign_count(M, 0);\n\n    vector<int> escape_state(M, 0); // 0 none,1 outward,2 wait,3 return\n    vector<int> escape_idx(M, 0);\n    vector<int> escape_wait_counter(M, 0);\n    vector<int> lure_fail_turns(M, 0);\n    vector<int> lure_cooldown(M, 0);\n\n    auto is_complete = [&](int idx) -> bool {\n        if (human_block_done[idx].empty()) return false;\n        for (int v : human_block_done[idx]) if (!v) return false;\n        return true;\n    };\n\n    auto set_candidate = [&](int idx, int cand) {\n        human_target_idx[idx] = cand;\n        targets[idx] = candidates[cand].pos;\n        human_block_cells[idx] = candidates[cand].blocks;\n        human_block_done[idx].assign(human_block_cells[idx].size(), 0);\n        for (int k = 0; k < (int)human_block_cells[idx].size(); ++k) {\n            auto &bc = human_block_cells[idx][k];\n            if (blocked[bc.x][bc.y]) human_block_done[idx][k] = 1;\n        }\n        human_escape_nodes[idx] = candidates[cand].escape_nodes;\n        final_block_index[idx] = candidates[cand].final_block_index;\n        stage[idx] = (humans[idx].x == targets[idx].x && humans[idx].y == targets[idx].y)\n                     ? (is_complete(idx) ? 2 : 1) : 0;\n        idle_block_turns[idx] = 0;\n        stuck_move_turns[idx] = 0;\n        pet_on_me_turns[idx] = 0;\n        block_reason[idx] = 0;\n        escape_state[idx] = 0;\n        escape_idx[idx] = 0;\n        escape_wait_counter[idx] = 0;\n        lure_fail_turns[idx] = 0;\n        lure_cooldown[idx] = 0;\n    };\n\n    for (int i = 0; i < M; ++i) {\n        candidate_owner[assign[i]] = i;\n        set_candidate(i, assign[i]);\n    }\n\n    auto try_reassign = [&](int idx, int remaining, int turn) -> bool {\n        if (reassign_count[idx] >= MAX_REASSIGN) return false;\n        if (escape_state[idx] != 0) return false;\n        int old = human_target_idx[idx];\n        if (old < 0) return false;\n        candidate_owner[old] = -1;\n        candidate_block_until[old] = turn + CAND_COOLDOWN;\n        const int INF = 1e9;\n        int best = -1, best_cost = INF;\n        for (int j = 0; j < C; ++j) {\n            if (candidate_owner[j] != -1) continue;\n            if (candidate_block_until[j] > turn) continue;\n            int dist = abs(humans[idx].x - candidates[j].pos.x) + abs(humans[idx].y - candidates[j].pos.y);\n            if (dist + REASSIGN_BUFFER > remaining) continue;\n            if (blocked[candidates[j].pos.x][candidates[j].pos.y]) continue;\n            int cur = dist * DIST_WEIGHT + candidate_penalty[j];\n            if (cur < best_cost) {\n                best_cost = cur;\n                best = j;\n            }\n        }\n        if (best == -1) {\n            candidate_owner[old] = idx;\n            return false;\n        }\n        candidate_owner[best] = idx;\n        set_candidate(idx, best);\n        reassign_count[idx]++;\n        return true;\n    };\n\n    for (int turn = 0; turn < 300; ++turn) {\n        for (int i = 0; i < M; ++i) {\n            for (int k = 0; k < (int)human_block_cells[i].size(); ++k) {\n                if (!human_block_done[i][k]) {\n                    auto &bc = human_block_cells[i][k];\n                    if (blocked[bc.x][bc.y]) human_block_done[i][k] = 1;\n                }\n            }\n        }\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 0 && humans[i].x == targets[i].x && humans[i].y == targets[i].y) {\n                stage[i] = is_complete(i) ? 2 : 1;\n                escape_state[i] = 0;\n                escape_idx[i] = 0;\n                escape_wait_counter[i] = 0;\n            }\n            if (stage[i] == 1 && is_complete(i)) {\n                stage[i] = 2;\n                escape_state[i] = 0;\n                escape_idx[i] = 0;\n            }\n            if (stage[i] != 1) {\n                escape_state[i] = 0;\n                escape_idx[i] = 0;\n                escape_wait_counter[i] = 0;\n                lure_fail_turns[i] = 0;\n            }\n        }\n\n        vector<vector<int>> humans_here(H, vector<int>(W, 0));\n        for (const auto &h : humans) humans_here[h.x][h.y]++;\n\n        vector<int> planned_block_index(M, -1);\n        vector<int> escape_move_target_idx(M, -1);\n        vector<int> block_reason_new(M, 0);\n        string actions(M, '.');\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] != 1) continue;\n\n            if (escape_state[i] == 1) {\n                int next_idx = escape_idx[i] + 1;\n                if (next_idx < (int)human_escape_nodes[i].size()) {\n                    Point tgt = human_escape_nodes[i][next_idx];\n                    char move = step_char(humans[i], tgt);\n                    if (move != '.') {\n                        actions[i] = move;\n                        escape_move_target_idx[i] = next_idx;\n                    }\n                }\n                continue;\n            }\n            if (escape_state[i] == 2) {\n                block_reason_new[i] = 0;\n                continue;\n            }\n            if (escape_state[i] == 3) {\n                if (escape_idx[i] > 0) {\n                    int next_idx = escape_idx[i] - 1;\n                    Point tgt = human_escape_nodes[i][next_idx];\n                    char move = step_char(humans[i], tgt);\n                    if (move != '.') {\n                        actions[i] = move;\n                        escape_move_target_idx[i] = next_idx;\n                    }\n                } else {\n                    escape_state[i] = 0;\n                }\n                block_reason_new[i] = 0;\n                continue;\n            }\n\n            int idx = -1;\n            for (int j = 0; j < (int)human_block_cells[i].size(); ++j) {\n                if (!human_block_done[i][j]) { idx = j; break; }\n            }\n            while (idx != -1) {\n                auto &bc = human_block_cells[i][idx];\n                if (blocked[bc.x][bc.y]) {\n                    human_block_done[i][idx] = 1;\n                    idx = -1;\n                    for (int j = 0; j < (int)human_block_cells[i].size(); ++j) {\n                        if (!human_block_done[i][j]) { idx = j; break; }\n                    }\n                    continue;\n                }\n                int reason = 0;\n                if (pet_count[bc.x][bc.y] > 0) reason = 1;\n                else {\n                    bool adj_pet = false;\n                    for (int d = 0; d < 4; ++d) {\n                        int ax = bc.x + DX[d];\n                        int ay = bc.y + DY[d];\n                        if (inside(ax, ay) && pet_count[ax][ay] > 0) {\n                            adj_pet = true;\n                            break;\n                        }\n                    }\n                    if (adj_pet) reason = 2;\n                    else if (humans_here[bc.x][bc.y] > 0) reason = 3;\n                }\n                if (reason == 0) {\n                    planned_block_index[i] = idx;\n                    actions[i] = bc.action;\n                } else {\n                    block_reason_new[i] = reason;\n                }\n                break;\n            }\n            if (idx == -1) block_reason_new[i] = 0;\n        }\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 1 && escape_state[i] == 0) {\n                if (planned_block_index[i] == -1) {\n                    if (block_reason_new[i] == 1 || block_reason_new[i] == 2) lure_fail_turns[i]++;\n                    else lure_fail_turns[i] = 0;\n                } else {\n                    lure_fail_turns[i] = 0;\n                }\n            } else {\n                lure_fail_turns[i] = 0;\n            }\n        }\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] != 1 || escape_state[i] != 0) continue;\n            if (is_complete(i)) continue;\n            if (human_block_done[i][final_block_index[i]] == 0 &&\n                humans[i].x == targets[i].x && humans[i].y == targets[i].y &&\n                (block_reason_new[i] == 1 || block_reason_new[i] == 2 || pet_on_me_turns[i] >= PET_ON_ME_ESCAPE) &&\n                lure_cooldown[i] == 0 && (int)human_escape_nodes[i].size() >= 2) {\n\n                bool triggered = false;\n                if ((block_reason_new[i] == 1 || block_reason_new[i] == 2) && lure_fail_turns[i] >= LURE_TRIGGER)\n                    triggered = true;\n                if (pet_on_me_turns[i] >= PET_ON_ME_ESCAPE) triggered = true;\n\n                if (triggered) {\n                    escape_state[i] = 1;\n                    escape_idx[i] = 0;\n                    escape_wait_counter[i] = 0;\n                    lure_fail_turns[i] = 0;\n                    pet_on_me_turns[i] = 0;\n                    if (actions[i] == '.') {\n                        Point tgt = human_escape_nodes[i][1];\n                        if (!blocked[tgt.x][tgt.y]) {\n                            char move = step_char(humans[i], tgt);\n                            if (move != '.') {\n                                actions[i] = move;\n                                escape_move_target_idx[i] = 1;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        vector<vector<int>> temp_blocked = blocked;\n        for (int i = 0; i < M; ++i) {\n            if (planned_block_index[i] != -1) {\n                auto &bc = human_block_cells[i][planned_block_index[i]];\n                temp_blocked[bc.x][bc.y] = 1;\n            }\n        }\n\n        vector<int> move_dir(M, -2);\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] != 0) continue;\n            if (humans[i].x == targets[i].x && humans[i].y == targets[i].y) {\n                stage[i] = is_complete(i) ? 2 : 1;\n                continue;\n            }\n            int dir = bfs_next_dir(temp_blocked, humans[i], targets[i]);\n            move_dir[i] = dir;\n            if (dir != -1) {\n                actions[i] = MOVE_CH[dir];\n                stuck_move_turns[i] = 0;\n            } else {\n                stuck_move_turns[i]++;\n            }\n        }\n\n        cout << actions << endl;\n\n        vector<Point> start_pos = humans;\n        for (int i = 0; i < M; ++i) {\n            char act = actions[i];\n            int dir = dir_from_char(act);\n            if (act == '.' || dir == -1) continue;\n            if ('A' <= act && act <= 'Z') {\n                humans[i].x += DX[dir];\n                humans[i].y += DY[dir];\n            } else {\n                int nx = start_pos[i].x + DX[dir];\n                int ny = start_pos[i].y + DY[dir];\n                if (inside(nx, ny)) {\n                    blocked[nx][ny] = 1;\n                    if (planned_block_index[i] != -1) human_block_done[i][planned_block_index[i]] = 1;\n                }\n            }\n        }\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 1) {\n                if (escape_state[i] != 0) {\n                    idle_block_turns[i] = 0;\n                } else if (planned_block_index[i] != -1 && actions[i] == human_block_cells[i][planned_block_index[i]].action) {\n                    idle_block_turns[i] = 0;\n                } else if (!is_complete(i)) {\n                    idle_block_turns[i]++;\n                } else {\n                    idle_block_turns[i] = 0;\n                }\n            } else {\n                idle_block_turns[i] = 0;\n            }\n        }\n\n        for (int i = 0; i < M; ++i) {\n            if (escape_move_target_idx[i] != -1) {\n                escape_idx[i] = escape_move_target_idx[i];\n            }\n        }\n        for (int i = 0; i < M; ++i) {\n            if (escape_state[i] == 1 && escape_idx[i] == (int)human_escape_nodes[i].size() - 1) {\n                escape_state[i] = 2;\n                escape_wait_counter[i] = 0;\n            } else if (escape_state[i] == 3 && escape_idx[i] == 0) {\n                escape_state[i] = 0;\n                escape_wait_counter[i] = 0;\n                lure_cooldown[i] = LURE_COOLDOWN;\n            } else if (escape_state[i] == 2) {\n                escape_wait_counter[i]++;\n                if (escape_wait_counter[i] >= ESCAPE_WAIT_TURNS) {\n                    escape_state[i] = 3;\n                }\n            }\n        }\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 1 && escape_state[i] == 0) block_reason[i] = block_reason_new[i];\n            else block_reason[i] = 0;\n        }\n\n        for (int i = 0; i < N; ++i) {\n            string s;\n            cin >> s;\n            for (char c : s) {\n                int dir = dir_from_char(c);\n                if (dir == -1) continue;\n                pets[i].x += DX[dir];\n                pets[i].y += DY[dir];\n            }\n        }\n        for (int x = 0; x < H; ++x) fill(pet_count[x].begin(), pet_count[x].end(), 0);\n        for (auto &p : pets) if (inside(p.x, p.y)) pet_count[p.x][p.y]++;\n        update_penalty();\n\n        for (int i = 0; i < M; ++i) {\n            if (pet_count[humans[i].x][humans[i].y] > 0) pet_on_me_turns[i]++;\n            else pet_on_me_turns[i] = 0;\n        }\n        for (int i = 0; i < M; ++i) if (lure_cooldown[i] > 0) lure_cooldown[i]--;\n\n        int remaining = 300 - (turn + 1);\n        if (remaining >= MIN_REMAINING_FOR_REASSIGN) {\n            for (int i = 0; i < M; ++i) {\n                if (escape_state[i] != 0) continue;\n                bool need = false;\n                if (stage[i] == 1 && !is_complete(i)) {\n                    if ((block_reason[i] == 1 || block_reason[i] == 2) && idle_block_turns[i] >= REASSIGN_WAIT) need = true;\n                    if (pet_on_me_turns[i] >= PET_ON_ME_WAIT) need = true;\n                }\n                if (!need && stage[i] == 0 && stuck_move_turns[i] >= MOVE_STUCK_WAIT) need = true;\n                if (need) try_reassign(i, remaining, turn);\n            }\n        }\n    }\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int H = 20;\nconstexpr int W = 20;\nconstexpr int N = H * W;\nconstexpr int MAX_L = 200;\nconstexpr int MAX_SEG_LEN = 80;\nconst char DIR_CHARS[4] = {'U', 'D', 'L', 'R'};\nconstexpr double TIME_LIMIT = 1.95;\nconstexpr double IMPROVE_EPS = 1e-9;\n\nstruct StepResult {\n    double score;\n    double reachProb;\n};\n\ninline StepResult apply_transition_raw(const double* from, double* to, int dir, int step,\n                                       double forgetProb, double moveProb,\n                                       const array<array<int, N>, 4>& neighbor,\n                                       int targetIdx) {\n    StepResult res{0.0, 0.0};\n    fill(to, to + N, 0.0);\n    const double rewardFactor = 401.0 - (step + 1);\n    for (int idx = 0; idx < N; ++idx) {\n        double prob = from[idx];\n        if (prob <= 1e-15) continue;\n        double stayProb = prob * forgetProb;\n        int nxt = neighbor[dir][idx];\n        double move = prob * moveProb;\n        if (nxt == idx) {\n            stayProb += move;\n        } else if (nxt == targetIdx) {\n            res.score += rewardFactor * move;\n            res.reachProb += move;\n        } else {\n            to[nxt] += move;\n        }\n        to[idx] += stayProb;\n    }\n    return res;\n}\n\ninline double dot_product_raw(const double* a, const double* b) {\n    double sum = 0.0;\n    for (int i = 0; i < N; ++i) sum += a[i] * b[i];\n    return sum;\n}\n\ninline double expected_distance_raw(const double* dist, const double* distTarget) {\n    double sum = 0.0;\n    for (int idx = 0; idx < N; ++idx) sum += dist[idx] * distTarget[idx];\n    return sum;\n}\n\nvector<int> compute_distances(const array<array<int, N>, 4>& neighbor, int targetIdx) {\n    const int INF = 1e9;\n    vector<int> dist(N, INF);\n    queue<int> q;\n    dist[targetIdx] = 0;\n    q.push(targetIdx);\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        for (int dir = 0; dir < 4; ++dir) {\n            int v = neighbor[dir][u];\n            if (v == u) continue;\n            if (dist[v] > dist[u] + 1) {\n                dist[v] = dist[u] + 1;\n                q.push(v);\n            }\n        }\n    }\n    return dist;\n}\n\nvector<int> build_default_sequence() {\n    vector<int> seq(MAX_L);\n    for (int i = 0; i < MAX_L; ++i) seq[i] = (i % 4 == 3) ? 3 : 1;\n    return seq;\n}\n\nvector<int> build_bfs_candidate(int startIdx, int targetIdx,\n                                const array<array<int, N>, 4>& neighbor) {\n    vector<int> parent(N, -1);\n    vector<int> parentDir(N, -1);\n    queue<int> q;\n    q.push(startIdx);\n    parent[startIdx] = startIdx;\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        if (u == targetIdx) break;\n        for (int dir = 0; dir < 4; ++dir) {\n            int v = neighbor[dir][u];\n            if (v == u) continue;\n            if (parent[v] != -1) continue;\n            parent[v] = u;\n            parentDir[v] = dir;\n            q.push(v);\n        }\n    }\n    vector<int> path;\n    if (parent[targetIdx] != -1) {\n        int cur = targetIdx;\n        while (cur != startIdx) {\n            int dir = parentDir[cur];\n            path.push_back(dir);\n            cur = parent[cur];\n        }\n        reverse(path.begin(), path.end());\n    }\n    vector<int> seq = build_default_sequence();\n    int pos = 0;\n    for (int dir : path) {\n        if (pos >= MAX_L) break;\n        seq[pos++] = dir;\n    }\n    return seq;\n}\n\nstruct BeamParam {\n    double weight;\n    double noise;\n    int width;\n};\n\nstruct BeamResult {\n    vector<int> seq;\n    double score;\n};\n\nBeamResult run_beam(const BeamParam& param,\n                    const array<array<int, N>, 4>& neighbor,\n                    const vector<double>& distTarget,\n                    int startIdx, int targetIdx,\n                    double forgetProb,\n                    mt19937& rng) {\n    const double moveProb = 1.0 - forgetProb;\n    struct Candidate {\n        array<double, N> dist;\n        double score;\n        double heuristic;\n        array<uint8_t, MAX_L> path;\n        int len;\n    };\n    vector<Candidate> beam, next;\n    beam.reserve(param.width);\n    next.reserve(param.width * 4);\n\n    Candidate init;\n    init.dist.fill(0.0);\n    init.dist[startIdx] = 1.0;\n    init.score = 0.0;\n    init.len = 0;\n    init.path.fill(0);\n    init.heuristic = 0.0;\n    beam.push_back(init);\n\n    uniform_real_distribution<double> noiseDist(-param.noise, param.noise);\n    auto cmp = [](const Candidate& a, const Candidate& b) {\n        return a.heuristic > b.heuristic;\n    };\n\n    for (int step = 0; step < MAX_L; ++step) {\n        next.clear();\n        for (const Candidate& cand : beam) {\n            for (int dir = 0; dir < 4; ++dir) {\n                Candidate child;\n                child.path = cand.path;\n                child.path[cand.len] = static_cast<uint8_t>(dir);\n                child.len = cand.len + 1;\n                StepResult sr = apply_transition_raw(cand.dist.data(), child.dist.data(),\n                                                     dir, step, forgetProb, moveProb,\n                                                     neighbor, targetIdx);\n                child.score = cand.score + sr.score;\n                double expDist = expected_distance_raw(child.dist.data(), distTarget.data());\n                double noise = (param.noise > 0) ? noiseDist(rng) : 0.0;\n                child.heuristic = child.score - param.weight * expDist + noise;\n                next.push_back(std::move(child));\n            }\n        }\n        if (next.empty()) break;\n        int width = min(param.width, static_cast<int>(next.size()));\n        partial_sort(next.begin(), next.begin() + width, next.end(), cmp);\n        next.resize(width);\n        beam.swap(next);\n    }\n\n    Candidate best = beam[0];\n    for (const Candidate& cand : beam) if (cand.score > best.score) best = cand;\n    vector<int> seq(MAX_L);\n    for (int i = 0; i < MAX_L; ++i) seq[i] = best.path[i];\n    return {seq, best.score};\n}\n\nstruct Evaluator {\n    const array<array<int, N>, 4>& neighbor;\n    int startIdx;\n    int targetIdx;\n    double forgetProb;\n    double moveProb;\n    vector<double> cur, nxt;\n    Evaluator(const array<array<int, N>, 4>& neighbor_, int s, int t, double p)\n        : neighbor(neighbor_), startIdx(s), targetIdx(t), forgetProb(p), moveProb(1.0 - p),\n          cur(N, 0.0), nxt(N, 0.0) {}\n\n    double evaluate(const vector<int>& seq) {\n        fill(cur.begin(), cur.end(), 0.0);\n        cur[startIdx] = 1.0;\n        double total = 0.0;\n        for (int step = 0; step < (int)seq.size(); ++step) {\n            StepResult sr = apply_transition_raw(cur.data(), nxt.data(), seq[step], step,\n                                                 forgetProb, moveProb, neighbor, targetIdx);\n            total += sr.score;\n            cur.swap(nxt);\n            bool empty = true;\n            for (double v : cur) if (v > 1e-15) { empty = false; break; }\n            if (empty) break;\n        }\n        return total;\n    }\n};\n\nvoid recompute_forward_from(int startStep,\n                            const vector<int>& seq,\n                            vector<array<double, N>>& forward,\n                            vector<double>& prefixScore,\n                            vector<double>& aliveProb,\n                            double forgetProb, double moveProb,\n                            const array<array<int, N>, 4>& neighbor,\n                            int targetIdx, int startIdx) {\n    if (startStep <= 0) {\n        startStep = 0;\n        forward[0].fill(0.0);\n        forward[0][startIdx] = 1.0;\n        prefixScore[0] = 0.0;\n        aliveProb[0] = 1.0;\n    }\n    for (int step = startStep; step < MAX_L; ++step) {\n        StepResult sr = apply_transition_raw(forward[step].data(), forward[step + 1].data(),\n                                             seq[step], step, forgetProb, moveProb,\n                                             neighbor, targetIdx);\n        prefixScore[step + 1] = prefixScore[step] + sr.score;\n        double alive = aliveProb[step] - sr.reachProb;\n        if (alive < 0.0) alive = 0.0;\n        aliveProb[step + 1] = alive;\n    }\n}\n\nvoid recompute_backward_up_to(int uptoStep,\n                              const vector<int>& seq,\n                              vector<array<double, N>>& value,\n                              double forgetProb, double moveProb,\n                              const array<array<int, N>, 4>& neighbor,\n                              int targetIdx) {\n    if (uptoStep >= MAX_L - 1) uptoStep = MAX_L - 1;\n    for (int step = uptoStep; step >= 0; --step) {\n        auto& cur = value[step];\n        auto& nxt = value[step + 1];\n        int dir = seq[step];\n        double rewardFactor = 401.0 - (step + 1);\n        for (int idx = 0; idx < N; ++idx) {\n            double val = forgetProb * nxt[idx];\n            int nextIdx = neighbor[dir][idx];\n            if (nextIdx == idx) {\n                val += moveProb * nxt[idx];\n            } else if (nextIdx == targetIdx) {\n                val += moveProb * rewardFactor;\n            } else {\n                val += moveProb * nxt[nextIdx];\n            }\n            cur[idx] = val;\n        }\n        cur[targetIdx] = 0.0;\n    }\n}\n\nstruct SegmentParam {\n    double weight;\n    double noise;\n    int width;\n    double futureCoeff;\n};\n\nstruct SegmentResult {\n    bool success;\n    vector<int> path;\n    double totalContribution;\n};\n\nSegmentResult run_segment_beam(const array<double, N>& distPre,\n                               const array<double, N>& suffixValue,\n                               int len, int stepOffset,\n                               const array<array<int, N>, 4>& neighbor,\n                               double forgetProb, double moveProb,\n                               const vector<double>& distTarget,\n                               const SegmentParam& param,\n                               mt19937& rng,\n                               int targetIdx) {\n    SegmentResult result{false, {}, -1e300};\n    if (len <= 0 || len > MAX_SEG_LEN) return result;\n    struct Node {\n        array<double, N> dist;\n        double score;\n        double heuristic;\n        array<uint8_t, MAX_SEG_LEN> path;\n        int len;\n    };\n    vector<Node> beam;\n    vector<Node> next;\n    beam.reserve(param.width);\n    next.reserve(param.width * 4);\n\n    Node init;\n    init.dist = distPre;\n    init.score = 0.0;\n    init.len = 0;\n    init.heuristic = dot_product_raw(distPre.data(), suffixValue.data());\n    init.path.fill(0);\n    beam.push_back(init);\n\n    uniform_real_distribution<double> noiseDist(-param.noise, param.noise);\n    auto cmp = [](const Node& a, const Node& b) {\n        return a.heuristic > b.heuristic;\n    };\n\n    for (int step = 0; step < len; ++step) {\n        next.clear();\n        for (const Node& cand : beam) {\n            for (int dir = 0; dir < 4; ++dir) {\n                Node child;\n                child.path = cand.path;\n                child.path[cand.len] = static_cast<uint8_t>(dir);\n                child.len = cand.len + 1;\n                StepResult sr = apply_transition_raw(cand.dist.data(), child.dist.data(),\n                                                     dir, stepOffset + step,\n                                                     forgetProb, moveProb,\n                                                     neighbor, targetIdx);\n                child.score = cand.score + sr.score;\n                double expDist = expected_distance_raw(child.dist.data(), distTarget.data());\n                double futureEst = dot_product_raw(child.dist.data(), suffixValue.data());\n                double noise = (param.noise > 0) ? noiseDist(rng) : 0.0;\n                child.heuristic = child.score + param.futureCoeff * futureEst\n                                - param.weight * expDist + noise;\n                next.push_back(std::move(child));\n            }\n        }\n        if (next.empty()) return result;\n        int width = min(param.width, static_cast<int>(next.size()));\n        partial_sort(next.begin(), next.begin() + width, next.end(), cmp);\n        next.resize(width);\n        beam.swap(next);\n    }\n\n    double bestTotal = -1e300;\n    int bestIdx = 0;\n    for (int i = 0; i < (int)beam.size(); ++i) {\n        double total = beam[i].score + dot_product_raw(beam[i].dist.data(), suffixValue.data());\n        if (total > bestTotal) {\n            bestTotal = total;\n            bestIdx = i;\n        }\n    }\n    result.success = true;\n    result.totalContribution = bestTotal;\n    result.path.resize(len);\n    for (int i = 0; i < len; ++i) result.path[i] = beam[bestIdx].path[i];\n    return result;\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    cin >> si >> sj >> ti >> tj >> p;\n    vector<string> h(H), v(H - 1);\n    for (int i = 0; i < H; ++i) cin >> h[i];\n    for (int i = 0; i < H - 1; ++i) cin >> v[i];\n\n    array<array<int, N>, 4> neighbor;\n    auto idx = [&](int r, int c) { return r * W + c; };\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int id = idx(i, j);\n            neighbor[0][id] = (i > 0 && v[i - 1][j] == '0') ? idx(i - 1, j) : id;\n            neighbor[1][id] = (i < H - 1 && v[i][j] == '0') ? idx(i + 1, j) : id;\n            neighbor[2][id] = (j > 0 && h[i][j - 1] == '0') ? idx(i, j - 1) : id;\n            neighbor[3][id] = (j < W - 1 && h[i][j] == '0') ? idx(i, j + 1) : id;\n        }\n    }\n\n    int startIdx = idx(si, sj);\n    int targetIdx = idx(ti, tj);\n\n    vector<int> distInt = compute_distances(neighbor, targetIdx);\n    vector<double> distTarget(N);\n    for (int i = 0; i < N; ++i) distTarget[i] = (distInt[i] >= 1e8) ? 100.0 : (double)distInt[i];\n\n    mt19937 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n\n    vector<vector<int>> candidates;\n    candidates.push_back(build_bfs_candidate(startIdx, targetIdx, neighbor));\n    candidates.push_back(build_default_sequence());\n\n    vector<BeamParam> beamParams;\n    double factor = 0.6 + 0.8 * p;\n    beamParams.push_back({0.8 * factor, 3e-4, 10});\n    beamParams.push_back({1.1 * factor, 2e-4, 12});\n    beamParams.push_back({1.5 * factor, 1e-4, 14});\n    beamParams.push_back({2.1 * factor, 5e-5, 16});\n    beamParams.push_back({2.9 * factor, 2e-5, 18});\n    beamParams.push_back({3.6 * factor, 1e-5, 20});\n    beamParams.push_back({4.4 * factor, 5e-6, 22});\n\n    double beamTimeLimit = min(0.55, TIME_LIMIT * 0.4);\n    size_t paramIdx = 0;\n    while (elapsed() < beamTimeLimit && paramIdx < beamParams.size()) {\n        BeamResult res = run_beam(beamParams[paramIdx], neighbor, distTarget,\n                                  startIdx, targetIdx, p, rng);\n        candidates.push_back(std::move(res.seq));\n        ++paramIdx;\n    }\n\n    Evaluator evaluator(neighbor, startIdx, targetIdx, p);\n    double bestEval = -1.0;\n    vector<int> bestSeq;\n    for (const auto& seq : candidates) {\n        double sc = evaluator.evaluate(seq);\n        if (sc > bestEval + IMPROVE_EPS) {\n            bestEval = sc;\n            bestSeq = seq;\n        }\n    }\n    if (bestSeq.empty()) bestSeq = build_default_sequence();\n\n    vector<array<double, N>> forward(MAX_L + 1), value(MAX_L + 1);\n    for (auto& arr : forward) arr.fill(0.0);\n    for (auto& arr : value) arr.fill(0.0);\n    vector<double> prefixScore(MAX_L + 1, 0.0);\n    vector<double> aliveProb(MAX_L + 1, 0.0);\n\n    forward[0][startIdx] = 1.0;\n    aliveProb[0] = 1.0;\n    recompute_forward_from(0, bestSeq, forward, prefixScore, aliveProb,\n                           p, 1.0 - p, neighbor, targetIdx, startIdx);\n    value[MAX_L].fill(0.0);\n    recompute_backward_up_to(MAX_L - 1, bestSeq, value,\n                             p, 1.0 - p, neighbor, targetIdx);\n    double bestScore = prefixScore[MAX_L];\n\n    array<double, N> tempDist;\n\n    auto buildSegmentParam = [&](int len, int step) -> SegmentParam {\n        SegmentParam param;\n        double lenRatio = (double)len / 32.0;\n        double early = max(0.0, 1.0 - step / 160.0);\n        param.weight = (0.85 + 0.9 * p) * (1.0 + 0.1 * min(2.0, lenRatio)) * (1.0 + 0.15 * early);\n        param.futureCoeff = 0.55 + 0.2 * min(1.5, (double)len / 40.0) + 0.15 * early;\n        param.noise = 7e-5 / (1.0 + 0.25 * lenRatio);\n        int baseWidth;\n        if (len <= 12) baseWidth = 32;\n        else if (len <= 20) baseWidth = 28;\n        else if (len <= 28) baseWidth = 24;\n        else if (len <= 36) baseWidth = 22;\n        else if (len <= 48) baseWidth = 20;\n        else if (len <= 56) baseWidth = 18;\n        else if (len <= 64) baseWidth = 16;\n        else baseWidth = 14;\n        if (step < 50) baseWidth += 4;\n        else if (step < 100) baseWidth += 2;\n        if (step > 140) baseWidth -= 3;\n        else if (step > 110) baseWidth -= 1;\n        baseWidth -= (int)round(p * 2.0);\n        param.width = max(baseWidth, 10);\n        return param;\n    };\n\n    auto sample_weighted_start = [&](mt19937& rng) -> int {\n        array<double, MAX_L> weights;\n        double total = 0.0;\n        for (int i = 0; i < MAX_L; ++i) {\n            double w = aliveProb[i] * (401.0 - (i + 1));\n            weights[i] = max(0.0, w);\n            total += weights[i];\n        }\n        if (total < 1e-9) {\n            uniform_int_distribution<int> dist(0, MAX_L - 1);\n            return dist(rng);\n        }\n        uniform_real_distribution<double> dist(0.0, total);\n        double r = dist(rng);\n        double acc = 0.0;\n        for (int i = 0; i < MAX_L; ++i) {\n            acc += weights[i];\n            if (r <= acc) return i;\n        }\n        return MAX_L - 1;\n    };\n\n    auto try_segment = [&](int start, int len) -> bool {\n        if (len <= 0) return false;\n        if (start < 0) {\n            len += start;\n            start = 0;\n        }\n        if (start >= MAX_L || len < 4) return false;\n        if (start + len > MAX_L) len = MAX_L - start;\n        if (len <= 0 || len > MAX_SEG_LEN) return false;\n        if (aliveProb[start] < 1e-9) return false;\n        SegmentParam param = buildSegmentParam(len, start);\n        SegmentResult segRes = run_segment_beam(forward[start], value[start + len],\n                                                len, start, neighbor, p, 1.0 - p,\n                                                distTarget, param, rng, targetIdx);\n        if (!segRes.success) return false;\n        double candidateScore = prefixScore[start] + segRes.totalContribution;\n        if (candidateScore > bestScore + IMPROVE_EPS) {\n            for (int i = 0; i < len; ++i) bestSeq[start + i] = segRes.path[i];\n            recompute_forward_from(start, bestSeq, forward, prefixScore, aliveProb,\n                                   p, 1.0 - p, neighbor, targetIdx, startIdx);\n            recompute_backward_up_to(start + len - 1, bestSeq, value,\n                                     p, 1.0 - p, neighbor, targetIdx);\n            bestScore = prefixScore[MAX_L];\n            return true;\n        }\n        return false;\n    };\n\n    auto run_coordinate = [&](double limitTime, int maxPass) {\n        bool improved = true;\n        int passes = 0;\n        while (improved && elapsed() < limitTime && passes < maxPass) {\n            improved = false;\n            ++passes;\n            for (int step = 0; step < MAX_L && elapsed() < limitTime; ++step) {\n                if (aliveProb[step] < 1e-9) break;\n                auto& distIn = forward[step];\n                auto& suffix = value[step + 1];\n                double currentVal = -1e300;\n                double bestVal = -1e300;\n                int bestDir = bestSeq[step];\n                for (int dir = 0; dir < 4; ++dir) {\n                    StepResult sr = apply_transition_raw(distIn.data(), tempDist.data(),\n                                                         dir, step, p, 1.0 - p,\n                                                         neighbor, targetIdx);\n                    double val = sr.score + dot_product_raw(tempDist.data(), suffix.data());\n                    if (dir == bestSeq[step]) currentVal = val;\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestDir = dir;\n                    }\n                }\n                if (bestVal > currentVal + IMPROVE_EPS && bestDir != bestSeq[step]) {\n                    bestSeq[step] = bestDir;\n                    recompute_forward_from(step, bestSeq, forward, prefixScore, aliveProb,\n                                           p, 1.0 - p, neighbor, targetIdx, startIdx);\n                    recompute_backward_up_to(step, bestSeq, value,\n                                             p, 1.0 - p, neighbor, targetIdx);\n                    bestScore = prefixScore[MAX_L];\n                    improved = true;\n                }\n            }\n        }\n    };\n\n    auto apply_drop_segments = [&](double timeLimit, int topK) {\n        vector<pair<double, int>> drops;\n        drops.reserve(MAX_L);\n        for (int step = 0; step < MAX_L; ++step) {\n            double drop = aliveProb[step] - aliveProb[step + 1];\n            if (drop > 1e-8) drops.emplace_back(drop, step);\n        }\n        sort(drops.begin(), drops.end(), greater<>());\n        vector<int> dropLens = {8, 12, 16, 20, 24, 32, 40};\n        for (int i = 0; i < (int)drops.size() && i < topK; ++i) {\n            if (elapsed() > timeLimit) break;\n            int center = drops[i].second;\n            for (int len : dropLens) {\n                if (elapsed() > timeLimit) break;\n                int start = center - len / 2;\n                if (start < 0) start = 0;\n                if (start + len > MAX_L) start = MAX_L - len;\n                try_segment(start, len);\n            }\n        }\n    };\n\n    double coordLimit = min(1.05, TIME_LIMIT * 0.7);\n    run_coordinate(coordLimit, 3);\n\n    double dropLimit = TIME_LIMIT * 0.82;\n    apply_drop_segments(dropLimit, 12);\n\n    run_coordinate(min(TIME_LIMIT * 0.9, coordLimit + 0.2), 1);\n\n    vector<pair<int, int>> prioritySegments;\n    auto addSeg = [&](int s, int len) {\n        if (len <= 0) return;\n        if (s < 0) {\n            len += s;\n            s = 0;\n        }\n        if (s >= MAX_L) return;\n        if (s + len > MAX_L) len = MAX_L - s;\n        if (len >= 4) prioritySegments.emplace_back(s, len);\n    };\n    addSeg(0, 64);\n    addSeg(0, 48);\n    addSeg(16, 48);\n    addSeg(32, 48);\n    addSeg(48, 48);\n    addSeg(MAX_L - 96, 48);\n    addSeg(MAX_L - 64, 64);\n    addSeg(MAX_L - 48, 48);\n\n    double priorityLimit = TIME_LIMIT * 0.9;\n    for (auto [st, len] : prioritySegments) {\n        if (elapsed() > priorityLimit) break;\n        try_segment(st, len);\n    }\n\n    run_coordinate(min(TIME_LIMIT * 0.94, priorityLimit + 0.12), 1);\n\n    vector<int> segLens = {4, 6, 8, 10, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72};\n    vector<double> lenWeights;\n    for (int len : segLens) lenWeights.push_back(1.0 / len);\n    discrete_distribution<int> lenDist(lenWeights.begin(), lenWeights.end());\n\n    double lnsLimit = TIME_LIMIT * 0.985;\n    while (elapsed() < lnsLimit) {\n        int len = segLens[lenDist(rng)];\n        int start = sample_weighted_start(rng);\n        if (start + len > MAX_L) start = MAX_L - len;\n        if (start < 0) start = 0;\n        if (aliveProb[start] < 1e-9) continue;\n        try_segment(start, len);\n    }\n\n    run_coordinate(TIME_LIMIT * 0.997, 1);\n\n    string answer(MAX_L, 'U');\n    for (int i = 0; i < MAX_L; ++i) answer[i] = DIR_CHARS[bestSeq[i]];\n    cout << answer << '\\n';\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int H = 30;\nconstexpr int W = 30;\nconstexpr int N = H * W;\nconstexpr int DIR = 4;\nconstexpr int STATE = N * DIR;\n\nconstexpr int di[4] = {0, -1, 0, 1};   // left, up, right, down\nconstexpr int dj[4] = {-1, 0, 1, 0};\n\nconstexpr int TO_TABLE[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\nconstexpr int ROT_NEXT[8] = {1, 2, 3, 0, 5, 4, 7, 6};\n\nstruct EvalResult {\n    long long score;\n    int l1;\n    int l2;\n    int loopCnt;\n};\n\nstruct Evaluator {\n    array<int, STATE> visitedStamp{};\n    array<int, STATE> pathStamp{};\n    array<int, STATE> pathPos{};\n    int visitedToken = 0;\n    int pathToken = 0;\n    vector<int> pathList;\n\n    Evaluator() { pathList.reserve(STATE); }\n\n    EvalResult operator()(const vector<int>& finalType) {\n        ++visitedToken;\n        int token = visitedToken;\n\n        for (int cell = 0; cell < N; ++cell) {\n            int type = finalType[cell];\n            for (int d = 0; d < DIR; ++d) {\n                if (TO_TABLE[type][d] == -1) {\n                    visitedStamp[(cell << 2) | d] = token;\n                }\n            }\n        }\n\n        long long best1 = 0, best2 = 0;\n        int loops = 0;\n\n        for (int cell = 0; cell < N; ++cell) {\n            for (int d = 0; d < DIR; ++d) {\n                int stateIdx = (cell << 2) | d;\n                if (visitedStamp[stateIdx] == token) continue;\n\n                ++pathToken;\n                int pathTok = pathToken;\n                pathList.clear();\n\n                int curCell = cell;\n                int curDir = d;\n                int i = curCell / W;\n                int j = curCell % W;\n                int length = 0;\n\n                while (true) {\n                    int idx = (curCell << 2) | curDir;\n                    if (visitedStamp[idx] == token) break;\n\n                    if (pathStamp[idx] == pathTok) {\n                        int loopLen = length - pathPos[idx];\n                        if (loopLen > 0) {\n                            ++loops;\n                            if (loopLen >= best1) {\n                                best2 = best1;\n                                best1 = loopLen;\n                            } else if (loopLen > best2) {\n                                best2 = loopLen;\n                            }\n                        }\n                        break;\n                    }\n\n                    pathStamp[idx] = pathTok;\n                    pathPos[idx] = length;\n                    pathList.push_back(idx);\n\n                    int type = finalType[curCell];\n                    int nextDir = TO_TABLE[type][curDir];\n                    if (nextDir == -1) break;\n\n                    int ni = i + di[nextDir];\n                    int nj = j + dj[nextDir];\n                    if (ni < 0 || ni >= H || nj < 0 || nj >= W) break;\n\n                    i = ni;\n                    j = nj;\n                    curCell = ni * W + nj;\n                    curDir = (nextDir + 2) & 3;\n                    ++length;\n                }\n\n                for (int idx2 : pathList) {\n                    visitedStamp[idx2] = token;\n                }\n            }\n        }\n\n        long long total = (loops >= 2) ? best1 * best2 : 0LL;\n        return {total, (int)best1, (int)best2, loops};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> base(N);\n    for (int i = 0; i < H; ++i) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < W; ++j) {\n            base[i * W + j] = s[j] - '0';\n        }\n    }\n\n    int ROT_TABLE[8][4];\n    int ROT_INV[8][8];\n    memset(ROT_INV, -1, sizeof(ROT_INV));\n    for (int t = 0; t < 8; ++t) {\n        ROT_TABLE[t][0] = t;\n        for (int r = 1; r < 4; ++r) {\n            ROT_TABLE[t][r] = ROT_NEXT[ROT_TABLE[t][r - 1]];\n        }\n        for (int r = 0; r < 4; ++r) {\n            int type = ROT_TABLE[t][r];\n            if (ROT_INV[t][type] == -1) ROT_INV[t][type] = r;\n        }\n    }\n\n    vector<array<int, 4>> neighbors(N);\n    for (int cell = 0; cell < N; ++cell) {\n        int i = cell / W;\n        int j = cell % W;\n        for (int d = 0; d < DIR; ++d) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= H || nj < 0 || nj >= W) neighbors[cell][d] = -1;\n            else neighbors[cell][d] = ni * W + nj;\n        }\n    }\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    vector<int> rot(N, 0);\n    vector<int> finalType(N);\n\n    const int MATCH_BONUS = 7;\n    const int OPEN_PENALTY = -3;\n    const int BORDER_PENALTY = -6;\n\n    auto startTime = chrono::steady_clock::now();\n    auto nowTime = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n    const double TIME_LIMIT = 1.9;\n\n    // Initial orientation: prefer keeping rails inside the board\n    for (int cell = 0; cell < N; ++cell) {\n        int baseState = base[cell];\n        int bestR = 0;\n        int bestVal = -1e9;\n        array<char, 8> used{};\n        for (int r = 0; r < 4; ++r) {\n            int type = ROT_TABLE[baseState][r];\n            if (used[type]) continue;\n            used[type] = 1;\n            int val = 0;\n            for (int d = 0; d < DIR; ++d) {\n                if (TO_TABLE[type][d] == -1) continue;\n                int nb = neighbors[cell][d];\n                if (nb == -1) val += BORDER_PENALTY;\n                else val += MATCH_BONUS / 2;\n            }\n            if (val > bestVal || (val == bestVal && (rng() & 1))) {\n                bestVal = val;\n                bestR = r;\n            }\n        }\n        rot[cell] = bestR;\n        finalType[cell] = ROT_TABLE[baseState][bestR];\n    }\n\n    vector<int> openEnds(N, 0);\n    vector<int> badPos(N, -1);\n    vector<int> badCells;\n    badCells.reserve(N);\n\n    auto setBadState = [&](int cell, bool bad) {\n        if (bad) {\n            if (badPos[cell] == -1) {\n                badPos[cell] = (int)badCells.size();\n                badCells.push_back(cell);\n            }\n        } else if (badPos[cell] != -1) {\n            int idx = badPos[cell];\n            int last = badCells.back();\n            badCells[idx] = last;\n            badPos[last] = idx;\n            badCells.pop_back();\n            badPos[cell] = -1;\n        }\n    };\n\n    struct LocalResult {\n        int score;\n        int open;\n    };\n\n    auto localEval = [&](int cell, int type) -> LocalResult {\n        LocalResult res{0, 0};\n        const auto& nbList = neighbors[cell];\n        for (int d = 0; d < DIR; ++d) {\n            if (TO_TABLE[type][d] == -1) continue;\n            int nb = nbList[d];\n            if (nb == -1) {\n                res.score += BORDER_PENALTY;\n                res.open += 1;\n            } else {\n                int nbType = finalType[nb];\n                if (TO_TABLE[nbType][(d + 2) & 3] != -1) {\n                    res.score += MATCH_BONUS;\n                } else {\n                    res.score += OPEN_PENALTY;\n                    res.open += 1;\n                }\n            }\n        }\n        return res;\n    };\n\n    auto updateOne = [&](int cell) {\n        if (cell < 0) return;\n        LocalResult res = localEval(cell, finalType[cell]);\n        openEnds[cell] = res.open;\n        setBadState(cell, res.open > 0);\n    };\n\n    auto updateAround = [&](int cell) {\n        updateOne(cell);\n        for (int d = 0; d < DIR; ++d) {\n            int nb = neighbors[cell][d];\n            if (nb != -1) updateOne(nb);\n        }\n    };\n\n    auto recomputeAll = [&]() {\n        badCells.clear();\n        fill(badPos.begin(), badPos.end(), -1);\n        for (int cell = 0; cell < N; ++cell) updateOne(cell);\n    };\n\n    recomputeAll();\n\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    double greedyLimit = min(0.45, TIME_LIMIT * 0.35);\n\n    while (nowTime() < greedyLimit) {\n        bool improved = false;\n        shuffle(order.begin(), order.end(), rng);\n        for (int cell : order) {\n            if (nowTime() > greedyLimit) break;\n            int baseState = base[cell];\n            int curType = finalType[cell];\n            LocalResult curRes = localEval(cell, curType);\n            pair<int, int> bestMetric = {curRes.score, -curRes.open};\n            int bestType = curType;\n            int bestRot = rot[cell];\n\n            array<char, 8> used{};\n            for (int r = 0; r < 4; ++r) {\n                int candType = ROT_TABLE[baseState][r];\n                if (used[candType]) continue;\n                used[candType] = 1;\n                LocalResult candRes = localEval(cell, candType);\n                pair<int, int> candMetric = {candRes.score, -candRes.open};\n                if (candMetric > bestMetric ||\n                    (candMetric == bestMetric && (rng() & 1))) {\n                    bestMetric = candMetric;\n                    bestType = candType;\n                    bestRot = r;\n                }\n            }\n\n            if (bestType != curType) {\n                finalType[cell] = bestType;\n                rot[cell] = bestRot;\n                improved = true;\n                updateAround(cell);\n            }\n        }\n        if (!improved) break;\n    }\n\n    recomputeAll();\n\n    Evaluator evaluator;\n    EvalResult curEval = evaluator(finalType);\n    long long currentScore = curEval.score;\n    long long bestScore = currentScore;\n    vector<int> bestRot = rot;\n    vector<int> bestType = finalType;\n\n    double saStart = nowTime();\n    double saEnd = min(TIME_LIMIT - 0.05, TIME_LIMIT * 0.98);\n    if (saEnd < saStart + 1e-3) saEnd = min(TIME_LIMIT - 1e-3, saStart + 1e-3);\n    double span = max(1e-9, saEnd - saStart);\n\n    const double T0 = 4.0;\n    const double T1 = 0.05;\n\n    while (nowTime() < saEnd) {\n        double progress = (nowTime() - saStart) / span;\n        if (progress < 0) progress = 0;\n        if (progress > 1) progress = 1;\n        double temp = T0 + (T1 - T0) * progress;\n\n        int cell;\n        if (!badCells.empty() && dist01(rng) < 0.85) {\n            cell = badCells[rng() % badCells.size()];\n        } else {\n            cell = rng() % N;\n        }\n\n        int baseState = base[cell];\n        int oldRot = rot[cell];\n        int oldType = finalType[cell];\n\n        int newRot = oldRot;\n        int newType = oldType;\n        bool changed = false;\n        for (int tries = 0; tries < 4; ++tries) {\n            int diff = rng() % 3 + 1;\n            int candRot = (oldRot + diff) & 3;\n            int candType = ROT_TABLE[baseState][candRot];\n            if (candType != oldType) {\n                newRot = candRot;\n                newType = candType;\n                changed = true;\n                break;\n            }\n        }\n        if (!changed) {\n            for (int r = 0; r < 4; ++r) {\n                int candType = ROT_TABLE[baseState][r];\n                if (candType != oldType) {\n                    newRot = r;\n                    newType = candType;\n                    changed = true;\n                    break;\n                }\n            }\n        }\n        if (!changed) continue;\n\n        finalType[cell] = newType;\n        rot[cell] = newRot;\n\n        EvalResult newEval = evaluator(finalType);\n        long long delta = newEval.score - currentScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else if (exp(delta / temp) > dist01(rng)) accept = true;\n\n        if (accept) {\n            currentScore = newEval.score;\n            updateAround(cell);\n            if (newEval.score > bestScore) {\n                bestScore = newEval.score;\n                bestRot = rot;\n                bestType = finalType;\n            }\n        } else {\n            finalType[cell] = oldType;\n            rot[cell] = oldRot;\n        }\n    }\n\n    rot = bestRot;\n    finalType = bestType;\n\n    string answer;\n    answer.reserve(N);\n    for (int idx = 0; idx < N; ++idx) {\n        answer.push_back(char('0' + rot[idx]));\n    }\n    cout << answer << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAX_N = 10;\nconst int MAX_CELLS = MAX_N * MAX_N;\n\nint N, T;\nint total_cells, total_tiles;\n\nuint64_t zobrist[MAX_CELLS][16];\nuint8_t visited_buf[MAX_CELLS];\nint queue_buf[MAX_CELLS];\n\nconst int CONN_DX[4] = {0, -1, 0, 1};   // left, up, right, down\nconst int CONN_DY[4] = {-1, 0, 1, 0};\nconst int CONN_BIT[4] = {1, 2, 4, 8};\nconst int CONN_OPP[4] = {2, 3, 0, 1};\n\nconst int BLANK_DX[4] = {-1, 1, 0, 0};  // U, D, L, R (blank movement)\nconst int BLANK_DY[4] = {0, 0, -1, 1};\nconst char MOVE_CHAR[4] = {'U', 'D', 'L', 'R'};\n\nstruct EvalResult {\n    int matched_edges;\n    int largest_tree;\n    int best_component_nodes;\n    int best_component_cycles;\n};\n\ninline bool evalBetter(const EvalResult& a, const EvalResult& b) {\n    if (a.largest_tree != b.largest_tree) return a.largest_tree > b.largest_tree;\n    if (a.best_component_nodes != b.best_component_nodes) return a.best_component_nodes > b.best_component_nodes;\n    if (a.best_component_cycles != b.best_component_cycles) return a.best_component_cycles < b.best_component_cycles;\n    if (a.matched_edges != b.matched_edges) return a.matched_edges > b.matched_edges;\n    return false;\n}\n\ninline bool evalEqual(const EvalResult& a, const EvalResult& b) {\n    return a.largest_tree == b.largest_tree &&\n           a.best_component_nodes == b.best_component_nodes &&\n           a.best_component_cycles == b.best_component_cycles &&\n           a.matched_edges == b.matched_edges;\n}\n\nEvalResult evaluateBoard(const uint8_t* board) {\n    EvalResult res;\n    res.matched_edges = 0;\n    res.largest_tree = 0;\n    res.best_component_nodes = 0;\n    res.best_component_cycles = INT_MAX;\n\n    for (int i = 0; i < N; ++i) {\n        int base = i * N;\n        for (int j = 0; j < N; ++j) {\n            int idx = base + j;\n            uint8_t val = board[idx];\n            if (!val) continue;\n            if (j + 1 < N) {\n                uint8_t nb = board[idx + 1];\n                if (nb && (val & 4) && (nb & 1)) res.matched_edges++;\n            }\n            if (i + 1 < N) {\n                uint8_t nb = board[idx + N];\n                if (nb && (val & 8) && (nb & 2)) res.matched_edges++;\n            }\n        }\n    }\n\n    fill(visited_buf, visited_buf + total_cells, 0);\n    for (int idx = 0; idx < total_cells; ++idx) {\n        uint8_t val = board[idx];\n        if (!val || visited_buf[idx]) continue;\n        int head = 0, tail = 0;\n        queue_buf[tail++] = idx;\n        visited_buf[idx] = 1;\n        int nodes = 0;\n        int edges = 0;\n        while (head < tail) {\n            int cur = queue_buf[head++];\n            nodes++;\n            int cx = cur / N;\n            int cy = cur % N;\n            uint8_t curv = board[cur];\n            for (int d = 0; d < 4; ++d) {\n                if (!(curv & CONN_BIT[d])) continue;\n                int nx = cx + CONN_DX[d];\n                int ny = cy + CONN_DY[d];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                int nidx = nx * N + ny;\n                uint8_t nval = board[nidx];\n                if (!nval) continue;\n                if (!(nval & CONN_BIT[CONN_OPP[d]])) continue;\n                if (cur < nidx) edges++;\n                if (!visited_buf[nidx]) {\n                    visited_buf[nidx] = 1;\n                    queue_buf[tail++] = nidx;\n                }\n            }\n        }\n        int cycles = max(0, edges - (nodes - 1));\n        if (cycles == 0) res.largest_tree = max(res.largest_tree, nodes);\n        if (nodes > res.best_component_nodes ||\n            (nodes == res.best_component_nodes && cycles < res.best_component_cycles)) {\n            res.best_component_nodes = nodes;\n            res.best_component_cycles = cycles;\n        }\n    }\n    if (res.best_component_nodes == 0) res.best_component_cycles = 0;\n    return res;\n}\n\nuint64_t computeHash(const array<uint8_t, MAX_CELLS>& board) {\n    uint64_t h = 0;\n    for (int i = 0; i < total_cells; ++i) {\n        h ^= zobrist[i][board[i]];\n    }\n    return h;\n}\n\nstruct NodeInfo {\n    int parent;\n    char move;\n};\n\nstruct SearchState {\n    array<uint8_t, MAX_CELLS> tiles;\n    uint16_t blank = 0;\n    uint64_t hash = 0;\n    EvalResult eval{};\n    uint16_t depth = 0;\n    int node_id = 0;\n    uint32_t rand_key = 0;\n};\n\nstruct AttemptResult {\n    EvalResult eval;\n    int depth;\n    string sequence;\n    array<uint8_t, MAX_CELLS> board;\n    int blank;\n};\n\nAttemptResult runAttempt(const array<uint8_t, MAX_CELLS>& start_tiles,\n                         int blank_pos,\n                         int beam_width,\n                         int depth_limit,\n                         double time_limit,\n                         const chrono::steady_clock::time_point& start_time,\n                         mt19937& rng) {\n    AttemptResult result;\n    result.board = start_tiles;\n    result.blank = blank_pos;\n    result.eval = evaluateBoard(start_tiles.data());\n    result.depth = 0;\n    result.sequence.clear();\n\n    if (depth_limit <= 0 || result.eval.largest_tree == total_tiles) {\n        return result;\n    }\n\n    vector<NodeInfo> nodes;\n    nodes.reserve(1 + beam_width * 64);\n    nodes.push_back({-1, '?'});\n\n    size_t reserve_est = (size_t)beam_width * min(depth_limit, 64);\n    unordered_map<uint64_t, uint16_t> visited;\n    visited.reserve(reserve_est + 16);\n\n    vector<SearchState> beam;\n    vector<SearchState> candidates;\n    beam.reserve(beam_width);\n    candidates.reserve(beam_width * 4 + 8);\n\n    SearchState init;\n    init.tiles = start_tiles;\n    init.blank = blank_pos;\n    init.hash = computeHash(start_tiles);\n    init.eval = result.eval;\n    init.depth = 0;\n    init.node_id = 0;\n    init.rand_key = rng();\n    beam.push_back(init);\n    visited.emplace(init.hash, 0);\n\n    EvalResult best_eval = init.eval;\n    int best_depth = 0;\n    int best_node = 0;\n    array<uint8_t, MAX_CELLS> best_tiles = start_tiles;\n    int best_blank = blank_pos;\n\n    auto stateComparator = [](const SearchState& a, const SearchState& b) {\n        if (evalBetter(a.eval, b.eval)) return true;\n        if (evalBetter(b.eval, a.eval)) return false;\n        if (a.depth != b.depth) return a.depth < b.depth;\n        return a.rand_key < b.rand_key;\n    };\n\n    int current_depth = 0;\n    bool terminate = false;\n\n    while (!beam.empty() && current_depth < depth_limit && !terminate) {\n        if ((current_depth & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n            if (elapsed > time_limit) break;\n        }\n        candidates.clear();\n        for (size_t si = 0; si < beam.size() && !terminate; ++si) {\n            if ((si & 3) == 0) {\n                double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n                if (elapsed > time_limit) {\n                    terminate = true;\n                    break;\n                }\n            }\n            const SearchState& state = beam[si];\n            int blank = state.blank;\n            int bx = blank / N;\n            int by = blank % N;\n            int dir_order[4] = {0, 1, 2, 3};\n            for (int i = 3; i > 0; --i) {\n                int j = rng() % (i + 1);\n                swap(dir_order[i], dir_order[j]);\n            }\n            for (int k = 0; k < 4; ++k) {\n                int dir = dir_order[k];\n                int nx = bx + BLANK_DX[dir];\n                int ny = by + BLANK_DY[dir];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                int nidx = nx * N + ny;\n                if (state.tiles[nidx] == 0) continue;\n                SearchState child = state;\n                uint8_t tile_to_move = state.tiles[nidx];\n                child.tiles[blank] = tile_to_move;\n                child.tiles[nidx] = 0;\n                child.blank = nidx;\n                child.depth = state.depth + 1;\n                if (child.depth > depth_limit) continue;\n                child.hash ^= zobrist[blank][0];\n                child.hash ^= zobrist[nidx][tile_to_move];\n                child.hash ^= zobrist[blank][tile_to_move];\n                child.hash ^= zobrist[nidx][0];\n                auto it = visited.find(child.hash);\n                if (it != visited.end()) {\n                    if (child.depth >= it->second) continue;\n                    it->second = child.depth;\n                } else {\n                    visited.emplace(child.hash, child.depth);\n                }\n                child.node_id = static_cast<int>(nodes.size());\n                nodes.push_back({state.node_id, MOVE_CHAR[dir]});\n                child.eval = evaluateBoard(child.tiles.data());\n                child.rand_key = rng();\n                if (evalBetter(child.eval, best_eval) ||\n                    (evalEqual(child.eval, best_eval) && child.depth < best_depth)) {\n                    best_eval = child.eval;\n                    best_depth = child.depth;\n                    best_node = child.node_id;\n                    best_tiles = child.tiles;\n                    best_blank = child.blank;\n                    if (best_eval.largest_tree == total_tiles) {\n                        terminate = true;\n                        candidates.emplace_back(std::move(child));\n                        break;\n                    }\n                }\n                candidates.emplace_back(std::move(child));\n            }\n        }\n        if (terminate || candidates.empty()) break;\n        sort(candidates.begin(), candidates.end(), stateComparator);\n        if ((int)candidates.size() > beam_width) candidates.resize(beam_width);\n        beam.swap(candidates);\n        current_depth++;\n    }\n\n    string seq;\n    seq.reserve(best_depth);\n    int node = best_node;\n    while (node != 0) {\n        seq.push_back(nodes[node].move);\n        node = nodes[node].parent;\n    }\n    reverse(seq.begin(), seq.end());\n    result.sequence = seq;\n    result.eval = best_eval;\n    result.depth = best_depth;\n    result.board = best_tiles;\n    result.blank = best_blank;\n    return result;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T;\n    total_cells = N * N;\n    total_tiles = total_cells - 1;\n\n    array<uint8_t, MAX_CELLS> initial_tiles{};\n    int blank_pos = -1;\n    for (int i = 0; i < N; ++i) {\n        string row;\n        cin >> row;\n        for (int j = 0; j < N; ++j) {\n            char c = row[j];\n            int val = (c <= '9') ? c - '0' : 10 + (c - 'a');\n            int idx = i * N + j;\n            initial_tiles[idx] = static_cast<uint8_t>(val);\n            if (val == 0) blank_pos = idx;\n        }\n    }\n\n    mt19937_64 rng64(chrono::steady_clock::now().time_since_epoch().count());\n    for (int i = 0; i < MAX_CELLS; ++i) {\n        for (int v = 0; v < 16; ++v) {\n            uint64_t x = rng64();\n            if (x == 0) x = 1;\n            zobrist[i][v] = x;\n        }\n    }\n    mt19937 rng(static_cast<uint32_t>(rng64()));\n\n    EvalResult best_eval = evaluateBoard(initial_tiles.data());\n    string best_sequence;\n    best_sequence.reserve(T);\n    array<uint8_t, MAX_CELLS> best_board = initial_tiles;\n    int best_blank = blank_pos;\n    int best_length = 0;\n\n    const double TIME_LIMIT = 2.80;\n    const double FIRST_PHASE_RATIO = 0.7;\n    auto start_time = chrono::steady_clock::now();\n\n    int base_width = 80 - 4 * N;\n    base_width = max(12, min(base_width, 90));\n\n    int attempt = 0;\n    while (true) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n        if (elapsed > TIME_LIMIT || elapsed > TIME_LIMIT * FIRST_PHASE_RATIO) break;\n        int width = base_width;\n        int mod = attempt % 3;\n        if (mod == 1) width += 6;\n        else if (mod == 2) width -= 6;\n        width = max(8, min(width, 96));\n        AttemptResult res = runAttempt(initial_tiles, blank_pos, width, T, TIME_LIMIT, start_time, rng);\n        attempt++;\n        if (evalBetter(res.eval, best_eval) ||\n            (evalEqual(res.eval, best_eval) && res.depth < best_length)) {\n            best_eval = res.eval;\n            best_sequence = res.sequence;\n            best_length = res.depth;\n            best_board = res.board;\n            best_blank = res.blank;\n        }\n        if (best_eval.largest_tree == total_tiles) break;\n    }\n\n    best_length = (int)best_sequence.size();\n    if (best_eval.largest_tree < total_tiles && best_length < T) {\n        while (true) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n            if (elapsed > TIME_LIMIT) break;\n            int remaining = T - best_length;\n            if (remaining <= 0) break;\n            int width = max(8, base_width - 4);\n            AttemptResult res = runAttempt(best_board, best_blank, width, remaining, TIME_LIMIT, start_time, rng);\n            if (res.depth == 0) {\n                if (res.eval.largest_tree == total_tiles) {\n                    best_eval = res.eval;\n                    break;\n                }\n                continue;\n            }\n            if (evalBetter(res.eval, best_eval)) {\n                best_eval = res.eval;\n                best_sequence += res.sequence;\n                best_length += res.depth;\n                best_board = res.board;\n                best_blank = res.blank;\n                if (best_eval.largest_tree == total_tiles || best_length >= T) break;\n            }\n        }\n    }\n\n    cout << best_sequence << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\nstruct Line { long long A, B, C; };\nstruct Key { unsigned long long lo, hi; };\nstruct PieceSegment { int start, len; };\nusing CountArr = array<int, 11>;\n\nconst long long COORD_LIMIT = 1'000'000'000LL;\nconst double TIME_LIMIT = 2.8;\nconst int DIR_LIMIT = 1000;\nconst int GENERATE_LINE_ATTEMPTS = 100;\n\nint N, K;\narray<int, 11> demand{};\nvector<Point> points;\n\nvector<unsigned long long> pattern_lo, pattern_hi;\nvector<Key> tmp_keys;\nvector<long long> proj_values;\nvector<int> state_order;\nvector<int> eval_order;\nvector<int> piece_id;\nvector<PieceSegment> piece_segments;\nvector<int> gap_indices;\nvector<Line> lines_current;\n\nint bits_used = 0;\nbool piece_info_valid = false;\n\nmt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\nchrono::steady_clock::time_point start_time;\nbool time_up = false;\n\ninline long long absll(long long x) { return x >= 0 ? x : -x; }\n\nlong long floor_div(long long a, long long b) {\n    assert(b != 0);\n    if (b < 0) { a = -a; b = -b; }\n    if (a >= 0) return a / b;\n    return -(( -a + b - 1 ) / b);\n}\nlong long ceil_div(long long a, long long b) {\n    assert(b != 0);\n    if (b < 0) { a = -a; b = -b; }\n    if (a >= 0) return (a + b - 1) / b;\n    return -((-a) / b);\n}\n\nlong long ext_gcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) {\n        x = (a >= 0) ? 1 : -1;\n        y = 0;\n        return absll(a);\n    }\n    long long x1, y1;\n    long long g = ext_gcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\ninline bool check_time() {\n    if (time_up) return true;\n    double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    if (elapsed > TIME_LIMIT) time_up = true;\n    return time_up;\n}\n\nvoid reset_state() {\n    fill(pattern_lo.begin(), pattern_lo.end(), 0ULL);\n    fill(pattern_hi.begin(), pattern_hi.end(), 0ULL);\n    lines_current.clear();\n    lines_current.reserve(K);\n    bits_used = 0;\n    piece_info_valid = false;\n}\n\nint score_from_counts(const CountArr &cnt) {\n    int sc = 0;\n    for (int d = 1; d <= 10; ++d) sc += min(demand[d], cnt[d]);\n    return sc;\n}\n\nint recompute_state(CountArr &out_cnt, bool store_info) {\n    out_cnt.fill(0);\n    for (int i = 0; i < N; ++i) {\n        tmp_keys[i] = {pattern_lo[i], pattern_hi[i]};\n        state_order[i] = i;\n    }\n    auto cmp = [&](int lhs, int rhs) {\n        const Key &a = tmp_keys[lhs];\n        const Key &b = tmp_keys[rhs];\n        if (a.hi != b.hi) return a.hi < b.hi;\n        return a.lo < b.lo;\n    };\n    sort(state_order.begin(), state_order.end(), cmp);\n\n    if (store_info) {\n        piece_segments.clear();\n        piece_segments.reserve(N);\n        piece_info_valid = true;\n    } else {\n        piece_info_valid = false;\n    }\n\n    int idx = 0;\n    while (idx < N) {\n        int j = idx + 1;\n        while (j < N) {\n            const Key &ka = tmp_keys[state_order[idx]];\n            const Key &kb = tmp_keys[state_order[j]];\n            if (ka.lo != kb.lo || ka.hi != kb.hi) break;\n            ++j;\n        }\n        int len = j - idx;\n        if (len <= 10) out_cnt[len]++;\n        if (store_info) {\n            piece_segments.push_back({idx, len});\n            int pid = (int)piece_segments.size() - 1;\n            for (int t = idx; t < j; ++t) piece_id[state_order[t]] = pid;\n        }\n        idx = j;\n    }\n    return score_from_counts(out_cnt);\n}\n\nint evaluate_candidate(const Line &line) {\n    if (bits_used >= 128) return -1;\n    for (int i = 0; i < N; ++i) {\n        long long val = line.A * points[i].x + line.B * points[i].y - line.C;\n        if (val == 0) return -1;\n        unsigned long long bit = (val > 0) ? 1ULL : 0ULL;\n        unsigned long long lo = pattern_lo[i];\n        unsigned long long hi = pattern_hi[i];\n        if (bits_used < 64) lo |= bit << bits_used;\n        else hi |= bit << (bits_used - 64);\n        tmp_keys[i] = {lo, hi};\n        eval_order[i] = i;\n    }\n    auto cmp = [&](int lhs, int rhs) {\n        const Key &a = tmp_keys[lhs];\n        const Key &b = tmp_keys[rhs];\n        if (a.hi != b.hi) return a.hi < b.hi;\n        return a.lo < b.lo;\n    };\n    sort(eval_order.begin(), eval_order.end(), cmp);\n    CountArr cnt;\n    cnt.fill(0);\n    int idx = 0;\n    while (idx < N) {\n        int j = idx + 1;\n        while (j < N) {\n            const Key &ka = tmp_keys[eval_order[idx]];\n            const Key &kb = tmp_keys[eval_order[j]];\n            if (ka.lo != kb.lo || ka.hi != kb.hi) break;\n            ++j;\n        }\n        int len = j - idx;\n        if (len <= 10) cnt[len]++;\n        idx = j;\n    }\n    return score_from_counts(cnt);\n}\n\ninline long long rand_ll(long long l, long long r) {\n    unsigned long long range = (unsigned long long)(r - l + 1);\n    return l + (long long)(rng() % range);\n}\n\nbool sample_pair_line_indices(int i, int j, Line &line) {\n    if (i == j) return false;\n    long long a = points[j].x - points[i].x;\n    long long b = points[j].y - points[i].y;\n    long long g = std::gcd(absll(a), absll(b));\n    if (g == 0) return false;\n    a /= g; b /= g;\n    if (a < 0 || (a == 0 && b < 0)) { a = -a; b = -b; }\n    long long vi = a * points[i].x + b * points[i].y;\n    long long vj = a * points[j].x + b * points[j].y;\n    if (vi == vj) return false;\n    long long lo = min(vi, vj);\n    long long hi = max(vi, vj);\n    if (hi - lo < 2) return false;\n    long long c = rand_ll(lo + 1, hi - 1);\n    line = {a, b, c};\n    return true;\n}\n\nbool sample_direction_line(Line &line) {\n    static const pair<int,int> preset[4] = {{1,0},{0,1},{1,1},{1,-1}};\n    for (int iter = 0; iter < 12; ++iter) {\n        long long a = 0, b = 0;\n        int mode = rng() % 6;\n        if (mode < 4) {\n            a = preset[mode].first;\n            b = preset[mode].second;\n        } else {\n            do {\n                a = rand_ll(-DIR_LIMIT, DIR_LIMIT);\n                b = rand_ll(-DIR_LIMIT, DIR_LIMIT);\n            } while (a == 0 && b == 0);\n        }\n        long long g = std::gcd(absll(a), absll(b));\n        if (g == 0) continue;\n        a /= g; b /= g;\n        if (a < 0 || (a == 0 && b < 0)) { a = -a; b = -b; }\n        for (int i = 0; i < N; ++i) proj_values[i] = a * points[i].x + b * points[i].y;\n        sort(proj_values.begin(), proj_values.end());\n        gap_indices.clear();\n        for (int i = 1; i < N; ++i) {\n            if (proj_values[i] - proj_values[i - 1] >= 2) gap_indices.push_back(i);\n        }\n        if (gap_indices.empty()) continue;\n        int pos = gap_indices[rng() % gap_indices.size()];\n        long long left = proj_values[pos - 1];\n        long long right = proj_values[pos];\n        long long c = rand_ll(left + 1, right - 1);\n        line = {a, b, c};\n        return true;\n    }\n    return false;\n}\n\nbool sample_pair_line(Line &line) {\n    if (N < 2) return false;\n    for (int tries = 0; tries < 40; ++tries) {\n        int i = rng() % N;\n        int j = rng() % N;\n        if (i == j) continue;\n        if (sample_pair_line_indices(i, j, line)) return true;\n    }\n    return false;\n}\n\nbool sample_piece_line(Line &line) {\n    if (!piece_info_valid || piece_segments.empty()) return false;\n    for (int tries = 0; tries < 80; ++tries) {\n        int idx = rng() % N;\n        int pid = piece_id[idx];\n        const auto &seg = piece_segments[pid];\n        if (seg.len < 2) continue;\n        int offset = rng() % seg.len;\n        int other = state_order[seg.start + offset];\n        if (other == idx) continue;\n        if (sample_pair_line_indices(idx, other, line)) return true;\n    }\n    return false;\n}\n\nbool generate_candidate_line(Line &line) {\n    for (int attempt = 0; attempt < GENERATE_LINE_ATTEMPTS; ++attempt) {\n        if (check_time()) break;\n        int choice = rng() % 100;\n        bool ok = false;\n        if (piece_info_valid && choice < 50) ok = sample_piece_line(line);\n        if (!ok && choice < 75) ok = sample_pair_line(line);\n        if (!ok) ok = sample_direction_line(line);\n        if (ok) return true;\n    }\n    return false;\n}\n\nvoid apply_line(const Line &line) {\n    for (int i = 0; i < N; ++i) {\n        long long val = line.A * points[i].x + line.B * points[i].y - line.C;\n        if (val == 0) val = 1;\n        unsigned long long bit = (val > 0) ? 1ULL : 0ULL;\n        if (bits_used < 64) pattern_lo[i] |= bit << bits_used;\n        else pattern_hi[i] |= bit << (bits_used - 64);\n    }\n    lines_current.push_back(line);\n    ++bits_used;\n}\n\nint candidate_trials(int iter) {\n    if (iter < 10) return 45;\n    if (iter < 25) return 35;\n    if (iter < 50) return 28;\n    if (iter < 80) return 22;\n    return 18;\n}\n\nstruct AttemptResult {\n    int score;\n    vector<Line> lines;\n};\n\nAttemptResult run_attempt(const vector<Line> &base_lines) {\n    reset_state();\n    for (const auto &ln : base_lines) {\n        if ((int)lines_current.size() >= K) break;\n        apply_line(ln);\n    }\n    CountArr current_counts;\n    int current_score = recompute_state(current_counts, true);\n    int best_score_local = current_score;\n    vector<Line> best_lines_local = lines_current;\n\n    while ((int)lines_current.size() < K && !check_time()) {\n        int trials = candidate_trials((int)lines_current.size());\n        Line chosen{};\n        int chosen_score = INT_MIN;\n        bool found = false;\n        for (int t = 0; t < trials && !check_time(); ++t) {\n            Line cand;\n            if (!generate_candidate_line(cand)) continue;\n            int sc = evaluate_candidate(cand);\n            if (sc < 0) continue;\n            if (!found || sc > chosen_score) {\n                found = true;\n                chosen_score = sc;\n                chosen = cand;\n            }\n        }\n        if (!found) break;\n        apply_line(chosen);\n        current_score = recompute_state(current_counts, true);\n        if (current_score > best_score_local) {\n            best_score_local = current_score;\n            best_lines_local = lines_current;\n        }\n    }\n    return {best_score_local, best_lines_local};\n}\n\nbool line_to_points(const Line &line, array<long long,4> &out) {\n    long long A = line.A, B = line.B, C = line.C;\n    if (A == 0 && B == 0) return false;\n    if (B == 0) {\n        long long x = C / A;\n        long long y1 = -COORD_LIMIT + 1;\n        long long y2 = y1 + 1;\n        out = {{x, y1, x, y2}};\n        return true;\n    }\n    if (A == 0) {\n        long long y = C / B;\n        long long x1 = -COORD_LIMIT + 1;\n        long long x2 = x1 + 1;\n        out = {{x1, y, x2, y}};\n        return true;\n    }\n    long long x0, y0;\n    long long g = ext_gcd(A, B, x0, y0);\n    if (g == 0 || C % g != 0) return false;\n    long long mult = C / g;\n    x0 *= mult;\n    y0 *= mult;\n    auto range_for = [&](long long base, long long coeff) -> pair<long long,long long> {\n        const long long INF = (1LL << 60);\n        if (coeff == 0) {\n            if (absll(base) > COORD_LIMIT) return {1, 0};\n            return {-INF, INF};\n        }\n        long long low = -INF, high = INF;\n        if (coeff > 0) {\n            low = max(low, ceil_div(-COORD_LIMIT - base, coeff));\n            high = min(high, floor_div(COORD_LIMIT - base, coeff));\n        } else {\n            high = min(high, floor_div(-COORD_LIMIT - base, coeff));\n            low = max(low, ceil_div(COORD_LIMIT - base, coeff));\n        }\n        return {low, high};\n    };\n    auto rx = range_for(x0, B);\n    auto ry = range_for(y0, -A);\n    long long low = max(rx.first, ry.first);\n    long long high = min(rx.second, ry.second);\n    if (low > high) return false;\n    auto point_from = [&](long long k) -> pair<long long,long long> {\n        return {x0 + B * k, y0 - A * k};\n    };\n    long long k0 = min(max(0LL, low), high);\n    auto P = point_from(k0);\n    if (absll(P.first) > COORD_LIMIT || absll(P.second) > COORD_LIMIT) {\n        P = point_from(low);\n        k0 = low;\n    }\n    long long qk = (k0 < high) ? k0 + 1 : k0 - 1;\n    auto Q = point_from(qk);\n    if (absll(Q.first) > COORD_LIMIT || absll(Q.second) > COORD_LIMIT || (Q.first == P.first && Q.second == P.second)) {\n        bool found = false;\n        for (long long delta = 1; delta <= 200000 && !found; ++delta) {\n            if (k0 + delta <= high) {\n                auto cand = point_from(k0 + delta);\n                if (absll(cand.first) <= COORD_LIMIT && absll(cand.second) <= COORD_LIMIT && (cand.first != P.first || cand.second != P.second)) {\n                    Q = cand;\n                    found = true;\n                    break;\n                }\n            }\n            if (k0 - delta >= low) {\n                auto cand = point_from(k0 - delta);\n                if (absll(cand.first) <= COORD_LIMIT && absll(cand.second) <= COORD_LIMIT && (cand.first != P.first || cand.second != P.second)) {\n                    Q = cand;\n                    found = true;\n                    break;\n                }\n            }\n        }\n        if (!found) return false;\n    }\n    out = {{P.first, P.second, Q.first, Q.second}};\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K;\n    for (int d = 1; d <= 10; ++d) cin >> demand[d];\n    points.resize(N);\n    for (int i = 0; i < N; ++i) cin >> points[i].x >> points[i].y;\n\n    pattern_lo.assign(N, 0ULL);\n    pattern_hi.assign(N, 0ULL);\n    tmp_keys.resize(N);\n    proj_values.resize(N);\n    state_order.resize(N);\n    eval_order.resize(N);\n    piece_id.resize(N);\n    lines_current.reserve(K);\n    gap_indices.reserve(N);\n\n    start_time = chrono::steady_clock::now();\n\n    int global_best_score = -1;\n    vector<Line> global_best_lines;\n    vector<Line> base_prefix;\n    base_prefix.reserve(K);\n\n    while (!check_time()) {\n        base_prefix.clear();\n        if (!global_best_lines.empty()) {\n            int mode = rng() % 5;\n            if (mode <= 2) {\n                int drop = rng() % (global_best_lines.size() + 1);\n                int keep = (int)global_best_lines.size() - drop;\n                keep = min(keep, K);\n                base_prefix.insert(base_prefix.end(), global_best_lines.begin(), global_best_lines.begin() + keep);\n            } else {\n                int keep_percent = 55 + (rng() % 36);\n                for (const auto &ln : global_best_lines) {\n                    if ((int)base_prefix.size() >= K) break;\n                    if ((int)(rng() % 100) < keep_percent) base_prefix.push_back(ln);\n                }\n            }\n            if ((int)base_prefix.size() >= K) base_prefix.resize(max(0, K - 1));\n        }\n\n        AttemptResult res = run_attempt(base_prefix);\n        if (res.score > global_best_score) {\n            global_best_score = res.score;\n            global_best_lines = res.lines;\n        }\n        if (check_time()) break;\n    }\n\n    vector<array<long long,4>> output;\n    output.reserve(global_best_lines.size());\n    for (const auto &ln : global_best_lines) {\n        array<long long,4> pts;\n        if (!line_to_points(ln, pts)) {\n            pts = {{-COORD_LIMIT + 1, -COORD_LIMIT + 1, -COORD_LIMIT + 2, -COORD_LIMIT + 1}};\n        }\n        output.push_back(pts);\n    }\n\n    cout << output.size() << '\\n';\n    for (auto &v : output) {\n        cout << v[0] << ' ' << v[1] << ' ' << v[2] << ' ' << v[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    struct Candidate {\n        array<int, 8> pts{};\n    };\n    struct NeighborInfo {\n        bool exists = false;\n        bool edgeFree = false;\n        int x = 0;\n        int y = 0;\n    };\n    struct Param {\n        double lambdaStart;\n        double lambdaEnd;\n        double progressPower;\n        double noiseAmp;\n        double timeBudget;\n    };\n    struct RunResult {\n        long long totalWeight = 0;\n        vector<array<int, 8>> ops;\n    };\n\n    int N = 0, M = 0;\n    vector<pair<int, int>> initialDots;\n\n    vector<vector<int>> rowDots, colDots;\n    vector<vector<int>> diagPosDots, diagNegDots;\n    vector<vector<char>> hasDot;\n    vector<vector<char>> usedH, usedV, usedDiagPos, usedDiagNeg;\n    vector<vector<int>> weight;\n    vector<array<int, 8>> currentOperations;\n\n    int center = 0;\n    int diagOffset = 0;\n    int totalCells = 0;\n    int baseInitialCount = 0;\n    int extraCapacity = 1;\n\n    int dotCount = 0;\n    long long totalWeight = 0;\n\n    chrono::steady_clock::time_point globalStart;\n    double absoluteTimeLimit = 4.95;\n    double currentTimeLimit = 4.95;\n    const double safetyMargin = 0.05;\n\n    mt19937 rng;\n    uint64_t baseSeed = 0;\n\n    double elapsed() const {\n        using namespace chrono;\n        return duration<double>(steady_clock::now() - globalStart).count();\n    }\n\n    pair<int, int> uvToXY(int u, int v) const {\n        int x = (u + v) / 2;\n        int y = (u - v) / 2;\n        return {x, y};\n    }\n\n    void insertSorted(vector<int> &vec, int val) {\n        auto it = lower_bound(vec.begin(), vec.end(), val);\n        vec.insert(it, val);\n    }\n\n    bool addDot(int x, int y) {\n        if (hasDot[x][y]) return false;\n        hasDot[x][y] = 1;\n        insertSorted(rowDots[y], x);\n        insertSorted(colDots[x], y);\n        insertSorted(diagPosDots[x - y + diagOffset], x + y);\n        insertSorted(diagNegDots[x + y], x - y);\n        return true;\n    }\n\n    void resetState() {\n        for (auto &row : rowDots) row.clear();\n        for (auto &col : colDots) col.clear();\n        for (auto &diag : diagPosDots) diag.clear();\n        for (auto &diag : diagNegDots) diag.clear();\n        for (int x = 0; x < N; ++x) fill(hasDot[x].begin(), hasDot[x].end(), 0);\n        for (auto &row : usedH) fill(row.begin(), row.end(), 0);\n        for (auto &col : usedV) fill(col.begin(), col.end(), 0);\n        for (auto &row : usedDiagPos) fill(row.begin(), row.end(), 0);\n        for (auto &row : usedDiagNeg) fill(row.begin(), row.end(), 0);\n        currentOperations.clear();\n        currentOperations.reserve(totalCells);\n        dotCount = 0;\n        totalWeight = 0;\n        for (auto [x, y] : initialDots) {\n            if (addDot(x, y)) {\n                ++dotCount;\n                totalWeight += weight[x][y];\n            }\n        }\n        baseInitialCount = dotCount;\n        extraCapacity = max(1, totalCells - baseInitialCount);\n    }\n\n    bool horizontalSegmentUnused(int y, int x1, int x2) const {\n        if (x1 == x2) return false;\n        int l = min(x1, x2);\n        int r = max(x1, x2);\n        for (int x = l; x < r; ++x) {\n            if (usedH[y][x]) return false;\n        }\n        return true;\n    }\n\n    bool verticalSegmentUnused(int x, int y1, int y2) const {\n        if (y1 == y2) return false;\n        int l = min(y1, y2);\n        int r = max(y1, y2);\n        for (int y = l; y < r; ++y) {\n            if (usedV[x][y]) return false;\n        }\n        return true;\n    }\n\n    bool diagPosSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return false;\n        if (x2 < x1) return diagPosSegmentsUnused(x2, y2, x1, y1);\n        if ((x2 - x1) != (y2 - y1)) return false;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            if (usedDiagPos[x1 + i][y1 + i]) return false;\n        }\n        return true;\n    }\n\n    bool diagNegSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return false;\n        if (x2 < x1) return diagNegSegmentsUnused(x2, y2, x1, y1);\n        if ((x2 - x1) != -(y2 - y1)) return false;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            int y = y1 - i;\n            if (y <= 0 || y > N - 1) return false;\n            if (usedDiagNeg[x1 + i][y - 1]) return false;\n        }\n        return true;\n    }\n\n    void markHorizontal(int y, int x1, int x2) {\n        if (x1 == x2) return;\n        int l = min(x1, x2);\n        int r = max(x1, x2);\n        for (int x = l; x < r; ++x) usedH[y][x] = 1;\n    }\n\n    void markVertical(int x, int y1, int y2) {\n        if (y1 == y2) return;\n        int l = min(y1, y2);\n        int r = max(y1, y2);\n        for (int y = l; y < r; ++y) usedV[x][y] = 1;\n    }\n\n    void markDiagPos(int x1, int y1, int x2, int y2) {\n        if (x2 < x1) {\n            markDiagPos(x2, y2, x1, y1);\n            return;\n        }\n        if ((x2 - x1) != (y2 - y1)) return;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) usedDiagPos[x1 + i][y1 + i] = 1;\n    }\n\n    void markDiagNeg(int x1, int y1, int x2, int y2) {\n        if (x2 < x1) {\n            markDiagNeg(x2, y2, x1, y1);\n            return;\n        }\n        if ((x2 - x1) != -(y2 - y1)) return;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            int y = y1 - i;\n            if (y > 0) usedDiagNeg[x1 + i][y - 1] = 1;\n        }\n    }\n\n    bool edgeSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return verticalSegmentUnused(x1, y1, y2);\n        if (y1 == y2) return horizontalSegmentUnused(y1, x1, x2);\n        if (x2 - x1 == y2 - y1) return diagPosSegmentsUnused(x1, y1, x2, y2);\n        if (x2 - x1 == -(y2 - y1)) return diagNegSegmentsUnused(x1, y1, x2, y2);\n        return false;\n    }\n\n    void markEdge(int x1, int y1, int x2, int y2) {\n        if (x1 == x2) markVertical(x1, y1, y2);\n        else if (y1 == y2) markHorizontal(y1, x1, x2);\n        else if (x2 - x1 == y2 - y1) markDiagPos(x1, y1, x2, y2);\n        else if (x2 - x1 == -(y2 - y1)) markDiagNeg(x1, y1, x2, y2);\n    }\n\n    bool edgeInteriorClear(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2 && y1 == y2) return false;\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n        int steps = max(abs(dx), abs(dy));\n        if (steps <= 1) return true;\n        int sx = (dx > 0) - (dx < 0);\n        int sy = (dy > 0) - (dy < 0);\n        int cx = x1 + sx;\n        int cy = y1 + sy;\n        for (int i = 1; i < steps; ++i) {\n            if (cx < 0 || cx >= N || cy < 0 || cy >= N) return false;\n            if (hasDot[cx][cy]) return false;\n            cx += sx;\n            cy += sy;\n        }\n        return true;\n    }\n\n    void applyCandidate(const Candidate &cand) {\n        const auto &pts = cand.pts;\n        for (int i = 0; i < 4; ++i) {\n            int j = (i + 1) & 3;\n            markEdge(pts[2 * i], pts[2 * i + 1], pts[2 * j], pts[2 * j + 1]);\n        }\n        int dx = pts[0], dy = pts[1];\n        if (addDot(dx, dy)) {\n            ++dotCount;\n            totalWeight += weight[dx][dy];\n        }\n        currentOperations.push_back(pts);\n    }\n\n    bool findBestCandidate(double lambda, double noiseAmp, Candidate &best, bool &timeoutFlag) {\n        const double NEG_INF = -1e100;\n        double bestScore = NEG_INF;\n        double bestPerim = 1e100;\n        int bestLen = INT_MAX;\n        Candidate bestCand;\n        bool found = false;\n        timeoutFlag = false;\n\n        double amp = max(0.0, noiseAmp);\n        uniform_real_distribution<double> noiseDist(-amp, amp);\n        auto noise = [&]() -> double {\n            return amp > 0.0 ? noiseDist(rng) : 0.0;\n        };\n\n        auto updateBest = [&](const array<int, 8> &seq, double perim, int len, double score) {\n            if (!found || score > bestScore + 1e-9 ||\n                (abs(score - bestScore) <= 1e-9 &&\n                 (perim < bestPerim - 1e-9 ||\n                  (abs(perim - bestPerim) <= 1e-9 && len < bestLen)))) {\n                found = true;\n                bestScore = score;\n                bestPerim = perim;\n                bestLen = len;\n                bestCand.pts = seq;\n            }\n        };\n\n        bool stop = false;\n        int processed = 0;\n\n        for (int y = 0; y < N && !stop; ++y) {\n            const auto &row = rowDots[y];\n            int rowSize = (int)row.size();\n            if (rowSize == 0) continue;\n            for (int idx = 0; idx < rowSize && !stop; ++idx) {\n                if ((processed & 63) == 0 && elapsed() > currentTimeLimit) {\n                    timeoutFlag = true;\n                    stop = true;\n                    break;\n                }\n                ++processed;\n                int ax = row[idx];\n                int ay = y;\n\n                NeighborInfo left, right, up, down, ne, sw, nw, se;\n\n                if (idx > 0) {\n                    left.exists = true;\n                    left.x = row[idx - 1];\n                    left.y = ay;\n                    left.edgeFree = edgeSegmentsUnused(ax, ay, left.x, left.y);\n                }\n                if (idx + 1 < rowSize) {\n                    right.exists = true;\n                    right.x = row[idx + 1];\n                    right.y = ay;\n                    right.edgeFree = edgeSegmentsUnused(ax, ay, right.x, right.y);\n                }\n\n                const auto &col = colDots[ax];\n                auto itCol = lower_bound(col.begin(), col.end(), ay);\n                if (itCol == col.end() || *itCol != ay) continue;\n                int posCol = int(itCol - col.begin());\n                if (posCol > 0) {\n                    down.exists = true;\n                    down.x = ax;\n                    down.y = col[posCol - 1];\n                    down.edgeFree = edgeSegmentsUnused(ax, ay, down.x, down.y);\n                }\n                if (posCol + 1 < (int)col.size()) {\n                    up.exists = true;\n                    up.x = ax;\n                    up.y = col[posCol + 1];\n                    up.edgeFree = edgeSegmentsUnused(ax, ay, up.x, up.y);\n                }\n\n                int uVal = ax + ay;\n                int vVal = ax - ay;\n\n                auto &diagV = diagPosDots[vVal + diagOffset];\n                auto itV = lower_bound(diagV.begin(), diagV.end(), uVal);\n                if (itV != diagV.end() && *itV == uVal) {\n                    int posV = int(itV - diagV.begin());\n                    if (posV > 0) {\n                        int uNeighbor = diagV[posV - 1];\n                        auto [nx, ny] = uvToXY(uNeighbor, vVal);\n                        sw.exists = true;\n                        sw.x = nx;\n                        sw.y = ny;\n                        sw.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                    if (posV + 1 < (int)diagV.size()) {\n                        int uNeighbor = diagV[posV + 1];\n                        auto [nx, ny] = uvToXY(uNeighbor, vVal);\n                        ne.exists = true;\n                        ne.x = nx;\n                        ne.y = ny;\n                        ne.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                }\n\n                auto &diagU = diagNegDots[uVal];\n                auto itU = lower_bound(diagU.begin(), diagU.end(), vVal);\n                if (itU != diagU.end() && *itU == vVal) {\n                    int posU = int(itU - diagU.begin());\n                    if (posU > 0) {\n                        int vNeighbor = diagU[posU - 1];\n                        auto [nx, ny] = uvToXY(uVal, vNeighbor);\n                        nw.exists = true;\n                        nw.x = nx;\n                        nw.y = ny;\n                        nw.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                    if (posU + 1 < (int)diagU.size()) {\n                        int vNeighbor = diagU[posU + 1];\n                        auto [nx, ny] = uvToXY(uVal, vNeighbor);\n                        se.exists = true;\n                        se.x = nx;\n                        se.y = ny;\n                        se.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                }\n\n                auto considerAxis = [&](const NeighborInfo &vert, const NeighborInfo &horiz) {\n                    if (!vert.exists || !horiz.exists) return;\n                    if (!vert.edgeFree || !horiz.edgeFree) return;\n                    int dx = horiz.x;\n                    int dy = vert.y;\n                    if (dx < 0 || dx >= N || dy < 0 || dy >= N) return;\n                    if (hasDot[dx][dy]) return;\n                    if (!edgeInteriorClear(vert.x, vert.y, dx, dy)) return;\n                    if (!edgeInteriorClear(horiz.x, horiz.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(vert.x, vert.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(horiz.x, horiz.y, dx, dy)) return;\n                    int width = abs(dx - ax);\n                    int height = abs(dy - ay);\n                    if (width <= 0 || height <= 0) return;\n                    double perim = 2.0 * (width + height);\n                    double score = (double)weight[dx][dy] - lambda * perim + noise();\n                    int len = width + height;\n                    array<int, 8> seq = {dx, dy,\n                                         vert.x, vert.y,\n                                         ax, ay,\n                                         horiz.x, horiz.y};\n                    updateBest(seq, perim, len, score);\n                };\n\n                auto considerDiag = [&](const NeighborInfo &diagP, const NeighborInfo &diagN) {\n                    if (!diagP.exists || !diagN.exists) return;\n                    if (!diagP.edgeFree || !diagN.edgeFree) return;\n                    int dx = diagP.x + (diagN.x - ax);\n                    int dy = diagP.y + (diagN.y - ay);\n                    if (dx < 0 || dx >= N || dy < 0 || dy >= N) return;\n                    if (hasDot[dx][dy]) return;\n                    if (!edgeInteriorClear(diagP.x, diagP.y, dx, dy)) return;\n                    if (!edgeInteriorClear(diagN.x, diagN.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(diagP.x, diagP.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(diagN.x, diagN.y, dx, dy)) return;\n                    int len1 = abs(diagP.x - ax);\n                    int len2 = abs(diagN.x - ax);\n                    if (len1 <= 0 || len2 <= 0) return;\n                    double perim = 2.0 * (len1 + len2);\n                    double score = (double)weight[dx][dy] - lambda * perim + noise();\n                    int len = len1 + len2;\n                    array<int, 8> seq = {dx, dy,\n                                         diagP.x, diagP.y,\n                                         ax, ay,\n                                         diagN.x, diagN.y};\n                    updateBest(seq, perim, len, score);\n                };\n\n                considerAxis(up, right);\n                considerAxis(up, left);\n                considerAxis(down, right);\n                considerAxis(down, left);\n\n                considerDiag(ne, nw);\n                considerDiag(ne, se);\n                considerDiag(sw, nw);\n                considerDiag(sw, se);\n            }\n        }\n\n        if (!found) return false;\n        best = bestCand;\n        return true;\n    }\n\n    RunResult runOne(const Param &param, double budget, uint64_t seedShift) {\n        resetState();\n        rng.seed(baseSeed + seedShift * 0x9e3779b97f4a7c15ULL + 0x7f4a7c15ULL);\n        double now = elapsed();\n        currentTimeLimit = min(absoluteTimeLimit, now + max(0.0, budget));\n\n        while (true) {\n            double cur = elapsed();\n            if (cur > currentTimeLimit) break;\n            int gained = dotCount - baseInitialCount;\n            if (gained < 0) gained = 0;\n            double progress = (double)gained / (double)extraCapacity;\n            progress = min(1.0, max(0.0, progress));\n            double factor = (param.progressPower == 1.0)\n                                ? progress\n                                : pow(progress, param.progressPower);\n            double lambda = param.lambdaStart +\n                            (param.lambdaEnd - param.lambdaStart) * factor;\n\n            Candidate cand;\n            bool timeout = false;\n            if (!findBestCandidate(lambda, param.noiseAmp, cand, timeout)) break;\n            applyCandidate(cand);\n            if (timeout) break;\n        }\n\n        RunResult res;\n        res.totalWeight = totalWeight;\n        res.ops = currentOperations;\n        return res;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M)) return;\n        initialDots.resize(M);\n        for (int i = 0; i < M; ++i) {\n            cin >> initialDots[i].first >> initialDots[i].second;\n        }\n\n        center = (N - 1) / 2;\n        diagOffset = N - 1;\n        totalCells = N * N;\n\n        weight.assign(N, vector<int>(N, 0));\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                int dx = x - center;\n                int dy = y - center;\n                weight[x][y] = dx * dx + dy * dy + 1;\n            }\n        }\n\n        rowDots.assign(N, {});\n        colDots.assign(N, {});\n        diagPosDots.assign(2 * N, {});\n        diagNegDots.assign(2 * N, {});\n        hasDot.assign(N, vector<char>(N, 0));\n        int seg = max(1, N - 1);\n        usedH.assign(N, vector<char>(seg, 0));\n        usedV.assign(N, vector<char>(seg, 0));\n        usedDiagPos.assign(seg, vector<char>(seg, 0));\n        usedDiagNeg.assign(seg, vector<char>(seg, 0));\n        currentOperations.reserve(totalCells);\n\n        baseSeed = 1469598103934665603ULL;\n        baseSeed ^= (uint64_t)(N + 0x9e3779b97f4a7c15ULL + (baseSeed << 6) + (baseSeed >> 2));\n        baseSeed ^= (uint64_t)(M + 0x9e3779b97f4a7c15ULL + (baseSeed << 6) + (baseSeed >> 2));\n        for (auto [x, y] : initialDots) {\n            uint64_t v = (uint64_t)(x + 1) * 1000003ULL + (uint64_t)(y + 1) * 998244353ULL;\n            baseSeed ^= v + 0x9e3779b97f4a7c15ULL + (baseSeed << 6) + (baseSeed >> 2);\n        }\n\n        globalStart = chrono::steady_clock::now();\n\n        vector<Param> params = {\n            {55.0, -5.0, 0.45, 0.6, 1.5},\n            {38.0, -18.0, 0.90, 1.4, 1.2},\n            {70.0, 12.0, 0.50, 0.3, 1.0},\n            {24.0, -28.0, 1.20, 2.2, 0.8}\n        };\n\n        vector<array<int, 8>> bestOps;\n        long long bestWeight = -1;\n        bool ranAny = false;\n\n        for (int idx = 0; idx < (int)params.size(); ++idx) {\n            double now = elapsed();\n            double timeLeft = absoluteTimeLimit - now;\n            if (timeLeft <= safetyMargin) break;\n            double available = max(0.0, timeLeft - safetyMargin);\n            double budget = min(params[idx].timeBudget, available);\n            if (budget <= 0.02) break;\n            RunResult res = runOne(params[idx], budget, idx + 1);\n            ranAny = true;\n            if (res.totalWeight > bestWeight) {\n                bestWeight = res.totalWeight;\n                bestOps = move(res.ops);\n            }\n        }\n\n        if (!ranAny) {\n            double now = elapsed();\n            double timeLeft = max(0.02, absoluteTimeLimit - now - 0.01);\n            RunResult res = runOne(params.front(), timeLeft, params.size() + 5);\n            bestOps = move(res.ops);\n        }\n\n        cout << bestOps.size() << '\\n';\n        for (auto &op : bestOps) {\n            for (int i = 0; i < 8; ++i) {\n                if (i) cout << ' ';\n                cout << op[i];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct MinCostFlow {\n    struct Edge { int to, rev, cap, cost; };\n    int N;\n    vector<vector<Edge>> graph;\n    MinCostFlow(int n = 0) : N(n), graph(n) {}\n    void add_edge(int fr, int to, int cap, int cost) {\n        Edge f{to, (int)graph[to].size(), cap, cost};\n        Edge b{fr, (int)graph[fr].size(), 0, -cost};\n        graph[fr].push_back(f);\n        graph[to].push_back(b);\n    }\n    pair<int,long long> min_cost_flow(int s, int t, int maxf) {\n        const long long INF = (1LL<<60);\n        vector<long long> potential(N, 0), dist(N);\n        vector<int> prevv(N), preve(N);\n        int flow = 0;\n        long long cost = 0;\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INF);\n            dist[s] = 0;\n            priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n            pq.emplace(0LL, s);\n            while (!pq.empty()) {\n                auto [d,v] = pq.top(); pq.pop();\n                if (dist[v] < d) continue;\n                for (int i = 0; i < (int)graph[v].size(); ++i) {\n                    const Edge &e = graph[v][i];\n                    if (e.cap <= 0) continue;\n                    long long nd = dist[v] + e.cost + potential[v] - potential[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        prevv[e.to] = v;\n                        preve[e.to] = i;\n                        pq.emplace(nd, e.to);\n                    }\n                }\n            }\n            if (dist[t] == INF) break;\n            for (int v = 0; v < N; ++v) if (dist[v] < INF) potential[v] += dist[v];\n            int d = maxf - flow;\n            for (int v = t; v != s; v = prevv[v]) {\n                d = min(d, graph[prevv[v]][preve[v]].cap);\n            }\n            flow += d;\n            cost += 1LL * d * potential[t];\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                e.cap -= d;\n                graph[v][e.rev].cap += d;\n            }\n        }\n        return {flow, cost};\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 10;\n    using Grid = array<array<uint8_t, N>, N>;\n    static constexpr char DIRS[4] = {'F', 'B', 'L', 'R'};\n    static constexpr double ZONE_ALPHA = 0.35;\n    static constexpr double W_COMPONENT = 1.0;\n    static constexpr double W_ADJ_SAME = 18.0;\n    static constexpr double W_ADJ_DIFF = 13.0;\n    static constexpr double W_ZONE = 60.0;\n    static constexpr double W_LARGEST = 12.0;\n    static constexpr double W_COMP_COUNT = 20.0;\n    static constexpr double W_ZONE_HIT = 6.0;\n    static constexpr double W_ZONE_DIST = 1.0;\n    static constexpr double LOOKAHEAD_WEIGHT = 0.35;\n    static constexpr double REVERSE_PENALTY = 0.35;\n    static constexpr int FULL_LOOKAHEAD_THRESHOLD = 24;\n\n    vector<int> flavors = vector<int>(100);\n    array<int, 3> totalCounts{};\n    Grid board{};\n    int placed = 0;\n    mt19937 rng;\n    array<array<int8_t, N>, N> targetZone{};\n    array<array<array<uint8_t, N>, N>, 3> zoneDistance{};\n    array<int, 3> zoneCellCount{};\n    array<pair<int, int>, N * N> cellOrder{};\n    bool hasLastMove = false;\n    char lastMove = 'F';\n\n    Solver() {\n        for (int idx = 0; idx < N * N; ++idx) {\n            cellOrder[idx] = {idx / N, idx % N};\n        }\n    }\n\n    bool readInput() {\n        totalCounts.fill(0);\n        for (int i = 0; i < 100; ++i) {\n            if (!(cin >> flavors[i])) return false;\n            if (1 <= flavors[i] && flavors[i] <= 3) {\n                totalCounts[flavors[i] - 1]++;\n            }\n        }\n        uint32_t seed = 712387u;\n        for (int i = 0; i < 100; ++i) {\n            seed = seed * 1000003u + static_cast<uint32_t>(flavors[i]) * 239017u + i;\n        }\n        rng.seed(seed);\n        computeZones();\n        return true;\n    }\n\n    void solve() {\n        for (auto &row : board) row.fill(0);\n        placed = 0;\n        hasLastMove = false;\n        lastMove = 'F';\n        for (int t = 0; t < 100; ++t) {\n            int p;\n            if (!(cin >> p)) return;\n            placeCandy(p, flavors[t]);\n            ++placed;\n            Decision dec = chooseMove(placed);\n            board = dec.board;\n            lastMove = dec.dir;\n            hasLastMove = true;\n            cout << dec.dir << '\\n' << flush;\n        }\n    }\n\n    void placeCandy(int idx, int flavor) {\n        int target = idx;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (board[r][c] == 0) {\n                    if (--target == 0) {\n                        board[r][c] = static_cast<uint8_t>(flavor);\n                        return;\n                    }\n                }\n            }\n        }\n    }\n\n    void applyTilt(Grid &g, char dir) const {\n        if (dir == 'F') {\n            for (int c = 0; c < N; ++c) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int r = 0; r < N; ++r) if (g[r][c]) tmp[k++] = g[r][c];\n                for (int r = 0; r < N; ++r) g[r][c] = (r < k ? tmp[r] : 0);\n            }\n        } else if (dir == 'B') {\n            for (int c = 0; c < N; ++c) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int r = 0; r < N; ++r) if (g[r][c]) tmp[k++] = g[r][c];\n                int idx = k - 1;\n                for (int r = N - 1; r >= 0; --r) g[r][c] = (idx >= 0 ? tmp[idx--] : 0);\n            }\n        } else if (dir == 'L') {\n            for (int r = 0; r < N; ++r) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int c = 0; c < N; ++c) if (g[r][c]) tmp[k++] = g[r][c];\n                for (int c = 0; c < N; ++c) g[r][c] = (c < k ? tmp[c] : 0);\n            }\n        } else { // 'R'\n            for (int r = 0; r < N; ++r) {\n                array<uint8_t, N> tmp{};\n                int k = 0;\n                for (int c = 0; c < N; ++c) if (g[r][c]) tmp[k++] = g[r][c];\n                int idx = k - 1;\n                for (int c = N - 1; c >= 0; --c) g[r][c] = (idx >= 0 ? tmp[idx--] : 0);\n            }\n        }\n    }\n\n    struct Decision {\n        char dir = 'F';\n        Grid board{};\n    };\n\n    Decision chooseMove(int filled) {\n        Decision best;\n        bool first = true;\n        double bestScore = -1e100;\n        for (char dir : DIRS) {\n            Grid cand = board;\n            applyTilt(cand, dir);\n            double score = evaluateWithLookahead(cand, filled);\n            if (hasLastMove && isOpposite(dir, lastMove)) {\n                score -= REVERSE_PENALTY;\n            }\n            score += randomNoise();\n            if (first || score > bestScore) {\n                first = false;\n                bestScore = score;\n                best.dir = dir;\n                best.board = cand;\n            }\n        }\n        return best;\n    }\n\n    bool isOpposite(char a, char b) const {\n        return (a == 'F' && b == 'B') || (a == 'B' && b == 'F') ||\n               (a == 'L' && b == 'R') || (a == 'R' && b == 'L');\n    }\n\n    double evaluateWithLookahead(const Grid &state, int filled) {\n        double base = evaluate(state, filled);\n        if (filled >= 100 || LOOKAHEAD_WEIGHT <= 1e-9) return base;\n        int nextIdx = filled;\n        if (nextIdx >= (int)flavors.size()) return base;\n\n        vector<int> empties;\n        empties.reserve(N * N);\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                if (state[r][c] == 0)\n                    empties.push_back(r * N + c);\n        if (empties.empty()) return base;\n\n        int emptiesSz = (int)empties.size();\n        bool useAll = (emptiesSz <= FULL_LOOKAHEAD_THRESHOLD);\n        int sampleCount;\n        if (useAll) {\n            sampleCount = emptiesSz;\n        } else {\n            int limit = getSampleLimit(filled);\n            sampleCount = min(limit, emptiesSz);\n            for (int i = 0; i < sampleCount; ++i) {\n                int span = emptiesSz - i;\n                int j = i + (int)(rng() % span);\n                swap(empties[i], empties[j]);\n            }\n        }\n\n        const int nextFlavor = flavors[nextIdx];\n        double accum = 0.0;\n        for (int i = 0; i < sampleCount; ++i) {\n            int idx = empties[i];\n            int r = idx / N;\n            int c = idx % N;\n            Grid tmp = state;\n            tmp[r][c] = static_cast<uint8_t>(nextFlavor);\n            double bestNext = -1e100;\n            for (char dir : DIRS) {\n                Grid fut = tmp;\n                applyTilt(fut, dir);\n                double val = evaluate(fut, filled + 1);\n                if (val > bestNext) bestNext = val;\n            }\n            accum += bestNext;\n        }\n        double avg = accum / sampleCount;\n\n        double fillRatio = static_cast<double>(filled) / 100.0;\n        double adapt = 0.35 + 0.65 * (1.0 - fillRatio);\n        double coverage = useAll ? 1.0 : static_cast<double>(sampleCount) / emptiesSz;\n        double coverageFactor = sqrt(max(1e-9, coverage));\n        double lookFactor = LOOKAHEAD_WEIGHT * adapt * coverageFactor;\n        if (lookFactor > 0.5) lookFactor = 0.5;\n\n        return base * (1.0 - lookFactor) + avg * lookFactor;\n    }\n\n    int getSampleLimit(int filled) const {\n        if (filled < 25) return 28;\n        if (filled < 50) return 20;\n        if (filled < 75) return 14;\n        if (filled < 90) return 10;\n        return 8;\n    }\n\n    double evaluate(const Grid &g, int filled) const {\n        array<int,3> cnt = {0,0,0};\n        array<double,3> sumR = {0,0,0};\n        array<double,3> sumC = {0,0,0};\n        double sameAdj = 0.0, diffAdj = 0.0;\n        double zoneHit = 0.0, zoneDistSum = 0.0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int val = g[r][c];\n                if (!val) continue;\n                int idx = val - 1;\n                cnt[idx]++;\n                sumR[idx] += r;\n                sumC[idx] += c;\n                if (targetZone[r][c] == idx) zoneHit += 1.0;\n                zoneDistSum += zoneDistance[idx][r][c];\n                if (r + 1 < N && g[r + 1][c]) {\n                    if (g[r + 1][c] == val) sameAdj += 1.0;\n                    else diffAdj += 1.0;\n                }\n                if (c + 1 < N && g[r][c + 1]) {\n                    if (g[r][c + 1] == val) sameAdj += 1.0;\n                    else diffAdj += 1.0;\n                }\n            }\n        }\n\n        array<double,3> meanR = {0,0,0}, meanC = {0,0,0};\n        for (int i = 0; i < 3; ++i) {\n            if (cnt[i]) {\n                meanR[i] = sumR[i] / cnt[i];\n                meanC[i] = sumC[i] / cnt[i];\n            }\n        }\n\n        double centroidScore = 0.0;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int val = g[r][c];\n                if (!val) continue;\n                int idx = val - 1;\n                double dr = r - meanR[idx];\n                double dc = c - meanC[idx];\n                double dist2 = dr * dr + dc * dc;\n                centroidScore += 1.0 / (1.0 + ZONE_ALPHA * dist2);\n            }\n        }\n\n        array<array<uint8_t, N>, N> vis{};\n        array<int,3> compCounts = {0,0,0};\n        array<int,3> largest = {0,0,0};\n        double compScore = 0.0;\n        const int dr4[4] = {-1, 1, 0, 0};\n        const int dc4[4] = {0, 0, -1, 1};\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!g[r][c] || vis[r][c]) continue;\n                int color = g[r][c];\n                queue<pair<int,int>> q;\n                q.emplace(r,c);\n                vis[r][c] = 1;\n                int sz = 0;\n                while (!q.empty()) {\n                    auto [cr,cc] = q.front(); q.pop();\n                    ++sz;\n                    for (int d = 0; d < 4; ++d) {\n                        int nr = cr + dr4[d];\n                        int nc = cc + dc4[d];\n                        if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                        if (vis[nr][nc] || g[nr][nc] != color) continue;\n                        vis[nr][nc] = 1;\n                        q.emplace(nr,nc);\n                    }\n                }\n                compScore += 1.0 * sz * sz;\n                int idx = color - 1;\n                compCounts[idx]++;\n                largest[idx] = max(largest[idx], sz);\n            }\n        }\n\n        int compCountSum = compCounts[0] + compCounts[1] + compCounts[2];\n        int largestSum = largest[0] + largest[1] + largest[2];\n\n        double fillRatio = (filled <= 0 ? 0.0 : static_cast<double>(filled) / 100.0);\n        double zoneWeight = W_ZONE * (0.4 + 0.6 * (1.0 - fillRatio));\n        double adjFactor = 0.4 + 0.6 * fillRatio;\n        double adjSameWeight = W_ADJ_SAME * adjFactor;\n        double adjDiffWeight = W_ADJ_DIFF * adjFactor;\n        double compCountWeight = W_COMP_COUNT * fillRatio * fillRatio;\n        double zoneAlignWeight = W_ZONE_HIT * (0.6 + 0.4 * (1.0 - fillRatio));\n        double zoneDistWeight = W_ZONE_DIST * (0.5 + 0.5 * fillRatio);\n\n        double score = W_COMPONENT * compScore\n                     + adjSameWeight * sameAdj\n                     - adjDiffWeight * diffAdj\n                     + zoneWeight * centroidScore\n                     + W_LARGEST * largestSum\n                     - compCountWeight * compCountSum\n                     + zoneAlignWeight * zoneHit\n                     - zoneDistWeight * zoneDistSum;\n\n        return score;\n    }\n\n    double randomNoise() {\n        return (static_cast<double>(rng() & 0xffffu) / 65535.0 - 0.5) * 1e-3;\n    }\n\n    void computeZones() {\n        ZoneGrid zone{};\n        if (!buildBestZone(zone)) {\n            fallbackZone(zone);\n        }\n        targetZone = zone;\n        zoneCellCount.fill(0);\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                zoneCellCount[targetZone[r][c]]++;\n        computeZoneDistances();\n    }\n\n    using ZoneGrid = array<array<int8_t, N>, N>;\n\n    bool buildBestZone(ZoneGrid &outZone) {\n        vector<array<pair<int,int>,3>> anchorSets;\n        auto addSet = [&](initializer_list<pair<int,int>> pts) {\n            if (pts.size() != 3) return;\n            array<pair<int,int>,3> arr{};\n            int idx = 0;\n            for (auto pt : pts) arr[idx++] = pt;\n            anchorSets.push_back(arr);\n        };\n        addSet({{1,1},{1,8},{7,4}});\n        addSet({{1,1},{8,1},{4,8}});\n        addSet({{1,8},{8,8},{4,1}});\n        addSet({{8,1},{8,8},{1,4}});\n        addSet({{0,0},{9,0},{4,9}});\n        addSet({{0,0},{0,9},{9,4}});\n        addSet({{0,4},{9,4},{4,9}});\n        addSet({{4,0},{4,9},{8,5}});\n        addSet({{2,2},{2,7},{7,5}});\n        addSet({{2,2},{7,2},{5,7}});\n        addSet({{1,1},{8,8},{5,5}});\n        addSet({{8,1},{1,8},{5,5}});\n\n        bool success = false;\n        long long bestCost = (1LL<<60);\n        ZoneGrid bestZone{};\n\n        for (const auto &set : anchorSets) {\n            array<int,3> perm = {0,1,2};\n            do {\n                array<pair<int,int>,3> anchors{};\n                for (int i = 0; i < 3; ++i) anchors[perm[i]] = set[i];\n                ZoneGrid zoneCand{};\n                long long cost;\n                if (!buildZoneForAnchors(anchors, zoneCand, cost)) continue;\n                if (!success || cost < bestCost) {\n                    success = true;\n                    bestCost = cost;\n                    bestZone = zoneCand;\n                }\n            } while (next_permutation(perm.begin(), perm.end()));\n        }\n        if (success) outZone = bestZone;\n        return success;\n    }\n\n    bool buildZoneForAnchors(const array<pair<int,int>,3> &anchors,\n                             ZoneGrid &outZone, long long &outCost) {\n        const int totalCells = N * N;\n        const int SRC = 0;\n        const int COLOR_BASE = 1;\n        const int CELL_BASE = COLOR_BASE + 3;\n        const int SINK = CELL_BASE + totalCells;\n        MinCostFlow mcf(SINK + 1);\n        vector<vector<int>> edgeIndex(3, vector<int>(totalCells, -1));\n\n        int totalCandy = totalCounts[0] + totalCounts[1] + totalCounts[2];\n        if (totalCandy == 0) return false;\n\n        for (int color = 0; color < 3; ++color) {\n            mcf.add_edge(SRC, COLOR_BASE + color, totalCounts[color], 0);\n        }\n        for (int color = 0; color < 3; ++color) {\n            if (totalCounts[color] == 0) continue;\n            auto [ar, ac] = anchors[color];\n            ar = clamp(ar, 0, N - 1);\n            ac = clamp(ac, 0, N - 1);\n            int node = COLOR_BASE + color;\n            for (int idx = 0; idx < totalCells; ++idx) {\n                auto [r,c] = cellOrder[idx];\n                int cost = abs(r - ar) + abs(c - ac);\n                int pos = (int)mcf.graph[node].size();\n                mcf.add_edge(node, CELL_BASE + idx, 1, cost);\n                edgeIndex[color][idx] = pos;\n            }\n        }\n        for (int idx = 0; idx < totalCells; ++idx) {\n            mcf.add_edge(CELL_BASE + idx, SINK, 1, 0);\n        }\n\n        auto res = mcf.min_cost_flow(SRC, SINK, totalCandy);\n        if (res.first != totalCandy) return false;\n        outCost = res.second;\n\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                outZone[r][c] = 0;\n\n        for (int idx = 0; idx < totalCells; ++idx) {\n            int assigned = -1;\n            for (int color = 0; color < 3; ++color) {\n                int pos = edgeIndex[color][idx];\n                if (pos == -1) continue;\n                if (mcf.graph[COLOR_BASE + color][pos].cap == 0) {\n                    assigned = color;\n                    break;\n                }\n            }\n            if (assigned == -1) assigned = 0;\n            auto [r,c] = cellOrder[idx];\n            outZone[r][c] = static_cast<int8_t>(assigned);\n        }\n        return true;\n    }\n\n    void fallbackZone(ZoneGrid &zone) {\n        array<int,3> remaining = totalCounts;\n        int color = 0;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                while (color < 3 && remaining[color] == 0) ++color;\n                if (color >= 3) color = 2;\n                zone[r][c] = static_cast<int8_t>(color);\n                if (remaining[color] > 0) --remaining[color];\n            }\n        }\n    }\n\n    void computeZoneDistances() {\n        const int INF = 1e9;\n        for (int color = 0; color < 3; ++color) {\n            if (zoneCellCount[color] == 0) {\n                for (int r = 0; r < N; ++r)\n                    for (int c = 0; c < N; ++c)\n                        zoneDistance[color][r][c] = 0;\n                continue;\n            }\n            array<array<int, N>, N> dist;\n            for (int r = 0; r < N; ++r)\n                for (int c = 0; c < N; ++c)\n                    dist[r][c] = INF;\n            queue<pair<int,int>> q;\n            for (int r = 0; r < N; ++r) {\n                for (int c = 0; c < N; ++c) {\n                    if (targetZone[r][c] == color) {\n                        dist[r][c] = 0;\n                        q.emplace(r,c);\n                    }\n                }\n            }\n            while (!q.empty()) {\n                auto [r,c] = q.front(); q.pop();\n                for (int d = 0; d < 4; ++d) {\n                    int nr = r + (d == 0 ? -1 : d == 1 ? 1 : 0);\n                    int nc = c + (d == 2 ? -1 : d == 3 ? 1 : 0);\n                    if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                    if (dist[nr][nc] > dist[r][c] + 1) {\n                        dist[nr][nc] = dist[r][c] + 1;\n                        q.emplace(nr,nc);\n                    }\n                }\n            }\n            for (int r = 0; r < N; ++r) {\n                for (int c = 0; c < N; ++c) {\n                    int d = dist[r][c];\n                    if (d == INF) d = 250;\n                    if (d > 250) d = 250;\n                    zoneDistance[color][r][c] = static_cast<uint8_t>(d);\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    if (!solver.readInput()) return 0;\n    solver.solve();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Hungarian {\n    int n;\n    vector<vector<int>> cost;\n    vector<int> assignment;\n    Hungarian(int n=0){ init(n); }\n    void init(int m){\n        n = m;\n        cost.assign(n, vector<int>(n, 0));\n        assignment.assign(n, -1);\n    }\n    void solve(){\n        const int INF = 1e9;\n        vector<int> u(n+1,0), v(n+1,0), p(n+1,0), way(n+1,0);\n        for(int i=1;i<=n;i++){\n            p[0]=i;\n            vector<int> minv(n+1, INF);\n            vector<char> used(n+1,false);\n            int j0=0;\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> ans(n,-1);\n        for(int j=1;j<=n;j++) if(p[j]>0) ans[p[j]-1]=j-1;\n        assignment=ans;\n    }\n};\n\nstruct Designer {\n    static constexpr int N = 60;\n    static constexpr int A = 32;\n    static constexpr int P = N - A;\n\n    int payloadEdges;\n    int payloadWords;\n    vector<vector<int>> anchorAdj;\n    vector<uint64_t> anchorAdjMask;\n    vector<uint64_t> payloadAnchorMask;\n    vector<int> degAA_can, degAP_can;\n    vector<vector<uint64_t>> graphCodes;\n    vector<pair<int,int>> payloadPairs;\n    vector<vector<int>> payloadPairIdx;\n    mt19937_64 rng;\n    uint64_t seedBase = 0;\n\n    Designer(){\n        payloadEdges = P*(P-1)/2;\n        payloadWords = (payloadEdges + 63) / 64;\n        payloadPairIdx.assign(P, vector<int>(P, -1));\n        int idx=0;\n        for(int i=0;i<P;i++){\n            for(int j=i+1;j<P;j++){\n                payloadPairIdx[i][j]=idx++;\n                payloadPairs.emplace_back(i,j);\n            }\n        }\n    }\n\n    void generateAnchorAdj(double prob=0.8){\n        anchorAdj.assign(A, vector<int>(A,0));\n        anchorAdjMask.assign(A,0);\n        uniform_real_distribution<double> dist(0.0,1.0);\n        for(int i=0;i<A;i++){\n            for(int j=i+1;j<A;j++){\n                bool edge = dist(rng) < prob;\n                anchorAdj[i][j]=anchorAdj[j][i]=edge?1:0;\n            }\n        }\n        degAA_can.assign(A,0);\n        for(int i=0;i<A;i++){\n            uint64_t mask=0;\n            int cnt=0;\n            for(int j=0;j<A;j++){\n                if(anchorAdj[i][j]){\n                    mask |= (1ULL<<j);\n                    cnt++;\n                }\n            }\n            anchorAdjMask[i]=mask;\n            degAA_can[i]=cnt;\n        }\n    }\n\n    void generatePayloadRows(int minWeight=10, int maxWeight=22, int minDist=8){\n        payloadAnchorMask.clear();\n        int attempts=0;\n        const int limit=30000;\n        while((int)payloadAnchorMask.size()<P){\n            uint64_t mask = rng() & ((1ULL<<A)-1ULL);\n            int w = __builtin_popcountll(mask);\n            if(w<minWeight || w>maxWeight){\n                attempts++;\n            }else{\n                bool ok=true;\n                for(auto prev: payloadAnchorMask){\n                    if(__builtin_popcountll(mask ^ prev) < minDist){\n                        ok=false; break;\n                    }\n                }\n                if(ok) payloadAnchorMask.push_back(mask);\n                else attempts++;\n            }\n            if(attempts>limit){\n                if(minDist>5) minDist--;\n                else if(minWeight>6) minWeight--;\n                else attempts=0;\n            }\n        }\n        degAP_can.assign(A,0);\n        for(int i=0;i<A;i++){\n            int cnt=0;\n            for(auto mask: payloadAnchorMask){\n                if((mask>>i)&1ULL) cnt++;\n            }\n            degAP_can[i]=cnt;\n        }\n    }\n\n    vector<uint64_t> randomPayloadBits(){\n        vector<uint64_t> bits(payloadWords,0);\n        for(auto &w: bits) w=rng();\n        if(payloadEdges % 64){\n            bits.back() &= ((1ULL<<(payloadEdges%64)) - 1ULL);\n        }\n        return bits;\n    }\n\n    int hamming(const vector<uint64_t>&a,const vector<uint64_t>&b) const{\n        int s=0;\n        for(size_t i=0;i<a.size();i++) s+=__builtin_popcountll(a[i]^b[i]);\n        return s;\n    }\n\n    void generateGraphCodes(int M, int baseDist){\n        graphCodes.clear();\n        int curDist = min(baseDist, payloadEdges);\n        int attempts=0;\n        const int limit=60000;\n        while((int)graphCodes.size()<M){\n            auto cand = randomPayloadBits();\n            bool ok=true;\n            for(auto &ex: graphCodes){\n                if(hamming(cand, ex) < curDist){ ok=false; break; }\n            }\n            if(ok){\n                graphCodes.push_back(move(cand));\n            }else{\n                attempts++;\n                if(attempts>limit && curDist>70){\n                    curDist--;\n                    attempts=0;\n                }\n            }\n        }\n    }\n\n    void build(int M, int epsInt){\n        seedBase = 1234567ULL + 10007ULL*M + 7919ULL*epsInt;\n        rng.seed(seedBase);\n        generateAnchorAdj();\n        generatePayloadRows();\n        int baseDist = 110 + epsInt/4;\n        generateGraphCodes(M, baseDist);\n    }\n\n    string graphString(int idx){\n        string s;\n        s.reserve(N*(N-1)/2);\n        auto &code = graphCodes[idx];\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                bool val=false;\n                if(i<A && j<A){\n                    val = anchorAdj[i][j];\n                }else if(i<A && j>=A){\n                    int p = j-A;\n                    val = ((payloadAnchorMask[p]>>i)&1ULL);\n                }else{\n                    int u = i-A;\n                    int v = j-A;\n                    int bitIdx = payloadPairIdx[u][v];\n                    val = (code[bitIdx>>6]>>(bitIdx&63))&1ULL;\n                }\n                s.push_back(val?'1':'0');\n            }\n        }\n        return s;\n    }\n};\n\nstruct Decoder {\n    Designer *des;\n    mt19937 rng;\n    Decoder(Designer* d): des(d){\n        rng.seed(des->seedBase ^ 0x9e3779b97f4a7c15ULL);\n    }\n\n    vector<uint64_t> parse(const string& s){\n        vector<uint64_t> adj(Designer::N,0);\n        int pos=0;\n        for(int i=0;i<Designer::N;i++){\n            for(int j=i+1;j<Designer::N;j++){\n                if(s[pos++]=='1'){\n                    adj[i] |= (1ULL<<j);\n                    adj[j] |= (1ULL<<i);\n                }\n            }\n        }\n        return adj;\n    }\n\n    vector<int> improveAnchors(vector<int> set, const vector<uint64_t>&adj){\n        if((int)set.size()!=Designer::A){\n            set.resize(Designer::A);\n            iota(set.begin(), set.end(), 0);\n        }\n        auto recompute = [&](const vector<int>&curr){\n            vector<int> deg(Designer::N,0);\n            for(int v=0; v<Designer::N; ++v){\n                int cnt=0;\n                for(int u: curr){\n                    if(u==v) continue;\n                    if((adj[v]>>u)&1ULL) cnt++;\n                }\n                deg[v]=cnt;\n            }\n            return deg;\n        };\n        vector<int> degIn = recompute(set);\n        vector<char> in(Designer::N,false);\n        for(int v:set) in[v]=true;\n        for(int iter=0; iter<6; ++iter){\n            int bestDelta=0, bestU=-1, bestV=-1;\n            for(int u: set){\n                for(int v=0; v<Designer::N; ++v){\n                    if(in[v]) continue;\n                    bool edge_uv = (adj[u]>>v)&1ULL;\n                    int delta = (degIn[v] - (edge_uv?1:0)) - degIn[u];\n                    if(delta>bestDelta){\n                        bestDelta=delta;\n                        bestU=u;\n                        bestV=v;\n                    }\n                }\n            }\n            if(bestDelta<=0) break;\n            in[bestU]=false;\n            in[bestV]=true;\n            for(int &x: set) if(x==bestU){ x=bestV; break; }\n            degIn = recompute(set);\n        }\n        sort(set.begin(), set.end());\n        return set;\n    }\n\n    vector<vector<int>> generateAnchorCandidates(const vector<uint64_t>&adj){\n        const int N = Designer::N;\n        const int A = Designer::A;\n        vector<int> deg(N);\n        for(int i=0;i<N;i++) deg[i]=__builtin_popcountll(adj[i]);\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a,int b){\n            if(deg[a]!=deg[b]) return deg[a]>deg[b];\n            return a<b;\n        });\n        auto makeValid = [&](vector<int> cand){\n            vector<char> used(N,false);\n            vector<int> res;\n            res.reserve(A);\n            for(int v: cand){\n                if(v<0 || v>=N) continue;\n                if(!used[v]){\n                    used[v]=true;\n                    res.push_back(v);\n                    if((int)res.size()==A) break;\n                }\n            }\n            if((int)res.size()<A){\n                for(int v: order){\n                    if(!used[v]){\n                        used[v]=true;\n                        res.push_back(v);\n                        if((int)res.size()==A) break;\n                    }\n                }\n            }\n            return res;\n        };\n        vector<vector<int>> candidates;\n        auto addCandidate = [&](vector<int> cand){\n            vector<int> valid = makeValid(cand);\n            vector<int> improved = improveAnchors(valid, adj);\n            if(find(candidates.begin(), candidates.end(), improved)==candidates.end()){\n                candidates.push_back(improved);\n            }\n        };\n        vector<int> base(order.begin(), order.begin()+A);\n        addCandidate(base);\n        int maxShift = min(5, N-A);\n        for(int shift=1; shift<=maxShift; ++shift){\n            vector<int> cand(order.begin()+shift, order.begin()+shift+A);\n            addCandidate(cand);\n        }\n        if(N-A>=4){\n            vector<int> cand = base;\n            for(int r=0;r<4;r++){\n                cand[A-1-r] = order[A+r];\n            }\n            addCandidate(cand);\n        }\n        vector<int> perm(N);\n        iota(perm.begin(), perm.end(), 0);\n        for(int t=0;t<3;t++){\n            shuffle(perm.begin(), perm.end(), rng);\n            vector<int> cand(perm.begin(), perm.begin()+A);\n            addCandidate(cand);\n        }\n        if(candidates.empty()) addCandidate(base);\n        return candidates;\n    }\n\n    pair<vector<int>, vector<int>> mapAnchors(const vector<uint64_t>&adj, const vector<int>&cand){\n        const int N = Designer::N;\n        const int A = Designer::A;\n        vector<char> isAnchor(N,false);\n        for(int v: cand) isAnchor[v]=true;\n        vector<int> payloads;\n        payloads.reserve(N-A);\n        for(int i=0;i<N;i++) if(!isAnchor[i]) payloads.push_back(i);\n        uint64_t payloadMask=0;\n        for(int v: payloads) payloadMask |= (1ULL<<v);\n        vector<vector<int>> obsAA(A, vector<int>(A,0));\n        vector<int> degAA_obs(A,0), degAP_obs(A,0);\n        for(int i=0;i<A;i++){\n            int vi = cand[i];\n            for(int j=0;j<A;j++){\n                if(i==j) continue;\n                if((adj[vi]>>cand[j])&1ULL){\n                    obsAA[i][j]=1;\n                    degAA_obs[i]++;\n                }\n            }\n            degAP_obs[i]=__builtin_popcountll(adj[vi] & payloadMask);\n        }\n        Hungarian hung(A);\n        const int W1=5, W2=1;\n        for(int i=0;i<A;i++){\n            for(int j=0;j<A;j++){\n                int cost = W1*abs(des->degAA_can[i]-degAA_obs[j]) + W2*abs(des->degAP_can[i]-degAP_obs[j]);\n                hung.cost[i][j]=cost;\n            }\n        }\n        hung.solve();\n        vector<int> perm = hung.assignment;\n        auto calcCost = [&](const vector<int>&p){\n            int total=0;\n            for(int i=0;i<A;i++){\n                for(int j=i+1;j<A;j++){\n                    total += des->anchorAdj[i][j] ^ obsAA[p[i]][p[j]];\n                }\n            }\n            return total;\n        };\n        vector<int> best = perm;\n        int bestCost = calcCost(best);\n        vector<int> current = perm;\n        int currentCost = bestCost;\n        uniform_int_distribution<int> distIdx(0, A-1);\n        uniform_real_distribution<double> distReal(0.0,1.0);\n        double temp=4.0;\n        for(int iter=0; iter<3500; ++iter){\n            int i = distIdx(rng);\n            int j = distIdx(rng);\n            if(i==j) continue;\n            if(i>j) swap(i,j);\n            int oi = current[i];\n            int oj = current[j];\n            int delta=0;\n            for(int k=0;k<A;k++){\n                if(k==i || k==j) continue;\n                int ok = current[k];\n                delta += (des->anchorAdj[i][k] ^ obsAA[oj][ok]) - (des->anchorAdj[i][k] ^ obsAA[oi][ok]);\n                delta += (des->anchorAdj[j][k] ^ obsAA[oi][ok]) - (des->anchorAdj[j][k] ^ obsAA[oj][ok]);\n            }\n            delta += (des->anchorAdj[i][j] ^ obsAA[oj][oi]) - (des->anchorAdj[i][j] ^ obsAA[oi][oj]);\n            if(delta < 0 || (temp>1e-6 && distReal(rng) < exp(-delta/temp))){\n                swap(current[i], current[j]);\n                currentCost += delta;\n                if(currentCost < bestCost){\n                    bestCost=currentCost;\n                    best=current;\n                }\n            }\n            temp *= 0.996;\n            if(temp < 0.15) temp = 0.15;\n        }\n        vector<int> anchorMap(A);\n        for(int i=0;i<A;i++) anchorMap[i] = cand[best[i]];\n        sort(payloads.begin(), payloads.end());\n        return {anchorMap, payloads};\n    }\n\n    vector<int> mapPayloads(const vector<uint64_t>&adj, const vector<int>&anchorMap, const vector<int>&payloads){\n        const int A = Designer::A;\n        const int P = Designer::P;\n        vector<uint64_t> obsMask(P,0);\n        for(int i=0;i<P;i++){\n            uint64_t mask=0;\n            int v = payloads[i];\n            for(int a=0;a<A;a++){\n                if((adj[v]>>anchorMap[a])&1ULL) mask |= (1ULL<<a);\n            }\n            obsMask[i]=mask;\n        }\n        Hungarian hung(P);\n        for(int i=0;i<P;i++){\n            for(int j=0;j<P;j++){\n                int dist = __builtin_popcountll(obsMask[i] ^ des->payloadAnchorMask[j]);\n                hung.cost[i][j]=dist;\n            }\n        }\n        hung.solve();\n        vector<int> ordering(P);\n        for(int j=0;j<P;j++){\n            int row=-1;\n            for(int i=0;i<P;i++){\n                if(hung.assignment[i]==j){ row=i; break; }\n            }\n            if(row==-1) row=j;\n            ordering[j]=payloads[row];\n        }\n        return ordering;\n    }\n\n    vector<uint64_t> observedPayloadBits(const vector<uint64_t>&adj, const vector<int>&payloadOrder){\n        vector<uint64_t> bits(des->payloadWords,0);\n        int idx=0;\n        for(int i=0;i<Designer::P;i++){\n            for(int j=i+1;j<Designer::P;j++){\n                bool bit = (adj[payloadOrder[i]]>>payloadOrder[j])&1ULL;\n                if(bit) bits[idx>>6] |= (1ULL<<(idx&63));\n                idx++;\n            }\n        }\n        return bits;\n    }\n\n    pair<int,int> decodeWithAnchors(const vector<uint64_t>&adj, const vector<int>&cand){\n        if((int)cand.size()!=Designer::A) return {-1, INT_MAX};\n        auto [anchorMap, payloadList] = mapAnchors(adj, cand);\n        if((int)payloadList.size()!=Designer::P) return {-1, INT_MAX};\n        auto payloadOrder = mapPayloads(adj, anchorMap, payloadList);\n        auto obsBits = observedPayloadBits(adj, payloadOrder);\n        int best=-1, bestDist=INT_MAX;\n        for(int k=0;k<(int)des->graphCodes.size();k++){\n            int dist = des->hamming(obsBits, des->graphCodes[k]);\n            if(dist < bestDist){\n                bestDist=dist;\n                best=k;\n            }\n        }\n        return {best, bestDist};\n    }\n\n    int decode(const string& s){\n        auto adj = parse(s);\n        auto candidates = generateAnchorCandidates(adj);\n        int best=-1, bestDist=INT_MAX;\n        for(auto &cand : candidates){\n            auto [g, dist] = decodeWithAnchors(adj, cand);\n            if(g==-1) continue;\n            if(dist < bestDist){\n                bestDist=dist;\n                best=g;\n            }\n        }\n        if(best==-1){\n            uniform_int_distribution<int> dist(0, (int)des->graphCodes.size()-1);\n            best = dist(rng);\n        }\n        return best;\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int M;\n    double eps;\n    if(!(cin>>M>>eps)) return 0;\n    Designer designer;\n    int epsInt = (int)round(eps*100 + 1e-9);\n    designer.build(M, epsInt);\n    cout<<Designer::N<<\"\\n\";\n    for(int k=0;k<M;k++){\n        cout<<designer.graphString(k)<<\"\\n\";\n    }\n    cout.flush();\n    Decoder decoder(&designer);\n    for(int q=0;q<100;q++){\n        string H;\n        if(!(cin>>H)) break;\n        int ans = decoder.decode(H);\n        cout<<ans<<\"\\n\";\n        cout.flush();\n    }\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n};\n\nstruct DSU {\n    int n;\n    vector<int> parent, sz;\n    int components;\n    DSU(int n=0){ if(n) init(n); }\n    void init(int n_) {\n        n = n_;\n        parent.resize(n);\n        sz.resize(n);\n        reset();\n    }\n    void reset() {\n        iota(parent.begin(), parent.end(), 0);\n        fill(sz.begin(), sz.end(), 1);\n        components = n;\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    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        parent[b]=a;\n        sz[a]+=sz[b];\n        --components;\n        return true;\n    }\n};\n\nconst double TOTAL_TIME_LIMIT = 5.8;\nconst double CENTRALITY_LIMIT = 2.9;\nconst double LOCAL_SEARCH_LIMIT = 5.0;\nconst double MOVE_EPS = 1e-9;\nconst double VERTEX_COEFF = 0.18;\nconst double DAYCOUNT_COEFF = 0.035;\nconst double LENGTH_COEFF_RATIO = 0.05;\nconst double MIN_REMAIN_FOR_NEW_RUN = 0.9;\nconst int MAX_RUNS = 3;\nconst int MAX_SAMPLE = 8;\nconst ll INFLL = (1LL<<60);\n\nint N,M,D,K;\nvector<int> U,V,W;\nvector<vector<pair<int,int>>> graphAdj;\nvector<int> vertexOffset;\n\nvector<double> edgeScore;\nvector<int> assignment;\nvector<vector<int>> dayEdges;\nvector<int> edgePos;\nvector<double> dayScore;\nvector<int> dayCount;\nvector<int> vertexDayCount;\nvector<vector<char>> dayBlocked;\n\nvector<int> sampleSources;\nvector<vector<ll>> baseDist;\n\nvector<vector<vector<ll>>> daySampleDist;\nvector<vector<double>> daySampleSum;\nvector<double> dayEval;\n\nmt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\n\ndouble alphaCoeff, betaCoeff;\n\nvoid dijkstra_with_block(int src, const vector<char>* blocked, vector<ll> &dist){\n    priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n    fill(dist.begin(), dist.end(), INFLL);\n    dist[src] = 0;\n    pq.emplace(0LL, src);\n    while(!pq.empty()){\n        auto [d,v] = pq.top();\n        pq.pop();\n        if(d != dist[v]) continue;\n        for(auto [to,eid] : graphAdj[v]){\n            if(blocked && (*blocked)[eid]) continue;\n            ll nd = d + W[eid];\n            if(nd < dist[to]){\n                dist[to] = nd;\n                pq.emplace(nd, to);\n            }\n        }\n    }\n}\n\nvoid select_samples_and_base(){\n    int sampleCnt = min(MAX_SAMPLE, N);\n    vector<int> nodes(N);\n    iota(nodes.begin(), nodes.end(), 0);\n    vector<int> deg(N,0);\n    for(int i=0;i<M;++i){\n        deg[U[i]]++;\n        deg[V[i]]++;\n    }\n    sort(nodes.begin(), nodes.end(), [&](int a,int b){\n        if(deg[a]!=deg[b]) return deg[a]>deg[b];\n        return a<b;\n    });\n    sampleSources.clear();\n    for(int i=0;i<sampleCnt;++i) sampleSources.push_back(nodes[i]);\n    baseDist.assign(sampleCnt, vector<ll>(N, INFLL));\n    vector<ll> dist(N);\n    for(int i=0;i<sampleCnt;++i){\n        dijkstra_with_block(sampleSources[i], nullptr, dist);\n        baseDist[i] = dist;\n    }\n}\n\nvector<double> compute_edge_scores(Timer &timer){\n    vector<double> score(M, 0.0);\n    vector<ll> dist(N);\n    vector<double> sigma(N), delta(N);\n    vector<vector<int>> preds(N);\n    for(int i=0;i<N;++i) preds[i].reserve(graphAdj[i].size());\n    vector<int> order;\n    order.reserve(N);\n    vector<int> nodes(N);\n    iota(nodes.begin(), nodes.end(), 0);\n    shuffle(nodes.begin(), nodes.end(), rng);\n    int processed = 0;\n    for(int idx=0; idx<N; ++idx){\n        if(timer.elapsed() > CENTRALITY_LIMIT) break;\n        int s = nodes[idx];\n        fill(dist.begin(), dist.end(), INFLL);\n        fill(sigma.begin(), sigma.end(), 0.0);\n        fill(delta.begin(), delta.end(), 0.0);\n        for(int i=0;i<N;++i) preds[i].clear();\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[s] = 0;\n        sigma[s] = 1.0;\n        pq.emplace(0LL, s);\n        order.clear();\n        while(!pq.empty()){\n            auto [d,v] = pq.top();\n            pq.pop();\n            if(d != dist[v]) continue;\n            order.push_back(v);\n            for(auto [to,eid] : graphAdj[v]){\n                ll nd = d + W[eid];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    pq.emplace(nd, to);\n                    sigma[to] = sigma[v];\n                    preds[to].clear();\n                    preds[to].push_back(eid);\n                }else if(nd == dist[to]){\n                    sigma[to] += sigma[v];\n                    preds[to].push_back(eid);\n                }\n            }\n        }\n        while(!order.empty()){\n            int w = order.back();\n            order.pop_back();\n            if(sigma[w] <= 0.0) continue;\n            double coeff = (1.0 + delta[w]) / sigma[w];\n            for(int eid : preds[w]){\n                int v = (U[eid]==w) ? V[eid] : U[eid];\n                double contrib = sigma[v] * coeff;\n                delta[v] += contrib;\n                score[eid] += contrib;\n            }\n        }\n        ++processed;\n    }\n    if(processed == 0) processed = 1;\n    if(processed < N){\n        double scale = (double)N / processed;\n        for(double &x : score) x *= scale;\n    }\n    double totalScore = 0.0;\n    for(double s : score) totalScore += s;\n    if(totalScore <= 0) totalScore = 1.0;\n    long double baseScale = (long double)totalScore * totalScore;\n    baseScale /= max(1, M);\n    baseScale /= max(1, D);\n    alphaCoeff = (double)(baseScale * VERTEX_COEFF);\n    betaCoeff  = (double)(baseScale * DAYCOUNT_COEFF);\n    if(!isfinite(alphaCoeff) || alphaCoeff < 1e-9) alphaCoeff = 1e-9;\n    if(!isfinite(betaCoeff)  || betaCoeff  < 1e-9) betaCoeff  = 1e-9;\n    alphaCoeff = min(alphaCoeff, 1e18);\n    betaCoeff  = min(betaCoeff , 1e18);\n\n    ll sumW = 0;\n    for(int w : W) sumW += w;\n    double avgScore = totalScore / M;\n    double avgW = (double)sumW / M;\n    double lengthCoeff = (avgW > 0) ? LENGTH_COEFF_RATIO * avgScore / avgW : 0.0;\n    for(int i=0;i<M;++i){\n        score[i] += lengthCoeff * W[i];\n        if(score[i] <= 0) score[i] = 1e-9;\n    }\n    return score;\n}\n\nvoid initialize_state(){\n    assignment.assign(M, -1);\n    dayEdges.assign(D, {});\n    edgePos.assign(M, -1);\n    dayScore.assign(D, 0.0);\n    dayCount.assign(D, 0);\n    vertexDayCount.assign(N*D, 0);\n    dayBlocked.assign(D, vector<char>(M, 0));\n}\n\nvoid move_edge(int eid, int newDay){\n    int oldDay = assignment[eid];\n    if(oldDay == newDay) return;\n    double s = edgeScore[eid];\n    if(oldDay != -1){\n        auto &vec = dayEdges[oldDay];\n        int pos = edgePos[eid];\n        int last = vec.back();\n        if(pos != (int)vec.size()-1){\n            vec[pos] = last;\n            edgePos[last] = pos;\n        }\n        vec.pop_back();\n        dayScore[oldDay] -= s;\n        dayCount[oldDay]--;\n        vertexDayCount[U[eid]*D + oldDay]--;\n        vertexDayCount[V[eid]*D + oldDay]--;\n        dayBlocked[oldDay][eid] = 0;\n    }\n    assignment[eid] = newDay;\n    if(newDay != -1){\n        auto &vec = dayEdges[newDay];\n        edgePos[eid] = vec.size();\n        vec.push_back(eid);\n        dayScore[newDay] += s;\n        dayCount[newDay]++;\n        vertexDayCount[U[eid]*D + newDay]++;\n        vertexDayCount[V[eid]*D + newDay]++;\n        dayBlocked[newDay][eid] = 1;\n    }else{\n        edgePos[eid] = -1;\n    }\n}\n\ndouble move_delta(int eid, int fromDay, int toDay){\n    double s = edgeScore[eid];\n    double delta = s * (dayScore[toDay] - dayScore[fromDay]);\n    int u = U[eid], v = V[eid];\n    delta += alphaCoeff * ((vertexDayCount[u*D + toDay] + vertexDayCount[v*D + toDay])\n                         - (vertexDayCount[u*D + fromDay] + vertexDayCount[v*D + fromDay]));\n    delta += betaCoeff * (dayCount[toDay] - dayCount[fromDay]);\n    return delta;\n}\n\nbool is_day_connected_plain(int day){\n    DSU dsu(N);\n    for(int eid=0; eid<M; ++eid){\n        if(assignment[eid] == day) continue;\n        dsu.unite(U[eid], V[eid]);\n    }\n    return dsu.components == 1;\n}\n\nint build_components_without_day(int day, vector<int> &comp){\n    DSU dsu(N);\n    for(int eid=0; eid<M; ++eid){\n        if(assignment[eid] == day) continue;\n        dsu.unite(U[eid], V[eid]);\n    }\n    if((int)comp.size()!=N) comp.assign(N, 0);\n    vector<int> rootId(N, -1);\n    int comps = 0;\n    for(int i=0;i<N;++i){\n        int r = dsu.find(i);\n        if(rootId[r]==-1) rootId[r]=comps++;\n        comp[i]=rootId[r];\n    }\n    return comps;\n}\n\nint pick_low_score_edge(int day){\n    if(dayEdges[day].empty()) return -1;\n    int best = dayEdges[day][0];\n    double bestScore = edgeScore[best];\n    for(int eid : dayEdges[day]){\n        if(edgeScore[eid] < bestScore){\n            bestScore = edgeScore[eid];\n            best = eid;\n        }\n    }\n    return best;\n}\n\nbool attempt_swap_move(int eid, int targetDay, bool enforceConnectivity){\n    int fromDay = assignment[eid];\n    int swapEdge = pick_low_score_edge(targetDay);\n    if(swapEdge == -1) return false;\n    move_edge(eid, -1);\n    move_edge(swapEdge, fromDay);\n    move_edge(eid, targetDay);\n    if(enforceConnectivity){\n        if(!is_day_connected_plain(targetDay)){\n            move_edge(eid, -1);\n            move_edge(swapEdge, targetDay);\n            move_edge(eid, fromDay);\n            return false;\n        }\n        if(!is_day_connected_plain(fromDay)){\n            move_edge(eid, -1);\n            move_edge(swapEdge, targetDay);\n            move_edge(eid, fromDay);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool try_move_edge_from_day(int eid, int day){\n    vector<pair<double,int>> withSlot;\n    vector<pair<double,int>> noSlot;\n    for(int d=0; d<D; ++d){\n        if(d==day) continue;\n        double delta = move_delta(eid, day, d);\n        if(dayCount[d] < K) withSlot.emplace_back(delta, d);\n        else noSlot.emplace_back(delta, d);\n    }\n    sort(withSlot.begin(), withSlot.end());\n    for(auto [delta, d] : withSlot){\n        move_edge(eid, d);\n        if(is_day_connected_plain(day) && is_day_connected_plain(d)) return true;\n        move_edge(eid, day);\n    }\n    for(auto [delta, d] : withSlot){\n        move_edge(eid, d);\n        return true;\n    }\n    sort(noSlot.begin(), noSlot.end());\n    for(auto [delta, d] : noSlot){\n        if(attempt_swap_move(eid, d, true)) return true;\n    }\n    for(auto [delta, d] : noSlot){\n        if(attempt_swap_move(eid, d, false)) return true;\n    }\n    return false;\n}\n\nvoid enforce_connectivity(Timer &timer){\n    vector<int> comp(N);\n    int outerGuard = 0;\n    while(timer.elapsed() < TOTAL_TIME_LIMIT - 0.4 && outerGuard < 4*D){\n        bool changed = false;\n        for(int day=0; day<D; ++day){\n            if(timer.elapsed() > TOTAL_TIME_LIMIT - 0.45) return;\n            int guard = 0;\n            while(guard < M){\n                int comps = build_components_without_day(day, comp);\n                if(comps <= 1) break;\n                vector<int> critical;\n                for(int eid : dayEdges[day]){\n                    if(comp[U[eid]] != comp[V[eid]]) critical.push_back(eid);\n                }\n                if(critical.empty()) break;\n                sort(critical.begin(), critical.end(), [&](int a,int b){\n                    if(edgeScore[a]!=edgeScore[b]) return edgeScore[a] > edgeScore[b];\n                    return a<b;\n                });\n                bool moved = false;\n                for(int eid : critical){\n                    if(try_move_edge_from_day(eid, day)){\n                        changed = true;\n                        moved = true;\n                        break;\n                    }\n                }\n                if(!moved) break;\n                ++guard;\n            }\n        }\n        if(!changed) break;\n        ++outerGuard;\n    }\n}\n\nvoid greedy_initial_assignment(const vector<int> &order){\n    for(int eid : order){\n        double bestVal = numeric_limits<double>::infinity();\n        int bestDay = -1;\n        double s = edgeScore[eid];\n        int u = U[eid], v = V[eid];\n        int baseU = u*D, baseV = v*D;\n        for(int day=0; day<D; ++day){\n            if(dayCount[day] >= K) continue;\n            double val = dayScore[day] * s\n                       + alphaCoeff * (vertexDayCount[baseU + day] + vertexDayCount[baseV + day])\n                       + betaCoeff  * dayCount[day];\n            if(val < bestVal - 1e-12){\n                bestVal = val;\n                bestDay = day;\n            }\n        }\n        if(bestDay == -1){\n            bestDay = min_element(dayCount.begin(), dayCount.end()) - dayCount.begin();\n        }\n        move_edge(eid, bestDay);\n    }\n}\n\nvoid local_search(Timer &timer){\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    bool improved = true;\n    while(improved && timer.elapsed() < LOCAL_SEARCH_LIMIT){\n        improved = false;\n        shuffle(idx.begin(), idx.end(), rng);\n        for(int eid : idx){\n            if(timer.elapsed() > LOCAL_SEARCH_LIMIT) return;\n            int oldDay = assignment[eid];\n            vector<pair<double,int>> cand;\n            cand.reserve(D-1);\n            for(int day=0; day<D; ++day){\n                if(day == oldDay) continue;\n                if(dayCount[day] >= K) continue;\n                double delta = move_delta(eid, oldDay, day);\n                cand.emplace_back(delta, day);\n            }\n            sort(cand.begin(), cand.end());\n            for(auto [delta, day] : cand){\n                if(delta >= -MOVE_EPS) break;\n                move_edge(eid, day);\n                if(is_day_connected_plain(oldDay) && is_day_connected_plain(day)){\n                    improved = true;\n                    break;\n                }else{\n                    move_edge(eid, oldDay);\n                }\n            }\n        }\n    }\n}\n\ndouble compute_full_eval(){\n    if(sampleSources.empty()) return 0.0;\n    int S = sampleSources.size();\n    daySampleDist.assign(D, vector<vector<ll>>(S, vector<ll>(N)));\n    daySampleSum.assign(D, vector<double>(S, 0.0));\n    dayEval.assign(D, 0.0);\n    vector<ll> dist(N);\n    double total = 0.0;\n    for(int day=0; day<D; ++day){\n        double sumSamples = 0.0;\n        for(int s=0; s<S; ++s){\n            dijkstra_with_block(sampleSources[s], &dayBlocked[day], dist);\n            daySampleDist[day][s] = dist;\n            long double diffSum = 0.0;\n            const auto &base = baseDist[s];\n            for(int v=0; v<N; ++v){\n                ll ref = base[v];\n                if(ref >= INFLL/4) ref = 1000000000LL;\n                ll cur = dist[v];\n                ll diff;\n                if(cur >= INFLL/4) diff = 1000000000LL - ref;\n                else diff = cur - ref;\n                if(diff < 0) diff = 0;\n                diffSum += diff;\n            }\n            double norm = diffSum / (double)max(1, N-1);\n            daySampleSum[day][s] = norm;\n            sumSamples += norm;\n        }\n        dayEval[day] = sumSamples / S;\n        total += dayEval[day];\n    }\n    return total / D;\n}\n\nvoid compute_day_temp(int day, vector<vector<ll>> &bufDist, vector<double> &bufSum, vector<ll> &scratch){\n    int S = sampleSources.size();\n    for(int s=0; s<S; ++s){\n        dijkstra_with_block(sampleSources[s], &dayBlocked[day], scratch);\n        bufDist[s] = scratch;\n        long double diffSum = 0.0;\n        const auto &base = baseDist[s];\n        for(int v=0; v<N; ++v){\n            ll ref = base[v];\n            if(ref >= INFLL/4) ref = 1000000000LL;\n            ll cur = scratch[v];\n            ll diff;\n            if(cur >= INFLL/4) diff = 1000000000LL - ref;\n            else diff = cur - ref;\n            if(diff < 0) diff = 0;\n            diffSum += diff;\n        }\n        bufSum[s] = diffSum / (double)max(1, N-1);\n    }\n}\n\nbool try_move_eval(int eid, int newDay, double &currentScore,\n                   vector<vector<ll>> &tempDistOld,\n                   vector<vector<ll>> &tempDistNew,\n                   vector<double> &tempSumOld,\n                   vector<double> &tempSumNew,\n                   vector<ll> &scratch){\n    int oldDay = assignment[eid];\n    if(oldDay == newDay) return false;\n    if(dayCount[newDay] >= K) return false;\n    move_edge(eid, newDay);\n    if(!is_day_connected_plain(oldDay) || !is_day_connected_plain(newDay)){\n        move_edge(eid, oldDay);\n        return false;\n    }\n    compute_day_temp(oldDay, tempDistOld, tempSumOld, scratch);\n    compute_day_temp(newDay, tempDistNew, tempSumNew, scratch);\n    double evalOld = accumulate(tempSumOld.begin(), tempSumOld.end(), 0.0) / sampleSources.size();\n    double evalNew = accumulate(tempSumNew.begin(), tempSumNew.end(), 0.0) / sampleSources.size();\n    double newTotal = currentScore - dayEval[oldDay] - dayEval[newDay] + evalOld + evalNew;\n    if(newTotal < currentScore - 1e-6){\n        for(size_t s=0; s<sampleSources.size(); ++s){\n            daySampleDist[oldDay][s] = tempDistOld[s];\n            daySampleDist[newDay][s] = tempDistNew[s];\n            daySampleSum[oldDay][s] = tempSumOld[s];\n            daySampleSum[newDay][s] = tempSumNew[s];\n        }\n        dayEval[oldDay] = evalOld;\n        dayEval[newDay] = evalNew;\n        currentScore = newTotal;\n        return true;\n    }else{\n        move_edge(eid, oldDay);\n        return false;\n    }\n}\n\nvoid sample_based_improve(double &currentScore, Timer &timer){\n    if(sampleSources.empty()) return;\n    const double TIME_MARGIN = 0.25;\n    vector<vector<ll>> tempDistA(sampleSources.size(), vector<ll>(N));\n    vector<vector<ll>> tempDistB(sampleSources.size(), vector<ll>(N));\n    vector<double> tempSumA(sampleSources.size());\n    vector<double> tempSumB(sampleSources.size());\n    vector<ll> scratch(N);\n    while(timer.elapsed() < TOTAL_TIME_LIMIT - TIME_MARGIN){\n        int dayWorst = max_element(dayEval.begin(), dayEval.end()) - dayEval.begin();\n        auto edges = dayEdges[dayWorst];\n        if(edges.empty()) break;\n        sort(edges.begin(), edges.end(), [&](int a,int b){\n            return edgeScore[a] > edgeScore[b];\n        });\n        if((int)edges.size() > 10) edges.resize(10);\n        bool improved = false;\n        for(int eid : edges){\n            int currentDay = assignment[eid];\n            vector<pair<double,int>> cand;\n            cand.reserve(D-1);\n            for(int day=0; day<D; ++day){\n                if(day == currentDay) continue;\n                if(dayCount[day] >= K) continue;\n                double approxDelta = move_delta(eid, currentDay, day);\n                cand.emplace_back(approxDelta, day);\n            }\n            if(cand.empty()) continue;\n            sort(cand.begin(), cand.end());\n            if((int)cand.size() > 6) cand.resize(6);\n            for(auto [approxDelta, day] : cand){\n                if(timer.elapsed() > TOTAL_TIME_LIMIT - TIME_MARGIN) break;\n                if(try_move_eval(eid, day, currentScore, tempDistA, tempDistB, tempSumA, tempSumB, scratch)){\n                    improved = true;\n                    break;\n                }\n            }\n            if(improved) break;\n        }\n        if(!improved) break;\n    }\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Timer timer;\n    if(!(cin >> N >> M >> D >> K)) return 0;\n    U.resize(M); V.resize(M); W.resize(M);\n    graphAdj.assign(N, {});\n    for(int i=0;i<M;++i){\n        int u,v,w;\n        cin >> u >> v >> w;\n        --u; --v;\n        U[i]=u; V[i]=v; W[i]=w;\n        graphAdj[u].push_back({v,i});\n        graphAdj[v].push_back({u,i});\n    }\n    for(int i=0;i<N;++i){\n        int x,y;\n        cin >> x >> y;\n        (void)x; (void)y;\n    }\n    vertexOffset.resize(N);\n    for(int i=0;i<N;++i) vertexOffset[i] = i*D;\n\n    select_samples_and_base();\n    edgeScore = compute_edge_scores(timer);\n\n    vector<int> bestAssignment;\n    double bestApprox = 1e300;\n    uniform_real_distribution<double> noiseDist(-1.0, 1.0);\n\n    int run = 0;\n    while(run < MAX_RUNS){\n        if(run>0 && TOTAL_TIME_LIMIT - timer.elapsed() < MIN_REMAIN_FOR_NEW_RUN) break;\n\n        initialize_state();\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        vector<double> key(M);\n        double noiseLevel = (run==0 ? 0.0 : 0.2);\n        for(int i=0;i<M;++i){\n            double noise = noiseLevel * noiseDist(rng);\n            key[i] = edgeScore[i] * (1.0 + noise);\n        }\n        sort(order.begin(), order.end(), [&](int a,int b){\n            if(key[a]!=key[b]) return key[a] > key[b];\n            return a<b;\n        });\n\n        greedy_initial_assignment(order);\n        enforce_connectivity(timer);\n        local_search(timer);\n        enforce_connectivity(timer);\n\n        double approxScore = compute_full_eval();\n        sample_based_improve(approxScore, timer);\n\n        if(approxScore < bestApprox){\n            bestApprox = approxScore;\n            bestAssignment = assignment;\n        }\n        ++run;\n    }\n\n    if(bestAssignment.empty()) bestAssignment = assignment;\n\n    for(int i=0;i<M;++i){\n        if(i) cout << ' ';\n        cout << bestAssignment[i] + 1;\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Segment {\n    int x, y;\n    int z0;\n    int len;\n};\n\nstruct Builder {\n    bool active = false;\n    int start = 0;\n    int len = 0;\n};\n\nstruct LayerAssign {\n    vector<pair<int, int>> pairs;\n    vector<int> assigned_y_for_x;\n    vector<int> assigned_x_for_y;\n};\n\nLayerAssign assign_x_major(\n        int D,\n        const vector<int>& X,\n        const vector<int>& Y,\n        const vector<int>& prev_y_for_x,\n        const vector<int>& prev_x_for_y) {\n\n    LayerAssign res;\n    res.assigned_y_for_x.assign(D, -1);\n    res.assigned_x_for_y.assign(D, -1);\n    vector<char> x_present(D, 0), y_present(D, 0);\n    for (int x : X) x_present[x] = 1;\n    for (int y : Y) y_present[y] = 1;\n\n    vector<char> x_assigned(D, 0);\n\n    auto choose_x_with_prev = [&](int target_y) -> int {\n        for (int x : X) if (!x_assigned[x] && prev_y_for_x[x] == target_y) return x;\n        return -1;\n    };\n    auto choose_any_x = [&]() -> int {\n        for (int x : X) if (!x_assigned[x]) return x;\n        return -1;\n    };\n\n    for (int y : Y) {\n        int x = choose_x_with_prev(y);\n        if (x == -1) x = choose_any_x();\n        if (x == -1) x = X.front(); // safety\n        x_assigned[x] = 1;\n        res.assigned_y_for_x[x] = y;\n        res.assigned_x_for_y[y] = x;\n        res.pairs.emplace_back(x, y);\n    }\n\n    if (!Y.empty()) {\n        size_t ptr = 0;\n        for (int x : X) {\n            if (x_assigned[x]) continue;\n            int y = -1;\n            if (prev_y_for_x[x] != -1 && y_present[prev_y_for_x[x]]) {\n                y = prev_y_for_x[x];\n            } else {\n                y = Y[ptr];\n                ptr = (ptr + 1) % Y.size();\n            }\n            x_assigned[x] = 1;\n            res.assigned_y_for_x[x] = y;\n            res.assigned_x_for_y[y] = x;\n            res.pairs.emplace_back(x, y);\n        }\n    }\n\n    return res;\n}\n\nLayerAssign assign_y_major(\n        int D,\n        const vector<int>& X,\n        const vector<int>& Y,\n        const vector<int>& prev_y_for_x,\n        const vector<int>& prev_x_for_y) {\n\n    LayerAssign res;\n    res.assigned_y_for_x.assign(D, -1);\n    res.assigned_x_for_y.assign(D, -1);\n    vector<char> x_present(D, 0), y_present(D, 0);\n    for (int x : X) x_present[x] = 1;\n    for (int y : Y) y_present[y] = 1;\n\n    vector<char> y_assigned(D, 0);\n\n    auto choose_y_with_prev = [&](int target_x) -> int {\n        for (int y : Y) if (!y_assigned[y] && prev_x_for_y[y] == target_x) return y;\n        return -1;\n    };\n    auto choose_any_y = [&]() -> int {\n        for (int y : Y) if (!y_assigned[y]) return y;\n        return -1;\n    };\n\n    for (int x : X) {\n        int y = choose_y_with_prev(x);\n        if (y == -1) y = choose_any_y();\n        if (y == -1) y = Y.front(); // safety\n        y_assigned[y] = 1;\n        res.assigned_y_for_x[x] = y;\n        res.assigned_x_for_y[y] = x;\n        res.pairs.emplace_back(x, y);\n    }\n\n    if (!X.empty()) {\n        size_t ptr = 0;\n        for (int y : Y) {\n            if (y_assigned[y]) continue;\n            int x = -1;\n            if (prev_x_for_y[y] != -1 && x_present[prev_x_for_y[y]]) {\n                x = prev_x_for_y[y];\n            } else {\n                x = X[ptr];\n                ptr = (ptr + 1) % X.size();\n            }\n            y_assigned[y] = 1;\n            res.assigned_x_for_y[y] = x;\n            res.assigned_y_for_x[x] = y;\n            res.pairs.emplace_back(x, y);\n        }\n    }\n\n    return res;\n}\n\nvector<Segment> build_segments(int D, const vector<string>& front, const vector<string>& right) {\n    vector<Segment> segments;\n    vector<vector<Builder>> builder(D, vector<Builder>(D));\n    vector<vector<char>> stay(D, vector<char>(D, 0));\n    vector<int> prev_y_for_x(D, -1), prev_x_for_y(D, -1);\n\n    for (int z = 0; z < D; ++z) {\n        vector<int> X, Y;\n        for (int x = 0; x < D; ++x) if (front[z][x] == '1') X.push_back(x);\n        for (int y = 0; y < D; ++y) if (right[z][y] == '1') Y.push_back(y);\n\n        LayerAssign assign = (X.size() >= Y.size())\n                             ? assign_x_major(D, X, Y, prev_y_for_x, prev_x_for_y)\n                             : assign_y_major(D, X, Y, prev_y_for_x, prev_x_for_y);\n\n        for (int x = 0; x < D; ++x) fill(stay[x].begin(), stay[x].end(), 0);\n        for (auto [x, y] : assign.pairs) {\n            if (!builder[x][y].active) {\n                builder[x][y].active = true;\n                builder[x][y].start = z;\n                builder[x][y].len = 0;\n            }\n            builder[x][y].len++;\n            stay[x][y] = 1;\n        }\n\n        for (int x = 0; x < D; ++x) {\n            for (int y = 0; y < D; ++y) {\n                if (builder[x][y].active && !stay[x][y]) {\n                    segments.push_back({x, y, builder[x][y].start, builder[x][y].len});\n                    builder[x][y].active = false;\n                }\n            }\n        }\n\n        prev_y_for_x = assign.assigned_y_for_x;\n        prev_x_for_y = assign.assigned_x_for_y;\n    }\n\n    for (int x = 0; x < D; ++x) {\n        for (int y = 0; y < D; ++y) {\n            if (builder[x][y].active) {\n                segments.push_back({x, y, builder[x][y].start, builder[x][y].len});\n                builder[x][y].active = false;\n            }\n        }\n    }\n    return segments;\n}\n\nstruct MatchResult {\n    vector<int> block_id0;\n    vector<int> block_id1;\n    int total_blocks;\n};\n\nstruct PQNode {\n    int len;\n    int idx;\n};\nstruct PQCmp {\n    bool operator()(const PQNode& a, const PQNode& b) const {\n        return a.len < b.len; // max-heap\n    }\n};\n\nPQNode pop_valid(priority_queue<PQNode, vector<PQNode>, PQCmp>& pq,\n                 const vector<Segment>& segs,\n                 const vector<int>& blockId) {\n    while (!pq.empty()) {\n        PQNode node = pq.top();\n        pq.pop();\n        if (node.idx >= (int)segs.size()) continue;\n        if (blockId[node.idx] != -1) continue;\n        if (segs[node.idx].len != node.len) {\n            pq.push({segs[node.idx].len, node.idx});\n            continue;\n        }\n        return node;\n    }\n    return {-1, -1};\n}\n\nMatchResult match_segments(vector<Segment>& seg0, vector<Segment>& seg1) {\n    vector<int> blockId0(seg0.size(), -1), blockId1(seg1.size(), -1);\n    priority_queue<PQNode, vector<PQNode>, PQCmp> pq0, pq1;\n    for (int i = 0; i < (int)seg0.size(); ++i) pq0.push({seg0[i].len, i});\n    for (int i = 0; i < (int)seg1.size(); ++i) pq1.push({seg1[i].len, i});\n    int nextId = 1;\n\n    auto split_segment = [&](vector<Segment>& segs, vector<int>& blockId, int idx, int take_len) -> int {\n        Segment& seg = segs[idx];\n        Segment newSeg{seg.x, seg.y, seg.z0, take_len};\n        seg.z0 += take_len;\n        seg.len -= take_len;\n        int newIdx = segs.size();\n        segs.push_back(newSeg);\n        blockId.push_back(-1);\n        return newIdx;\n    };\n\n    while (true) {\n        PQNode node0 = pop_valid(pq0, seg0, blockId0);\n        if (node0.idx == -1) break;\n        PQNode node1 = pop_valid(pq1, seg1, blockId1);\n        if (node1.idx == -1) {\n            pq0.push({seg0[node0.idx].len, node0.idx});\n            break;\n        }\n        int idx0 = node0.idx, idx1 = node1.idx;\n        int len0 = node0.len, len1 = node1.len;\n        if (len0 == len1) {\n            blockId0[idx0] = blockId1[idx1] = nextId++;\n        } else if (len0 > len1) {\n            int newIdx = split_segment(seg0, blockId0, idx0, len1);\n            blockId0[newIdx] = blockId1[idx1] = nextId++;\n            pq0.push({seg0[idx0].len, idx0});\n        } else {\n            int newIdx = split_segment(seg1, blockId1, idx1, len0);\n            blockId0[idx0] = blockId1[newIdx] = nextId++;\n            pq1.push({seg1[idx1].len, idx1});\n        }\n    }\n\n    for (int i = 0; i < (int)seg0.size(); ++i) {\n        if (blockId0[i] == -1) blockId0[i] = nextId++;\n    }\n    for (int i = 0; i < (int)seg1.size(); ++i) {\n        if (blockId1[i] == -1) blockId1[i] = nextId++;\n    }\n\n    return {blockId0, blockId1, nextId - 1};\n}\n\nbool verify(int D, const vector<int>& grid,\n            const vector<string>& front, const vector<string>& right) {\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n    for (int z = 0; z < D; ++z) {\n        for (int x = 0; x < D; ++x) {\n            bool occ = false;\n            for (int y = 0; y < D; ++y) if (grid[idx(x, y, z)]) { occ = true; break; }\n            if (occ != (front[z][x] == '1')) return false;\n        }\n        for (int y = 0; y < D; ++y) {\n            bool occ = false;\n            for (int x = 0; x < D; ++x) if (grid[idx(x, y, z)]) { occ = true; break; }\n            if (occ != (right[z][y] == '1')) return false;\n        }\n    }\n    return true;\n}\n\nstruct Cell { int x, y, z; };\n\nvector<Cell> build_min_cells(int D, const vector<string>& front, const vector<string>& right) {\n    vector<Cell> cells;\n    for (int z = 0; z < D; ++z) {\n        vector<int> xs, ys;\n        for (int x = 0; x < D; ++x) if (front[z][x] == '1') xs.push_back(x);\n        for (int y = 0; y < D; ++y) if (right[z][y] == '1') ys.push_back(y);\n        if (xs.empty()) xs.push_back(0);\n        if (ys.empty()) ys.push_back(0);\n        if ((int)xs.size() >= (int)ys.size()) {\n            for (size_t i = 0; i < xs.size(); ++i)\n                cells.push_back({xs[i], ys[i % ys.size()], z});\n        } else {\n            for (size_t i = 0; i < ys.size(); ++i)\n                cells.push_back({xs[i % xs.size()], ys[i], z});\n        }\n    }\n    return cells;\n}\n\ntuple<int, vector<int>, vector<int>> baseline_solution(\n        int D,\n        const vector<string>& f0, const vector<string>& r0,\n        const vector<string>& f1, const vector<string>& r1) {\n    vector<Cell> c0 = build_min_cells(D, f0, r0);\n    vector<Cell> c1 = build_min_cells(D, f1, r1);\n    int n = max(c0.size(), c1.size());\n    vector<int> grid0(D * D * D, 0), grid1(D * D * D, 0);\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n    for (size_t i = 0; i < c0.size(); ++i) grid0[idx(c0[i].x, c0[i].y, c0[i].z)] = i + 1;\n    for (size_t i = 0; i < c1.size(); ++i) grid1[idx(c1[i].x, c1[i].y, c1[i].z)] = i + 1;\n    return {n, grid0, grid1};\n}\n\nbool build_advanced(\n        int D,\n        const vector<string>& f0, const vector<string>& r0,\n        const vector<string>& f1, const vector<string>& r1,\n        int& n,\n        vector<int>& grid0,\n        vector<int>& grid1) {\n\n    vector<Segment> seg0 = build_segments(D, f0, r0);\n    vector<Segment> seg1 = build_segments(D, f1, r1);\n\n    MatchResult match = match_segments(seg0, seg1);\n    n = match.total_blocks;\n    grid0.assign(D * D * D, 0);\n    grid1.assign(D * D * D, 0);\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n\n    for (int i = 0; i < (int)seg0.size(); ++i) {\n        int bid = match.block_id0[i];\n        for (int dz = 0; dz < seg0[i].len; ++dz) {\n            int z = seg0[i].z0 + dz;\n            grid0[idx(seg0[i].x, seg0[i].y, z)] = bid;\n        }\n    }\n    for (int i = 0; i < (int)seg1.size(); ++i) {\n        int bid = match.block_id1[i];\n        for (int dz = 0; dz < seg1[i].len; ++dz) {\n            int z = seg1[i].z0 + dz;\n            grid1[idx(seg1[i].x, seg1[i].y, z)] = bid;\n        }\n    }\n    if (!verify(D, grid0, f0, r0)) return false;\n    if (!verify(D, grid1, f1, r1)) return false;\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int D;\n    if (!(cin >> D)) return 0;\n    vector<vector<string>> front(2, vector<string>(D));\n    vector<vector<string>> right(2, vector<string>(D));\n    for (int i = 0; i < 2; ++i) {\n        for (int z = 0; z < D; ++z) cin >> front[i][z];\n        for (int z = 0; z < D; ++z) cin >> right[i][z];\n    }\n\n    int n;\n    vector<int> grid0, grid1;\n    if (!build_advanced(D, front[0], right[0], front[1], right[1], n, grid0, grid1)) {\n        tie(n, grid0, grid1) = baseline_solution(D, front[0], right[0], front[1], right[1]);\n    }\n\n    cout << n << '\\n';\n    for (int i = 0; i < D * D * D; ++i) {\n        if (i) cout << ' ';\n        cout << grid0[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < D * D * D; ++i) {\n        if (i) cout << ' ';\n        cout << grid1[i];\n    }\n    cout << '\\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};\nstruct AdjEdge {\n    int to;\n    long long w;\n    int id;\n};\nstruct Candidate {\n    long long dist;\n    int to;\n};\n\nstruct Solver {\n    int N, M, K;\n    vector<long long> xs, ys;\n    vector<long long> ax, ay;\n    vector<Edge> edges;\n    vector<vector<AdjEdge>> graph;\n\n    const long long INF64 = (1LL << 60);\n    const long long MAX_RAD_SQ = 5000LL * 5000LL;\n\n    vector<vector<long long>> distMat;\n    vector<vector<int>> parentEdge;\n    vector<vector<int>> parentVertex;\n\n    vector<vector<Candidate>> resCandidates;\n\n    vector<int> assignStation;\n    vector<long long> distAssigned;\n\n    vector<vector<int>> residentsOfStation;\n    vector<long long> maxDist;\n    vector<int> P;\n    vector<char> broadcast;\n\n    long long currentPcost = 0;\n    long long currentTreeCost = 0;\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M >> K)) return;\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; ++i) cin >> xs[i] >> ys[i];\n        edges.resize(M);\n        graph.assign(N, {});\n        for (int j = 0; j < M; ++j) {\n            int u, v;\n            long long w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[j] = {u, v, w};\n            graph[u].push_back({v, w, j});\n            graph[v].push_back({u, w, j});\n        }\n        ax.resize(K);\n        ay.resize(K);\n        for (int i = 0; i < K; ++i) cin >> ax[i] >> ay[i];\n\n        computeAllPairs();\n        buildResidentCandidates();\n        initialAssignment();\n\n        residentsOfStation.assign(N, {});\n        maxDist.assign(N, 0);\n        P.assign(N, 0);\n        broadcast.assign(N, false);\n\n        rebuildAll();\n        optimize();\n\n        vector<int> edgeOn(M, 0);\n        buildFinalEdges(edgeOn);\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << P[i];\n        }\n        cout << '\\n';\n        for (int j = 0; j < M; ++j) {\n            if (j) cout << ' ';\n            cout << edgeOn[j];\n        }\n        cout << '\\n';\n    }\n\n    void computeAllPairs() {\n        distMat.assign(N, vector<long long>(N, INF64));\n        parentEdge.assign(N, vector<int>(N, -1));\n        parentVertex.assign(N, vector<int>(N, -1));\n        for (int s = 0; s < N; ++s) {\n            vector<long long> dist(N, INF64);\n            vector<int> prevE(N, -1), prevV(N, -1);\n            dist[s] = 0;\n            using Node = pair<long long, int>;\n            priority_queue<Node, vector<Node>, greater<Node>> pq;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [d, v] = pq.top();\n                pq.pop();\n                if (d != dist[v]) continue;\n                for (const auto &ed : graph[v]) {\n                    int to = ed.to;\n                    long long nd = d + ed.w;\n                    if (nd < dist[to]) {\n                        dist[to] = nd;\n                        prevE[to] = ed.id;\n                        prevV[to] = v;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n            distMat[s] = dist;\n            parentEdge[s] = prevE;\n            parentVertex[s] = prevV;\n        }\n    }\n\n    void buildResidentCandidates() {\n        resCandidates.assign(K, {});\n        vector<pair<long long, int>> tmp;\n        tmp.reserve(N);\n        for (int k = 0; k < K; ++k) {\n            tmp.clear();\n            for (int i = 0; i < N; ++i) {\n                long long dx = xs[i] - ax[k];\n                long long dy = ys[i] - ay[k];\n                long long d = dx * dx + dy * dy;\n                tmp.emplace_back(d, i);\n            }\n            sort(tmp.begin(), tmp.end());\n            vector<Candidate> cand;\n            cand.reserve(N);\n            bool hasWithin = false;\n            for (auto &p : tmp) {\n                if (p.first <= MAX_RAD_SQ) {\n                    cand.push_back({p.first, p.second});\n                    hasWithin = true;\n                } else if (hasWithin) {\n                    break;\n                }\n            }\n            if (cand.empty()) cand.push_back({tmp[0].first, tmp[0].second});\n            resCandidates[k] = move(cand);\n        }\n    }\n\n    void initialAssignment() {\n        assignStation.assign(K, 0);\n        distAssigned.assign(K, 0);\n        for (int k = 0; k < K; ++k) {\n            if (resCandidates[k].empty()) {\n                assignStation[k] = 0;\n                distAssigned[k] = 0;\n            } else {\n                assignStation[k] = resCandidates[k][0].to;\n                long long d = resCandidates[k][0].dist;\n                if (d > MAX_RAD_SQ) d = MAX_RAD_SQ;\n                distAssigned[k] = d;\n            }\n        }\n    }\n\n    int ceil_sqrt_ll(long long v) const {\n        if (v <= 0) return 0;\n        long double r = sqrt((long double)v);\n        long long x = (long long)r;\n        while (x * x < v) ++x;\n        while (x > 0 && (x - 1) * (x - 1) >= v) --x;\n        if (x > 5000) x = 5000;\n        return (int)x;\n    }\n\n    void rebuildAll() {\n        for (int i = 0; i < N; ++i) {\n            residentsOfStation[i].clear();\n            maxDist[i] = 0;\n        }\n        for (int k = 0; k < K; ++k) {\n            int st = assignStation[k];\n            residentsOfStation[st].push_back(k);\n            if (distAssigned[k] > maxDist[st]) maxDist[st] = distAssigned[k];\n        }\n        currentPcost = 0;\n        for (int i = 0; i < N; ++i) {\n            if (!residentsOfStation[i].empty()) {\n                broadcast[i] = 1;\n                P[i] = ceil_sqrt_ll(maxDist[i]);\n            } else {\n                broadcast[i] = 0;\n                maxDist[i] = 0;\n                P[i] = 0;\n            }\n            currentPcost += 1LL * P[i] * P[i];\n        }\n        currentTreeCost = computeCurrentMST();\n    }\n\n    long long computeMSTNodes(const vector<int> &nodes) {\n        if (nodes.size() <= 1) return 0;\n        vector<long long> key(nodes.size(), INF64);\n        vector<int> parent(nodes.size(), -1);\n        vector<char> used(nodes.size(), false);\n        key[0] = 0;\n        long long total = 0;\n        for (size_t it = 0; it < nodes.size(); ++it) {\n            int u = -1;\n            long long best = INF64;\n            for (size_t i = 0; i < nodes.size(); ++i) {\n                if (!used[i] && key[i] < best) {\n                    best = key[i];\n                    u = (int)i;\n                }\n            }\n            if (u == -1) break;\n            used[u] = true;\n            total += key[u];\n            for (size_t v = 0; v < nodes.size(); ++v) {\n                if (used[v]) continue;\n                long long d = distMat[nodes[u]][nodes[v]];\n                if (d < key[v]) {\n                    key[v] = d;\n                    parent[v] = u;\n                }\n            }\n        }\n        return total;\n    }\n\n    long long computeCurrentMST() {\n        vector<int> nodes;\n        nodes.reserve(N);\n        nodes.push_back(0);\n        for (int i = 1; i < N; ++i) {\n            if (broadcast[i]) nodes.push_back(i);\n        }\n        return computeMSTNodes(nodes);\n    }\n\n    bool tryRemove(int s) {\n        if (!broadcast[s]) return false;\n        vector<int> resList = residentsOfStation[s];\n        if (resList.empty()) return false;\n\n        int R = resList.size();\n        vector<long long> firstAlt(R, INF64);\n        for (int idx = 0; idx < R; ++idx) {\n            int rid = resList[idx];\n            for (const auto &cand : resCandidates[rid]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                if (cand.to == s) continue;\n                if (!broadcast[cand.to]) continue;\n                firstAlt[idx] = cand.dist;\n                break;\n            }\n            if (firstAlt[idx] == INF64) return false;\n        }\n\n        vector<int> order(R);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (firstAlt[a] != firstAlt[b]) return firstAlt[a] > firstAlt[b];\n            return resList[a] < resList[b];\n        });\n\n        vector<long long> tempMax = maxDist;\n        vector<int> tempP = P;\n        vector<int> chosenStation(R, -1);\n        vector<long long> chosenDist(R, 0);\n\n        for (int ordIdx : order) {\n            int idx = ordIdx;\n            int rid = resList[idx];\n            long long bestDelta = INF64;\n            int bestT = -1;\n            long long bestD = 0;\n            int bestNewP = 0;\n            long long bestNewMax = INF64;\n            for (const auto &cand : resCandidates[rid]) {\n                long long dist = cand.dist;\n                if (dist > MAX_RAD_SQ) break;\n                int t = cand.to;\n                if (t == s) continue;\n                if (!broadcast[t]) continue;\n                long long curMax = tempMax[t];\n                int curP = tempP[t];\n                long long newMax = curMax;\n                int newP = curP;\n                if (dist > newMax) {\n                    newMax = dist;\n                    newP = ceil_sqrt_ll(newMax);\n                }\n                long long delta = 1LL * newP * newP - 1LL * curP * curP;\n                if (bestT == -1 || delta < bestDelta || (delta == bestDelta && newMax < bestNewMax)) {\n                    bestDelta = delta;\n                    bestT = t;\n                    bestD = dist;\n                    bestNewP = newP;\n                    bestNewMax = newMax;\n                }\n            }\n            if (bestT == -1) return false;\n            chosenStation[idx] = bestT;\n            chosenDist[idx] = bestD;\n            tempMax[bestT] = bestNewMax;\n            tempP[bestT] = bestNewP;\n        }\n\n        tempMax[s] = 0;\n        tempP[s] = 0;\n\n        long long newPcost = 0;\n        vector<int> nodesAfter;\n        nodesAfter.reserve(N);\n        nodesAfter.push_back(0);\n        for (int i = 0; i < N; ++i) {\n            newPcost += 1LL * tempP[i] * tempP[i];\n            if (i > 0 && tempP[i] > 0) nodesAfter.push_back(i);\n        }\n        long long newTreeCost = computeMSTNodes(nodesAfter);\n        long long currentTotal = currentPcost + currentTreeCost;\n        long long newTotal = newPcost + newTreeCost;\n        if (newTotal >= currentTotal) return false;\n\n        for (int idx = 0; idx < R; ++idx) {\n            int rid = resList[idx];\n            assignStation[rid] = chosenStation[idx];\n            distAssigned[rid] = chosenDist[idx];\n        }\n        rebuildAll();\n        return true;\n    }\n\n    bool tryReassignAll() {\n        vector<int> newAssign(K);\n        vector<long long> newDist(K);\n        bool changed = false;\n        for (int r = 0; r < K; ++r) {\n            int bestStation = -1;\n            long long bestDist = 0;\n            for (const auto &cand : resCandidates[r]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                if (!broadcast[cand.to]) continue;\n                bestStation = cand.to;\n                bestDist = cand.dist;\n                break;\n            }\n            if (bestStation == -1) return false;\n            newAssign[r] = bestStation;\n            newDist[r] = bestDist;\n            if (bestStation != assignStation[r]) changed = true;\n        }\n        if (!changed) return false;\n\n        vector<long long> newMax(N, 0);\n        vector<int> counts(N, 0);\n        for (int r = 0; r < K; ++r) {\n            int st = newAssign[r];\n            ++counts[st];\n            if (newDist[r] > newMax[st]) newMax[st] = newDist[r];\n        }\n        vector<int> newP(N, 0);\n        vector<char> newBroadcast(N, 0);\n        long long newPcost = 0;\n        for (int i = 0; i < N; ++i) {\n            if (counts[i] > 0) {\n                newBroadcast[i] = 1;\n                newP[i] = ceil_sqrt_ll(newMax[i]);\n            } else {\n                newBroadcast[i] = 0;\n                newP[i] = 0;\n            }\n            newPcost += 1LL * newP[i] * newP[i];\n        }\n        vector<int> nodesAfter;\n        nodesAfter.reserve(N);\n        nodesAfter.push_back(0);\n        for (int i = 1; i < N; ++i) if (newBroadcast[i]) nodesAfter.push_back(i);\n        long long newTreeCost = computeMSTNodes(nodesAfter);\n        long long currentTotal = currentPcost + currentTreeCost;\n        long long newTotal = newPcost + newTreeCost;\n        if (newTotal >= currentTotal) return false;\n\n        assignStation.swap(newAssign);\n        distAssigned.swap(newDist);\n        rebuildAll();\n        return true;\n    }\n\n    bool improveSingleFarMove() {\n        vector<int> order;\n        order.reserve(N);\n        for (int i = 0; i < N; ++i) if (broadcast[i]) order.push_back(i);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (P[a] != P[b]) return P[a] > P[b];\n            return residentsOfStation[a].size() > residentsOfStation[b].size();\n        });\n        for (int s : order) {\n            if ((int)residentsOfStation[s].size() <= 1) continue;\n            int farRes = -1;\n            long long farDist = -1;\n            for (int r : residentsOfStation[s]) {\n                if (distAssigned[r] > farDist) {\n                    farDist = distAssigned[r];\n                    farRes = r;\n                }\n            }\n            if (farRes == -1) continue;\n            long long newMaxS = 0;\n            for (int r : residentsOfStation[s]) {\n                if (r == farRes) continue;\n                if (distAssigned[r] > newMaxS) newMaxS = distAssigned[r];\n            }\n            int newPs = ceil_sqrt_ll(newMaxS);\n            int oldPs = P[s];\n            long long bestDelta = 0;\n            int bestTarget = -1;\n            long long bestDist = 0;\n            for (const auto &cand : resCandidates[farRes]) {\n                long long dist = cand.dist;\n                if (dist > MAX_RAD_SQ) break;\n                int t = cand.to;\n                if (t == s) continue;\n                if (!broadcast[t]) continue;\n                long long newMaxT = max(maxDist[t], dist);\n                int newPt = ceil_sqrt_ll(newMaxT);\n                long long delta = 1LL * newPs * newPs + 1LL * newPt * newPt - (1LL * oldPs * oldPs + 1LL * P[t] * P[t]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestTarget = t;\n                    bestDist = dist;\n                }\n            }\n            if (bestTarget != -1) {\n                assignStation[farRes] = bestTarget;\n                distAssigned[farRes] = bestDist;\n                rebuildAll();\n                return true;\n            }\n        }\n        return false;\n    }\n\n    void optimize() {\n        while (true) {\n            bool changed = false;\n            while (true) {\n                vector<int> order;\n                order.reserve(N);\n                for (int i = 0; i < N; ++i) if (broadcast[i]) order.push_back(i);\n                sort(order.begin(), order.end(), [&](int a, int b) {\n                    if (residentsOfStation[a].size() != residentsOfStation[b].size())\n                        return residentsOfStation[a].size() < residentsOfStation[b].size();\n                    if (P[a] != P[b]) return P[a] < P[b];\n                    return a < b;\n                });\n                bool removed = false;\n                for (int s : order) {\n                    if (tryRemove(s)) {\n                        changed = true;\n                        removed = true;\n                        break;\n                    }\n                }\n                if (!removed) break;\n            }\n            if (tryReassignAll()) {\n                changed = true;\n                continue;\n            }\n            if (improveSingleFarMove()) {\n                changed = true;\n                continue;\n            }\n            if (!changed) break;\n        }\n    }\n\n    void recomputeSP(int s) {\n        vector<long long> dist(N, INF64);\n        vector<int> prevE(N, -1), prevV(N, -1);\n        dist[s] = 0;\n        using Node = pair<long long, int>;\n        priority_queue<Node, vector<Node>, greater<Node>> pq;\n        pq.push({0, s});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            for (const auto &ed : graph[v]) {\n                int to = ed.to;\n                long long nd = d + ed.w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    prevE[to] = ed.id;\n                    prevV[to] = v;\n                    pq.push({nd, to});\n                }\n            }\n        }\n        distMat[s] = dist;\n        parentEdge[s] = prevE;\n        parentVertex[s] = prevV;\n    }\n\n    void addPath(int s, int t, vector<int> &edgeOn) {\n        if (s == t) return;\n        int cur = t;\n        while (cur != s) {\n            int e = parentEdge[s][cur];\n            int pv = parentVertex[s][cur];\n            if (e == -1 || pv == -1) {\n                recomputeSP(s);\n                e = parentEdge[s][cur];\n                pv = parentVertex[s][cur];\n                if (e == -1 || pv == -1) break;\n            }\n            edgeOn[e] = 1;\n            cur = pv;\n        }\n    }\n\n    void buildFinalEdges(vector<int> &edgeOn) {\n        fill(edgeOn.begin(), edgeOn.end(), 0);\n        vector<int> nodes;\n        nodes.reserve(N);\n        nodes.push_back(0);\n        for (int i = 1; i < N; ++i) if (broadcast[i]) nodes.push_back(i);\n        if (nodes.size() <= 1) return;\n        int T = nodes.size();\n        vector<long long> key(T, INF64);\n        vector<int> parent(T, -1);\n        vector<char> used(T, false);\n        key[0] = 0;\n        for (int iter = 0; iter < T; ++iter) {\n            int u = -1;\n            long long best = INF64;\n            for (int i = 0; i < T; ++i) {\n                if (!used[i] && key[i] < best) {\n                    best = key[i];\n                    u = i;\n                }\n            }\n            if (u == -1) break;\n            used[u] = true;\n            if (parent[u] != -1) {\n                addPath(nodes[u], nodes[parent[u]], edgeOn);\n            }\n            for (int v = 0; v < T; ++v) {\n                if (used[v]) continue;\n                long long d = distMat[nodes[u]][nodes[v]];\n                if (d < key[v]) {\n                    key[v] = d;\n                    parent[v] = u;\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 30;\nconstexpr int LIMIT = 10000;\nusing Tri = vector<vector<int>>;\n\nstruct Result {\n    vector<array<int, 4>> ops;\n    Tri board;\n};\n\ninline bool inRange(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y <= x;\n}\n\nbool adjacent(int x1, int y1, int x2, int y2) {\n    if (!inRange(x1, y1) || !inRange(x2, y2)) return false;\n    if (x1 == x2) return abs(y1 - y2) == 1;\n    if (x1 + 1 == x2) return (y1 == y2) || (y1 == y2 - 1);\n    if (x2 + 1 == x1) return (y2 == y1) || (y2 == y1 - 1);\n    return false;\n}\n\nint countViolations(const Tri& a) {\n    int cnt = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            if (a[x][y] > a[x + 1][y]) ++cnt;\n            if (a[x][y] > a[x + 1][y + 1]) ++cnt;\n        }\n    }\n    return cnt;\n}\n\nbool applyOps(const Tri& initial, const vector<array<int, 4>>& ops, Tri& board) {\n    if ((int)ops.size() > LIMIT) return false;\n    board = initial;\n    for (const auto& op : ops) {\n        int x1 = op[0], y1 = op[1], x2 = op[2], y2 = op[3];\n        if (!adjacent(x1, y1, x2, y2)) return false;\n        swap(board[x1][y1], board[x2][y2]);\n    }\n    return true;\n}\n\nbool ensureValid(Result& res, const Tri& initial) {\n    Tri board;\n    if (!applyOps(initial, res.ops, board)) return false;\n    if (countViolations(board) != 0) return false;\n    res.board = move(board);\n    return true;\n}\n\nResult runBaseline(const Tri& initial) {\n    Result res;\n    res.board = initial;\n    res.ops.reserve(5000);\n\n    auto swapBall = [&](int x1, int y1, int x2, int y2) {\n        res.ops.push_back({x1, y1, x2, y2});\n        swap(res.board[x1][y1], res.board[x2][y2]);\n    };\n\n    for (int x = N - 2; x >= 0; --x) {\n        for (int y = 0; y <= x; ++y) {\n            int cx = x, cy = y;\n            while (cx < N - 1) {\n                int left = res.board[cx + 1][cy];\n                int right = res.board[cx + 1][cy + 1];\n                int mn = min(left, right);\n                if (res.board[cx][cy] <= mn) break;\n                int ny = (left < right ? cy : cy + 1);\n                swapBall(cx, cy, cx + 1, ny);\n                ++cx;\n                cy = ny;\n            }\n        }\n    }\n    return res;\n}\n\nstruct XorShift {\n    uint64_t state;\n    explicit XorShift(uint64_t seed) : state(seed ? seed : 1) {}\n    uint32_t next() {\n        uint64_t x = state;\n        x ^= x << 7;\n        x ^= x >> 9;\n        return state = x;\n    }\n};\n\nbool runPriorityFix(const Tri& initial, int upperBound, Result& out, XorShift& rng, int mode) {\n    if (upperBound <= 0) return false;\n    upperBound = min(upperBound, LIMIT);\n    Tri board = initial;\n    vector<array<int, 4>> ops;\n    ops.reserve(upperBound);\n\n    auto calcPriority = [&](int x, int diff) -> int {\n        int depth = N - 1 - x; // deeper => smaller depth\n        switch (mode % 6) {\n            case 0: return diff;\n            case 1: return diff * (depth + 1);\n            case 2: return diff * (depth + 1) + depth;\n            case 3: return diff * (depth + 1) * (depth + 1);\n            case 4: return diff * 2 + depth;\n            case 5: return diff * (depth + 1) + diff;\n            default: return diff;\n        }\n    };\n\n    struct Node {\n        int pri, x, y;\n        uint32_t rd;\n        bool operator<(const Node& other) const {\n            if (pri != other.pri) return pri < other.pri;\n            return rd < other.rd;\n        }\n    };\n    priority_queue<Node> pq;\n\n    auto pushNode = [&](int x, int y) {\n        if (x < 0 || x >= N - 1 || y < 0 || y > x) return;\n        int left = board[x + 1][y];\n        int right = board[x + 1][y + 1];\n        int diff = board[x][y] - min(left, right);\n        if (diff > 0) {\n            int pri = calcPriority(x, diff);\n            pq.push(Node{pri, x, y, rng.next()});\n        }\n    };\n\n    for (int x = 0; x < N - 1; ++x)\n        for (int y = 0; y <= x; ++y)\n            pushNode(x, y);\n\n    while (!pq.empty()) {\n        if ((int)ops.size() >= upperBound) return false;\n        Node cur = pq.top(); pq.pop();\n        int x = cur.x, y = cur.y;\n        if (x >= N - 1) continue;\n        int left = board[x + 1][y];\n        int right = board[x + 1][y + 1];\n        int mn = min(left, right);\n        if (board[x][y] <= mn) continue;\n        int childY;\n        if (left == right) {\n            childY = (rng.next() & 1) ? y : y + 1;\n        } else {\n            childY = (left < right ? y : y + 1);\n        }\n        int cx = x + 1, cy = childY;\n        ops.push_back({x, y, cx, cy});\n        swap(board[x][y], board[cx][cy]);\n\n        pushNode(x, y);\n        pushNode(cx, cy);\n        pushNode(x - 1, y - 1);\n        pushNode(x - 1, y);\n        if (childY == y) pushNode(x, y - 1);\n        else pushNode(x, y + 1);\n    }\n\n    if ((int)ops.size() >= upperBound) return false;\n    if (countViolations(board) != 0) return false;\n    out.board = move(board);\n    out.ops = move(ops);\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Tri initial(N);\n    for (int x = 0; x < N; ++x) {\n        initial[x].resize(x + 1);\n        for (int y = 0; y <= x; ++y) cin >> initial[x][y];\n    }\n\n    Result baseline = runBaseline(initial);\n    ensureValid(baseline, initial);\n\n    Result best = baseline;\n    int bestK = best.ops.size();\n\n    uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n    seed ^= (uint64_t)initial[0][0] << 21;\n    XorShift rng(seed);\n\n    const double TIME_LIMIT = 1.80;\n    auto start = chrono::steady_clock::now();\n    vector<int> modes = {0, 1, 2, 3, 4, 5};\n    int attempt = 0;\n\n    while (true) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        if (elapsed > TIME_LIMIT) break;\n        if (bestK <= 1) break;\n        int bound = bestK - 1;\n        if (bound <= 0) break;\n        Result cand;\n        int mode = modes[attempt % modes.size()];\n        if (runPriorityFix(initial, bound, cand, rng, mode)) {\n            if ((int)cand.ops.size() < bestK) {\n                best = move(cand);\n                bestK = best.ops.size();\n            }\n        }\n        ++attempt;\n        if (attempt > 200) break; // safety bound\n    }\n\n    if (!ensureValid(best, initial)) {\n        best = baseline;\n        ensureValid(best, initial);\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (const auto& op : best.ops) {\n        cout << op[0] << ' ' << op[1] << ' ' << op[2] << ' ' << op[3] << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int DX[4] = {1, -1, 0, 0};\nconst int DY[4] = {0, 0, 1, -1};\n\nconst int EMPTY     = -1;\nconst int ENTRANCE  = -2;\nconst int OBSTACLE  = -3;\nconst int TEMPBLOCK = -4;\n\nint D;\nint entrance_i, entrance_j;\nvector<vector<int>> grid;\nvector<vector<int>> dist_from_entrance;\nvector<pair<int,int>> target_order;\nvector<vector<int>> target_rank;\nvector<int> remaining_small;   // unseen IDs prefix counts\nvector<int> empty_prefix;      // empty ranks prefix counts\nint total_cells = 0;\nint empty_cells_remaining = 0;\nlong long tie_counter = 0;\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < D && 0 <= y && y < D;\n}\n\nvector<vector<int>> compute_dist(const vector<vector<int>>& base_grid) {\n    const int INF = 1e9;\n    vector<vector<int>> dist(D, vector<int>(D, INF));\n    queue<pair<int,int>> q;\n    q.push({entrance_i, entrance_j});\n    dist[entrance_i][entrance_j] = 0;\n    while (!q.empty()) {\n        auto [x, y] = q.front(); q.pop();\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = x + DX[dir];\n            int ny = y + DY[dir];\n            if (!inside(nx, ny)) continue;\n            if (base_grid[nx][ny] == OBSTACLE) continue;\n            if (dist[nx][ny] != INF) continue;\n            dist[nx][ny] = dist[x][y] + 1;\n            q.push({nx, ny});\n        }\n    }\n    return dist;\n}\n\nbool is_safe_offline(vector<vector<int>>& state, int x, int y, int remain) {\n    if (state[x][y] != 0) return false;\n    state[x][y] = -1;\n    queue<int> q;\n    vector<char> visited(D * D, 0);\n    int start = entrance_i * D + entrance_j;\n    q.push(start);\n    visited[start] = 1;\n    int reachable = 0;\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int cx = v / D;\n        int cy = v % D;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = cx + DX[dir];\n            int ny = cy + DY[dir];\n            if (!inside(nx, ny)) continue;\n            int nid = nx * D + ny;\n            if (visited[nid]) continue;\n            if (state[nx][ny] == -1) continue;\n            visited[nid] = 1;\n            q.push(nid);\n            if (state[nx][ny] == 0) ++reachable;\n        }\n    }\n    state[x][y] = 0;\n    return reachable == remain - 1;\n}\n\nvector<pair<int,int>> compute_target_order(const vector<vector<int>>& base_grid) {\n    vector<vector<int>> state(D, vector<int>(D, -1));\n    int remain = 0;\n    for (int i = 0; i < D; ++i) {\n        for (int j = 0; j < D; ++j) {\n            if (base_grid[i][j] == OBSTACLE) continue;\n            if (i == entrance_i && j == entrance_j) {\n                state[i][j] = -2;\n            } else {\n                state[i][j] = 0;\n                ++remain;\n            }\n        }\n    }\n\n    vector<pair<int,int>> elimination;\n    elimination.reserve(remain);\n\n    while (remain > 0) {\n        pair<int,int> best = {-1, -1};\n        int bestScore = INT_MIN;\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (state[i][j] != 0) continue;\n                if (!is_safe_offline(state, i, j, remain)) continue;\n                int score = dist_from_entrance[i][j] * 1000 - (abs(i - entrance_i) + abs(j - entrance_j));\n                if (score > bestScore) {\n                    bestScore = score;\n                    best = {i, j};\n                }\n            }\n        }\n        if (best.first == -1) {\n            for (int i = 0; i < D && best.first == -1; ++i) {\n                for (int j = 0; j < D; ++j) {\n                    if (state[i][j] == 0) {\n                        best = {i, j};\n                        break;\n                    }\n                }\n            }\n        }\n        elimination.push_back(best);\n        state[best.first][best.second] = -1;\n        --remain;\n    }\n\n    vector<pair<int,int>> retrieval = elimination;\n    reverse(retrieval.begin(), retrieval.end());\n    return retrieval;\n}\n\nbool is_safe_cell(int x, int y) {\n    grid[x][y] = TEMPBLOCK;\n    queue<int> q;\n    vector<char> visited(D * D, 0);\n    int start = entrance_i * D + entrance_j;\n    q.push(start);\n    visited[start] = 1;\n    int reachable = 0;\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int cx = v / D;\n        int cy = v % D;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = cx + DX[dir];\n            int ny = cy + DY[dir];\n            if (!inside(nx, ny)) continue;\n            int nid = nx * D + ny;\n            if (visited[nid]) continue;\n            int val = grid[nx][ny];\n            if (val == OBSTACLE || val == TEMPBLOCK) continue;\n            if (val >= 0) continue;\n            visited[nid] = 1;\n            q.push(nid);\n            if (val == EMPTY) ++reachable;\n        }\n    }\n    grid[x][y] = EMPTY;\n    return reachable == empty_cells_remaining - 1;\n}\n\npair<int,int> choose_cell(int number) {\n    const long long DIFF_WEIGHT  = 4000;\n    const long long NEG_EXTRA    = 25000;\n    const long long DIST_WEIGHT  = 200;\n    const long long DEGREE_WEIGHT = 80;\n\n    int bestDef = INT_MAX;\n    long long bestCost = (1LL << 60);\n    pair<int,int> best = {-1, -1};\n\n    for (int i = 0; i < D; ++i) {\n        for (int j = 0; j < D; ++j) {\n            if (grid[i][j] != EMPTY) continue;\n            if (!is_safe_cell(i, j)) continue;\n            int r = target_rank[i][j];\n            if (r < 0) continue;\n\n            int deficit = 0;\n            if (bestDef != 0) {\n                for (int q = r; q < total_cells; ++q) {\n                    int need = remaining_small[q];\n                    if (need == 0) continue;\n                    int avail = empty_prefix[q] - 1;\n                    if (avail < need) {\n                        deficit += need - avail;\n                        if (bestDef != INT_MAX && deficit > bestDef) break;\n                    }\n                }\n                if (bestDef != INT_MAX && deficit > bestDef) continue;\n            } else {\n                bool ok = true;\n                for (int q = r; q < total_cells; ++q) {\n                    int need = remaining_small[q];\n                    if (need == 0) continue;\n                    int avail = empty_prefix[q] - 1;\n                    if (avail < need) { ok = false; break; }\n                }\n                if (!ok) continue;\n                deficit = 0;\n            }\n\n            long long diff = (long long)r - number;\n            long long absdiff = llabs(diff);\n            long long cost = absdiff * absdiff * DIFF_WEIGHT;\n            if (diff < 0) cost += (-diff) * NEG_EXTRA;\n            cost += (long long)dist_from_entrance[i][j] * DIST_WEIGHT;\n\n            int degree = 0;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + DX[dir];\n                int nj = j + DY[dir];\n                if (!inside(ni, nj)) continue;\n                if (grid[ni][nj] == EMPTY) ++degree;\n            }\n            int leafScore = max(0, 3 - degree);\n            cost += (long long)leafScore * DEGREE_WEIGHT;\n\n            cost = (cost << 4) + (tie_counter++ & 15);\n\n            if (deficit < bestDef || (deficit == bestDef && cost < bestCost)) {\n                bestDef = deficit;\n                bestCost = cost;\n                best = {i, j};\n            }\n        }\n    }\n\n    if (best.first == -1) {\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (grid[i][j] == EMPTY && is_safe_cell(i, j)) {\n                    best = {i, j};\n                    break;\n                }\n            }\n            if (best.first != -1) break;\n        }\n    }\n\n    return best;\n}\n\nvector<pair<int,int>> build_retrieval_order() {\n    vector<pair<int,int>> order;\n    order.reserve(total_cells);\n    vector<vector<char>> cleared(D, vector<char>(D, 0));\n    vector<vector<char>> in_queue(D, vector<char>(D, 0));\n    cleared[entrance_i][entrance_j] = 1;\n\n    struct Node {\n        int value;\n        int rank;\n        long long tie;\n        int x, y;\n    };\n    struct Cmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.value != b.value) return a.value > b.value;\n            if (a.rank  != b.rank)  return a.rank > b.rank;\n            return a.tie > b.tie;\n        }\n    };\n\n    priority_queue<Node, vector<Node>, Cmp> pq;\n\n    auto push_node = [&](int x, int y) {\n        if (!inside(x, y)) return;\n        if (cleared[x][y]) return;\n        if (grid[x][y] < 0) return;\n        if (in_queue[x][y]) return;\n        pq.push(Node{grid[x][y], target_rank[x][y], tie_counter++, x, y});\n        in_queue[x][y] = 1;\n    };\n\n    for (int dir = 0; dir < 4; ++dir)\n        push_node(entrance_i + DX[dir], entrance_j + DY[dir]);\n\n    auto refill = [&]() {\n        if (!pq.empty()) return;\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (grid[i][j] < 0 || cleared[i][j] || in_queue[i][j]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + DX[dir];\n                    int nj = j + DY[dir];\n                    if (!inside(ni, nj)) continue;\n                    if (cleared[ni][nj]) {\n                        push_node(i, j);\n                        break;\n                    }\n                }\n            }\n        }\n    };\n\n    while ((int)order.size() < total_cells) {\n        refill();\n        if (pq.empty()) break;\n        Node cur = pq.top(); pq.pop();\n        if (cleared[cur.x][cur.y]) continue;\n        order.push_back({cur.x, cur.y});\n        cleared[cur.x][cur.y] = 1;\n        grid[cur.x][cur.y] = EMPTY;\n        for (int dir = 0; dir < 4; ++dir)\n            push_node(cur.x + DX[dir], cur.y + DY[dir]);\n    }\n    return order;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> D >> N)) return 0;\n    entrance_i = 0;\n    entrance_j = (D - 1) / 2;\n\n    grid.assign(D, vector<int>(D, EMPTY));\n    for (int k = 0; k < N; ++k) {\n        int r, c; cin >> r >> c;\n        grid[r][c] = OBSTACLE;\n    }\n    grid[entrance_i][entrance_j] = ENTRANCE;\n\n    vector<vector<int>> base_grid = grid;\n\n    dist_from_entrance = compute_dist(base_grid);\n    target_order = compute_target_order(base_grid);\n    total_cells = (int)target_order.size();\n\n    target_rank.assign(D, vector<int>(D, -1));\n    for (int idx = 0; idx < total_cells; ++idx) {\n        auto [x, y] = target_order[idx];\n        target_rank[x][y] = idx;\n    }\n\n    remaining_small.assign(total_cells, 0);\n    empty_prefix.assign(total_cells, 0);\n    for (int q = 0; q < total_cells; ++q) {\n        remaining_small[q] = q + 1;\n        empty_prefix[q] = q + 1;\n    }\n\n    empty_cells_remaining = total_cells;\n    int total_containers = total_cells;\n\n    for (int step = 0; step < total_containers; ++step) {\n        int t; cin >> t;\n        for (int q = t; q < total_cells; ++q)\n            --remaining_small[q];\n\n        auto cell = choose_cell(t);\n        grid[cell.first][cell.second] = t;\n        --empty_cells_remaining;\n\n        int r = target_rank[cell.first][cell.second];\n        for (int q = r; q < total_cells; ++q)\n            --empty_prefix[q];\n\n        cout << cell.first << ' ' << cell.second << '\\n' << flush;\n    }\n\n    auto retrieval = build_retrieval_order();\n    for (auto [x, y] : retrieval)\n        cout << x << ' ' << y << '\\n';\n    cout.flush();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr double TIME_LIMIT = 1.90;  // seconds\n    static constexpr double ZERO_WEIGHT = 4.0;  // weight of zero adjacency in priority score\n    static constexpr double ANCHOR_JITTER = 6.0;\n\n    int n, m, m1, N;\n    vector<int> initialBoard;\n    vector<int> initialColorCount;\n    vector<vector<int>> colorCells;\n    vector<double> centroidRow, centroidCol;\n    vector<int> baseAdjCount;\n    vector<char> canTouchZero;\n    vector<int> bestBoard;\n    int bestZero = 0;\n\n    chrono::steady_clock::time_point startTime;\n    mt19937_64 rng;\n\n    const array<int, 4> di{-1, 1, 0, 0};\n    const array<int, 4> dj{0, 0, -1, 1};\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    inline int adjIndex(int a, int b) const { return a * m1 + b; }\n\n    inline void changeAdj(vector<int>& adj, int a, int b, int delta) const {\n        if (a == b || delta == 0) return;\n        int idx1 = adjIndex(a, b);\n        int idx2 = adjIndex(b, a);\n        adj[idx1] += delta;\n        adj[idx2] += delta;\n    }\n\n    inline int getAdj(const vector<int>& adj, int a, int b) const {\n        return adj[adjIndex(a, b)];\n    }\n\n    bool checkConnectivity(int removeIdx, int color, const vector<int>& board,\n                           const vector<int>& colorCount, vector<int>& visitStamp,\n                           int& visitToken) const {\n        int remaining = colorCount[color] - 1;\n        if (remaining <= 0) return false;\n\n        int start = -1;\n        int ri = removeIdx / n;\n        int rj = removeIdx % n;\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = ri + di[dir];\n            int nj = rj + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n            int nidx = ni * n + nj;\n            if (board[nidx] == color) {\n                start = nidx;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        visitToken++;\n        if (visitToken == INT_MAX) {\n            fill(visitStamp.begin(), visitStamp.end(), 0);\n            visitToken = 1;\n        }\n        visitStamp[start] = visitToken;\n        queue<int> q;\n        q.push(start);\n        int reached = 0;\n        while (!q.empty()) {\n            int cur = q.front();\n            q.pop();\n            reached++;\n            if (reached == remaining) return true;\n            int ci = cur / n;\n            int cj = cur % n;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = ci + di[dir];\n                int nj = cj + dj[dir];\n                if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n                int nidx = ni * n + nj;\n                if (nidx == removeIdx) continue;\n                if (board[nidx] == color && visitStamp[nidx] != visitToken) {\n                    visitStamp[nidx] = visitToken;\n                    q.push(nidx);\n                }\n            }\n        }\n        return reached == remaining;\n    }\n\n    bool tryRemove(int idx, vector<int>& board, vector<int>& colorCount,\n                   vector<int>& adjCount, vector<int>& visitStamp, int& visitToken) const {\n        int c = board[idx];\n        if (c == 0 || !canTouchZero[c] || colorCount[c] <= 1) return false;\n\n        int i = idx / n;\n        int j = idx % n;\n\n        int zeroEdges = 0;\n        int sameNeighbors = 0;\n        int neighborColors[4];\n        int neighborEdges[4];\n        int neighborKinds = 0;\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                zeroEdges++;\n                continue;\n            }\n            int nidx = ni * n + nj;\n            int d = board[nidx];\n            if (d == 0) {\n                zeroEdges++;\n            } else if (d == c) {\n                sameNeighbors++;\n            } else {\n                if (!canTouchZero[d]) return false;\n                bool found = false;\n                for (int t = 0; t < neighborKinds; ++t) {\n                    if (neighborColors[t] == d) {\n                        neighborEdges[t]++;\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) {\n                    neighborColors[neighborKinds] = d;\n                    neighborEdges[neighborKinds] = 1;\n                    neighborKinds++;\n                }\n            }\n        }\n\n        if (zeroEdges == 0) return false;\n        if (getAdj(adjCount, c, 0) <= zeroEdges) return false;\n        for (int t = 0; t < neighborKinds; ++t) {\n            int d = neighborColors[t];\n            if (getAdj(adjCount, c, d) <= neighborEdges[t]) return false;\n        }\n\n        if (sameNeighbors >= 2) {\n            if (!checkConnectivity(idx, c, board, colorCount, visitStamp, visitToken)) {\n                return false;\n            }\n        }\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                changeAdj(adjCount, c, 0, -1);\n            } else {\n                int nidx = ni * n + nj;\n                int d = board[nidx];\n                if (d == c) continue;\n                changeAdj(adjCount, c, d, -1);\n            }\n        }\n\n        board[idx] = 0;\n        colorCount[c]--;\n        colorCount[0]++;\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n            int nidx = ni * n + nj;\n            int d = board[nidx];\n            if (d == 0) continue;\n            changeAdj(adjCount, 0, d, +1);\n        }\n\n        return true;\n    }\n\n    struct IterationResult {\n        vector<int> board;\n        int zeroCount;\n    };\n\n    IterationResult runIteration(bool usePriority, const vector<pair<double, double>>& anchors) {\n        vector<int> board = initialBoard;\n        vector<int> colorCount = initialColorCount;\n        vector<int> adjCount = baseAdjCount;\n        vector<int> visitStamp(N, 0);\n        int visitToken = 1;\n\n        auto zeroAdjCount = [&](int idx) -> int {\n            int i = idx / n;\n            int j = idx % n;\n            int cnt = 0;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + di[dir];\n                int nj = j + dj[dir];\n                if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                    cnt++;\n                } else if (board[ni * n + nj] == 0) {\n                    cnt++;\n                }\n            }\n            return cnt;\n        };\n\n        if (usePriority) {\n            struct Entry {\n                double score;\n                int idx;\n                int version;\n                bool operator<(const Entry& other) const { return score < other.score; }\n            };\n            priority_queue<Entry> pq;\n            vector<int> version(N, 0);\n            uniform_real_distribution<double> noiseDist(0.0, 1.0);\n\n            auto pushCandidate = [&](int idx) {\n                if (idx < 0 || idx >= N) return;\n                if (board[idx] == 0) return;\n                int c = board[idx];\n                if (!canTouchZero[c]) return;\n                int zeroAdj = zeroAdjCount(idx);\n                if (zeroAdj == 0) return;\n                int i = idx / n;\n                int j = idx % n;\n                double dist = fabs(i - anchors[c].first) + fabs(j - anchors[c].second);\n                double score = dist + ZERO_WEIGHT * zeroAdj + noiseDist(rng);\n                int ver = ++version[idx];\n                pq.push({score, idx, ver});\n            };\n\n            for (int i = 0; i < n; ++i) {\n                pushCandidate(i * n);\n                pushCandidate(i * n + (n - 1));\n            }\n            for (int j = 0; j < n; ++j) {\n                pushCandidate(j);\n                pushCandidate((n - 1) * n + j);\n            }\n\n            while (!pq.empty()) {\n                if (elapsed() > TIME_LIMIT) break;\n                auto cur = pq.top();\n                pq.pop();\n                if (cur.version != version[cur.idx]) continue;\n                int idx = cur.idx;\n                if (board[idx] == 0) continue;\n                int c = board[idx];\n                if (!canTouchZero[c]) continue;\n                if (zeroAdjCount(idx) == 0) continue;\n                if (!tryRemove(idx, board, colorCount, adjCount, visitStamp, visitToken)) continue;\n                int ci = idx / n;\n                int cj = idx % n;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = ci + di[dir];\n                    int nj = cj + dj[dir];\n                    if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n                    pushCandidate(ni * n + nj);\n                }\n            }\n        } else {\n            vector<int> frontier;\n            frontier.reserve(N);\n            vector<char> inFrontier(N, 0);\n\n            auto pushCandidate = [&](int idx) {\n                if (idx < 0 || idx >= N) return;\n                if (board[idx] == 0) return;\n                if (inFrontier[idx]) return;\n                int c = board[idx];\n                if (!canTouchZero[c]) return;\n                if (zeroAdjCount(idx) == 0) return;\n                inFrontier[idx] = 1;\n                frontier.push_back(idx);\n            };\n\n            for (int i = 0; i < n; ++i) {\n                pushCandidate(i * n);\n                pushCandidate(i * n + (n - 1));\n            }\n            for (int j = 0; j < n; ++j) {\n                pushCandidate(j);\n                pushCandidate((n - 1) * n + j);\n            }\n\n            while (!frontier.empty()) {\n                if (elapsed() > TIME_LIMIT) break;\n                int pos = rng() % frontier.size();\n                int idx = frontier[pos];\n                frontier[pos] = frontier.back();\n                frontier.pop_back();\n                inFrontier[idx] = 0;\n                if (board[idx] == 0) continue;\n                int c = board[idx];\n                if (!canTouchZero[c]) continue;\n                if (zeroAdjCount(idx) == 0) continue;\n                if (!tryRemove(idx, board, colorCount, adjCount, visitStamp, visitToken)) continue;\n                int ci = idx / n;\n                int cj = idx % n;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = ci + di[dir];\n                    int nj = cj + dj[dir];\n                    if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n                    pushCandidate(ni * n + nj);\n                }\n            }\n        }\n\n        return {std::move(board), colorCount[0]};\n    }\n\n    void readInput() {\n        cin >> n >> m;\n        m1 = m + 1;\n        N = n * n;\n        initialBoard.assign(N, 0);\n        colorCells.assign(m1, {});\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int c;\n                cin >> c;\n                initialBoard[i * n + j] = c;\n                colorCells[c].push_back(i * n + j);\n            }\n        }\n    }\n\n    void precompute() {\n        initialColorCount.assign(m1, 0);\n        centroidRow.assign(m1, 0.0);\n        centroidCol.assign(m1, 0.0);\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int idx = i * n + j;\n                int c = initialBoard[idx];\n                initialColorCount[c]++;\n                centroidRow[c] += i;\n                centroidCol[c] += j;\n            }\n        }\n        for (int c = 0; c <= m; ++c) {\n            if (initialColorCount[c] > 0) {\n                centroidRow[c] /= initialColorCount[c];\n                centroidCol[c] /= initialColorCount[c];\n            }\n        }\n\n        baseAdjCount.assign(m1 * m1, 0);\n        auto addEdge = [&](int a, int b) {\n            if (a == b) return;\n            int idx1 = adjIndex(a, b);\n            int idx2 = adjIndex(b, a);\n            baseAdjCount[idx1] += 1;\n            baseAdjCount[idx2] += 1;\n        };\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int idx = i * n + j;\n                int c = initialBoard[idx];\n                if (i + 1 < n) addEdge(c, initialBoard[(i + 1) * n + j]);\n                if (j + 1 < n) addEdge(c, initialBoard[i * n + (j + 1)]);\n                if (i == 0) addEdge(c, 0);\n                if (i == n - 1) addEdge(c, 0);\n                if (j == 0) addEdge(c, 0);\n                if (j == n - 1) addEdge(c, 0);\n            }\n        }\n\n        canTouchZero.assign(m1, 0);\n        canTouchZero[0] = 1;\n        for (int c = 1; c <= m; ++c) {\n            if (baseAdjCount[adjIndex(c, 0)] > 0) {\n                canTouchZero[c] = 1;\n            }\n        }\n\n        bestBoard = initialBoard;\n        bestZero = initialColorCount[0];\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        readInput();\n        precompute();\n\n        startTime = chrono::steady_clock::now();\n        rng.seed(startTime.time_since_epoch().count());\n\n        vector<pair<double, double>> anchors(m1, {0.0, 0.0});\n        vector<pair<double, double>> dummyAnchors(m1, {0.0, 0.0});\n        uniform_real_distribution<double> jitterDist(-ANCHOR_JITTER, ANCHOR_JITTER);\n\n        int iteration = 0;\n        while (elapsed() < TIME_LIMIT) {\n            bool usePriority = (iteration % 3 != 2);\n            if (usePriority) {\n                bool useRandomCellAnchor = (iteration % 6 == 0);\n                for (int c = 1; c <= m; ++c) {\n                    if (useRandomCellAnchor && !colorCells[c].empty()) {\n                        int pick = colorCells[c][rng() % colorCells[c].size()];\n                        anchors[c].first = pick / n;\n                        anchors[c].second = pick % n;\n                    } else {\n                        double baseR = centroidRow[c];\n                        double baseC = centroidCol[c];\n                        anchors[c].first = clamp(baseR + jitterDist(rng), 0.0, double(n - 1));\n                        anchors[c].second = clamp(baseC + jitterDist(rng), 0.0, double(n - 1));\n                    }\n                }\n            }\n            const auto& anchorRef = usePriority ? anchors : dummyAnchors;\n            IterationResult res = runIteration(usePriority, anchorRef);\n            if (res.zeroCount > bestZero) {\n                bestZero = res.zeroCount;\n                bestBoard = std::move(res.board);\n            }\n            iteration++;\n            if (elapsed() > TIME_LIMIT) break;\n        }\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                if (j) cout << ' ';\n                cout << bestBoard[i * n + j];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Query {\n    vector<int> idx;\n    vector<int8_t> coeff;\n    double scale = 1.0;\n    double invScale = 1.0;\n    double invScaleSq = 1.0;\n    int result = 0; // 1: L>R, -1: L<R, 0: equal\n};\n\nvector<double> estimate_weights(const vector<Query>& queries, int N, mt19937& rng) {\n    vector<double> w(N, 1.0);\n    if (queries.empty()) return w;\n    const double minW = 1e-6;\n    const double lr_main = 0.05;\n    const double lr_eq = 0.04;\n    const double reg = 1e-4;\n    uniform_int_distribution<int> qdist(0, (int)queries.size() - 1);\n    int iterations = min(200000, max(20000, 30 * (int)queries.size()));\n\n    for (int iter = 0; iter < iterations; ++iter) {\n        const Query& qu = queries[qdist(rng)];\n        if (qu.idx.empty()) continue;\n        double diff = 0.0;\n        for (size_t k = 0; k < qu.idx.size(); ++k) diff += w[qu.idx[k]] * qu.coeff[k];\n\n        if (qu.result == 0) {\n            double grad_base = diff * qu.invScaleSq;\n            for (size_t k = 0; k < qu.idx.size(); ++k) {\n                int idx = qu.idx[k];\n                double grad = grad_base * qu.coeff[k] + reg * w[idx];\n                w[idx] -= lr_eq * grad;\n                if (w[idx] < minW) w[idx] = minW;\n            }\n        } else {\n            int y = qu.result;\n            double score = diff * qu.invScale;\n            double s = y * score;\n            double sigma;\n            if (s >= 0) {\n                double e = exp(-s);\n                sigma = e / (1.0 + e);\n            } else {\n                double e = exp(s);\n                sigma = 1.0 / (1.0 + e);\n            }\n            double grad_base = -y * sigma * qu.invScale;\n            for (size_t k = 0; k < qu.idx.size(); ++k) {\n                int idx = qu.idx[k];\n                double grad = grad_base * qu.coeff[k] + reg * w[idx];\n                w[idx] -= lr_main * grad;\n                if (w[idx] < minW) w[idx] = minW;\n            }\n        }\n\n        if ((iter & 255) == 0) {\n            double mean = 0.0;\n            for (double val : w) mean += val;\n            mean /= N;\n            if (mean > 0) for (double &val : w) val /= mean;\n        }\n    }\n\n    double perceptron_lr = 0.02;\n    for (int pass = 0; pass < 2; ++pass) {\n        for (const Query& qu : queries) {\n            if (qu.idx.empty()) continue;\n            double diff = 0.0;\n            for (size_t k = 0; k < qu.idx.size(); ++k) diff += w[qu.idx[k]] * qu.coeff[k];\n            double margin = 0.05 * qu.scale;\n            bool violation = false;\n            if (qu.result == 1) {\n                if (diff < margin) violation = true;\n            } else if (qu.result == -1) {\n                if (diff > -margin) violation = true;\n            } else {\n                if (fabs(diff) > margin) violation = true;\n            }\n            if (!violation) continue;\n\n            if (qu.result == 0) {\n                double grad_base = diff * qu.invScaleSq;\n                for (size_t k = 0; k < qu.idx.size(); ++k) {\n                    int idx = qu.idx[k];\n                    w[idx] -= perceptron_lr * grad_base * qu.coeff[k];\n                    if (w[idx] < minW) w[idx] = minW;\n                }\n            } else {\n                for (size_t k = 0; k < qu.idx.size(); ++k) {\n                    int idx = qu.idx[k];\n                    w[idx] += perceptron_lr * qu.result * qu.coeff[k];\n                    if (w[idx] < minW) w[idx] = minW;\n                }\n            }\n        }\n        double mean = 0.0;\n        for (double val : w) mean += val;\n        mean /= N;\n        if (mean > 0) for (double &val : w) val /= mean;\n    }\n\n    double sum = 0.0;\n    for (double val : w) sum += val;\n    if (sum > 0) {\n        double factor = (double)N / sum;\n        for (double &val : w) val *= factor;\n    }\n    return w;\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    vector<Query> queries;\n    queries.reserve(Q);\n    vector<double> biasScore(N, 0.0);\n\n    mt19937 rng(\n        (uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> uniform01(0.0, 1.0);\n\n    auto ask = [&](const vector<int>& L, const vector<int>& R) -> int {\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string resp;\n        if (!(cin >> resp)) exit(0);\n        int res = 0;\n        if (!resp.empty()) {\n            if (resp[0] == '>') res = 1;\n            else if (resp[0] == '<') res = -1;\n        }\n\n        Query q;\n        q.result = res;\n        q.idx.reserve(L.size() + R.size());\n        q.coeff.reserve(L.size() + R.size());\n        for (int x : L) { q.idx.push_back(x); q.coeff.push_back(1); }\n        for (int x : R) { q.idx.push_back(x); q.coeff.push_back(-1); }\n        int len = (int)q.idx.size();\n        if (len == 0) len = 1;\n        q.scale = sqrt((double)len);\n        q.invScale = 1.0 / q.scale;\n        q.invScaleSq = q.invScale * q.invScale;\n        queries.push_back(std::move(q));\n\n        if (res == 1) {\n            for (int x : L) biasScore[x] += 1.0;\n            for (int x : R) biasScore[x] -= 1.0;\n        } else if (res == -1) {\n            for (int x : L) biasScore[x] -= 1.0;\n            for (int x : R) biasScore[x] += 1.0;\n        }\n        return res;\n    };\n\n    int champion = 0;\n    for (int i = 1; i < N && (int)queries.size() < Q; ++i) {\n        vector<int> L = {champion};\n        vector<int> R = {i};\n        int res = ask(L, R);\n        if (res == -1) champion = i;\n    }\n\n    while ((int)queries.size() < Q) {\n        vector<int> L, R;\n        int type = rng() % 3;\n        if (type == 0) {\n            int a = rng() % N;\n            int b = rng() % N;\n            while (b == a) b = rng() % N;\n            L = {a};\n            R = {b};\n        } else if (type == 1) {\n            vector<int> picks;\n            picks.reserve(4);\n            while ((int)picks.size() < 4) {\n                int x = rng() % N;\n                bool ok = true;\n                for (int y : picks) if (y == x) { ok = false; break; }\n                if (ok) picks.push_back(x);\n            }\n            L = {picks[0], picks[1]};\n            R = {picks[2], picks[3]};\n        } else {\n            double density = 0.18 + 0.22 * (double)N / 100.0;\n            density = min(0.35, max(0.18, density));\n            for (int i = 0; i < N; ++i) {\n                double v = uniform01(rng);\n                if (v < density) L.push_back(i);\n                else if (v < 2.0 * density) R.push_back(i);\n            }\n            if (L.empty() && !R.empty()) {\n                L.push_back(R.back());\n                R.pop_back();\n            }\n            if (R.empty() && !L.empty()) {\n                R.push_back(L.back());\n                L.pop_back();\n            }\n            if (L.empty() || R.empty()) {\n                int a = rng() % N;\n                int b = rng() % N;\n                while (b == a) b = rng() % N;\n                L = {a};\n                R = {b};\n            }\n        }\n        ask(L, R);\n    }\n\n    vector<double> weights = estimate_weights(queries, N, rng);\n\n    double maxAbs = 0.0;\n    for (double s : biasScore) maxAbs = max(maxAbs, fabs(s));\n    if (maxAbs < 1e-9) maxAbs = 1.0;\n    const double alpha = 0.4;\n    for (int i = 0; i < N; ++i) {\n        double factor = 1.0 + alpha * (biasScore[i] / maxAbs);\n        weights[i] *= factor;\n        if (weights[i] < 1e-6) weights[i] = 1e-6;\n    }\n\n    double sum = 0.0;\n    for (double v : weights) sum += v;\n    if (sum > 0.0) {\n        double factor = (double)N / sum;\n        for (double &v : weights) v *= factor;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        double noise = 0.98 + 0.04 * uniform01(rng);\n        weights[i] *= noise;\n    }\n    sum = 0.0;\n    for (double v : weights) sum += v;\n    if (sum > 0.0) {\n        double factor = (double)N / sum;\n        for (double &v : weights) v *= factor;\n    }\n\n    double mean = 0.0;\n    for (double v : weights) mean += v;\n    mean /= N;\n    double var = 0.0;\n    for (double v : weights) {\n        double diff = v - mean;\n        var += diff * diff;\n    }\n    var /= N;\n    if (var < 1e-4) {\n        for (int i = 0; i < N; ++i) {\n            double factor = 1.0 + 0.5 * (biasScore[i] / maxAbs);\n            weights[i] = max(1e-6, factor);\n        }\n        sum = 0.0;\n        for (double v : weights) sum += v;\n        if (sum > 0.0) {\n            double factor = (double)N / sum;\n            for (double &v : weights) v *= factor;\n        }\n    }\n\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(),\n         [&](int a, int b) {\n             if (weights[a] != weights[b]) return weights[a] > weights[b];\n             return a < b;\n         });\n\n    vector<int> assignment(N, 0);\n    vector<double> bucket_sum(D, 0.0);\n    vector<int> bucket_size(D, 0);\n\n    for (int idx : order) {\n        int best = 0;\n        for (int d = 1; d < D; ++d) {\n            if (bucket_sum[d] + 1e-9 < bucket_sum[best]) best = d;\n            else if (fabs(bucket_sum[d] - bucket_sum[best]) <= 1e-9 &&\n                     bucket_size[d] < bucket_size[best]) best = d;\n        }\n        assignment[idx] = best;\n        bucket_sum[best] += weights[idx];\n        bucket_size[best] += 1;\n    }\n\n    double total = 0.0;\n    for (double s : bucket_sum) total += s;\n    double target = total / D;\n\n    if (D > 1) {\n        int LS_ITERS = 10000 + 200 * N;\n        uniform_int_distribution<int> distItem(0, N - 1);\n        uniform_int_distribution<int> distBucket(0, D - 1);\n        for (int iter = 0; iter < LS_ITERS; ++iter) {\n            if (rng() & 1) {\n                int i = distItem(rng);\n                int from = assignment[i];\n                int to = distBucket(rng);\n                if (from == to) continue;\n                double wi = weights[i];\n                double sa = bucket_sum[from];\n                double sb = bucket_sum[to];\n                double oldScore = (sa - target) * (sa - target) +\n                                  (sb - target) * (sb - target);\n                double na = sa - wi;\n                double nb = sb + wi;\n                double newScore = (na - target) * (na - target) +\n                                  (nb - target) * (nb - target);\n                if (newScore + 1e-9 < oldScore) {\n                    assignment[i] = to;\n                    bucket_sum[from] = na;\n                    bucket_sum[to] = nb;\n                    bucket_size[from]--;\n                    bucket_size[to]++;\n                }\n            } else {\n                int i = distItem(rng);\n                int j = distItem(rng);\n                if (assignment[i] == assignment[j]) continue;\n                int a = assignment[i];\n                int b = assignment[j];\n                double wi = weights[i];\n                double wj = weights[j];\n                double sa = bucket_sum[a];\n                double sb = bucket_sum[b];\n                double oldScore = (sa - target) * (sa - target) +\n                                  (sb - target) * (sb - target);\n                double na = sa - wi + wj;\n                double nb = sb - wj + wi;\n                double newScore = (na - target) * (na - target) +\n                                  (nb - target) * (nb - target);\n                if (newScore + 1e-9 < oldScore) {\n                    assignment[i] = b;\n                    assignment[j] = a;\n                    bucket_sum[a] = na;\n                    bucket_sum[b] = nb;\n                }\n            }\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << assignment[i];\n    }\n    cout << '\\n' << flush;\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int n, m, bucketSize;\n    vector<vector<int>> stacks;\n    struct Pos {\n        int stack = -1;\n        int idx = -1;\n    };\n    vector<Pos> pos;\n    vector<int> targetStack;\n    vector<pair<int,int>> operations;\n    long long energy = 0;\n\n    int stack_min(int idx) const {\n        if (stacks[idx].empty()) return 1e9;\n        int mn = stacks[idx][0];\n        for (int v : stacks[idx]) mn = min(mn, v);\n        return mn;\n    }\n\n    int choose_destination(int source, const vector<int>& chunk, int chunk_min) {\n        const int INF = 1e9;\n        struct Cand {\n            int idx;\n            bool safe;\n            int stackMin;\n            int match;\n            int height;\n            int top;\n        };\n        Cand bestSafe{ -1, false, -1, -1, -1, -1 };\n        Cand bestUnsafe{ -1, false, -1, -1, -1, -1 };\n        for (int i = 0; i < m; ++i) {\n            if (i == source) continue;\n            bool empty = stacks[i].empty();\n            int topVal = empty ? INF : stacks[i].back();\n            bool safe = empty || topVal >= chunk_min;\n            int smin = empty ? INF : stack_min(i);\n            int match = 0;\n            for (int v : chunk) if (targetStack[v] == i) ++match;\n            int height = (int)stacks[i].size();\n            Cand cand{i, safe, smin, match, height, empty ? INF : topVal};\n\n            if (safe) {\n                if (bestSafe.idx == -1) bestSafe = cand;\n                else {\n                    auto &b = bestSafe;\n                    if (cand.stackMin != b.stackMin) { if (cand.stackMin > b.stackMin) bestSafe = cand; continue; }\n                    if (cand.match != b.match) { if (cand.match > b.match) bestSafe = cand; continue; }\n                    if (cand.height != b.height) { if (cand.height < b.height) bestSafe = cand; continue; }\n                    if (cand.top != b.top) { if (cand.top > b.top) bestSafe = cand; continue; }\n                    if (cand.idx < b.idx) bestSafe = cand;\n                }\n            } else {\n                if (bestUnsafe.idx == -1) bestUnsafe = cand;\n                else {\n                    auto &b = bestUnsafe;\n                    if (cand.top != b.top) { if (cand.top > b.top) bestUnsafe = cand; continue; }\n                    if (cand.stackMin != b.stackMin) { if (cand.stackMin > b.stackMin) bestUnsafe = cand; continue; }\n                    if (cand.height != b.height) { if (cand.height < b.height) bestUnsafe = cand; continue; }\n                    if (cand.match != b.match) { if (cand.match > b.match) bestUnsafe = cand; continue; }\n                    if (cand.idx < b.idx) bestUnsafe = cand;\n                }\n            }\n        }\n        if (bestSafe.idx != -1) return bestSafe.idx;\n        if (bestUnsafe.idx != -1) return bestUnsafe.idx;\n        for (int i = 0; i < m; ++i) if (i != source) return i;\n        return source; // should never happen\n    }\n\n    void move_segment(int box, int dest) {\n        auto p = pos[box];\n        int s = p.stack;\n        int idx = p.idx;\n        if (s == -1 || dest == -1 || s == dest) return;\n        vector<int> segment;\n        segment.reserve(stacks[s].size() - idx);\n        for (int i = idx; i < (int)stacks[s].size(); ++i) segment.push_back(stacks[s][i]);\n        stacks[s].resize(idx);\n        int destStart = stacks[dest].size();\n        stacks[dest].insert(stacks[dest].end(), segment.begin(), segment.end());\n        for (int t = 0; t < (int)segment.size(); ++t) {\n            pos[segment[t]].stack = dest;\n            pos[segment[t]].idx = destStart + t;\n        }\n        operations.emplace_back(box, dest + 1);\n        energy += (long long)segment.size() + 1;\n    }\n\n    void remove_box(int box) {\n        auto p = pos[box];\n        int s = p.stack;\n        if (s == -1) return;\n        stacks[s].pop_back();\n        pos[box].stack = -1;\n        pos[box].idx = -1;\n        operations.emplace_back(box, 0);\n    }\n\n    void solve() {\n        cin >> n >> m;\n        bucketSize = n / m;\n        stacks.assign(m, {});\n        pos.assign(n + 1, {});\n        targetStack.assign(n + 1, 0);\n        for (int v = 1; v <= n; ++v) {\n            targetStack[v] = min(m - 1, (v - 1) / bucketSize);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            stacks[i].resize(bucketSize);\n            for (int j = 0; j < bucketSize; ++j) {\n                int v; cin >> v;\n                stacks[i][j] = v;\n                pos[v].stack = i;\n                pos[v].idx = j;\n            }\n        }\n\n        for (int v = 1; v <= n; ++v) {\n            while (true) {\n                auto p = pos[v];\n                int s = p.stack;\n                if (s == -1) break;\n                int idx = p.idx;\n                if (idx == (int)stacks[s].size() - 1) {\n                    remove_box(v);\n                    break;\n                } else {\n                    vector<int> chunk;\n                    chunk.reserve(stacks[s].size() - idx - 1);\n                    int chunk_min = INT_MAX;\n                    for (int t = idx + 1; t < (int)stacks[s].size(); ++t) {\n                        int val = stacks[s][t];\n                        chunk.push_back(val);\n                        chunk_min = min(chunk_min, val);\n                    }\n                    int dest = choose_destination(s, chunk, chunk_min);\n                    if (dest == s) {\n                        for (int i = 0; i < m; ++i) if (i != s) { dest = i; break; }\n                    }\n                    int box_to_move = stacks[s][idx + 1];\n                    move_segment(box_to_move, dest);\n                }\n            }\n        }\n\n        for (auto [v, i] : operations) {\n            cout << v << ' ' << i << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MOVE_LIMIT = 100000;\n    static constexpr double TIME_LIMIT = 1.95;\n    static constexpr double FINAL_MARGIN = 0.15;\n    static constexpr array<char, 4> DIR_CHARS = {'U', 'D', 'L', 'R'};\n    static constexpr double LOCAL_TWO = 0.03;\n    static constexpr double LOCAL_OR = 0.03;\n    static constexpr double LOCAL_RAND = 0.015;\n\n    int N;\n    int totalNodes;\n    vector<string> h, v;\n    vector<vector<int>> d;\n    vector<int> d_flat;\n    vector<vector<int>> adj;\n    vector<array<int, 4>> dirNeighbor;\n    vector<int> node_r, node_c;\n    vector<uint16_t> dist_all;\n    vector<uint16_t> next_all;\n    vector<vector<int>> visitTimes;\n    vector<vector<int>> candidates;\n\n    mt19937 rng;\n    chrono::steady_clock::time_point start_time;\n\n    Solver()\n        : rng(static_cast<uint32_t>(chrono::steady_clock::now().time_since_epoch().count())) {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n        read_input();\n    }\n\n    void read_input() {\n        cin >> N;\n        h.resize(max(0, N - 1));\n        for (int i = 0; i < N - 1; ++i) cin >> h[i];\n        v.resize(N);\n        for (int i = 0; i < N; ++i) cin >> v[i];\n        d.assign(N, vector<int>(N));\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                cin >> d[i][j];\n\n        totalNodes = N * N;\n        node_r.resize(totalNodes);\n        node_c.resize(totalNodes);\n        d_flat.resize(totalNodes);\n        int idx = 0;\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j, ++idx) {\n                node_r[idx] = i;\n                node_c[idx] = j;\n                d_flat[idx] = d[i][j];\n            }\n\n        adj.assign(totalNodes, {});\n        dirNeighbor.assign(totalNodes, array<int, 4>{-1, -1, -1, -1});\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int u = i * N + j;\n                if (i + 1 < N && h[i][j] == '0') {\n                    int w = (i + 1) * N + j;\n                    adj[u].push_back(w);\n                    adj[w].push_back(u);\n                    dirNeighbor[u][1] = w;\n                    dirNeighbor[w][0] = u;\n                }\n                if (j + 1 < N && v[i][j] == '0') {\n                    int w = i * N + (j + 1);\n                    adj[u].push_back(w);\n                    adj[w].push_back(u);\n                    dirNeighbor[u][3] = w;\n                    dirNeighbor[w][2] = u;\n                }\n            }\n        }\n        visitTimes.assign(totalNodes, {});\n    }\n\n    void solve() {\n        start_time = chrono::steady_clock::now();\n\n        string bestRoute = build_dfs_route();\n        long double bestScore = evaluate(bestRoute);\n\n        precompute_all_pairs();\n        build_candidates(min(25, max(1, totalNodes - 1)));\n\n        vector<vector<int>> perms;\n        perms.reserve(16);\n        auto add_perm = [&](vector<int> perm) {\n            if ((int)perm.size() != totalNodes) return;\n            normalize_order(perm);\n            perms.push_back(move(perm));\n        };\n\n        add_perm(order_snake_rows());\n        add_perm(order_snake_cols());\n        add_perm(order_morton());\n        add_perm(order_bfs(false));\n        add_perm(order_bfs(true));\n        add_perm(order_dfs(false));\n        add_perm(order_dfs(true));\n        add_perm(order_nearest());\n        add_perm(order_sorted_d());\n        add_perm(order_cheapest_insertion(false));\n        add_perm(order_cheapest_insertion(true));\n        add_perm(order_random());\n        add_perm(order_random());\n\n        if (perms.empty()) {\n            cout << bestRoute << '\\n';\n            return;\n        }\n\n        vector<pair<long long, int>> orderCost;\n        orderCost.reserve(perms.size());\n        for (int i = 0; i < (int)perms.size(); ++i) {\n            long long cost = tour_cost(perms[i]);\n            orderCost.emplace_back(cost, i);\n        }\n        sort(orderCost.begin(), orderCost.end());\n\n        vector<pair<long long, vector<int>>> candidatePerms;\n        candidatePerms.reserve(16);\n\n        auto push_candidate = [&](const vector<int>& perm, long long cost) {\n            candidatePerms.emplace_back(cost, perm);\n        };\n\n        push_candidate(perms[orderCost[0].second], orderCost[0].first);\n        if (orderCost.size() >= 2) push_candidate(perms[orderCost[1].second], orderCost[1].first);\n\n        vector<int> bestPerm = perms[orderCost[0].second];\n        long long bestPermCost = orderCost[0].first;\n\n        int localCount = min(6, (int)orderCost.size());\n        for (int t = 0; t < localCount; ++t) {\n            if (elapsed() > TIME_LIMIT - FINAL_MARGIN - 0.05) break;\n            int idx = orderCost[t].second;\n            vector<int> perm = perms[idx];\n            long long cost = orderCost[t].first;\n            improve_perm(perm, cost, LOCAL_TWO, LOCAL_OR, LOCAL_RAND);\n            push_candidate(perm, cost);\n            if (cost < bestPermCost) {\n                bestPermCost = cost;\n                bestPerm = perm;\n            }\n        }\n\n        if (!bestPerm.empty() && elapsed() < TIME_LIMIT - FINAL_MARGIN - 0.02) {\n            double now = elapsed();\n            double randStop = min(TIME_LIMIT - FINAL_MARGIN, now + 0.18);\n            random_two_opt(bestPerm, bestPermCost, randStop, 25000);\n            now = elapsed();\n            double orStop = min(TIME_LIMIT - FINAL_MARGIN, now + 0.08);\n            or_opt_local(bestPerm, bestPermCost, orStop);\n            now = elapsed();\n            double detStop = min(TIME_LIMIT - FINAL_MARGIN, now + 0.05);\n            two_opt_candidates(bestPerm, bestPermCost, detStop);\n            push_candidate(bestPerm, bestPermCost);\n        }\n        push_candidate(bestPerm, bestPermCost);\n\n        sort(candidatePerms.begin(), candidatePerms.end(),\n             [](const auto& a, const auto& b) {\n                 if (a.first != b.first) return a.first < b.first;\n                 return a.second < b.second;\n             });\n\n        vector<pair<long long, vector<int>>> selected;\n        selected.reserve(6);\n        for (auto& cand : candidatePerms) {\n            bool duplicate = false;\n            for (auto& sel : selected) {\n                if (sel.first == cand.first && sel.second == cand.second) {\n                    duplicate = true;\n                    break;\n                }\n            }\n            if (!duplicate) selected.push_back(cand);\n            if ((int)selected.size() >= 5) break;\n        }\n\n        for (auto& cand : selected) {\n            if (cand.first > MOVE_LIMIT) continue;\n            if (elapsed() > TIME_LIMIT - 0.02) break;\n            vector<int> perm = cand.second;\n            normalize_order(perm);\n            string route;\n            if (!build_route_from_perm(perm, route)) continue;\n            long double score = evaluate(route);\n            if (score < bestScore) {\n                bestScore = score;\n                bestRoute = route;\n            }\n        }\n\n        if (bestRoute.empty()) bestRoute = build_dfs_route();\n        cout << bestRoute << '\\n';\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void normalize_order(vector<int>& perm) const {\n        if (perm.empty()) return;\n        auto it = find(perm.begin(), perm.end(), 0);\n        if (it != perm.end() && it != perm.begin()) {\n            rotate(perm.begin(), it, perm.end());\n        }\n    }\n\n    string build_dfs_route() const {\n        string route;\n        route.reserve(totalNodes * 2);\n        vector<char> visited(totalNodes, 0);\n        auto dfs = [&](auto&& self, int u) -> void {\n            visited[u] = 1;\n            for (int dir = 0; dir < 4; ++dir) {\n                int nxt = dirNeighbor[u][dir];\n                if (nxt == -1 || visited[nxt]) continue;\n                route.push_back(DIR_CHARS[dir]);\n                self(self, nxt);\n                route.push_back(DIR_CHARS[dir ^ 1]);\n            }\n        };\n        dfs(dfs, 0);\n        return route;\n    }\n\n    void precompute_all_pairs() {\n        int n = totalNodes;\n        dist_all.assign((size_t)n * n, 0);\n        next_all.assign((size_t)n * n, 0);\n        vector<int> dist(n);\n        vector<int> parent(n);\n        vector<int> order(n);\n        vector<int> queue_buf(n);\n        vector<int> rootChild(n);\n\n        for (int s = 0; s < n; ++s) {\n            fill(dist.begin(), dist.end(), -1);\n            int head = 0, tail = 0;\n            queue_buf[tail++] = s;\n            dist[s] = 0;\n            parent[s] = -1;\n            int qsize = 0;\n            while (head < tail) {\n                int u = queue_buf[head++];\n                order[qsize++] = u;\n                for (int vtx : adj[u]) {\n                    if (dist[vtx] != -1) continue;\n                    dist[vtx] = dist[u] + 1;\n                    parent[vtx] = u;\n                    queue_buf[tail++] = vtx;\n                }\n            }\n            rootChild[s] = s;\n            for (int k = 1; k < qsize; ++k) {\n                int u = order[k];\n                int p = parent[u];\n                rootChild[u] = (p == s) ? u : rootChild[p];\n            }\n            size_t base = (size_t)s * n;\n            for (int t = 0; t < n; ++t) {\n                dist_all[base + t] = static_cast<uint16_t>(dist[t]);\n                next_all[base + t] = static_cast<uint16_t>(rootChild[t]);\n            }\n        }\n    }\n\n    void build_candidates(int K) {\n        if (totalNodes <= 1 || K <= 0) {\n            candidates.assign(totalNodes, {});\n            return;\n        }\n        candidates.assign(totalNodes, {});\n        vector<int> indices(totalNodes - 1);\n        for (int u = 0; u < totalNodes; ++u) {\n            int m = 0;\n            for (int v = 0; v < totalNodes; ++v) {\n                if (v == u) continue;\n                indices[m++] = v;\n            }\n            int need = min(K, m);\n            auto comp = [&](int a, int b) {\n                return dist_idx(u, a) < dist_idx(u, b);\n            };\n            if (need < m) {\n                nth_element(indices.begin(), indices.begin() + need, indices.begin() + m, comp);\n            }\n            sort(indices.begin(), indices.begin() + need, comp);\n            candidates[u].assign(indices.begin(), indices.begin() + need);\n        }\n    }\n\n    inline int dist_idx(int a, int b) const {\n        return dist_all[(size_t)a * totalNodes + b];\n    }\n\n    inline int next_idx(int a, int b) const {\n        return next_all[(size_t)a * totalNodes + b];\n    }\n\n    vector<int> order_snake_rows() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        for (int i = 0; i < N; ++i) {\n            if (i % 2 == 0) {\n                for (int j = 0; j < N; ++j) perm.push_back(i * N + j);\n            } else {\n                for (int j = N - 1; j >= 0; --j) perm.push_back(i * N + j);\n            }\n        }\n        return perm;\n    }\n\n    vector<int> order_snake_cols() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        for (int j = 0; j < N; ++j) {\n            if (j % 2 == 0) {\n                for (int i = 0; i < N; ++i) perm.push_back(i * N + j);\n            } else {\n                for (int i = N - 1; i >= 0; --i) perm.push_back(i * N + j);\n            }\n        }\n        return perm;\n    }\n\n    vector<int> order_morton() const {\n        vector<pair<uint32_t, int>> nodes;\n        nodes.reserve(totalNodes - 1);\n        for (int idx = 1; idx < totalNodes; ++idx) {\n            nodes.emplace_back(morton_code(node_r[idx], node_c[idx]), idx);\n        }\n        sort(nodes.begin(), nodes.end());\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        for (auto& p : nodes) perm.push_back(p.second);\n        return perm;\n    }\n\n    uint32_t morton_code(int r, int c) const {\n        uint32_t code = 0;\n        for (int i = 0; i < 6; ++i) {\n            code |= ((uint32_t)((r >> i) & 1)) << (2 * i + 1);\n            code |= ((uint32_t)((c >> i) & 1)) << (2 * i);\n        }\n        return code;\n    }\n\n    vector<int> order_bfs(bool randomize) {\n        vector<int> order;\n        order.reserve(totalNodes);\n        vector<char> visited(totalNodes, 0);\n        queue<int> q;\n        q.push(0);\n        visited[0] = 1;\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            order.push_back(u);\n            vector<int> neighbors = adj[u];\n            if (randomize) shuffle(neighbors.begin(), neighbors.end(), rng);\n            for (int vtx : neighbors) {\n                if (visited[vtx]) continue;\n                visited[vtx] = 1;\n                q.push(vtx);\n            }\n        }\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (!visited[vtx]) order.push_back(vtx);\n        }\n        return order;\n    }\n\n    vector<int> order_dfs(bool randomize) {\n        vector<int> order;\n        order.reserve(totalNodes);\n        vector<char> visited(totalNodes, 0);\n        vector<int> stack = {0};\n        while (!stack.empty()) {\n            int u = stack.back();\n            stack.pop_back();\n            if (visited[u]) continue;\n            visited[u] = 1;\n            order.push_back(u);\n            vector<int> neighbors = adj[u];\n            if (randomize) shuffle(neighbors.begin(), neighbors.end(), rng);\n            for (int vtx : neighbors) {\n                if (!visited[vtx]) stack.push_back(vtx);\n            }\n        }\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (!visited[vtx]) order.push_back(vtx);\n        }\n        return order;\n    }\n\n    vector<int> order_nearest() {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        vector<char> used(totalNodes, 0);\n        int cur = 0;\n        perm.push_back(cur);\n        used[cur] = 1;\n        for (int step = 1; step < totalNodes; ++step) {\n            int best = -1;\n            int bestDist = INT_MAX;\n            for (int vtx = 0; vtx < totalNodes; ++vtx) {\n                if (used[vtx]) continue;\n                int dd = dist_idx(cur, vtx);\n                if (best == -1 || dd < bestDist ||\n                    (dd == bestDist && (d_flat[vtx] > d_flat[best] ||\n                                        ((rng() & 1) && d_flat[vtx] == d_flat[best])))) {\n                    best = vtx;\n                    bestDist = dd;\n                }\n            }\n            if (best == -1) break;\n            perm.push_back(best);\n            used[best] = 1;\n            cur = best;\n        }\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (!used[vtx]) perm.push_back(vtx);\n        }\n        return perm;\n    }\n\n    vector<int> order_sorted_d() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        vector<pair<int, int>> nodes;\n        nodes.reserve(totalNodes - 1);\n        for (int idx = 1; idx < totalNodes; ++idx) {\n            nodes.emplace_back(-d_flat[idx], idx);\n        }\n        sort(nodes.begin(), nodes.end());\n        for (auto& p : nodes) perm.push_back(p.second);\n        return perm;\n    }\n\n    vector<int> order_random() {\n        vector<int> perm(totalNodes);\n        iota(perm.begin(), perm.end(), 0);\n        if (totalNodes > 1) shuffle(perm.begin() + 1, perm.end(), rng);\n        return perm;\n    }\n\n    vector<int> order_cheapest_insertion(bool useFarthest) {\n        if (totalNodes == 1) return vector<int>{0};\n        vector<char> used(totalNodes, 0);\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        used[0] = 1;\n\n        int second = -1;\n        int bestVal = useFarthest ? -1 : INT_MAX;\n        for (int vtx = 1; vtx < totalNodes; ++vtx) {\n            int val = dist_idx(0, vtx);\n            if (second == -1 ||\n                (!useFarthest && val < bestVal) ||\n                (useFarthest && val > bestVal)) {\n                second = vtx;\n                bestVal = val;\n            }\n        }\n        if (second == -1) second = 1;\n        perm.push_back(second);\n        used[second] = 1;\n\n        vector<int> unvisited;\n        unvisited.reserve(totalNodes - 2);\n        vector<int> bestDist(totalNodes, INT_MAX);\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (used[vtx]) continue;\n            unvisited.push_back(vtx);\n            bestDist[vtx] = min(dist_idx(vtx, 0), dist_idx(vtx, second));\n        }\n\n        while (!unvisited.empty()) {\n            int bestNode = -1;\n            int bestMetric = useFarthest ? -1 : INT_MAX;\n            size_t bestIdx = 0;\n            for (size_t idx = 0; idx < unvisited.size(); ++idx) {\n                int node = unvisited[idx];\n                int val = bestDist[node];\n                if (bestNode == -1 ||\n                    (!useFarthest && (val < bestMetric ||\n                                      (val == bestMetric &&\n                                       (d_flat[node] > d_flat[bestNode] ||\n                                        ((rng() & 1) && d_flat[node] == d_flat[bestNode]))))) ||\n                    (useFarthest && (val > bestMetric ||\n                                     (val == bestMetric &&\n                                      (d_flat[node] > d_flat[bestNode] ||\n                                       ((rng() & 1) && d_flat[node] == d_flat[bestNode])))))) {\n                    bestNode = node;\n                    bestMetric = val;\n                    bestIdx = idx;\n                }\n            }\n            int node = bestNode;\n            unvisited[bestIdx] = unvisited.back();\n            unvisited.pop_back();\n\n            int m = perm.size();\n            int bestPos = 0;\n            int bestDelta = INT_MAX;\n            for (int i = 0; i < m; ++i) {\n                int a = perm[i];\n                int b = perm[(i + 1) % m];\n                int delta = dist_idx(a, node) + dist_idx(node, b) - dist_idx(a, b);\n                if (delta < bestDelta || (delta == bestDelta && (rng() & 1))) {\n                    bestDelta = delta;\n                    bestPos = i;\n                }\n            }\n            perm.insert(perm.begin() + bestPos + 1, node);\n            used[node] = 1;\n            for (int rest : unvisited) {\n                bestDist[rest] = min(bestDist[rest], dist_idx(rest, node));\n            }\n        }\n        return perm;\n    }\n\n    long long tour_cost(const vector<int>& perm) const {\n        if (perm.empty()) return (long long)4e18;\n        long long cost = 0;\n        for (int i = 0; i + 1 < (int)perm.size(); ++i) {\n            cost += dist_idx(perm[i], perm[i + 1]);\n        }\n        cost += dist_idx(perm.back(), perm.front());\n        return cost;\n    }\n\n    void improve_perm(vector<int>& perm, long long& cost,\n                      double twoBudget, double orBudget, double randBudget) {\n        if (perm.empty()) return;\n        if (elapsed() >= TIME_LIMIT - FINAL_MARGIN) return;\n        double now = elapsed();\n        double detStop = min(TIME_LIMIT - FINAL_MARGIN, now + twoBudget);\n        if (detStop > now) two_opt_candidates(perm, cost, detStop);\n        if (elapsed() >= TIME_LIMIT - FINAL_MARGIN) return;\n        now = elapsed();\n        double orStop = min(TIME_LIMIT - FINAL_MARGIN, now + orBudget);\n        if (orStop > now) or_opt_local(perm, cost, orStop);\n        if (elapsed() >= TIME_LIMIT - FINAL_MARGIN) return;\n        now = elapsed();\n        double randStop = min(TIME_LIMIT - FINAL_MARGIN, now + randBudget);\n        if (randStop > now) random_two_opt(perm, cost, randStop, 12000);\n    }\n\n    long long two_opt_delta(const vector<int>& perm, int ii, int jj) const {\n        int n = perm.size();\n        int prev_i = (ii == 0) ? n - 1 : ii - 1;\n        int next_j = (jj + 1 == n) ? 0 : jj + 1;\n        int a = perm[prev_i];\n        int b = perm[ii];\n        int c = perm[jj];\n        int d = perm[next_j];\n        return (long long)dist_idx(a, c) + dist_idx(b, d)\n             - dist_idx(a, b) - dist_idx(c, d);\n    }\n\n    void two_opt_candidates(vector<int>& perm, long long& cost, double stopTime) {\n        int n = perm.size();\n        if (n <= 3) return;\n        if (elapsed() >= stopTime) return;\n        vector<int> pos(n);\n        for (int i = 0; i < n; ++i) pos[perm[i]] = i;\n        while (elapsed() < stopTime) {\n            bool improved = false;\n            for (int i = 0; i < n; ++i) {\n                int a = perm[i];\n                for (int b : candidates[a]) {\n                    int j = pos[b];\n                    if (i == j) continue;\n                    int ii = i, jj = j;\n                    if (ii > jj) swap(ii, jj);\n                    if (jj == ii || jj == ii + 1) continue;\n                    if (ii == 0 && jj == n - 1) continue;\n                    long long delta = two_opt_delta(perm, ii, jj);\n                    if (delta < 0) {\n                        reverse(perm.begin() + ii, perm.begin() + jj + 1);\n                        for (int k = ii; k <= jj; ++k) pos[perm[k]] = k;\n                        cost += delta;\n                        improved = true;\n                        break;\n                    }\n                }\n                if (improved) break;\n                if ((i & 31) == 0 && elapsed() >= stopTime) return;\n            }\n            if (!improved) break;\n        }\n    }\n\n    void or_opt_local(vector<int>& perm, long long& cost, double stopTime) {\n        int n = perm.size();\n        if (n <= 4 || elapsed() >= stopTime) return;\n        vector<int> pos(n);\n        auto rebuild_pos = [&]() {\n            for (int i = 0; i < n; ++i) pos[perm[i]] = i;\n        };\n        rebuild_pos();\n        while (elapsed() < stopTime) {\n            bool moved = false;\n            for (int len = 1; len <= 3; ++len) {\n                for (int st = 1; st + len <= n; ++st) {\n                    if (elapsed() >= stopTime) return;\n                    int en = st + len - 1;\n                    bool hasZero = false;\n                    for (int k = st; k <= en; ++k) {\n                        if (perm[k] == 0) {\n                            hasZero = true;\n                            break;\n                        }\n                    }\n                    if (hasZero) continue;\n                    int a = perm[st - 1];\n                    int b = perm[st];\n                    int c = perm[en];\n                    int d = (en + 1 < n) ? perm[en + 1] : perm[0];\n                    long long removeDelta =\n                        (long long)dist_idx(a, d) - dist_idx(a, b) - dist_idx(c, d);\n\n                    vector<int> posList;\n                    posList.reserve(24);\n                    auto try_add = [&](int insertAfter) {\n                        if (insertAfter < 0 || insertAfter >= n) return;\n                        if (insertAfter == n - 1) return;\n                        if (insertAfter >= st - 1 && insertAfter <= en) return;\n                        if (insertAfter == st - 2 && st - 2 >= 0) return;\n                        for (int val : posList)\n                            if (val == insertAfter) return;\n                        posList.push_back(insertAfter);\n                    };\n                    for (int cand : candidates[b]) {\n                        try_add(pos[cand]);\n                        if ((int)posList.size() >= 18) break;\n                    }\n                    for (int cand : candidates[c]) {\n                        try_add(pos[cand]);\n                        if ((int)posList.size() >= 24) break;\n                    }\n                    try_add(st - 2);\n                    try_add(en + 1);\n                    for (int t = 0; t < 3; ++t) try_add(rng() % (n - 1));\n\n                    for (int insertAfter : posList) {\n                        if (insertAfter < 0 || insertAfter >= n - 0) continue;\n                        if (insertAfter == n - 1) continue;\n                        int x = perm[insertAfter];\n                        int y = (insertAfter + 1 < n) ? perm[insertAfter + 1] : perm[0];\n                        long long insertDelta =\n                            (long long)dist_idx(x, b) + dist_idx(c, y) - dist_idx(x, y);\n                        long long delta = removeDelta + insertDelta;\n                        if (delta < 0) {\n                            vector<int> segment(perm.begin() + st, perm.begin() + en + 1);\n                            perm.erase(perm.begin() + st, perm.begin() + en + 1);\n                            int insertIndex = (insertAfter < st)\n                                                  ? insertAfter + 1\n                                                  : insertAfter - len + 1;\n                            perm.insert(perm.begin() + insertIndex, segment.begin(),\n                                        segment.end());\n                            cost += delta;\n                            n = perm.size();\n                            rebuild_pos();\n                            moved = true;\n                            goto NEXT_OUTER;\n                        }\n                    }\n                }\n            }\n        NEXT_OUTER:\n            if (!moved || elapsed() >= stopTime) break;\n        }\n    }\n\n    void random_two_opt(vector<int>& perm, long long& cost, double stopTime, int idleLimit) {\n        int n = perm.size();\n        if (n <= 3) return;\n        if (elapsed() >= stopTime) return;\n        vector<int> pos(n);\n        for (int i = 0; i < n; ++i) pos[perm[i]] = i;\n        int idle = 0;\n        while (elapsed() < stopTime && idle < idleLimit) {\n            int i = rng() % n;\n            int j = rng() % n;\n            if (i == j) continue;\n            int ii = i, jj = j;\n            if (ii > jj) swap(ii, jj);\n            if (jj == ii || jj == ii + 1) continue;\n            if (ii == 0 && jj == n - 1) continue;\n            long long delta = two_opt_delta(perm, ii, jj);\n            if (delta < 0) {\n                reverse(perm.begin() + ii, perm.begin() + jj + 1);\n                for (int k = ii; k <= jj; ++k) pos[perm[k]] = k;\n                cost += delta;\n                idle = 0;\n            } else {\n                ++idle;\n            }\n        }\n    }\n\n    bool build_route_from_perm(const vector<int>& perm, string& route) const {\n        if (perm.empty() || perm[0] != 0) return false;\n        route.clear();\n        route.reserve(min(MOVE_LIMIT, totalNodes * 4));\n        int cur = perm[0];\n        for (int idx = 1; idx < (int)perm.size(); ++idx) {\n            if (!append_path(cur, perm[idx], route)) return false;\n            cur = perm[idx];\n        }\n        if (!append_path(cur, perm[0], route)) return false;\n        return (int)route.size() <= MOVE_LIMIT;\n    }\n\n    bool append_path(int from, int to, string& route) const {\n        if (from == to) return true;\n        int safety = totalNodes * 4 + 10;\n        int cur = from;\n        while (cur != to && safety-- > 0) {\n            int nxt = next_idx(cur, to);\n            if (nxt == cur) return false;\n            char mv = move_char(cur, nxt);\n            if (mv == '?') return false;\n            route.push_back(mv);\n            cur = nxt;\n            if ((int)route.size() > MOVE_LIMIT) return false;\n        }\n        return cur == to;\n    }\n\n    char move_char(int from, int to) const {\n        int r1 = node_r[from], c1 = node_c[from];\n        int r2 = node_r[to], c2 = node_c[to];\n        if (r2 == r1 - 1 && c2 == c1) return 'U';\n        if (r2 == r1 + 1 && c2 == c1) return 'D';\n        if (r2 == r1 && c2 == c1 - 1) return 'L';\n        if (r2 == r1 && c2 == c1 + 1) return 'R';\n        return '?';\n    }\n\n    int char_dir(char c) const {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        if (c == 'R') return 3;\n        return -1;\n    }\n\n    long double evaluate(const string& route) {\n        if (route.empty() || (int)route.size() > MOVE_LIMIT) return 1e100L;\n        for (auto& vec : visitTimes) vec.clear();\n        int pos = 0;\n        for (int t = 0; t < (int)route.size(); ++t) {\n            int dir = char_dir(route[t]);\n            if (dir == -1) return 1e100L;\n            int nxt = dirNeighbor[pos][dir];\n            if (nxt == -1) return 1e100L;\n            pos = nxt;\n            visitTimes[pos].push_back(t + 1);\n        }\n        if (pos != 0) return 1e100L;\n\n        long double total = 0.0L;\n        long double L = (long double)route.size();\n        for (int idx = 0; idx < totalNodes; ++idx) {\n            auto& times = visitTimes[idx];\n            if (times.empty()) return 1e100L;\n            size_t m = times.size();\n            for (size_t j = 0; j < m; ++j) {\n                long long cur = times[j];\n                long long nxt = (j + 1 < m) ? times[j + 1] : (long long)times[0] + (long long)L;\n                long long delta = nxt - cur;\n                total += (long double)d_flat[idx] * (long double)delta * (double)(delta - 1) / 2.0L;\n            }\n        }\n        return total / L;\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n};\n\nstruct XorShift64 {\n    unsigned long long x;\n    explicit XorShift64(unsigned long long seed = 88172645463393265ull) : x(seed) {}\n    unsigned long long next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return int(next() % n); }\n    double nextDouble() { return (next() >> 11) * (1.0 / (1ull << 53)); }\n};\n\nconstexpr int CODE_POWER = 26 * 26 * 26 * 26;\nconstexpr int GREEDY_K = 6;\n\nint encodeWord(const string &w) {\n    int code = 0;\n    for (char c : w) code = code * 26 + (c - 'A');\n    return code;\n}\n\nint calcOverlap(const string &a, const string &b) {\n    for (int len = 4; len >= 0; --len) {\n        bool ok = true;\n        for (int k = 0; k < len; ++k) {\n            if (a[5 - len + k] != b[k]) { ok = false; break; }\n        }\n        if (ok) return len;\n    }\n    return 0;\n}\n\nint computeOrderCost(const vector<int>& order, const vector<vector<int>>& cost) {\n    if (order.empty()) return 0;\n    int total = 5;\n    for (int i = 0; i + 1 < (int)order.size(); ++i) total += cost[order[i]][order[i + 1]];\n    return total;\n}\n\nvector<int> greedyOrderFromStart(int start, bool randomized,\n                                 const vector<vector<int>>& cost,\n                                 const vector<int>& sumOut,\n                                 XorShift64& rng) {\n    int n = cost.size();\n    vector<int> order;\n    vector<char> used(n, 0);\n    order.reserve(n);\n    int cur = start;\n    used[cur] = 1;\n    order.push_back(cur);\n    for (int step = 1; step < n; ++step) {\n        array<int, GREEDY_K> candNode;\n        array<int, GREEDY_K> candCost;\n        candNode.fill(-1);\n        candCost.fill(INT_MAX / 4);\n        for (int nxt = 0; nxt < n; ++nxt) {\n            if (used[nxt]) continue;\n            int c = cost[cur][nxt];\n            for (int pos = 0; pos < GREEDY_K; ++pos) {\n                if (candNode[pos] == -1 ||\n                    c < candCost[pos] ||\n                    (c == candCost[pos] &&\n                     (sumOut[nxt] < sumOut[candNode[pos]] ||\n                      (sumOut[nxt] == sumOut[candNode[pos]] && nxt < candNode[pos])))) {\n                    for (int q = GREEDY_K - 1; q > pos; --q) {\n                        candNode[q] = candNode[q - 1];\n                        candCost[q] = candCost[q - 1];\n                    }\n                    candNode[pos] = nxt;\n                    candCost[pos] = c;\n                    break;\n                }\n            }\n        }\n        int candCnt = 0;\n        while (candCnt < GREEDY_K && candNode[candCnt] != -1) ++candCnt;\n        int pick = 0;\n        if (randomized && candCnt > 1) {\n            double r = rng.nextDouble();\n            if (candCnt >= 3) {\n                if (r < 0.6) pick = 0;\n                else if (r < 0.85) pick = 1;\n                else if (r < 0.95) pick = 2;\n                else pick = rng.nextInt(candCnt);\n            } else {\n                pick = (r < 0.8) ? 0 : 1;\n            }\n        }\n        int nextNode = candNode[pick];\n        if (nextNode == -1) {\n            for (int nxt = 0; nxt < n; ++nxt) if (!used[nxt]) { nextNode = nxt; break; }\n        }\n        used[nextNode] = 1;\n        order.push_back(nextNode);\n        cur = nextNode;\n    }\n    return order;\n}\n\nvector<int> cheapestInsertionOrder(bool deterministicStart,\n                                   bool randomized,\n                                   const vector<vector<int>>& cost,\n                                   const vector<int>& sumOut,\n                                   XorShift64& rng) {\n    int n = cost.size();\n    vector<int> order;\n    vector<char> used(n, 0);\n    int a = 0, b = 1;\n    if (deterministicStart) {\n        int best = INT_MAX;\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) if (i != j) {\n                int c = cost[i][j];\n                if (c < best || (c == best && sumOut[i] + sumOut[j] < sumOut[a] + sumOut[b])) {\n                    best = c;\n                    a = i;\n                    b = j;\n                }\n            }\n        }\n    } else {\n        a = rng.nextInt(n);\n        b = rng.nextInt(n - 1);\n        if (b >= a) ++b;\n    }\n    order.push_back(a);\n    order.push_back(b);\n    used[a] = used[b] = 1;\n    while ((int)order.size() < n) {\n        int bestNode = -1, bestPos = 0;\n        int bestDelta = INT_MAX / 4;\n        for (int node = 0; node < n; ++node) if (!used[node]) {\n            for (int pos = 0; pos <= (int)order.size(); ++pos) {\n                int prev = (pos == 0) ? -1 : order[pos - 1];\n                int next = (pos == (int)order.size()) ? -1 : order[pos];\n                int delta;\n                if (prev == -1 && next == -1) delta = 0;\n                else if (prev == -1) delta = cost[node][next];\n                else if (next == -1) delta = cost[prev][node];\n                else delta = cost[prev][node] + cost[node][next] - cost[prev][next];\n                bool take = false;\n                if (delta < bestDelta) take = true;\n                else if (delta == bestDelta) {\n                    if (randomized) take = rng.nextDouble() < 0.5;\n                    else if (bestNode == -1 || sumOut[node] < sumOut[bestNode] ||\n                             (sumOut[node] == sumOut[bestNode] && node < bestNode)) take = true;\n                }\n                if (take) {\n                    bestDelta = delta;\n                    bestNode = node;\n                    bestPos = pos;\n                }\n            }\n        }\n        if (bestNode == -1) {\n            for (int node = 0; node < n; ++node) if (!used[node]) { bestNode = node; bestPos = order.size(); break; }\n        }\n        order.insert(order.begin() + bestPos, bestNode);\n        used[bestNode] = 1;\n    }\n    return order;\n}\n\nint swapDelta(const vector<int>& order, int i, int j, const vector<vector<int>>& cost) {\n    if (i == j) return 0;\n    if (i > j) swap(i, j);\n    int n = order.size();\n    auto edge = [&](int u, int v)->int { return (u < 0 || v < 0) ? 0 : cost[u][v]; };\n    int a = order[i];\n    int b = order[j];\n    if (j == i + 1) {\n        int li = (i > 0) ? order[i - 1] : -1;\n        int rj = (j + 1 < n) ? order[j + 1] : -1;\n        int before = 0, after = 0;\n        if (li != -1) before += edge(li, a);\n        before += edge(a, b);\n        if (rj != -1) before += edge(b, rj);\n        if (li != -1) after += edge(li, b);\n        after += edge(b, a);\n        if (rj != -1) after += edge(a, rj);\n        return after - before;\n    } else {\n        int li = (i > 0) ? order[i - 1] : -1;\n        int ri = (i + 1 < n) ? order[i + 1] : -1;\n        int lj = (j > 0) ? order[j - 1] : -1;\n        int rj = (j + 1 < n) ? order[j + 1] : -1;\n        int before = 0, after = 0;\n        if (li != -1) before += edge(li, a);\n        if (ri != -1) before += edge(a, ri);\n        if (lj != -1) before += edge(lj, b);\n        if (rj != -1) before += edge(b, rj);\n        if (li != -1) after += edge(li, b);\n        if (ri != -1) after += edge(b, ri);\n        if (lj != -1) after += edge(lj, a);\n        if (rj != -1) after += edge(a, rj);\n        return after - before;\n    }\n}\n\nint segmentMoveDelta(const vector<int>& order, int L, int len, int insertPos, const vector<vector<int>>& cost) {\n    int n = order.size();\n    int R = L + len - 1;\n    if (insertPos >= L && insertPos <= R + 1) return 0;\n    auto edge = [&](int u, int v)->int { return (u < 0 || v < 0) ? 0 : cost[u][v]; };\n    int segFront = order[L];\n    int segBack = order[R];\n    int left = (L > 0) ? order[L - 1] : -1;\n    int right = (R + 1 < n) ? order[R + 1] : -1;\n    int delta = 0;\n    if (left != -1) delta -= edge(left, segFront);\n    if (right != -1) delta -= edge(segBack, right);\n    if (left != -1 && right != -1) delta += edge(left, right);\n    int reducedTarget;\n    if (insertPos <= L) reducedTarget = insertPos;\n    else if (insertPos > R + 1) reducedTarget = insertPos - len;\n    else return 0;\n    int newSize = n - len;\n    auto getValue = [&](int idx)->int {\n        if (idx < 0) return -1;\n        if (idx >= newSize) return -1;\n        if (idx < L) return order[idx];\n        return order[idx + len];\n    };\n    int before = getValue(reducedTarget - 1);\n    int after = getValue(reducedTarget);\n    if (before != -1) delta += edge(before, segFront);\n    if (after != -1) delta += edge(segBack, after);\n    if (before != -1 && after != -1) delta -= edge(before, after);\n    return delta;\n}\n\nvoid applySegmentMove(vector<int>& order, int L, int len, int insertPos) {\n    vector<int> segment(order.begin() + L, order.begin() + L + len);\n    order.erase(order.begin() + L, order.begin() + L + len);\n    int pos = insertPos;\n    if (pos > L) pos -= len;\n    pos = max(0, min(pos, (int)order.size()));\n    order.insert(order.begin() + pos, segment.begin(), segment.end());\n}\n\nint twoOptDelta(const vector<int>& order, int l, int r, const vector<vector<int>>& cost) {\n    if (l >= r) return 0;\n    int n = order.size();\n    auto edge = [&](int u, int v)->int { return (u < 0 || v < 0) ? 0 : cost[u][v]; };\n    int delta = 0;\n    int left = (l > 0) ? order[l - 1] : -1;\n    int right = (r + 1 < n) ? order[r + 1] : -1;\n    if (left != -1) delta += edge(left, order[r]) - edge(left, order[l]);\n    if (right != -1) delta += edge(order[l], right) - edge(order[r], right);\n    for (int i = l; i < r; ++i) {\n        int u = order[i];\n        int v = order[i + 1];\n        delta += edge(v, u) - edge(u, v);\n    }\n    return delta;\n}\n\nbool improveSwap(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                 Timer& timer, double deadline) {\n    int n = order.size();\n    int bestI = -1, bestJ = -1;\n    int bestDelta = 0;\n    for (int i = 0; i < n; ++i) {\n        if (timer.elapsed() >= deadline) break;\n        for (int j = i + 1; j < n; ++j) {\n            int delta = swapDelta(order, i, j, cost);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestI = i;\n                bestJ = j;\n            }\n        }\n    }\n    if (bestDelta < 0) {\n        swap(order[bestI], order[bestJ]);\n        costVal += bestDelta;\n        return true;\n    }\n    return false;\n}\n\nbool improveSegmentMoveLen(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                           int len, Timer& timer, double deadline) {\n    int n = order.size();\n    if (n <= len) return false;\n    int bestL = -1, bestPos = -1;\n    int bestDelta = 0;\n    for (int L = 0; L + len <= n; ++L) {\n        if (timer.elapsed() >= deadline) break;\n        for (int pos = 0; pos <= n; ++pos) {\n            if (pos >= L && pos <= L + len) continue;\n            int delta = segmentMoveDelta(order, L, len, pos, cost);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestL = L;\n                bestPos = pos;\n            }\n        }\n    }\n    if (bestDelta < 0) {\n        applySegmentMove(order, bestL, len, bestPos);\n        costVal += bestDelta;\n        return true;\n    }\n    return false;\n}\n\nbool improveTwoOpt(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                   Timer& timer, double deadline) {\n    int n = order.size();\n    for (int l = 0; l < n; ++l) {\n        if (timer.elapsed() >= deadline) break;\n        for (int r = l + 1; r < n; ++r) {\n            int delta = twoOptDelta(order, l, r, cost);\n            if (delta < 0) {\n                reverse(order.begin() + l, order.begin() + r + 1);\n                costVal += delta;\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nvoid deterministicLocalSearch(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                              Timer& timer, double deadline) {\n    while (timer.elapsed() < deadline) {\n        if (improveSwap(order, costVal, cost, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveSegmentMoveLen(order, costVal, cost, 1, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveSegmentMoveLen(order, costVal, cost, 2, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveSegmentMoveLen(order, costVal, cost, 3, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveTwoOpt(order, costVal, cost, timer, deadline)) continue;\n        break;\n    }\n}\n\nvoid simulatedAnnealing(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                        XorShift64& rng, Timer& timer, double deadline) {\n    double startTime = timer.elapsed();\n    double totalTime = deadline - startTime;\n    if (totalTime <= 1e-4) return;\n    vector<int> bestOrder = order;\n    int bestCost = costVal;\n    int n = order.size();\n    const double START_TEMP = 4.0;\n    const double END_TEMP = 0.1;\n    while (true) {\n        double now = timer.elapsed();\n        if (now >= deadline) break;\n        double progress = (now - startTime) / totalTime;\n        progress = min(max(progress, 0.0), 1.0);\n        double temp = START_TEMP + (END_TEMP - START_TEMP) * progress;\n        temp = max(temp, 1e-4);\n        int op = rng.nextInt(4);\n        if (op == 0) {\n            if (n <= 1) continue;\n            int i = rng.nextInt(n);\n            int j = rng.nextInt(n - 1);\n            if (j >= i) ++j;\n            int delta = swapDelta(order, i, j, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                swap(order[i], order[j]);\n                costVal += delta;\n                if (costVal < bestCost) {\n                    bestCost = costVal;\n                    bestOrder = order;\n                }\n            }\n        } else if (op == 1) {\n            int len = (n >= 4 && rng.nextDouble() < 0.5) ? 2 : 1;\n            if (n <= len) continue;\n            int L = rng.nextInt(n - len + 1);\n            int pos = rng.nextInt(n + 1);\n            if (pos >= L && pos <= L + len) continue;\n            int delta = segmentMoveDelta(order, L, len, pos, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                applySegmentMove(order, L, len, pos);\n                costVal += delta;\n                if (costVal < bestCost) {\n                    bestCost = costVal;\n                    bestOrder = order;\n                }\n            }\n        } else if (op == 2) {\n            if (n < 3) continue;\n            int l = rng.nextInt(n - 1);\n            int r = rng.nextInt(n - l - 1) + l + 1;\n            int delta = twoOptDelta(order, l, r, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                reverse(order.begin() + l, order.begin() + r + 1);\n                costVal += delta;\n                if (costVal < bestCost) {\n                    bestCost = costVal;\n                    bestOrder = order;\n                }\n            }\n        } else {\n            if (n < 5) continue;\n            int len = 3;\n            int L = rng.nextInt(n - len + 1);\n            int pos = rng.nextInt(n + 1);\n            if (pos >= L && pos <= L + len) continue;\n            int delta = segmentMoveDelta(order, L, len, pos, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                applySegmentMove(order, L, len, pos);\n                costVal += delta;\n                if (costVal < bestCost) {\n                    bestCost = costVal;\n                    bestOrder = order;\n                }\n            }\n        }\n    }\n    if (bestCost < costVal) {\n        order = bestOrder;\n        costVal = bestCost;\n    }\n}\n\nstring buildLuckyString(const vector<int>& order,\n                        const vector<string>& words,\n                        const vector<vector<int>>& overlap) {\n    if (order.empty()) return \"\";\n    string result = words[order[0]];\n    for (int idx = 1; idx < (int)order.size(); ++idx) {\n        int u = order[idx - 1];\n        int v = order[idx];\n        int ov = overlap[u][v];\n        result.append(words[v].substr(ov));\n    }\n    return result;\n}\n\nvoid ensureCoverage(string &S, const vector<string>& words,\n                    const unordered_map<int,int>& codeToIdx) {\n    int M = words.size();\n    vector<char> seen(M, 0);\n    int covered = 0;\n    int windowLen = 0;\n    int code = 0;\n    for (char c : S) {\n        int val = c - 'A';\n        if (windowLen < 5) {\n            code = code * 26 + val;\n            ++windowLen;\n        } else {\n            code %= CODE_POWER;\n            code = code * 26 + val;\n        }\n        if (windowLen >= 5) {\n            auto it = codeToIdx.find(code);\n            if (it != codeToIdx.end() && !seen[it->second]) {\n                seen[it->second] = 1;\n                ++covered;\n                if (covered == M) return;\n            }\n        }\n    }\n    if (covered == M) return;\n    auto appendWord = [&](const string& w) {\n        int overlapLen = 0;\n        int limit = min(4, (int)S.size());\n        for (int len = limit; len >= 0; --len) {\n            bool ok = true;\n            for (int k = 0; k < len; ++k) {\n                if (S[S.size() - len + k] != w[k]) { ok = false; break; }\n            }\n            if (ok) { overlapLen = len; break; }\n        }\n        for (int k = overlapLen; k < 5; ++k) {\n            char c = w[k];\n            S.push_back(c);\n            int val = c - 'A';\n            if (windowLen < 5) {\n                code = code * 26 + val;\n                ++windowLen;\n            } else {\n                code %= CODE_POWER;\n                code = code * 26 + val;\n            }\n            if (windowLen >= 5) {\n                auto it = codeToIdx.find(code);\n                if (it != codeToIdx.end() && !seen[it->second]) {\n                    seen[it->second] = 1;\n                    ++covered;\n                }\n            }\n        }\n    };\n    for (int idx = 0; idx < M; ++idx) {\n        if (!seen[idx]) {\n            appendWord(words[idx]);\n            if (covered == M) break;\n        }\n    }\n}\n\nvector<int> buildTypingPlan(const string& S, int si, int sj,\n                            const vector<vector<int>>& cellsByChar,\n                            const vector<int>& rowOfCell,\n                            const vector<int>& colOfCell) {\n    const int INF = 1e9;\n    if (S.empty()) return {};\n    int L = S.size();\n    vector<vector<int>> dp(L);\n    vector<vector<int>> parent(L);\n    for (int pos = 0; pos < L; ++pos) {\n        int c = S[pos] - 'A';\n        const auto &cells = cellsByChar[c];\n        int m = cells.size();\n        dp[pos].assign(m, INF);\n        parent[pos].assign(m, -1);\n        if (pos == 0) {\n            for (int idx = 0; idx < m; ++idx) {\n                int cell = cells[idx];\n                dp[pos][idx] = abs(rowOfCell[cell] - si) + abs(colOfCell[cell] - sj) + 1;\n            }\n        } else {\n            int prevC = S[pos - 1] - 'A';\n            const auto &prevCells = cellsByChar[prevC];\n            for (int idx = 0; idx < m; ++idx) {\n                int cell = cells[idx];\n                int bestVal = INF;\n                int bestPrev = -1;\n                for (int p = 0; p < (int)prevCells.size(); ++p) {\n                    int prevCell = prevCells[p];\n                    int prevCost = dp[pos - 1][p];\n                    if (prevCost >= INF) continue;\n                    int dist = abs(rowOfCell[cell] - rowOfCell[prevCell]) +\n                               abs(colOfCell[cell] - colOfCell[prevCell]);\n                    int cand = prevCost + dist + 1;\n                    if (cand < bestVal) {\n                        bestVal = cand;\n                        bestPrev = p;\n                    }\n                }\n                dp[pos][idx] = bestVal;\n                parent[pos][idx] = bestPrev;\n            }\n        }\n    }\n    int lastPos = L - 1;\n    const auto &lastCells = cellsByChar[S[lastPos] - 'A'];\n    int bestIdx = 0;\n    for (int idx = 1; idx < (int)lastCells.size(); ++idx) {\n        if (dp[lastPos][idx] < dp[lastPos][bestIdx]) bestIdx = idx;\n    }\n    vector<int> path(L);\n    int curIdx = bestIdx;\n    for (int pos = L - 1; pos >= 0; --pos) {\n        path[pos] = cellsByChar[S[pos] - 'A'][curIdx];\n        if (pos == 0) break;\n        curIdx = parent[pos][curIdx];\n        if (curIdx < 0) curIdx = 0;\n    }\n    return path;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TOTAL_LIMIT = 1.95;\n    const double RESERVED_TIME = 0.20;\n    double heurDeadline = min(1.55, TOTAL_LIMIT - RESERVED_TIME);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n    vector<string> words(M);\n    for (int i = 0; i < M; ++i) cin >> words[i];\n\n    vector<int> rowOfCell(N * N), colOfCell(N * N);\n    vector<vector<int>> cellsByChar(26);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int idx = i * N + j;\n            rowOfCell[idx] = i;\n            colOfCell[idx] = j;\n            cellsByChar[grid[i][j] - 'A'].push_back(idx);\n        }\n    }\n\n    unordered_map<int,int> codeToIdx;\n    codeToIdx.reserve(M * 2);\n    for (int i = 0; i < M; ++i) codeToIdx[encodeWord(words[i])] = i;\n\n    vector<vector<int>> overlap(M, vector<int>(M, 0));\n    vector<vector<int>> cost(M, vector<int>(M, 5));\n    for (int i = 0; i < M; ++i) {\n        for (int j = 0; j < M; ++j) if (i != j) {\n            int ov = calcOverlap(words[i], words[j]);\n            overlap[i][j] = ov;\n            cost[i][j] = 5 - ov;\n        }\n    }\n    vector<int> sumOut(M, 0);\n    for (int i = 0; i < M; ++i) {\n        int s = 0;\n        for (int j = 0; j < M; ++j) if (i != j) s += cost[i][j];\n        sumOut[i] = s;\n    }\n\n    uint64_t seed = 1469598103934665603ull;\n    seed = seed * 1000003 + si * 911 + sj * 1013;\n    for (const auto &row : grid)\n        for (char c : row)\n            seed = seed * 1000003 + (unsigned char)c;\n    for (const auto &w : words)\n        for (char c : w)\n            seed = seed * 1000003 + (unsigned char)c;\n    XorShift64 rng(seed);\n\n    vector<vector<int>> candidateOrders;\n    vector<int> candidateCosts;\n    const int MAX_CAND = 8;\n    auto addCandidate = [&](const vector<int>& ord, int costVal) {\n        if ((int)candidateOrders.size() < MAX_CAND) {\n            candidateOrders.push_back(ord);\n            candidateCosts.push_back(costVal);\n        } else {\n            int worstIdx = max_element(candidateCosts.begin(), candidateCosts.end()) - candidateCosts.begin();\n            if (costVal < candidateCosts[worstIdx]) {\n                candidateOrders[worstIdx] = ord;\n                candidateCosts[worstIdx] = costVal;\n            }\n        }\n    };\n\n    vector<int> bestOrder;\n    int bestCost = INT_MAX;\n\n    for (int start = 0; start < M; ++start) {\n        if (timer.elapsed() > heurDeadline && !candidateOrders.empty()) break;\n        auto ord = greedyOrderFromStart(start, false, cost, sumOut, rng);\n        int c = computeOrderCost(ord, cost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidate(ord, c);\n    }\n\n    int randomGreedyRuns = 80;\n    for (int iter = 0; iter < randomGreedyRuns; ++iter) {\n        if (timer.elapsed() > heurDeadline) break;\n        int start = rng.nextInt(M);\n        auto ord = greedyOrderFromStart(start, true, cost, sumOut, rng);\n        int c = computeOrderCost(ord, cost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidate(ord, c);\n    }\n\n    if (timer.elapsed() < heurDeadline) {\n        auto ord = cheapestInsertionOrder(true, false, cost, sumOut, rng);\n        int c = computeOrderCost(ord, cost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidate(ord, c);\n    }\n\n    int insertionRuns = 10;\n    for (int iter = 0; iter < insertionRuns; ++iter) {\n        if (timer.elapsed() > heurDeadline) break;\n        auto ord = cheapestInsertionOrder(false, true, cost, sumOut, rng);\n        int c = computeOrderCost(ord, cost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidate(ord, c);\n    }\n\n    if (bestOrder.empty()) {\n        bestOrder.resize(M);\n        iota(bestOrder.begin(), bestOrder.end(), 0);\n        bestCost = computeOrderCost(bestOrder, cost);\n        addCandidate(bestOrder, bestCost);\n    }\n\n    vector<int> idx(candidateOrders.size());\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int a, int b) { return candidateCosts[a] < candidateCosts[b]; });\n\n    for (int id : idx) {\n        if (timer.elapsed() > heurDeadline) break;\n        vector<int> ord = candidateOrders[id];\n        int c = candidateCosts[id];\n        deterministicLocalSearch(ord, c, cost, timer, heurDeadline);\n        if (c < bestCost) {\n            bestCost = c;\n            bestOrder = ord;\n        }\n    }\n\n    if (timer.elapsed() < heurDeadline - 0.05) {\n        vector<int> ord = bestOrder;\n        int c = bestCost;\n        double saDeadline = heurDeadline - 0.02;\n        simulatedAnnealing(ord, c, cost, rng, timer, saDeadline);\n        deterministicLocalSearch(ord, c, cost, timer, heurDeadline);\n        if (c < bestCost) {\n            bestCost = c;\n            bestOrder = ord;\n        }\n    }\n\n    if (timer.elapsed() < heurDeadline - 0.05) {\n        vector<int> ord = bestOrder;\n        int n = ord.size();\n        for (int k = 0; k < n / 2; ++k) {\n            int i = rng.nextInt(n);\n            int j = rng.nextInt(n);\n            if (i != j) swap(ord[i], ord[j]);\n        }\n        int c = computeOrderCost(ord, cost);\n        deterministicLocalSearch(ord, c, cost, timer, heurDeadline);\n        if (c < bestCost) {\n            bestCost = c;\n            bestOrder = ord;\n        }\n    }\n\n    string lucky = buildLuckyString(bestOrder, words, overlap);\n    ensureCoverage(lucky, words, codeToIdx);\n    if ((int)lucky.size() > 5000) lucky.resize(5000);\n\n    vector<int> typingPath = buildTypingPlan(lucky, si, sj,\n                                             cellsByChar, rowOfCell, colOfCell);\n    for (int cell : typingPath) {\n        cout << rowOfCell[cell] << ' ' << colOfCell[cell] << '\\n';\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAX_N = 20;\nconstexpr int MAX_CELLS = MAX_N * MAX_N;\nconstexpr double LOG_SEARCH_LIMIT = 12.0;             // exp(12) \u2248 1.6e5 combinations\nconstexpr long long SEARCH_NODE_LIMIT = 1'000'000;    // DFS node cap\nconstexpr long long SEARCH_SOLUTION_LIMIT = 120'000;  // solution enumeration cap\n\nstruct Candidate {\n    vector<int> cells;\n    bitset<MAX_CELLS> mask;\n};\n\nstruct FieldState {\n    vector<Candidate> candidates;\n    vector<char> alive;\n    int rem = 0;\n    vector<int> cellCoverCount;\n    vector<unsigned char> possibleFlag;\n    vector<unsigned char> guaranteedFlag;\n    bool fixed = false;\n    int fixedCandidate = -1;\n};\n\nint N, M;\ndouble eps;\nint nCells;\nvector<FieldState> fields;\nvector<int> assigned_total;\nvector<int> observed;\nvector<char> drilled;\nvector<int> observed_cells;\nvector<int> possible_sum;\nvector<int> guaranteed_sum;\nvector<int> cellStatus;   // -1 unknown, 0 zero, 1 positive\nint fixed_fields = 0;\nbool contradiction = false;\nmt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\ninline int cell_id(int i, int j) { return i * N + j; }\n\nvoid update_trivial_statuses() {\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (drilled[idx] && observed[idx] >= 0) {\n            cellStatus[idx] = (observed[idx] > 0) ? 1 : 0;\n            continue;\n        }\n        if (assigned_total[idx] > 0 || guaranteed_sum[idx] > 0) {\n            cellStatus[idx] = 1;\n        } else if (cellStatus[idx] == -1 && possible_sum[idx] == 0) {\n            cellStatus[idx] = 0;\n        }\n    }\n}\n\nvoid recompute_field_flags(int k) {\n    FieldState &F = fields[k];\n    if (F.fixed) return;\n    for (int idx = 0; idx < nCells; ++idx) {\n        unsigned char newPossible = (F.cellCoverCount[idx] > 0) ? 1 : 0;\n        unsigned char newGuaranteed = (F.rem > 0 && F.cellCoverCount[idx] == F.rem) ? 1 : 0;\n        if (newPossible != F.possibleFlag[idx]) {\n            possible_sum[idx] += int(newPossible) - int(F.possibleFlag[idx]);\n            F.possibleFlag[idx] = newPossible;\n        }\n        if (newGuaranteed != F.guaranteedFlag[idx]) {\n            guaranteed_sum[idx] += int(newGuaranteed) - int(F.guaranteedFlag[idx]);\n            F.guaranteedFlag[idx] = newGuaranteed;\n        }\n    }\n}\n\nvoid fix_field(int k);\n\nvoid eliminate_candidate(int k, int t) {\n    FieldState &F = fields[k];\n    if (F.fixed) return;\n    if (!F.alive[t]) return;\n    F.alive[t] = false;\n    F.rem--;\n    for (int idx : F.candidates[t].cells) {\n        F.cellCoverCount[idx]--;\n    }\n    recompute_field_flags(k);\n    if (!F.fixed) {\n        if (F.rem < 0) {\n            contradiction = true;\n        } else if (F.rem == 1) {\n            fix_field(k);\n        } else if (F.rem == 0) {\n            contradiction = true;\n        }\n    }\n}\n\nvoid fix_field(int k) {\n    FieldState &F = fields[k];\n    if (F.fixed) return;\n    int t = -1;\n    for (int i = 0; i < (int)F.candidates.size(); ++i) {\n        if (F.alive[i]) {\n            t = i;\n            break;\n        }\n    }\n    if (t == -1) {\n        contradiction = true;\n        return;\n    }\n    F.fixed = true;\n    F.fixedCandidate = t;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (F.possibleFlag[idx]) {\n            possible_sum[idx] -= 1;\n            F.possibleFlag[idx] = 0;\n        }\n        if (F.guaranteedFlag[idx]) {\n            guaranteed_sum[idx] -= 1;\n            F.guaranteedFlag[idx] = 0;\n        }\n    }\n    F.alive.assign(F.candidates.size(), 0);\n    F.alive[t] = 1;\n    F.rem = 0;\n    for (int idx : F.candidates[t].cells) {\n        assigned_total[idx]++;\n        cellStatus[idx] = 1;\n    }\n    fixed_fields++;\n}\n\nbool check_candidate(int k, int t) {\n    FieldState &F = fields[k];\n    const Candidate &cand = F.candidates[t];\n    for (int idx : observed_cells) {\n        if (!F.possibleFlag[idx]) continue;\n        int cover = cand.mask.test(idx) ? 1 : 0;\n        int need = observed[idx] - (assigned_total[idx] + cover);\n        int min_other = guaranteed_sum[idx];\n        int max_other = possible_sum[idx];\n        if (F.guaranteedFlag[idx]) min_other -= 1;\n        if (F.possibleFlag[idx]) max_other -= 1;\n        if (need < min_other || need > max_other) return false;\n    }\n    return true;\n}\n\nbool validate_bounds() {\n    for (int idx : observed_cells) {\n        int min_total = assigned_total[idx] + guaranteed_sum[idx];\n        int max_total = assigned_total[idx] + possible_sum[idx];\n        if (observed[idx] < min_total || observed[idx] > max_total) {\n            return false;\n        }\n    }\n    return true;\n}\n\nbool run_propagation() {\n    bool changed = true;\n    while (!contradiction && changed) {\n        changed = false;\n        for (int k = 0; k < M; ++k) {\n            FieldState &F = fields[k];\n            if (F.fixed) continue;\n            for (int t = 0; t < (int)F.candidates.size(); ++t) {\n                if (!F.alive[t]) continue;\n                if (!check_candidate(k, t)) {\n                    eliminate_candidate(k, t);\n                    changed = true;\n                    if (contradiction) return false;\n                }\n            }\n        }\n        if (!validate_bounds()) return false;\n    }\n    return true;\n}\n\nint drill_cell(int idx) {\n    if (drilled[idx]) return observed[idx];\n    int i = idx / N;\n    int j = idx % N;\n    cout << \"q 1 \" << i << ' ' << j << '\\n' << flush;\n    int val;\n    if (!(cin >> val)) exit(0);\n    drilled[idx] = 1;\n    observed[idx] = val;\n    cellStatus[idx] = (val > 0) ? 1 : 0;\n    observed_cells.push_back(idx);\n    return val;\n}\n\nbool all_cells_determined() {\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (cellStatus[idx] == -1) return false;\n    }\n    return true;\n}\n\nint select_any_undetermined_cell() {\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (!drilled[idx] && cellStatus[idx] == -1) return idx;\n    }\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (cellStatus[idx] == -1) return idx;\n    }\n    return -1;\n}\n\nint select_next_cell() {\n    long long bestScore = -1;\n    int bestIdx = -1;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (drilled[idx]) continue;\n        if (cellStatus[idx] != -1) continue;\n        long long score = 0;\n        for (int k = 0; k < M; ++k) {\n            FieldState &F = fields[k];\n            if (F.fixed) continue;\n            if (F.rem <= 1) continue;\n            int cnt = F.cellCoverCount[idx];\n            if (cnt == 0 || cnt == F.rem) continue;\n            score += min(cnt, F.rem - cnt);\n        }\n        if (score > bestScore) {\n            bestScore = score;\n            bestIdx = idx;\n        } else if (score == bestScore && score > 0) {\n            if (rng() & 1) bestIdx = idx;\n        }\n    }\n    if (bestIdx != -1 && bestScore > 0) return bestIdx;\n    long long fallbackScore = -1;\n    int fallbackIdx = -1;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (drilled[idx]) continue;\n        if (cellStatus[idx] != -1) continue;\n        long long s = possible_sum[idx] - guaranteed_sum[idx];\n        if (s < 0) s = 0;\n        if (s > fallbackScore) {\n            fallbackScore = s;\n            fallbackIdx = idx;\n        }\n    }\n    return fallbackIdx;\n}\n\nbool apply_propagation() {\n    if (!run_propagation()) {\n        contradiction = true;\n        return false;\n    }\n    update_trivial_statuses();\n    return true;\n}\n\nstruct AttemptResult {\n    bool progress = false;\n    bool needPropagation = false;\n};\n\nAttemptResult attempt_search() {\n    AttemptResult result;\n    if (contradiction) return result;\n    if (observed_cells.empty()) return result;\n\n    vector<int> order;\n    order.reserve(M);\n    double logSum = 0.0;\n    for (int k = 0; k < M; ++k) {\n        if (fields[k].fixed) continue;\n        if (fields[k].rem <= 0) continue;\n        order.push_back(k);\n        logSum += log((double)fields[k].rem);\n    }\n    if (order.empty()) return result;\n    if (logSum > LOG_SEARCH_LIMIT) return result;\n\n    int K = (int)order.size();\n    int obsCount = observed_cells.size();\n    vector<int> obsIndex(nCells, -1);\n    for (int i = 0; i < obsCount; ++i) {\n        obsIndex[observed_cells[i]] = i;\n    }\n    vector<int> residual(obsCount);\n    for (int i = 0; i < obsCount; ++i) {\n        residual[i] = observed[observed_cells[i]] - assigned_total[observed_cells[i]];\n        if (residual[i] < 0) {\n            contradiction = true;\n            return result;\n        }\n    }\n    vector<vector<int>> suffixPossible(K + 1, vector<int>(obsCount, 0));\n    for (int pos = K - 1; pos >= 0; --pos) {\n        suffixPossible[pos] = suffixPossible[pos + 1];\n        FieldState &F = fields[order[pos]];\n        for (int i = 0; i < obsCount; ++i) {\n            if (F.possibleFlag[observed_cells[i]]) suffixPossible[pos][i]++;\n        }\n    }\n    for (int i = 0; i < obsCount; ++i) {\n        if (residual[i] > suffixPossible[0][i]) {\n            contradiction = true;\n            return result;\n        }\n    }\n\n    vector<vector<int>> candList(K);\n    vector<vector<vector<int>>> candObs(K);\n    for (int pos = 0; pos < K; ++pos) {\n        FieldState &F = fields[order[pos]];\n        for (int t = 0; t < (int)F.candidates.size(); ++t) {\n            if (!F.alive[t]) continue;\n            candList[pos].push_back(t);\n            vector<int> obsVec;\n            for (int cell : F.candidates[t].cells) {\n                int map = obsIndex[cell];\n                if (map != -1) obsVec.push_back(map);\n            }\n            candObs[pos].push_back(move(obsVec));\n        }\n        if (candList[pos].empty()) {\n            contradiction = true;\n            return result;\n        }\n    }\n\n    vector<vector<char>> used(K);\n    for (int pos = 0; pos < K; ++pos) {\n        used[pos].assign(candList[pos].size(), 0);\n    }\n    vector<uint16_t> curTotal(nCells, 0);\n    for (int idx = 0; idx < nCells; ++idx) curTotal[idx] = assigned_total[idx];\n    vector<char> alwaysPos(nCells, 1), everPos(nCells, 0);\n    vector<int> chosenLocal(K, -1);\n\n    long long nodeCount = 0;\n    long long solutionCount = 0;\n    bool aborted = false;\n\n    auto dfs = [&](auto&& self, int pos) -> void {\n        if (aborted) return;\n        if (++nodeCount > SEARCH_NODE_LIMIT) {\n            aborted = true;\n            return;\n        }\n        for (int i = 0; i < obsCount; ++i) {\n            if (residual[i] > suffixPossible[pos][i]) return;\n        }\n        if (pos == K) {\n            for (int i = 0; i < obsCount; ++i) {\n                if (residual[i] != 0) return;\n            }\n            solutionCount++;\n            if (solutionCount > SEARCH_SOLUTION_LIMIT) {\n                aborted = true;\n                return;\n            }\n            for (int idx = 0; idx < nCells; ++idx) {\n                bool positive = curTotal[idx] > 0;\n                if (!positive) alwaysPos[idx] = 0;\n                else everPos[idx] = 1;\n            }\n            for (int p = 0; p < K; ++p) {\n                int loc = chosenLocal[p];\n                if (loc >= 0) used[p][loc] = 1;\n            }\n            return;\n        }\n        int fk = order[pos];\n        auto &candIdxs = candList[pos];\n        auto &candObsList = candObs[pos];\n        for (int ci = 0; ci < (int)candIdxs.size(); ++ci) {\n            auto &obsVec = candObsList[ci];\n            bool ok = true;\n            for (int obsId : obsVec) {\n                if (residual[obsId] == 0) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (!ok) continue;\n            for (int obsId : obsVec) residual[obsId]--;\n            for (int cell : fields[fk].candidates[candIdxs[ci]].cells) curTotal[cell]++;\n            chosenLocal[pos] = ci;\n            self(self, pos + 1);\n            chosenLocal[pos] = -1;\n            for (int cell : fields[fk].candidates[candIdxs[ci]].cells) curTotal[cell]--;\n            for (int obsId : obsVec) residual[obsId]++;\n            if (aborted) return;\n        }\n    };\n\n    dfs(dfs, 0);\n    if (aborted) return result;\n    if (solutionCount == 0) {\n        contradiction = true;\n        return result;\n    }\n\n    bool statusChange = false;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (alwaysPos[idx] && cellStatus[idx] != 1) {\n            cellStatus[idx] = 1;\n            statusChange = true;\n        }\n        if (!everPos[idx] && cellStatus[idx] != 0) {\n            cellStatus[idx] = 0;\n            statusChange = true;\n        }\n    }\n\n    bool fieldsChanged = false;\n    for (int pos = 0; pos < K; ++pos) {\n        int fk = order[pos];\n        for (int ci = 0; ci < (int)candList[pos].size(); ++ci) {\n            if (!used[pos][ci]) {\n                eliminate_candidate(fk, candList[pos][ci]);\n                fieldsChanged = true;\n                if (contradiction) return result;\n            }\n        }\n    }\n\n    result.progress = statusChange || fieldsChanged;\n    result.needPropagation = fieldsChanged;\n    return result;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> M >> eps)) return 0;\n    nCells = N * N;\n    fields.resize(M);\n    assigned_total.assign(nCells, 0);\n    observed.assign(nCells, -1);\n    drilled.assign(nCells, 0);\n    possible_sum.assign(nCells, 0);\n    guaranteed_sum.assign(nCells, 0);\n    cellStatus.assign(nCells, -1);\n    observed_cells.reserve(nCells);\n\n    for (int k = 0; k < M; ++k) {\n        int d;\n        cin >> d;\n        vector<pair<int, int>> shape(d);\n        int max_i = 0, max_j = 0;\n        for (int t = 0; t < d; ++t) {\n            int a, b;\n            cin >> a >> b;\n            shape[t] = {a, b};\n            max_i = max(max_i, a);\n            max_j = max(max_j, b);\n        }\n        FieldState &F = fields[k];\n        for (int di = 0; di + max_i < N; ++di) {\n            for (int dj = 0; dj + max_j < N; ++dj) {\n                Candidate cand;\n                cand.cells.reserve(d);\n                cand.mask.reset();\n                bool ok = true;\n                for (auto [a, b] : shape) {\n                    int ii = di + a;\n                    int jj = dj + b;\n                    if (ii < 0 || ii >= N || jj < 0 || jj >= N) {\n                        ok = false;\n                        break;\n                    }\n                    int idx = cell_id(ii, jj);\n                    cand.cells.push_back(idx);\n                    cand.mask.set(idx);\n                }\n                if (ok) F.candidates.push_back(move(cand));\n            }\n        }\n        F.rem = (int)F.candidates.size();\n        if (F.rem == 0) {\n            contradiction = true;\n        }\n        F.alive.assign(F.rem, 1);\n        F.cellCoverCount.assign(nCells, 0);\n        for (int t = 0; t < F.rem; ++t) {\n            for (int idx : F.candidates[t].cells) {\n                F.cellCoverCount[idx]++;\n            }\n        }\n        F.possibleFlag.assign(nCells, 0);\n        F.guaranteedFlag.assign(nCells, 0);\n        for (int idx = 0; idx < nCells; ++idx) {\n            if (F.cellCoverCount[idx] > 0) {\n                F.possibleFlag[idx] = 1;\n                possible_sum[idx] += 1;\n            }\n            if (F.rem > 0 && F.cellCoverCount[idx] == F.rem) {\n                F.guaranteedFlag[idx] = 1;\n                guaranteed_sum[idx] += 1;\n            }\n        }\n    }\n\n    for (int k = 0; k < M; ++k) {\n        if (!fields[k].fixed && fields[k].rem == 1) fix_field(k);\n    }\n    update_trivial_statuses();\n\n    while (!contradiction && !all_cells_determined()) {\n        AttemptResult sr = attempt_search();\n        if (contradiction) break;\n        if (sr.needPropagation) {\n            if (!apply_propagation()) break;\n            continue;\n        }\n        if (sr.progress) {\n            continue;\n        }\n        int next = select_next_cell();\n        if (next == -1) next = select_any_undetermined_cell();\n        if (next == -1) break;\n        drill_cell(next);\n        if (!apply_propagation()) break;\n    }\n\n    if (contradiction || !all_cells_determined()) {\n        for (int idx = 0; idx < nCells; ++idx) {\n            if (!drilled[idx]) drill_cell(idx);\n        }\n        update_trivial_statuses();\n    }\n\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (cellStatus[idx] == -1) {\n            if (observed[idx] >= 0) cellStatus[idx] = (observed[idx] > 0) ? 1 : 0;\n            else if (assigned_total[idx] > 0) cellStatus[idx] = 1;\n            else cellStatus[idx] = 0;\n        }\n    }\n\n    vector<pair<int, int>> answer;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (cellStatus[idx] == 1) {\n            answer.emplace_back(idx / N, idx % N);\n        }\n    }\n\n    cout << \"a \" << answer.size();\n    for (auto [i, j] : answer) {\n        cout << ' ' << i << ' ' << j;\n    }\n    cout << '\\n' << flush;\n\n    int verdict;\n    if (!(cin >> verdict)) return 0;\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RectInfo {\n    int i0 = 0, j0 = 0, i1 = 1, j1 = 1;\n};\n\nstruct TreeNode {\n    int left = -1;\n    int right = -1;\n    int leaf = -1;\n    bool isLeaf = false;\n    bool splitHorizontal = false;\n};\n\nint W, D, N;\nlong long TOT;\n\nvector<vector<int>> demands;\nvector<long long> baseArea;\n\nvector<TreeNode> nodes;\nint rootNode = -1;\n\nvector<int> orderIdx;\n\nvector<RectInfo> currentRects;\nvector<long long> leafActualArea;\nvector<long double> subtreeWeight;\n\nvector<long long> compute_base_area() {\n    const long long baseMin = 1;\n    vector<long long> area(N, baseMin);\n    vector<vector<int>> stats(N, vector<int>(D));\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) {\n            stats[k][d] = demands[d][N - 1 - k];\n        }\n    }\n    for (int k = 0; k < N; ++k) sort(stats[k].begin(), stats[k].end());\n\n    struct NodeWF {\n        int benefit;\n        long long len;\n        int idx;\n    };\n    struct CmpWF {\n        bool operator()(const NodeWF& a, const NodeWF& b) const {\n            if (a.benefit != b.benefit) return a.benefit < b.benefit;\n            if (a.len != b.len) return a.len < b.len;\n            return a.idx > b.idx;\n        }\n    };\n\n    vector<int> ptr(N, 0);\n    priority_queue<NodeWF, vector<NodeWF>, CmpWF> pq;\n    auto push = [&](int j) {\n        while (ptr[j] < D && (long long)stats[j][ptr[j]] <= area[j]) ptr[j]++;\n        if (ptr[j] >= D) return;\n        long long len = (long long)stats[j][ptr[j]] - area[j];\n        if (len <= 0) return;\n        int benefit = D - ptr[j];\n        if (benefit <= 0) return;\n        pq.push(NodeWF{benefit, len, j});\n    };\n    for (int j = 0; j < N; ++j) push(j);\n\n    long long used = baseMin * N;\n    long long remaining = TOT - used;\n    while (remaining > 0 && !pq.empty()) {\n        NodeWF cur = pq.top(); pq.pop();\n        long long take = min(cur.len, remaining);\n        area[cur.idx] += take;\n        remaining -= take;\n        cur.len -= take;\n        if (cur.len > 0) pq.push(cur);\n        else push(cur.idx);\n    }\n    long long sum = 0;\n    for (auto v : area) sum += v;\n    if (sum < TOT) {\n        long long leftover = TOT - sum;\n        long long addEach = leftover / N;\n        if (addEach > 0) {\n            for (int i = 0; i < N; ++i) area[i] += addEach;\n            leftover -= addEach * N;\n        }\n        for (int i = 0; i < N && leftover > 0; ++i) {\n            area[i] += 1;\n            leftover -= 1;\n        }\n    }\n    return area;\n}\n\nint build_tree(const vector<int>& ids, int x0, int y0, int x1, int y1) {\n    int nodeId = (int)nodes.size();\n    nodes.push_back(TreeNode());\n    TreeNode &node = nodes.back();\n    if ((int)ids.size() == 1) {\n        node.isLeaf = true;\n        node.leaf = ids[0];\n        return nodeId;\n    }\n    int h = x1 - x0;\n    int w = y1 - y0;\n\n    vector<long long> prefix(ids.size() + 1, 0);\n    for (int i = 0; i < (int)ids.size(); ++i)\n        prefix[i + 1] = prefix[i] + baseArea[ids[i]];\n    long long total = prefix.back();\n    int bestMid = 1;\n    long long bestDiff = (1LL << 62);\n    for (int mid = 1; mid < (int)ids.size(); ++mid) {\n        long long diff = llabs(prefix[mid] * 2 - total);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestMid = mid;\n        }\n    }\n    vector<int> leftIds(ids.begin(), ids.begin() + bestMid);\n    vector<int> rightIds(ids.begin() + bestMid, ids.end());\n    long long sumLeft = prefix[bestMid];\n    long long sumRight = total - sumLeft;\n\n    bool preferHoriz = (h >= w);\n    int splitLen = -1;\n    bool ok = false;\n\n    auto try_split_horizontal = [&](long long needLeft, long long needRight) -> bool {\n        if (h < 2 || w <= 0) return false;\n        long double ratio = total > 0 ? (long double)needLeft / (long double)total : 0.5L;\n        int split = (int)llround((long double)h * ratio);\n        split = max(1, min(h - 1, split));\n        splitLen = split;\n        return true;\n    };\n    auto try_split_vertical = [&](long long needLeft, long long needRight) -> bool {\n        if (w < 2 || h <= 0) return false;\n        long double ratio = total > 0 ? (long double)needLeft / (long double)total : 0.5L;\n        int split = (int)llround((long double)w * ratio);\n        split = max(1, min(w - 1, split));\n        splitLen = split;\n        return true;\n    };\n\n    if (preferHoriz) {\n        ok = try_split_horizontal(sumLeft, sumRight);\n        if (ok) node.splitHorizontal = true;\n    }\n    if (!ok) {\n        ok = try_split_vertical(sumLeft, sumRight);\n        if (ok) node.splitHorizontal = false;\n    }\n    if (!ok) {\n        if (h >= 2) {\n            node.splitHorizontal = true;\n            splitLen = max(1, min(h - 1, h / 2));\n        } else {\n            node.splitHorizontal = false;\n            splitLen = max(1, min(w - 1, w / 2));\n        }\n    }\n\n    if (node.splitHorizontal) {\n        node.left = build_tree(leftIds, x0, y0, x0 + splitLen, y1);\n        node.right = build_tree(rightIds, x0 + splitLen, y0, x1, y1);\n    } else {\n        node.left = build_tree(leftIds, x0, y0, x1, y0 + splitLen);\n        node.right = build_tree(rightIds, x0, y0 + splitLen, x1, y1);\n    }\n    return nodeId;\n}\n\nlong double build_weights(int node, const vector<long double>& weightLD) {\n    TreeNode &nd = nodes[node];\n    if (nd.isLeaf) {\n        long double val = max<long double>(weightLD[nd.leaf], 1e-9L);\n        subtreeWeight[node] = val;\n        return val;\n    }\n    long double left = build_weights(nd.left, weightLD);\n    long double right = build_weights(nd.right, weightLD);\n    subtreeWeight[node] = left + right;\n    return subtreeWeight[node];\n}\n\nint calc_split_len(int len, long double leftWeight, long double totalWeight) {\n    if (len <= 1) return 1;\n    if (totalWeight <= 0) totalWeight = 1.0L;\n    long double ratio = leftWeight / totalWeight;\n    ratio = max((long double)0.0L, min((long double)1.0L, ratio));\n    int split = (int)llround((long double)len * ratio);\n    split = max(1, min(len - 1, split));\n    return split;\n}\n\nvoid assign_geometry(int node, int x0, int y0, int x1, int y1) {\n    TreeNode &nd = nodes[node];\n    if (nd.isLeaf) {\n        currentRects[nd.leaf].i0 = x0;\n        currentRects[nd.leaf].j0 = y0;\n        currentRects[nd.leaf].i1 = x1;\n        currentRects[nd.leaf].j1 = y1;\n        long long area = 1LL * (x1 - x0) * (y1 - y0);\n        if (area <= 0) area = 1;\n        leafActualArea[nd.leaf] = area;\n        return;\n    }\n    int h = x1 - x0;\n    int w = y1 - y0;\n    bool canHoriz = h >= 2;\n    bool canVert = w >= 2;\n\n    bool useHoriz = nd.splitHorizontal;\n    if (useHoriz && !canHoriz) useHoriz = false;\n    if (!useHoriz && !canVert) useHoriz = true;\n\n    long double leftW = subtreeWeight[nd.left];\n    long double rightW = subtreeWeight[nd.right];\n    long double total = leftW + rightW;\n    if (total <= 0) { leftW = rightW = 1.0L; total = 2.0L; }\n\n    if (useHoriz) {\n        int split = calc_split_len(h, leftW, total);\n        assign_geometry(nd.left, x0, y0, x0 + split, y1);\n        assign_geometry(nd.right, x0 + split, y0, x1, y1);\n    } else {\n        int split = calc_split_len(w, leftW, total);\n        assign_geometry(nd.left, x0, y0, x1, y0 + split);\n        assign_geometry(nd.right, x0, y0 + split, x1, y1);\n    }\n}\n\nvoid apply_layout(const vector<long long>& weights, vector<long long>& actualAreas) {\n    vector<long double> weightLD(N);\n    for (int i = 0; i < N; ++i) {\n        weightLD[i] = max<long double>((long double)weights[i], 1.0L);\n    }\n    subtreeWeight.assign(nodes.size(), 0.0L);\n    build_weights(rootNode, weightLD);\n    assign_geometry(rootNode, 0, 0, W, W);\n    actualAreas = leafActualArea;\n}\n\nvoid adjust_working(const vector<long long>& base,\n                    const vector<long long>& target,\n                    vector<long long>& working) {\n    int n = base.size();\n    working = base;\n    vector<long long> curTarget(n);\n    for (int i = 0; i < n; ++i) curTarget[i] = max(1LL, target[i]);\n\n    long long need = 0;\n    vector<pair<long long,int>> donors;\n    donors.reserve(n);\n    for (int i = 0; i < n; ++i) {\n        if (working[i] < curTarget[i]) {\n            need += curTarget[i] - working[i];\n            working[i] = curTarget[i];\n        }\n    }\n    for (int i = 0; i < n; ++i) {\n        long long slack = working[i] - curTarget[i];\n        if (slack > 0) donors.emplace_back(slack, i);\n    }\n    sort(donors.begin(), donors.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 : donors) {\n        if (need == 0) break;\n        int idx = p.second;\n        long long avail = working[idx] - curTarget[idx];\n        if (avail <= 0) continue;\n        long long take = min(avail, need);\n        working[idx] -= take;\n        need -= take;\n    }\n    if (need > 0) {\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b){\n            if (working[a] != working[b]) return working[a] > working[b];\n            return a < b;\n        });\n        for (int idx : order) {\n            if (need == 0) break;\n            long long can = working[idx] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, need);\n            working[idx] -= take;\n            need -= take;\n        }\n    }\n    if (need > 0) {\n        for (int idx : orderIdx) {\n            if (need == 0) break;\n            long long can = working[idx] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, need);\n            working[idx] -= take;\n            need -= take;\n        }\n    }\n    if (need > 0) {\n        for (int i = 0; i < n && need > 0; ++i) {\n            long long can = working[i] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, need);\n            working[i] -= take;\n            need -= take;\n        }\n    }\n    if (need > 0) need = 0;\n\n    for (int i = 0; i < n; ++i) if (working[i] < 1) working[i] = 1;\n    long long sum = accumulate(working.begin(), working.end(), 0LL);\n    if (sum > TOT) {\n        long long excess = sum - TOT;\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b){\n            if (working[a] != working[b]) return working[a] > working[b];\n            return a < b;\n        });\n        for (int idx : order) {\n            if (excess == 0) break;\n            long long can = working[idx] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, excess);\n            working[idx] -= take;\n            excess -= take;\n        }\n        if (excess > 0) {\n            for (int i = 0; i < n && excess > 0; ++i) {\n                long long can = working[i] - 1;\n                if (can <= 0) continue;\n                long long take = min(can, excess);\n                working[i] -= take;\n                excess -= take;\n            }\n        }\n    } else if (sum < TOT) {\n        long long deficit = TOT - sum;\n        for (int idx : orderIdx) {\n            if (deficit == 0) break;\n            long long add = deficit;\n            working[idx] += add;\n            deficit -= add;\n        }\n        if (deficit > 0) {\n            for (int i = 0; i < n && deficit > 0; ++i) {\n                long long add = deficit;\n                working[i] += add;\n                deficit -= add;\n            }\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    if (!(cin >> W >> D >> N)) return 0;\n    TOT = 1LL * W * W;\n    demands.assign(D, vector<int>(N));\n    for (int d = 0; d < D; ++d)\n        for (int k = 0; k < N; ++k)\n            cin >> demands[d][k];\n\n    baseArea = compute_base_area();\n\n    orderIdx.resize(N);\n    iota(orderIdx.begin(), orderIdx.end(), 0);\n    sort(orderIdx.begin(), orderIdx.end(), [&](int a, int b) {\n        if (baseArea[a] != baseArea[b]) return baseArea[a] > baseArea[b];\n        return a < b;\n    });\n\n    nodes.reserve(2 * N + 5);\n    rootNode = build_tree(orderIdx, 0, 0, W, W);\n\n    currentRects.assign(N, RectInfo());\n    leafActualArea.assign(N, 1);\n\n    vector<long long> lastAreas = baseArea;\n\n    vector<pair<int,int>> req(N);\n    vector<int> reqToLeaf(N);\n    vector<long long> desiredLeaf(N);\n    vector<long long> effectiveTarget(N);\n    vector<long long> base(N), working(N), actual(N);\n\n    const int MAX_ITER = 6;\n\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) req[k] = {demands[d][k], k};\n        sort(req.begin(), req.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 pos = 0; pos < N; ++pos) {\n            int leaf = orderIdx[pos];\n            desiredLeaf[leaf] = req[pos].first;\n            reqToLeaf[req[pos].second] = leaf;\n        }\n\n        effectiveTarget = desiredLeaf;\n        base = lastAreas;\n\n        for (int iter = 0; iter < MAX_ITER; ++iter) {\n            adjust_working(base, effectiveTarget, working);\n            apply_layout(working, actual);\n            bool ok = true;\n            for (int i = 0; i < N; ++i) {\n                long long deficit = desiredLeaf[i] - actual[i];\n                if (deficit > 0) {\n                    effectiveTarget[i] += deficit + 1;\n                    ok = false;\n                }\n            }\n            base = actual;\n            if (ok) break;\n        }\n        lastAreas = actual;\n\n        for (int k = 0; k < N; ++k) {\n            const RectInfo& r = currentRects[reqToLeaf[k]];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Operation {\n    int stamp;\n    int p, q;\n    array<int, 9> cells;\n    array<int, 9> adds;\n};\n\nstruct Solver {\n    static constexpr int MOD = 998244353;\n    int N, M, K;\n    vector<int> board_mod;\n    vector<Operation> ops;\n    vector<char> used;\n    vector<int> used_ops;\n    vector<int> pos_in_used;\n    long long current_score = 0;\n    long long best_score = 0;\n    vector<int> best_ops;\n\n    mt19937 rng;\n    uniform_real_distribution<double> dist01;\n\n    Solver() : rng(random_device{}()), dist01(0.0, 1.0) {}\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        auto global_start = chrono::steady_clock::now();\n\n        cin >> N >> M >> K;\n        vector<int> initial(N * N);\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                cin >> initial[i * N + j];\n            }\n        }\n        vector<array<array<int, 3>, 3>> stamps(M);\n        for (int m = 0; m < M; ++m) {\n            for (int i = 0; i < 3; ++i) {\n                for (int j = 0; j < 3; ++j) {\n                    cin >> stamps[m][i][j];\n                }\n            }\n        }\n\n        build_operations(stamps);\n\n        board_mod = initial;\n        used.assign(ops.size(), 0);\n        pos_in_used.assign(ops.size(), -1);\n        used_ops.clear();\n        used_ops.reserve(K);\n\n        current_score = 0;\n        for (int v : board_mod) current_score += v;\n        best_score = current_score;\n        best_ops = used_ops;\n\n        greedy_init();\n\n        constexpr double TOTAL_TIME_LIMIT = 1.90; // seconds\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n        double remaining = TOTAL_TIME_LIMIT - elapsed;\n        if (remaining > 0.05 && !ops.empty()) {\n            simulated_annealing(max(0.01, remaining - 0.01));\n        }\n\n        output_best();\n    }\n\n    void build_operations(const vector<array<array<int, 3>, 3>>& stamps) {\n        ops.clear();\n        int placements = (N - 2) * (N - 2);\n        ops.reserve(M * placements);\n        for (int m = 0; m < M; ++m) {\n            for (int p = 0; p <= N - 3; ++p) {\n                for (int q = 0; q <= N - 3; ++q) {\n                    Operation op;\n                    op.stamp = m;\n                    op.p = p;\n                    op.q = q;\n                    int idx = 0;\n                    for (int i = 0; i < 3; ++i) {\n                        for (int j = 0; j < 3; ++j) {\n                            op.cells[idx] = (p + i) * N + (q + j);\n                            op.adds[idx] = stamps[m][i][j];\n                            ++idx;\n                        }\n                    }\n                    ops.push_back(op);\n                }\n            }\n        }\n    }\n\n    long long apply_operation(int op_idx) {\n        const Operation& op = ops[op_idx];\n        long long delta = 0;\n        for (int t = 0; t < 9; ++t) {\n            int add = op.adds[t];\n            if (add == 0) continue;\n            int idx = op.cells[t];\n            int before = board_mod[idx];\n            int after = before + add;\n            if (after >= MOD) after -= MOD;\n            board_mod[idx] = after;\n            delta += after - before;\n        }\n        return delta;\n    }\n\n    long long remove_operation(int op_idx) {\n        const Operation& op = ops[op_idx];\n        long long delta = 0;\n        for (int t = 0; t < 9; ++t) {\n            int add = op.adds[t];\n            if (add == 0) continue;\n            int idx = op.cells[t];\n            int before = board_mod[idx];\n            int after = before - add;\n            if (after < 0) after += MOD;\n            board_mod[idx] = after;\n            delta += after - before;\n        }\n        return delta;\n    }\n\n    void greedy_init() {\n        for (int iter = 0; iter < K; ++iter) {\n            long long best_delta = 0;\n            int best_idx = -1;\n            for (int op_idx = 0; op_idx < (int)ops.size(); ++op_idx) {\n                if (used[op_idx]) continue;\n                const Operation& op = ops[op_idx];\n                long long delta = 0;\n                for (int t = 0; t < 9; ++t) {\n                    int add = op.adds[t];\n                    if (add == 0) continue;\n                    int idx = op.cells[t];\n                    int before = board_mod[idx];\n                    int after = before + add;\n                    if (after >= MOD) after -= MOD;\n                    delta += after - before;\n                }\n                if (delta > best_delta) {\n                    best_delta = delta;\n                    best_idx = op_idx;\n                }\n            }\n            if (best_idx == -1 || best_delta <= 0) break;\n            long long delta = apply_operation(best_idx);\n            current_score += delta;\n            used[best_idx] = 1;\n            pos_in_used[best_idx] = used_ops.size();\n            used_ops.push_back(best_idx);\n            if (current_score > best_score) {\n                best_score = current_score;\n                best_ops = used_ops;\n            }\n        }\n    }\n\n    int pick_random_unused() {\n        if ((int)used_ops.size() >= (int)ops.size()) return -1;\n        for (int attempt = 0; attempt < 32; ++attempt) {\n            int idx = rng() % ops.size();\n            if (!used[idx]) return idx;\n        }\n        for (int idx = 0; idx < (int)ops.size(); ++idx) {\n            if (!used[idx]) return idx;\n        }\n        return -1;\n    }\n\n    bool accept_move(long long delta, double temp) {\n        if (delta >= 0) return true;\n        if (temp <= 1e-9) return false;\n        double ratio = delta / temp;\n        if (ratio < -50.0) return false;\n        double prob = exp(ratio);\n        return dist01(rng) < prob;\n    }\n\n    void simulated_annealing(double time_limit) {\n        auto start = chrono::steady_clock::now();\n        auto end_time = start + chrono::duration<double>(time_limit);\n        const double START_TEMP = 5e8;\n        const double END_TEMP = 5e2;\n        double temp = START_TEMP;\n        long long iter = 0;\n\n        while (true) {\n            if ((iter & 63) == 0) {\n                auto now = chrono::steady_clock::now();\n                if (now >= end_time) break;\n                double elapsed = chrono::duration<double>(now - start).count();\n                double progress = min(1.0, max(0.0, elapsed / time_limit));\n                temp = START_TEMP + (END_TEMP - START_TEMP) * progress;\n                if (temp < 1.0) temp = 1.0;\n            }\n            ++iter;\n\n            int used_cnt = (int)used_ops.size();\n            int move_type;\n            if (used_cnt == 0) {\n                move_type = 0;\n            } else if (used_cnt >= K) {\n                move_type = (rng() & 1) ? 1 : 2;\n            } else {\n                move_type = rng() % 3;\n            }\n\n            if (move_type == 0) { // add\n                int op_idx = pick_random_unused();\n                if (op_idx == -1) continue;\n                long long delta = apply_operation(op_idx);\n                current_score += delta;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    used[op_idx] = 1;\n                    pos_in_used[op_idx] = used_ops.size();\n                    used_ops.push_back(op_idx);\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev = remove_operation(op_idx);\n                    current_score += rev;\n                }\n            } else if (move_type == 1) { // remove\n                if (used_cnt == 0) continue;\n                int pos = rng() % used_cnt;\n                int op_idx = used_ops[pos];\n                long long delta = remove_operation(op_idx);\n                current_score += delta;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    int last_op = used_ops.back();\n                    used_ops[pos] = last_op;\n                    pos_in_used[last_op] = pos;\n                    used_ops.pop_back();\n                    used[op_idx] = 0;\n                    pos_in_used[op_idx] = -1;\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev = apply_operation(op_idx);\n                    current_score += rev;\n                }\n            } else { // swap\n                if (used_cnt == 0) continue;\n                int op_add = pick_random_unused();\n                if (op_add == -1) continue;\n                int pos = rng() % used_cnt;\n                int op_remove = used_ops[pos];\n\n                long long delta_remove = remove_operation(op_remove);\n                current_score += delta_remove;\n\n                long long delta_add = apply_operation(op_add);\n                current_score += delta_add;\n\n                long long delta = delta_remove + delta_add;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    int last_op = used_ops.back();\n                    used_ops[pos] = last_op;\n                    pos_in_used[last_op] = pos;\n                    used_ops.pop_back();\n                    used[op_remove] = 0;\n                    pos_in_used[op_remove] = -1;\n\n                    used[op_add] = 1;\n                    pos_in_used[op_add] = used_ops.size();\n                    used_ops.push_back(op_add);\n\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev_add = remove_operation(op_add);\n                    current_score += rev_add;\n                    long long rev_remove = apply_operation(op_remove);\n                    current_score += rev_remove;\n                }\n            }\n        }\n    }\n\n    void output_best() const {\n        cout << best_ops.size() << '\\n';\n        for (int idx : best_ops) {\n            const Operation& op = ops[idx];\n            cout << op.stamp << ' ' << op.p << ' ' << op.q << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int LIMIT = 10000;\n\nstruct ImprovedSolver {\n    int N;\n    const vector<vector<int>> &A;\n    string mainOps;\n    int cr = 0, cc = 0;\n    int holding = -1;\n    bool ok = true;\n\n    vector<int> gate_idx;\n    vector<int> next_needed;\n    vector<bool> id_done;\n    vector<pair<int,int>> stored_loc;\n    vector<vector<int>> stored_ids;\n    vector<int> stored_pos;\n    vector<vector<int>> grid;\n    vector<pair<int,int>> storage_cells;\n    int empty_slots = 0;\n    int stored_total = 0;\n    int total_dispatched = 0;\n\n    ImprovedSolver(int N_, const vector<vector<int>> &A_) : N(N_), A(A_) {\n        init();\n    }\n\n    void init() {\n        mainOps.clear();\n        cr = 0; cc = 0; holding = -1; ok = true;\n        int total = N * N;\n        gate_idx.assign(N, 0);\n        next_needed.resize(N);\n        for (int r = 0; r < N; ++r) next_needed[r] = r * N;\n        id_done.assign(total, false);\n        stored_loc.assign(total, {-1, -1});\n        stored_ids.assign(N, {});\n        stored_pos.assign(total, -1);\n        grid.assign(N, vector<int>(N, -99));\n        storage_cells.clear();\n        empty_slots = 0;\n        stored_total = 0;\n        total_dispatched = 0;\n\n        for (int r = 0; r < N; ++r) {\n            grid[r][0] = -10; // active gate\n            for (int c = 1; c <= N - 2; ++c) {\n                grid[r][c] = -1;\n                storage_cells.push_back({r, c});\n                ++empty_slots;\n            }\n            grid[r][N - 1] = -11; // dispatch\n        }\n    }\n\n    inline int dist(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    bool apply_action(char c) {\n        if (!ok) return false;\n        mainOps.push_back(c);\n        if ((int)mainOps.size() > LIMIT) {\n            ok = false;\n            return false;\n        }\n        return true;\n    }\n\n    bool move_char(char c) {\n        if (!apply_action(c)) return false;\n        if (c == 'U') --cr;\n        else if (c == 'D') ++cr;\n        else if (c == 'L') --cc;\n        else if (c == 'R') ++cc;\n        else { ok = false; return false; }\n        if (cr < 0 || cr >= N || cc < 0 || cc >= N) { ok = false; return false; }\n        return true;\n    }\n\n    bool move_to(int tr, int tc) {\n        while (cr < tr) if (!move_char('D')) return false;\n        while (cr > tr) if (!move_char('U')) return false;\n        while (cc < tc) if (!move_char('R')) return false;\n        while (cc > tc) if (!move_char('L')) return false;\n        return true;\n    }\n\n    bool pick_action(int id) {\n        if (holding != -1) { ok = false; return false; }\n        if (!apply_action('P')) return false;\n        holding = id;\n        return true;\n    }\n\n    bool drop_action() {\n        if (holding == -1) { ok = false; return false; }\n        if (!apply_action('Q')) return false;\n        holding = -1;\n        return true;\n    }\n\n    void advance_next(int row) {\n        int row_end = (row + 1) * N;\n        while (next_needed[row] < row_end && id_done[next_needed[row]]) {\n            ++next_needed[row];\n        }\n    }\n\n    void add_storage_cell(int r, int c) {\n        if (grid[r][c] == -10) {\n            grid[r][c] = -1;\n            storage_cells.push_back({r, c});\n            ++empty_slots;\n        }\n    }\n\n    pair<int,int> choose_storage_cell(int target_row) {\n        int best_cost = INT_MAX;\n        pair<int,int> best = {-1, -1};\n        int mid_col = (N - 1) / 2;\n        for (auto [r, c] : storage_cells) {\n            if (grid[r][c] == -1) {\n                int cost = abs(r - target_row) * 10 + abs(mid_col - c) * 2;\n                if (c == 0) cost += 5;\n                if (cost < best_cost) {\n                    best_cost = cost;\n                    best = {r, c};\n                }\n            }\n        }\n        return best;\n    }\n\n    bool store_current(int id) {\n        int row = id / N;\n        auto cell = choose_storage_cell(row);\n        if (cell.first == -1) { ok = false; return false; }\n        if (!move_to(cell.first, cell.second)) return false;\n        if (grid[cell.first][cell.second] != -1) { ok = false; return false; }\n        if (!drop_action()) return false;\n        grid[cell.first][cell.second] = id;\n        stored_loc[id] = cell;\n        stored_pos[id] = (int)stored_ids[row].size();\n        stored_ids[row].push_back(id);\n        --empty_slots;\n        ++stored_total;\n        return true;\n    }\n\n    bool pickup_from_storage(int id) {\n        auto [r, c] = stored_loc[id];\n        if (r == -1) { ok = false; return false; }\n        if (!move_to(r, c)) return false;\n        if (grid[r][c] != id) { ok = false; return false; }\n        if (!pick_action(id)) return false;\n        grid[r][c] = -1;\n        stored_loc[id] = {-1, -1};\n        ++empty_slots;\n        --stored_total;\n        int row = id / N;\n        int idx = stored_pos[id];\n        if (idx < 0) { ok = false; return false; }\n        int last = stored_ids[row].back();\n        stored_ids[row][idx] = last;\n        stored_pos[last] = idx;\n        stored_ids[row].pop_back();\n        stored_pos[id] = -1;\n        return true;\n    }\n\n    bool deliver_after_pick(int id) {\n        int row = id / N;\n        if (!move_to(row, N - 1)) return false;\n        if (!drop_action()) return false;\n        id_done[id] = true;\n        ++total_dispatched;\n        advance_next(row);\n        return true;\n    }\n\n    bool deliver_from_storage(int id) {\n        if (!pickup_from_storage(id)) return false;\n        return deliver_after_pick(id);\n    }\n\n    bool fetch_gate(int gate) {\n        if (gate_idx[gate] >= N) { ok = false; return false; }\n        int id = A[gate][gate_idx[gate]];\n        int row = id / N;\n        if (!move_to(gate, 0)) return false;\n        if (!pick_action(id)) return false;\n        ++gate_idx[gate];\n        if (gate_idx[gate] == N) add_storage_cell(gate, 0);\n\n        int row_end = (row + 1) * N;\n        bool immediate = (next_needed[row] < row_end && id == next_needed[row]);\n        if (immediate) return deliver_after_pick(id);\n        if (empty_slots <= 0) { ok = false; return false; }\n        return store_current(id);\n    }\n\n    bool deliver_ready_from_storage() {\n        int best_row = -1;\n        int best_id = -1;\n        int best_cost = INT_MAX;\n        for (int r = 0; r < N; ++r) {\n            int need = next_needed[r];\n            int row_end = (r + 1) * N;\n            if (need >= row_end) continue;\n            if (stored_pos[need] == -1) continue;\n            auto [sr, sc] = stored_loc[need];\n            int cost = dist(cr, cc, sr, sc) + dist(sr, sc, r, N - 1);\n            if (cost < best_cost || (cost == best_cost && need < best_id)) {\n                best_cost = cost;\n                best_row = r;\n                best_id = need;\n            }\n        }\n        if (best_row != -1) {\n            return deliver_from_storage(best_id);\n        }\n        return false;\n    }\n\n    bool fetch_gate_immediate() {\n        int best_gate = -1;\n        int best_id = -1;\n        int best_cost = INT_MAX;\n        for (int g = 0; g < N; ++g) {\n            if (gate_idx[g] >= N) continue;\n            int id = A[g][gate_idx[g]];\n            int row = id / N;\n            int row_end = (row + 1) * N;\n            if (!(next_needed[row] < row_end && id == next_needed[row])) continue;\n            int cost = dist(cr, cc, g, 0) + dist(g, 0, row, N - 1);\n            if (cost < best_cost || (cost == best_cost && id < best_id)) {\n                best_cost = cost;\n                best_gate = g;\n                best_id = id;\n            }\n        }\n        if (best_gate != -1) {\n            return fetch_gate(best_gate);\n        }\n        return false;\n    }\n\n    int select_forced_id_cost() {\n        const int gapW = 80;\n        int best_id = -1;\n        long long best_score = (1LL << 60);\n        for (int r = 0; r < N; ++r) {\n            if (stored_ids[r].empty()) continue;\n            int need = next_needed[r];\n            for (int id : stored_ids[r]) {\n                auto [sr, sc] = stored_loc[id];\n                if (sr == -1) continue;\n                int gap = max(id - need, 0);\n                int cost = dist(cr, cc, sr, sc) + dist(sr, sc, r, N - 1);\n                long long score = 1LL * gapW * gap + cost;\n                if (score < best_score || (score == best_score && id < best_id)) {\n                    best_score = score;\n                    best_id = id;\n                }\n            }\n        }\n        return best_id;\n    }\n\n    bool fetch_general_gate() {\n        const int diffW = 60;\n        const int backlogW = 8;\n        const int distW = 1;\n        long long best_score = (1LL << 60);\n        int best_gate = -1;\n        int best_diff = INT_MAX;\n        int best_distgate = INT_MAX;\n        int best_id = INT_MAX;\n        for (int g = 0; g < N; ++g) {\n            if (gate_idx[g] >= N) continue;\n            int id = A[g][gate_idx[g]];\n            int row = id / N;\n            int need = next_needed[row];\n            int row_end = (row + 1) * N;\n            int diff = (need < row_end) ? max(id - need, 0) : max(id - row_end, 0) + 5;\n            int backlog = (int)stored_ids[row].size();\n            int distGate = dist(cr, cc, g, 0);\n            long long score = 1LL * diffW * diff + 1LL * backlogW * backlog + 1LL * distW * distGate;\n            if (score < best_score ||\n                (score == best_score &&\n                 (diff < best_diff ||\n                  (diff == best_diff &&\n                   (distGate < best_distgate ||\n                    (distGate == best_distgate && id < best_id))))))\n            {\n                best_score = score;\n                best_gate = g;\n                best_diff = diff;\n                best_distgate = distGate;\n                best_id = id;\n            }\n        }\n        if (best_gate != -1) {\n            return fetch_gate(best_gate);\n        }\n        return false;\n    }\n\n    bool step() {\n        if (!ok) return false;\n        if (deliver_ready_from_storage()) return true;\n        if (fetch_gate_immediate()) return true;\n        if (empty_slots == 0) {\n            int forced_id = select_forced_id_cost();\n            if (forced_id == -1) { ok = false; return false; }\n            return deliver_from_storage(forced_id);\n        }\n        if (fetch_general_gate()) return true;\n        if (stored_total > 0) {\n            int forced_id = select_forced_id_cost();\n            if (forced_id == -1) { ok = false; return false; }\n            return deliver_from_storage(forced_id);\n        }\n        ok = false;\n        return false;\n    }\n\n    vector<string> run() {\n        int guard = 0;\n        while (ok && total_dispatched < N * N && guard < 200000) {\n            if (!step()) break;\n            ++guard;\n        }\n        if (!ok || total_dispatched != N * N || holding != -1) return {};\n        string big = mainOps;\n        if (big.empty()) big.push_back('.');\n        int L = big.size();\n        vector<string> ops(N);\n        ops[0] = big;\n        for (int i = 1; i < N; ++i) {\n            string s(L, '.');\n            if (!s.empty()) s[0] = 'B';\n            ops[i] = move(s);\n        }\n        return ops;\n    }\n};\n\nvector<string> solve_baseline(int N, const vector<vector<int>> &A) {\n    string mainOps;\n    int cr = 0, cc = 0;\n    auto move_char = [&](char c) {\n        mainOps.push_back(c);\n        if (c == 'U') --cr;\n        else if (c == 'D') ++cr;\n        else if (c == 'L') --cc;\n        else if (c == 'R') ++cc;\n    };\n    auto move_to = [&](int tr, int tc) {\n        while (cr < tr) move_char('D');\n        while (cr > tr) move_char('U');\n        while (cc < tc) move_char('R');\n        while (cc > tc) move_char('L');\n    };\n    for (int src = 0; src < N; ++src) {\n        for (int idx = 0; idx < N; ++idx) {\n            move_to(src, 0);\n            mainOps.push_back('P');\n            int id = A[src][idx];\n            int row = id / N;\n            move_to(row, N - 1);\n            mainOps.push_back('Q');\n        }\n    }\n    if (mainOps.empty()) mainOps.push_back('.');\n    vector<string> ops(N);\n    int L = mainOps.size();\n    ops[0] = mainOps;\n    for (int i = 1; i < N; ++i) {\n        string s(L, '.');\n        if (!s.empty()) s[0] = 'B';\n        ops[i] = move(s);\n    }\n    return ops;\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>> A(N, vector<int>(N));\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            cin >> A[i][j];\n\n    vector<string> ops;\n    {\n        ImprovedSolver solver(N, A);\n        ops = solver.run();\n    }\n    if (ops.empty() || ops[0].size() > LIMIT) {\n        ops = solve_baseline(N, A);\n    }\n    for (int i = 0; i < N; ++i) {\n        cout << ops[i] << '\\n';\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Cell {\n    int r, c, val;\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    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j) cin >> h[i][j];\n\n    vector<string> ops;\n    ops.reserve(120000);\n\n    int cur_r = 0, cur_c = 0;\n    long long load = 0;\n\n    auto moveTo = [&](int tr, int tc) {\n        while (cur_r < tr) { ops.emplace_back(\"D\"); ++cur_r; }\n        while (cur_r > tr) { ops.emplace_back(\"U\"); --cur_r; }\n        while (cur_c < tc) { ops.emplace_back(\"R\"); ++cur_c; }\n        while (cur_c > tc) { ops.emplace_back(\"L\"); --cur_c; }\n    };\n\n    vector<Cell> positives, negatives;\n    positives.reserve(N * N);\n    negatives.reserve(N * N);\n\n    auto collectCells = [&]() {\n        positives.clear();\n        negatives.clear();\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int val = h[i][j];\n                if (val > 0) positives.push_back({i, j, val});\n                else if (val < 0) negatives.push_back({i, j, val});\n            }\n        }\n    };\n\n    auto selectPositive = [&]() -> pair<int,int> {\n        long long bestScore = (1LL << 60);\n        int bestVal = -1;\n        pair<int,int> best{-1,-1};\n        for (const auto& p : positives) {\n            long long distTruck = abs(cur_r - p.r) + abs(cur_c - p.c);\n            long long nearestNeg = 0;\n            if (!negatives.empty()) {\n                int dmin = INT_MAX;\n                for (const auto& n : negatives) {\n                    int d = abs(p.r - n.r) + abs(p.c - n.c);\n                    if (d < dmin) dmin = d;\n                }\n                nearestNeg = dmin;\n            }\n            long long score = distTruck * 1000 + nearestNeg * 350 - 20LL * p.val;\n            if (score < bestScore || (score == bestScore && p.val > bestVal)) {\n                bestScore = score;\n                bestVal = p.val;\n                best = {p.r, p.c};\n            }\n        }\n        return best;\n    };\n\n    auto selectNegative = [&]() -> pair<int,int> {\n        long long bestScore = (1LL << 60);\n        long long bestDeliver = -1;\n        pair<int,int> best{-1,-1};\n        for (const auto& n : negatives) {\n            long long dist = abs(cur_r - n.r) + abs(cur_c - n.c);\n            long long need = -n.val;\n            long long deliver = min<long long>(load, need);\n            if (deliver <= 0) continue;\n            long long score = dist * 1000 - deliver * 25;\n            if (score < bestScore || (score == bestScore && deliver > bestDeliver)) {\n                bestScore = score;\n                bestDeliver = deliver;\n                best = {n.r, n.c};\n            }\n        }\n        return best;\n    };\n\n    const int MAX_OPS = 100000;\n    const int CLEANUP_RESERVE = 36000; // leave room for final gather/distribute\n    const int MAX_ITER = 200000;\n    int iter = 0;\n\n    while ((int)ops.size() < MAX_OPS - CLEANUP_RESERVE && iter < MAX_ITER) {\n        collectCells();\n        if (positives.empty() && negatives.empty() && load == 0) break;\n\n        if (load == 0) {\n            if (positives.empty()) break;\n            auto tgt = selectPositive();\n            if (tgt.first == -1) break;\n            moveTo(tgt.first, tgt.second);\n            int amount = h[tgt.first][tgt.second];\n            if (amount <= 0) { ++iter; continue; }\n            ops.emplace_back(\"+\" + to_string(amount));\n            load += amount;\n            h[tgt.first][tgt.second] = 0;\n        } else {\n            if (negatives.empty()) break;\n            auto tgt = selectNegative();\n            if (tgt.first == -1) break;\n            moveTo(tgt.first, tgt.second);\n            int need = -h[tgt.first][tgt.second];\n            if (need <= 0) { ++iter; continue; }\n            int amount = (int)min<long long>(load, need);\n            if (amount <= 0) { ++iter; continue; }\n            ops.emplace_back(\"-\" + to_string(amount));\n            load -= amount;\n            h[tgt.first][tgt.second] += amount;\n        }\n        ++iter;\n    }\n\n    if (load > 0) {\n        moveTo(0, 0);\n        ops.emplace_back(\"-\" + to_string(load));\n        h[0][0] += (int)load;\n        load = 0;\n    }\n\n    auto gatherPositivesToOrigin = [&]() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (i == 0 && j == 0) continue;\n                int val = h[i][j];\n                if (val <= 0) continue;\n                moveTo(i, j);\n                ops.emplace_back(\"+\" + to_string(val));\n                load += val;\n                h[i][j] = 0;\n                moveTo(0, 0);\n                ops.emplace_back(\"-\" + to_string(val));\n                load -= val;\n                h[0][0] += val;\n            }\n        }\n    };\n\n    auto distributeFromOrigin = [&]() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (h[i][j] >= 0) continue;\n                int need = -h[i][j];\n                if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n                ops.emplace_back(\"+\" + to_string(need));\n                load += need;\n                h[0][0] -= need;\n                moveTo(i, j);\n                ops.emplace_back(\"-\" + to_string(need));\n                load -= need;\n                h[i][j] = 0;\n            }\n        }\n    };\n\n    gatherPositivesToOrigin();\n    distributeFromOrigin();\n\n    if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n\n    if (h[0][0] > 0) {\n        int val = h[0][0];\n        ops.emplace_back(\"+\" + to_string(val));\n        load += val;\n        h[0][0] = 0;\n        ops.emplace_back(\"-\" + to_string(val));\n        load -= val;\n    } else if (h[0][0] < 0) {\n        int val = -h[0][0];\n        ops.emplace_back(\"-\" + to_string(val));\n        load -= val;\n        h[0][0] = 0;\n        ops.emplace_back(\"+\" + to_string(val));\n        load += val;\n    }\n\n    if (load > 0) {\n        if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n        ops.emplace_back(\"-\" + to_string(load));\n        h[0][0] += (int)load;\n        load = 0;\n    }\n\n    for (const string& op : ops) cout << op << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAX_M = 15;\nconstexpr int MAX_TOTAL = 2000;\nconstexpr int MAX_TARGETS = 5;\n\nstruct Seed {\n    array<int, MAX_M> attr;\n    int value;\n    Seed() {\n        attr.fill(0);\n        value = 0;\n    }\n};\n\ndouble computePairScore(const Seed& A, const Seed& B,\n                        const vector<int>& targets,\n                        const vector<double>& weights,\n                        const vector<double>& probWeights,\n                        int M,\n                        int bestValue,\n                        double potentialWeight,\n                        const vector<int>& attrTargets,\n                        const vector<double>& attrWeights,\n                        double attrComponentScale) {\n    static array<double, MAX_TOTAL> dp{};\n    static array<double, MAX_TOTAL> ndp{};\n\n    double attrScore = 0.0;\n    if (!attrWeights.empty()) {\n        for (int l = 0; l < M; ++l) {\n            double w = attrWeights[l];\n            if (w <= 1e-9) continue;\n            int target = attrTargets[l];\n            bool aGood = A.attr[l] >= target;\n            bool bGood = B.attr[l] >= target;\n            if (!aGood && !bGood) continue;\n            attrScore += (aGood && bGood) ? w : (w * 0.5);\n        }\n    }\n    double total = attrScore * attrComponentScale;\n\n    int maxSum = 0;\n    for (int l = 0; l < M; ++l) {\n        maxSum += max(A.attr[l], B.attr[l]);\n    }\n    if (maxSum + 1 > MAX_TOTAL) maxSum = MAX_TOTAL - 1;\n\n    fill(dp.begin(), dp.begin() + (maxSum + 1), 0.0);\n    dp[0] = 1.0;\n    int currentMax = 0;\n    for (int l = 0; l < M; ++l) {\n        int aVal = A.attr[l];\n        int bVal = B.attr[l];\n        int add = max(aVal, bVal);\n        int nextMax = currentMax + add;\n        if (nextMax > MAX_TOTAL - 1) nextMax = MAX_TOTAL - 1;\n        fill(ndp.begin(), ndp.begin() + (nextMax + 1), 0.0);\n        for (int s = 0; s <= currentMax; ++s) {\n            double prob = dp[s];\n            if (prob == 0.0) continue;\n            if (s + aVal <= nextMax) ndp[s + aVal] += prob * 0.5;\n            if (s + bVal <= nextMax) ndp[s + bVal] += prob * 0.5;\n        }\n        currentMax = nextMax;\n        dp.swap(ndp);\n    }\n\n    int K = targets.size();\n    if (K == 0) {\n        double potential = currentMax - bestValue;\n        if (potential > 0) total += potentialWeight * potential;\n        return total;\n    }\n\n    array<double, MAX_TARGETS> tailProb{};\n    array<double, MAX_TARGETS> tailSum{};\n    int minTarget = targets.front();\n    if (minTarget < 0) minTarget = 0;\n    if (currentMax > minTarget) {\n        for (int s = currentMax; s > minTarget; --s) {\n            double prob = dp[s];\n            if (prob == 0.0) continue;\n            for (int idx = 0; idx < K; ++idx) {\n                if (s > targets[idx]) {\n                    tailProb[idx] += prob;\n                    tailSum[idx] += prob * s;\n                } else {\n                    break;\n                }\n            }\n        }\n    }\n\n    for (int idx = 0; idx < K; ++idx) {\n        double sc = tailSum[idx] - static_cast<double>(targets[idx]) * tailProb[idx];\n        if (sc < 0) sc = 0;\n        total += weights[idx] * sc + probWeights[idx] * tailProb[idx];\n    }\n\n    double potential = currentMax - bestValue;\n    if (potential > 0) total += potentialWeight * potential;\n    return total;\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    int seedCount = 2 * N * (N - 1);\n    int selectCount = N * N;\n    vector<Seed> seeds(seedCount);\n    for (int i = 0; i < seedCount; ++i) {\n        int sum = 0;\n        for (int j = 0; j < M; ++j) {\n            int val;\n            cin >> val;\n            seeds[i].attr[j] = val;\n            sum += val;\n        }\n        for (int j = M; j < MAX_M; ++j) seeds[i].attr[j] = 0;\n        seeds[i].value = sum;\n    }\n\n    const int cellCount = selectCount;\n    vector<vector<int>> neighbors(cellCount);\n    vector<pair<int, int>> edges;\n    edges.reserve(2 * N * (N - 1));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int pos = i * N + j;\n            if (j + 1 < N) {\n                int q = pos + 1;\n                neighbors[pos].push_back(q);\n                neighbors[q].push_back(pos);\n                edges.emplace_back(pos, q);\n            }\n            if (i + 1 < N) {\n                int q = pos + N;\n                neighbors[pos].push_back(q);\n                neighbors[q].push_back(pos);\n                edges.emplace_back(pos, q);\n            }\n        }\n    }\n    vector<int> cellDegree(cellCount, 0);\n    for (int pos = 0; pos < cellCount; ++pos) {\n        sort(neighbors[pos].begin(), neighbors[pos].end());\n        neighbors[pos].erase(unique(neighbors[pos].begin(), neighbors[pos].end()), neighbors[pos].end());\n        cellDegree[pos] = (int)neighbors[pos].size();\n    }\n\n    vector<int> positionOrder(cellCount);\n    iota(positionOrder.begin(), positionOrder.end(), 0);\n    double center = (N - 1) / 2.0;\n    vector<double> cellDist(cellCount, 0.0);\n    for (int pos = 0; pos < cellCount; ++pos) {\n        int r = pos / N;\n        int c = pos % N;\n        cellDist[pos] = fabs(r - center) + fabs(c - center);\n    }\n    sort(positionOrder.begin(), positionOrder.end(), [&](int a, int b) {\n        if (fabs(cellDist[a] - cellDist[b]) > 1e-9) return cellDist[a] < cellDist[b];\n        if (cellDegree[a] != cellDegree[b]) return cellDegree[a] > cellDegree[b];\n        return a < b;\n    });\n    vector<int> positionOrderReverse = positionOrder;\n    reverse(positionOrderReverse.begin(), positionOrderReverse.end());\n    vector<int> positionOrderRow(cellCount);\n    iota(positionOrderRow.begin(), positionOrderRow.end(), 0);\n\n    mt19937 rng(712367);\n    uniform_real_distribution<double> realDist(0.0, 1.0);\n    uniform_int_distribution<int> posDist(0, cellCount - 1);\n\n    vector<int> orderIndices(seedCount);\n\n    for (int turn = 0; turn < T; ++turn) {\n        vector<int> bestAttrValue(M, -1);\n        vector<int> secondAttrValue(M, -1);\n        vector<int> bestAttrIndex(M, -1);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            for (int l = 0; l < M; ++l) {\n                int val = seeds[idx].attr[l];\n                if (val > bestAttrValue[l]) {\n                    secondAttrValue[l] = bestAttrValue[l];\n                    bestAttrValue[l] = val;\n                    bestAttrIndex[l] = idx;\n                } else if (val == bestAttrValue[l]) {\n                    if (bestAttrIndex[l] == -1 || seeds[idx].value > seeds[bestAttrIndex[l]].value) {\n                        secondAttrValue[l] = bestAttrValue[l];\n                        bestAttrValue[l] = val;\n                        bestAttrIndex[l] = idx;\n                    } else if (val > secondAttrValue[l]) {\n                        secondAttrValue[l] = val;\n                    }\n                } else if (val > secondAttrValue[l]) {\n                    secondAttrValue[l] = val;\n                }\n            }\n        }\n\n        vector<int> seedChampionCount(seedCount, 0);\n        vector<int> attrTopCount(M, 0);\n        for (int l = 0; l < M; ++l) {\n            if (bestAttrValue[l] < 0) continue;\n            for (int idx = 0; idx < seedCount; ++idx) {\n                if (seeds[idx].attr[l] == bestAttrValue[l]) {\n                    ++attrTopCount[l];\n                    ++seedChampionCount[idx];\n                }\n            }\n        }\n\n        vector<vector<int>> attrOrder(M, vector<int>(seedCount));\n        for (int l = 0; l < M; ++l) {\n            auto& arr = attrOrder[l];\n            iota(arr.begin(), arr.end(), 0);\n            int attrIdx = l;\n            sort(arr.begin(), arr.end(), [&](int a, int b) {\n                if (seeds[a].attr[attrIdx] != seeds[b].attr[attrIdx]) return seeds[a].attr[attrIdx] > seeds[b].attr[attrIdx];\n                if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n                return a < b;\n            });\n        }\n\n        int bestValue = 0;\n        for (const auto& s : seeds) bestValue = max(bestValue, s.value);\n\n        int targetMax = 0;\n        for (int l = 0; l < M; ++l) targetMax += max(0, bestAttrValue[l]);\n\n        const int maintainMargin = 8;\n        int maintainTarget = max(0, bestValue - maintainMargin);\n        int gap = max(0, targetMax - bestValue);\n        double phase = (T <= 1) ? 1.0 : (double)turn / (T - 1);\n        double gapFactor = min(1.0, (gap + 5.0) / 60.0);\n        int improveMargin1 = max(3, (int)round(min(gap * 0.35, 40.0)));\n        int improveMargin2 = max(improveMargin1 + 3, (int)round(min(gap * 0.65, 80.0)));\n        int targetImprove1 = min(bestValue + improveMargin1, targetMax);\n        int targetImprove2 = min(bestValue + improveMargin2, targetMax);\n\n        double improvementScale = (0.5 + 0.5 * (1.0 - phase)) * (0.4 + 0.6 * gapFactor);\n        improvementScale = clamp(improvementScale, 0.25, 1.2);\n        double maintainWeight = 0.8 + 0.5 * phase;\n        double maintainProbWeight = 0.05;\n        double improve1Weight = 4.0 * improvementScale;\n        double improve2Weight = 8.0 * improvementScale;\n        double improve1ProbWeight = 0.8 * improvementScale;\n        double improve2ProbWeight = 1.6 * improvementScale;\n        double potentialWeight = 0.02 + 0.04 * improvementScale;\n\n        vector<int> targets;\n        vector<double> weights, probWeights;\n        targets.reserve(MAX_TARGETS);\n        weights.reserve(MAX_TARGETS);\n        probWeights.reserve(MAX_TARGETS);\n        auto addTarget = [&](int target, double w, double pw) {\n            target = clamp(target, 0, targetMax);\n            if (!targets.empty() && target <= targets.back()) return;\n            if ((int)targets.size() >= MAX_TARGETS) return;\n            targets.push_back(target);\n            weights.push_back(w);\n            probWeights.push_back(pw);\n        };\n        addTarget(maintainTarget, maintainWeight, maintainProbWeight);\n        if (targetImprove1 > maintainTarget) addTarget(targetImprove1, improve1Weight, improve1ProbWeight);\n        if (targetImprove2 > targetImprove1) addTarget(targetImprove2, improve2Weight, improve2ProbWeight);\n\n        vector<int> attrTargets(M, 0);\n        vector<double> attrWeights(M, 0.0);\n        for (int l = 0; l < M; ++l) {\n            int bestVal = bestAttrValue[l];\n            if (bestVal <= 0) {\n                attrTargets[l] = 0;\n                attrWeights[l] = 0.0;\n                continue;\n            }\n            if (bestVal <= 8) {\n                attrTargets[l] = bestVal;\n                attrWeights[l] = 0.0;\n                continue;\n            }\n            int secondVal = max(0, secondAttrValue[l]);\n            int gapAttr = max(0, bestVal - secondVal);\n            int approx = (bestVal * 92 + 50) / 100;\n            int margin = max(1, gapAttr / 2);\n            int target = bestVal - margin;\n            target = max(target, approx);\n            target = max(target, bestVal - 6);\n            target = min(target, bestVal);\n            attrTargets[l] = max(0, target);\n            int bestCount = max(1, attrTopCount[l]);\n            double rarity = 1.0;\n            if (bestVal >= 90) rarity += 0.3;\n            else if (bestVal >= 80) rarity += 0.2;\n            if (gapAttr >= 5) rarity += 0.25;\n            if (gapAttr >= 10) rarity += 0.25;\n            if (bestCount <= 3) rarity += 0.25;\n            if (bestCount == 1) rarity += 0.35;\n            attrWeights[l] = rarity;\n        }\n        double attrComponentScale = (4.0 + 3.0 * (1.0 - phase)) * (0.85 + 0.25 * gapFactor);\n\n        vector<char> attrConsider(M, false);\n        vector<int> coverageThreshold(M, 0);\n        for (int l = 0; l < M; ++l) {\n            int bestVal = bestAttrValue[l];\n            if (bestVal >= 4) attrConsider[l] = true;\n            if (bestVal <= 1) {\n                coverageThreshold[l] = max(0, bestVal);\n            } else {\n                int base = max(attrTargets[l], bestVal - 4);\n                base = min(base, bestVal - 1);\n                coverageThreshold[l] = max(0, base);\n            }\n        }\n\n        vector<int> attrCoverage(seedCount, 0);\n        vector<int> nearBestCount(seedCount, 0);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            int sum = 0;\n            int near = 0;\n            for (int l = 0; l < M; ++l) {\n                if (!attrConsider[l]) continue;\n                int thr = coverageThreshold[l];\n                int diff = seeds[idx].attr[l] - thr;\n                if (diff >= 0) ++near;\n                if (diff > 0) sum += diff;\n            }\n            attrCoverage[idx] = sum;\n            nearBestCount[idx] = near;\n        }\n\n        double wValue = 1.0;\n        double wAttr = 4.5 + 6.0 * gapFactor;\n        double wNear = 8.0 + 6.0 * gapFactor;\n        double wChampion = 150.0 + 40.0 * gapFactor;\n\n        vector<double> combinedScore(seedCount, 0.0);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            combinedScore[idx] = wValue * seeds[idx].value +\n                                 wAttr * attrCoverage[idx] +\n                                 wChampion * seedChampionCount[idx] +\n                                 wNear * nearBestCount[idx];\n        }\n\n        vector<int> attrImportance(M);\n        iota(attrImportance.begin(), attrImportance.end(), 0);\n        sort(attrImportance.begin(), attrImportance.end(), [&](int a, int b) {\n            if (attrWeights[a] > attrWeights[b] + 1e-9) return true;\n            if (attrWeights[b] > attrWeights[a] + 1e-9) return false;\n            if (bestAttrValue[a] != bestAttrValue[b]) return bestAttrValue[a] > bestAttrValue[b];\n            return a < b;\n        });\n\n        vector<int> selectedIndices;\n        selectedIndices.reserve(selectCount);\n        vector<char> used(seedCount, false);\n\n        for (int l = 0; l < M; ++l) {\n            int idx = bestAttrIndex[l];\n            if (idx >= 0 && !used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n\n        int extraPerAttr = (gapFactor >= 0.65 ? 3 : 2);\n        for (int attrIdx : attrImportance) {\n            if ((int)selectedIndices.size() >= selectCount) break;\n            if (!attrConsider[attrIdx] && attrWeights[attrIdx] < 0.05) continue;\n            int added = 0;\n            for (int seedIdx : attrOrder[attrIdx]) {\n                if ((int)selectedIndices.size() >= selectCount) break;\n                if (used[seedIdx]) continue;\n                if (attrConsider[attrIdx]) {\n                    int thr = coverageThreshold[attrIdx];\n                    if (seeds[seedIdx].attr[attrIdx] + 2 < thr) break;\n                }\n                used[seedIdx] = true;\n                selectedIndices.push_back(seedIdx);\n                ++added;\n                if (added >= extraPerAttr) break;\n            }\n        }\n\n        iota(orderIndices.begin(), orderIndices.end(), 0);\n        sort(orderIndices.begin(), orderIndices.end(), [&](int a, int b) {\n            if (combinedScore[a] > combinedScore[b] + 1e-9) return true;\n            if (combinedScore[b] > combinedScore[a] + 1e-9) return false;\n            if (seedChampionCount[a] != seedChampionCount[b]) return seedChampionCount[a] > seedChampionCount[b];\n            if (attrCoverage[a] != attrCoverage[b]) return attrCoverage[a] > attrCoverage[b];\n            if (nearBestCount[a] != nearBestCount[b]) return nearBestCount[a] > nearBestCount[b];\n            if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n            return a < b;\n        });\n        for (int idx : orderIndices) {\n            if ((int)selectedIndices.size() >= selectCount) break;\n            if (!used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n        if ((int)selectedIndices.size() < selectCount) {\n            for (int idx = 0; idx < seedCount && (int)selectedIndices.size() < selectCount; ++idx) {\n                if (!used[idx]) {\n                    used[idx] = true;\n                    selectedIndices.push_back(idx);\n                }\n            }\n        }\n\n        vector<int> selectedValues(selectCount);\n        vector<int> selectedAttrCount(selectCount);\n        vector<int> selectedCoverage(selectCount);\n        vector<int> selectedNearCount(selectCount);\n        for (int i = 0; i < selectCount; ++i) {\n            int idx = selectedIndices[i];\n            selectedValues[i] = seeds[idx].value;\n            selectedAttrCount[i] = seedChampionCount[idx];\n            selectedCoverage[i] = attrCoverage[idx];\n            selectedNearCount[i] = nearBestCount[idx];\n        }\n\n        vector<int> targetsLocal = targets;\n        vector<double> weightsLocal = weights;\n        vector<double> probWeightsLocal = probWeights;\n\n        vector<int> attrTargetsLocal = attrTargets;\n        vector<double> attrWeightsLocal = attrWeights;\n\n        double attrComponentScaleLocal = attrComponentScale;\n\n        int S = selectCount;\n        vector<double> pairScore((size_t)S * S, 0.0);\n        for (int i = 0; i < S; ++i) {\n            pairScore[i * S + i] = 0.0;\n            for (int j = i + 1; j < S; ++j) {\n                double val = computePairScore(seeds[selectedIndices[i]],\n                                              seeds[selectedIndices[j]],\n                                              targetsLocal, weightsLocal, probWeightsLocal,\n                                              M, bestValue, potentialWeight,\n                                              attrTargetsLocal, attrWeightsLocal, attrComponentScaleLocal);\n                pairScore[i * S + j] = val;\n                pairScore[j * S + i] = val;\n            }\n        }\n\n        auto makeOrder = [&](auto comparator) {\n            vector<int> ord(S);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), comparator);\n            return ord;\n        };\n\n        auto cmpChampion = [&](int a, int b) {\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            if (selectedNearCount[a] != selectedNearCount[b]) return selectedNearCount[a] > selectedNearCount[b];\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n        auto cmpCoverage = [&](int a, int b) {\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedNearCount[a] != selectedNearCount[b]) return selectedNearCount[a] > selectedNearCount[b];\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n        auto cmpValue = [&](int a, int b) {\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            if (selectedNearCount[a] != selectedNearCount[b]) return selectedNearCount[a] > selectedNearCount[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n        vector<double> hybridScore(selectCount);\n        for (int i = 0; i < selectCount; ++i) {\n            hybridScore[i] = selectedValues[i] * 1.0 +\n                             selectedCoverage[i] * 6.5 +\n                             selectedAttrCount[i] * 220.0 +\n                             selectedNearCount[i] * 18.0;\n        }\n        auto cmpHybrid = [&](int a, int b) {\n            if (hybridScore[a] > hybridScore[b] + 1e-9) return true;\n            if (hybridScore[b] > hybridScore[a] + 1e-9) return false;\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n\n        vector<int> orderChampion = makeOrder(cmpChampion);\n        vector<int> orderHybrid = makeOrder(cmpHybrid);\n        vector<int> orderCoverage = makeOrder(cmpCoverage);\n        vector<int> orderValue = makeOrder(cmpValue);\n        vector<int> orderRandom(selectCount);\n        iota(orderRandom.begin(), orderRandom.end(), 0);\n        shuffle(orderRandom.begin(), orderRandom.end(), rng);\n        vector<int> orderRandom2 = orderRandom;\n        shuffle(orderRandom2.begin(), orderRandom2.end(), rng);\n\n        vector<vector<int>> seedOrders;\n        seedOrders.reserve(6);\n        seedOrders.push_back(orderChampion);\n        seedOrders.push_back(orderHybrid);\n        seedOrders.push_back(orderCoverage);\n        seedOrders.push_back(orderValue);\n        seedOrders.push_back(orderRandom);\n        seedOrders.push_back(orderRandom2);\n\n        vector<vector<int>> cellOrders = {positionOrder, positionOrderReverse, positionOrderRow};\n\n        const int MAX_INITIAL = 8;\n        vector<pair<int, int>> comboPriority = {\n            {0, 0}, {1, 0}, {2, 0}, {3, 0},\n            {0, 1}, {1, 2}, {2, 1}, {3, 2},\n            {4, 0}, {5, 0}, {4, 1}, {5, 1}\n        };\n\n        vector<vector<int>> initialAssignments;\n        for (auto [si, ci] : comboPriority) {\n            if ((int)initialAssignments.size() >= MAX_INITIAL) break;\n            if (si >= (int)seedOrders.size() || ci >= (int)cellOrders.size()) continue;\n            vector<int> assign(cellCount, -1);\n            const auto& order = seedOrders[si];\n            const auto& placement = cellOrders[ci];\n            for (int idx = 0; idx < cellCount; ++idx) {\n                assign[placement[idx]] = order[idx];\n            }\n            initialAssignments.push_back(assign);\n        }\n        if (initialAssignments.empty()) {\n            vector<int> assign(cellCount, -1);\n            for (int idx = 0; idx < cellCount; ++idx) {\n                assign[positionOrder[idx]] = orderChampion[idx];\n            }\n            initialAssignments.push_back(assign);\n        }\n\n        double degWeight = 0.02 * (0.9 - 0.4 * phase);\n        int initialCount = initialAssignments.size();\n        int totalBudget = (int)(15000 + 6000 * (1.0 - phase));\n        int iterPerInit = max(2000, totalBudget / max(1, initialCount));\n\n        vector<int> bestAssignGlobal;\n        double bestScoreGlobal = -1e100;\n\n        auto runSA = [&](const vector<int>& initialAssign) {\n            vector<int> assign = initialAssign;\n            double edgeScore = 0.0;\n            for (auto [u, v] : edges) {\n                edgeScore += pairScore[assign[u] * S + assign[v]];\n            }\n            double degTerm = 0.0;\n            for (int pos = 0; pos < cellCount; ++pos) {\n                degTerm += cellDegree[pos] * selectedValues[assign[pos]];\n            }\n            double currentScore = edgeScore + degWeight * degTerm;\n            double bestScore = currentScore;\n            vector<int> bestAssign = assign;\n\n            double Tstart = 1.2 * improvementScale + 0.3;\n            double Tend = 0.01;\n            array<pair<int, int>, 32> impacted{};\n\n            for (int iter = 0; iter < iterPerInit; ++iter) {\n                int pos1 = posDist(rng);\n                int pos2 = posDist(rng);\n                if (pos1 == pos2) continue;\n                int seed1 = assign[pos1];\n                int seed2 = assign[pos2];\n                if (seed1 == seed2) continue;\n\n                int cnt = 0;\n                auto addEdgeLocal = [&](int a, int b) {\n                    if (a > b) swap(a, b);\n                    for (int k = 0; k < cnt; ++k) {\n                        if (impacted[k].first == a && impacted[k].second == b) return;\n                    }\n                    impacted[cnt++] = {a, b};\n                };\n                for (int nb : neighbors[pos1]) addEdgeLocal(pos1, nb);\n                for (int nb : neighbors[pos2]) addEdgeLocal(pos2, nb);\n\n                double beforeEdge = 0.0;\n                for (int k = 0; k < cnt; ++k) {\n                    int a = impacted[k].first;\n                    int b = impacted[k].second;\n                    beforeEdge += pairScore[assign[a] * S + assign[b]];\n                }\n\n                double deltaPos = degWeight * (double)(selectedValues[seed2] - selectedValues[seed1]) *\n                                  (cellDegree[pos1] - cellDegree[pos2]);\n\n                swap(assign[pos1], assign[pos2]);\n\n                double afterEdge = 0.0;\n                for (int k = 0; k < cnt; ++k) {\n                    int a = impacted[k].first;\n                    int b = impacted[k].second;\n                    afterEdge += pairScore[assign[a] * S + assign[b]];\n                }\n\n                double delta = (afterEdge - beforeEdge) + deltaPos;\n                double progress = (double)iter / iterPerInit;\n                double temperature = Tstart + (Tend - Tstart) * progress;\n                bool accept = false;\n                if (delta >= 0) {\n                    accept = true;\n                } else if (temperature > 0) {\n                    double prob = exp(delta / temperature);\n                    if (realDist(rng) < prob) accept = true;\n                }\n                if (accept) {\n                    currentScore += delta;\n                    if (currentScore > bestScore) {\n                        bestScore = currentScore;\n                        bestAssign = assign;\n                    }\n                } else {\n                    swap(assign[pos1], assign[pos2]);\n                }\n            }\n\n            if (bestScore > bestScoreGlobal) {\n                bestScoreGlobal = bestScore;\n                bestAssignGlobal = bestAssign;\n            }\n        };\n\n        for (const auto& initAssign : initialAssignments) {\n            runSA(initAssign);\n        }\n\n        if (bestAssignGlobal.empty()) bestAssignGlobal = initialAssignments[0];\n\n        vector<vector<int>> grid(N, vector<int>(N, 0));\n        for (int pos = 0; pos < cellCount; ++pos) {\n            int r = pos / N;\n            int c = pos % N;\n            grid[r][c] = selectedIndices[bestAssignGlobal[pos]];\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (j) cout << ' ';\n                cout << grid[i][j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        if (turn + 1 == T) break;\n        for (int i = 0; i < seedCount; ++i) {\n            int sum = 0;\n            for (int j = 0; j < M; ++j) {\n                int val;\n                cin >> val;\n                seeds[i].attr[j] = val;\n                sum += val;\n            }\n            seeds[i].value = sum;\n        }\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Cell {\n    int x, y;\n};\n\nvector<int> hungarian(const vector<vector<int>>& a) {\n    int n = (int)a.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        vector<int> minv(n + 1, INF);\n        vector<char> used(n + 1, false);\n        int j0 = 0;\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 = a[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= n; ++j) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    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> match(n, -1);\n    for (int j = 1; j <= n; ++j) if (p[j] != 0) match[p[j] - 1] = j - 1;\n    return match;\n}\n\nuint64_t hilbertOrder(int x, int y, int pow2) {\n    uint64_t d = 0;\n    for (int s = pow2 / 2; s > 0; s >>= 1) {\n        int rx = (x & s) ? 1 : 0;\n        int ry = (y & s) ? 1 : 0;\n        d += (uint64_t)s * s * ((3 * rx) ^ ry);\n        if (ry == 0) {\n            if (rx == 1) {\n                x = pow2 - 1 - x;\n                y = pow2 - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n    return d;\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> s(N), t(N);\n    for (int i = 0; i < N; ++i) cin >> s[i];\n    for (int i = 0; i < N; ++i) cin >> t[i];\n\n    vector<vector<int>> occ(N, vector<int>(N));\n    vector<Cell> surplus, deficit;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            occ[i][j] = s[i][j] - '0';\n            int ti = t[i][j] - '0';\n            if (occ[i][j] == 1 && ti == 0) surplus.push_back({i, j});\n            else if (occ[i][j] == 0 && ti == 1) deficit.push_back({i, j});\n        }\n    }\n\n    int K = surplus.size();\n    vector<int> match;\n    if (K > 0) {\n        vector<vector<int>> cost(K, vector<int>(K));\n        for (int i = 0; i < K; ++i)\n            for (int j = 0; j < K; ++j)\n                cost[i][j] = abs(surplus[i].x - deficit[j].x) +\n                             abs(surplus[i].y - deficit[j].y);\n        match = hungarian(cost);\n    }\n\n    vector<int> pickX(K), pickY(K), dropX(K), dropY(K);\n    for (int i = 0; i < K; ++i) {\n        pickX[i] = surplus[i].x;\n        pickY[i] = surplus[i].y;\n        dropX[i] = deficit[match[i]].x;\n        dropY[i] = deficit[match[i]].y;\n    }\n\n    auto edgeCost = [&](const vector<int>& ord, int idx) -> int {\n        if (idx <= 0 || idx >= (int)ord.size()) return 0;\n        int prev = ord[idx - 1];\n        int cur = ord[idx];\n        return abs(dropX[prev] - pickX[cur]) + abs(dropY[prev] - pickY[cur]);\n    };\n\n    auto bridgingCost = [&](const vector<int>& ord) -> long long {\n        long long cost = 0;\n        for (int i = 1; i < (int)ord.size(); ++i)\n            cost += edgeCost(ord, i);\n        return cost;\n    };\n\n    auto improve_order = [&](vector<int> ord) -> vector<int> {\n        if ((int)ord.size() <= 1) return ord;\n        while (true) {\n            bool swapped = false;\n            for (int i = 0; i < (int)ord.size() - 1 && !swapped; ++i) {\n                for (int j = i + 1; j < (int)ord.size(); ++j) {\n                    int idxRaw[4] = {i, i + 1, j, j + 1};\n                    vector<int> idxs;\n                    idxs.reserve(4);\n                    for (int val : idxRaw)\n                        if (val >= 1 && val < (int)ord.size()) idxs.push_back(val);\n                    sort(idxs.begin(), idxs.end());\n                    idxs.erase(unique(idxs.begin(), idxs.end()), idxs.end());\n                    if (idxs.empty()) continue;\n                    int oldCost = 0;\n                    for (int idx : idxs) oldCost += edgeCost(ord, idx);\n                    swap(ord[i], ord[j]);\n                    int newCost = 0;\n                    for (int idx : idxs) newCost += edgeCost(ord, idx);\n                    if (newCost < oldCost) {\n                        swapped = true;\n                        break;\n                    }\n                    swap(ord[i], ord[j]);\n                }\n            }\n            if (!swapped) break;\n        }\n        return ord;\n    };\n\n    vector<vector<int>> candidates;\n    if (K > 0) {\n        vector<int> idx(K);\n        iota(idx.begin(), idx.end(), 0);\n\n        // Nearest-neighbor from center.\n        vector<int> greedy;\n        vector<char> used(K, false);\n        pair<int,int> curPos = {N / 2, N / 2};\n        for (int iter = 0; iter < K; ++iter) {\n            int best = -1, bestDist = INT_MAX, bestPair = INT_MAX;\n            for (int i = 0; i < K; ++i) if (!used[i]) {\n                int dist = abs(curPos.first - pickX[i]) + abs(curPos.second - pickY[i]);\n                int pairDist = abs(pickX[i] - dropX[i]) + abs(pickY[i] - dropY[i]);\n                if (dist < bestDist || (dist == bestDist && pairDist < bestPair)) {\n                    best = i;\n                    bestDist = dist;\n                    bestPair = pairDist;\n                }\n            }\n            used[best] = true;\n            greedy.push_back(best);\n            curPos = {dropX[best], dropY[best]};\n        }\n        candidates.push_back(greedy);\n\n        // Hilbert order by pickup location.\n        int pow2 = 1;\n        while (pow2 < max(N, 1)) pow2 <<= 1;\n        vector<int> hilbertIdx = idx;\n        vector<uint64_t> hilb(K);\n        for (int i = 0; i < K; ++i)\n            hilb[i] = hilbertOrder(pickX[i], pickY[i], pow2);\n        sort(hilbertIdx.begin(), hilbertIdx.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            if (pickX[a] != pickX[b]) return pickX[a] < pickX[b];\n            return pickY[a] < pickY[b];\n        });\n        candidates.push_back(hilbertIdx);\n\n        // Row-major order.\n        vector<int> rowIdx = idx;\n        sort(rowIdx.begin(), rowIdx.end(), [&](int a, int b) {\n            if (pickX[a] != pickX[b]) return pickX[a] < pickX[b];\n            return pickY[a] < pickY[b];\n        });\n        candidates.push_back(rowIdx);\n\n        // Deterministic random order.\n        vector<int> rndIdx = idx;\n        mt19937 rng(1234567);\n        shuffle(rndIdx.begin(), rndIdx.end(), rng);\n        candidates.push_back(rndIdx);\n    }\n\n    vector<int> bestOrder;\n    long long bestBridge = (1LL << 60);\n    if (K > 0) {\n        for (auto cand : candidates) {\n            auto ord = improve_order(cand);\n            long long cost = bridgingCost(ord);\n            if (bestOrder.empty() || cost < bestBridge) {\n                bestBridge = cost;\n                bestOrder = ord;\n            }\n        }\n        if (bestOrder.empty()) {\n            bestOrder.resize(K);\n            iota(bestOrder.begin(), bestOrder.end(), 0);\n        }\n    }\n\n    int root_x = 0, root_y = 0;\n    if (K > 0) {\n        root_x = pickX[bestOrder[0]];\n        root_y = pickY[bestOrder[0]];\n    }\n\n    cout << 1 << '\\n';\n    cout << root_x << ' ' << root_y << '\\n';\n\n    if (K == 0) return 0;\n\n    const int LIMIT = 100000;\n    vector<string> ops;\n    ops.reserve(LIMIT);\n    bool limitReached = false;\n    int rx = root_x, ry = root_y;\n    bool holding = false;\n\n    auto emit = [&](char moveChar, char actionChar) -> bool {\n        if ((int)ops.size() >= LIMIT) {\n            limitReached = true;\n            return false;\n        }\n        string op(2, '.');\n        op[0] = moveChar;\n        op[1] = actionChar;\n        ops.push_back(op);\n        if (moveChar == 'U') --rx;\n        else if (moveChar == 'D') ++rx;\n        else if (moveChar == 'L') --ry;\n        else if (moveChar == 'R') ++ry;\n        return true;\n    };\n\n    auto move_with_action = [&](int tx, int ty, bool doAction, bool isPick) {\n        if (limitReached) return;\n        vector<char> path;\n        int cx = rx, cy = ry;\n        while (cx < tx) { path.push_back('D'); ++cx; }\n        while (cx > tx) { path.push_back('U'); --cx; }\n        while (cy < ty) { path.push_back('R'); ++cy; }\n        while (cy > ty) { path.push_back('L'); --cy; }\n\n        if (path.empty()) {\n            if (doAction) {\n                if (!emit('.', 'P')) return;\n            }\n        } else {\n            for (size_t i = 0; i < path.size(); ++i) {\n                char action = (doAction && i + 1 == path.size()) ? 'P' : '.';\n                if (!emit(path[i], action)) return;\n            }\n        }\n        if (doAction && !limitReached) {\n            if (isPick) {\n                if (!holding && occ[tx][ty] == 1) {\n                    occ[tx][ty] = 0;\n                    holding = true;\n                }\n            } else {\n                if (holding && occ[tx][ty] == 0) {\n                    occ[tx][ty] = 1;\n                    holding = false;\n                }\n            }\n        }\n    };\n\n    for (int idx : bestOrder) {\n        move_with_action(pickX[idx], pickY[idx], true, true);\n        if (limitReached) break;\n        move_with_action(dropX[idx], dropY[idx], true, false);\n        if (limitReached) break;\n    }\n\n    for (const string& line : ops) cout << line << '\\n';\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAX_COORD = 100000;\nconst int NEG_INF = -1000000000;\nconstexpr double TIME_LIMIT = 1.92;\n\nstruct Score {\n    int diff;\n    int m;\n    int s;\n};\n\nstruct RectAns {\n    int x1 = 0, x2 = 0, y1 = 0, y2 = 0;\n    Score sc{NEG_INF, 0, 0};\n};\n\nstruct BIT2D {\n    int n = 0;\n    vector<int> xs_sorted;\n    vector<vector<int>> ys;\n    vector<vector<int>> bitM, bitS;\n\n    void build(const vector<int>& px, const vector<int>& py, const vector<int>& type) {\n        xs_sorted = px;\n        sort(xs_sorted.begin(), xs_sorted.end());\n        xs_sorted.erase(unique(xs_sorted.begin(), xs_sorted.end()), xs_sorted.end());\n        n = xs_sorted.size();\n        ys.assign(n + 1, {});\n        for (size_t idx = 0; idx < px.size(); ++idx) {\n            int xi = lower_bound(xs_sorted.begin(), xs_sorted.end(), px[idx]) - xs_sorted.begin() + 1;\n            for (int i = xi; i <= n; i += i & -i) ys[i].push_back(py[idx]);\n        }\n        bitM.assign(n + 1, {});\n        bitS.assign(n + 1, {});\n        for (int i = 1; i <= n; ++i) {\n            auto &vec = ys[i];\n            sort(vec.begin(), vec.end());\n            vec.erase(unique(vec.begin(), vec.end()), vec.end());\n            bitM[i].assign(vec.size() + 1, 0);\n            bitS[i].assign(vec.size() + 1, 0);\n        }\n        for (size_t idx = 0; idx < px.size(); ++idx) {\n            int xi = lower_bound(xs_sorted.begin(), xs_sorted.end(), px[idx]) - xs_sorted.begin() + 1;\n            int y = py[idx];\n            int addM = type[idx] == 1 ? 1 : 0;\n            int addS = type[idx] == -1 ? 1 : 0;\n            for (int i = xi; i <= n; i += i & -i) {\n                if (ys[i].empty()) continue;\n                int yi = lower_bound(ys[i].begin(), ys[i].end(), y) - ys[i].begin() + 1;\n                if (addM) {\n                    for (int j = yi; j < (int)bitM[i].size(); j += j & -j) bitM[i][j] += addM;\n                }\n                if (addS) {\n                    for (int j = yi; j < (int)bitS[i].size(); j += j & -j) bitS[i][j] += addS;\n                }\n            }\n        }\n    }\n\n    pair<int,int> prefix(int xVal, int yVal) const {\n        if (n == 0) return {0,0};\n        int xi = upper_bound(xs_sorted.begin(), xs_sorted.end(), xVal) - xs_sorted.begin();\n        int sumM = 0, sumS = 0;\n        for (int i = xi; i > 0; i -= i & -i) {\n            const auto &vec = ys[i];\n            if (vec.empty()) continue;\n            int yi = upper_bound(vec.begin(), vec.end(), yVal) - vec.begin();\n            for (int j = yi; j > 0; j -= j & -j) {\n                sumM += bitM[i][j];\n                sumS += bitS[i][j];\n            }\n        }\n        return {sumM, sumS};\n    }\n};\n\nBIT2D bit2d;\nint N;\nvector<int> xs, ys, types;\nvector<pair<int,int>> m_coords;\nRectAns best_rect;\nvector<RectAns> top_rects;\nconst int TOP_LIMIT = 24;\nvector<int> unique_x_vals, unique_y_vals;\n\nmt19937 rng(chrono::steady_clock::now().time_since_epoch().count());\nchrono::steady_clock::time_point start_time;\n\ninline double elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n}\n\ninline bool normalize_rect(int &x1, int &x2, int &y1, int &y2) {\n    if (x1 > x2) swap(x1, x2);\n    if (y1 > y2) swap(y1, y2);\n    x1 = clamp(x1, 0, MAX_COORD);\n    x2 = clamp(x2, 0, MAX_COORD);\n    y1 = clamp(y1, 0, MAX_COORD);\n    y2 = clamp(y2, 0, MAX_COORD);\n    if (x1 == x2) {\n        if (x2 < MAX_COORD) ++x2;\n        else if (x1 > 0) --x1;\n    }\n    if (y1 == y2) {\n        if (y2 < MAX_COORD) ++y2;\n        else if (y1 > 0) --y1;\n    }\n    return x1 != x2 && y1 != y2;\n}\n\ninline long long rect_area(int x1, int x2, int y1, int y2) {\n    return 1LL * (x2 - x1) * (y2 - y1);\n}\n\nbool better_rect(const RectAns &a, const RectAns &b) {\n    if (b.sc.diff == NEG_INF) return true;\n    if (a.sc.diff != b.sc.diff) return a.sc.diff > b.sc.diff;\n    if (a.sc.m != b.sc.m) return a.sc.m > b.sc.m;\n    if (a.sc.s != b.sc.s) return a.sc.s < b.sc.s;\n    return rect_area(a.x1,a.x2,a.y1,a.y2) < rect_area(b.x1,b.x2,b.y1,b.y2);\n}\n\nvoid record_candidate(const RectAns &cand) {\n    for (auto &r : top_rects) {\n        if (r.x1 == cand.x1 && r.x2 == cand.x2 && r.y1 == cand.y1 && r.y2 == cand.y2) {\n            if (better_rect(cand, r)) r = cand;\n            return;\n        }\n    }\n    auto it = top_rects.begin();\n    while (it != top_rects.end() && !better_rect(cand, *it)) ++it;\n    top_rects.insert(it, cand);\n    if ((int)top_rects.size() > TOP_LIMIT) top_rects.pop_back();\n}\n\nScore compute_score(int x1, int x2, int y1, int y2) {\n    auto A = bit2d.prefix(x2, y2);\n    auto B = bit2d.prefix(x1 - 1, y2);\n    auto C = bit2d.prefix(x2, y1 - 1);\n    auto D = bit2d.prefix(x1 - 1, y1 - 1);\n    int m = A.first - B.first - C.first + D.first;\n    int s = A.second - B.second - C.second + D.second;\n    return {m - s, m, s};\n}\n\nvoid push_candidate(int x1, int x2, int y1, int y2, const Score &sc) {\n    RectAns cand{x1,x2,y1,y2,sc};\n    if (better_rect(cand, best_rect)) best_rect = cand;\n    record_candidate(cand);\n}\n\nvoid consider_rect(int x1, int x2, int y1, int y2) {\n    if (!normalize_rect(x1,x2,y1,y2)) return;\n    Score sc = compute_score(x1,x2,y1,y2);\n    push_candidate(x1,x2,y1,y2,sc);\n}\n\nvector<int> gather_candidates(int low, int high, int current, const vector<int>& uniq_vals) {\n    vector<int> cand;\n    if (low > high) return cand;\n    auto clampv = [&](int v) {\n        if (v < low) v = low;\n        if (v > high) v = high;\n        return v;\n    };\n    static const int OFFSETS[] = {-20000,-10000,-5000,-2500,-1200,-600,-300,-150,-70,-30,-12,-5,0,5,12,30,70,150,300,600,1200,2500,5000,10000,20000};\n    cand.reserve(150);\n    cand.push_back(clampv(current));\n    for (int off : OFFSETS) cand.push_back(clampv(current + off));\n    cand.push_back(low);\n    cand.push_back(high);\n    auto itL = lower_bound(uniq_vals.begin(), uniq_vals.end(), low);\n    auto itR = upper_bound(uniq_vals.begin(), uniq_vals.end(), high);\n    int len = itR - itL;\n    if (len > 0) {\n        int step = max(1, len / 18);\n        for (int idx = 0; idx < len && (int)cand.size() < 160; idx += step) {\n            cand.push_back(*(itL + idx));\n        }\n        int random_samples = min(15, len);\n        for (int i = 0; i < random_samples; ++i) {\n            int idx = rng() % len;\n            cand.push_back(*(itL + idx));\n        }\n    }\n    if (high - low >= 1) {\n        int range = high - low;\n        for (int i = 0; i < 10; ++i) cand.push_back(low + (int)(rng() % (range + 1)));\n    }\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n    const int LIMIT = 80;\n    if ((int)cand.size() > LIMIT) {\n        vector<int> reduced;\n        reduced.reserve(LIMIT);\n        reduced.push_back(cand.front());\n        reduced.push_back(cand.back());\n        int cur_clamped = clampv(current);\n        auto it = lower_bound(cand.begin(), cand.end(), cur_clamped);\n        int pos = it - cand.begin();\n        for (int k = -4; k <= 4; ++k) {\n            int idx = pos + k;\n            if (idx >= 0 && idx < (int)cand.size()) reduced.push_back(cand[idx]);\n        }\n        while ((int)reduced.size() < LIMIT) {\n            reduced.push_back(cand[rng() % cand.size()]);\n        }\n        sort(reduced.begin(), reduced.end());\n        reduced.erase(unique(reduced.begin(), reduced.end()), reduced.end());\n        if ((int)reduced.size() > LIMIT) reduced.resize(LIMIT);\n        cand.swap(reduced);\n    }\n    return cand;\n}\n\nbool adjust_left(RectAns &rect) {\n    int low = 0;\n    int high = rect.x2 - 1;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(low, high, rect.x1, unique_x_vals);\n    RectAns best = rect;\n    bool improved = false;\n    for (int x1 : cand) {\n        if (x1 >= rect.x2) continue;\n        Score sc = compute_score(x1, rect.x2, rect.y1, rect.y2);\n        RectAns candRect{x1, rect.x2, rect.y1, rect.y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect.x1, rect.x2, rect.y1, rect.y2, rect.sc);\n    }\n    return improved;\n}\n\nbool adjust_right(RectAns &rect) {\n    int low = rect.x1 + 1;\n    int high = MAX_COORD;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(low, high, rect.x2, unique_x_vals);\n    RectAns best = rect;\n    bool improved = false;\n    for (int x2 : cand) {\n        if (x2 <= rect.x1) continue;\n        Score sc = compute_score(rect.x1, x2, rect.y1, rect.y2);\n        RectAns candRect{rect.x1, x2, rect.y1, rect.y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect.x1, rect.x2, rect.y1, rect.y2, rect.sc);\n    }\n    return improved;\n}\n\nbool adjust_bottom(RectAns &rect) {\n    int low = 0;\n    int high = rect.y2 - 1;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(low, high, rect.y1, unique_y_vals);\n    RectAns best = rect;\n    bool improved = false;\n    for (int y1 : cand) {\n        if (y1 >= rect.y2) continue;\n        Score sc = compute_score(rect.x1, rect.x2, y1, rect.y2);\n        RectAns candRect{rect.x1, rect.x2, y1, rect.y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect.x1, rect.x2, rect.y1, rect.y2, rect.sc);\n    }\n    return improved;\n}\n\nbool adjust_top(RectAns &rect) {\n    int low = rect.y1 + 1;\n    int high = MAX_COORD;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(low, high, rect.y2, unique_y_vals);\n    RectAns best = rect;\n    bool improved = false;\n    for (int y2 : cand) {\n        if (y2 <= rect.y1) continue;\n        Score sc = compute_score(rect.x1, rect.x2, rect.y1, y2);\n        RectAns candRect{rect.x1, rect.x2, rect.y1, y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect.x1, rect.x2, rect.y1, rect.y2, rect.sc);\n    }\n    return improved;\n}\n\nvoid refine_rectangle(RectAns rect, int cycles) {\n    if (rect.sc.diff == NEG_INF) rect.sc = compute_score(rect.x1, rect.x2, rect.y1, rect.y2);\n    RectAns current = rect;\n    for (int iter = 0; iter < cycles && elapsed() < TIME_LIMIT; ++iter) {\n        bool changed = false;\n        changed |= adjust_left(current);\n        if (elapsed() > TIME_LIMIT) break;\n        changed |= adjust_right(current);\n        if (elapsed() > TIME_LIMIT) break;\n        changed |= adjust_bottom(current);\n        if (elapsed() > TIME_LIMIT) break;\n        changed |= adjust_top(current);\n        if (!changed) break;\n    }\n}\n\nvoid refine_top_rects(int count, int cycles) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min(count, (int)seeds.size());\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        refine_rectangle(seeds[i], cycles);\n    }\n}\n\nint sample_half_span() {\n    static const int options[] = {0, 20, 40, 80, 150, 250, 400, 600, 900, 1300, 1800,\n                                  2500, 3400, 4500, 6000, 8000, 10500, 13500, 17000,\n                                  21000, 26000, 32000, 39000, 47000};\n    static const int SZ = sizeof(options)/sizeof(int);\n    int base = options[rng() % SZ];\n    int extra_range = base / 3 + 1;\n    if (base == 0) extra_range = 60;\n    int extra = rng() % extra_range;\n    return base + extra;\n}\n\nint sample_span() {\n    static const pair<int,int> ranges[] = {\n        {1, 400}, {200, 1200}, {800, 3200}, {2000, 7000}, {5000, 15000},\n        {12000, 30000}, {25000, 50000}, {40000, 80000}, {70000, 100000}\n    };\n    static const int SZ = sizeof(ranges)/sizeof(ranges[0]);\n    auto [lo, hi] = ranges[rng() % SZ];\n    hi = min(hi, MAX_COORD);\n    lo = min(lo, hi);\n    int width = lo;\n    if (hi > lo) width += rng() % (hi - lo + 1);\n    return max(1, width);\n}\n\nvector<int> build_lines(const vector<int>& coords, int segments) {\n    vector<int> lines;\n    int extras = segments / 3 + 2;\n    lines.reserve(segments + extras + 4);\n    lines.push_back(0);\n    if (!coords.empty()) {\n        int size = coords.size();\n        for (int i = 1; i < segments; ++i) {\n            long long idx = 1LL * size * i / segments;\n            idx = min<long long>(idx, size - 1);\n            lines.push_back(coords[idx]);\n        }\n        uniform_int_distribution<int> dist(0, size - 1);\n        int extra = min(extras, size);\n        for (int i = 0; i < extra; ++i) lines.push_back(coords[dist(rng)]);\n    }\n    lines.push_back(MAX_COORD + 1);\n    sort(lines.begin(), lines.end());\n    lines.erase(unique(lines.begin(), lines.end()), lines.end());\n    if (lines.front() != 0) lines.insert(lines.begin(), 0);\n    if (lines.back() != MAX_COORD + 1) lines.push_back(MAX_COORD + 1);\n    return lines;\n}\n\nvoid grid_search(int segments, const vector<int>& sorted_x, const vector<int>& sorted_y) {\n    if (elapsed() > TIME_LIMIT) return;\n    auto lines_x = build_lines(sorted_x, segments);\n    auto lines_y = build_lines(sorted_y, segments);\n    int W = (int)lines_x.size() - 1;\n    int H = (int)lines_y.size() - 1;\n    if (W <= 0 || H <= 0) return;\n\n    vector<int> grid(W * H, 0);\n    for (size_t i = 0; i < xs.size(); ++i) {\n        int cx = upper_bound(lines_x.begin(), lines_x.end(), xs[i]) - lines_x.begin() - 1;\n        int cy = upper_bound(lines_y.begin(), lines_y.end(), ys[i]) - lines_y.begin() - 1;\n        cx = clamp(cx, 0, W - 1);\n        cy = clamp(cy, 0, H - 1);\n        grid[cy * W + cx] += types[i];\n    }\n\n    vector<int> arr(W, 0);\n    int best_sum = NEG_INF;\n    int best_top = 0, best_bottom = 0, best_left = 0, best_right = 0;\n    for (int top = 0; top < H; ++top) {\n        fill(arr.begin(), arr.end(), 0);\n        for (int bottom = top; bottom < H; ++bottom) {\n            int row_offset = bottom * W;\n            for (int col = 0; col < W; ++col) arr[col] += grid[row_offset + col];\n            int cur = 0, start = 0;\n            for (int col = 0; col < W; ++col) {\n                if (cur <= 0) {\n                    cur = arr[col];\n                    start = col;\n                } else {\n                    cur += arr[col];\n                }\n                if (cur > best_sum) {\n                    best_sum = cur;\n                    best_top = top;\n                    best_bottom = bottom;\n                    best_left = start;\n                    best_right = col;\n                }\n            }\n        }\n    }\n\n    auto convert = [&](int left, int right, int top, int bottom) {\n        int x1 = lines_x[left];\n        int x2 = lines_x[right + 1] - 1;\n        int y1 = lines_y[top];\n        int y2 = lines_y[bottom + 1] - 1;\n        consider_rect(x1, x2, y1, y2);\n    };\n\n    convert(best_left, best_right, best_top, best_bottom);\n\n    array<pair<int,int>,3> top_cells;\n    int filled = 0;\n    for (int idx = 0; idx < H * W; ++idx) {\n        int val = grid[idx];\n        if (filled < 3) {\n            top_cells[filled++] = {val, idx};\n        } else {\n            int pos = 0;\n            for (int j = 1; j < 3; ++j) if (top_cells[j].first < top_cells[pos].first) pos = j;\n            if (val > top_cells[pos].first) top_cells[pos] = {val, idx};\n        }\n    }\n    for (int i = 0; i < filled; ++i) {\n        int idx = top_cells[i].second;\n        int cy = idx / W;\n        int cx = idx % W;\n        for (int rad = 0; rad <= 1; ++rad) {\n            int left = max(0, cx - rad);\n            int right = min(W - 1, cx + rad);\n            int top = max(0, cy - rad);\n            int bottom = min(H - 1, cy + rad);\n            convert(left, right, top, bottom);\n        }\n    }\n}\n\nvoid random_centered(int iterations) {\n    if (m_coords.empty()) return;\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        const auto &p = m_coords[dist(rng)];\n        int dx = sample_half_span();\n        int dy = sample_half_span();\n        consider_rect(p.first - dx, p.first + dx, p.second - dy, p.second + dy);\n    }\n}\n\nvoid random_global(int iterations) {\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int width = sample_span();\n        int height = sample_span();\n        int x1_max = max(0, MAX_COORD - width);\n        int y1_max = max(0, MAX_COORD - height);\n        int x1 = x1_max ? (int)(rng() % (x1_max + 1)) : 0;\n        int y1 = y1_max ? (int)(rng() % (y1_max + 1)) : 0;\n        consider_rect(x1, x1 + width, y1, y1 + height);\n    }\n}\n\nvoid random_pair_rects(int iterations) {\n    if (m_coords.empty()) return;\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        const auto &a = m_coords[dist(rng)];\n        const auto &b = m_coords[dist(rng)];\n        int x1 = min(a.first, b.first) - sample_half_span();\n        int x2 = max(a.first, b.first) + sample_half_span();\n        const auto &c = m_coords[dist(rng)];\n        const auto &d = m_coords[dist(rng)];\n        int y1 = min(c.second, d.second) - sample_half_span();\n        int y2 = max(c.second, d.second) + sample_half_span();\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_cluster_rects(int iterations) {\n    if (m_coords.empty()) return;\n    vector<int> cluster_sizes = {2,3,4,5,7,9,12,16};\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int k = cluster_sizes[rng() % cluster_sizes.size()];\n        k = min(k, (int)m_coords.size());\n        if (k == 0) break;\n        int minx = INT_MAX, miny = INT_MAX;\n        int maxx = INT_MIN, maxy = INT_MIN;\n        for (int j = 0; j < k; ++j) {\n            const auto &p = m_coords[rng() % m_coords.size()];\n            minx = min(minx, p.first);\n            maxx = max(maxx, p.first);\n            miny = min(miny, p.second);\n            maxy = max(maxy, p.second);\n        }\n        int marginx = sample_half_span();\n        int marginy = sample_half_span();\n        consider_rect(minx - marginx, maxx + marginx, miny - marginy, maxy + marginy);\n    }\n}\n\nvoid quantile_rects(int iterations, const vector<int>& sorted_x, const vector<int>& sorted_y) {\n    if (sorted_x.empty() || sorted_y.empty()) return;\n    uniform_int_distribution<int> dist_x(0, (int)sorted_x.size() - 1);\n    uniform_int_distribution<int> dist_y(0, (int)sorted_y.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int li = dist_x(rng);\n        int ri = dist_x(rng);\n        if (li > ri) swap(li, ri);\n        int marginx = sample_half_span() / 2 + rng() % 200;\n        int x1 = sorted_x[li] - marginx;\n        int x2 = sorted_x[ri] + marginx;\n        int lj = dist_y(rng);\n        int rj = dist_y(rng);\n        if (lj > rj) swap(lj, rj);\n        int marginy = sample_half_span() / 2 + rng() % 200;\n        int y1 = sorted_y[lj] - marginy;\n        int y2 = sorted_y[rj] + marginy;\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid slender_rects(int iterations) {\n    if (m_coords.empty()) return;\n    static const int widths[] = {150, 300, 600, 1000, 1600, 2500, 4000, 6000, 9000};\n    static const int SZ = sizeof(widths)/sizeof(widths[0]);\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        bool vertical = (rng() & 1);\n        const auto &center = m_coords[dist(rng)];\n        int span = widths[rng() % SZ];\n        int half = span / 2;\n        if (vertical) {\n            int x1 = center.first - half;\n            int x2 = center.first + half;\n            int height = sample_span();\n            int y_mid = rng() % (MAX_COORD + 1);\n            int y1 = y_mid - height / 2;\n            int y2 = y1 + height;\n            consider_rect(x1, x2, y1, y2);\n        } else {\n            int y1 = center.second - half;\n            int y2 = center.second + half;\n            int width = sample_span();\n            int x_mid = rng() % (MAX_COORD + 1);\n            int x1 = x_mid - width / 2;\n            int x2 = x1 + width;\n            consider_rect(x1, x2, y1, y2);\n        }\n    }\n}\n\nstatic const int BIG_PERTURB[] = {5, 15, 30, 60, 120, 250, 400, 700, 1100, 1700,\n                                  2500, 3600, 5000, 7500, 10000, 13500, 17000};\nstatic const int SMALL_PERTURB[] = {2,4,8,16,32,64,128,256,512,1024,2048,3072,4096};\nconst int BIG_PSZ = sizeof(BIG_PERTURB)/sizeof(int);\nconst int SMALL_PSZ = sizeof(SMALL_PERTURB)/sizeof(int);\n\nvoid random_perturb_rect(const RectAns &base, int iterations, const int *options, int opt_sz) {\n    if (base.sc.diff == NEG_INF) return;\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int delta = options[rng() % opt_sz];\n        int x1 = base.x1 - (int)(rng() % (delta + 1));\n        int x2 = base.x2 + (int)(rng() % (delta + 1));\n        int y1 = base.y1 - (int)(rng() % (delta + 1));\n        int y2 = base.y2 + (int)(rng() % (delta + 1));\n        int shiftx = delta ? (int)(rng() % (2 * delta + 1)) - delta : 0;\n        int shifty = delta ? (int)(rng() % (2 * delta + 1)) - delta : 0;\n        x1 += shiftx; x2 += shiftx;\n        y1 += shifty; y2 += shifty;\n        if (rng() & 1) x1 += rng() % (delta + 1);\n        if (rng() & 1) x2 -= rng() % (delta + 1);\n        if (rng() & 1) y1 += rng() % (delta + 1);\n        if (rng() & 1) y2 -= rng() % (delta + 1);\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_perturb_best(int iterations) {\n    random_perturb_rect(best_rect, iterations, BIG_PERTURB, BIG_PSZ);\n}\n\nvoid random_around_top_rects(int iterations_each) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min<int>(seeds.size(), 6);\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        random_perturb_rect(seeds[i], iterations_each, SMALL_PERTURB, SMALL_PSZ);\n    }\n}\n\nstatic const int LOCAL_STEPS[] = {1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946};\nconst int LOCAL_SZ = sizeof(LOCAL_STEPS)/sizeof(int);\n\nvoid local_search_from(const RectAns &seed, int iterations) {\n    if (seed.sc.diff == NEG_INF) return;\n    RectAns current = seed;\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int step = LOCAL_STEPS[rng() % LOCAL_SZ];\n        int op = rng() % 12;\n        int x1 = current.x1;\n        int x2 = current.x2;\n        int y1 = current.y1;\n        int y2 = current.y2;\n        switch (op) {\n            case 0: x1 -= step; break;\n            case 1: x1 += step; break;\n            case 2: x2 += step; break;\n            case 3: x2 -= step; break;\n            case 4: y1 -= step; break;\n            case 5: y1 += step; break;\n            case 6: y2 += step; break;\n            case 7: y2 -= step; break;\n            case 8: { int shift = (int)(rng() % (2 * step + 1)) - step; x1 += shift; x2 += shift; break; }\n            case 9: { int shift = (int)(rng() % (2 * step + 1)) - step; y1 += shift; y2 += shift; break; }\n            case 10: x1 -= step; x2 += step; break;\n            case 11: y1 -= step; y2 += step; break;\n        }\n        if (!normalize_rect(x1,x2,y1,y2)) continue;\n        Score sc = compute_score(x1,x2,y1,y2);\n        push_candidate(x1,x2,y1,y2,sc);\n        RectAns cand{x1,x2,y1,y2,sc};\n        if (better_rect(cand, current)) current = cand;\n        if ((it & 63) == 63 && better_rect(best_rect, current)) current = best_rect;\n    }\n}\n\nvoid run_local_search_pool(int iterations_per_seed) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min<int>(seeds.size(), 4);\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        local_search_from(seeds[i], iterations_per_seed);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    start_time = chrono::steady_clock::now();\n\n    cin >> N;\n    xs.reserve(2 * N);\n    ys.reserve(2 * N);\n    types.reserve(2 * N);\n    m_coords.reserve(N);\n\n    for (int i = 0; i < N; ++i) {\n        int x,y; cin >> x >> y;\n        xs.push_back(x); ys.push_back(y); types.push_back(1);\n        m_coords.emplace_back(x,y);\n    }\n    for (int i = 0; i < N; ++i) {\n        int x,y; cin >> x >> y;\n        xs.push_back(x); ys.push_back(y); types.push_back(-1);\n    }\n\n    vector<int> sorted_x = xs;\n    vector<int> sorted_y = ys;\n    sort(sorted_x.begin(), sorted_x.end());\n    sort(sorted_y.begin(), sorted_y.end());\n    unique_x_vals = sorted_x;\n    unique_y_vals = sorted_y;\n    unique_x_vals.erase(unique(unique_x_vals.begin(), unique_x_vals.end()), unique_x_vals.end());\n    unique_y_vals.erase(unique(unique_y_vals.begin(), unique_y_vals.end()), unique_y_vals.end());\n\n    bit2d.build(xs, ys, types);\n    best_rect.sc.diff = NEG_INF;\n    top_rects.clear();\n\n    consider_rect(0, MAX_COORD, 0, MAX_COORD);\n    int half = MAX_COORD / 2;\n    consider_rect(0, half, 0, half);\n    consider_rect(half, MAX_COORD, 0, half);\n    consider_rect(0, half, half, MAX_COORD);\n    consider_rect(half, MAX_COORD, half, MAX_COORD);\n    consider_rect(MAX_COORD/4, 3*MAX_COORD/4, MAX_COORD/4, 3*MAX_COORD/4);\n\n    vector<int> segments = {12, 18, 26, 35, 48, 64, 85, 110, 140};\n    for (int seg : segments) {\n        if (elapsed() > TIME_LIMIT) break;\n        grid_search(seg, sorted_x, sorted_y);\n    }\n\n    random_centered(2200);\n    random_pair_rects(1800);\n    random_cluster_rects(1200);\n    random_global(1500);\n    quantile_rects(1400, sorted_x, sorted_y);\n    slender_rects(1000);\n    random_centered(600);\n    random_perturb_best(2000);\n    random_around_top_rects(400);\n    run_local_search_pool(360);\n    refine_top_rects(6, 11);\n    random_around_top_rects(250);\n    random_perturb_best(800);\n    run_local_search_pool(240);\n    refine_top_rects(4, 9);\n\n    if (best_rect.sc.diff == NEG_INF) {\n        consider_rect(0, MAX_COORD, 0, MAX_COORD);\n    }\n\n    cout << 4 << '\\n';\n    cout << best_rect.x1 << ' ' << best_rect.y1 << '\\n';\n    cout << best_rect.x2 << ' ' << best_rect.y1 << '\\n';\n    cout << best_rect.x2 << ' ' << best_rect.y2 << '\\n';\n    cout << best_rect.x1 << ' ' << best_rect.y2 << '\\n';\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst long long INFLL = (long long)4e18;\n\nstruct Profile {\n    vector<long long> widths;\n    vector<long long> heights;  // non-increasing after preprocessing\n};\n\nstruct Solution {\n    vector<int> orientation;\n    vector<int> column_id;\n    vector<long long> column_widths;\n    vector<long long> column_heights;\n    vector<int> anchor;\n    vector<int> idx_max_width;\n    vector<pair<int,int>> ranges;\n    long long total_width = 0;\n    long long total_height = 0;\n    long long score = INFLL;\n    long long H_used = -1;\n};\n\nuint64_t hash_solution(const Solution &sol) {\n    uint64_t h = 1469598103934665603ULL;\n    for (size_t i = 0; i < sol.orientation.size(); ++i) {\n        uint64_t val = (uint64_t)(sol.orientation[i] & 1);\n        uint64_t cid = (uint64_t)(sol.column_id[i] & 0xFFFF);\n        val |= (cid << 1);\n        h ^= val;\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nstruct ColumnPackingSolver {\n    int N = 0;\n    vector<long long> w, h;\n    vector<array<long long,2>> widthOpt, heightOpt;\n    vector<long long> minHeight, maxHeight;\n    vector<vector<Profile>> profiles;\n    long long H_lower = 0;\n    long long H_upper = 0;\n    long long total_min_height = 0;\n\n    void init(const vector<long long>& W, const vector<long long>& H) {\n        w = W; h = H;\n        N = (int)w.size();\n        widthOpt.assign(N, {0,0});\n        heightOpt.assign(N, {0,0});\n        minHeight.resize(N);\n        maxHeight.resize(N);\n        total_min_height = 0;\n        H_lower = 0;\n        H_upper = 0;\n        for (int i = 0; i < N; ++i) {\n            widthOpt[i][0] = w[i];\n            heightOpt[i][0] = h[i];\n            widthOpt[i][1] = h[i];\n            heightOpt[i][1] = w[i];\n            minHeight[i] = min(heightOpt[i][0], heightOpt[i][1]);\n            maxHeight[i] = max(heightOpt[i][0], heightOpt[i][1]);\n            total_min_height += minHeight[i];\n            H_lower = max(H_lower, minHeight[i]);\n            H_upper += maxHeight[i];\n        }\n        if (H_upper < H_lower) H_upper = H_lower;\n        buildProfiles();\n    }\n\n    long long lower() const { return H_lower; }\n    long long upper() const { return H_upper; }\n    long long minHeightSum() const { return total_min_height; }\n\n    void buildProfiles() {\n        profiles.assign(N, vector<Profile>(N + 1));\n        for (int l = 0; l < N; ++l) {\n            for (int r = l + 1; r <= N; ++r) {\n                vector<long long> widths;\n                widths.reserve(2 * (r - l));\n                for (int k = l; k < r; ++k) {\n                    widths.push_back(widthOpt[k][0]);\n                    widths.push_back(widthOpt[k][1]);\n                }\n                sort(widths.begin(), widths.end());\n                widths.erase(unique(widths.begin(), widths.end()), widths.end());\n                vector<long long> heights(widths.size(), INFLL);\n                for (size_t idx = 0; idx < widths.size(); ++idx) {\n                    long long limit = widths[idx];\n                    long long sumH = 0;\n                    bool ok = true;\n                    for (int k = l; k < r; ++k) {\n                        long long best = INFLL;\n                        if (widthOpt[k][0] <= limit) best = min(best, heightOpt[k][0]);\n                        if (widthOpt[k][1] <= limit) best = min(best, heightOpt[k][1]);\n                        if (best >= INFLL/2) { ok = false; break; }\n                        sumH += best;\n                    }\n                    if (ok) heights[idx] = sumH;\n                }\n                long long last = INFLL;\n                for (size_t idx = 0; idx < heights.size(); ++idx) {\n                    if (heights[idx] < last) last = heights[idx];\n                    else heights[idx] = last;\n                }\n                profiles[l][r] = Profile{move(widths), move(heights)};\n            }\n        }\n    }\n\n    vector<long long> generate_candidate_heights(mt19937 &rng, int limit) const {\n        limit = max(limit, 2);\n        vector<long long> cand;\n        cand.reserve(limit * 2 + 100);\n        auto clampH = [&](long long v) {\n            if (v < H_lower) v = H_lower;\n            if (v > H_upper) v = H_upper;\n            return v;\n        };\n        auto add = [&](long long v) {\n            cand.push_back(clampH(v));\n        };\n\n        add(H_lower);\n        add(H_upper);\n        vector<double> fudge = {0.65, 0.75, 0.85, 0.95, 1.0, 1.05, 1.15, 1.3, 1.5};\n        int maxCols = min(N, 60);\n        for (int c = 1; c <= maxCols; ++c) {\n            double base = (double)total_min_height / max(1, c);\n            for (double f : fudge) add((long long)llround(base * f));\n        }\n        long double val = (long double)H_lower;\n        for (int i = 0; i < 100 && val <= (long double)H_upper; ++i) {\n            add((long long)llround(val));\n            val *= 1.05L;\n            if (val > (long double)H_upper * 1.01L) break;\n        }\n        if (H_upper > H_lower) {\n            int linearCnt = min(limit, 160);\n            for (int i = 0; i < linearCnt; ++i) {\n                long double ratio = (long double)i / max(1, linearCnt - 1);\n                add((long long)llround(H_lower + ratio * (H_upper - H_lower)));\n            }\n        }\n        add(total_min_height);\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n        if ((int)cand.size() > limit) {\n            vector<long long> reduced;\n            reduced.reserve(limit);\n            for (int i = 0; i < limit; ++i) {\n                size_t idx = (size_t)llround((long double)i * (cand.size() - 1) / max(1, limit - 1));\n                reduced.push_back(cand[idx]);\n            }\n            sort(reduced.begin(), reduced.end());\n            reduced.erase(unique(reduced.begin(), reduced.end()), reduced.end());\n            cand.swap(reduced);\n        }\n        if (cand.empty()) cand.push_back(H_lower);\n        return cand;\n    }\n\n    long long get_min_width(const Profile &prof, long long Hmax) const {\n        const auto &hv = prof.heights;\n        int l = 0, r = (int)hv.size();\n        while (l < r) {\n            int m = (l + r) / 2;\n            if (hv[m] <= Hmax) r = m;\n            else l = m + 1;\n        }\n        if (l >= (int)hv.size()) return INFLL;\n        return prof.widths[l];\n    }\n\n    int choose_orientation(int idx, long long width_limit) const {\n        int best = -1;\n        long long best_h = INFLL;\n        long long best_w = INFLL;\n        for (int o = 0; o < 2; ++o) {\n            if (widthOpt[idx][o] <= width_limit) {\n                long long hval = heightOpt[idx][o];\n                long long wval = widthOpt[idx][o];\n                if (best == -1 || hval < best_h || (hval == best_h && wval < best_w)) {\n                    best = o;\n                    best_h = hval;\n                    best_w = wval;\n                }\n            }\n        }\n        if (best == -1) {\n            best = (heightOpt[idx][0] <= heightOpt[idx][1]) ? 0 : 1;\n        }\n        return best;\n    }\n\n    bool build_solution(long long Hmax, Solution &sol, mt19937 &rng) const {\n        vector<long long> dp(N + 1, INFLL);\n        vector<int> prv(N + 1, -1);\n        vector<long long> width_choice(N + 1, -1);\n        vector<uint32_t> jitter(N + 1);\n        vector<uint32_t> best_jitter(N + 1, UINT_MAX);\n        for (int i = 0; i <= N; ++i) jitter[i] = rng();\n        dp[0] = 0;\n        best_jitter[0] = jitter[0];\n\n        for (int i = 1; i <= N; ++i) {\n            for (int j = 0; j < i; ++j) {\n                if (dp[j] >= INFLL/2) continue;\n                const Profile &prof = profiles[j][i];\n                long long width = get_min_width(prof, Hmax);\n                if (width >= INFLL/2) continue;\n                long long cand = dp[j] + width;\n                if (cand < dp[i] || (cand == dp[i] && jitter[j] < best_jitter[i])) {\n                    dp[i] = cand;\n                    prv[i] = j;\n                    width_choice[i] = width;\n                    best_jitter[i] = jitter[j];\n                }\n            }\n        }\n        if (dp[N] >= INFLL/2) return false;\n\n        vector<int> cuts;\n        int cur = N;\n        while (cur > 0) {\n            cuts.push_back(cur);\n            cur = prv[cur];\n            if (cur < 0) return false;\n        }\n        cuts.push_back(0);\n        reverse(cuts.begin(), cuts.end());\n        int cols = (int)cuts.size() - 1;\n\n        vector<int> orientation(N);\n        vector<int> column_id(N);\n        vector<long long> column_width(cols, 0);\n        vector<long long> column_height(cols, 0);\n        vector<int> idx_max(cols, -1);\n        vector<pair<int,int>> ranges(cols);\n\n        for (int c = 0; c < cols; ++c) {\n            int l = cuts[c];\n            int r = cuts[c + 1];\n            ranges[c] = {l, r};\n            long long width_limit = width_choice[r];\n            long long sumH = 0;\n            long long maxW = 0;\n            int idxRect = l;\n            for (int k = l; k < r; ++k) {\n                int orient = choose_orientation(k, width_limit);\n                orientation[k] = orient;\n                column_id[k] = c;\n                long long wval = widthOpt[k][orient];\n                long long hval = heightOpt[k][orient];\n                sumH += hval;\n                if (wval > maxW || (wval == maxW && k < idxRect)) {\n                    maxW = wval;\n                    idxRect = k;\n                }\n            }\n            column_width[c] = max(maxW, width_limit);\n            column_height[c] = sumH;\n            idx_max[c] = idxRect;\n        }\n\n        vector<int> anchor(cols);\n        for (int c = 0; c < cols; ++c) anchor[c] = (c == 0) ? -1 : idx_max[c - 1];\n\n        long long total_w = 0;\n        long long total_h = 0;\n        for (auto wcol : column_width) total_w += wcol;\n        for (auto hcol : column_height) total_h = max(total_h, hcol);\n\n        sol.orientation = move(orientation);\n        sol.column_id = move(column_id);\n        sol.column_widths = move(column_width);\n        sol.column_heights = move(column_height);\n        sol.anchor = move(anchor);\n        sol.idx_max_width = move(idx_max);\n        sol.ranges = move(ranges);\n        sol.total_width = total_w;\n        sol.total_height = total_h;\n        sol.score = total_w + total_h;\n        sol.H_used = Hmax;\n        return true;\n    }\n\n    Solution build_row_solution() const {\n        Solution sol;\n        sol.orientation.assign(N, 0);\n        sol.column_id.assign(N, 0);\n        sol.column_widths.assign(N, 0);\n        sol.column_heights.assign(N, 0);\n        sol.idx_max_width.resize(N);\n        sol.anchor.assign(N, -1);\n        sol.ranges.resize(N);\n        for (int i = 0; i < N; ++i) {\n            int best = 0;\n            if (widthOpt[i][1] < widthOpt[i][0]) best = 1;\n            else if (widthOpt[i][1] == widthOpt[i][0] && heightOpt[i][1] < heightOpt[i][0]) best = 1;\n            sol.orientation[i] = best;\n            sol.column_id[i] = i;\n            sol.column_widths[i] = widthOpt[i][best];\n            sol.column_heights[i] = heightOpt[i][best];\n            sol.idx_max_width[i] = i;\n            sol.ranges[i] = {i, i + 1};\n            sol.anchor[i] = (i == 0) ? -1 : i - 1;\n        }\n        long long total_w = accumulate(sol.column_widths.begin(), sol.column_widths.end(), 0LL);\n        long long total_h = 0;\n        for (auto hcol : sol.column_heights) total_h = max(total_h, hcol);\n        sol.total_width = total_w;\n        sol.total_height = total_h;\n        sol.score = total_w + total_h;\n        sol.H_used = -1;\n        return sol;\n    }\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_obs(N), h_obs(N);\n    for (int i = 0; i < N; ++i) cin >> w_obs[i] >> h_obs[i];\n\n    uint64_t seed = 1469598103934665603ULL;\n    auto mix = [&](uint64_t x) {\n        seed ^= x + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(N);\n    mix(T);\n    mix((uint64_t)sigma);\n    for (int i = 0; i < N; ++i) {\n        mix((uint64_t)w_obs[i]);\n        mix((uint64_t)h_obs[i] + 0x9e3779b97f4a7c15ULL);\n    }\n    mt19937 rng(seed);\n\n    ColumnPackingSolver solver;\n    solver.init(w_obs, h_obs);\n\n    int desired_pool = min(max(2 * T, 150), 1600);\n    vector<long long> heights = solver.generate_candidate_heights(rng, max(desired_pool, 400));\n    long long lower = solver.lower();\n    long long upper = solver.upper();\n    if (lower == upper) {\n        for (int i = 0; i < desired_pool; ++i) heights.push_back(lower);\n    } else {\n        uniform_int_distribution<long long> dist(lower, upper);\n        for (int i = 0; i < desired_pool; ++i) heights.push_back(dist(rng));\n    }\n    heights.push_back((lower + upper) / 2);\n    heights.push_back(solver.minHeightSum());\n    sort(heights.begin(), heights.end());\n    heights.erase(unique(heights.begin(), heights.end()), heights.end());\n\n    vector<Solution> pool;\n    pool.reserve(desired_pool + 5);\n    unordered_set<uint64_t> seen;\n    seen.reserve(desired_pool * 2 + 20);\n\n    auto try_add = [&](long long H) {\n        Solution sol;\n        if (!solver.build_solution(H, sol, rng)) return;\n        uint64_t h = hash_solution(sol);\n        if (seen.insert(h).second) {\n            pool.push_back(move(sol));\n        }\n    };\n\n    for (long long H : heights) {\n        try_add(H);\n        if ((int)pool.size() >= desired_pool) break;\n    }\n    if ((int)pool.size() < desired_pool) {\n        uniform_int_distribution<long long> dist(lower, upper);\n        int attempts = 0;\n        int max_attempts = desired_pool * 4 + 50;\n        while ((int)pool.size() < desired_pool && attempts < max_attempts) {\n            long long val = (lower == upper) ? lower : dist(rng);\n            try_add(val);\n            ++attempts;\n        }\n    }\n\n    Solution fallback = solver.build_row_solution();\n    uint64_t hf = hash_solution(fallback);\n    if (seen.insert(hf).second) pool.push_back(fallback);\n    if (pool.empty()) pool.push_back(fallback);\n\n    sort(pool.begin(), pool.end(), [](const Solution &a, const Solution &b) {\n        if (a.score != b.score) return a.score < b.score;\n        if (a.total_width != b.total_width) return a.total_width < b.total_width;\n        if (a.total_height != b.total_height) return a.total_height < b.total_height;\n        return a.column_widths.size() < b.column_widths.size();\n    });\n\n    int unique_available = (int)pool.size();\n    int unique_needed = min(unique_available, T);\n    vector<int> order;\n    order.reserve(unique_needed);\n    if (unique_needed == 0) {\n        order.push_back(0);\n        unique_needed = 1;\n    } else {\n        int random_share = unique_needed / 3;\n        int keep_best = unique_needed - random_share;\n        if (keep_best < 1) keep_best = 1;\n        for (int i = 0; i < keep_best && i < unique_available; ++i) order.push_back(i);\n        vector<int> rest;\n        for (int i = keep_best; i < unique_available; ++i) rest.push_back(i);\n        shuffle(rest.begin(), rest.end(), rng);\n        for (int idx : rest) {\n            if ((int)order.size() >= unique_needed) break;\n            order.push_back(idx);\n        }\n        while ((int)order.size() < unique_needed) order.push_back(order.back());\n        auto it = find(order.begin(), order.end(), 0);\n        if (it != order.end()) swap(order[0], *it);\n        if (order.size() > 1) {\n            vector<int> tail(order.begin() + 1, order.end());\n            shuffle(tail.begin(), tail.end(), rng);\n            for (size_t i = 1; i < order.size(); ++i) order[i] = tail[i - 1];\n        }\n    }\n\n    vector<int> plan_idx(T, 0);\n    for (int t = 0; t < T; ++t) {\n        if (t < (int)order.size()) plan_idx[t] = order[t];\n        else plan_idx[t] = order.empty() ? 0 : order[t % order.size()];\n    }\n\n    for (int t = 0; t < T; ++t) {\n        const Solution &sol = pool[plan_idx[t]];\n        cout << N << '\\n';\n        for (int i = 0; i < N; ++i) {\n            int col = sol.column_id[i];\n            int b = sol.anchor[col];\n            cout << i << ' ' << sol.orientation[i] << ' ' << 'U' << ' ' << b << '\\n';\n        }\n        cout.flush();\n        long long Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n    }\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct BuildParams {\n    double rootBeautyWeight;\n    double rootCenterWeight;\n    double rootRandomWeight;\n    int candidateMode;\n    int shallowThreshold;\n    long long depthWeight;\n    long long shallowBonus;\n    long long deepBonus;\n    long long beautyWeight;\n    int candidateRandomRange;\n};\n\nstruct Solution {\n    vector<int> parent;\n    vector<int> depth;\n    long long score;\n    Solution() : score(-(1LL << 60)) {}\n};\n\nlong long compute_score(const vector<int>& depth, const vector<int>& A) {\n    long long sum = 0;\n    for (size_t i = 0; i < depth.size(); ++i) {\n        sum += 1LL * (depth[i] + 1) * A[i];\n    }\n    return sum;\n}\n\ndouble randDouble(mt19937& rng, double low, double high) {\n    uniform_real_distribution<double> dist(low, high);\n    return dist(rng);\n}\n\nint randInt(mt19937& rng, int low, int high) {\n    uniform_int_distribution<int> dist(low, high);\n    return dist(rng);\n}\n\nBuildParams random_params(mt19937& rng, int H) {\n    BuildParams p;\n    p.rootBeautyWeight = randDouble(rng, 0.25, 1.35);\n    p.rootCenterWeight = randDouble(rng, -0.05, 0.12);\n    p.rootRandomWeight = randDouble(rng, 0.0, 4.0);\n    p.candidateMode = rng() % 2;\n\n    if (p.candidateMode == 0) {\n        int lowThr = max(1, H / 4);\n        int highThr = max(lowThr, H - 2);\n        p.shallowThreshold = randInt(rng, lowThr, highThr);\n        p.depthWeight = randInt(rng, 9000, 17000);\n        p.shallowBonus = randInt(rng, 2500, 6000);\n        p.deepBonus = randInt(rng, 100, 700);\n        p.beautyWeight = 0;\n    } else {\n        p.shallowThreshold = 0;\n        p.depthWeight = randInt(rng, 5000, 11000);\n        p.shallowBonus = 0;\n        p.deepBonus = 0;\n        p.beautyWeight = randInt(rng, 300, 450);\n    }\n    p.candidateRandomRange = randInt(rng, 30, 200);\n    return p;\n}\n\nvector<int> select_roots(const vector<vector<int>>& adj,\n                         const vector<int>& A,\n                         const vector<double>& distCenter,\n                         int H,\n                         const BuildParams& params,\n                         mt19937& rng) {\n    const int N = adj.size();\n    const int INF = 1e9;\n    vector<int> minDist(N, INF);\n    vector<double> tieValue(N, 0.0);\n    uniform_real_distribution<double> rand01(0.0, 1.0);\n\n    for (int v = 0; v < N; ++v) {\n        double rnd = (params.rootRandomWeight > 0.0) ? rand01(rng) : 0.0;\n        tieValue[v] = params.rootBeautyWeight * A[v]\n                    + params.rootCenterWeight * distCenter[v]\n                    + params.rootRandomWeight * rnd;\n    }\n\n    vector<int> dist_local(N, INF);\n    vector<int> touched;\n    touched.reserve(N);\n    vector<int> roots;\n\n    auto add_root = [&](int start) {\n        queue<int> q;\n        touched.clear();\n        dist_local[start] = 0;\n        touched.push_back(start);\n        q.push(start);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int d = dist_local[v];\n            if (d < minDist[v]) minDist[v] = d;\n            if (d == H) continue;\n            for (int nb : adj[v]) {\n                if (dist_local[nb] != INF) continue;\n                int nd = d + 1;\n                if (nd > H) continue;\n                dist_local[nb] = nd;\n                touched.push_back(nb);\n                q.push(nb);\n            }\n        }\n        for (int v : touched) dist_local[v] = INF;\n    };\n\n    while (true) {\n        int best = -1;\n        for (int v = 0; v < N; ++v) {\n            if (minDist[v] > H) {\n                if (best == -1 || minDist[v] > minDist[best] ||\n                    (minDist[v] == minDist[best] && tieValue[v] < tieValue[best])) {\n                    best = v;\n                }\n            }\n        }\n        if (best == -1) break;\n        add_root(best);\n        roots.push_back(best);\n    }\n    if (roots.empty()) {\n        int best = min_element(A.begin(), A.end()) - A.begin();\n        add_root(best);\n        roots.push_back(best);\n    }\n    return roots;\n}\n\nSolution build_solution(const vector<vector<int>>& adj,\n                        const vector<int>& A,\n                        const vector<double>& distCenter,\n                        int H,\n                        const BuildParams& params,\n                        mt19937& rng) {\n    const int N = adj.size();\n    Solution sol;\n    sol.parent.assign(N, -1);\n    sol.depth.assign(N, -1);\n\n    vector<int> roots = select_roots(adj, A, distCenter, H, params, rng);\n\n    vector<char> assigned(N, 0);\n    vector<int> bestDepth(N, -1);\n    vector<int> bestParent(N, -1);\n    vector<long long> bestKey(N, numeric_limits<long long>::min());\n\n    struct Candidate {\n        long long key;\n        int depth;\n        int node;\n        bool operator<(const Candidate& other) const {\n            if (key != other.key) return key < other.key;\n            if (depth != other.depth) return depth < other.depth;\n            return node > other.node;\n        }\n    };\n    priority_queue<Candidate> pq;\n\n    auto randContribution = [&](int range) -> long long {\n        if (range <= 0) return 0LL;\n        return static_cast<long long>(rng() % range);\n    };\n\n    int threshold = params.shallowThreshold;\n    threshold = max(0, min(threshold, H));\n\n    auto computeKey = [&](int v, int depth) -> long long {\n        long long key = 1LL * depth * params.depthWeight;\n        if (params.candidateMode == 0) {\n            if (depth <= threshold) key += params.shallowBonus - A[v];\n            else key += params.deepBonus + A[v];\n        } else {\n            key += 1LL * A[v] * params.beautyWeight;\n        }\n        key += randContribution(params.candidateRandomRange);\n        return key;\n    };\n\n    auto pushCandidate = [&](int child, int par) {\n        if (assigned[child]) return;\n        int parentDepth = sol.depth[par];\n        if (parentDepth < 0) return;\n        int newDepth = parentDepth + 1;\n        if (newDepth > H) return;\n        long long key = computeKey(child, newDepth);\n        if (newDepth > bestDepth[child] || (newDepth == bestDepth[child] && key > bestKey[child])) {\n            bestDepth[child] = newDepth;\n            bestParent[child] = par;\n            bestKey[child] = key;\n            pq.push({key, newDepth, child});\n        }\n    };\n\n    int assignedCount = 0;\n    for (int r : roots) {\n        if (!assigned[r]) {\n            assigned[r] = 1;\n            sol.depth[r] = 0;\n            sol.parent[r] = -1;\n            assignedCount++;\n        }\n    }\n    if (assignedCount == 0) {\n        int best = min_element(A.begin(), A.end()) - A.begin();\n        assigned[best] = 1;\n        sol.depth[best] = 0;\n        sol.parent[best] = -1;\n        assignedCount = 1;\n        roots.push_back(best);\n    }\n    for (int r : roots) {\n        for (int nb : adj[r]) if (!assigned[nb]) pushCandidate(nb, r);\n    }\n\n    while (assignedCount < N) {\n        if (pq.empty()) {\n            int choice = -1;\n            int bestBeauty = INT_MAX;\n            for (int v = 0; v < N; ++v) {\n                if (!assigned[v] && A[v] < bestBeauty) {\n                    bestBeauty = A[v];\n                    choice = v;\n                }\n            }\n            if (choice == -1) break;\n            assigned[choice] = 1;\n            sol.depth[choice] = 0;\n            sol.parent[choice] = -1;\n            assignedCount++;\n            for (int nb : adj[choice]) if (!assigned[nb]) pushCandidate(nb, choice);\n            continue;\n        }\n        Candidate cur = pq.top(); pq.pop();\n        int v = cur.node;\n        if (assigned[v]) continue;\n        if (cur.depth != bestDepth[v]) continue;\n        if (cur.key != bestKey[v]) continue;\n        int par = bestParent[v];\n        if (par == -1) {\n            assigned[v] = 1;\n            sol.depth[v] = 0;\n            sol.parent[v] = -1;\n        } else {\n            assigned[v] = 1;\n            sol.depth[v] = cur.depth;\n            sol.parent[v] = par;\n        }\n        assignedCount++;\n        for (int nb : adj[v]) if (!assigned[nb]) pushCandidate(nb, v);\n    }\n\n    for (int v = 0; v < N; ++v) {\n        if (sol.depth[v] < 0) {\n            sol.depth[v] = 0;\n            sol.parent[v] = -1;\n        }\n    }\n    sol.score = compute_score(sol.depth, A);\n    return sol;\n}\n\nvoid improve_leaves(const vector<vector<int>>& adj,\n                    const vector<int>& A,\n                    int H,\n                    const vector<int>& beautyOrder,\n                    Solution& sol,\n                    int maxIterations = 8) {\n    const int N = adj.size();\n    vector<int> childCnt(N, 0);\n    for (int v = 0; v < N; ++v) {\n        int p = sol.parent[v];\n        if (p >= 0) childCnt[p]++;\n    }\n\n    for (int iter = 0; iter < maxIterations; ++iter) {\n        bool changed = false;\n        for (int v : beautyOrder) {\n            if (childCnt[v] != 0) continue;\n            int curDepth = sol.depth[v];\n            int bestParent = -1;\n            int bestDepth = curDepth;\n            for (int nb : adj[v]) {\n                int parentDepth = sol.depth[nb];\n                if (parentDepth < 0) continue;\n                int newDepth = parentDepth + 1;\n                if (newDepth > H) continue;\n                if (newDepth > bestDepth) {\n                    bestDepth = newDepth;\n                    bestParent = nb;\n                } else if (newDepth == bestDepth && bestParent >= 0 && A[nb] > A[bestParent]) {\n                    bestParent = nb;\n                }\n            }\n            if (bestParent >= 0 && bestDepth > curDepth) {\n                int oldParent = sol.parent[v];\n                if (oldParent >= 0) childCnt[oldParent]--;\n                sol.parent[v] = bestParent;\n                sol.depth[v] = bestDepth;\n                childCnt[bestParent]++;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n    sol.score = compute_score(sol.depth, A);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    cin >> N >> M >> H;\n    vector<int> A(N);\n    for (int i = 0; i < N; ++i) cin >> A[i];\n\n    vector<vector<int>> adj(N);\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; ++i) cin >> xs[i] >> ys[i];\n\n    double cx = 0.0, cy = 0.0;\n    for (int i = 0; i < N; ++i) {\n        cx += xs[i];\n        cy += ys[i];\n    }\n    cx /= N;\n    cy /= N;\n\n    vector<double> distCenter(N, 0.0);\n    for (int i = 0; i < N; ++i) {\n        double dx = xs[i] - cx;\n        double dy = ys[i] - cy;\n        distCenter[i] = sqrt(dx * dx + dy * dy);\n    }\n\n    vector<int> beautyOrder(N);\n    iota(beautyOrder.begin(), beautyOrder.end(), 0);\n    sort(beautyOrder.begin(), beautyOrder.end(), [&](int lhs, int rhs) {\n        if (A[lhs] != A[rhs]) return A[lhs] > A[rhs];\n        return lhs < rhs;\n    });\n\n    vector<BuildParams> baseParams = {\n        {1.00,  0.02, 0.80, 0, 4, 15000, 4500, 350,   0,  80},\n        {0.80,  0.08, 2.50, 0, 5, 12000, 4200, 600,   0, 110},\n        {1.20, -0.02, 0.40, 0, 3, 17000, 5200, 250,   0,  70},\n        {0.60,  0.10, 3.00, 1, 0,  7000,    0,   0, 360, 120},\n        {0.45, -0.03, 4.40, 1, 0,  6200,    0,   0, 420, 150},\n        {0.95,  0.05, 1.50, 0, 2, 14000, 3600, 500,   0,  60}\n    };\n\n    mt19937 rng(123456789);\n    auto start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.80;\n\n    Solution best;\n    bool hasBest = false;\n\n    auto runAttempt = [&](const BuildParams& params) {\n        Solution sol = build_solution(adj, A, distCenter, H, params, rng);\n        improve_leaves(adj, A, H, beautyOrder, sol);\n        if (!hasBest || sol.score > best.score) {\n            best = sol;\n            hasBest = true;\n        }\n    };\n\n    for (const auto& params : baseParams) {\n        runAttempt(params);\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        if (elapsed > TIME_LIMIT) break;\n    }\n\n    while (chrono::duration<double>(chrono::steady_clock::now() - start).count() < TIME_LIMIT) {\n        BuildParams params = random_params(rng, H);\n        runAttempt(params);\n    }\n\n    if (!hasBest) {\n        BuildParams fallback = baseParams.front();\n        Solution sol = build_solution(adj, A, distCenter, H, fallback, rng);\n        improve_leaves(adj, A, H, beautyOrder, sol);\n        best = sol;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << best.parent[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Candidate {\n    char dir;\n    int idx;\n    int shifts;\n    int removal;\n};\n\nstruct CandidateData {\n    char dir;\n    int idx;\n    int shifts;\n    int removal;\n    double value;\n    int cost;\n    double ratio;\n};\n\nstruct PlanResult {\n    vector<Candidate> seq;\n    int cost = 0;\n    bool success = false;\n};\n\nint N;\nint LIMIT_OPS;\nvector<int> rowFirstO, rowLastO, colFirstO, colLastO;\nvector<vector<double>> cellWeight;\nconst double EPS = 1e-9;\n\nint countOni(const vector<string>& board) {\n    int cnt = 0;\n    for (const auto& row : board) {\n        for (char c : row) if (c == 'x') ++cnt;\n    }\n    return cnt;\n}\n\nchar oppositeDir(char dir) {\n    if (dir == 'U') return 'D';\n    if (dir == 'D') return 'U';\n    if (dir == 'L') return 'R';\n    return 'L';\n}\n\nint removeCells(vector<string>& board, const Candidate& cand) {\n    int removed = 0;\n    int n = board.size();\n    if (cand.dir == 'U') {\n        int limit = min(cand.shifts, n);\n        for (int r = 0; r < limit; ++r) {\n            char& cell = board[r][cand.idx];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'D') {\n        int limit = min(cand.shifts, n);\n        int start = n - limit;\n        for (int r = start; r < n; ++r) {\n            char& cell = board[r][cand.idx];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'L') {\n        int limit = min(cand.shifts, n);\n        for (int c = 0; c < limit; ++c) {\n            char& cell = board[cand.idx][c];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'R') {\n        int limit = min(cand.shifts, n);\n        int start = n - limit;\n        for (int c = start; c < n; ++c) {\n            char& cell = board[cand.idx][c];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    }\n    return removed;\n}\n\nvoid precomputeEdgeInfo(const vector<string>& board) {\n    rowFirstO.assign(N, N);\n    rowLastO.assign(N, -1);\n    colFirstO.assign(N, N);\n    colLastO.assign(N, -1);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (board[i][j] == 'o') {\n                rowFirstO[i] = min(rowFirstO[i], j);\n                rowLastO[i] = max(rowLastO[i], j);\n                colFirstO[j] = min(colFirstO[j], i);\n                colLastO[j] = max(colLastO[j], i);\n            }\n        }\n    }\n}\n\nvector<vector<double>> buildCellWeights(const vector<string>& initial) {\n    vector<vector<double>> weight(N, vector<double>(N, 0.0));\n    const double BASE = 1.0;\n    const double DEG_COEF = 0.65;\n    const double DIST_COEF = 0.03;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (initial[i][j] != 'x') continue;\n            int deg = 0;\n            int minShift = INT_MAX;\n            if (colFirstO[j] >= i) {\n                ++deg;\n                minShift = min(minShift, i + 1);\n            }\n            if (colLastO[j] <= i) {\n                ++deg;\n                minShift = min(minShift, N - i);\n            }\n            if (rowFirstO[i] >= j) {\n                ++deg;\n                minShift = min(minShift, j + 1);\n            }\n            if (rowLastO[i] <= j) {\n                ++deg;\n                minShift = min(minShift, N - j);\n            }\n            if (deg == 0) deg = 1;\n            if (minShift == INT_MAX) {\n                int fallback = std::min({i + 1, N - i, j + 1, N - j});\n                minShift = fallback;\n            }\n            double w = BASE + DEG_COEF / deg + DIST_COEF * minShift;\n            weight[i][j] = w;\n        }\n    }\n    return weight;\n}\n\nPlanResult greedyPlanFrom(const vector<string>& startBoard, mt19937& rng,\n                          double tolerance, int costLimit, bool deterministic = false) {\n    PlanResult result;\n    if (costLimit < 0) return result;\n    vector<string> board = startBoard;\n    int remainingOni = countOni(board);\n    if (remainingOni == 0) {\n        result.success = true;\n        return result;\n    }\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    while (remainingOni > 0) {\n        int budget = costLimit - result.cost;\n        if (budget <= 0) return PlanResult();\n\n        vector<CandidateData> candidates;\n        candidates.reserve(4 * N);\n\n        auto addCandidate = [&](char dir, int idx, int shifts, int removal, double value) {\n            if (shifts <= 0 || removal <= 0) return;\n            if (value <= EPS) value = removal;\n            int cost = shifts * 2;\n            if (cost > budget) return;\n            CandidateData cand{dir, idx, shifts, removal, value, cost, cost / value};\n            candidates.push_back(cand);\n        };\n\n        for (int j = 0; j < N; ++j) {\n            int limit = min(colFirstO[j], N);\n            int removal = 0;\n            double value = 0.0;\n            int deepest = -1;\n            for (int r = 0; r < limit; ++r) {\n                if (board[r][j] == 'x') {\n                    ++removal;\n                    value += cellWeight[r][j];\n                    deepest = r;\n                }\n            }\n            if (removal > 0) addCandidate('U', j, deepest + 1, removal, value);\n\n            int start = colLastO[j];\n            if (start < N - 1) {\n                int removal2 = 0;\n                double value2 = 0.0;\n                int topmost = N;\n                for (int r = N - 1; r > start; --r) {\n                    if (board[r][j] == 'x') {\n                        ++removal2;\n                        value2 += cellWeight[r][j];\n                        topmost = min(topmost, r);\n                    }\n                }\n                if (removal2 > 0) addCandidate('D', j, N - topmost, removal2, value2);\n            }\n        }\n\n        for (int i = 0; i < N; ++i) {\n            int limit = min(rowFirstO[i], N);\n            int removal = 0;\n            double value = 0.0;\n            int farthest = -1;\n            for (int c = 0; c < limit; ++c) {\n                if (board[i][c] == 'x') {\n                    ++removal;\n                    value += cellWeight[i][c];\n                    farthest = c;\n                }\n            }\n            if (removal > 0) addCandidate('L', i, farthest + 1, removal, value);\n\n            int start = rowLastO[i];\n            if (start < N - 1) {\n                int removal2 = 0;\n                double value2 = 0.0;\n                int leftmost = N;\n                for (int c = N - 1; c > start; --c) {\n                    if (board[i][c] == 'x') {\n                        ++removal2;\n                        value2 += cellWeight[i][c];\n                        leftmost = min(leftmost, c);\n                    }\n                }\n                if (removal2 > 0) addCandidate('R', i, N - leftmost, removal2, value2);\n            }\n        }\n\n        if (candidates.empty()) return PlanResult();\n\n        int chosenIdx = -1;\n        if (deterministic) {\n            chosenIdx = 0;\n            for (int i = 1; i < (int)candidates.size(); ++i) {\n                const auto& cur = candidates[i];\n                const auto& best = candidates[chosenIdx];\n                if (cur.ratio + EPS < best.ratio) {\n                    chosenIdx = i;\n                } else if (fabs(cur.ratio - best.ratio) <= EPS) {\n                    if (cur.cost < best.cost) chosenIdx = i;\n                    else if (cur.cost == best.cost && cur.removal > best.removal) chosenIdx = i;\n                    else if (cur.cost == best.cost && cur.removal == best.removal && cur.value > best.value + EPS) chosenIdx = i;\n                }\n            }\n        } else {\n            double minRatio = candidates.front().ratio;\n            for (const auto& cand : candidates) minRatio = min(minRatio, cand.ratio);\n            double threshold = minRatio * (1.0 + tolerance);\n            vector<int> eligible;\n            eligible.reserve(candidates.size());\n            for (int i = 0; i < (int)candidates.size(); ++i) {\n                if (candidates[i].ratio <= threshold + 1e-9) eligible.push_back(i);\n            }\n            if (eligible.empty()) {\n                int bestIdx = 0;\n                for (int i = 1; i < (int)candidates.size(); ++i)\n                    if (candidates[i].ratio + EPS < candidates[bestIdx].ratio)\n                        bestIdx = i;\n                eligible.push_back(bestIdx);\n            }\n            if (eligible.size() == 1) {\n                chosenIdx = eligible[0];\n            } else {\n                vector<double> weights;\n                weights.reserve(eligible.size());\n                double totalWeight = 0.0;\n                for (int idx : eligible) {\n                    double w = max(candidates[idx].value, 1e-9);\n                    w *= w;\n                    weights.push_back(w);\n                    totalWeight += w;\n                }\n                double pick = dist01(rng) * totalWeight;\n                double acc = 0.0;\n                for (int k = 0; k < (int)eligible.size(); ++k) {\n                    acc += weights[k];\n                    if (pick <= acc + 1e-12) {\n                        chosenIdx = eligible[k];\n                        break;\n                    }\n                }\n                if (chosenIdx == -1) chosenIdx = eligible.back();\n            }\n        }\n\n        const auto& chosen = candidates[chosenIdx];\n        Candidate op{chosen.dir, chosen.idx, chosen.shifts, chosen.removal};\n        int removed = removeCells(board, op);\n        if (removed <= 0) return PlanResult();\n        op.removal = removed;\n        result.seq.push_back(op);\n        result.cost += chosen.cost;\n        remainingOni -= removed;\n    }\n    result.success = true;\n    return result;\n}\n\nPlanResult sequentialPlan(const vector<string>& initial) {\n    vector<string> board = initial;\n    PlanResult res;\n    int total = countOni(board);\n    while (total > 0) {\n        Candidate best{};\n        int bestShift = INT_MAX;\n        bool found = false;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (board[i][j] != 'x') continue;\n                auto update = [&](char dir, int shifts, int idx) {\n                    if (shifts <= 0) return;\n                    if (shifts < bestShift) {\n                        bestShift = shifts;\n                        best = Candidate{dir, idx, shifts, 0};\n                        found = true;\n                    }\n                };\n                if (colFirstO[j] >= i) update('U', i + 1, j);\n                if (colLastO[j] <= i) update('D', N - i, j);\n                if (rowFirstO[i] >= j) update('L', j + 1, i);\n                if (rowLastO[i] <= j) update('R', N - j, i);\n            }\n        }\n        if (!found) break;\n        int removed = removeCells(board, best);\n        if (removed <= 0) break;\n        best.removal = removed;\n        res.seq.push_back(best);\n        res.cost += 2 * best.shifts;\n        total -= removed;\n        if (res.cost > LIMIT_OPS) break;\n    }\n    if (total == 0 && res.cost <= LIMIT_OPS) res.success = true;\n    return res;\n}\n\nbool applyPrefix(const vector<string>& initial, const vector<Candidate>& seq, int keep,\n                 vector<string>& boardOut, int& costOut) {\n    boardOut = initial;\n    costOut = 0;\n    for (int i = 0; i < keep; ++i) {\n        costOut += 2 * seq[i].shifts;\n        if (costOut > LIMIT_OPS) return false;\n        int removed = removeCells(boardOut, seq[i]);\n        if (removed < 0) return false;\n    }\n    return true;\n}\n\nvoid localSearch(const vector<string>& initial, PlanResult& best, mt19937& rng,\n                 int iterations, double maxTol) {\n    if (!best.success) return;\n    if (best.seq.empty()) return;\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n    vector<string> board;\n    int prefixCost = 0;\n\n    for (int iter = 0; iter < iterations; ++iter) {\n        int sz = (int)best.seq.size();\n        if (sz == 0) break;\n        int keep = 0;\n        if (sz > 1) {\n            double r = dist01(rng);\n            if (r < 0.25) keep = 0;\n            else if (r < 0.5) keep = rng() % min(sz, 4);\n            else if (r < 0.8) keep = rng() % (sz / 2 + 1);\n            else keep = rng() % sz;\n            if (keep >= sz) keep = sz - 1;\n        }\n        if (!applyPrefix(initial, best.seq, keep, board, prefixCost)) continue;\n        int remainingBudget = LIMIT_OPS - prefixCost;\n        if (remainingBudget < 0) continue;\n        double tol = pow(dist01(rng), 1.7) * maxTol;\n        PlanResult tail = greedyPlanFrom(board, rng, tol, remainingBudget);\n        if (!tail.success) continue;\n        PlanResult candidate;\n        candidate.seq.reserve(keep + tail.seq.size());\n        candidate.seq.insert(candidate.seq.end(), best.seq.begin(), best.seq.begin() + keep);\n        candidate.seq.insert(candidate.seq.end(), tail.seq.begin(), tail.seq.end());\n        candidate.cost = prefixCost + tail.cost;\n        candidate.success = true;\n        if (!best.success || candidate.cost < best.cost ||\n            (candidate.cost == best.cost && candidate.seq.size() < best.seq.size())) {\n            best = move(candidate);\n        }\n    }\n}\n\nbool simulatePlan(const vector<string>& initial, const PlanResult& plan,\n                  vector<pair<char,int>>& output) {\n    if (!plan.success) return false;\n    if (plan.cost > LIMIT_OPS) return false;\n    vector<string> board = initial;\n    int remaining = countOni(board);\n    output.clear();\n    output.reserve(plan.cost + 5);\n\n    auto doShift = [&](char dir, int idx) -> bool {\n        if ((int)output.size() >= LIMIT_OPS) return false;\n        output.emplace_back(dir, idx);\n        if (dir == 'U') {\n            char removed = board[0][idx];\n            for (int r = 0; r < N - 1; ++r) board[r][idx] = board[r + 1][idx];\n            board[N - 1][idx] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else if (dir == 'D') {\n            char removed = board[N - 1][idx];\n            for (int r = N - 1; r >= 1; --r) board[r][idx] = board[r - 1][idx];\n            board[0][idx] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else if (dir == 'L') {\n            char removed = board[idx][0];\n            for (int c = 0; c < N - 1; ++c) board[idx][c] = board[idx][c + 1];\n            board[idx][N - 1] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else {\n            char removed = board[idx][N - 1];\n            for (int c = N - 1; c >= 1; --c) board[idx][c] = board[idx][c - 1];\n            board[idx][0] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        }\n        return true;\n    };\n\n    for (const auto& cand : plan.seq) {\n        for (int i = 0; i < cand.shifts; ++i)\n            if (!doShift(cand.dir, cand.idx)) { output.clear(); return false; }\n        char opp = oppositeDir(cand.dir);\n        for (int i = 0; i < cand.shifts; ++i)\n            if (!doShift(opp, cand.idx)) { output.clear(); return false; }\n    }\n    if (remaining != 0) { output.clear(); return false; }\n    if ((int)output.size() > LIMIT_OPS) { output.clear(); return false; }\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N)) return 0;\n    vector<string> board(N);\n    for (int i = 0; i < N; ++i) cin >> board[i];\n    LIMIT_OPS = 4 * N * N;\n\n    precomputeEdgeInfo(board);\n    cellWeight = buildCellWeights(board);\n\n    uint64_t seed = 1469598103934665603ULL;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < N; ++i) {\n        for (char c : board[i]) {\n            seed ^= (uint64_t)(unsigned char)c + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n    mt19937 rng(seed);\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    const int MAX_TRIALS = 100;\n    const double MAX_TOL = 0.4;\n    PlanResult best;\n\n    for (int t = 0; t < MAX_TRIALS; ++t) {\n        double tol = (t == 0) ? 0.0 : pow(dist01(rng), 1.5) * MAX_TOL;\n        PlanResult plan = greedyPlanFrom(board, rng, tol, LIMIT_OPS);\n        if (!plan.success) continue;\n        if (!best.success || plan.cost < best.cost ||\n            (plan.cost == best.cost && plan.seq.size() < best.seq.size())) {\n            best = plan;\n        }\n    }\n\n    if (!best.success) {\n        mt19937 det_rng(seed ^ 0x9e3779b97f4a7c15ULL);\n        PlanResult det = greedyPlanFrom(board, det_rng, 0.0, LIMIT_OPS, true);\n        if (det.success) best = det;\n    }\n    if (!best.success) {\n        PlanResult seqPlan = sequentialPlan(board);\n        if (seqPlan.success) best = seqPlan;\n    }\n    if (best.success) {\n        localSearch(board, best, rng, 80, 0.35);\n    }\n\n    vector<pair<char,int>> ops;\n    if (!simulatePlan(board, best, ops)) {\n        mt19937 det_rng(seed ^ 0x123456789abcdefULL);\n        PlanResult det = greedyPlanFrom(board, det_rng, 0.0, LIMIT_OPS, true);\n        if (!det.success || !simulatePlan(board, det, ops)) {\n            PlanResult seqPlan = sequentialPlan(board);\n            simulatePlan(board, seqPlan, ops);\n        }\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\ndouble elapsedSec(const chrono::steady_clock::time_point &start) {\n    return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n}\n\nstruct AssignState {\n    int N = 0;\n    int totalItems = 0;\n    vector<int> src;\n    vector<int> weights;\n    vector<int> dest;\n    vector<int> itemPos;\n    vector<vector<int>> binItems;\n    vector<long long> cap;\n    vector<long long> sum;\n    vector<long long> rem;\n    vector<char> locked;\n    long long penalty = 0;\n\n    void setup(int n, const vector<int> &target) {\n        N = n;\n        totalItems = 2 * N;\n        src.resize(totalItems);\n        weights.resize(totalItems);\n        dest.assign(totalItems, -1);\n        itemPos.assign(totalItems, -1);\n        binItems.assign(N, {});\n        cap.resize(N);\n        sum.assign(N, 0);\n        rem.assign(N, 0);\n        locked.assign(totalItems, 0);\n        penalty = 0;\n        for (int i = 0; i < N; ++i) {\n            int w = target[i];\n            src[2 * i] = src[2 * i + 1] = i;\n            weights[2 * i] = weights[2 * i + 1] = w;\n            cap[i] = 2LL * w;\n            rem[i] = cap[i];\n        }\n    }\n};\n\nvoid initialAssign(AssignState &st, mt19937 &rng) {\n    for (int j = 0; j < st.N; ++j) {\n        st.binItems[j].clear();\n        st.sum[j] = 0;\n        st.rem[j] = st.cap[j];\n    }\n    fill(st.dest.begin(), st.dest.end(), -1);\n    fill(st.itemPos.begin(), st.itemPos.end(), -1);\n    fill(st.locked.begin(), st.locked.end(), 0);\n    vector<int> order(st.totalItems);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (st.weights[a] != st.weights[b]) return st.weights[a] > st.weights[b];\n        return a < b;\n    });\n    priority_queue<pair<long long, int>> pq;\n    for (int j = 0; j < st.N; ++j) pq.push({st.rem[j], j});\n    auto popValid = [&]() {\n        while (true) {\n            auto [val, idx] = pq.top();\n            pq.pop();\n            if (val == st.rem[idx]) return idx;\n        }\n    };\n    for (int item : order) {\n        int bin = popValid();\n        st.dest[item] = bin;\n        st.itemPos[item] = st.binItems[bin].size();\n        st.binItems[bin].push_back(item);\n        st.sum[bin] += st.weights[item];\n        st.rem[bin] = st.cap[bin] - st.sum[bin];\n        pq.push({st.rem[bin], bin});\n    }\n    st.penalty = 0;\n    for (int j = 0; j < st.N; ++j) st.penalty += llabs(st.rem[j]);\n}\n\nlong long penaltyDelta(const AssignState &st, int item, int newBin) {\n    int oldBin = st.dest[item];\n    if (oldBin == newBin) return 0;\n    long long w = st.weights[item];\n    long long before = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n    long long after = llabs(st.rem[oldBin] + w) + llabs(st.rem[newBin] - w);\n    return after - before;\n}\n\nvoid moveItem(AssignState &st, int item, int newBin) {\n    int oldBin = st.dest[item];\n    if (oldBin == newBin) return;\n    long long w = st.weights[item];\n    long long oldContribution = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n\n    int pos = st.itemPos[item];\n    int last = st.binItems[oldBin].back();\n    st.binItems[oldBin][pos] = last;\n    st.itemPos[last] = pos;\n    st.binItems[oldBin].pop_back();\n\n    st.sum[oldBin] -= w;\n    st.rem[oldBin] += w;\n\n    st.sum[newBin] += w;\n    st.rem[newBin] -= w;\n\n    st.itemPos[item] = st.binItems[newBin].size();\n    st.binItems[newBin].push_back(item);\n    st.dest[item] = newBin;\n\n    long long newContribution = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n    st.penalty += newContribution - oldContribution;\n}\n\nvoid balance(AssignState &st, bool respectLocked,\n             const chrono::steady_clock::time_point &start, double limitTime) {\n    while (true) {\n        if (elapsedSec(start) > limitTime) break;\n        vector<int> posBins;\n        for (int j = 0; j < st.N; ++j) if (st.rem[j] > 0) posBins.push_back(j);\n        if (posBins.empty()) break;\n        sort(posBins.begin(), posBins.end(),\n             [&](int a, int b) { return st.rem[a] > st.rem[b]; });\n        bool moved = false;\n        for (int pos : posBins) {\n            long long remPos = st.rem[pos];\n            long long bestDiff = 0;\n            int bestItem = -1;\n            for (int neg = 0; neg < st.N; ++neg) {\n                if (st.rem[neg] >= 0) continue;\n                long long remNeg = st.rem[neg];\n                for (int item : st.binItems[neg]) {\n                    if (respectLocked && st.locked[item]) continue;\n                    long long w = st.weights[item];\n                    long long newPos = remPos - w;\n                    long long newNeg = remNeg + w;\n                    long long diff = llabs(newPos) + llabs(newNeg)\n                                   - (llabs(remPos) + llabs(remNeg));\n                    if (diff < bestDiff) {\n                        bestDiff = diff;\n                        bestItem = item;\n                    }\n                }\n            }\n            if (bestItem != -1) {\n                moveItem(st, bestItem, pos);\n                moved = true;\n                break;\n            }\n        }\n        if (!moved) break;\n    }\n}\n\nvoid randomImprove(AssignState &st, bool respectLocked, int maxIter,\n                   const chrono::steady_clock::time_point &start,\n                   double limitTime, mt19937 &rng) {\n    for (int iter = 0; iter < maxIter; ++iter) {\n        if ((iter & 511) == 0 && elapsedSec(start) > limitTime) break;\n        int item = rng() % st.totalItems;\n        if (respectLocked) {\n            int tries = 0;\n            while (tries < 30 && st.locked[item]) {\n                item = rng() % st.totalItems;\n                ++tries;\n            }\n            if (st.locked[item]) continue;\n        }\n        int from = st.dest[item];\n        int bestBin = -1;\n        long long bestDelta = 0;\n        for (int attempt = 0; attempt < 6; ++attempt) {\n            int cand = rng() % st.N;\n            if (cand == from) continue;\n            long long delta = penaltyDelta(st, item, cand);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestBin = cand;\n            }\n        }\n        if (bestBin == -1) continue;\n        moveItem(st, item, bestBin);\n    }\n}\n\nstruct SCCResult {\n    vector<int> comp;\n    int cnt;\n};\n\nSCCResult computeSCC(const vector<int> &a, const vector<int> &b) {\n    int N = a.size();\n    vector<vector<int>> g(N), gr(N);\n    for (int i = 0; i < N; ++i) {\n        g[i].push_back(a[i]);\n        g[i].push_back(b[i]);\n        gr[a[i]].push_back(i);\n        gr[b[i]].push_back(i);\n    }\n    vector<int> used(N, 0), order;\n    auto dfs1 = [&](auto self, int v) -> void {\n        used[v] = 1;\n        for (int to : g[v]) if (!used[to]) self(self, to);\n        order.push_back(v);\n    };\n    for (int i = 0; i < N; ++i) if (!used[i]) dfs1(dfs1, i);\n    vector<int> comp(N, -1);\n    int compId = 0;\n    auto dfs2 = [&](auto self, int v) -> void {\n        comp[v] = compId;\n        for (int to : gr[v]) if (comp[to] == -1) self(self, to);\n    };\n    for (int i = N - 1; i >= 0; --i) {\n        int v = order[i];\n        if (comp[v] == -1) {\n            dfs2(dfs2, v);\n            ++compId;\n        }\n    }\n    return {comp, compId};\n}\n\nint ensureConnectivity(AssignState &st,\n                       const chrono::steady_clock::time_point &start,\n                       double limitTime) {\n    vector<int> a(st.N), b(st.N);\n    for (int i = 0; i < st.N; ++i) {\n        a[i] = st.dest[2 * i];\n        b[i] = st.dest[2 * i + 1];\n    }\n    auto scc = computeSCC(a, b);\n    int K = scc.cnt;\n    if (K == 1) return 0;\n    vector<vector<int>> nodesIn(K);\n    for (int i = 0; i < st.N; ++i) nodesIn[scc.comp[i]].push_back(i);\n    vector<int> order(K);\n    iota(order.begin(), order.end(), 0);\n    int lockedAdded = 0;\n    for (int idx = 0; idx < K; ++idx) {\n        if (elapsedSec(start) > limitTime) break;\n        int fromC = order[idx];\n        int toC = order[(idx + 1) % K];\n        vector<int> existing;\n        for (int node : nodesIn[fromC]) {\n            for (int t = 0; t < 2; ++t) {\n                int item = 2 * node + t;\n                if (st.dest[item] >= 0 && scc.comp[st.dest[item]] == toC) {\n                    existing.push_back(item);\n                }\n            }\n        }\n        if (!existing.empty()) {\n            int bestEdge = existing[0];\n            for (int item : existing) {\n                if (st.weights[item] < st.weights[bestEdge]) bestEdge = item;\n            }\n            st.locked[bestEdge] = 1;\n            ++lockedAdded;\n            continue;\n        }\n        long long bestDelta = (1LL << 60);\n        int bestEdge = -1, bestDest = -1;\n        for (int node : nodesIn[fromC]) {\n            for (int t = 0; t < 2; ++t) {\n                int item = 2 * node + t;\n                if (st.locked[item]) continue;\n                for (int destNode : nodesIn[toC]) {\n                    long long delta = penaltyDelta(st, item, destNode);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestEdge = item;\n                        bestDest = destNode;\n                    }\n                }\n            }\n        }\n        if (bestEdge == -1) continue;\n        moveItem(st, bestEdge, bestDest);\n        st.locked[bestEdge] = 1;\n        ++lockedAdded;\n    }\n    return lockedAdded;\n}\n\nlong long simulatePlan(const vector<int> &a, const vector<int> &b, int L,\n                       const vector<int> &target, vector<int> &cnt) {\n    int N = a.size();\n    if ((int)cnt.size() != N) cnt.assign(N, 0);\n    else fill(cnt.begin(), cnt.end(), 0);\n    int cur = 0;\n    cnt[cur] = 1;\n    for (int step = 1; step < L; ++step) {\n        int nxt = (cnt[cur] & 1) ? a[cur] : b[cur];\n        cur = nxt;\n        cnt[cur]++;\n    }\n    long long err = 0;\n    for (int i = 0; i < N; ++i) err += llabs(1LL * cnt[i] - target[i]);\n    return err;\n}\n\nstruct AttemptResult {\n    vector<int> a, b;\n    long long err = (1LL << 60);\n    long long weightPenalty = (1LL << 60);\n};\n\nAttemptResult runAttempt(const vector<int> &target, int N, int L,\n                         const chrono::steady_clock::time_point &start,\n                         double limitTime, uint64_t seed) {\n    AttemptResult res;\n    AssignState st;\n    st.setup(N, target);\n    mt19937 rng(seed);\n\n    initialAssign(st, rng);\n    balance(st, false, start, limitTime);\n    randomImprove(st, false, 200000, start, limitTime, rng);\n    balance(st, false, start, limitTime);\n\n    ensureConnectivity(st, start, limitTime);\n    balance(st, true, start, limitTime);\n    randomImprove(st, true, 120000, start, limitTime, rng);\n    balance(st, true, start, limitTime);\n\n    vector<int> a(N), b(N);\n    for (int i = 0; i < N; ++i) {\n        int da = st.dest[2 * i];\n        int db = st.dest[2 * i + 1];\n        if (da < 0 || da >= N) da = i;\n        if (db < 0 || db >= N) db = i;\n        a[i] = da;\n        b[i] = db;\n    }\n    vector<int> cnt(N);\n    long long err = simulatePlan(a, b, L, target, cnt);\n    res.a = move(a);\n    res.b = move(b);\n    res.err = err;\n    res.weightPenalty = st.penalty;\n    return res;\n}\n\nvoid localSearch(vector<int> &a, vector<int> &b, const vector<int> &target, int L,\n                 const chrono::steady_clock::time_point &start, double limitTime,\n                 mt19937 &rng) {\n    int N = a.size();\n    if (N == 0) return;\n    if (elapsedSec(start) >= limitTime) return;\n\n    vector<int> curCnt(N), bestCnt(N), testCnt(N), diff(N);\n    long long curErr = simulatePlan(a, b, L, target, curCnt);\n    long long bestErr = curErr;\n    bestCnt = curCnt;\n    vector<int> bestA = a, bestB = b;\n\n    auto refreshDiff = [&]() {\n        for (int i = 0; i < N; ++i) diff[i] = curCnt[i] - target[i];\n    };\n    refreshDiff();\n    if (bestErr == 0) {\n        a = bestA;\n        b = bestB;\n        return;\n    }\n\n    while (elapsedSec(start) < limitTime) {\n        vector<int> over, under;\n        over.reserve(N);\n        under.reserve(N);\n        for (int i = 0; i < N; ++i) {\n            if (diff[i] > 0) over.push_back(i);\n            else if (diff[i] < 0) under.push_back(i);\n        }\n        if (over.empty() || under.empty()) break;\n\n        int destOver;\n        if ((rng() & 7) != 0) {\n            destOver = over[0];\n            for (int idx : over) if (diff[idx] > diff[destOver]) destOver = idx;\n        } else destOver = over[rng() % over.size()];\n\n        int destUnder;\n        if ((rng() & 7) != 0) {\n            destUnder = under[0];\n            for (int idx : under) if (diff[idx] < diff[destUnder]) destUnder = idx;\n        } else destUnder = under[rng() % under.size()];\n\n        vector<pair<int, int>> edges;\n        edges.reserve(N);\n        for (int u = 0; u < N; ++u) {\n            if (a[u] == destOver) edges.emplace_back(u, 0);\n            if (b[u] == destOver) edges.emplace_back(u, 1);\n        }\n        if (edges.empty()) {\n            edges.emplace_back(destOver, 0);\n            edges.emplace_back(destOver, 1);\n        }\n\n        pair<int, int> chosen = edges[rng() % edges.size()];\n        if ((rng() & 3) != 0) {\n            pair<int, int> bestEdge = edges[0];\n            int bestVal = diff[bestEdge.first];\n            for (auto &e : edges) {\n                if (diff[e.first] > bestVal) {\n                    bestVal = diff[e.first];\n                    bestEdge = e;\n                }\n            }\n            chosen = bestEdge;\n        }\n\n        int src = chosen.first;\n        int which = chosen.second;\n        int oldDest = (which == 0) ? a[src] : b[src];\n        if (oldDest == destUnder) continue;\n\n        if (which == 0) a[src] = destUnder;\n        else b[src] = destUnder;\n\n        long long newErr = simulatePlan(a, b, L, target, testCnt);\n        if (newErr <= curErr) {\n            curErr = newErr;\n            curCnt = testCnt;\n            refreshDiff();\n            if (newErr < bestErr) {\n                bestErr = newErr;\n                bestA = a;\n                bestB = b;\n                bestCnt = testCnt;\n                if (bestErr == 0) break;\n            }\n        } else {\n            if (which == 0) a[src] = oldDest;\n            else b[src] = oldDest;\n        }\n\n        if (elapsedSec(start) >= limitTime) break;\n    }\n    a = bestA;\n    b = bestB;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\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    auto start = chrono::steady_clock::now();\n    const double TOTAL_LIMIT = 1.95;\n    const double FINAL_RESERVE = 0.03;\n    const double LS_RESERVE = 0.22;\n\n    double attemptBudget = TOTAL_LIMIT - (LS_RESERVE + FINAL_RESERVE);\n    if (attemptBudget < 0.4) attemptBudget = TOTAL_LIMIT - FINAL_RESERVE - 0.05;\n    if (attemptBudget < 0.3) attemptBudget = TOTAL_LIMIT - 0.05;\n    attemptBudget = max(0.3, min(attemptBudget, TOTAL_LIMIT - FINAL_RESERVE - 0.02));\n\n    vector<double> attemptLimits;\n    double firstLimit = min(0.9, attemptBudget);\n    if (attemptBudget - firstLimit < 0.12) {\n        attemptLimits.push_back(attemptBudget);\n    } else {\n        attemptLimits.push_back(firstLimit);\n        attemptLimits.push_back(attemptBudget);\n    }\n\n    mt19937 baseRng(chrono::steady_clock::now().time_since_epoch().count());\n    auto nextSeed = [&]() -> uint64_t {\n        uint64_t s = ((uint64_t)baseRng() << 32) ^ baseRng();\n        s ^= chrono::steady_clock::now().time_since_epoch().count();\n        return s;\n    };\n\n    vector<int> bestA(N), bestB(N);\n    long long bestErr = (1LL << 60);\n    long long bestPenalty = (1LL << 60);\n    bool haveBest = false;\n\n    for (size_t idx = 0; idx < attemptLimits.size(); ++idx) {\n        double limit = attemptLimits[idx];\n        if (elapsedSec(start) >= limit - 0.02) continue;\n        uint64_t seed = nextSeed() ^ (0x9e3779b97f4a7c15ULL * (idx + 1));\n        AttemptResult res = runAttempt(T, N, L, start, limit, seed);\n        if (!haveBest || res.err < bestErr ||\n            (res.err == bestErr && res.weightPenalty < bestPenalty)) {\n            bestA = res.a;\n            bestB = res.b;\n            bestErr = res.err;\n            bestPenalty = res.weightPenalty;\n            haveBest = true;\n        }\n        if (elapsedSec(start) > attemptBudget + 0.1) break;\n    }\n\n    if (!haveBest) {\n        uint64_t seed = nextSeed();\n        double fallbackLimit = min(TOTAL_LIMIT - FINAL_RESERVE - 0.05, TOTAL_LIMIT - FINAL_RESERVE);\n        AttemptResult res = runAttempt(T, N, L, start, fallbackLimit, seed);\n        bestA = res.a;\n        bestB = res.b;\n        bestErr = res.err;\n        haveBest = true;\n    }\n\n    double lsLimit = TOTAL_LIMIT - FINAL_RESERVE;\n    if (lsLimit > elapsedSec(start) + 0.01) {\n        localSearch(bestA, bestB, T, L, start, lsLimit, baseRng);\n        vector<int> cnt(N);\n        bestErr = simulatePlan(bestA, bestB, L, T, cnt);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << bestA[i] << ' ' << bestB[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nlong long hilbertOrder(long long x, long long y, int pow = 15, int rot = 0) {\n    if (pow == 0) return 0;\n    long long h = 1LL << (pow - 1);\n    long long seg = ((x < h) ? 0 : 1) | ((y < h) ? 0 : 2);\n    seg = (seg + rot) & 3;\n    static const int rotateDelta[4] = {3, 0, 0, 1};\n    long long nx = x & (h - 1);\n    long long ny = y & (h - 1);\n    int nrot = (rot + rotateDelta[seg]) & 3;\n    long long subSize = 1LL << (2 * pow - 2);\n    long long add = hilbertOrder(nx, ny, pow - 1, nrot);\n    if (seg == 1 || seg == 2) {\n        return seg * subSize + add;\n    } else {\n        return seg * subSize + (subSize - add - 1);\n    }\n}\n\nvector<int> build_global_parent(const vector<double>& px, const vector<double>& py) {\n    int n = (int)px.size();\n    const double INF = 1e100;\n    vector<double> best(n, INF);\n    vector<int> parent(n, -1);\n    vector<char> used(n, 0);\n    best[0] = 0.0;\n    for (int it = 0; it < n; ++it) {\n        int v = -1;\n        double bv = INF;\n        for (int i = 0; i < n; ++i) if (!used[i] && best[i] < bv) {\n            bv = best[i];\n            v = i;\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        for (int u = 0; u < n; ++u) if (!used[u]) {\n            double dx = px[v] - px[u];\n            double dy = py[v] - py[u];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[u]) {\n                best[u] = dist;\n                parent[u] = v;\n            }\n        }\n    }\n    for (int i = 1; i < n; ++i) if (parent[i] == -1) parent[i] = 0;\n    return parent;\n}\n\ndouble group_cost(const vector<int>& nodes, const vector<double>& px, const vector<double>& py) {\n    int k = (int)nodes.size();\n    if (k <= 1) return 0.0;\n    const double INF = 1e100;\n    static vector<double> best;\n    static vector<char> used;\n    best.assign(k, INF);\n    used.assign(k, 0);\n    best[0] = 0.0;\n    double total = 0.0;\n    for (int iter = 0; iter < k; ++iter) {\n        int v = -1;\n        double bv = INF;\n        for (int i = 0; i < k; ++i)\n            if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n        if (v == -1) break;\n        used[v] = 1;\n        if (iter > 0) total += sqrt(max(0.0, bv));\n        for (int j = 0; j < k; ++j) if (!used[j]) {\n            double dx = px[nodes[v]] - px[nodes[j]];\n            double dy = py[nodes[v]] - py[nodes[j]];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[j]) best[j] = dist;\n        }\n    }\n    return total;\n}\n\nvector<pair<int,int>> build_group_mst(const vector<int>& nodes,\n                                      const vector<double>& px,\n                                      const vector<double>& py) {\n    int k = (int)nodes.size();\n    vector<pair<int,int>> edges;\n    if (k <= 1) return edges;\n    const double INF = 1e100;\n    vector<double> best(k, INF);\n    vector<int> parent(k, -1);\n    vector<char> used(k, 0);\n    best[0] = 0.0;\n    for (int iter = 0; iter < k; ++iter) {\n        int v = -1;\n        double bv = INF;\n        for (int i = 0; i < k; ++i)\n            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[v], nodes[parent[v]]);\n        for (int j = 0; j < k; ++j) if (!used[j]) {\n            double dx = px[nodes[v]] - px[nodes[j]];\n            double dy = py[nodes[v]] - py[nodes[j]];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[j]) {\n                best[j] = dist;\n                parent[j] = v;\n            }\n        }\n    }\n    if ((int)edges.size() != k - 1) {\n        edges.clear();\n        for (int i = 1; i < k; ++i)\n            edges.emplace_back(nodes[i - 1], nodes[i]);\n    }\n    return edges;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    auto global_start = chrono::steady_clock::now();\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) cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n\n    vector<double> px(N), py(N);\n    vector<int> ix(N), iy(N);\n    for (int i = 0; i < N; ++i) {\n        px[i] = 0.5 * (lx[i] + rx[i]);\n        py[i] = 0.5 * (ly[i] + ry[i]);\n        ix[i] = (lx[i] + rx[i]) / 2;\n        iy[i] = (ly[i] + ry[i]) / 2;\n    }\n\n    vector<long long> hilb(N);\n    for (int i = 0; i < N; ++i) hilb[i] = hilbertOrder(ix[i], iy[i], 15, 0);\n\n    vector<int> parent = build_global_parent(px, py);\n    vector<vector<int>> adj(N);\n    for (int v = 1; v < N; ++v) {\n        int p = parent[v];\n        if (p < 0 || p >= N || p == v) p = 0;\n        adj[v].push_back(p);\n        adj[p].push_back(v);\n    }\n    for (int v = 0; v < N; ++v) {\n        auto &nbr = adj[v];\n        sort(nbr.begin(), nbr.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n        nbr.erase(unique(nbr.begin(), nbr.end()), nbr.end());\n    }\n    vector<int> order_mst;\n    order_mst.reserve(N);\n    vector<char> vis(N, 0);\n    auto dfs = [&](auto self, int u, int p) -> void {\n        vis[u] = 1;\n        order_mst.push_back(u);\n        for (int v : adj[u]) if (v != p && !vis[v]) self(self, v, u);\n    };\n    for (int i = 0; i < N; ++i) if (!vis[i]) dfs(dfs, i, -1);\n\n    vector<int> base(N);\n    iota(base.begin(), base.end(), 0);\n\n    uint64_t seed = 987654321;\n    seed = seed * 1000003ULL + N;\n    seed = seed * 1000003ULL + M;\n    seed = seed * 1000003ULL + Q;\n    seed = seed * 1000003ULL + L;\n    seed = seed * 1000003ULL + W;\n    for (int i = 0; i < min(N, 20); ++i) {\n        seed = seed * 1000003ULL + (uint64_t)(ix[i] + 10001);\n        seed = seed * 1000003ULL + (uint64_t)(iy[i] + 10001);\n    }\n    mt19937 rng(static_cast<uint32_t>(seed));\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    auto hash_order = [&](const vector<int>& ord) -> uint64_t {\n        uint64_t h = 0;\n        for (int v : ord) h = h * 1000003ULL + (uint64_t)(v + 1);\n        return h;\n    };\n\n    auto build_groups = [&](const vector<int>& ord, vector<vector<int>>& groups) -> bool {\n        if ((int)ord.size() != N) return false;\n        size_t pos = 0;\n        for (int i = 0; i < M; ++i) {\n            size_t need = (size_t)G[i];\n            if (pos + need > ord.size()) return false;\n            groups[i].assign(ord.begin() + pos, ord.begin() + pos + need);\n            pos += need;\n        }\n        return pos == ord.size();\n    };\n\n    unordered_set<uint64_t> seen;\n    seen.reserve(256);\n    seen.max_load_factor(0.7f);\n\n    vector<vector<int>> bestGroups;\n    double bestCost = 1e100;\n    bool haveBest = false;\n\n    auto evaluate_candidate = [&](const vector<int>& ord) {\n        uint64_t h = hash_order(ord);\n        if (!seen.insert(h).second) return;\n        vector<vector<int>> groups(M);\n        if (!build_groups(ord, groups)) return;\n        double total = 0.0;\n        for (int i = 0; i < M; ++i) total += group_cost(groups[i], px, py);\n        if (!haveBest || total < bestCost) {\n            haveBest = true;\n            bestCost = total;\n            bestGroups = std::move(groups);\n        }\n    };\n\n    auto add_sorted = [&](auto cmp) {\n        vector<int> ord = base;\n        sort(ord.begin(), ord.end(), cmp);\n        evaluate_candidate(ord);\n    };\n\n    evaluate_candidate(base);\n    {\n        vector<int> tmp = base;\n        reverse(tmp.begin(), tmp.end());\n        evaluate_candidate(tmp);\n    }\n    evaluate_candidate(order_mst);\n    {\n        vector<int> tmp = order_mst;\n        reverse(tmp.begin(), tmp.end());\n        evaluate_candidate(tmp);\n    }\n    {\n        vector<int> tmp = base;\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n        evaluate_candidate(tmp);\n        reverse(tmp.begin(), tmp.end());\n        evaluate_candidate(tmp);\n    }\n    add_sorted([&](int a, int b) {\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        if (iy[a] != iy[b]) return iy[a] < iy[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        if (iy[a] != iy[b]) return iy[a] < iy[b];\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] + iy[a];\n        long long kb = (long long)ix[b] + iy[b];\n        if (ka != kb) return ka < kb;\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] - iy[a];\n        long long kb = (long long)ix[b] - iy[b];\n        if (ka != kb) return ka < kb;\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] * 2 + iy[a];\n        long long kb = (long long)ix[b] * 2 + iy[b];\n        if (ka != kb) return ka < kb;\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] - 2LL * iy[a];\n        long long kb = (long long)ix[b] - 2LL * iy[b];\n        if (ka != kb) return ka < kb;\n        return a < b;\n    });\n    for (int iter = 0; iter < 8; ++iter) {\n        vector<int> ord = base;\n        shuffle(ord.begin(), ord.end(), rng);\n        evaluate_candidate(ord);\n    }\n\n    if (!haveBest) {\n        vector<vector<int>> groups(M);\n        build_groups(base, groups);\n        bestGroups = groups;\n        bestCost = 0.0;\n        for (int i = 0; i < M; ++i) bestCost += group_cost(bestGroups[i], px, py);\n    }\n\n    vector<vector<int>> groups = bestGroups;\n    vector<double> groupCost(M, 0.0);\n    vector<double> sum_x(M, 0.0), sum_y(M, 0.0);\n    double curCost = 0.0;\n    for (int i = 0; i < M; ++i) {\n        groupCost[i] = group_cost(groups[i], px, py);\n        curCost += groupCost[i];\n        for (int v : groups[i]) {\n            sum_x[i] += px[v];\n            sum_y[i] += py[v];\n        }\n    }\n    bestCost = curCost;\n    bestGroups = groups;\n\n    const double TOTAL_LIMIT = 1.8;\n    auto deadline = global_start + chrono::duration<double>(TOTAL_LIMIT);\n    if (M > 1) {\n        const double T0 = 500.0;\n        const double T1 = 1e-3;\n        while (chrono::steady_clock::now() < deadline) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n            double progress = min(1.0, elapsed / TOTAL_LIMIT);\n            double temperature = T0 * pow(T1 / T0, progress);\n\n            int g = rng() % M;\n            auto choose_partner = [&](int gidx) -> int {\n                if (M <= 1) return gidx;\n                if (uni01(rng) < 0.3) {\n                    int cand = rng() % (M - 1);\n                    if (cand >= gidx) ++cand;\n                    return cand;\n                }\n                double cgx = sum_x[gidx] / groups[gidx].size();\n                double cgy = sum_y[gidx] / groups[gidx].size();\n                double bestd = 1e300;\n                int best = -1;\n                int samples = min(M - 1, 10);\n                for (int t = 0; t < samples; ++t) {\n                    int cand = rng() % M;\n                    if (cand == gidx) continue;\n                    double csx = sum_x[cand] / groups[cand].size();\n                    double csy = sum_y[cand] / groups[cand].size();\n                    double dx = cgx - csx;\n                    double dy = cgy - csy;\n                    double dist = dx * dx + dy * dy;\n                    if (dist < bestd) {\n                        bestd = dist;\n                        best = cand;\n                    }\n                }\n                if (best == -1) {\n                    best = (gidx + 1 + (rng() % (M - 1))) % M;\n                }\n                return best;\n            };\n            int h = choose_partner(g);\n            if (h == g) continue;\n\n            auto pick_index = [&](int grp) -> int {\n                int sz = (int)groups[grp].size();\n                if (sz <= 1) return 0;\n                if ((rng() & 1) == 0) return rng() % sz;\n                double cx = sum_x[grp] / sz;\n                double cy = sum_y[grp] / sz;\n                int bestIdx = rng() % sz;\n                double bestScore = -1.0;\n                int samples = min(sz, 6);\n                for (int t = 0; t < samples; ++t) {\n                    int idx = rng() % sz;\n                    double dx = px[groups[grp][idx]] - cx;\n                    double dy = py[groups[grp][idx]] - cy;\n                    double sc = dx * dx + dy * dy;\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestIdx = idx;\n                    }\n                }\n                return bestIdx;\n            };\n\n            if (groups[g].empty() || groups[h].empty()) continue;\n            int idx_g = pick_index(g);\n            int idx_h = pick_index(h);\n            int node_g = groups[g][idx_g];\n            int node_h = groups[h][idx_h];\n            if (node_g == node_h) continue;\n\n            swap(groups[g][idx_g], groups[h][idx_h]);\n            double newCostG = group_cost(groups[g], px, py);\n            double newCostH = group_cost(groups[h], px, py);\n            double delta = (newCostG + newCostH) - (groupCost[g] + groupCost[h]);\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-delta / temperature);\n                if (uni01(rng) < prob) accept = true;\n            }\n            if (accept) {\n                groupCost[g] = newCostG;\n                groupCost[h] = newCostH;\n                curCost += delta;\n                sum_x[g] += px[node_h] - px[node_g];\n                sum_y[g] += py[node_h] - py[node_g];\n                sum_x[h] += px[node_g] - px[node_h];\n                sum_y[h] += py[node_g] - py[node_h];\n                if (curCost + 1e-9 < bestCost) {\n                    bestCost = curCost;\n                    bestGroups = groups;\n                }\n            } else {\n                swap(groups[g][idx_g], groups[h][idx_h]);\n            }\n        }\n    }\n\n    groups = bestGroups;\n    vector<vector<pair<int,int>>> edges(M);\n    for (int i = 0; i < M; ++i) edges[i] = build_group_mst(groups[i], px, py);\n\n    cout << \"!\\n\";\n    for (int i = 0; i < M; ++i) {\n        for (size_t j = 0; j < groups[i].size(); ++j) {\n            if (j) cout << ' ';\n            cout << groups[i][j];\n        }\n        cout << '\\n';\n        for (auto &e : edges[i]) cout << e.first << ' ' << e.second << '\\n';\n    }\n    cout.flush();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int DIRS = 4;\nconst int dr[DIRS] = {-1, 1, 0, 0};\nconst int dc[DIRS] = {0, 0, -1, 1};\nconst char dirc[DIRS] = {'U', 'D', 'L', 'R'};\n\nstruct Planner {\n    int N, B, BLOCK_NONE, TOT, chunk_max;\n    vector<int> row, col;\n    vector<array<vector<int>, DIRS>> rays;\n\n    vector<int> dist, prev_state;\n    vector<char> prev_act, prev_dir;\n    vector<int> touched;\n\n    Planner(int N_, int chunk_max_) : N(N_), chunk_max(chunk_max_) {\n        B = N * N;\n        BLOCK_NONE = B;\n        TOT = B * (B + 1);\n        int state_count = TOT * (chunk_max + 1);\n\n        row.resize(B);\n        col.resize(B);\n        for (int idx = 0; idx < B; ++idx) {\n            row[idx] = idx / N;\n            col[idx] = idx % N;\n        }\n\n        rays.resize(B);\n        for (int pos = 0; pos < B; ++pos) {\n            int r = row[pos], c = col[pos];\n            for (int d = 0; d < DIRS; ++d) {\n                auto &line = rays[pos][d];\n                int nr = r + dr[d], nc = c + dc[d];\n                while (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                    line.push_back(nr * N + nc);\n                    nr += dr[d];\n                    nc += dc[d];\n                }\n            }\n        }\n\n        dist.assign(state_count, -1);\n        prev_state.assign(state_count, -1);\n        prev_act.assign(state_count, 0);\n        prev_dir.assign(state_count, 0);\n        touched.reserve(state_count);\n    }\n\n    bool run_chunk(int chunk_len, int start_pos, int start_block,\n                   const vector<int> &targets,\n                   vector<pair<char, char>> &seq,\n                   int &end_block) {\n        seq.clear();\n        if (chunk_len == 0 || chunk_len > chunk_max) {\n            end_block = start_block;\n            return chunk_len == 0;\n        }\n\n        queue<int> q;\n        touched.clear();\n\n        auto state_id = [&](int prog, int pos, int block) -> int {\n            return prog * TOT + pos * (B + 1) + block;\n        };\n\n        int start_state = state_id(0, start_pos, start_block);\n        q.push(start_state);\n        touched.push_back(start_state);\n        dist[start_state] = 0;\n        prev_state[start_state] = -1;\n\n        int goal_state = -1;\n\n        while (!q.empty()) {\n            int st = q.front();\n            q.pop();\n            int prog = st / TOT;\n            if (prog == chunk_len) {\n                goal_state = st;\n                break;\n            }\n            int rem = st % TOT;\n            int pos = rem / (B + 1);\n            int block = rem % (B + 1);\n            int r = row[pos], c = col[pos];\n            int block_idx = (block == BLOCK_NONE ? -1 : block);\n\n            auto push_state = [&](int npos, int nblock, bool can_visit,\n                                  char act, char dir) {\n                int nprog = prog;\n                if (can_visit && nprog < chunk_len &&\n                    npos == targets[nprog]) {\n                    ++nprog;\n                }\n                int nid = state_id(nprog, npos, nblock);\n                if (dist[nid] != -1) return;\n                dist[nid] = dist[st] + 1;\n                prev_state[nid] = st;\n                prev_act[nid] = act;\n                prev_dir[nid] = dir;\n                q.push(nid);\n                touched.push_back(nid);\n            };\n\n            // Move\n            for (int d = 0; d < DIRS; ++d) {\n                int nr = r + dr[d];\n                int nc = c + dc[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int npos = nr * N + nc;\n                if (block_idx == npos) continue;\n                push_state(npos, block, true, 'M', dirc[d]);\n            }\n\n            // Slide\n            for (int d = 0; d < DIRS; ++d) {\n                const auto &line = rays[pos][d];\n                if (line.empty()) continue;\n                int dest = -1;\n                if (block_idx == -1) {\n                    dest = line.back();\n                } else {\n                    int prev_cell = pos;\n                    bool found = false;\n                    for (int cell : line) {\n                        if (cell == block_idx) {\n                            found = true;\n                            if (prev_cell == pos) dest = -1;\n                            else dest = prev_cell;\n                            break;\n                        }\n                        prev_cell = cell;\n                    }\n                    if (found && dest == -1) continue;\n                    if (!found) dest = line.back();\n                }\n                if (dest == -1 || dest == pos) continue;\n                push_state(dest, block, true, 'S', dirc[d]);\n            }\n\n            // Alter (toggle adjacent block)\n            for (int d = 0; d < DIRS; ++d) {\n                int ar = r + dr[d];\n                int ac = c + dc[d];\n                if (ar < 0 || ar >= N || ac < 0 || ac >= N) continue;\n                int adj = ar * N + ac;\n                if (block == BLOCK_NONE) {\n                    push_state(pos, adj, false, 'A', dirc[d]);\n                } else if (block_idx == adj) {\n                    push_state(pos, BLOCK_NONE, false, 'A', dirc[d]);\n                }\n            }\n        }\n\n        if (goal_state == -1) {\n            for (int id : touched) dist[id] = -1;\n            touched.clear();\n            return false;\n        }\n\n        vector<pair<char, char>> rev;\n        for (int cur = goal_state; cur != start_state; cur = prev_state[cur]) {\n            rev.emplace_back(prev_act[cur], prev_dir[cur]);\n        }\n        reverse(rev.begin(), rev.end());\n        seq = move(rev);\n\n        int rem = goal_state % TOT;\n        end_block = rem % (B + 1);\n\n        for (int id : touched) dist[id] = -1;\n        touched.clear();\n        return true;\n    }\n};\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    vector<pair<int, int>> pts(M);\n    for (int i = 0; i < M; ++i) cin >> pts[i].first >> pts[i].second;\n\n    const int LIMIT = 2 * N * M;\n    const int CHUNK_MAX = 3;\n\n    Planner planner(N, CHUNK_MAX);\n\n    vector<int> idx(M);\n    for (int i = 0; i < M; ++i) idx[i] = pts[i].first * N + pts[i].second;\n\n    vector<pair<char, char>> answer;\n    answer.reserve(LIMIT);\n\n    vector<pair<char, char>> seq;\n    vector<int> chunk_targets;\n    chunk_targets.reserve(CHUNK_MAX);\n\n    int current_idx = 0;\n    int block_state = planner.BLOCK_NONE;\n\n    while (current_idx < M - 1 && (int)answer.size() < LIMIT) {\n        int remaining = (M - 1) - current_idx;\n        int used_len = 0;\n        int next_block = block_state;\n        for (int len = min(CHUNK_MAX, remaining); len >= 1; --len) {\n            chunk_targets.clear();\n            for (int t = 1; t <= len; ++t) {\n                chunk_targets.push_back(idx[current_idx + t]);\n            }\n            if (planner.run_chunk(len, idx[current_idx], block_state,\n                                  chunk_targets, seq, next_block)) {\n                used_len = len;\n                break;\n            }\n        }\n        if (used_len == 0) break;  // should not happen\n\n        if ((int)answer.size() + (int)seq.size() > LIMIT) break;\n\n        answer.insert(answer.end(), seq.begin(), seq.end());\n        block_state = next_block;\n        current_idx += used_len;\n    }\n\n    for (auto [a, d] : answer) {\n        cout << a << ' ' << d << '\\n';\n    }\n    return 0;\n}"},"8":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Rect {\n    int x1, y1, x2, y2;\n};\n\nconst int BOARD_SIZE = 10000;\nconst int GROW_ITER_PER_RECT = 20;\nconst int SHRINK_ITER_PER_RECT = 12;\nconst int EXPAND_STEP_LIMIT = 5000;\nconst int SHRINK_STEP_LIMIT = 5000;\nconst int RANDOM_SHRINK_STEP_LIMIT = 120;\nconst int STAGNATION_LIMIT = 28;\n\nlong long rect_area(const Rect &r) {\n    return 1LL * (r.x2 - r.x1) * (r.y2 - r.y1);\n}\n\ndouble single_score_from_area(long long s, long long r) {\n    if (s <= 0 || r <= 0) return 0.0;\n    long long mn = min(s, r);\n    long long mx = max(s, r);\n    double ratio = (double)mn / (double)mx;\n    return 2.0 * ratio - ratio * ratio;\n}\n\narray<int, 4> compute_expand_limits(const vector<Rect> &rects, int idx) {\n    const Rect &ri = rects[idx];\n    array<int, 4> lim = {ri.x1, BOARD_SIZE - ri.x2, ri.y1, BOARD_SIZE - ri.y2};\n    int n = rects.size();\n    for (int j = 0; j < n; ++j) if (j != idx) {\n        const Rect &rj = rects[j];\n        bool overlapY = (ri.y1 < rj.y2) && (ri.y2 > rj.y1);\n        bool overlapX = (ri.x1 < rj.x2) && (ri.x2 > rj.x1);\n        if (overlapY) {\n            if (rj.x2 <= ri.x1) lim[0] = min(lim[0], max(0, ri.x1 - rj.x2));\n            if (rj.x1 >= ri.x2) lim[1] = min(lim[1], max(0, rj.x1 - ri.x2));\n        }\n        if (overlapX) {\n            if (rj.y2 <= ri.y1) lim[2] = min(lim[2], max(0, ri.y1 - rj.y2));\n            if (rj.y1 >= ri.y2) lim[3] = min(lim[3], max(0, rj.y1 - ri.y2));\n        }\n    }\n    for (int d = 0; d < 4; ++d) lim[d] = max(lim[d], 0);\n    return lim;\n}\n\nbool grow_rect(int idx, vector<Rect> &rects, const vector<int> &target, mt19937 &rng) {\n    bool changed = false;\n    for (int iter = 0; iter < GROW_ITER_PER_RECT; ++iter) {\n        Rect &rc = rects[idx];\n        long long width = rc.x2 - rc.x1;\n        long long height = rc.y2 - rc.y1;\n        long long area = width * height;\n        long long deficit = (long long)target[idx] - area;\n        if (deficit <= 0) break;\n\n        auto lim = compute_expand_limits(rects, idx);\n        long long unit[4] = {height, height, width, width};\n\n        double bestScore = -1;\n        vector<int> dirs;\n        for (int dir = 0; dir < 4; ++dir) {\n            if (lim[dir] <= 0 || unit[dir] <= 0) continue;\n            long long potential = 1LL * lim[dir] * unit[dir];\n            long long effective = min(deficit, potential);\n            if (effective <= 0) continue;\n            double score = (double)effective;\n            if (score > bestScore + 1e-9) {\n                bestScore = score;\n                dirs.clear();\n                dirs.push_back(dir);\n            } else if (fabs(score - bestScore) <= 1e-9) {\n                dirs.push_back(dir);\n            }\n        }\n        if (dirs.empty()) break;\n        int dir = dirs[rng() % dirs.size()];\n        long long u = unit[dir];\n        long long need = (deficit + u - 1) / u;\n        long long limit = min<long long>(lim[dir], EXPAND_STEP_LIMIT);\n        if (limit <= 0) break;\n        long long w = max(1LL, min(limit, need));\n        if (dir == 0) rc.x1 -= (int)w;\n        else if (dir == 1) rc.x2 += (int)w;\n        else if (dir == 2) rc.y1 -= (int)w;\n        else rc.y2 += (int)w;\n        changed = true;\n    }\n    return changed;\n}\n\nbool shrink_rect(int idx, vector<Rect> &rects, const vector<int> &target,\n                 const vector<int> &xs, const vector<int> &ys, mt19937 &rng) {\n    bool changed = false;\n    for (int iter = 0; iter < SHRINK_ITER_PER_RECT; ++iter) {\n        Rect &rc = rects[idx];\n        long long width = rc.x2 - rc.x1;\n        long long height = rc.y2 - rc.y1;\n        long long area = width * height;\n        long long surplus = area - (long long)target[idx];\n        if (surplus <= 0) break;\n\n        int avail[4] = {\n            xs[idx] - rc.x1,\n            rc.x2 - (xs[idx] + 1),\n            ys[idx] - rc.y1,\n            rc.y2 - (ys[idx] + 1)\n        };\n        long long unit[4] = {height, height, width, width};\n\n        double bestScore = -1;\n        vector<int> dirs;\n        for (int dir = 0; dir < 4; ++dir) {\n            if (avail[dir] <= 0 || unit[dir] <= 0) continue;\n            long long potential = 1LL * avail[dir] * unit[dir];\n            long long effective = min(surplus, potential);\n            if (effective <= 0) continue;\n            double score = (double)effective;\n            if (score > bestScore + 1e-9) {\n                bestScore = score;\n                dirs.clear();\n                dirs.push_back(dir);\n            } else if (fabs(score - bestScore) <= 1e-9) {\n                dirs.push_back(dir);\n            }\n        }\n        if (dirs.empty()) break;\n        int dir = dirs[rng() % dirs.size()];\n        long long u = unit[dir];\n        long long need = (surplus + u - 1) / u;\n        long long limit = min<long long>(avail[dir], SHRINK_STEP_LIMIT);\n        if (limit <= 0) break;\n        long long w = max(1LL, min(limit, need));\n        if (dir == 0) rc.x1 += (int)w;\n        else if (dir == 1) rc.x2 -= (int)w;\n        else if (dir == 2) rc.y1 += (int)w;\n        else rc.y2 -= (int)w;\n        changed = true;\n    }\n    return changed;\n}\n\nbool shrink_phase(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                  const vector<int> &target, mt19937 &rng) {\n    int n = rects.size();\n    vector<pair<long long, int>> overs;\n    overs.reserve(n);\n    for (int i = 0; i < n; ++i) {\n        long long def = rect_area(rects[i]) - (long long)target[i];\n        if (def > 0) overs.emplace_back(def, i);\n    }\n    sort(overs.begin(), overs.end(), greater<>());\n    bool changed = false;\n    for (auto &p : overs) {\n        if (shrink_rect(p.second, rects, target, xs, ys, rng)) changed = true;\n    }\n    return changed;\n}\n\nbool random_shrink(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                   const vector<int> &target, mt19937 &rng,\n                   int operations, bool prefer_surplus) {\n    int n = rects.size();\n    if (operations <= 0 || n == 0) return false;\n    vector<int> pool;\n    pool.reserve(n);\n    if (prefer_surplus) {\n        for (int i = 0; i < n; ++i)\n            if (rect_area(rects[i]) > (long long)target[i]) pool.push_back(i);\n    }\n    if (pool.empty()) {\n        pool.resize(n);\n        iota(pool.begin(), pool.end(), 0);\n    }\n    bool changed = false;\n    for (int t = 0; t < operations; ++t) {\n        int idx = pool[rng() % pool.size()];\n        Rect &rc = rects[idx];\n        int avail[4] = {\n            xs[idx] - rc.x1,\n            rc.x2 - (xs[idx] + 1),\n            ys[idx] - rc.y1,\n            rc.y2 - (ys[idx] + 1)\n        };\n        vector<int> dirs;\n        for (int d = 0; d < 4; ++d) if (avail[d] > 0) dirs.push_back(d);\n        if (dirs.empty()) continue;\n        int dir = dirs[rng() % dirs.size()];\n        int cap = min(avail[dir], RANDOM_SHRINK_STEP_LIMIT);\n        if (cap <= 0) continue;\n        int amount = 1 + (cap > 1 ? rng() % cap : 0);\n        if (dir == 0) rc.x1 += amount;\n        else if (dir == 1) rc.x2 -= amount;\n        else if (dir == 2) rc.y1 += amount;\n        else rc.y2 -= amount;\n        changed = true;\n    }\n    return changed;\n}\n\ndouble compute_score(const vector<Rect> &rects, const vector<int> &target) {\n    double sum = 0.0;\n    for (int i = 0; i < (int)rects.size(); ++i) sum += single_score_from_area(rect_area(rects[i]), target[i]);\n    return sum;\n}\n\nbool validate_rects(const vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys) {\n    int n = rects.size();\n    for (int i = 0; i < n; ++i) {\n        const Rect &r = rects[i];\n        if (r.x1 < 0 || r.x1 >= r.x2 || r.x2 > BOARD_SIZE) return false;\n        if (r.y1 < 0 || r.y1 >= r.y2 || r.y2 > BOARD_SIZE) return false;\n        if (!(r.x1 <= xs[i] && xs[i] + 1 <= r.x2)) return false;\n        if (!(r.y1 <= ys[i] && ys[i] + 1 <= r.y2)) return false;\n    }\n    for (int i = 0; i < n; ++i) for (int j = i + 1; j < n; ++j) {\n        const Rect &a = rects[i];\n        const Rect &b = rects[j];\n        if (max(a.x1, b.x1) < min(a.x2, b.x2) &&\n            max(a.y1, b.y1) < min(a.y2, b.y2)) return false;\n    }\n    return true;\n}\n\nbool reset_worst(vector<Rect> &rects, const vector<Rect> &base_rects,\n                 const vector<int> &target, int count) {\n    int n = rects.size();\n    if (count <= 0) return false;\n    vector<pair<double, int>> order;\n    order.reserve(n);\n    for (int i = 0; i < n; ++i)\n        order.emplace_back(single_score_from_area(rect_area(rects[i]), target[i]), i);\n    sort(order.begin(), order.end(), [&](const auto &a, const auto &b) {\n        if (fabs(a.first - b.first) > 1e-9) return a.first < b.first;\n        long long da = llabs(rect_area(rects[a.second]) - (long long)target[a.second]);\n        long long db = llabs(rect_area(rects[b.second]) - (long long)target[b.second]);\n        if (da != db) return da > db;\n        return a.second < b.second;\n    });\n    bool changed = false;\n    count = min(count, n);\n    for (int k = 0; k < count; ++k) {\n        int idx = order[k].second;\n        if (rects[idx].x1 == base_rects[idx].x1 &&\n            rects[idx].x2 == base_rects[idx].x2 &&\n            rects[idx].y1 == base_rects[idx].y1 &&\n            rects[idx].y2 == base_rects[idx].y2) continue;\n        rects[idx] = base_rects[idx];\n        changed = true;\n    }\n    return changed;\n}\n\nbool vertical_move(vector<Rect> &rects, vector<long long> &areas,\n                   const vector<int> &xs, const vector<int> &target,\n                   int left, int right, bool left_gets) {\n    long long height = rects[left].y2 - rects[left].y1;\n    if (height <= 0) return false;\n    int maxUnits;\n    if (left_gets) {\n        int limit_point = xs[right] - rects[right].x1;\n        int limit_width = rects[right].x2 - rects[right].x1 - 1;\n        maxUnits = min(limit_point, limit_width);\n    } else {\n        int limit_point_left = rects[left].x2 - (xs[left] + 1);\n        int limit_width_left = rects[left].x2 - rects[left].x1 - 1;\n        int limit_right_expand = rects[right].x1;\n        maxUnits = min({limit_point_left, limit_width_left, limit_right_expand});\n    }\n    if (maxUnits <= 0) return false;\n\n    vector<int> cand;\n    cand.reserve(6);\n    cand.push_back(1);\n    cand.push_back(maxUnits);\n    long long diff = left_gets ? ((long long)target[left] - areas[left])\n                               : (areas[left] - (long long)target[left]);\n    if (diff < 0) diff = 0;\n    long long approx = height > 0 ? diff / height : 0;\n    if (approx > 0) cand.push_back((int)min<long long>(maxUnits, max<long long>(1, approx)));\n    if (approx + 1 <= maxUnits) cand.push_back((int)min<long long>(maxUnits, approx + 1));\n    if (maxUnits >= 3) cand.push_back(maxUnits / 3);\n    if (maxUnits >= 2) cand.push_back((maxUnits + 1) / 2);\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n    double baseScore = single_score_from_area(areas[left], target[left]) +\n                       single_score_from_area(areas[right], target[right]);\n    double bestDelta = 1e-12;\n    int bestUnits = 0;\n    for (int units : cand) {\n        if (units <= 0 || units > maxUnits) continue;\n        long long delta = 1LL * units * height;\n        long long newL = left_gets ? areas[left] + delta : areas[left] - delta;\n        long long newR = left_gets ? areas[right] - delta : areas[right] + delta;\n        if (newL <= 0 || newR <= 0) continue;\n        double newScore = single_score_from_area(newL, target[left]) +\n                          single_score_from_area(newR, target[right]);\n        double diffScore = newScore - baseScore;\n        if (diffScore > bestDelta) {\n            bestDelta = diffScore;\n            bestUnits = units;\n        }\n    }\n    if (bestUnits > 0) {\n        long long delta = 1LL * bestUnits * height;\n        if (left_gets) {\n            rects[left].x2 += bestUnits;\n            rects[right].x1 += bestUnits;\n            areas[left] += delta;\n            areas[right] -= delta;\n        } else {\n            rects[left].x2 -= bestUnits;\n            rects[right].x1 -= bestUnits;\n            areas[left] -= delta;\n            areas[right] += delta;\n        }\n        return true;\n    }\n    return false;\n}\n\nbool horizontal_move(vector<Rect> &rects, vector<long long> &areas,\n                     const vector<int> &ys, const vector<int> &target,\n                     int bottom, int top, bool bottom_gets) {\n    long long width = rects[bottom].x2 - rects[bottom].x1;\n    if (width <= 0) return false;\n    int maxUnits;\n    if (bottom_gets) {\n        int limit_point = ys[top] - rects[top].y1;\n        int limit_height = rects[top].y2 - rects[top].y1 - 1;\n        maxUnits = min(limit_point, limit_height);\n    } else {\n        int limit_point_bottom = rects[bottom].y2 - (ys[bottom] + 1);\n        int limit_height_bottom = rects[bottom].y2 - rects[bottom].y1 - 1;\n        int limit_top_expand = rects[top].y1;\n        maxUnits = min({limit_point_bottom, limit_height_bottom, limit_top_expand});\n    }\n    if (maxUnits <= 0) return false;\n\n    vector<int> cand;\n    cand.reserve(6);\n    cand.push_back(1);\n    cand.push_back(maxUnits);\n    long long diff = bottom_gets ? ((long long)target[bottom] - areas[bottom])\n                                 : (areas[bottom] - (long long)target[bottom]);\n    if (diff < 0) diff = 0;\n    long long approx = width > 0 ? diff / width : 0;\n    if (approx > 0) cand.push_back((int)min<long long>(maxUnits, max<long long>(1, approx)));\n    if (approx + 1 <= maxUnits) cand.push_back((int)min<long long>(maxUnits, approx + 1));\n    if (maxUnits >= 3) cand.push_back(maxUnits / 3);\n    if (maxUnits >= 2) cand.push_back((maxUnits + 1) / 2);\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n    double baseScore = single_score_from_area(areas[bottom], target[bottom]) +\n                       single_score_from_area(areas[top], target[top]);\n    double bestDelta = 1e-12;\n    int bestUnits = 0;\n    for (int units : cand) {\n        if (units <= 0 || units > maxUnits) continue;\n        long long delta = 1LL * units * width;\n        long long newB = bottom_gets ? areas[bottom] + delta : areas[bottom] - delta;\n        long long newT = bottom_gets ? areas[top] - delta : areas[top] + delta;\n        if (newB <= 0 || newT <= 0) continue;\n        double newScore = single_score_from_area(newB, target[bottom]) +\n                          single_score_from_area(newT, target[top]);\n        double diffScore = newScore - baseScore;\n        if (diffScore > bestDelta) {\n            bestDelta = diffScore;\n            bestUnits = units;\n        }\n    }\n    if (bestUnits > 0) {\n        long long delta = 1LL * bestUnits * width;\n        if (bottom_gets) {\n            rects[bottom].y2 += bestUnits;\n            rects[top].y1 += bestUnits;\n            areas[bottom] += delta;\n            areas[top] -= delta;\n        } else {\n            rects[bottom].y2 -= bestUnits;\n            rects[top].y1 -= bestUnits;\n            areas[bottom] -= delta;\n            areas[top] += delta;\n        }\n        return true;\n    }\n    return false;\n}\n\nbool boundary_balance(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                      const vector<int> &target, mt19937 &rng, int rounds = 2) {\n    if (rounds <= 0) return false;\n    int n = rects.size();\n    vector<long long> areas(n);\n    for (int i = 0; i < n; ++i) areas[i] = rect_area(rects[i]);\n    vector<pair<int, int>> pairs;\n    pairs.reserve(n * (n - 1) / 2);\n    for (int i = 0; i < n; ++i)\n        for (int j = i + 1; j < n; ++j)\n            pairs.emplace_back(i, j);\n\n    bool changed = false;\n    for (int round = 0; round < rounds; ++round) {\n        shuffle(pairs.begin(), pairs.end(), rng);\n        bool any = false;\n        for (auto [i, j] : pairs) {\n            bool local = false;\n            if (rects[i].y1 == rects[j].y1 && rects[i].y2 == rects[j].y2) {\n                if (rects[i].x2 == rects[j].x1) {\n                    long long defI = (long long)target[i] - areas[i];\n                    long long defJ = (long long)target[j] - areas[j];\n                    if (defI > 0 && defJ < 0) local |= vertical_move(rects, areas, xs, target, i, j, true);\n                    if ((long long)target[i] - areas[i] < 0 &&\n                        (long long)target[j] - areas[j] > 0)\n                        local |= vertical_move(rects, areas, xs, target, i, j, false);\n                } else if (rects[j].x2 == rects[i].x1) {\n                    long long defI = (long long)target[i] - areas[i];\n                    long long defJ = (long long)target[j] - areas[j];\n                    if (defJ > 0 && defI < 0) local |= vertical_move(rects, areas, xs, target, j, i, true);\n                    if ((long long)target[j] - areas[j] < 0 &&\n                        (long long)target[i] - areas[i] > 0)\n                        local |= vertical_move(rects, areas, xs, target, j, i, false);\n                }\n            }\n            if (rects[i].x1 == rects[j].x1 && rects[i].x2 == rects[j].x2) {\n                if (rects[i].y2 == rects[j].y1) {\n                    long long defI = (long long)target[i] - areas[i];\n                    long long defJ = (long long)target[j] - areas[j];\n                    if (defI > 0 && defJ < 0) local |= horizontal_move(rects, areas, ys, target, i, j, true);\n                    if ((long long)target[i] - areas[i] < 0 &&\n                        (long long)target[j] - areas[j] > 0)\n                        local |= horizontal_move(rects, areas, ys, target, i, j, false);\n                } else if (rects[j].y2 == rects[i].y1) {\n                    long long defI = (long long)target[i] - areas[i];\n                    long long defJ = (long long)target[j] - areas[j];\n                    if (defJ > 0 && defI < 0) local |= horizontal_move(rects, areas, ys, target, j, i, true);\n                    if ((long long)target[j] - areas[j] < 0 &&\n                        (long long)target[i] - areas[i] > 0)\n                        local |= horizontal_move(rects, areas, ys, target, j, i, false);\n                }\n            }\n            any |= local;\n        }\n        if (!any) break;\n        changed |= any;\n    }\n    return changed;\n}\n\nvector<Rect> build_initial_rects_randomized(const vector<int> &xs, const vector<int> &ys,\n                                            const vector<int> &rs, mt19937 &rng,\n                                            double noise_strength);\n\nstruct AttemptResult {\n    vector<Rect> rects;\n    double score;\n};\n\nAttemptResult run_attempt(const vector<Rect> &start_rects, const vector<Rect> &base_rects,\n                          const vector<int> &xs, const vector<int> &ys,\n                          const vector<int> &target, mt19937 &rng,\n                          chrono::steady_clock::time_point deadline) {\n    vector<Rect> rects = start_rects;\n    vector<Rect> best_rect = rects;\n    double best_score = compute_score(rects, target);\n    int n = rects.size();\n    vector<long long> defs(n);\n    int stagnation = 0;\n    int pass = 0;\n\n    while (true) {\n        if ((pass & 7) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n        for (int i = 0; i < n; ++i) defs[i] = (long long)target[i] - rect_area(rects[i]);\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (defs[a] != defs[b]) return defs[a] > defs[b];\n            return a < b;\n        });\n\n        bool changedExp = false;\n        for (int idx : order) if (grow_rect(idx, rects, target, rng)) changedExp = true;\n        bool changedShrink = shrink_phase(rects, xs, ys, target, rng);\n        bool changed = changedExp || changedShrink;\n\n        if (!changed) {\n            stagnation++;\n            if (stagnation % 4 == 0) {\n                int ops = max(1, n / 3);\n                if (random_shrink(rects, xs, ys, target, rng, ops, true)) {\n                    changed = true;\n                    stagnation = max(0, stagnation - 2);\n                }\n            }\n            if (!changed && stagnation > STAGNATION_LIMIT) {\n                int batch = max(1, n / 8);\n                if (reset_worst(rects, base_rects, target, batch)) {\n                    stagnation = 0;\n                    pass++;\n                    continue;\n                } else {\n                    rects = best_rect;\n                    random_shrink(rects, xs, ys, target, rng, max(1, n / 2), false);\n                    stagnation = 0;\n                    pass++;\n                    continue;\n                }\n            }\n        } else stagnation = 0;\n\n        double cur_score = compute_score(rects, target);\n        if (cur_score > best_score + 1e-9) {\n            best_score = cur_score;\n            best_rect = rects;\n        }\n        pass++;\n        if (chrono::steady_clock::now() >= deadline) break;\n    }\n\n    boundary_balance(rects, xs, ys, target, rng, 2);\n    double final_score = compute_score(rects, target);\n    if (final_score > best_score + 1e-9) {\n        best_score = final_score;\n        best_rect = rects;\n    }\n    return {best_rect, best_score};\n}\n\nvector<Rect> build_initial_rects_randomized(const vector<int> &xs, const vector<int> &ys,\n                                            const vector<int> &rs, mt19937 &rng,\n                                            double noise_strength) {\n    int n = xs.size();\n    vector<Rect> res(n);\n    uniform_real_distribution<double> uni(0.0, 1.0);\n    function<void(const vector<int>&, int, int, int, int)> dfs =\n        [&](const vector<int> &idxs, int x1, int y1, int x2, int y2) {\n            if (idxs.empty()) return;\n            if (idxs.size() == 1) {\n                res[idxs[0]] = {x1, y1, x2, y2};\n                return;\n            }\n            long long total = 0;\n            for (int id : idxs) total += rs[id];\n            int width = x2 - x1;\n            int height = y2 - y1;\n\n            auto attempt_split = [&](bool useX) -> bool {\n                if (useX ? width < 2 : height < 2) return false;\n                vector<int> order = idxs;\n                if (useX) {\n                    sort(order.begin(), order.end(), [&](int a, int b) {\n                        if (xs[a] != xs[b]) return xs[a] < xs[b];\n                        return ys[a] < ys[b];\n                    });\n                } else {\n                    sort(order.begin(), order.end(), [&](int a, int b) {\n                        if (ys[a] != ys[b]) return ys[a] < ys[b];\n                        return xs[a] < xs[b];\n                    });\n                }\n                vector<long long> pref(order.size() + 1, 0);\n                for (int i = 0; i < (int)order.size(); ++i) pref[i + 1] = pref[i] + rs[order[i]];\n                double ratio_target = 0.5;\n                if (noise_strength > 1e-9) {\n                    double val = (uni(rng) - 0.5) * 2.0;\n                    ratio_target += val * 0.15 * noise_strength;\n                    ratio_target = min(0.85, max(0.15, ratio_target));\n                }\n                long long desired_sum = (long long)llround(total * ratio_target);\n                desired_sum = max(1LL, min(total - 1, desired_sum));\n                int cut = int(lower_bound(pref.begin(), pref.end(), desired_sum) - pref.begin());\n                if (cut <= 0 || cut >= (int)order.size()) cut = (int)order.size() / 2;\n                long long sum_left = pref[cut];\n                if (sum_left == 0 || sum_left == total) return false;\n                vector<int> left(order.begin(), order.begin() + cut);\n                vector<int> right(order.begin() + cut, order.end());\n                if (useX) {\n                    int max_left = -1, min_right = BOARD_SIZE + 1;\n                    for (int id : left) max_left = max(max_left, xs[id]);\n                    for (int id : right) min_right = min(min_right, xs[id]);\n                    int low = max(x1 + 1, max_left + 1);\n                    int high = min(x2 - 1, min_right);\n                    if (low > high) return false;\n                    long double ratio = (long double)sum_left / total;\n                    if (noise_strength > 1e-9) {\n                        double jitter = (uni(rng) - 0.5) * 2.0 * 0.25 * noise_strength;\n                        ratio = min(0.9L, max(0.1L, ratio + jitter));\n                    }\n                    int desired = x1 + (int)llround(width * ratio);\n                    desired = min(max(desired, low), high);\n                    dfs(left, x1, y1, desired, y2);\n                    dfs(right, desired, y1, x2, y2);\n                } else {\n                    int max_left = -1, min_right = BOARD_SIZE + 1;\n                    for (int id : left) max_left = max(max_left, ys[id]);\n                    for (int id : right) min_right = min(min_right, ys[id]);\n                    int low = max(y1 + 1, max_left + 1);\n                    int high = min(y2 - 1, min_right);\n                    if (low > high) return false;\n                    long double ratio = (long double)sum_left / total;\n                    if (noise_strength > 1e-9) {\n                        double jitter = (uni(rng) - 0.5) * 2.0 * 0.25 * noise_strength;\n                        ratio = min(0.9L, max(0.1L, ratio + jitter));\n                    }\n                    int desired = y1 + (int)llround(height * ratio);\n                    desired = min(max(desired, low), high);\n                    dfs(left, x1, y1, x2, desired);\n                    dfs(right, x1, desired, x2, y2);\n                }\n                return true;\n            };\n\n            bool axis = (width >= height);\n            if (noise_strength > 1e-9) {\n                double flip_prob = min(0.35, 0.1 + 0.25 * noise_strength);\n                if (uni(rng) < flip_prob) axis = !axis;\n            }\n            if (attempt_split(axis)) return;\n            if (attempt_split(!axis)) return;\n            if (attempt_split(true)) return;\n            if (attempt_split(false)) return;\n\n            for (int id : idxs) res[id] = {xs[id], ys[id], xs[id] + 1, ys[id] + 1};\n        };\n\n    vector<int> root(n);\n    iota(root.begin(), root.end(), 0);\n    dfs(root, 0, 0, BOARD_SIZE, BOARD_SIZE);\n    return res;\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> xs(n), ys(n), rs(n);\n    for (int i = 0; i < n; ++i) cin >> xs[i] >> ys[i] >> rs[i];\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    vector<double> noise_levels = {0.0, 0.25, 0.5, 0.75};\n    vector<vector<Rect>> base_candidates;\n    for (double noise : noise_levels) {\n        int repeats = (noise < 1e-9) ? 1 : 2;\n        for (int rep = 0; rep < repeats; ++rep)\n            base_candidates.push_back(build_initial_rects_randomized(xs, ys, rs, rng, noise));\n    }\n    if (base_candidates.empty())\n        base_candidates.push_back(build_initial_rects_randomized(xs, ys, rs, rng, 0.0));\n\n    int base_count = base_candidates.size();\n    int primary_idx = 0;\n    double primary_score = -1.0;\n    for (int i = 0; i < base_count; ++i) {\n        double sc = compute_score(base_candidates[i], rs);\n        if (sc > primary_score) {\n            primary_score = sc;\n            primary_idx = i;\n        }\n    }\n    const vector<Rect> &primary_base = base_candidates[primary_idx];\n    vector<Rect> best = primary_base;\n    double best_score = primary_score;\n\n    const double GLOBAL_LIMIT = 4.85;\n    auto global_start = chrono::steady_clock::now();\n    auto global_deadline = global_start + chrono::duration_cast<chrono::steady_clock::duration>(\n                                           chrono::duration<double>(GLOBAL_LIMIT));\n\n    int attempt = 0;\n    while (true) {\n        auto now = chrono::steady_clock::now();\n        if (now >= global_deadline) break;\n        double remain = chrono::duration<double>(global_deadline - now).count();\n        if (remain <= 0.05) break;\n        double budget = min(remain - 0.02, 0.75 + 0.25 * (attempt % 4));\n        if (budget <= 0.02) budget = remain - 0.02;\n        if (budget <= 0.0) break;\n        auto attempt_deadline = now + chrono::duration_cast<chrono::steady_clock::duration>(\n                                        chrono::duration<double>(budget));\n        if (attempt_deadline > global_deadline) attempt_deadline = global_deadline;\n\n        int base_idx = attempt % base_count;\n        const vector<Rect> &base_cur = base_candidates[base_idx];\n        vector<Rect> seed = base_cur;\n        random_shrink(seed, xs, ys, rs, rng, max(1, n / 2), false);\n\n        AttemptResult res = run_attempt(seed, base_cur, xs, ys, rs, rng, attempt_deadline);\n        if (res.score > best_score + 1e-9) {\n            best_score = res.score;\n            best = res.rects;\n        }\n        attempt++;\n    }\n\n    auto now = chrono::steady_clock::now();\n    if (now < global_deadline - chrono::duration_cast<chrono::steady_clock::duration>(\n                                 chrono::duration<double>(0.04))) {\n        auto polish_deadline = min(global_deadline,\n            now + chrono::duration_cast<chrono::steady_clock::duration>(\n                      chrono::duration<double>(0.35)));\n        AttemptResult res = run_attempt(best, primary_base, xs, ys, rs, rng, polish_deadline);\n        if (res.score > best_score + 1e-9) {\n            best_score = res.score;\n            best = res.rects;\n        }\n    }\n\n    if (boundary_balance(best, xs, ys, rs, rng, 4)) {\n        double sc = compute_score(best, rs);\n        if (sc > best_score) best_score = sc;\n    }\n\n    if (!validate_rects(best, xs, ys)) best = primary_base;\n\n    for (const auto &r : best) {\n        cout << r.x1 << ' ' << r.y1 << ' ' << r.x2 << ' ' << r.y2 << '\\n';\n    }\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int N2 = N * N;\n    static constexpr int MAX_TILES = 2500;\n    using VisitBitset = bitset<MAX_TILES>;\n\n    struct Neighbor {\n        int to;\n        char dir;\n    };\n    struct Node {\n        VisitBitset visited;\n        int pos = 0;\n        int score = 0;\n        int parent = -1;\n        char move = '?';\n        int depth = 0;\n    };\n    struct Candidate {\n        double eval;\n        int idx;\n    };\n    struct Features {\n        int mobility = 0;\n        int nei1 = 0;\n        int nei2 = 0;\n        int two = 0;\n    };\n\n    vector<int> tileOf;\n    vector<int> value;\n    vector<vector<Neighbor>> adj;\n    int startIdx = 0;\n\n    mt19937_64 rng;\n    chrono::steady_clock::time_point timeStart;\n    string bestPath;\n    int bestScore = 0;\n\n    const double TIME_LIMIT = 1.95;\n    const double LENGTH_WEIGHT = 8.0;\n    const double MOBILITY_WEIGHT = 16.0;\n    const double NEI1_WEIGHT = 1.1;\n    const double NEI2_WEIGHT = 0.4;\n    const double TWO_WEIGHT = 0.6;\n    const double RANDOM_WEIGHT = 0.8;\n\n    const double GREEDY_VALUE_WEIGHT = 1.0;\n    const double GREEDY_MOB_WEIGHT = 20.0;\n    const double GREEDY_NEI_WEIGHT = 0.9;\n    const double GREEDY_TWO_WEIGHT = 0.4;\n    const double GREEDY_RANDOM_WEIGHT = 0.4;\n    const int MAX_GREEDY_STEPS = 1500;\n    const int MAX_GREEDY_CANDIDATES = 3;\n\n    inline double rand01() {\n        static constexpr double INV = 1.0 / (1ULL << 53);\n        return (rng() >> 11) * INV;\n    }\n    inline double elapsed() const {\n        using namespace chrono;\n        return duration<double>(steady_clock::now() - timeStart).count();\n    }\n    inline bool timeUp() const {\n        return elapsed() > TIME_LIMIT;\n    }\n\n    Features calcFeatures(const VisitBitset &vis, int pos) const {\n        Features feat;\n        for (const auto &nb : adj[pos]) {\n            if (vis.test(tileOf[nb.to])) continue;\n            ++feat.mobility;\n            int val = value[nb.to];\n            if (val >= feat.nei1) {\n                feat.nei2 = feat.nei1;\n                feat.nei1 = val;\n            } else if (val > feat.nei2) {\n                feat.nei2 = val;\n            }\n            for (const auto &nb2 : adj[nb.to]) {\n                if (vis.test(tileOf[nb2.to])) continue;\n                int val2 = value[nb2.to];\n                if (val2 > feat.two) feat.two = val2;\n            }\n        }\n        return feat;\n    }\n\n    string buildPath(const vector<Node> &pool, int idx) const {\n        string res;\n        res.reserve(pool[idx].depth);\n        int cur = idx;\n        while (cur != -1) {\n            const Node &node = pool[cur];\n            if (node.parent == -1) break;\n            res.push_back(node.move);\n            cur = node.parent;\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    void greedyExtend(const Node &startNode, string path) {\n        VisitBitset vis = startNode.visited;\n        int pos = startNode.pos;\n        int score = startNode.score;\n        array<Neighbor, 4> moveBuf;\n        int steps = 0;\n        while (!timeUp() && steps < MAX_GREEDY_STEPS) {\n            int moveCount = 0;\n            for (const auto &nb : adj[pos]) {\n                if (vis.test(tileOf[nb.to])) continue;\n                moveBuf[moveCount++] = nb;\n            }\n            if (moveCount == 0) break;\n            double bestEval = -1e100;\n            int bestIdx = -1;\n            VisitBitset bestVis;\n            for (int i = 0; i < moveCount; ++i) {\n                VisitBitset nextVis = vis;\n                nextVis.set(tileOf[moveBuf[i].to]);\n                Features feat = calcFeatures(nextVis, moveBuf[i].to);\n                double eval = GREEDY_VALUE_WEIGHT * value[moveBuf[i].to]\n                            + GREEDY_MOB_WEIGHT * feat.mobility\n                            + GREEDY_NEI_WEIGHT * feat.nei1\n                            + GREEDY_TWO_WEIGHT * feat.two\n                            + GREEDY_RANDOM_WEIGHT * rand01();\n                if (eval > bestEval) {\n                    bestEval = eval;\n                    bestIdx = i;\n                    bestVis = nextVis;\n                }\n            }\n            if (bestIdx == -1) break;\n            const Neighbor &chosen = moveBuf[bestIdx];\n            vis = bestVis;\n            pos = chosen.to;\n            score += value[pos];\n            path.push_back(chosen.dir);\n            ++steps;\n        }\n        if (score > bestScore || (score == bestScore && path.size() > bestPath.size())) {\n            bestScore = score;\n            bestPath = std::move(path);\n        }\n    }\n\n    void runBeam(int beamWidth) {\n        if (timeUp()) return;\n        const size_t MAX_POOL_RESERVE = 220000;\n        vector<Node> pool;\n        size_t reserveSize = min<size_t>(static_cast<size_t>(beamWidth) * 900 + 1000ULL, MAX_POOL_RESERVE);\n        pool.reserve(reserveSize);\n\n        pool.emplace_back();\n        Node &root = pool.back();\n        root.visited.reset();\n        root.visited.set(tileOf[startIdx]);\n        root.pos = startIdx;\n        root.score = value[startIdx];\n        root.parent = -1;\n        root.move = '?';\n        root.depth = 0;\n\n        int runBestIdx = 0;\n        int runBestScore = root.score;\n\n        vector<int> current;\n        current.reserve(beamWidth);\n        current.push_back(0);\n\n        vector<Candidate> candBuf;\n        candBuf.reserve(beamWidth * 4 + 10);\n\n        array<Neighbor, 4> moveBuf;\n        bool forceStop = false;\n\n        while (!current.empty() && !forceStop) {\n            if (timeUp()) break;\n            candBuf.clear();\n            for (int idx : current) {\n                if (timeUp()) { forceStop = true; break; }\n                VisitBitset parentVis = pool[idx].visited;\n                int pos = pool[idx].pos;\n                int baseScore = pool[idx].score;\n                int depth = pool[idx].depth;\n\n                int moveCount = 0;\n                for (const auto &nb : adj[pos]) {\n                    if (parentVis.test(tileOf[nb.to])) continue;\n                    moveBuf[moveCount++] = nb;\n                }\n                if (moveCount == 0) continue;\n                if (moveCount > 1) {\n                    shuffle(moveBuf.begin(), moveBuf.begin() + moveCount, rng);\n                }\n                for (int mi = 0; mi < moveCount; ++mi) {\n                    if (timeUp()) { forceStop = true; break; }\n                    const Neighbor &nb = moveBuf[mi];\n                    pool.emplace_back();\n                    Node &child = pool.back();\n                    child.visited = parentVis;\n                    child.visited.set(tileOf[nb.to]);\n                    child.pos = nb.to;\n                    child.score = baseScore + value[nb.to];\n                    child.parent = idx;\n                    child.move = nb.dir;\n                    child.depth = depth + 1;\n                    int childIdx = (int)pool.size() - 1;\n\n                    Features feat = calcFeatures(child.visited, child.pos);\n                    double eval = child.score\n                                + LENGTH_WEIGHT * child.depth\n                                + MOBILITY_WEIGHT * feat.mobility\n                                + NEI1_WEIGHT * feat.nei1\n                                + NEI2_WEIGHT * feat.nei2\n                                + TWO_WEIGHT * feat.two\n                                + RANDOM_WEIGHT * rand01();\n\n                    candBuf.push_back({eval, childIdx});\n\n                    if (child.score > runBestScore ||\n                        (child.score == runBestScore && child.depth > pool[runBestIdx].depth)) {\n                        runBestScore = child.score;\n                        runBestIdx = childIdx;\n                    }\n                }\n                if (forceStop) break;\n            }\n            if (forceStop || candBuf.empty()) break;\n\n            auto cmp = [](const Candidate &a, const Candidate &b) { return a.eval > b.eval; };\n            if ((int)candBuf.size() > beamWidth) {\n                partial_sort(candBuf.begin(), candBuf.begin() + beamWidth, candBuf.end(), cmp);\n                candBuf.resize(beamWidth);\n            } else {\n                sort(candBuf.begin(), candBuf.end(), cmp);\n            }\n\n            current.clear();\n            current.reserve(candBuf.size());\n            for (const auto &cand : candBuf) current.push_back(cand.idx);\n        }\n\n        string runBestPath = buildPath(pool, runBestIdx);\n        if (runBestScore > bestScore ||\n            (runBestScore == bestScore && runBestPath.size() > bestPath.size())) {\n            bestScore = runBestScore;\n            bestPath = runBestPath;\n        }\n\n        if (!timeUp()) {\n            vector<int> greedies;\n            greedies.reserve(MAX_GREEDY_CANDIDATES);\n            greedies.push_back(runBestIdx);\n            for (int idx : current) {\n                if ((int)greedies.size() >= MAX_GREEDY_CANDIDATES) break;\n                bool dup = false;\n                for (int g : greedies) if (g == idx) { dup = true; break; }\n                if (!dup) greedies.push_back(idx);\n            }\n            for (int idx : greedies) {\n                if (timeUp()) break;\n                string path = buildPath(pool, idx);\n                greedyExtend(pool[idx], std::move(path));\n            }\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        int si, sj;\n        if (!(cin >> si >> sj)) return;\n        tileOf.resize(N2);\n        int maxTile = -1;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int t;\n                cin >> t;\n                int idx = i * N + j;\n                tileOf[idx] = t;\n                maxTile = max(maxTile, t);\n            }\n        }\n        [[maybe_unused]] int tileCount = maxTile + 1;\n        value.resize(N2);\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int p;\n                cin >> p;\n                value[i * N + j] = p;\n            }\n        }\n        startIdx = si * N + sj;\n\n        adj.assign(N2, {});\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n        const char dirChar[4] = {'U', 'D', 'L', 'R'};\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int idx = i * N + j;\n                for (int d = 0; d < 4; ++d) {\n                    int ni = i + di[d];\n                    int nj = j + dj[d];\n                    if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                    int nidx = ni * N + nj;\n                    adj[idx].push_back({nidx, dirChar[d]});\n                }\n            }\n        }\n\n        bestScore = value[startIdx];\n        bestPath.clear();\n\n        timeStart = chrono::steady_clock::now();\n        rng.seed(chrono::steady_clock::now().time_since_epoch().count());\n\n        vector<int> beamOptions = {60, 80, 100};\n        int iteration = 0;\n        while (!timeUp()) {\n            int bw = beamOptions[iteration % beamOptions.size()];\n            runBeam(bw);\n            ++iteration;\n        }\n\n        cout << bestPath << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\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    static constexpr int HOR = H * (W - 1);\n    static constexpr int VER = (H - 1) * W;\n    static constexpr int EDGE_CNT = HOR + VER;\n\n    // Estimation parameters\n    const double INIT_MEAN = 5000.0;\n    const double INIT_PERT = 200.0;\n\n    const double BASE_VAR = 1.0e7;\n    const double INFO_OFFSET = 0.5;\n    const double MIN_VAR = 1.0e4;\n    const double MAX_INFO = 600.0;\n    const double INFO_GAIN_BASE = 1.2;\n\n    const double MEAS_NOISE_COEFF = (0.2 * 0.2) / 12.0;\n    const double MEAS_VAR_FLOOR = 1e5;\n\n    const double MIN_EDGE_WEIGHT = 900.0;\n    const double MAX_EDGE_WEIGHT = 9200.0;\n    const double MIN_SEARCH_WEIGHT = 1.0;\n\n    const double ALPHA_MIN = 0.05;\n    const double ALPHA_MAX = 0.9;\n\n    // Exploration\n    const double USE_EXPLORE_COEFF = 520.0;\n    const double INFO_EXPLORE_COEFF = 360.0;\n    const double EXPLORE_BASE = 1.0;\n\n    // Smoothing parameters\n    const double SMOOTH_SELF_BIAS = 0.6;\n    const double SMOOTH_NEIGH_BIAS = 1.5;\n    const double SMOOTH_PULL = 0.55;\n    const double SMOOTH_DENOM = 0.8;\n    const double SMOOTH_MAX_PUSH = 0.45;\n    const double GLOBAL_SMOOTH_SCALE = 800.0;\n    const double GLOBAL_SMOOTH_MIN = 0.25;\n    const double SMOOTH_INFO_REQ = 1.0;\n    const int ROUGH_MIN_COUNT = 80;\n    const double LOCAL_DIFF_SCALE = 900.0;\n    const double MIN_LOCAL_GATE = 0.08;\n    const double LOW_INFO_THRESHOLD = 0.25;\n    const double LOW_INFO_MULT = 1.35;\n\n    vector<double> edgeWeight;\n    vector<int> edgeUse;\n    vector<double> edgeInfo;\n\n    vector<double> dist;\n    vector<int> prevNode;\n    vector<int> prevEdge;\n    vector<char> prevMove;\n\n    vector<double> tmpHor;\n    vector<double> tmpVer;\n\n    mt19937 rng;\n\n    Solver()\n        : edgeWeight(EDGE_CNT),\n          edgeUse(EDGE_CNT, 0),\n          edgeInfo(EDGE_CNT, 0.0),\n          dist(N),\n          prevNode(N),\n          prevEdge(N),\n          prevMove(N),\n          tmpHor(HOR),\n          tmpVer(VER) {\n        rng.seed(chrono::steady_clock::now().time_since_epoch().count());\n        uniform_real_distribution<double> pert(-INIT_PERT, INIT_PERT);\n        for (int i = 0; i < EDGE_CNT; ++i) {\n            edgeWeight[i] = INIT_MEAN + pert(rng);\n        }\n    }\n\n    inline int nodeId(int i, int j) const { return i * W + j; }\n    inline int horId(int i, int j) const { return i * (W - 1) + j; }\n    inline int verId(int i, int j) const { return HOR + i * W + j; }\n\n    inline double clampWeight(double v) const {\n        if (v < MIN_EDGE_WEIGHT) return MIN_EDGE_WEIGHT;\n        if (v > MAX_EDGE_WEIGHT) return MAX_EDGE_WEIGHT;\n        return v;\n    }\n\n    double edgeCostForSearch(int eid) const {\n        double useBias = USE_EXPLORE_COEFF / sqrt(edgeUse[eid] + EXPLORE_BASE);\n        double infoBias = INFO_EXPLORE_COEFF / sqrt(edgeInfo[eid] + 1.0);\n        double w = edgeWeight[eid] - useBias - infoBias;\n        if (w < MIN_SEARCH_WEIGHT) w = MIN_SEARCH_WEIGHT;\n        return w;\n    }\n\n    void buildFallback(int si, int sj, int ti, int tj, string &path, vector<int> &pathEdges) {\n        path.clear();\n        pathEdges.clear();\n        int ci = si, cj = sj;\n        auto pushStep = [&](char mv) {\n            path.push_back(mv);\n            if (mv == 'U') {\n                pathEdges.push_back(verId(ci - 1, cj));\n                --ci;\n            } else if (mv == 'D') {\n                pathEdges.push_back(verId(ci, cj));\n                ++ci;\n            } else if (mv == 'L') {\n                pathEdges.push_back(horId(ci, cj - 1));\n                --cj;\n            } else {\n                pathEdges.push_back(horId(ci, cj));\n                ++cj;\n            }\n        };\n        while (ci < ti) pushStep('D');\n        while (ci > ti) pushStep('U');\n        while (cj < tj) pushStep('R');\n        while (cj > tj) pushStep('L');\n    }\n\n    void computePath(int si, int sj, int ti, int tj, string &path, vector<int> &pathEdges) {\n        path.clear();\n        pathEdges.clear();\n        int start = nodeId(si, sj);\n        int target = nodeId(ti, tj);\n        const double INF = 1e100;\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevNode.begin(), prevNode.end(), -1);\n        fill(prevEdge.begin(), prevEdge.end(), -1);\n        fill(prevMove.begin(), prevMove.end(), 0);\n\n        struct PQNode {\n            double dist;\n            int node;\n            bool operator<(const PQNode &o) const { return dist > o.dist; }\n        };\n\n        priority_queue<PQNode> pq;\n        dist[start] = 0.0;\n        pq.push({0.0, start});\n\n        while (!pq.empty()) {\n            auto cur = pq.top();\n            pq.pop();\n            if (cur.dist > dist[cur.node]) continue;\n            if (cur.node == target) break;\n            int i = cur.node / W;\n            int j = cur.node % W;\n\n            if (i > 0) {\n                int nb = cur.node - W;\n                int eid = verId(i - 1, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'U';\n                    pq.push({nd, nb});\n                }\n            }\n            if (i + 1 < H) {\n                int nb = cur.node + W;\n                int eid = verId(i, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'D';\n                    pq.push({nd, nb});\n                }\n            }\n            if (j > 0) {\n                int nb = cur.node - 1;\n                int eid = horId(i, j - 1);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'L';\n                    pq.push({nd, nb});\n                }\n            }\n            if (j + 1 < W) {\n                int nb = cur.node + 1;\n                int eid = horId(i, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'R';\n                    pq.push({nd, nb});\n                }\n            }\n        }\n\n        if (start != target && prevEdge[target] == -1) {\n            buildFallback(si, sj, ti, tj, path, pathEdges);\n            return;\n        }\n        int cur = target;\n        while (cur != start) {\n            int pe = prevEdge[cur];\n            if (pe == -1) {\n                buildFallback(si, sj, ti, tj, path, pathEdges);\n                return;\n            }\n            path.push_back(prevMove[cur]);\n            pathEdges.push_back(pe);\n            cur = prevNode[cur];\n        }\n        reverse(path.begin(), path.end());\n        reverse(pathEdges.begin(), pathEdges.end());\n    }\n\n    double computeSmoothFactor() const {\n        double sumDiff = 0.0;\n        int cnt = 0;\n\n        for (int i = 0; i < H; ++i) {\n            for (int j = 1; j < W - 1; ++j) {\n                int eid = horId(i, j);\n                int left = horId(i, j - 1);\n                double minInfo = min(edgeInfo[eid], edgeInfo[left]);\n                if (minInfo < SMOOTH_INFO_REQ) continue;\n                sumDiff += fabs(edgeWeight[eid] - edgeWeight[left]);\n                ++cnt;\n            }\n        }\n        for (int j = 0; j < W; ++j) {\n            for (int i = 1; i < H - 1; ++i) {\n                int eid = verId(i, j);\n                int up = verId(i - 1, j);\n                double minInfo = min(edgeInfo[eid], edgeInfo[up]);\n                if (minInfo < SMOOTH_INFO_REQ) continue;\n                sumDiff += fabs(edgeWeight[eid] - edgeWeight[up]);\n                ++cnt;\n            }\n        }\n\n        if (cnt < ROUGH_MIN_COUNT) return 1.0;\n        double avg = sumDiff / cnt;\n        double factor = 1.0 / (1.0 + avg / GLOBAL_SMOOTH_SCALE);\n        if (factor < GLOBAL_SMOOTH_MIN) factor = GLOBAL_SMOOTH_MIN;\n        if (factor > 1.0) factor = 1.0;\n        return factor;\n    }\n\n    void smoothHorizontal(double globalFactor) {\n        for (int i = 0; i < H; ++i) {\n            for (int j = 0; j < W - 1; ++j) {\n                int eid = horId(i, j);\n                double sum = (edgeInfo[eid] + SMOOTH_SELF_BIAS) * edgeWeight[eid];\n                double denom = edgeInfo[eid] + SMOOTH_SELF_BIAS;\n\n                auto addNeighbor = [&](int nj) {\n                    int nid = horId(i, nj);\n                    double diff = fabs(edgeWeight[eid] - edgeWeight[nid]);\n                    double gate = 1.0 / (1.0 + diff / LOCAL_DIFF_SCALE);\n                    if (gate < MIN_LOCAL_GATE) gate = MIN_LOCAL_GATE;\n                    double w = (edgeInfo[nid] + SMOOTH_NEIGH_BIAS) * gate;\n                    sum += w * edgeWeight[nid];\n                    denom += w;\n                };\n\n                if (j > 0) addNeighbor(j - 1);\n                if (j + 1 < W - 1) addNeighbor(j + 1);\n\n                double avg = sum / denom;\n                double push = SMOOTH_PULL / (edgeInfo[eid] + SMOOTH_DENOM);\n                if (edgeInfo[eid] < LOW_INFO_THRESHOLD) push *= LOW_INFO_MULT;\n                push = min(push, SMOOTH_MAX_PUSH);\n                push *= globalFactor;\n\n                double newVal = edgeWeight[eid] + push * (avg - edgeWeight[eid]);\n                tmpHor[eid] = clampWeight(newVal);\n            }\n        }\n        for (int i = 0; i < HOR; ++i) edgeWeight[i] = tmpHor[i];\n    }\n\n    void smoothVertical(double globalFactor) {\n        for (int j = 0; j < W; ++j) {\n            for (int i = 0; i < H - 1; ++i) {\n                int eid = verId(i, j);\n                double sum = (edgeInfo[eid] + SMOOTH_SELF_BIAS) * edgeWeight[eid];\n                double denom = edgeInfo[eid] + SMOOTH_SELF_BIAS;\n\n                auto addNeighbor = [&](int ni) {\n                    int nid = verId(ni, j);\n                    double diff = fabs(edgeWeight[eid] - edgeWeight[nid]);\n                    double gate = 1.0 / (1.0 + diff / LOCAL_DIFF_SCALE);\n                    if (gate < MIN_LOCAL_GATE) gate = MIN_LOCAL_GATE;\n                    double w = (edgeInfo[nid] + SMOOTH_NEIGH_BIAS) * gate;\n                    sum += w * edgeWeight[nid];\n                    denom += w;\n                };\n\n                if (i > 0) addNeighbor(i - 1);\n                if (i + 1 < H - 1) addNeighbor(i + 1);\n\n                double avg = sum / denom;\n                double push = SMOOTH_PULL / (edgeInfo[eid] + SMOOTH_DENOM);\n                if (edgeInfo[eid] < LOW_INFO_THRESHOLD) push *= LOW_INFO_MULT;\n                push = min(push, SMOOTH_MAX_PUSH);\n                push *= globalFactor;\n\n                double newVal = edgeWeight[eid] + push * (avg - edgeWeight[eid]);\n                int idx = i * W + j;\n                tmpVer[idx] = clampWeight(newVal);\n            }\n        }\n        for (int i = 0; i < VER; ++i) edgeWeight[HOR + i] = tmpVer[i];\n    }\n\n    void smoothEstimates() {\n        double factor = computeSmoothFactor();\n        smoothHorizontal(factor);\n        smoothVertical(factor);\n    }\n\n    void update(const vector<int> &pathEdges, double measurement) {\n        if (pathEdges.empty()) return;\n\n        size_t m = pathEdges.size();\n        vector<double> vars;\n        vars.reserve(m);\n\n        double predicted = 0.0;\n        double sumVar = 0.0;\n        for (int eid : pathEdges) {\n            predicted += edgeWeight[eid];\n            double var = BASE_VAR / (edgeInfo[eid] + INFO_OFFSET);\n            if (var < MIN_VAR) var = MIN_VAR;\n            vars.push_back(var);\n            sumVar += var;\n        }\n        if (sumVar <= 0.0) sumVar = MIN_VAR;\n\n        double residual = measurement - predicted;\n        double safePred = max(predicted, 1.0);\n        double measurementVar = MEAS_NOISE_COEFF * safePred * safePred + MEAS_VAR_FLOOR;\n        double alpha = sumVar / (sumVar + measurementVar);\n        if (alpha < ALPHA_MIN) alpha = ALPHA_MIN;\n        if (alpha > ALPHA_MAX) alpha = ALPHA_MAX;\n\n        double scale = alpha * residual / sumVar;\n        for (size_t idx = 0; idx < m; ++idx) {\n            int eid = pathEdges[idx];\n            double delta = vars[idx] * scale;\n            edgeWeight[eid] = clampWeight(edgeWeight[eid] + delta);\n        }\n\n        double invSumVar = 1.0 / sumVar;\n        for (size_t idx = 0; idx < m; ++idx) {\n            int eid = pathEdges[idx];\n            double infoGain = INFO_GAIN_BASE * vars[idx] * invSumVar;\n            edgeInfo[eid] = min(edgeInfo[eid] + infoGain, MAX_INFO);\n            edgeUse[eid] = min(edgeUse[eid] + 1, 1000000000);\n        }\n\n        smoothEstimates();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    string path;\n    path.reserve(128);\n    vector<int> pathEdges;\n    pathEdges.reserve(128);\n\n    for (int q = 0; q < 1000; ++q) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        solver.computePath(si, sj, ti, tj, path, pathEdges);\n        cout << path << '\\n' << flush;\n\n        int measurement;\n        if (!(cin >> measurement)) return 0;\n        if (measurement < 0) return 0;\n\n        solver.update(pathEdges, static_cast<double>(measurement));\n    }\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 20;\nconstexpr int MAXLEN = 12;\nconstexpr int ORIENT = 2;\nconstexpr int PL_PER_ORIENT = N * N;\nconstexpr int PL = ORIENT * PL_PER_ORIENT;\nconstexpr uint8_t EMPTY = 0xFF;\nconst double TIME_LIMIT = 2.9;\nconst double LOCAL_SEARCH_MARGIN = 0.6;\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 Placement {\n    array<uint8_t, MAXLEN> rows;\n    array<uint8_t, MAXLEN> cols;\n    array<int, MAXLEN> cellIndex;\n};\n\nstruct Read {\n    string s;\n    vector<uint8_t> codes;\n    int len;\n};\n\nusing Grid = array<array<uint8_t, N>, N>;\n\nstruct Candidate {\n    Grid grid;\n    int score;\n};\n\ninline double vote_weight(int match, int len) {\n    if (match <= 0) return 0.0;\n    if (match >= len) return 6.5;\n    if (match == len - 1) return 2.3;\n    if (match == len - 2) return 0.9;\n    if (match >= len - 3) return 0.4;\n    if (match * 2 >= len) return 0.12;\n    return 0.03;\n}\n\nvector<Placement> build_placements() {\n    vector<Placement> placements(PL);\n    int idx = 0;\n    for (int ori = 0; ori < ORIENT; ++ori) {\n        for (int fixed = 0; fixed < N; ++fixed) {\n            for (int start = 0; start < N; ++start) {\n                Placement &p = placements[idx++];\n                for (int t = 0; t < MAXLEN; ++t) {\n                    int r, c;\n                    if (ori == 0) {\n                        r = fixed;\n                        c = (start + t) % N;\n                    } else {\n                        r = (start + t) % N;\n                        c = fixed;\n                    }\n                    p.rows[t] = static_cast<uint8_t>(r);\n                    p.cols[t] = static_cast<uint8_t>(c);\n                    p.cellIndex[t] = ((r * N + c) << 3);\n                }\n            }\n        }\n    }\n    return placements;\n}\n\nGrid seed_grid(const vector<Read> &reads, const vector<Placement> &placements, mt19937_64 &rng) {\n    Grid grid;\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            grid[i][j] = EMPTY;\n\n    vector<int> order(reads.size());\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (reads[a].len != reads[b].len) return reads[a].len > reads[b].len;\n        return a < b;\n    });\n\n    for (int idx : order) {\n        const Read &rd = reads[idx];\n        int len = rd.len;\n        int chosen = -1;\n        int cnt = 0;\n        for (int pid = 0; pid < PL; ++pid) {\n            bool ok = true;\n            for (int t = 0; t < len; ++t) {\n                uint8_t cur = grid[placements[pid].rows[t]][placements[pid].cols[t]];\n                if (cur != EMPTY && cur != rd.codes[t]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) {\n                ++cnt;\n                if ((uint64_t)rng() % cnt == 0) chosen = pid;\n            }\n        }\n        if (chosen != -1) {\n            for (int t = 0; t < len; ++t) {\n                grid[placements[chosen].rows[t]][placements[chosen].cols[t]] = rd.codes[t];\n            }\n        }\n    }\n\n    uniform_int_distribution<int> dist(0, 7);\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            if (grid[i][j] == EMPTY)\n                grid[i][j] = static_cast<uint8_t>(dist(rng));\n    return grid;\n}\n\nint compute_delta(int iter, int total) {\n    if (total <= 4) return 1;\n    if (iter * 3 >= total * 2) return 1;\n    if (iter * 3 >= total) return 2;\n    return 3;\n}\n\nvoid run_em(Grid &grid, int iterations, const vector<Read> &reads,\n            const vector<Placement> &placements, vector<double> &counts,\n            array<uint8_t, PL> &matchBuf, const vector<double> &weights,\n            double inertia, Timer &timer) {\n    for (int iter = 0; iter < iterations; ++iter) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n        fill(counts.begin(), counts.end(), 0.0);\n        int delta = compute_delta(iter, iterations);\n\n        for (const Read &rd : reads) {\n            const uint8_t *codes = rd.codes.data();\n            int len = rd.len;\n            int best = 0;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = 0;\n                for (int t = 0; t < len; ++t)\n                    if (grid[placements[pid].rows[t]][placements[pid].cols[t]] == codes[t]) ++match;\n                matchBuf[pid] = static_cast<uint8_t>(match);\n                if (match > best) best = match;\n            }\n            if (best == 0) continue;\n            int threshold = max(0, best - delta);\n            double totalWeight = 0.0;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = matchBuf[pid];\n                if (match < threshold) continue;\n                totalWeight += weights[match];\n            }\n            if (totalWeight <= 0) continue;\n            double inv = 1.0 / totalWeight;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = matchBuf[pid];\n                if (match < threshold) continue;\n                double w = weights[match];\n                if (w <= 0) continue;\n                double scaled = w * inv;\n                for (int t = 0; t < len; ++t)\n                    counts[placements[pid].cellIndex[t] + codes[t]] += scaled;\n            }\n        }\n\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                counts[((r * N + c) << 3) + grid[r][c]] += inertia;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int base = ((r * N + c) << 3);\n                double bestVal = counts[base];\n                int bestLetter = 0;\n                for (int letter = 1; letter < 8; ++letter) {\n                    double v = counts[base + letter];\n                    if (v > bestVal) {\n                        bestVal = v;\n                        bestLetter = letter;\n                    }\n                }\n                grid[r][c] = static_cast<uint8_t>(bestLetter);\n            }\n        }\n    }\n}\n\nint compute_best_matches(const Grid &grid, const vector<Read> &reads,\n                         vector<int> &bestPid, vector<uint8_t> &bestMatch,\n                         vector<uint8_t> *sat = nullptr) {\n    array<array<uint8_t, N * 2>, N> rowBuf, colBuf;\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            uint8_t val = grid[r][c];\n            rowBuf[r][c] = val;\n            rowBuf[r][c + N] = val;\n            colBuf[c][r] = val;\n            colBuf[c][r + N] = val;\n        }\n    }\n\n    int M = reads.size();\n    if ((int)bestPid.size() != M) bestPid.assign(M, 0);\n    if ((int)bestMatch.size() != M) bestMatch.assign(M, 0);\n    if (sat && (int)sat->size() != M) sat->assign(M, 0);\n\n    int satisfied = 0;\n    for (int idx = 0; idx < M; ++idx) {\n        const Read &rd = reads[idx];\n        const uint8_t *codes = rd.codes.data();\n        int len = rd.len;\n        int best = -1;\n        int bestPlacement = 0;\n        bool perfect = false;\n\n        for (int r = 0; r < N && !perfect; ++r) {\n            const uint8_t *rowPtr = rowBuf[r].data();\n            for (int start = 0; start < N; ++start) {\n                const uint8_t *seg = rowPtr + start;\n                int match = 0;\n                for (int t = 0; t < len; ++t)\n                    match += (seg[t] == codes[t]);\n                if (match > best) {\n                    best = match;\n                    bestPlacement = r * N + start;\n                    if (match == len) { perfect = true; break; }\n                }\n            }\n        }\n        if (!perfect) {\n            for (int c = 0; c < N && !perfect; ++c) {\n                const uint8_t *colPtr = colBuf[c].data();\n                for (int start = 0; start < N; ++start) {\n                    const uint8_t *seg = colPtr + start;\n                    int match = 0;\n                    for (int t = 0; t < len; ++t)\n                        match += (seg[t] == codes[t]);\n                    if (match > best) {\n                        best = match;\n                        bestPlacement = PL_PER_ORIENT + c * N + start;\n                        if (match == len) { perfect = true; break; }\n                    }\n                }\n            }\n        }\n        if (best < 0) best = 0;\n        bestPid[idx] = bestPlacement;\n        bestMatch[idx] = static_cast<uint8_t>(best);\n        bool satFlag = (best == len);\n        if (sat) (*sat)[idx] = static_cast<uint8_t>(satFlag);\n        if (satFlag) ++satisfied;\n    }\n    return satisfied;\n}\n\nvoid repair_grid(Grid &grid, const vector<Read> &reads, const vector<Placement> &placements,\n                 Timer &timer, const vector<int> &bestPid, const vector<uint8_t> &bestMatch,\n                 int threshold) {\n    int M = reads.size();\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        int ma = reads[a].len - bestMatch[a];\n        int mb = reads[b].len - bestMatch[b];\n        if (ma != mb) return ma < mb;\n        return reads[a].len > reads[b].len;\n    });\n    for (int idx : order) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n        int mismatch = reads[idx].len - bestMatch[idx];\n        if (mismatch <= 0 || mismatch > threshold) continue;\n        int pid = bestPid[idx];\n        if (pid < 0 || pid >= PL) continue;\n        const Placement &pl = placements[pid];\n        const Read &rd = reads[idx];\n        for (int t = 0; t < rd.len; ++t) {\n            grid[pl.rows[t]][pl.cols[t]] = rd.codes[t];\n        }\n    }\n}\n\nvoid local_search(Grid &grid, const vector<Read> &reads,\n                  const vector<Placement> &placements, Timer &timer,\n                  Grid &globalBest, int &globalBestScore, mt19937_64 &rng,\n                  int maxIter = 220) {\n    int M = reads.size();\n    vector<int> curBestPid(M), tmpBestPid(M);\n    vector<uint8_t> curBestMatch(M), tmpBestMatch(M);\n    vector<uint8_t> curSat(M), tmpSat(M);\n\n    int curScore = compute_best_matches(grid, reads, curBestPid, curBestMatch, &curSat);\n    if (curScore > globalBestScore) {\n        globalBestScore = curScore;\n        globalBest = grid;\n    }\n\n    array<vector<int>, MAXLEN + 1> buckets;\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    for (int iter = 0; iter < maxIter; ++iter) {\n        if (timer.elapsed() > TIME_LIMIT - 0.02) break;\n        if (curScore == M) break;\n\n        for (auto &vec : buckets) vec.clear();\n        for (int i = 0; i < M; ++i) {\n            if (curSat[i]) continue;\n            int mismatch = reads[i].len - curBestMatch[i];\n            if (mismatch < 1) mismatch = 1;\n            if (mismatch > MAXLEN) mismatch = MAXLEN;\n            buckets[mismatch].push_back(i);\n        }\n        int chosenMis = -1;\n        for (int mis = 1; mis <= MAXLEN; ++mis) {\n            if (!buckets[mis].empty()) { chosenMis = mis; break; }\n        }\n        if (chosenMis == -1) break;\n        int range = min(MAXLEN, chosenMis + 3);\n        for (int mis = chosenMis + 1; mis <= range; ++mis) {\n            if (!buckets[mis].empty() && uni01(rng) < 0.25) {\n                chosenMis = mis;\n                break;\n            }\n        }\n        const vector<int> &bucket = buckets[chosenMis];\n        int pick = bucket[rng() % bucket.size()];\n        int pid = curBestPid[pick];\n        if (pid < 0 || pid >= PL) continue;\n        const Placement &pl = placements[pid];\n        const Read &rd = reads[pick];\n        array<uint8_t, MAXLEN> backup;\n        bool changed = false;\n        for (int t = 0; t < rd.len; ++t) {\n            int r = pl.rows[t], c = pl.cols[t];\n            backup[t] = grid[r][c];\n            uint8_t desired = rd.codes[t];\n            if (grid[r][c] != desired) {\n                grid[r][c] = desired;\n                changed = true;\n            }\n        }\n        if (!changed) continue;\n\n        int newScore = compute_best_matches(grid, reads, tmpBestPid, tmpBestMatch, &tmpSat);\n        double progress = max(0.0, min(1.0, static_cast<double>(iter) / max(1, maxIter - 1)));\n        double temp = 2.8 + (0.25 - 2.8) * progress;\n        int diff = newScore - curScore;\n        bool accept = diff >= 0;\n        if (!accept) {\n            double prob = exp(diff / temp);\n            if (prob > uni01(rng)) accept = true;\n        }\n\n        if (accept) {\n            curScore = newScore;\n            swap(curBestPid, tmpBestPid);\n            swap(curBestMatch, tmpBestMatch);\n            swap(curSat, tmpSat);\n            if (curScore > globalBestScore) {\n                globalBestScore = curScore;\n                globalBest = grid;\n            }\n        } else {\n            for (int t = 0; t < rd.len; ++t)\n                grid[pl.rows[t]][pl.cols[t]] = backup[t];\n        }\n    }\n}\n\nint placement_vote_refine(Grid &grid, const vector<Read> &reads,\n                          const vector<Placement> &placements,\n                          vector<int> &bestPid, vector<uint8_t> &bestMatch,\n                          vector<double> &counts, Timer &timer, int iterations) {\n    int currentScore = compute_best_matches(grid, reads, bestPid, bestMatch);\n    Grid bestGrid = grid;\n    int bestScore = currentScore;\n\n    int M = reads.size();\n    for (int it = 0; it < iterations; ++it) {\n        if (timer.elapsed() > TIME_LIMIT - 0.02) break;\n        fill(counts.begin(), counts.end(), 0.0);\n\n        for (int i = 0; i < M; ++i) {\n            int match = bestMatch[i];\n            double weight = vote_weight(match, reads[i].len);\n            if (weight <= 0) continue;\n            int pid = bestPid[i];\n            if (pid < 0 || pid >= PL) continue;\n            const Placement &pl = placements[pid];\n            const Read &rd = reads[i];\n            for (int t = 0; t < rd.len; ++t) {\n                counts[pl.cellIndex[t] + rd.codes[t]] += weight;\n            }\n        }\n\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                counts[((r * N + c) << 3) + grid[r][c]] += 0.25;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int base = ((r * N + c) << 3);\n                double bestVal = counts[base];\n                int bestLetter = 0;\n                for (int letter = 1; letter < 8; ++letter) {\n                    double v = counts[base + letter];\n                    if (v > bestVal) {\n                        bestVal = v;\n                        bestLetter = letter;\n                    }\n                }\n                grid[r][c] = static_cast<uint8_t>(bestLetter);\n            }\n        }\n\n        currentScore = compute_best_matches(grid, reads, bestPid, bestMatch);\n        if (currentScore > bestScore) {\n            bestScore = currentScore;\n            bestGrid = grid;\n        }\n    }\n\n    grid = bestGrid;\n    return bestScore;\n}\n\nvoid run_restart(Grid &bestGrid, int &bestScore, const vector<Read> &reads,\n                 const vector<Placement> &placements, vector<double> &counts,\n                 array<uint8_t, PL> &matchBuf, const vector<double> &weights,\n                 Timer &timer, mt19937_64 &rng,\n                 vector<int> &workBestPid, vector<uint8_t> &workBestMatch,\n                 vector<Candidate> &candidates) {\n    Grid grid = seed_grid(reads, placements, rng);\n    run_em(grid, 30, reads, placements, counts, matchBuf, weights, 0.35, timer);\n    int score = compute_best_matches(grid, reads, workBestPid, workBestMatch);\n    candidates.push_back({grid, score});\n    if (score > bestScore) {\n        bestScore = score;\n        bestGrid = grid;\n    }\n\n    if (TIME_LIMIT - timer.elapsed() > 0.35) {\n        repair_grid(grid, reads, placements, timer, workBestPid, workBestMatch, 2);\n        run_em(grid, 8, reads, placements, counts, matchBuf, weights, 0.25, timer);\n        score = compute_best_matches(grid, reads, workBestPid, workBestMatch);\n        candidates.push_back({grid, score});\n        if (score > bestScore) {\n            bestScore = score;\n            bestGrid = grid;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N_input, M;\n    if (!(cin >> N_input >> M)) return 0;\n    vector<Read> reads(M);\n    for (int i = 0; i < M; ++i) {\n        string s; cin >> s;\n        reads[i].s = s;\n        reads[i].len = s.size();\n        reads[i].codes.resize(s.size());\n        for (int j = 0; j < (int)s.size(); ++j)\n            reads[i].codes[j] = static_cast<uint8_t>(s[j] - 'A');\n    }\n\n    auto placements = build_placements();\n    vector<double> counts(N * N * 8, 0.0);\n    array<uint8_t, PL> matchBuf{};\n    vector<double> weights(MAXLEN + 1, 0.0);\n    weights[1] = 0.05;\n    double w = 1.0;\n    for (int m = 2; m <= MAXLEN; ++m) {\n        weights[m] = w;\n        w *= 1.75;\n    }\n\n    Timer timer;\n    mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    Grid bestGrid{};\n    int bestScore = -1;\n    vector<int> workBestPid(M);\n    vector<uint8_t> workBestMatch(M);\n    vector<Candidate> candidates;\n\n    int restarts = 0;\n    while (timer.elapsed() < TIME_LIMIT - LOCAL_SEARCH_MARGIN) {\n        run_restart(bestGrid, bestScore, reads, placements, counts, matchBuf, weights,\n                    timer, rng, workBestPid, workBestMatch, candidates);\n        ++restarts;\n        if (timer.elapsed() > TIME_LIMIT - LOCAL_SEARCH_MARGIN) break;\n    }\n    if (restarts == 0) {\n        run_restart(bestGrid, bestScore, reads, placements, counts, matchBuf, weights,\n                    timer, rng, workBestPid, workBestMatch, candidates);\n    }\n    if (candidates.empty()) candidates.push_back({bestGrid, bestScore});\n    sort(candidates.begin(), candidates.end(), [](const Candidate &a, const Candidate &b) {\n        return a.score > b.score;\n    });\n    if (bestScore < 0) {\n        bestGrid = candidates[0].grid;\n        bestScore = candidates[0].score;\n    }\n\n    const int MAX_LOCAL_CANDS = 4;\n    int localRuns = min(MAX_LOCAL_CANDS, (int)candidates.size());\n    for (int i = 0; i < localRuns; ++i) {\n        if (timer.elapsed() > TIME_LIMIT - 0.08) break;\n        Grid start = candidates[i].grid;\n        int iter = max(120, 220 - i * 30);\n        local_search(start, reads, placements, timer, bestGrid, bestScore, rng, iter);\n    }\n\n    if (timer.elapsed() < TIME_LIMIT - 0.08) {\n        Grid candidate = bestGrid;\n        int refinedScore = placement_vote_refine(candidate, reads, placements,\n                                                 workBestPid, workBestMatch,\n                                                 counts, timer, 2);\n        if (refinedScore > bestScore) {\n            bestScore = refinedScore;\n            bestGrid = candidate;\n        }\n    }\n\n    if (timer.elapsed() < TIME_LIMIT - 0.03) {\n        Grid start = bestGrid;\n        local_search(start, reads, placements, timer, bestGrid, bestScore, rng, 110);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        string line(N, 'A');\n        for (int j = 0; j < N; ++j)\n            line[j] = static_cast<char>('A' + bestGrid[i][j]);\n        cout << line << '\\n';\n    }\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst long long INFLL = (1LL << 60);\nconst long long INF_CAP = (1LL << 55);\nconst long long MAX_WEIGHT = (1LL << 50);\nconst int PLAN_KEEP = 6;\nconst int TSP_PLAN_LIMIT = 5;\nconst int TSP_TARGET_LIMIT = 260;\nconst int EXACT_TSP_LIMIT = 15;\n\nconst int di[4] = {-1, 1, 0, 0};\nconst int dj[4] = {0, 0, -1, 1};\n\nstruct Dinic {\n    struct Edge { int to; long long cap; int rev; };\n    int N;\n    vector<vector<Edge>> G;\n    vector<int> level, prog;\n    Dinic(int n = 0) { init(n); }\n    void init(int n) { N = n; G.assign(n, {}); }\n    void add_edge(int fr, int to, long long cap) {\n        Edge f{to, cap, (int)G[to].size()};\n        Edge b{fr, 0, (int)G[fr].size()};\n        G[fr].push_back(f);\n        G[to].push_back(b);\n    }\n    bool bfs(int s, int t) {\n        level.assign(N, -1);\n        queue<int> q;\n        level[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            for (const auto &e : G[v])\n                if (e.cap > 0 && level[e.to] < 0) {\n                    level[e.to] = level[v] + 1;\n                    q.push(e.to);\n                }\n        }\n        return level[t] >= 0;\n    }\n    long long dfs(int v, int t, long long f) {\n        if (v == t) return f;\n        for (int &i = prog[v]; i < (int)G[v].size(); ++i) {\n            Edge &e = G[v][i];\n            if (e.cap > 0 && level[v] < level[e.to]) {\n                long long d = dfs(e.to, t, min(f, e.cap));\n                if (d > 0) {\n                    e.cap -= d;\n                    G[e.to][e.rev].cap += d;\n                    return d;\n                }\n            }\n        }\n        return 0;\n    }\n    long long max_flow(int s, int t) {\n        long long flow = 0;\n        while (bfs(s, t)) {\n            prog.assign(N, 0);\n            while (true) {\n                long long f = dfs(s, t, (1LL << 60));\n                if (!f) break;\n                flow += f;\n            }\n        }\n        return flow;\n    }\n};\n\nstruct SideParam {\n    long long base = 10;\n    long long coeffStart = 1;\n    int anchor1 = -1;\n    long long coeffAnchor1 = 0;\n    int anchor2 = -1;\n    long long coeffAnchor2 = 0;\n    long long lenFactor = 0;\n    int noiseRange = 0;\n};\n\nstruct WeightParam {\n    SideParam row;\n    SideParam col;\n};\n\nstruct Cover {\n    vector<char> row_cover;\n    vector<char> col_cover;\n};\n\nstruct Plan {\n    vector<int> targets;\n    long long approx;\n};\n\nstruct CandidatePlan {\n    long long cost;\n    vector<int> targets;\n};\n\nstruct SPCache {\n    int N, total;\n    const vector<int> &cost;\n    unordered_map<int,int> idx;\n    vector<vector<long long>> dist;\n    vector<vector<int>> parent;\n    SPCache(int N, const vector<int> &cost) : N(N), total(N * N), cost(cost) {\n        idx.reserve(512);\n    }\n    int get(int root) {\n        auto it = idx.find(root);\n        if (it != idx.end()) return it->second;\n        vector<long long> d(total, INFLL);\n        vector<int> p(total, -1);\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        d[root] = 0;\n        pq.emplace(0, root);\n        while (!pq.empty()) {\n            auto [distU, u] = pq.top(); pq.pop();\n            if (distU != d[u]) continue;\n            int ui = u / N, uj = u % N;\n            for (int dir = 0; dir < 4; ++dir) {\n                int vi = ui + di[dir];\n                int vj = uj + dj[dir];\n                if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n                int v = vi * N + vj;\n                if (cost[v] < 0) continue;\n                long long nd = distU + cost[v];\n                if (nd < d[v]) {\n                    d[v] = nd;\n                    p[v] = u;\n                    pq.emplace(nd, v);\n                }\n            }\n        }\n        int id = dist.size();\n        idx[root] = id;\n        dist.push_back(move(d));\n        parent.push_back(move(p));\n        return id;\n    }\n};\n\nchar dir_char(int from, int to, int N) {\n    int fi = from / N, fj = from % N;\n    int ti = to / N, tj = to % N;\n    if (ti == fi - 1 && tj == fj) return 'U';\n    if (ti == fi + 1 && tj == fj) return 'D';\n    if (tj == fj - 1 && ti == fi) return 'L';\n    if (tj == fj + 1 && ti == fi) return 'R';\n    return 'U';\n}\n\nvoid run_dijkstra(int source, const vector<int> &cost, int N,\n                  vector<long long> &dist, vector<int> *parent) {\n    int total = N * N;\n    dist.assign(total, INFLL);\n    if (parent) parent->assign(total, -1);\n    using P = pair<long long,int>;\n    priority_queue<P, vector<P>, greater<P>> pq;\n    dist[source] = 0;\n    pq.emplace(0, source);\n    while (!pq.empty()) {\n        auto [d, u] = pq.top(); pq.pop();\n        if (d != dist[u]) continue;\n        int ui = u / N, uj = u % N;\n        for (int dir = 0; dir < 4; ++dir) {\n            int vi = ui + di[dir];\n            int vj = uj + dj[dir];\n            if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n            int v = vi * N + vj;\n            if (cost[v] < 0) continue;\n            long long nd = d + cost[v];\n            if (nd < dist[v]) {\n                dist[v] = nd;\n                if (parent) (*parent)[v] = u;\n                pq.emplace(nd, v);\n            }\n        }\n    }\n}\n\nCover solve_weighted_cover(const vector<vector<int>> &adj,\n                           const vector<long long> &w_row,\n                           const vector<long long> &w_col) {\n    int R = (int)w_row.size();\n    int C = (int)w_col.size();\n    Dinic din(R + C + 2);\n    int SRC = 0, SNK = R + C + 1;\n    for (int r = 0; r < R; ++r) din.add_edge(SRC, 1 + r, min(MAX_WEIGHT, w_row[r]));\n    for (int r = 0; r < R; ++r)\n        for (int c : adj[r]) din.add_edge(1 + r, 1 + R + c, INF_CAP);\n    for (int c = 0; c < C; ++c) din.add_edge(1 + R + c, SNK, min(MAX_WEIGHT, w_col[c]));\n    din.max_flow(SRC, SNK);\n    vector<char> vis(din.N, 0);\n    queue<int> q;\n    q.push(SRC);\n    vis[SRC] = 1;\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        for (const auto &e : din.G[v]) if (e.cap > 0 && !vis[e.to]) {\n            vis[e.to] = 1;\n            q.push(e.to);\n        }\n    }\n    vector<char> row_cover(R, 0), col_cover(C, 0);\n    for (int r = 0; r < R; ++r) row_cover[r] = !vis[1 + r];\n    for (int c = 0; c < C; ++c) col_cover[c] = vis[1 + R + c];\n    return {row_cover, col_cover};\n}\n\nvoid reduce_targets(vector<int> &targets,\n                    const vector<char> &row_cover,\n                    const vector<char> &col_cover,\n                    const vector<int> &row_id,\n                    const vector<int> &col_id,\n                    const vector<long long> &distStart,\n                    int start_id,\n                    int R, int C) {\n    if (targets.empty()) {\n        targets.push_back(start_id);\n        return;\n    }\n    vector<int> row_cnt(R, 0), col_cnt(C, 0);\n    for (int cell : targets) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && r < R && row_cover[r]) ++row_cnt[r];\n        if (c >= 0 && c < C && col_cover[c]) ++col_cnt[c];\n    }\n    vector<int> order(targets.size());\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        long long da = distStart[targets[a]];\n        long long db = distStart[targets[b]];\n        if (da != db) return da > db;\n        return targets[a] < targets[b];\n    });\n    vector<char> keep(targets.size(), 1);\n    for (int idx : order) {\n        int cell = targets[idx];\n        int r = row_id[cell];\n        int c = col_id[cell];\n        bool essential = false;\n        if (r >= 0 && r < R && row_cover[r] && row_cnt[r] <= 1) essential = true;\n        if (c >= 0 && c < C && col_cover[c] && col_cnt[c] <= 1) essential = true;\n        if (!essential) {\n            keep[idx] = 0;\n            if (r >= 0 && r < R && row_cover[r]) --row_cnt[r];\n            if (c >= 0 && c < C && col_cover[c]) --col_cnt[c];\n        }\n    }\n    vector<int> newTargets;\n    for (int i = 0; i < (int)targets.size(); ++i) if (keep[i]) newTargets.push_back(targets[i]);\n    if (newTargets.empty()) newTargets.push_back(start_id);\n    targets.swap(newTargets);\n}\n\nPlan build_plan(const vector<char> &row_cover,\n                const vector<char> &col_cover,\n                const vector<vector<int>> &row_cells,\n                const vector<vector<int>> &col_cells,\n                const vector<int> &row_id,\n                const vector<int> &col_id,\n                const vector<int> &best_row_cell,\n                const vector<int> &best_col_cell,\n                const vector<int> &sorted_cells,\n                const vector<long long> &distStart,\n                int total, int start_id, int R, int C) {\n    vector<char> row_need = row_cover;\n    vector<char> col_need = col_cover;\n    vector<char> is_target(total, 0);\n    vector<int> targets;\n    targets.reserve(R + C);\n    auto add_target = [&](int cell) {\n        if (cell < 0) return;\n        if (!is_target[cell]) {\n            is_target[cell] = 1;\n            targets.push_back(cell);\n        }\n    };\n    for (int cell : sorted_cells) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && c >= 0 && r < R && c < C && row_need[r] && col_need[c]) {\n            add_target(cell);\n            row_need[r] = 0;\n            col_need[c] = 0;\n        }\n    }\n    for (int r = 0; r < R; ++r) if (row_need[r]) {\n        int cell = best_row_cell[r];\n        if (cell == -1 && !row_cells[r].empty()) cell = row_cells[r][0];\n        add_target(cell);\n        row_need[r] = 0;\n    }\n    for (int c = 0; c < C; ++c) if (col_need[c]) {\n        int cell = best_col_cell[c];\n        if (cell == -1 && !col_cells[c].empty()) cell = col_cells[c][0];\n        add_target(cell);\n        col_need[c] = 0;\n    }\n    vector<char> row_hit(R, 0), col_hit(C, 0);\n    for (int cell : targets) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && r < R) row_hit[r] = 1;\n        if (c >= 0 && c < C) col_hit[c] = 1;\n    }\n    for (int r = 0; r < R; ++r) if (row_cover[r] && !row_hit[r]) {\n        int cell = best_row_cell[r];\n        if (cell == -1 && !row_cells[r].empty()) cell = row_cells[r][0];\n        add_target(cell);\n        row_hit[r] = 1;\n        int c = col_id[cell];\n        if (c >= 0 && c < C) col_hit[c] = 1;\n    }\n    for (int c = 0; c < C; ++c) if (col_cover[c] && !col_hit[c]) {\n        int cell = best_col_cell[c];\n        if (cell == -1 && !col_cells[c].empty()) cell = col_cells[c][0];\n        add_target(cell);\n        col_hit[c] = 1;\n        int r = row_id[cell];\n        if (r >= 0 && r < R) row_hit[r] = 1;\n    }\n    reduce_targets(targets, row_cover, col_cover, row_id, col_id, distStart, start_id, R, C);\n    long long approx = 0;\n    for (int cell : targets) {\n        long long d = distStart[cell];\n        if (d >= INFLL / 4) d = INFLL / 4;\n        approx += d;\n    }\n    approx += 20LL * targets.size();\n    if (targets.empty()) targets.push_back(start_id);\n    return {targets, approx};\n}\n\nbool buildSteinerTree(const vector<int> &targets, vector<vector<int>> &treeAdj,\n                      int start_id, const vector<int> &cost, int N) {\n    int total = (int)cost.size();\n    vector<char> need(total, 0);\n    int remaining = 0;\n    for (int cell : targets) if (!need[cell]) { need[cell] = 1; ++remaining; }\n    vector<char> in_tree(total, 0);\n    vector<int> treeNodes;\n    treeNodes.reserve(total);\n    in_tree[start_id] = 1;\n    treeNodes.push_back(start_id);\n    if (need[start_id]) { need[start_id] = 0; --remaining; }\n    vector<long long> dist(total, INFLL);\n    vector<int> parent(total, -1);\n    while (remaining > 0) {\n        fill(dist.begin(), dist.end(), INFLL);\n        fill(parent.begin(), parent.end(), -1);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        for (int node : treeNodes) {\n            dist[node] = 0;\n            parent[node] = -1;\n            pq.emplace(0, node);\n        }\n        int best = -1;\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (need[u]) { best = u; break; }\n            int ui = u / N, uj = u % N;\n            for (int dir = 0; dir < 4; ++dir) {\n                int vi = ui + di[dir];\n                int vj = uj + dj[dir];\n                if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n                int v = vi * N + vj;\n                if (cost[v] < 0) continue;\n                long long nd = d + cost[v];\n                if (nd < dist[v]) {\n                    dist[v] = nd;\n                    parent[v] = u;\n                    pq.emplace(nd, v);\n                }\n            }\n        }\n        if (best == -1) return false;\n        need[best] = 0;\n        --remaining;\n        if (in_tree[best]) continue;\n        vector<int> path;\n        int cur = best;\n        while (!in_tree[cur]) {\n            path.push_back(cur);\n            cur = parent[cur];\n            if (cur == -1) return false;\n        }\n        int prev = cur;\n        for (int i = (int)path.size() - 1; i >= 0; --i) {\n            int node = path[i];\n            treeAdj[node].push_back(prev);\n            treeAdj[prev].push_back(node);\n            if (!in_tree[node]) {\n                in_tree[node] = 1;\n                treeNodes.push_back(node);\n            }\n            if (need[node]) {\n                need[node] = 0;\n                --remaining;\n            }\n            prev = node;\n        }\n    }\n    return true;\n}\n\nvoid buildTreeSP(const vector<int> &targets, vector<vector<int>> &treeAdj,\n                 int start_id, const vector<int> &parent, int total) {\n    vector<char> required(total, 0);\n    required[start_id] = 1;\n    for (int cell : targets) {\n        int cur = cell;\n        while (cur != -1 && !required[cur]) {\n            required[cur] = 1;\n            if (cur == start_id) break;\n            cur = parent[cur];\n        }\n    }\n    for (int v = 0; v < total; ++v) {\n        if (!required[v]) continue;\n        int p = parent[v];\n        if (p == -1 || !required[p]) continue;\n        treeAdj[v].push_back(p);\n        treeAdj[p].push_back(v);\n    }\n}\n\nstring buildRoute(const vector<vector<int>> &treeAdj, int start_id, int N) {\n    string route;\n    route.reserve(treeAdj.size() * 2);\n    struct Frame { int node, parent, idx; };\n    vector<Frame> st;\n    st.push_back({start_id, -1, 0});\n    while (!st.empty()) {\n        Frame &fr = st.back();\n        if (fr.idx == (int)treeAdj[fr.node].size()) {\n            st.pop_back();\n            if (fr.parent != -1) route.push_back(dir_char(fr.node, fr.parent, N));\n            continue;\n        }\n        int nxt = treeAdj[fr.node][fr.idx++];\n        if (nxt == fr.parent) continue;\n        route.push_back(dir_char(fr.node, nxt, N));\n        st.push_back({nxt, fr.node, 0});\n    }\n    return route;\n}\n\nlong long simulateRoute(const string &route, const vector<int> &cost,\n                        int N, int si, int sj) {\n    int i = si, j = sj;\n    long long total = 0;\n    for (char mv : route) {\n        if (mv == 'U') --i;\n        else if (mv == 'D') ++i;\n        else if (mv == 'L') --j;\n        else if (mv == 'R') ++j;\n        if (i < 0 || i >= N || j < 0 || j >= N) return INFLL;\n        int id = i * N + j;\n        if (cost[id] < 0) return INFLL;\n        total += cost[id];\n    }\n    if (i != si || j != sj) return INFLL;\n    return total;\n}\n\nint nearestRoadByManhattan(int ti, int tj, const vector<int> &road_cells, int N) {\n    int best = -1;\n    int bestDist = INT_MAX;\n    for (int cell : road_cells) {\n        int ci = cell / N, cj = cell % N;\n        int d = abs(ci - ti) + abs(cj - tj);\n        if (d < bestDist) {\n            bestDist = d;\n            best = cell;\n        }\n    }\n    if (best == -1 && !road_cells.empty()) best = road_cells[0];\n    return\tbest;\n}\n\nvoid add_candidate_plan(const vector<int> &targets, long long cost,\n                        vector<CandidatePlan> &plans) {\n    plans.push_back({cost, targets});\n    sort(plans.begin(), plans.end(), [](const CandidatePlan &a, const CandidatePlan &b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return a.targets.size() < b.targets.size();\n    });\n    if ((int)plans.size() > PLAN_KEEP) plans.resize(PLAN_KEEP);\n}\n\ntemplate<class Visitor>\nbool append_shortest_path_collect(int from, int to, string &route,\n                                  SPCache &cache, int N, Visitor &&visit) {\n    if (from == to) return true;\n    int idx = cache.get(from);\n    const auto &parent = cache.parent[idx];\n    int cur = to;\n    vector<int> path;\n    while (true) {\n        if (cur == from) break;\n        int p = parent[cur];\n        if (p == -1) return false;\n        path.push_back(cur);\n        cur = p;\n    }\n    int prev = from;\n    for (int i = (int)path.size() - 1; i >= 0; --i) {\n        int node = path[i];\n        route.push_back(dir_char(prev, node, N));\n        visit(node);\n        prev = node;\n    }\n    return true;\n}\n\nbool exact_tsp_cycle(const vector<vector<long long>> &dist,\n                     vector<int> &order, long long &bestLen, long long best_limit) {\n    int T = dist.size();\n    if (T > EXACT_TSP_LIMIT) return false;\n    int FULL = 1 << T;\n    vector<vector<long long>> dp(FULL, vector<long long>(T, INFLL));\n    vector<vector<int>> prv(FULL, vector<int>(T, -1));\n    dp[1][0] = 0;\n    for (int mask = 1; mask < FULL; ++mask) {\n        if ((mask & 1) == 0) continue;\n        for (int last = 0; last < T; ++last) {\n            if (!(mask & (1 << last))) continue;\n            long long cur = dp[mask][last];\n            if (cur >= INFLL / 4) continue;\n            for (int nxt = 1; nxt < T; ++nxt) {\n                if (mask & (1 << nxt)) continue;\n                long long nd = cur + dist[last][nxt];\n                int nmask = mask | (1 << nxt);\n                if (nd < dp[nmask][nxt]) {\n                    dp[nmask][nxt] = nd;\n                    prv[nmask][nxt] = last;\n                }\n            }\n        }\n    }\n    int full = FULL - 1;\n    long long best = INFLL;\n    int bestLast = -1;\n    for (int last = 1; last < T; ++last) {\n        long long val = dp[full][last];\n        if (val >= INFLL / 4) continue;\n        val += dist[last][0];\n        if (val < best) {\n            best = val;\n            bestLast = last;\n        }\n    }\n    if (bestLast == -1) return false;\n    if (best_limit < INFLL / 4 && best >= best_limit) return false;\n    vector<int> ord(T);\n    int mask = full;\n    int cur = bestLast;\n    for (int i = T - 1; i >= 1; --i) {\n        ord[i] = cur;\n        int prev = prv[mask][cur];\n        mask ^= (1 << cur);\n        cur = prev;\n       ord[0] = 0;\n    }\n    order = ord;\n    bestLen = best;\n    return true;\n}\n\nlong long cycle_len(const vector<vector<long long>> &dist,\n                    const vector<int> &ord, long long best_limit) {\n    int T = ord.size();\n    long long len = 0;\n    for (int i = 0; i < T; ++i) {\n        long long d = dist[ord[i]][ord[(i + 1) % T]];\n        len += d;\n        if (best_limit < INFLL / 4 && len >= best_limit) return INFLL;\n    }\n    return len;\n}\n\nvoid two_opt(vector<int> &ord, const vector<vector<long long>> &dist) {\n    int T = ord.size();\n    bool improved = true;\n    int iter = 0;\n    while (improved && iter < 40) {\n        improved = false;\n        ++iter;\n        for (int i = 1; i < T - 1; ++i) {\n            for (int j = i + 1; j < T; ++j) {\n                int a = ord[i - 1];\n                int b = ord[i];\n                int c = ord[j];\n                int d = ord[(j + 1) % T];\n                long long delta = (dist[a][c] + dist[b][d]) - (dist[a][b] + dist[c][d]);\n                if (delta < 0) {\n                    reverse(ord.begin() + i, ord.begin() + j + 1);\n                    improved = true;\n                }\n            }\n        }\n    }\n}\n\nbool heuristic_tsp(const vector<vector<long long>> &dist, vector<int> &bestOrd,\n                   long long &bestLen, long long best_limit, mt19937 &rng) {\n    int T = dist.size();\n    vector<int> order(T);\n    iota(order.begin(), order.end(), 0);\n    vector<char> used(T, 0);\n    order[0] = 0;\n    used[0] = 1;\n    for (int pos = 1; pos < T; ++pos) {\n        int prev = order[pos - 1];\n        long long bestd = INFLL;\n        int best = -1;\n        for (int j = 1; j < T; ++j) if (!used[j]) {\n            long long d = dist[prev][j];\n            if (d < bestd) {\n                bestd = d;\n                best = j;\n            }\n        }\n        if (best == -1) return false;\n        order[pos] = best;\n        used[best] = 1;\n    }\n    two_opt(order, dist);\n    bestOrd = order;\n    bestLen = cycle_len(dist, order, best_limit);\n    if (bestLen >= INFLL / 4) return false;\n\n    int restarts = min(6, max(2, T / 25 + 2));\n    for (int r = 0; r < restarts; ++r) {\n        vector<int> cur(T);\n        cur[0] = 0;\n        for (int i = 1; i < T; ++i) cur[i] = i;\n        shuffle(cur.begin() + 1, cur.end(), rng);\n        two_opt(cur, dist);\n        long long len = cycle_len(dist, cur, min(bestLen, best_limit));\n        if (len < bestLen) {\n            bestLen = len;\n            bestOrd = cur;\n        }\n    }\n    return true;\n}\n\nbool build_cycle_route(const vector<int> &nodes, const vector<int> &order,\n                       SPCache &cache, int N, string &route) {\n    int T = nodes.size();\n    vector<int> pos(cache.total, -1);\n    for (int i = 0; i < T; ++i) pos[nodes[i]] = i;\n    vector<char> visited(T, 0);\n    int visitedCnt = 0;\n    auto visitor = [&](int cell) {\n        int idx = pos[cell];\n        if (idx != -1 && !visited[idx]) {\n            visited[idx] = 1;\n            ++visitedCnt;\n        }\n    };\n    visitor(nodes[0]);\n    int current = nodes[0];\n    int ptr = 1;\n    int loops = 0;\n    while (visitedCnt < T && loops < T * 4) {\n        int idxOrder = order[ptr];\n        ptr = (ptr + 1) % T;\n        if (idxOrder == 0) continue;\n        if (visited[idxOrder]) continue;\n        if (!append_shortest_path_collect(current, nodes[idxOrder], route, cache, N, visitor))\n            return false;\n        current = nodes[idxOrder];\n        ++loops;\n    }\n    for (int i = 1; i < T; ++i)\n        if (!visited[i]) {\n            if (!append_shortest_path_collect(current, nodes[i], route, cache, N, visitor))\n                return false;\n            current = nodes[i];\n        }\n    if (!append_shortest_path_collect(current, nodes[0], route, cache, N, visitor))\n        return false;\n    return true;\n}\n\nbool try_tsp_route(const vector<int> &planTargets, int start_id, const vector<int> &cost,\n                   int N, int si, int sj, string &best_route, long long &best_cost,\n                   SPCache &cache, mt19937 &rng) {\n    vector<int> nodes = planTargets;\n    nodes.push_back(start_id);\n    sort(nodes.begin(), nodes.end());\n    nodes.erase(unique(nodes.begin(), nodes.end()), nodes.end());\n    int start_pos = find(nodes.begin(), nodes.end(), start_id) - nodes.begin();\n    if (start_pos != 0) swap(nodes[0], nodes[start_pos]);\n    int T = nodes.size();\n    if (T <= 1) {\n        if (best_cost > 0) {\n            best_cost = 0;\n            best_route.clear();\n        }\n        return true;\n    }\n    if (T > TSP_TARGET_LIMIT) return false;\n    vector<vector<long long>> dist(T, vector<long long>(T, INFLL));\n    for (int i = 0; i < T; ++i) {\n        int idx = cache.get(nodes[i]);\n        const auto &d = cache.dist[idx];\n        for (int j = 0; j < T; ++j) dist[i][j] = d[nodes[j]];\n    }\n    for (int i = 0; i < T; ++i)\n        for (int j = 0; j < T; ++j)\n            if (dist[i][j] >= INFLL / 4) return false;\n\n    vector<int> order;\n    long long bestLen = INFLL;\n    if (!exact_tsp_cycle(dist, order, bestLen, best_cost)) {\n        if (!heuristic_tsp(dist, order, bestLen, best_cost, rng)) return false;\n    }\n    if (bestLen >= INFLL / 4) return false;\n\n    string route;\n    route.reserve((size_t)bestLen + 16);\n    if (!build_cycle_route(nodes, order, cache, N, route)) return false;\n\n    long long travel = simulateRoute(route, cost, N, si, sj);\n    if (travel < best_cost) {\n        best_cost = travel;\n        best_route = route;\n        return true;\n    }\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, si, sj;\n    if (!(cin >> N >> si >> sj)) return 0;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n    int total = N * N;\n    auto idx = [&](int i, int j) { return i * N + j; };\n    vector<int> cost(total, -1);\n    vector<int> road_cells;\n    road_cells.reserve(total);\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            if (grid[i][j] != '#') {\n                int id = idx(i, j);\n                cost[id] = grid[i][j] - '0';\n                road_cells.push_back(id);\n            }\n    int start_id = idx(si, sj);\n\n    vector<int> row_id(total, -1);\n    vector<vector<int>> row_cells;\n    for (int i = 0; i < N; ++i) {\n        int j = 0;\n        while (j < N) {\n            if (grid[i][j] == '#') { ++j; continue; }\n            vector<int> cells;\n            while (j < N && grid[i][j] != '#') {\n                int cell = idx(i, j);\n                row_id[cell] = (int)row_cells.size();\n                cells.push_back(cell);\n                ++j;\n            }\n            row_cells.push_back(move(cells));\n        }\n    }\n    int R = (int)row_cells.size();\n\n    vector<int> col_id(total, -1);\n    vector<vector<int>> col_cells;\n    for (int j = 0; j < N; ++j) {\n        int i = 0;\n        while (i < N) {\n            if (grid[i][j] == '#') { ++i; continue; }\n            vector<int> cells;\n            while (i < N && grid[i][j] != '#') {\n                int cell = idx(i, j);\n                col_id[cell] = (int)col_cells.size();\n                cells.push_back(cell);\n                ++i;\n            }\n            col_cells.push_back(move(cells));\n        }\n    }\n    int C = (int)col_cells.size();\n\n    vector<vector<int>> row_adj(R);\n    for (int cell : road_cells) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && c >= 0) row_adj[r].push_back(c);\n    }\n    for (auto &vec : row_adj) {\n        sort(vec.begin(), vec.end());\n        vec.erase(unique(vec.begin(), vec.end()), vec.end());\n    }\n    vector<int> row_len(R), col_len(C);\n    for (int r = 0; r < R; ++r) row_len[r] = (int)row_cells[r].size();\n    for (int c = 0; c < C; ++c) col_len[c] = (int)col_cells[c].size();\n\n    vector<long long> distStart(total, INFLL);\n    vector<int> parentStart(total, -1);\n    run_dijkstra(start_id, cost, N, distStart, &parentStart);\n\n    vector<int> sorted_cells = road_cells;\n    sort(sorted_cells.begin(), sorted_cells.end(), [&](int a, int b) {\n        if (distStart[a] != distStart[b]) return distStart[a] < distStart[b];\n        return a < b;\n    });\n\n    vector<int> best_row_cell(R, -1), best_col_cell(C, -1);\n    for (int r = 0; r < R; ++r)\n        for (int cell : row_cells[r])\n            if (best_row_cell[r] == -1 || distStart[cell] < distStart[best_row_cell[r]])\n                best_row_cell[r] = cell;\n    for (int c = 0; c < C; ++c)\n        for (int cell : col_cells[c])\n            if (best_col_cell[c] == -1 || distStart[cell] < distStart[best_col_cell[c]])\n                best_col_cell[c] = cell;\n\n    vector<int> anchor_cells;\n    anchor_cells.push_back(start_id);\n    vector<pair<int,int>> points = {{N/2, N/2}, {0,0}, {0,N-1}, {N-1,0}, {N-1,N-1}};\n    for (auto [pi, pj] : points) {\n        int cell = nearestRoadByManhattan(pi, pj, road_cells, N);\n        if (cell == -1) continue;\n        if (find(anchor_cells.begin(), anchor_cells.end(), cell) == anchor_cells.end())\n            anchor_cells.push_back(cell);\n    }\n    mt19937 rng(712367 + N * 131 + si * 37 + sj);\n    while ((int)anchor_cells.size() < 7 && (int)anchor_cells.size() < (int)road_cells.size()) {\n        int cell = road_cells[rng() % road_cells.size()];\n        if (find(anchor_cells.begin(), anchor_cells.end(), cell) == anchor_cells.end())\n            anchor_cells.push_back(cell);\n    }\n\n    int numAnchors = (int)anchor_cells.size();\n    vector<vector<long long>> distAnchors;\n    distAnchors.reserve(numAnchors);\n    distAnchors.push_back(distStart);\n    for (int a = 1; a < numAnchors; ++a) {\n        vector<long long> dist(total, INFLL);\n        run_dijkstra(anchor_cells[a], cost, N, dist, nullptr);\n        distAnchors.push_back(dist);\n    }\n\n    vector<vector<long long>> bestRowDistAnchor(numAnchors, vector<long long>(R, INFLL));\n    vector<vector<long long>> bestColDistAnchor(numAnchors, vector<long long>(C, INFLL));\n    for (int a = 0; a < numAnchors; ++a) {\n        const auto &dist = distAnchors[a];\n        for (int r = 0; r < R; ++r) {\n            long long best = INFLL;\n            for (int cell : row_cells[r]) best = min(best, dist[cell]);\n            bestRowDistAnchor[a][r] = best;\n        }\n        for (int c = 0; c < C; ++c) {\n            long long best = INFLL;\n            for (int cell : col_cells[c]) best = min(best, dist[cell]);\n            bestColDistAnchor[a][c] = best;\n        }\n    }\n\n    vector<long long> wRow(R), wCol(C);\n\n    auto assign_weights = [&](const SideParam &param,\n                              const vector<vector<long long>> &bestDistByAnchor,\n                              const vector<int> &lengths,\n                              vector<long long> &weights) {\n        uniform_int_distribution<int> noiseDist(0, max(0, param.noiseRange));\n        for (int s = 0; s < (int)weights.size(); ++s) {\n            long long w = param.base;\n            auto add = [&](int anchor, long long coeff) {\n                if (anchor < 0 || coeff == 0) return;\n                long long d = bestDistByAnchor[anchor][s];\n                if (d >= INFLL / 4) d = INFLL / 4;\n                w += coeff * d;\n            };\n            add(0, param.coeffStart);\n            add(param.anchor1, param.coeffAnchor1);\n            add(param.anchor2, param.coeffAnchor2);\n            w += param.lenFactor * (long long)lengths[s];\n            if (param.noiseRange > 0) w += noiseDist(rng);\n            if (w < 1) w = 1;\n            if (w > MAX_WEIGHT) w = MAX_WEIGHT;\n            weights[s] = w;\n        }\n    };\n\n    auto apply_spec = [&](const WeightParam &spec) {\n        assign_weights(spec.row, bestRowDistAnchor, row_len, wRow);\n        assign_weights(spec.col, bestColDistAnchor, col_len, wCol);\n    };\n\n    WeightParam base_spec;\n    base_spec.row.base = 40;\n    base_spec.row.coeffStart = 1;\n    base_spec.col = base_spec.row;\n\n    WeightParam unweighted_spec;\n    unweighted_spec.row.base = 1;\n    unweighted_spec.row.coeffStart = 0;\n    unweighted_spec.col = unweighted_spec.row;\n\n    auto random_side = [&](int numAnchors) {\n        SideParam sp;\n        uniform_int_distribution<int> baseDist(15, 120);\n        uniform_int_distribution<int> coeffStartDist(0, 2);\n        uniform_int_distribution<int> lenDist(-4, 4);\n        uniform_int_distribution<int> noiseDist(0, 80);\n        sp.base = baseDist(rng);\n        sp.coeffStart = coeffStartDist(rng);\n        sp.lenFactor = lenDist(rng);\n        sp.noiseRange = noiseDist(rng);\n        if (numAnchors >= 2 && uniform_int_distribution<int>(0, 99)(rng) < 70) {\n            sp.anchor1 = uniform_int_distribution<int>(0, numAnchors - 1)(rng);\n            sp.coeffAnchor1 = uniform_int_distribution<int>(1, 3)(rng);\n        }\n        if (numAnchors >= 3 && uniform_int_distribution<int>(0, 99)(rng) < 35) {\n            do {\n                sp.anchor2 = uniform_int_distribution<int>(0, numAnchors - 1)(rng);\n            } while (sp.anchor2 == sp.anchor1);\n            sp.coeffAnchor2 = uniform_int_distribution<int>(1, 2)(rng);\n        }\n        return sp;\n    };\n\n    auto random_spec = [&](int numAnchors) {\n        WeightParam spec;\n        spec.row = random_side(numAnchors);\n        spec.col = random_side(numAnchors);\n        int bias = uniform_int_distribution<int>(0, 2)(rng);\n        if (bias == 0) {\n            spec.row.base = max(5LL, spec.row.base / 2);\n            spec.col.base += 30;\n        } else if (bias == 1) {\n            spec.col.base = max(5LL, spec.col.base / 2);\n            spec.row.base += 30;\n        }\n        return spec;\n    };\n\n    vector<int> matchRow(R, -1), matchCol(C, -1);\n    vector<char> seen(C, 0);\n    function<bool(int)> dfs_match = [&](int u) -> bool {\n        for (int v : row_adj[u]) {\n            if (seen[v]) continue;\n            seen[v] = 1;\n            if (matchCol[v] == -1 || dfs_match(matchCol[v])) {\n                matchRow[u] = v;\n                matchCol[v] = u;\n                return true;\n            }\n        }\n        return false;\n    };\n    for (int u = 0; u < R; ++u) {\n        fill(seen.begin(), seen.end(), 0);\n        dfs_match(u);\n    }\n    vector<char> visRow(R, 0), visCol(C, 0);\n    queue<int> qq;\n    for (int u = 0; u < R; ++u) if (matchRow[u] == -1) {\n        visRow[u] = 1;\n        qq.push(u);\n    }\n    while (!qq.empty()) {\n        int u = qq.front(); qq.pop();\n        for (int v : row_adj[u]) {\n            if (matchRow[u] == v) continue;\n            if (visCol[v]) continue;\n            visCol[v] = 1;\n            int mu = matchCol[v];\n            if (mu != -1 && !visRow[mu]) {\n                visRow[mu] = 1;\n                qq.push(mu);\n            }\n        }\n    }\n    vector<char> row_cover_un(R, 0), col_cover_un(C, 0);\n    for (int r = 0; r < R; ++r) row_cover_un[r] = !visRow[r];\n    for (int c = 0; c < C; ++c) col_cover_un[c] = visCol[c];\n\n    vector<CandidatePlan> planStore;\n    planStore.reserve(PLAN_KEEP + 5);\n    long long best_cost = INFLL;\n    string best_route;\n\n    auto evaluate_spec = [&](const WeightParam &spec) {\n        apply_spec(spec);\n        Cover cover = solve_weighted_cover(row_adj, wRow, wCol);\n        Plan plan = build_plan(cover.row_cover, cover.col_cover, row_cells, col_cells,\n                               row_id, col_id, best_row_cell, best_col_cell,\n                               sorted_cells, distStart, total, start_id, R, C);\n        if (best_cost < INFLL / 4 && plan.approx > best_cost * 3 + 50000) return;\n        vector<vector<int>> treeAdj(total);\n        if (!buildSteinerTree(plan.targets, treeAdj, start_id, cost, N)) {\n            treeAdj.assign(total, {});\n            buildTreeSP(plan.targets, treeAdj, start_id, parentStart, total);\n        }\n        string route = buildRoute(treeAdj, start_id, N);\n        long long travel = simulateRoute(route, cost, N, si, sj);\n        if (travel >= INFLL / 2) return;\n        add_candidate_plan(plan.targets, travel, planStore);\n        if (travel < best_cost) {\n            best_cost = travel;\n            best_route = route;\n        }\n    };\n\n    auto startClock = chrono::steady_clock::now();\n    const double RANDOM_TIME_LIMIT = 2.7;\n\n    evaluate_spec(base_spec);\n    evaluate_spec(unweighted_spec);\n\n    int randomIter = 0;\n    const int MAX_RANDOM = 45;\n    while (randomIter < MAX_RANDOM) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startClock).count();\n        if (elapsed > RANDOM_TIME_LIMIT) break;\n        WeightParam spec = random_spec(numAnchors);\n        evaluate_spec(spec);\n        ++randomIter;\n    }\n\n    SPCache spCache(N, cost);\n    const double TSP_LIMIT = 2.98;\n    for (int i = 0; i < (int)planStore.size() && i < TSP_PLAN_LIMIT; ++i) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startClock).count();\n        if (elapsed > TSP_LIMIT) break;\n        try_tsp_route(planStore[i].targets, start_id, cost, N, si, sj,\n                      best_route, best_cost, spCache, rng);\n    }\n\n    if (best_route.empty()) {\n        vector<vector<int>> treeAdj(total);\n        vector<int> fallbackTargets = road_cells;\n        buildTreeSP(fallbackTargets, treeAdj, start_id, parentStart, total);\n        best_route = buildRoute(treeAdj, start_id, N);\n    }\n\n    cout << best_route << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Node {\n    long long priority;\n    int task;\n    bool operator<(const Node& other) const {\n        if (priority != other.priority) return priority < other.priority; // max-heap\n        return task > other.task;\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>> req(N, vector<int>(K));\n    for (int i = 0; i < N; ++i)\n        for (int k = 0; k < K; ++k)\n            cin >> req[i][k];\n\n    vector<vector<int>> adj(N);\n    vector<int> indeg(N, 0), outdeg(N, 0);\n    for (int i = 0; i < R; ++i) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        adj[u].push_back(v);\n        indeg[v]++;\n        outdeg[u]++;\n    }\n\n    vector<int> sum_d(N, 0), max_d(N, 0);\n    long long total_diff = 0;\n    for (int i = 0; i < N; ++i) {\n        int s = 0, m = 0;\n        for (int k = 0; k < K; ++k) {\n            s += req[i][k];\n            m = max(m, req[i][k]);\n        }\n        sum_d[i] = s;\n        max_d[i] = m;\n        total_diff += s;\n    }\n\n    vector<int> level(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        int best = 0;\n        for (int v : adj[i]) best = max(best, level[v] + 1);\n        level[i] = best;\n    }\n\n    vector<int> sorted_diff = sum_d;\n    sort(sorted_diff.begin(), sorted_diff.end());\n    int hard_threshold = sorted_diff[(int)(0.65 * N)];\n    hard_threshold = max(hard_threshold, 1);\n\n    vector<int> ready_since(N, (int)1e9);\n    vector<int> task_state(N, 0); // 0 not ready, 1 ready, 2 running, 3 done\n    priority_queue<Node> pq;\n\n    auto calc_priority = [&](int task, int day) -> long long {\n        long long wait = max(0, day - ready_since[task]);\n        long long val = 2'000'000LL * level[task];\n        val += 15'000LL * outdeg[task];\n        val += 80'000LL * wait;\n        val += 300LL * sum_d[task];\n        val += 1'200LL * max_d[task];\n        val += (1000 - task);\n        return val;\n    };\n    auto push_task = [&](int task, int day) {\n        pq.push({calc_priority(task, day), task});\n    };\n\n    for (int i = 0; i < N; ++i) {\n        if (indeg[i] == 0) {\n            task_state[i] = 1;\n            ready_since[i] = 1;\n            push_task(i, 1);\n        }\n    }\n\n    vector<int> worker_task(M, -1), worker_start(M, -1);\n    double avg_diff = (double)total_diff / max(1, N);\n    double baseAbility = max(1.0, avg_diff / 8.0);\n    const double MIN_ABILITY = 0.3;\n    const double MAX_ABILITY = 500.0;\n    const double ability_alpha = 0.35;\n    vector<double> ability_all(M, baseAbility);\n    vector<double> ability_easy(M, baseAbility);\n    vector<double> ability_hard(M, baseAbility);\n\n    vector<char> assignedFlag(N, 0);\n    vector<int> assignedList;\n\n    int day = 1;\n    while (true) {\n        vector<int> idle_workers;\n        for (int j = 0; j < M; ++j)\n            if (worker_task[j] == -1)\n                idle_workers.push_back(j);\n\n        vector<int> readyTasks;\n        if (!idle_workers.empty()) {\n            int limit = max(25, (int)idle_workers.size() * 4);\n            limit = min(limit, 200);\n            readyTasks.reserve(limit);\n            while ((int)readyTasks.size() < limit && !pq.empty()) {\n                Node cur = pq.top();\n                long long real = calc_priority(cur.task, day);\n                if (cur.priority != real) {\n                    pq.pop();\n                    if (task_state[cur.task] == 1)\n                        pq.push({real, cur.task});\n                    continue;\n                }\n                pq.pop();\n                if (task_state[cur.task] != 1) continue;\n                readyTasks.push_back(cur.task);\n            }\n        }\n\n        vector<int> task_order = readyTasks;\n        sort(task_order.begin(), task_order.end(), [&](int a, int b) {\n            if (level[a] != level[b]) return level[a] > level[b];\n            int waitA = max(0, day - ready_since[a]);\n            int waitB = max(0, day - ready_since[b]);\n            if (waitA != waitB) return waitA > waitB;\n            if (outdeg[a] != outdeg[b]) return outdeg[a] > outdeg[b];\n            if (sum_d[a] != sum_d[b]) return sum_d[a] > sum_d[b];\n            return a < b;\n        });\n\n        vector<char> workerUsed(M, 0);\n        vector<pair<int,int>> assignments;\n        assignedList.clear();\n\n        int remaining = idle_workers.size();\n        for (int task : task_order) {\n            if (remaining == 0) break;\n            double bestScore = 1e100;\n            int bestWorker = -1;\n            bool heavy = (sum_d[task] >= hard_threshold);\n            for (int w : idle_workers) {\n                if (workerUsed[w]) continue;\n                double ability = heavy ? ability_hard[w] : ability_easy[w];\n                ability = max(ability, MIN_ABILITY);\n                double predicted = max(1.0, sum_d[task] / ability);\n                predicted += 0.1 * max(0, level[task] - 3);\n                predicted -= 0.05 * max(0, day - ready_since[task]);\n                if (predicted + 1e-9 < bestScore ||\n                    (fabs(predicted - bestScore) <= 1e-9 &&\n                     (bestWorker == -1 || ability_all[w] > ability_all[bestWorker]))) {\n                    bestScore = predicted;\n                    bestWorker = w;\n                }\n            }\n            if (bestWorker != -1) {\n                worker_task[bestWorker] = task;\n                worker_start[bestWorker] = day;\n                task_state[task] = 2;\n                workerUsed[bestWorker] = 1;\n                assignments.emplace_back(bestWorker, task);\n                assignedFlag[task] = 1;\n                assignedList.push_back(task);\n                remaining--;\n            }\n        }\n\n        for (int task : readyTasks) {\n            if (!assignedFlag[task]) {\n                push_task(task, day);\n            }\n        }\n        for (int task : assignedList) assignedFlag[task] = 0;\n\n        cout << assignments.size();\n        for (auto &p : assignments) {\n            cout << ' ' << (p.first + 1) << ' ' << (p.second + 1);\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int n_finish;\n        if (!(cin >> n_finish)) return 0;\n        if (n_finish == -1) break;\n\n        vector<int> finished_workers(n_finish);\n        for (int i = 0; i < n_finish; ++i) {\n            cin >> finished_workers[i];\n            finished_workers[i]--;\n        }\n\n        for (int w : finished_workers) {\n            if (w < 0 || w >= M) continue;\n            int task = worker_task[w];\n            if (task == -1) continue;\n            int duration = day - worker_start[w] + 1;\n            duration = max(duration, 1);\n            double difficulty = max(1, sum_d[task]);\n            double ratio = difficulty / duration;\n\n            auto update = [&](double &val) {\n                val = val * (1.0 - ability_alpha) + ratio * ability_alpha;\n                if (val < MIN_ABILITY) val = MIN_ABILITY;\n                if (val > MAX_ABILITY) val = MAX_ABILITY;\n            };\n            ability_all[w] = ability_all[w] * (1.0 - ability_alpha) + ratio * ability_alpha;\n            ability_all[w] = min(max(ability_all[w], MIN_ABILITY), MAX_ABILITY);\n            if (sum_d[task] >= hard_threshold)\n                update(ability_hard[w]);\n            else\n                update(ability_easy[w]);\n\n            worker_task[w] = -1;\n            worker_start[w] = -1;\n            task_state[task] = 3;\n\n            for (int nxt : adj[task]) {\n                if (--indeg[nxt] == 0) {\n                    task_state[nxt] = 1;\n                    ready_since[nxt] = day + 1;\n                    push_task(nxt, day + 1);\n                }\n            }\n        }\n\n        day++;\n        if (day > 2100) break; // safety\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int ORDER_COUNT = 1000;\nconst int K = 50;\nconst int OFFICE = 400;\n\nstruct Order {\n    int ax, ay, cx, cy;\n    int len;\n    int base;\n    int officeScore;\n};\n\nstruct Node {\n    int order;\n    int type; // 0: pickup, 1: drop\n};\n\nstruct Point {\n    int x, y;\n};\n\ninline int manhattan(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\ninline int manhattan(const Point& a, const Point& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nconst Point OFFICE_POINT{OFFICE, OFFICE};\n\nstruct XorShift {\n    uint64_t state;\n    XorShift(uint64_t seed = 88172645463393265ULL) {\n        if (seed == 0) seed = 88172645463393265ULL;\n        state = seed;\n    }\n    inline uint64_t nextU64() {\n        state ^= state << 7;\n        state ^= state >> 9;\n        return state;\n    }\n    inline int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nPoint nodePoint(const Node& node, const vector<Order>& orders) {\n    const Order& ord = orders[node.order];\n    if (node.type == 0) return {ord.ax, ord.ay};\n    return {ord.cx, ord.cy};\n}\n\nlong long calcCostFromCoords(const vector<Point>& coords) {\n    Point cur = OFFICE_POINT;\n    long long cost = 0;\n    for (const Point& p : coords) {\n        cost += manhattan(cur, p);\n        cur = p;\n    }\n    cost += manhattan(cur, OFFICE_POINT);\n    return cost;\n}\n\nlong long calcNodeRouteCost(const vector<Node>& nodes, const vector<Order>& orders) {\n    vector<Point> coords;\n    coords.reserve(nodes.size());\n    for (const Node& node : nodes) coords.push_back(nodePoint(node, orders));\n    return calcCostFromCoords(coords);\n}\n\nvector<int> buildInitialRoute(const vector<int>& selected, const vector<Order>& orders, XorShift& rng) {\n    vector<int> remaining = selected;\n    vector<int> route;\n    route.reserve(selected.size());\n    Point cur = OFFICE_POINT;\n    while (!remaining.empty()) {\n        int bestIdx = 0;\n        int bestDist = INT_MAX;\n        for (int i = 0; i < (int)remaining.size(); ++i) {\n            int id = remaining[i];\n            int dist = manhattan(cur.x, cur.y, orders[id].ax, orders[id].ay);\n            if (dist < bestDist ||\n                (dist == bestDist && orders[id].len < orders[remaining[bestIdx]].len) ||\n                (dist == bestDist && orders[id].len == orders[remaining[bestIdx]].len && rng.nextInt(2))) {\n                bestDist = dist;\n                bestIdx = i;\n            }\n        }\n        int chosen = remaining[bestIdx];\n        route.push_back(chosen);\n        cur = {orders[chosen].cx, orders[chosen].cy};\n        remaining[bestIdx] = remaining.back();\n        remaining.pop_back();\n    }\n    return route;\n}\n\nlong long calcOrderRouteCost(const vector<int>& sequence, const vector<Order>& orders) {\n    Point cur = OFFICE_POINT;\n    long long cost = 0;\n    for (int id : sequence) {\n        const Order& ord = orders[id];\n        Point pick{ord.ax, ord.ay};\n        Point drop{ord.cx, ord.cy};\n        cost += manhattan(cur, pick);\n        cost += manhattan(pick, drop);\n        cur = drop;\n    }\n    cost += manhattan(cur, OFFICE_POINT);\n    return cost;\n}\n\nlong long twoOptImprove(vector<int>& route, const vector<Order>& orders) {\n    int n = route.size();\n    if (n <= 1) return calcOrderRouteCost(route, orders);\n    long long bestCost = calcOrderRouteCost(route, orders);\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int i = 0; i < n - 1; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                reverse(route.begin() + i, route.begin() + j + 1);\n                long long newCost = calcOrderRouteCost(route, orders);\n                if (newCost < bestCost) {\n                    bestCost = newCost;\n                    improved = true;\n                } else {\n                    reverse(route.begin() + i, route.begin() + j + 1);\n                }\n            }\n        }\n    }\n    return bestCost;\n}\n\nvector<Node> buildNodesFromSequence(const vector<int>& sequence) {\n    vector<Node> nodes;\n    nodes.reserve(sequence.size() * 2);\n    for (int id : sequence) {\n        nodes.push_back({id, 0});\n        nodes.push_back({id, 1});\n    }\n    return nodes;\n}\n\nvoid recomputePositions(const vector<Node>& nodes,\n                        const vector<int>& selected,\n                        vector<int>& pickPos,\n                        vector<int>& dropPos) {\n    for (int id : selected) {\n        pickPos[id] = -1;\n        dropPos[id] = -1;\n    }\n    for (int i = 0; i < (int)nodes.size(); ++i) {\n        if (nodes[i].type == 0) pickPos[nodes[i].order] = i;\n        else dropPos[nodes[i].order] = i;\n    }\n}\n\ninline void removeNode(vector<Node>& nodes, vector<Point>& coords, int pos, long long& cost) {\n    int sz = coords.size();\n    Point prev = (pos == 0 ? OFFICE_POINT : coords[pos - 1]);\n    Point curr = coords[pos];\n    Point next = (pos + 1 == sz ? OFFICE_POINT : coords[pos + 1]);\n    cost += manhattan(prev, next) - manhattan(prev, curr) - manhattan(curr, next);\n    nodes.erase(nodes.begin() + pos);\n    coords.erase(coords.begin() + pos);\n}\n\ninline void insertNode(vector<Node>& nodes, vector<Point>& coords, int pos,\n                       const Node& node, const Point& point, long long& cost) {\n    Point prev = (pos == 0 ? OFFICE_POINT : coords[pos - 1]);\n    Point next = (pos == (int)coords.size() ? OFFICE_POINT : coords[pos]);\n    cost += -manhattan(prev, next) + manhattan(prev, point) + manhattan(point, next);\n    nodes.insert(nodes.begin() + pos, node);\n    coords.insert(coords.begin() + pos, point);\n}\n\nbool saMoveSingle(vector<Node>& nodes,\n                  vector<Point>& coords,\n                  vector<int>& pickPos,\n                  vector<int>& dropPos,\n                  const vector<int>& selected,\n                  long long& currCost,\n                  long long& bestCost,\n                  vector<Node>& bestNodes,\n                  vector<Point>& bestCoords,\n                  double temp,\n                  XorShift& rng) {\n    int L = nodes.size();\n    if (L <= 1) return false;\n    int origPos = rng.nextInt(L);\n    Node node = nodes[origPos];\n    Point point = coords[origPos];\n    long long prevCost = currCost;\n\n    removeNode(nodes, coords, origPos, currCost);\n    int n = nodes.size();\n    int insertPos = rng.nextInt(n + 1);\n\n    bool feasible = true;\n    if (node.type == 0) {\n        int dropIdx = dropPos[node.order];\n        if (dropIdx == -1) feasible = false;\n        else {\n            if (dropIdx > origPos) dropIdx--;\n            if (insertPos > dropIdx) feasible = false;\n        }\n    } else {\n        int pickIdx = pickPos[node.order];\n        if (pickIdx == -1) feasible = false;\n        else {\n            if (pickIdx > origPos) pickIdx--;\n            if (insertPos <= pickIdx) feasible = false;\n        }\n    }\n\n    if (!feasible) {\n        insertNode(nodes, coords, origPos, node, point, currCost);\n        currCost = prevCost;\n        return false;\n    }\n\n    insertNode(nodes, coords, insertPos, node, point, currCost);\n    long long newCost = currCost;\n    bool accept = false;\n    if (newCost <= prevCost) accept = true;\n    else {\n        double prob = exp((double)(prevCost - newCost) / temp);\n        if (prob > rng.nextDouble()) accept = true;\n    }\n    if (accept) {\n        if (newCost < bestCost) {\n            bestCost = newCost;\n            bestNodes = nodes;\n            bestCoords = coords;\n        }\n        recomputePositions(nodes, selected, pickPos, dropPos);\n    } else {\n        removeNode(nodes, coords, insertPos, currCost);\n        insertNode(nodes, coords, origPos, node, point, currCost);\n        currCost = prevCost;\n    }\n    return true;\n}\n\nbool saMovePair(vector<Node>& nodes,\n                vector<Point>& coords,\n                vector<int>& pickPos,\n                vector<int>& dropPos,\n                const vector<int>& selected,\n                long long& currCost,\n                long long& bestCost,\n                vector<Node>& bestNodes,\n                vector<Point>& bestCoords,\n                double temp,\n                XorShift& rng) {\n    if (selected.empty()) return false;\n    int orderId = selected[rng.nextInt(selected.size())];\n    int posPick = pickPos[orderId];\n    int posDrop = dropPos[orderId];\n    if (posPick == -1 || posDrop == -1) return false;\n    if (posPick > posDrop) swap(posPick, posDrop);\n\n    Node pickNode = nodes[posPick];\n    Point pickPoint = coords[posPick];\n    Node dropNode = nodes[posDrop];\n    Point dropPoint = coords[posDrop];\n    long long prevCost = currCost;\n\n    removeNode(nodes, coords, posDrop, currCost);\n    removeNode(nodes, coords, posPick, currCost);\n\n    int n = nodes.size();\n    int insertPick = rng.nextInt(n + 1);\n    insertNode(nodes, coords, insertPick, pickNode, pickPoint, currCost);\n\n    int sizeAfterPick = nodes.size();\n    int insertDrop = rng.nextInt(sizeAfterPick - insertPick) + insertPick + 1;\n    insertNode(nodes, coords, insertDrop, dropNode, dropPoint, currCost);\n\n    long long newCost = currCost;\n    bool accept = false;\n    if (newCost <= prevCost) accept = true;\n    else {\n        double prob = exp((double)(prevCost - newCost) / temp);\n        if (prob > rng.nextDouble()) accept = true;\n    }\n    if (accept) {\n        if (newCost < bestCost) {\n            bestCost = newCost;\n            bestNodes = nodes;\n            bestCoords = coords;\n        }\n        recomputePositions(nodes, selected, pickPos, dropPos);\n    } else {\n        removeNode(nodes, coords, insertDrop, currCost);\n        removeNode(nodes, coords, insertPick, currCost);\n        insertNode(nodes, coords, posPick, pickNode, pickPoint, currCost);\n        insertNode(nodes, coords, posDrop, dropNode, dropPoint, currCost);\n        currCost = prevCost;\n    }\n    return true;\n}\n\nlong long runNodeSA(vector<Node>& nodes,\n                    const vector<int>& selected,\n                    const vector<Order>& orders,\n                    double timeLimit,\n                    XorShift& rng,\n                    chrono::steady_clock::time_point globalStart,\n                    double globalLimit) {\n    vector<Point> coords(nodes.size());\n    for (int i = 0; i < (int)nodes.size(); ++i) coords[i] = nodePoint(nodes[i], orders);\n    long long currCost = calcCostFromCoords(coords);\n    long long bestCost = currCost;\n    vector<Node> bestNodes = nodes;\n    vector<Point> bestCoords = coords;\n\n    vector<int> pickPos(ORDER_COUNT, -1), dropPos(ORDER_COUNT, -1);\n    recomputePositions(nodes, selected, pickPos, dropPos);\n\n    if (timeLimit <= 1e-6) {\n        nodes = bestNodes;\n        return bestCost;\n    }\n\n    const double START_TEMP = 2000.0;\n    const double END_TEMP = 5.0;\n    const double LOG_RATIO = std::log(END_TEMP / START_TEMP);\n    auto localStart = chrono::steady_clock::now();\n    double temp = START_TEMP;\n    long long iter = 0;\n    while (true) {\n        if ((iter & 0x3FFLL) == 0) {\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - localStart).count();\n            double globalElapsed = chrono::duration<double>(now - globalStart).count();\n            if (elapsed > timeLimit || globalElapsed > globalLimit) break;\n            double progress = min(1.0, elapsed / timeLimit);\n            temp = START_TEMP * exp(LOG_RATIO * progress);\n        }\n        ++iter;\n        int op = rng.nextInt(100);\n        if (op < 70) {\n            saMoveSingle(nodes, coords, pickPos, dropPos, selected,\n                         currCost, bestCost, bestNodes, bestCoords, temp, rng);\n        } else {\n            saMovePair(nodes, coords, pickPos, dropPos, selected,\n                       currCost, bestCost, bestNodes, bestCoords, temp, rng);\n        }\n    }\n    nodes = bestNodes;\n    return bestCost;\n}\n\nvector<pair<int, int>> buildPathFromNodes(const vector<Node>& nodes, const vector<Order>& orders) {\n    vector<pair<int, int>> path;\n    path.reserve(nodes.size() + 2);\n    path.emplace_back(OFFICE_POINT.x, OFFICE_POINT.y);\n    for (const Node& node : nodes) {\n        Point p = nodePoint(node, orders);\n        path.emplace_back(p.x, p.y);\n    }\n    path.emplace_back(OFFICE_POINT.x, OFFICE_POINT.y);\n    return path;\n}\n\nstruct RouteSolution {\n    vector<int> selectedOrders;\n    vector<Node> nodes;\n    long long cost = (1LL << 60);\n};\n\nvector<int> extractSelectedOrders(const vector<Node>& nodes) {\n    vector<int> res;\n    vector<char> seen(ORDER_COUNT, 0);\n    for (const Node& node : nodes) {\n        if (node.type == 0 && !seen[node.order]) {\n            seen[node.order] = 1;\n            res.push_back(node.order);\n        }\n    }\n    return res;\n}\n\nRouteSolution optimizeSet(const vector<int>& selected,\n                          double saTime,\n                          const vector<Order>& orders,\n                          XorShift& rng,\n                          chrono::steady_clock::time_point globalStart,\n                          double globalLimit) {\n    RouteSolution sol;\n    sol.selectedOrders = selected;\n    vector<int> route = buildInitialRoute(selected, orders, rng);\n    twoOptImprove(route, orders);\n    vector<Node> nodes = buildNodesFromSequence(route);\n    long long cost = runNodeSA(nodes, selected, orders, saTime, rng, globalStart, globalLimit);\n    sol.cost = cost;\n    sol.nodes = nodes;\n    return sol;\n}\n\nstruct PosDelta {\n    int pos;\n    int delta;\n};\n\nvector<PosDelta> enumerateInsertOptions(const vector<Point>& coords,\n                                        const Point& insertPoint,\n                                        int startPos,\n                                        int limit,\n                                        int randomExtra,\n                                        XorShift& rng) {\n    int M = coords.size();\n    startPos = max(0, min(startPos, M));\n    vector<PosDelta> opts;\n    opts.reserve(M - startPos + 1);\n    for (int pos = startPos; pos <= M; ++pos) {\n        const Point& prev = (pos == 0 ? OFFICE_POINT : coords[pos - 1]);\n        const Point& next = (pos == M ? OFFICE_POINT : coords[pos]);\n        int delta = manhattan(prev, insertPoint) + manhattan(insertPoint, next) - manhattan(prev, next);\n        opts.push_back({pos, delta});\n    }\n    sort(opts.begin(), opts.end(), [](const PosDelta& a, const PosDelta& b) {\n        if (a.delta != b.delta) return a.delta < b.delta;\n        return a.pos < b.pos;\n    });\n    vector<PosDelta> res;\n    int take = min(limit, (int)opts.size());\n    for (int i = 0; i < take; ++i) res.push_back(opts[i]);\n    int attempts = randomExtra;\n    while (attempts-- > 0 && (int)res.size() < (int)opts.size()) {\n        int idx = rng.nextInt(opts.size());\n        int pos = opts[idx].pos;\n        bool exist = false;\n        for (const auto& pd : res) if (pd.pos == pos) { exist = true; break; }\n        if (!exist) res.push_back(opts[idx]);\n    }\n    return res;\n}\n\ntemplate <class T>\nvoid shuffleWithRNG(vector<T>& vec, XorShift& rng) {\n    for (int i = (int)vec.size() - 1; i > 0; --i) {\n        int j = rng.nextInt(i + 1);\n        swap(vec[i], vec[j]);\n    }\n}\n\nvoid swapImprove(RouteSolution& sol,\n                 const vector<Order>& orders,\n                 const vector<int>& ranking,\n                 double timeLimit,\n                 chrono::steady_clock::time_point globalStart,\n                 double globalLimit,\n                 XorShift& rng) {\n    if (timeLimit <= 1e-4) return;\n    auto localStart = chrono::steady_clock::now();\n    vector<Node>& bestNodes = sol.nodes;\n    long long bestCost = sol.cost;\n\n    vector<int> selectedOrders = extractSelectedOrders(bestNodes);\n    vector<char> inSelected(ORDER_COUNT, 0);\n    for (int id : selectedOrders) inSelected[id] = 1;\n\n    const int CAND_LIMIT = 100;\n    const int PICK_LIMIT = 10;\n    const int DROP_LIMIT = 12;\n    const int RANDOM_PICK = 3;\n    const int RANDOM_DROP = 3;\n\n    auto timeExceeded = [&]() -> bool {\n        auto now = chrono::steady_clock::now();\n        double localElapsed = chrono::duration<double>(now - localStart).count();\n        double globalElapsed = chrono::duration<double>(now - globalStart).count();\n        return (localElapsed > timeLimit) || (globalElapsed > globalLimit);\n    };\n\n    bool timeup = false;\n    while (!timeup) {\n        if (timeExceeded()) break;\n        vector<int> candidatePool;\n        candidatePool.reserve(CAND_LIMIT);\n        for (int idx : ranking) {\n            if (!inSelected[idx]) {\n                candidatePool.push_back(idx);\n                if ((int)candidatePool.size() >= CAND_LIMIT) break;\n            }\n        }\n        if (candidatePool.empty()) break;\n        shuffleWithRNG(candidatePool, rng);\n        vector<int> removalOrder = selectedOrders;\n        shuffleWithRNG(removalOrder, rng);\n\n        bool improvement = false;\n\n        for (int removeId : removalOrder) {\n            if (timeExceeded()) { timeup = true; break; }\n\n            vector<Node> baseNodes;\n            baseNodes.reserve(bestNodes.size() - 2);\n            for (const Node& node : bestNodes) {\n                if (node.order == removeId) continue;\n                baseNodes.push_back(node);\n            }\n            if ((int)baseNodes.size() != (int)bestNodes.size() - 2) continue;\n\n            long long baseCost = calcNodeRouteCost(baseNodes, orders);\n\n            vector<Point> baseCoords;\n            baseCoords.reserve(baseNodes.size());\n            for (const Node& node : baseNodes) {\n                baseCoords.push_back(nodePoint(node, orders));\n            }\n\n            for (int candId : candidatePool) {\n                if (inSelected[candId]) continue;\n                if (timeExceeded()) { timeup = true; break; }\n\n                Point pickPoint{orders[candId].ax, orders[candId].ay};\n                auto pickOptions = enumerateInsertOptions(baseCoords, pickPoint, 0, PICK_LIMIT, RANDOM_PICK, rng);\n                if (pickOptions.empty()) continue;\n\n                for (const auto& pickOpt : pickOptions) {\n                    if (timeExceeded()) { timeup = true; break; }\n\n                    int pickPos = pickOpt.pos;\n                    int deltaPick = pickOpt.delta;\n\n                    vector<Point> coordsWithPick = baseCoords;\n                    coordsWithPick.insert(coordsWithPick.begin() + pickPos, pickPoint);\n\n                    Point dropPoint{orders[candId].cx, orders[candId].cy};\n                    auto dropOptions = enumerateInsertOptions(coordsWithPick, dropPoint, pickPos + 1, DROP_LIMIT, RANDOM_DROP, rng);\n                    if (dropOptions.empty()) continue;\n\n                    if ((long long)baseCost + deltaPick + dropOptions[0].delta >= bestCost) continue;\n\n                    for (const auto& dropOpt : dropOptions) {\n                        long long candidateCost = (long long)baseCost + deltaPick + dropOpt.delta;\n                        if (candidateCost >= bestCost) continue;\n\n                        vector<Node> improved = baseNodes;\n                        improved.insert(improved.begin() + pickPos, Node{candId, 0});\n                        improved.insert(improved.begin() + dropOpt.pos, Node{candId, 1});\n\n                        bestNodes = move(improved);\n                        bestCost = candidateCost;\n                        inSelected[removeId] = 0;\n                        inSelected[candId] = 1;\n                        for (int& x : selectedOrders) if (x == removeId) { x = candId; break; }\n                        improvement = true;\n                        break;\n                    }\n                    if (timeExceeded()) { timeup = true; break; }\n                    if (improvement) break;\n                }\n                if (timeExceeded()) { timeup = true; break; }\n                if (improvement) break;\n            }\n            if (timeExceeded()) { timeup = true; break; }\n            if (improvement) break;\n        }\n        if (timeExceeded()) break;\n        if (!improvement) break;\n    }\n\n    sol.nodes = bestNodes;\n    sol.cost = calcNodeRouteCost(sol.nodes, orders);\n    sol.selectedOrders = extractSelectedOrders(sol.nodes);\n}\n\nvector<pair<int, int>> pathFromNodes(const vector<Node>& nodes, const vector<Order>& orders) {\n    return buildPathFromNodes(nodes, orders);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<Order> orders(ORDER_COUNT);\n    for (int i = 0; i < ORDER_COUNT; ++i) {\n        cin >> orders[i].ax >> orders[i].ay >> orders[i].cx >> orders[i].cy;\n        orders[i].len = manhattan(orders[i].ax, orders[i].ay, orders[i].cx, orders[i].cy);\n        orders[i].base = manhattan(OFFICE, OFFICE, orders[i].ax, orders[i].ay) +\n                         orders[i].len +\n                         manhattan(orders[i].cx, orders[i].cy, OFFICE, OFFICE);\n        orders[i].officeScore = manhattan(OFFICE, OFFICE, orders[i].ax, orders[i].ay) +\n                                manhattan(OFFICE, OFFICE, orders[i].cx, orders[i].cy);\n    }\n\n    vector<int> idx(ORDER_COUNT);\n    iota(idx.begin(), idx.end(), 0);\n\n    vector<int> byBase = idx;\n    sort(byBase.begin(), byBase.end(), [&](int a, int b) {\n        if (orders[a].base != orders[b].base) return orders[a].base < orders[b].base;\n        return a < b;\n    });\n    vector<int> byOffice = idx;\n    sort(byOffice.begin(), byOffice.end(), [&](int a, int b) {\n        if (orders[a].officeScore != orders[b].officeScore) return orders[a].officeScore < orders[b].officeScore;\n        return a < b;\n    });\n    vector<int> byLen = idx;\n    sort(byLen.begin(), byLen.end(), [&](int a, int b) {\n        if (orders[a].len != orders[b].len) return orders[a].len < orders[b].len;\n        return a < b;\n    });\n\n    auto firstK = [&](const vector<int>& arr) {\n        vector<int> res;\n        for (int i = 0; i < K; ++i) res.push_back(arr[i]);\n        return res;\n    };\n\n    XorShift rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    vector<vector<int>> candidateSets;\n    candidateSets.push_back(firstK(byBase));\n    candidateSets.push_back(firstK(byOffice));\n    candidateSets.push_back(firstK(byLen));\n\n    auto makeRandomSet = [&](const vector<int>& pool, int noiseRange) -> vector<int> {\n        vector<pair<long long, int>> tmp;\n        tmp.reserve(pool.size());\n        for (int id : pool) {\n            long long noise = (long long)(rng.nextU64() % (noiseRange + 1));\n            long long score = (long long)orders[id].base + noise;\n            tmp.emplace_back(score, id);\n        }\n        sort(tmp.begin(), tmp.end());\n        vector<int> res;\n        for (int i = 0; i < K && i < (int)tmp.size(); ++i) res.push_back(tmp[i].second);\n        return res;\n    };\n\n    vector<int> poolTop;\n    int poolTopSize = min(300, ORDER_COUNT);\n    for (int i = 0; i < poolTopSize; ++i) poolTop.push_back(byBase[i]);\n    if (!poolTop.empty()) candidateSets.push_back(makeRandomSet(poolTop, 4000));\n    candidateSets.push_back(makeRandomSet(idx, 8000));\n\n    auto globalStart = chrono::steady_clock::now();\n    const double GLOBAL_LIMIT = 1.95;\n    const double STAGE1_LIMIT = 1.35;\n\n    int maxSets = min(5, (int)candidateSets.size());\n    RouteSolution bestSolution;\n    for (int setIdx = 0; setIdx < maxSets; ++setIdx) {\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - globalStart).count();\n        if (elapsed >= STAGE1_LIMIT || elapsed >= GLOBAL_LIMIT - 0.4) break;\n        double remainingStage = STAGE1_LIMIT - elapsed;\n        double globalRemaining = GLOBAL_LIMIT - elapsed;\n        if (remainingStage <= 0.05 || globalRemaining <= 0.4) break;\n        int setsLeft = maxSets - setIdx;\n        double saTime = min(0.35, remainingStage / setsLeft);\n        saTime = max(saTime, 0.02);\n        RouteSolution sol = optimizeSet(candidateSets[setIdx], saTime, orders, rng, globalStart, GLOBAL_LIMIT);\n        if (sol.cost < bestSolution.cost) bestSolution = sol;\n    }\n    if (bestSolution.cost == (1LL << 60)) {\n        bestSolution = optimizeSet(candidateSets[0], 0.2, orders, rng, globalStart, GLOBAL_LIMIT);\n    }\n\n    auto ensureSelectedOrders = [&]() {\n        bestSolution.selectedOrders = extractSelectedOrders(bestSolution.nodes);\n    };\n    ensureSelectedOrders();\n    bestSolution.cost = calcNodeRouteCost(bestSolution.nodes, orders);\n\n    auto now = chrono::steady_clock::now();\n    double elapsed = chrono::duration<double>(now - globalStart).count();\n    double remaining = GLOBAL_LIMIT - elapsed;\n\n    if (remaining > 0.1) {\n        double swapTime = min(0.45, remaining - 0.05);\n        swapImprove(bestSolution, orders, byBase, swapTime, globalStart, GLOBAL_LIMIT, rng);\n        ensureSelectedOrders();\n    }\n\n    now = chrono::steady_clock::now();\n    elapsed = chrono::duration<double>(now - globalStart).count();\n    remaining = GLOBAL_LIMIT - elapsed;\n    if (remaining > 0.08) {\n        double finalTime = min(0.2, remaining - 0.03);\n        if (finalTime > 0.0) {\n            vector<int> selected = extractSelectedOrders(bestSolution.nodes);\n            long long newCost = runNodeSA(bestSolution.nodes, selected, orders, finalTime, rng, globalStart, GLOBAL_LIMIT);\n            bestSolution.cost = newCost;\n            ensureSelectedOrders();\n        }\n    }\n\n    vector<int> orderOutput = extractSelectedOrders(bestSolution.nodes);\n    orderOutput.resize(K);\n\n    vector<pair<int, int>> path = buildPathFromNodes(bestSolution.nodes, orders);\n\n    cout << K;\n    for (int id : orderOutput) cout << ' ' << (id + 1);\n    cout << '\\n';\n    cout << path.size();\n    for (auto [x, y] : path) cout << ' ' << x << ' ' << y;\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 400;\nconstexpr int M = 1995;\nconstexpr int LIGHT_LIMIT = 135;\n\nstruct Edge {\n    int u, v;\n    int d;\n    bool in_ref = false;\n};\n\nstruct DSU {\n    vector<int> parent;\n    vector<int> sz;\n    int comp;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        parent.resize(n);\n        sz.assign(n, 1);\n        iota(parent.begin(), parent.end(), 0);\n        comp = n;\n    }\n    int find(int x) {\n        if (parent[x] == x) return x;\n        return parent[x] = find(parent[x]);\n    }\n    int root_size(int r) const { return sz[r]; }\n    int merge_roots(int a, int b, int &loser) {\n        a = find(a);\n        b = find(b);\n        if (a == b) {\n            loser = -1;\n            return a;\n        }\n        if (sz[a] < sz[b]) swap(a, b);\n        parent[b] = a;\n        sz[a] += sz[b];\n        sz[b] = 0;\n        comp--;\n        loser = b;\n        return a;\n    }\n};\n\nstruct CompStats {\n    int best_d;\n    int second_d;\n    int light_cnt;\n    int total;\n};\n\nint rounded_distance(const pair<int,int>& A, const pair<int,int>& B) {\n    long long dx = (long long)A.first - B.first;\n    long long dy = (long long)A.second - B.second;\n    double dist = std::sqrt((double)dx * dx + (double)dy * dy);\n    return (int)std::llround(dist);\n}\n\nvoid remove_future_edge(int ru, int rv,\n                        vector<vector<int>>& adj, vector<int>& out_deg) {\n    if (ru == rv) return;\n    if (adj[ru][rv] > 0) {\n        --adj[ru][rv];\n        --adj[rv][ru];\n    } else {\n        adj[ru][rv] = adj[rv][ru] = 0;\n    }\n    if (out_deg[ru] > 0) --out_deg[ru];\n    if (out_deg[rv] > 0) --out_deg[rv];\n}\n\nvoid merge_adj(int keep, int lose,\n               vector<vector<int>>& adj, vector<int>& out_deg) {\n    if (lose < 0 || keep == lose) return;\n    int between = adj[keep][lose];\n    adj[keep][lose] = adj[lose][keep] = 0;\n    out_deg[keep] = max(0, out_deg[keep] + out_deg[lose] - 2 * between);\n    out_deg[lose] = 0;\n    for (int c = 0; c < N; ++c) {\n        if (c == keep || c == lose) continue;\n        int add = adj[lose][c];\n        if (!add) continue;\n        adj[keep][c] += add;\n        adj[c][keep] = adj[keep][c];\n        adj[lose][c] = adj[c][lose] = 0;\n    }\n    adj[keep][keep] = 0;\n}\n\nvoid merge_edge_lists(int keep, int lose, vector<vector<int>>& comp_edges) {\n    if (lose < 0 || keep == lose) return;\n    if (comp_edges[keep].size() < comp_edges[lose].size())\n        comp_edges[keep].swap(comp_edges[lose]);\n    comp_edges[keep].insert(comp_edges[keep].end(),\n                            comp_edges[lose].begin(),\n                            comp_edges[lose].end());\n    vector<int>().swap(comp_edges[lose]);\n}\n\nCompStats get_comp_stats(int root, DSU &dsu,\n                         const vector<Edge>& edges,\n                         const vector<char>& processed,\n                         const vector<vector<int>>& comp_edges,\n                         int target = -1,\n                         int* best_cross = nullptr,\n                         int* cross_light = nullptr) {\n    const int INF_D = 1e9;\n    if (best_cross) *best_cross = INF_D;\n    if (cross_light) *cross_light = 0;\n\n    int best = INF_D;\n    int second = INF_D;\n    int lights = 0;\n    int total = 0;\n\n    for (int idx : comp_edges[root]) {\n        if (processed[idx]) continue;\n        const Edge &e = edges[idx];\n        int a = dsu.find(e.u);\n        int b = dsu.find(e.v);\n        if (a == b) continue;\n        if (a != root && b != root) continue;\n\n        ++total;\n        int d = e.d;\n        if (d < best) {\n            second = best;\n            best = d;\n        } else if (d < second) {\n            second = d;\n        }\n        if (d <= LIGHT_LIMIT) ++lights;\n\n        if (target != -1 && best_cross) {\n            int other = (a == root) ? b : a;\n            if (other == target) {\n                if (d < *best_cross) *best_cross = d;\n                if (cross_light && d <= LIGHT_LIMIT) ++(*cross_light);\n            }\n        }\n    }\n    if (best == INF_D) second = INF_D;\n    return {best, second, lights, total};\n}\n\ndouble compute_threshold(double progress, double comp_frac,\n                         const Edge& edge, double len,\n                         int sizeA, int sizeB,\n                         int outA, int outB,\n                         const CompStats& statsA,\n                         const CompStats& statsB,\n                         int best_cross, int cross_light,\n                         int direct_remaining,\n                         double slack_ratio, double slack_norm,\n                         int k_any, int k_direct) {\n    using std::clamp;\n    using std::pow;\n\n    constexpr double BASE_START = 1.03;\n    constexpr double BASE_END = 2.08;\n    constexpr double BASE_POWER = 0.78;\n    constexpr double COMP_COEFF = 0.32;\n    constexpr double COMP_POWER = 0.82;\n    constexpr double LAG_COEFF = 0.44;\n    constexpr double LEAD_COEFF = 0.11;\n    constexpr double SIZE_COEFF = 0.28;\n    constexpr double SIZE_POWER = 0.62;\n    constexpr double SMALLD_LIMIT = 150.0;\n    constexpr double SMALLD_COEFF = 0.30;\n    constexpr double LARGE_LIMIT = 260.0;\n    constexpr double LARGE_SPAN = 360.0;\n    constexpr double LARGE_COEFF = 0.11;\n    constexpr double REF_BONUS = 0.22;\n    constexpr double DENSITY_TARGET = 1.8;\n    constexpr double DENSITY_COEFF = 0.42;\n    constexpr double OUT_TARGET = 8.0;\n    constexpr double OUT_COEFF = 0.31;\n    constexpr double LEN_REFERENCE = 200.0;\n    constexpr double LEN_COEFF = 0.15;\n    constexpr double SCARCITY_COEFF = 0.17;\n    constexpr double LIGHT_NONE_BONUS = 0.18;\n    constexpr double LIGHT_FEW_BONUS = 0.09;\n    constexpr double LIGHT_MANY_PENALTY = 0.06;\n    constexpr double FUTURE_COEFF = 0.35;\n    constexpr double NO_FUTURE_BONUS = 0.33;\n    constexpr double GAP_COEFF = 0.13;\n    constexpr double GAP_WINDOW = 60.0;\n    constexpr double DIRECT_BONUS = 0.18;\n    constexpr double DIRECT_PENALTY = 0.03;\n    constexpr double CROSS_NONE_BONUS = 0.28;\n    constexpr double CROSS_ADV_COEFF = 0.33;\n    constexpr double CROSS_SUP_COEFF = 0.11;\n    constexpr double CROSS_LIGHT_COEFF = 0.05;\n    constexpr double SLACK_LOW_LIMIT = 0.25;\n    constexpr double SLACK_HIGH_LIMIT = 0.95;\n    constexpr double SLACK_LOW_COEFF = 0.30;\n    constexpr double SLACK_HIGH_COEFF = 0.17;\n    constexpr double SLACK_ABS_COEFF = 0.22;\n    constexpr double EXPECT_ANY_PULL = 0.18;\n    constexpr double EXPECT_DIRECT_PULL = 0.14;\n    constexpr double MIN_THRESHOLD = 0.92;\n    constexpr double MAX_THRESHOLD = 2.65;\n    constexpr int INF_D = 1e9;\n\n    progress = clamp(progress, 0.0, 1.0);\n    comp_frac = clamp(comp_frac, 0.0, 1.0);\n\n    double base = BASE_START + (BASE_END - BASE_START) * pow(progress, BASE_POWER);\n    base += COMP_COEFF * pow(comp_frac, COMP_POWER);\n    double lag = clamp(progress - comp_frac, 0.0, 1.0);\n    double lead = clamp(comp_frac - progress, 0.0, 1.0);\n    base += LAG_COEFF * lag;\n    base -= LEAD_COEFF * lead;\n\n    double thr = base;\n    double size_frac = double(sizeA + sizeB) / double(N);\n    thr += SIZE_COEFF * pow(size_frac, SIZE_POWER);\n\n    double small_factor = clamp((SMALLD_LIMIT - double(edge.d)) / SMALLD_LIMIT, -1.0, 1.0);\n    thr += SMALLD_COEFF * small_factor;\n    double large_factor = clamp((double(edge.d) - LARGE_LIMIT) / LARGE_SPAN, 0.0, 1.0);\n    thr -= LARGE_COEFF * large_factor;\n\n    if (edge.in_ref) thr += REF_BONUS;\n\n    double densityA = sizeA > 0 ? double(outA) / double(sizeA) : 0.0;\n    double densityB = sizeB > 0 ? double(outB) / double(sizeB) : 0.0;\n    double density = min(densityA, densityB);\n    double density_need = clamp((DENSITY_TARGET - density) / DENSITY_TARGET, 0.0, 1.5);\n    thr += DENSITY_COEFF * density_need;\n\n    int min_out = min(outA, outB);\n    double scarcity = clamp((OUT_TARGET - double(min_out)) / OUT_TARGET, 0.0, 1.5);\n    thr += OUT_COEFF * scarcity;\n\n    double len_effect = clamp((LEN_REFERENCE - len) / LEN_REFERENCE, -1.0, 1.0);\n    thr += LEN_COEFF * len_effect;\n\n    if (statsA.total <= 2) thr += SCARCITY_COEFF;\n    if (statsB.total <= 2) thr += SCARCITY_COEFF;\n\n    int light_total = statsA.light_cnt + statsB.light_cnt;\n    if (light_total == 0) thr += LIGHT_NONE_BONUS;\n    else if (light_total <= 2) thr += LIGHT_FEW_BONUS;\n    else if (light_total >= 7) thr -= LIGHT_MANY_PENALTY;\n\n    int best_future = min(statsA.best_d, statsB.best_d);\n    if (best_future >= INF_D / 2) {\n        thr += NO_FUTURE_BONUS;\n    } else {\n        double future_rel = (double(best_future) - double(edge.d)) /\n                            max(60.0, double(edge.d));\n        thr += FUTURE_COEFF * future_rel;\n    }\n\n    auto gap_value = [&](const CompStats& st) -> double {\n        if (st.second_d >= INF_D / 2 || st.best_d >= INF_D / 2) return GAP_WINDOW;\n        return double(st.second_d - st.best_d);\n    };\n    double gap = min(gap_value(statsA), gap_value(statsB));\n    if (gap < GAP_WINDOW) {\n        double gap_term = clamp((GAP_WINDOW - gap) / GAP_WINDOW, 0.0, 1.0);\n        thr -= GAP_COEFF * gap_term;\n    }\n\n    if (best_cross >= INF_D / 2) {\n        thr += CROSS_NONE_BONUS;\n    } else {\n        double diff = double(edge.d) - double(best_cross);\n        if (diff > 0) {\n            double norm = clamp(diff / max(40.0, double(edge.d)), 0.0, 1.5);\n            thr -= CROSS_ADV_COEFF * norm;\n            if (cross_light > 0) {\n                thr -= CROSS_LIGHT_COEFF * min(3, cross_light);\n            }\n        } else if (diff < 0) {\n            double norm = clamp((-diff) / max(40.0, double(edge.d)), 0.0, 1.0);\n            thr += CROSS_SUP_COEFF * norm;\n        }\n    }\n\n    if (direct_remaining == 0) {\n        thr += DIRECT_BONUS * (0.6 + 0.4 * size_frac);\n    } else {\n        thr -= DIRECT_PENALTY * min(direct_remaining, 4);\n    }\n\n    slack_ratio = clamp(slack_ratio, 0.0, 2.0);\n    slack_norm = clamp(slack_norm, 0.0, 1.0);\n    double low_term = clamp((SLACK_LOW_LIMIT - slack_ratio) / SLACK_LOW_LIMIT, 0.0, 1.0);\n    thr += SLACK_LOW_COEFF * low_term;\n    double high_term = clamp((slack_ratio - SLACK_HIGH_LIMIT) / (1.35 - SLACK_HIGH_LIMIT), 0.0, 1.0);\n    thr -= SLACK_HIGH_COEFF * high_term;\n    thr -= SLACK_ABS_COEFF * slack_norm;\n\n    if (k_any > 0) {\n        double exp_any = 1.0 + 2.0 / double(k_any + 1);\n        exp_any = clamp(exp_any, 1.0, 3.0);\n        thr -= EXPECT_ANY_PULL * (thr - exp_any);\n    }\n    if (k_direct > 0) {\n        double exp_direct = 1.0 + 2.0 / double(k_direct + 1);\n        exp_direct = clamp(exp_direct, 1.0, 3.0);\n        thr -= EXPECT_DIRECT_PULL * (thr - exp_direct);\n    }\n\n    return clamp(thr, MIN_THRESHOLD, MAX_THRESHOLD);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<pair<int,int>> pos(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> pos[i].first >> pos[i].second;\n    }\n\n    vector<Edge> edges(M);\n    vector<vector<int>> adj(N, vector<int>(N, 0));\n    vector<int> out_deg(N, 0);\n    vector<vector<int>> comp_edges(N);\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        edges[i].d = rounded_distance(pos[u], pos[v]);\n        adj[u][v] += 1;\n        adj[v][u] += 1;\n        out_deg[u] += 1;\n        out_deg[v] += 1;\n        comp_edges[u].push_back(i);\n        comp_edges[v].push_back(i);\n    }\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n    DSU mst_dsu(N);\n    int need = N - 1;\n    for (int idx : order) {\n        int loser;\n        mst_dsu.merge_roots(edges[idx].u, edges[idx].v, loser);\n        if (loser != -1) {\n            edges[idx].in_ref = true;\n            if (--need == 0) break;\n        }\n    }\n\n    DSU dsu(N);\n    vector<char> processed(M, false);\n    std::mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n    std::uniform_real_distribution<double> noise_dist(-0.012, 0.012);\n\n    for (int i = 0; i < M; ++i) {\n        int len;\n        if (!(cin >> len)) return 0;\n        Edge &edge = edges[i];\n        int ru = dsu.find(edge.u);\n        int rv = dsu.find(edge.v);\n        processed[i] = true;\n\n        if (ru == rv) {\n            cout << 0 << '\\n' << flush;\n            continue;\n        }\n\n        remove_future_edge(ru, rv, adj, out_deg);\n        int direct_after = adj[ru][rv];\n\n        bool accept = false;\n        if (out_deg[ru] == 0 || out_deg[rv] == 0) {\n            accept = true;\n        }\n\n        int future_edges = M - i - 1;\n        int need_edges = dsu.comp - 1;\n        int slack_edges = max(future_edges - need_edges, 0);\n        double slack_ratio = double(slack_edges + 1) / double(need_edges + 1);\n        double slack_norm = double(slack_edges) / double(M);\n\n        CompStats statsA{}, statsB{};\n        int best_cross = 1e9;\n        int cross_light = 0;\n\n        if (!accept) {\n            statsA = get_comp_stats(ru, dsu, edges, processed, comp_edges,\n                                    rv, &best_cross, &cross_light);\n            statsB = get_comp_stats(rv, dsu, edges, processed, comp_edges);\n\n            int sizeA = dsu.root_size(ru);\n            int sizeB = dsu.root_size(rv);\n            int outA = out_deg[ru];\n            int outB = out_deg[rv];\n            double progress = double(i) / double(M);\n            double comp_frac = double(N - dsu.comp) / double(N - 1);\n\n            int k_any = min(statsA.total, statsB.total);\n            int k_direct = direct_after;\n\n            double threshold = compute_threshold(progress, comp_frac, edge, double(len),\n                                                 sizeA, sizeB, outA, outB,\n                                                 statsA, statsB,\n                                                 best_cross, cross_light,\n                                                 direct_after,\n                                                 slack_ratio, slack_norm,\n                                                 k_any, k_direct);\n            threshold += noise_dist(rng);\n            threshold = std::clamp(threshold, 0.90, 2.70);\n\n            double ratio = double(len) / double(max(edge.d, 1));\n            if (ratio <= threshold) accept = true;\n\n            if (!accept && future_edges <= need_edges) accept = true;\n        }\n\n        if (accept) {\n            cout << 1 << '\\n' << flush;\n            int loser;\n            int keep = dsu.merge_roots(ru, rv, loser);\n            merge_adj(keep, loser, adj, out_deg);\n            merge_edge_lists(keep, loser, comp_edges);\n        } else {\n            cout << 0 << '\\n' << flush;\n        }\n    }\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\n\nstruct BlockCell {\n    int x, y;\n    char action;\n    int rx, ry;   // required human position when blocking\n};\n\nstruct Candidate {\n    Point home;\n    vector<BlockCell> blocks;\n    int final_block_index;\n};\n\nconst int H = 30;\nconst int W = 30;\nconst int DX[4] = {-1, 1, 0, 0};\nconst int DY[4] = {0, 0, -1, 1};\nconst char MOVE_CH[4] = {'U', 'D', 'L', 'R'};\n\nconst int DIST_WEIGHT = 10;\nconst int PET_RADIUS = 6;\nconst int PET_WEIGHT = 50;\nconst int REASSIGN_WAIT = 25;\nconst int REASSIGN_BUFFER = 6;\nconst int MIN_REMAINING_FOR_REASSIGN = 50;\nconst int MAX_REASSIGN = 3;\nconst int PET_ON_ME_WAIT = 12;\nconst int MOVE_STUCK_WAIT = 12;\nconst int CAND_COOLDOWN = 18;\n\ninline bool inside(int x, int y) { return 0 <= x && x < H && 0 <= y && y < W; }\n\nint dir_from_char(char c) {\n    if (c == 'U' || c == 'u') return 0;\n    if (c == 'D' || c == 'd') return 1;\n    if (c == 'L' || c == 'l') return 2;\n    if (c == 'R' || c == 'r') return 3;\n    return -1;\n}\n\nint bfs_next_dir(const vector<vector<int>>& impassable, const Point& start, const Point& goal) {\n    if (start.x == goal.x && start.y == goal.y) return -1;\n    array<array<int, W>, H> dist;\n    for (int i = 0; i < H; ++i) dist[i].fill(-1);\n    queue<Point> q;\n    dist[start.x][start.y] = 0;\n    q.push(start);\n    while (!q.empty()) {\n        Point cur = q.front(); q.pop();\n        for (int d = 0; d < 4; ++d) {\n            int nx = cur.x + DX[d], ny = cur.y + DY[d];\n            if (!inside(nx, ny) || impassable[nx][ny] || dist[nx][ny] != -1) continue;\n            dist[nx][ny] = dist[cur.x][cur.y] + 1;\n            q.push({nx, ny});\n        }\n    }\n    if (dist[goal.x][goal.y] == -1) return -1;\n    Point cur = goal;\n    while (true) {\n        for (int d = 0; d < 4; ++d) {\n            int px = cur.x - DX[d], py = cur.y - DY[d];\n            if (!inside(px, py)) continue;\n            if (dist[px][py] == dist[cur.x][cur.y] - 1) {\n                if (px == start.x && py == start.y) return d;\n                cur = {px, py};\n                break;\n            }\n        }\n    }\n}\n\nvector<int> hungarian(const vector<vector<int>>& a) {\n    int n = (int)a.size();\n    int m = (int)a[0].size();\n    const int INF = 1e9;\n    vector<int> u(n + 1), v(m + 1), p(m + 1), way(m + 1);\n    for (int i = 1; i <= n; ++i) {\n        p[0] = i;\n        vector<int> minv(m + 1, INF);\n        vector<char> used(m + 1, false);\n        int j0 = 0;\n        do {\n            used[j0] = true;\n            int i0 = p[j0], delta = INF, j1 = 0;\n            for (int j = 1; j <= m; ++j) if (!used[j]) {\n                int cur = a[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= m; ++j) {\n                if (used[j]) u[p[j]] += delta, v[j] -= delta;\n                else minv[j] -= delta;\n            }\n            j0 = j1;\n        } while (p[j0]);\n        do {\n            int j1 = way[j0];\n            p[j0] = p[j1];\n            j0 = j1;\n        } while (j0);\n    }\n    vector<int> ans(n, -1);\n    for (int j = 1; j <= m; ++j) if (p[j]) ans[p[j] - 1] = j - 1;\n    return ans;\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<Point> pets(N);\n    vector<int> pet_type(N);\n    for (int i = 0; i < N; ++i) {\n        int px, py, pt;\n        cin >> px >> py >> pt;\n        pets[i] = {px - 1, py - 1};\n        pet_type[i] = pt;\n    }\n    int M;\n    cin >> M;\n    vector<Point> humans(M);\n    for (int i = 0; i < M; ++i) {\n        int hx, hy;\n        cin >> hx >> hy;\n        humans[i] = {hx - 1, hy - 1};\n    }\n\n    vector<vector<int>> blocked(H, vector<int>(W, 0));\n    vector<vector<int>> pet_count(H, vector<int>(W, 0));\n    for (auto &p : pets) if (inside(p.x, p.y)) pet_count[p.x][p.y]++;\n\n    vector<int> edge = {2, 6, 10, 14, 18, 22, 26};\n    vector<Candidate> candidates;\n\n    auto add_block = [](vector<BlockCell>& vec, int x, int y, char act, int rx, int ry) {\n        vec.push_back({x, y, act, rx, ry});\n    };\n\n    auto add_top = [&](int y) {\n        Candidate c;\n        c.home = {0, y};\n        vector<BlockCell> b;\n        add_block(b, 2, y, 'd', 1, y);\n        add_block(b, 1, y + 1, 'd', 0, y + 1);\n        add_block(b, 0, y + 1, 'r', 0, y);\n        add_block(b, 1, y - 1, 'd', 0, y - 1);\n        add_block(b, 0, y - 1, 'l', 0, y);\n        add_block(b, 1, y, 'd', 0, y);\n        c.blocks = b;\n        c.final_block_index = (int)b.size() - 1;\n        candidates.push_back(c);\n    };\n    auto add_bottom = [&](int y) {\n        Candidate c;\n        c.home = {H - 1, y};\n        vector<BlockCell> b;\n        add_block(b, H - 3, y, 'u', H - 2, y);\n        add_block(b, H - 2, y + 1, 'u', H - 1, y + 1);\n        add_block(b, H - 1, y + 1, 'r', H - 1, y);\n        add_block(b, H - 2, y - 1, 'u', H - 1, y - 1);\n        add_block(b, H - 1, y - 1, 'l', H - 1, y);\n        add_block(b, H - 2, y, 'u', H - 1, y);\n        c.blocks = b;\n        c.final_block_index = (int)b.size() - 1;\n        candidates.push_back(c);\n    };\n    auto add_left = [&](int x) {\n        Candidate c;\n        c.home = {x, 0};\n        vector<BlockCell> b;\n        add_block(b, x, 2, 'r', x, 1);\n        add_block(b, x + 1, 1, 'r', x + 1, 0);\n        add_block(b, x + 1, 0, 'd', x, 0);\n        add_block(b, x - 1, 1, 'r', x - 1, 0);\n        add_block(b, x - 1, 0, 'u', x, 0);\n        add_block(b, x, 1, 'r', x, 0);\n        c.blocks = b;\n        c.final_block_index = (int)b.size() - 1;\n        candidates.push_back(c);\n    };\n    auto add_right = [&](int x) {\n        Candidate c;\n        c.home = {x, W - 1};\n        vector<BlockCell> b;\n        add_block(b, x, W - 3, 'l', x, W - 2);\n        add_block(b, x + 1, W - 2, 'l', x + 1, W - 1);\n        add_block(b, x + 1, W - 1, 'd', x, W - 1);\n        add_block(b, x - 1, W - 2, 'l', x - 1, W - 1);\n        add_block(b, x - 1, W - 1, 'u', x, W - 1);\n        add_block(b, x, W - 2, 'l', x, W - 1);\n        c.blocks = b;\n        c.final_block_index = (int)b.size() - 1;\n        candidates.push_back(c);\n    };\n    for (int y : edge) add_top(y);\n    for (int y : edge) add_bottom(y);\n    for (int x : edge) add_left(x);\n    for (int x : edge) add_right(x);\n\n    int C = (int)candidates.size();\n    vector<int> candidate_penalty(C, 0);\n    array<int, 6> type_weight = {0, 1, 1, 1, 3, 2};\n\n    auto update_penalty = [&]() {\n        fill(candidate_penalty.begin(), candidate_penalty.end(), 0);\n        for (int j = 0; j < C; ++j) {\n            int pen = 0;\n            for (int i = 0; i < N; ++i) {\n                int dist = abs(pets[i].x - candidates[j].home.x) + abs(pets[i].y - candidates[j].home.y);\n                if (dist < PET_RADIUS)\n                    pen += (PET_RADIUS - dist) * PET_WEIGHT * type_weight[pet_type[i]];\n            }\n            candidate_penalty[j] = pen;\n        }\n    };\n    update_penalty();\n\n    vector<vector<int>> cost(M, vector<int>(C));\n    for (int i = 0; i < M; ++i)\n        for (int j = 0; j < C; ++j) {\n            int dist = abs(humans[i].x - candidates[j].home.x) + abs(humans[i].y - candidates[j].home.y);\n            cost[i][j] = dist * DIST_WEIGHT + candidate_penalty[j];\n        }\n    vector<int> assign = hungarian(cost);\n\n    vector<int> candidate_owner(C, -1);\n    vector<int> candidate_block_until(C, -1000);\n\n    vector<int> human_target_idx(M, -1);\n    vector<Point> targets(M);\n    vector<vector<BlockCell>> human_block_cells(M);\n    vector<vector<int>> human_block_done(M);\n    vector<int> final_block_index(M, -1);\n    vector<int> stage(M, 0);\n    vector<int> idle_block_turns(M, 0);\n    vector<int> stuck_move_turns(M, 0);\n    vector<int> pet_on_me_turns(M, 0);\n    vector<int> block_reason(M, 0);\n    vector<int> reassign_count(M, 0);\n\n    auto is_complete = [&](int idx) -> bool {\n        for (int v : human_block_done[idx]) if (!v) return false;\n        return true;\n    };\n\n    auto set_candidate = [&](int idx, int cand) {\n        human_target_idx[idx] = cand;\n        targets[idx] = candidates[cand].home;\n        human_block_cells[idx] = candidates[cand].blocks;\n        human_block_done[idx].assign(human_block_cells[idx].size(), 0);\n        for (int k = 0; k < (int)human_block_cells[idx].size(); ++k) {\n            const auto &bc = human_block_cells[idx][k];\n            if (blocked[bc.x][bc.y]) human_block_done[idx][k] = 1;\n        }\n        final_block_index[idx] = candidates[cand].final_block_index;\n        idle_block_turns[idx] = 0;\n        stuck_move_turns[idx] = 0;\n        pet_on_me_turns[idx] = 0;\n        block_reason[idx] = 0;\n        if (humans[idx].x == targets[idx].x && humans[idx].y == targets[idx].y) {\n            stage[idx] = is_complete(idx) ? 2 : 1;\n        } else {\n            stage[idx] = 0;\n        }\n    };\n\n    for (int i = 0; i < M; ++i) {\n        candidate_owner[assign[i]] = i;\n        set_candidate(i, assign[i]);\n    }\n\n    auto try_reassign = [&](int idx, int remaining, int turn) -> bool {\n        if (reassign_count[idx] >= MAX_REASSIGN) return false;\n        int old = human_target_idx[idx];\n        if (old < 0) return false;\n        candidate_owner[old] = -1;\n        candidate_block_until[old] = turn + CAND_COOLDOWN;\n        const int INF = 1e9;\n        int best = -1, best_cost = INF;\n        for (int j = 0; j < C; ++j) {\n            if (candidate_owner[j] != -1) continue;\n            if (candidate_block_until[j] > turn) continue;\n            if (blocked[candidates[j].home.x][candidates[j].home.y]) continue;\n            int dist = abs(humans[idx].x - candidates[j].home.x) + abs(humans[idx].y - candidates[j].home.y);\n            if (dist + REASSIGN_BUFFER > remaining) continue;\n            int cur = dist * DIST_WEIGHT + candidate_penalty[j];\n            if (cur < best_cost) best_cost = cur, best = j;\n        }\n        if (best == -1) {\n            candidate_owner[old] = idx;\n            return false;\n        }\n        candidate_owner[best] = idx;\n        set_candidate(idx, best);\n        reassign_count[idx]++;\n        return true;\n    };\n\n    for (int turn = 0; turn < 300; ++turn) {\n        for (int i = 0; i < M; ++i) {\n            for (int k = 0; k < (int)human_block_cells[i].size(); ++k) {\n                if (!human_block_done[i][k]) {\n                    const auto &bc = human_block_cells[i][k];\n                    if (blocked[bc.x][bc.y]) human_block_done[i][k] = 1;\n                }\n            }\n            if (stage[i] == 1 && is_complete(i)) stage[i] = 2;\n        }\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 0 && humans[i].x == targets[i].x && humans[i].y == targets[i].y) {\n                stage[i] = is_complete(i) ? 2 : 1;\n            }\n        }\n\n        vector<vector<int>> humans_here(H, vector<int>(W, 0));\n        for (auto &h : humans) humans_here[h.x][h.y]++;\n\n        Point invalid{-1, -1};\n        vector<Point> move_target(M, invalid);\n        vector<int> block_exec(M, -1);\n        vector<int> block_reason_tmp(M, 0);\n        vector<int> current_block_idx(M, -1);\n        string actions(M, '.');\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 0) {\n                move_target[i] = targets[i];\n                continue;\n            }\n            if (stage[i] != 1) {\n                block_reason_tmp[i] = 0;\n                continue;\n            }\n            while (true) {\n                int blk = -1;\n                for (int k = 0; k < (int)human_block_cells[i].size(); ++k)\n                    if (!human_block_done[i][k]) { blk = k; break; }\n                if (blk == -1) { stage[i] = 2; block_reason_tmp[i] = 0; break; }\n                current_block_idx[i] = blk;\n                const auto &bc = human_block_cells[i][blk];\n                if (blocked[bc.x][bc.y]) {\n                    human_block_done[i][blk] = 1;\n                    continue;\n                }\n                if (humans[i].x != bc.rx || humans[i].y != bc.ry) {\n                    move_target[i] = {bc.rx, bc.ry};\n                    block_reason_tmp[i] = 0;\n                } else {\n                    if (pet_count[bc.x][bc.y] > 0) {\n                        block_reason_tmp[i] = 1;\n                    } else {\n                        bool adj_pet = false;\n                        for (int d = 0; d < 4; ++d) {\n                            int ax = bc.x + DX[d], ay = bc.y + DY[d];\n                            if (inside(ax, ay) && pet_count[ax][ay] > 0) { adj_pet = true; break; }\n                        }\n                        if (adj_pet) {\n                            block_reason_tmp[i] = 2;\n                        } else if (humans_here[bc.x][bc.y] > 0) {\n                            block_reason_tmp[i] = 3;\n                        } else {\n                            actions[i] = bc.action;\n                            block_exec[i] = blk;\n                            block_reason_tmp[i] = 0;\n                        }\n                    }\n                }\n                break;\n            }\n        }\n\n        vector<vector<int>> temp_blocked = blocked;\n        for (int i = 0; i < M; ++i) {\n            if (block_exec[i] != -1) {\n                const auto &bc = human_block_cells[i][block_exec[i]];\n                temp_blocked[bc.x][bc.y] = 1;\n            }\n        }\n\n        vector<int> move_dir(M, -2);\n        for (int i = 0; i < M; ++i) {\n            if (actions[i] != '.') continue;\n            if (move_target[i].x == -1) continue;\n            if (humans[i].x == move_target[i].x && humans[i].y == move_target[i].y) continue;\n            int dir = bfs_next_dir(temp_blocked, humans[i], move_target[i]);\n            move_dir[i] = dir;\n            if (dir != -1) actions[i] = MOVE_CH[dir];\n        }\n\n        cout << actions << endl;\n\n        vector<Point> start_pos = humans;\n        for (int i = 0; i < M; ++i) {\n            char act = actions[i];\n            int dir = dir_from_char(act);\n            if (act == '.' || dir == -1) continue;\n            if ('A' <= act && act <= 'Z') {\n                humans[i].x += DX[dir];\n                humans[i].y += DY[dir];\n            } else {\n                const auto &bc = human_block_cells[i][block_exec[i]];\n                blocked[bc.x][bc.y] = 1;\n                human_block_done[i][block_exec[i]] = 1;\n            }\n        }\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 1) {\n                if (block_exec[i] != -1) {\n                    idle_block_turns[i] = 0;\n                } else if (move_target[i].x != -1 &&\n                           !(humans[i].x == move_target[i].x && humans[i].y == move_target[i].y)) {\n                    idle_block_turns[i] = 0;\n                } else if (block_reason_tmp[i] == 1 || block_reason_tmp[i] == 2) {\n                    idle_block_turns[i]++;\n                } else {\n                    idle_block_turns[i] = 0;\n                }\n            } else {\n                idle_block_turns[i] = 0;\n            }\n            if (move_target[i].x != -1 &&\n                !(humans[i].x == move_target[i].x && humans[i].y == move_target[i].y) &&\n                move_dir[i] == -1) {\n                stuck_move_turns[i]++;\n            } else if (move_target[i].x != -1 &&\n                       !(humans[i].x == move_target[i].x && humans[i].y == move_target[i].y) &&\n                       move_dir[i] != -2) {\n                stuck_move_turns[i] = 0;\n            } else if (move_target[i].x == -1) {\n                stuck_move_turns[i] = 0;\n            }\n            block_reason[i] = block_reason_tmp[i];\n        }\n\n        vector<string> pet_moves(N);\n        for (int i = 0; i < N; ++i) cin >> pet_moves[i];\n        for (int i = 0; i < N; ++i) {\n            for (char c : pet_moves[i]) {\n                int dir = dir_from_char(c);\n                if (dir == -1) continue;\n                pets[i].x += DX[dir];\n                pets[i].y += DY[dir];\n            }\n        }\n        for (int x = 0; x < H; ++x) fill(pet_count[x].begin(), pet_count[x].end(), 0);\n        for (auto &p : pets)\n            if (inside(p.x, p.y)) pet_count[p.x][p.y]++;\n        update_penalty();\n\n        for (int i = 0; i < M; ++i) {\n            if (pet_count[humans[i].x][humans[i].y] > 0) pet_on_me_turns[i]++;\n            else pet_on_me_turns[i] = 0;\n        }\n\n        int remaining = 300 - (turn + 1);\n        if (remaining >= MIN_REMAINING_FOR_REASSIGN) {\n            for (int i = 0; i < M; ++i) {\n                if (stage[i] == 2) continue;\n                bool need = false;\n                if (stage[i] == 1 && !is_complete(i)) {\n                    if ((block_reason[i] == 1 || block_reason[i] == 2) && idle_block_turns[i] >= REASSIGN_WAIT)\n                        need = true;\n                    if (pet_on_me_turns[i] >= PET_ON_ME_WAIT) need = true;\n                }\n                if (!need && stuck_move_turns[i] >= MOVE_STUCK_WAIT) need = true;\n                if (need) try_reassign(i, remaining, turn);\n            }\n        }\n    }\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int H = 20;\nconstexpr int W = 20;\nconstexpr int N = H * W;\nconstexpr int MAX_L = 200;\nconstexpr int MAX_SEG_LEN = 80;\nconst char DIR_CHARS[4] = {'U', 'D', 'L', 'R'};\nconstexpr double TIME_LIMIT = 1.95;\nconstexpr double IMPROVE_EPS = 1e-9;\n\nstruct StepResult {\n    double score;\n    double reachProb;\n};\n\ninline StepResult apply_transition_raw(const double* from, double* to, int dir, int step,\n                                       double forgetProb, double moveProb,\n                                       const array<array<int, N>, 4>& neighbor,\n                                       int targetIdx) {\n    StepResult res{0.0, 0.0};\n    fill(to, to + N, 0.0);\n    const double rewardFactor = 401.0 - (step + 1);\n    for (int idx = 0; idx < N; ++idx) {\n        double prob = from[idx];\n        if (prob <= 1e-15) continue;\n        double stayProb = prob * forgetProb;\n        int nxt = neighbor[dir][idx];\n        double move = prob * moveProb;\n        if (nxt == idx) {\n            stayProb += move;\n        } else if (nxt == targetIdx) {\n            res.score += rewardFactor * move;\n            res.reachProb += move;\n        } else {\n            to[nxt] += move;\n        }\n        to[idx] += stayProb;\n    }\n    return res;\n}\n\ninline double dot_product_raw(const double* a, const double* b) {\n    double sum = 0.0;\n    for (int i = 0; i < N; ++i) sum += a[i] * b[i];\n    return sum;\n}\n\ninline double expected_distance_raw(const double* dist, const double* distTarget) {\n    double sum = 0.0;\n    for (int idx = 0; idx < N; ++idx) sum += dist[idx] * distTarget[idx];\n    return sum;\n}\n\nvector<int> compute_distances(const array<array<int, N>, 4>& neighbor, int targetIdx) {\n    const int INF = 1e9;\n    vector<int> dist(N, INF);\n    queue<int> q;\n    dist[targetIdx] = 0;\n    q.push(targetIdx);\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        for (int dir = 0; dir < 4; ++dir) {\n            int v = neighbor[dir][u];\n            if (v == u) continue;\n            if (dist[v] > dist[u] + 1) {\n                dist[v] = dist[u] + 1;\n                q.push(v);\n            }\n        }\n    }\n    return dist;\n}\n\nvector<int> compute_bfs_path(const array<array<int, N>, 4>& neighbor,\n                             int startIdx, int targetIdx) {\n    vector<int> parent(N, -1);\n    vector<int> parentDir(N, -1);\n    queue<int> q;\n    q.push(startIdx);\n    parent[startIdx] = startIdx;\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        if (u == targetIdx) break;\n        for (int dir = 0; dir < 4; ++dir) {\n            int v = neighbor[dir][u];\n            if (v == u) continue;\n            if (parent[v] != -1) continue;\n            parent[v] = u;\n            parentDir[v] = dir;\n            q.push(v);\n        }\n    }\n    vector<int> path;\n    if (parent[targetIdx] != -1) {\n        int cur = targetIdx;\n        vector<int> rev;\n        while (cur != startIdx) {\n            rev.push_back(parentDir[cur]);\n            cur = parent[cur];\n        }\n        path.assign(rev.rbegin(), rev.rend());\n    }\n    return path;\n}\n\nvector<int> build_sequence_from_path(const vector<int>& path, int repeatEach, bool loopMode) {\n    vector<int> seq(MAX_L);\n    int pos = 0;\n    auto append_once = [&]() {\n        for (int dir : path) {\n            for (int r = 0; r < repeatEach; ++r) {\n                if (pos >= MAX_L) return;\n                seq[pos++] = dir;\n            }\n        }\n    };\n    if (!path.empty() && loopMode) {\n        while (pos < MAX_L) append_once();\n    } else {\n        append_once();\n    }\n    while (pos < MAX_L) seq[pos++] = (pos % 4 == 3) ? 3 : 1;\n    return seq;\n}\n\nvector<int> build_default_sequence() {\n    vector<int> seq(MAX_L);\n    for (int i = 0; i < MAX_L; ++i) seq[i] = (i % 4 == 3) ? 3 : 1;\n    return seq;\n}\n\nstruct BeamParam {\n    double weight;\n    double noise;\n    int width;\n};\n\nstruct BeamResult {\n    vector<int> seq;\n    double score;\n};\n\nBeamResult run_beam(const BeamParam& param,\n                    const array<array<int, N>, 4>& neighbor,\n                    const vector<double>& distTarget,\n                    int startIdx, int targetIdx,\n                    double forgetProb,\n                    mt19937& rng) {\n    const double moveProb = 1.0 - forgetProb;\n    struct Candidate {\n        array<double, N> dist;\n        double score;\n        double heuristic;\n        array<uint8_t, MAX_L> path;\n        int len;\n    };\n    vector<Candidate> beam, next;\n    beam.reserve(param.width);\n    next.reserve(param.width * 4);\n\n    Candidate init;\n    init.dist.fill(0.0);\n    init.dist[startIdx] = 1.0;\n    init.score = 0.0;\n    init.len = 0;\n    init.path.fill(0);\n    init.heuristic = 0.0;\n    beam.push_back(init);\n\n    uniform_real_distribution<double> noiseDist(-param.noise, param.noise);\n    auto cmp = [](const Candidate& a, const Candidate& b) {\n        return a.heuristic > b.heuristic;\n    };\n\n    for (int step = 0; step < MAX_L; ++step) {\n        next.clear();\n        for (const Candidate& cand : beam) {\n            for (int dir = 0; dir < 4; ++dir) {\n                Candidate child;\n                child.path = cand.path;\n                child.path[cand.len] = static_cast<uint8_t>(dir);\n                child.len = cand.len + 1;\n                StepResult sr = apply_transition_raw(cand.dist.data(), child.dist.data(),\n                                                     dir, step, forgetProb, moveProb,\n                                                     neighbor, targetIdx);\n                child.score = cand.score + sr.score;\n                double expDist = expected_distance_raw(child.dist.data(), distTarget.data());\n                double noise = (param.noise > 0) ? noiseDist(rng) : 0.0;\n                child.heuristic = child.score - param.weight * expDist + noise;\n                next.push_back(std::move(child));\n            }\n        }\n        if (next.empty()) break;\n        int width = min(param.width, static_cast<int>(next.size()));\n        partial_sort(next.begin(), next.begin() + width, next.end(), cmp);\n        next.resize(width);\n        beam.swap(next);\n    }\n\n    Candidate best = beam[0];\n    for (const Candidate& cand : beam) if (cand.score > best.score) best = cand;\n    vector<int> seq(MAX_L);\n    for (int i = 0; i < MAX_L; ++i) seq[i] = best.path[i];\n    return {seq, best.score};\n}\n\nstruct Evaluator {\n    const array<array<int, N>, 4>& neighbor;\n    int startIdx;\n    int targetIdx;\n    double forgetProb;\n    double moveProb;\n    vector<double> cur, nxt;\n    Evaluator(const array<array<int, N>, 4>& neighbor_, int s, int t, double p)\n        : neighbor(neighbor_), startIdx(s), targetIdx(t), forgetProb(p), moveProb(1.0 - p),\n          cur(N, 0.0), nxt(N, 0.0) {}\n\n    double evaluate(const vector<int>& seq) {\n        fill(cur.begin(), cur.end(), 0.0);\n        cur[startIdx] = 1.0;\n        double total = 0.0;\n        for (int step = 0; step < (int)seq.size(); ++step) {\n            StepResult sr = apply_transition_raw(cur.data(), nxt.data(), seq[step], step,\n                                                 forgetProb, moveProb, neighbor, targetIdx);\n            total += sr.score;\n            cur.swap(nxt);\n            bool empty = true;\n            for (double v : cur) if (v > 1e-15) { empty = false; break; }\n            if (empty) break;\n        }\n        return total;\n    }\n};\n\nvoid recompute_forward_from(int startStep,\n                            const vector<int>& seq,\n                            vector<array<double, N>>& forward,\n                            vector<double>& prefixScore,\n                            vector<double>& aliveProb,\n                            double forgetProb, double moveProb,\n                            const array<array<int, N>, 4>& neighbor,\n                            int targetIdx, int startIdx) {\n    if (startStep <= 0) {\n        startStep = 0;\n        forward[0].fill(0.0);\n        forward[0][startIdx] = 1.0;\n        prefixScore[0] = 0.0;\n        aliveProb[0] = 1.0;\n    }\n    for (int step = startStep; step < MAX_L; ++step) {\n        StepResult sr = apply_transition_raw(forward[step].data(), forward[step + 1].data(),\n                                             seq[step], step, forgetProb, moveProb,\n                                             neighbor, targetIdx);\n        prefixScore[step + 1] = prefixScore[step] + sr.score;\n        double alive = aliveProb[step] - sr.reachProb;\n        if (alive < 0.0) alive = 0.0;\n        aliveProb[step + 1] = alive;\n    }\n}\n\nvoid recompute_backward_up_to(int uptoStep,\n                              const vector<int>& seq,\n                              vector<array<double, N>>& value,\n                              double forgetProb, double moveProb,\n                              const array<array<int, N>, 4>& neighbor,\n                              int targetIdx) {\n    if (uptoStep >= MAX_L - 1) uptoStep = MAX_L - 1;\n    for (int step = uptoStep; step >= 0; --step) {\n        auto& cur = value[step];\n        auto& nxt = value[step + 1];\n        int dir = seq[step];\n        double rewardFactor = 401.0 - (step + 1);\n        for (int idx = 0; idx < N; ++idx) {\n            double val = forgetProb * nxt[idx];\n            int nextIdx = neighbor[dir][idx];\n            if (nextIdx == idx) {\n                val += moveProb * nxt[idx];\n            } else if (nextIdx == targetIdx) {\n                val += moveProb * rewardFactor;\n            } else {\n                val += moveProb * nxt[nextIdx];\n            }\n            cur[idx] = val;\n        }\n        cur[targetIdx] = 0.0;\n    }\n}\n\nstruct SegmentParam {\n    double weight;\n    double noise;\n    int width;\n    double futureCoeff;\n};\n\nstruct SegmentResult {\n    bool success;\n    vector<int> path;\n    double totalContribution;\n};\n\nSegmentResult run_segment_beam(const array<double, N>& distPre,\n                               const array<double, N>& suffixValue,\n                               int len, int stepOffset,\n                               const array<array<int, N>, 4>& neighbor,\n                               double forgetProb, double moveProb,\n                               const vector<double>& distTarget,\n                               const SegmentParam& param,\n                               mt19937& rng,\n                               int targetIdx) {\n    SegmentResult result{false, {}, -1e300};\n    if (len <= 0 || len > MAX_SEG_LEN) return result;\n    struct Node {\n        array<double, N> dist;\n        double score;\n        double heuristic;\n        array<uint8_t, MAX_SEG_LEN> path;\n        int len;\n    };\n    vector<Node> beam;\n    vector<Node> next;\n    beam.reserve(param.width);\n    next.reserve(param.width * 4);\n\n    Node init;\n    init.dist = distPre;\n    init.score = 0.0;\n    init.len = 0;\n    init.heuristic = dot_product_raw(distPre.data(), suffixValue.data());\n    init.path.fill(0);\n    beam.push_back(init);\n\n    uniform_real_distribution<double> noiseDist(-param.noise, param.noise);\n    auto cmp = [](const Node& a, const Node& b) {\n        return a.heuristic > b.heuristic;\n    };\n\n    for (int step = 0; step < len; ++step) {\n        next.clear();\n        for (const Node& cand : beam) {\n            for (int dir = 0; dir < 4; ++dir) {\n                Node child;\n                child.path = cand.path;\n                child.path[cand.len] = static_cast<uint8_t>(dir);\n                child.len = cand.len + 1;\n                StepResult sr = apply_transition_raw(cand.dist.data(), child.dist.data(),\n                                                     dir, stepOffset + step,\n                                                     forgetProb, moveProb,\n                                                     neighbor, targetIdx);\n                child.score = cand.score + sr.score;\n                double expDist = expected_distance_raw(child.dist.data(), distTarget.data());\n                double futureEst = dot_product_raw(child.dist.data(), suffixValue.data());\n                double noise = (param.noise > 0) ? noiseDist(rng) : 0.0;\n                child.heuristic = child.score + param.futureCoeff * futureEst\n                                - param.weight * expDist + noise;\n                next.push_back(std::move(child));\n            }\n        }\n        if (next.empty()) return result;\n        int width = min(param.width, static_cast<int>(next.size()));\n        partial_sort(next.begin(), next.begin() + width, next.end(), cmp);\n        next.resize(width);\n        beam.swap(next);\n    }\n\n    double bestTotal = -1e300;\n    int bestIdx = 0;\n    for (int i = 0; i < (int)beam.size(); ++i) {\n        double total = beam[i].score + dot_product_raw(beam[i].dist.data(), suffixValue.data());\n        if (total > bestTotal) {\n            bestTotal = total;\n            bestIdx = i;\n        }\n    }\n    result.success = true;\n    result.totalContribution = bestTotal;\n    result.path.resize(len);\n    for (int i = 0; i < len; ++i) result.path[i] = beam[bestIdx].path[i];\n    return result;\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    cin >> si >> sj >> ti >> tj >> p;\n    vector<string> h(H), v(H - 1);\n    for (int i = 0; i < H; ++i) cin >> h[i];\n    for (int i = 0; i < H - 1; ++i) cin >> v[i];\n\n    array<array<int, N>, 4> neighbor;\n    auto idx = [&](int r, int c) { return r * W + c; };\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int id = idx(i, j);\n            neighbor[0][id] = (i > 0 && v[i - 1][j] == '0') ? idx(i - 1, j) : id;\n            neighbor[1][id] = (i < H - 1 && v[i][j] == '0') ? idx(i + 1, j) : id;\n            neighbor[2][id] = (j > 0 && h[i][j - 1] == '0') ? idx(i, j - 1) : id;\n            neighbor[3][id] = (j < W - 1 && h[i][j] == '0') ? idx(i, j + 1) : id;\n        }\n    }\n\n    int startIdx = idx(si, sj);\n    int targetIdx = idx(ti, tj);\n\n    vector<int> distInt = compute_distances(neighbor, targetIdx);\n    vector<double> distTarget(N);\n    for (int i = 0; i < N; ++i) distTarget[i] = (distInt[i] >= 1e8) ? 100.0 : (double)distInt[i];\n\n    auto bfsPath = compute_bfs_path(neighbor, startIdx, targetIdx);\n\n    mt19937 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n\n    vector<vector<int>> candidates;\n    candidates.push_back(build_sequence_from_path(bfsPath, 1, false));\n    candidates.push_back(build_sequence_from_path(bfsPath, 2, false));\n    candidates.push_back(build_sequence_from_path(bfsPath, 3, false));\n    candidates.push_back(build_sequence_from_path(bfsPath, 1, true));\n    candidates.push_back(build_sequence_from_path(bfsPath, 2, true));\n    candidates.push_back(build_default_sequence());\n\n    vector<BeamParam> beamParams;\n    double factor = 0.6 + 0.8 * p;\n    beamParams.push_back({0.8 * factor, 3e-4, 10});\n    beamParams.push_back({1.1 * factor, 2e-4, 12});\n    beamParams.push_back({1.5 * factor, 1e-4, 14});\n    beamParams.push_back({2.1 * factor, 5e-5, 16});\n    beamParams.push_back({2.9 * factor, 2e-5, 18});\n    beamParams.push_back({3.6 * factor, 1e-5, 20});\n    beamParams.push_back({4.4 * factor, 5e-6, 22});\n\n    double beamTimeLimit = min(0.55, TIME_LIMIT * 0.4);\n    size_t paramIdx = 0;\n    while (elapsed() < beamTimeLimit && paramIdx < beamParams.size()) {\n        BeamResult res = run_beam(beamParams[paramIdx], neighbor, distTarget,\n                                  startIdx, targetIdx, p, rng);\n        candidates.push_back(std::move(res.seq));\n        ++paramIdx;\n    }\n\n    Evaluator evaluator(neighbor, startIdx, targetIdx, p);\n    double bestEval = -1.0;\n    vector<int> bestSeq;\n    for (const auto& seq : candidates) {\n        double sc = evaluator.evaluate(seq);\n        if (sc > bestEval + IMPROVE_EPS) {\n            bestEval = sc;\n            bestSeq = seq;\n        }\n    }\n    if (bestSeq.empty()) bestSeq = build_default_sequence();\n\n    vector<array<double, N>> forward(MAX_L + 1), value(MAX_L + 1);\n    for (auto& arr : forward) arr.fill(0.0);\n    for (auto& arr : value) arr.fill(0.0);\n    vector<double> prefixScore(MAX_L + 1, 0.0);\n    vector<double> aliveProb(MAX_L + 1, 0.0);\n\n    forward[0][startIdx] = 1.0;\n    aliveProb[0] = 1.0;\n    recompute_forward_from(0, bestSeq, forward, prefixScore, aliveProb,\n                           p, 1.0 - p, neighbor, targetIdx, startIdx);\n    value[MAX_L].fill(0.0);\n    recompute_backward_up_to(MAX_L - 1, bestSeq, value,\n                             p, 1.0 - p, neighbor, targetIdx);\n    double bestScore = prefixScore[MAX_L];\n\n    array<double, N> tempDist;\n\n    auto buildSegmentParam = [&](int len, int step) -> SegmentParam {\n        SegmentParam param;\n        double lenRatio = (double)len / 32.0;\n        double early = max(0.0, 1.0 - step / 160.0);\n        param.weight = (0.85 + 0.9 * p) * (1.0 + 0.1 * min(2.0, lenRatio)) * (1.0 + 0.15 * early);\n        param.futureCoeff = 0.55 + 0.2 * min(1.5, (double)len / 40.0) + 0.15 * early;\n        param.noise = 7e-5 / (1.0 + 0.25 * lenRatio);\n        int baseWidth;\n        if (len <= 12) baseWidth = 32;\n        else if (len <= 20) baseWidth = 28;\n        else if (len <= 28) baseWidth = 24;\n        else if (len <= 36) baseWidth = 22;\n        else if (len <= 48) baseWidth = 20;\n        else if (len <= 56) baseWidth = 18;\n        else if (len <= 64) baseWidth = 16;\n        else if (len <= 72) baseWidth = 15;\n        else baseWidth = 14;\n        if (step < 50) baseWidth += 4;\n        else if (step < 100) baseWidth += 2;\n        if (step > 140) baseWidth -= 3;\n        else if (step > 110) baseWidth -= 1;\n        baseWidth -= (int)round(p * 2.0);\n        param.width = max(baseWidth, 10);\n        return param;\n    };\n\n    auto try_segment = [&](int start, int len) -> bool {\n        if (len <= 0) return false;\n        if (start < 0) {\n            len += start;\n            start = 0;\n        }\n        if (start >= MAX_L || len < 4) return false;\n        if (start + len > MAX_L) len = MAX_L - start;\n        if (len <= 0 || len > MAX_SEG_LEN) return false;\n        if (aliveProb[start] < 1e-9) return false;\n        SegmentParam param = buildSegmentParam(len, start);\n        SegmentResult segRes = run_segment_beam(forward[start], value[start + len],\n                                                len, start, neighbor, p, 1.0 - p,\n                                                distTarget, param, rng, targetIdx);\n        if (!segRes.success) return false;\n        double candidateScore = prefixScore[start] + segRes.totalContribution;\n        if (candidateScore > bestScore + IMPROVE_EPS) {\n            for (int i = 0; i < len; ++i) bestSeq[start + i] = segRes.path[i];\n            recompute_forward_from(start, bestSeq, forward, prefixScore, aliveProb,\n                                   p, 1.0 - p, neighbor, targetIdx, startIdx);\n            recompute_backward_up_to(start + len - 1, bestSeq, value,\n                                     p, 1.0 - p, neighbor, targetIdx);\n            bestScore = prefixScore[MAX_L];\n            return true;\n        }\n        return false;\n    };\n\n    auto run_coordinate = [&](double limitTime, int maxPass, vector<double>* marginOut) {\n        if (elapsed() >= limitTime) return;\n        if (marginOut) fill(marginOut->begin(), marginOut->end(), 0.0);\n        bool improved = true;\n        int passes = 0;\n        while (improved && elapsed() < limitTime && passes < maxPass) {\n            improved = false;\n            ++passes;\n            for (int step = 0; step < MAX_L && elapsed() < limitTime; ++step) {\n                if (aliveProb[step] < 1e-9) break;\n                auto& distIn = forward[step];\n                auto& suffix = value[step + 1];\n                double currentVal = -1e300;\n                double bestVal = -1e300;\n                int bestDir = bestSeq[step];\n                for (int dir = 0; dir < 4; ++dir) {\n                    StepResult sr = apply_transition_raw(distIn.data(), tempDist.data(),\n                                                         dir, step, p, 1.0 - p,\n                                                         neighbor, targetIdx);\n                    double val = sr.score + dot_product_raw(tempDist.data(), suffix.data());\n                    if (dir == bestSeq[step]) currentVal = val;\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestDir = dir;\n                    }\n                }\n                if (marginOut) (*marginOut)[step] = max(0.0, bestVal - currentVal);\n                if (bestVal > currentVal + IMPROVE_EPS && bestDir != bestSeq[step]) {\n                    bestSeq[step] = bestDir;\n                    recompute_forward_from(step, bestSeq, forward, prefixScore, aliveProb,\n                                           p, 1.0 - p, neighbor, targetIdx, startIdx);\n                    recompute_backward_up_to(step, bestSeq, value,\n                                             p, 1.0 - p, neighbor, targetIdx);\n                    bestScore = prefixScore[MAX_L];\n                    improved = true;\n                }\n            }\n        }\n    };\n\n    auto apply_margin_segments = [&](const vector<double>& margin,\n                                     double timeLimit, int topK) {\n        vector<pair<double, int>> items;\n        items.reserve(MAX_L);\n        for (int step = 0; step < MAX_L; ++step) {\n            if (aliveProb[step] < 1e-9) continue;\n            if (margin[step] <= 1e-8) continue;\n            items.emplace_back(margin[step], step);\n        }\n        sort(items.begin(), items.end(), greater<>());\n        vector<int> lengths = {6, 10, 14, 20, 28, 36};\n        int processed = 0;\n        for (const auto& [m, step] : items) {\n            if (processed >= topK) break;\n            if (elapsed() > timeLimit) break;\n            ++processed;\n            for (int len : lengths) {\n                if (elapsed() > timeLimit) break;\n                int start = step - len / 2;\n                if (try_segment(start, len)) break;\n            }\n        }\n    };\n\n    auto apply_drop_segments = [&](double timeLimit, int topK) {\n        vector<pair<double, int>> drops;\n        drops.reserve(MAX_L);\n        for (int step = 0; step < MAX_L; ++step) {\n            double drop = aliveProb[step] - aliveProb[step + 1];\n            if (drop > 1e-8) drops.emplace_back(drop, step);\n        }\n        sort(drops.begin(), drops.end(), greater<>());\n        vector<int> lengths = {8, 12, 16, 24, 32, 40};\n        int processed = 0;\n        for (const auto& [drop, step] : drops) {\n            if (processed >= topK) break;\n            if (elapsed() > timeLimit) break;\n            ++processed;\n            for (int len : lengths) {\n                if (elapsed() > timeLimit) break;\n                int start = step - len / 2;\n                if (try_segment(start, len)) break;\n            }\n        }\n    };\n\n    vector<double> marginBuf(MAX_L, 0.0);\n    double coordLimit1 = min(1.0, TIME_LIMIT * 0.65);\n    run_coordinate(coordLimit1, 3, &marginBuf);\n\n    double marginLimit = TIME_LIMIT * 0.75;\n    apply_margin_segments(marginBuf, marginLimit, 14);\n\n    run_coordinate(min(TIME_LIMIT * 0.8, coordLimit1 + 0.2), 1, nullptr);\n\n    double dropLimit = TIME_LIMIT * 0.86;\n    apply_drop_segments(dropLimit, 12);\n\n    run_coordinate(min(TIME_LIMIT * 0.9, dropLimit + 0.12), 1, nullptr);\n\n    vector<pair<int, int>> prioritySegments;\n    auto addSeg = [&](int s, int len) {\n        if (len <= 0) return;\n        if (s < 0) {\n            len += s;\n            s = 0;\n        }\n        if (s >= MAX_L) return;\n        if (s + len > MAX_L) len = MAX_L - s;\n        if (len >= 4) prioritySegments.emplace_back(s, len);\n    };\n    addSeg(0, 64);\n    addSeg(0, 48);\n    addSeg(16, 48);\n    addSeg(32, 48);\n    addSeg(48, 48);\n    addSeg(MAX_L - 96, 48);\n    addSeg(MAX_L - 64, 64);\n    addSeg(MAX_L - 48, 48);\n\n    double priorityLimit = TIME_LIMIT * 0.92;\n    for (auto [st, len] : prioritySegments) {\n        if (elapsed() > priorityLimit) break;\n        try_segment(st, len);\n    }\n\n    run_coordinate(min(TIME_LIMIT * 0.95, priorityLimit + 0.1), 1, nullptr);\n\n    vector<int> segLens = {4, 6, 8, 10, 12, 16, 20, 24, 28, 32,\n                           36, 40, 48, 56, 64, 72, 80};\n    vector<double> lenWeights;\n    for (int len : segLens) lenWeights.push_back(1.0 / len);\n    discrete_distribution<int> lenDist(lenWeights.begin(), lenWeights.end());\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    auto sample_weighted_start = [&](mt19937& rng) -> int {\n        array<double, MAX_L> weights;\n        double total = 0.0;\n        for (int i = 0; i < MAX_L; ++i) {\n            double w = aliveProb[i] * (401.0 - (i + 1));\n            weights[i] = max(0.0, w);\n            total += weights[i];\n        }\n        if (total < 1e-9) {\n            uniform_int_distribution<int> dist(0, MAX_L - 1);\n            return dist(rng);\n        }\n        uniform_real_distribution<double> dist(0.0, total);\n        double r = dist(rng);\n        double acc = 0.0;\n        for (int i = 0; i < MAX_L; ++i) {\n            acc += weights[i];\n            if (r <= acc) return i;\n        }\n        return MAX_L - 1;\n    };\n\n    double lnsLimit = TIME_LIMIT * 0.985;\n    while (elapsed() < lnsLimit) {\n        int len = segLens[lenDist(rng)];\n        int start = sample_weighted_start(rng);\n        if (start + len > MAX_L) start = MAX_L - len;\n        if (start < 0) start = 0;\n        if (aliveProb[start] < 1e-9) continue;\n        try_segment(start, len);\n    }\n\n    apply_drop_segments(TIME_LIMIT * 0.99, 6);\n    run_coordinate(TIME_LIMIT * 0.998, 1, nullptr);\n\n    string answer(MAX_L, 'U');\n    for (int i = 0; i < MAX_L; ++i) answer[i] = DIR_CHARS[bestSeq[i]];\n    cout << answer << '\\n';\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int H = 30;\nconstexpr int W = 30;\nconstexpr int N = H * W;\nconstexpr int DIR = 4;\nconstexpr int STATE = N * DIR;\n\nconstexpr int di[4] = {0, -1, 0, 1};\nconstexpr int dj[4] = {-1, 0, 1, 0};\n\nconstexpr int TO_TABLE[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\nconstexpr int ROT_NEXT[8] = {1, 2, 3, 0, 5, 4, 7, 6};\narray<array<int, 4>, N> g_neighbors;\nint ROT_TABLE[8][4];\n\nstruct EvalResult {\n    long long score;\n    int l1;\n    int l2;\n    int loopCnt;\n};\n\nstruct Evaluator {\n    array<int, STATE> visitedStamp{};\n    array<int, STATE> pathStamp{};\n    array<int, STATE> pathPos{};\n    int visitedToken = 0;\n    int pathToken = 0;\n    vector<int> pathList;\n\n    Evaluator() { pathList.reserve(STATE); }\n\n    EvalResult operator()(const vector<int>& finalType) {\n        ++visitedToken;\n        int token = visitedToken;\n        for (int cell = 0; cell < N; ++cell) {\n            int type = finalType[cell];\n            for (int d = 0; d < DIR; ++d) {\n                if (TO_TABLE[type][d] == -1) {\n                    visitedStamp[(cell << 2) | d] = token;\n                }\n            }\n        }\n\n        long long best1 = 0, best2 = 0;\n        int loops = 0;\n\n        for (int cell = 0; cell < N; ++cell) {\n            for (int d = 0; d < DIR; ++d) {\n                int idx = (cell << 2) | d;\n                if (visitedStamp[idx] == token) continue;\n\n                ++pathToken;\n                int pathTok = pathToken;\n                pathList.clear();\n\n                int curCell = cell;\n                int curDir = d;\n                int i = curCell / W;\n                int j = curCell % W;\n                int length = 0;\n\n                while (true) {\n                    int stateIdx = (curCell << 2) | curDir;\n                    if (visitedStamp[stateIdx] == token) break;\n\n                    if (pathStamp[stateIdx] == pathTok) {\n                        int loopLen = length - pathPos[stateIdx];\n                        if (loopLen > 0) {\n                            ++loops;\n                            if (loopLen >= best1) {\n                                best2 = best1;\n                                best1 = loopLen;\n                            } else if (loopLen > best2) {\n                                best2 = loopLen;\n                            }\n                        }\n                        break;\n                    }\n\n                    pathStamp[stateIdx] = pathTok;\n                    pathPos[stateIdx] = length;\n                    pathList.push_back(stateIdx);\n\n                    int type = finalType[curCell];\n                    int nextDir = TO_TABLE[type][curDir];\n                    if (nextDir == -1) break;\n\n                    int ni = i + di[nextDir];\n                    int nj = j + dj[nextDir];\n                    if (ni < 0 || ni >= H || nj < 0 || nj >= W) break;\n\n                    i = ni;\n                    j = nj;\n                    curCell = ni * W + nj;\n                    curDir = (nextDir + 2) & 3;\n                    ++length;\n                }\n\n                for (int s : pathList) {\n                    visitedStamp[s] = token;\n                }\n            }\n        }\n\n        long long score = (loops >= 2) ? best1 * best2 : 0LL;\n        return {score, (int)best1, (int)best2, loops};\n    }\n};\n\nstruct Solution {\n    long long score = -1;\n    vector<int> rot;\n    vector<int> type;\n};\n\nSolution solve_single(const vector<int>& base, double TIME_LIMIT, uint64_t seed,\n                      const vector<int>* initialRot = nullptr) {\n    auto start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    mt19937 rng(seed);\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    vector<int> rot(N, 0);\n    vector<int> finalType(N, 0);\n\n    const int MATCH_BONUS = 7;\n    const int OPEN_PENALTY = -3;\n    const int BORDER_PENALTY = -6;\n\n    if (initialRot) {\n        rot = *initialRot;\n        for (int cell = 0; cell < N; ++cell) {\n            rot[cell] &= 3;\n            finalType[cell] = ROT_TABLE[base[cell]][rot[cell]];\n        }\n    } else {\n        for (int cell = 0; cell < N; ++cell) {\n            int baseType = base[cell];\n            int bestR = 0;\n            int bestVal = -1e9;\n            array<char, 8> used{};\n            for (int r = 0; r < 4; ++r) {\n                int type = ROT_TABLE[baseType][r];\n                if (used[type]) continue;\n                used[type] = 1;\n                int val = 0;\n                for (int d = 0; d < DIR; ++d) {\n                    if (TO_TABLE[type][d] == -1) continue;\n                    int nb = g_neighbors[cell][d];\n                    if (nb == -1) val += BORDER_PENALTY;\n                    else val += MATCH_BONUS / 2;\n                }\n                if (val > bestVal || (val == bestVal && (rng() & 1))) {\n                    bestVal = val;\n                    bestR = r;\n                }\n            }\n            rot[cell] = bestR;\n            finalType[cell] = ROT_TABLE[baseType][bestR];\n        }\n    }\n\n    vector<int> openEnds(N, 0);\n    vector<int> badPos(N, -1);\n    vector<int> badCells;\n    badCells.reserve(N);\n\n    auto setBadState = [&](int cell, bool bad) {\n        if (bad) {\n            if (badPos[cell] == -1) {\n                badPos[cell] = (int)badCells.size();\n                badCells.push_back(cell);\n            }\n        } else if (badPos[cell] != -1) {\n            int idx = badPos[cell];\n            int last = badCells.back();\n            badCells[idx] = last;\n            badPos[last] = idx;\n            badCells.pop_back();\n            badPos[cell] = -1;\n        }\n    };\n\n    struct LocalResult { int score; int open; };\n\n    auto localEval = [&](int cell, int type) -> LocalResult {\n        LocalResult res{0, 0};\n        for (int d = 0; d < DIR; ++d) {\n            if (TO_TABLE[type][d] == -1) continue;\n            int nb = g_neighbors[cell][d];\n            if (nb == -1) {\n                res.score += BORDER_PENALTY;\n                res.open += 1;\n            } else {\n                int nbType = finalType[nb];\n                if (TO_TABLE[nbType][(d + 2) & 3] != -1) {\n                    res.score += MATCH_BONUS;\n                } else {\n                    res.score += OPEN_PENALTY;\n                    res.open += 1;\n                }\n            }\n        }\n        return res;\n    };\n\n    auto updateOne = [&](int cell) {\n        if (cell < 0) return;\n        LocalResult res = localEval(cell, finalType[cell]);\n        openEnds[cell] = res.open;\n        setBadState(cell, res.open > 0);\n    };\n\n    auto updateAround = [&](int cell) {\n        updateOne(cell);\n        for (int d = 0; d < DIR; ++d) {\n            int nb = g_neighbors[cell][d];\n            if (nb != -1) updateOne(nb);\n        }\n    };\n\n    auto recomputeAll = [&]() {\n        badCells.clear();\n        fill(badPos.begin(), badPos.end(), -1);\n        for (int cell = 0; cell < N; ++cell) updateOne(cell);\n    };\n\n    recomputeAll();\n\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    double greedyLimit = initialRot ? 0.0 : min(0.45, TIME_LIMIT * 0.35);\n\n    while (elapsed() < greedyLimit) {\n        bool improved = false;\n        shuffle(order.begin(), order.end(), rng);\n        for (int cell : order) {\n            if (elapsed() > greedyLimit) break;\n            int baseType = base[cell];\n            int curType = finalType[cell];\n            LocalResult curRes = localEval(cell, curType);\n            pair<int, int> bestMetric = {curRes.score, -curRes.open};\n            int bestType = curType;\n            int bestRot = rot[cell];\n            array<char, 8> used{};\n            for (int r = 0; r < 4; ++r) {\n                int candType = ROT_TABLE[baseType][r];\n                if (used[candType]) continue;\n                used[candType] = 1;\n                LocalResult candRes = localEval(cell, candType);\n                pair<int, int> metric = {candRes.score, -candRes.open};\n                if (metric > bestMetric || (metric == bestMetric && (rng() & 1))) {\n                    bestMetric = metric;\n                    bestType = candType;\n                    bestRot = r;\n                }\n            }\n            if (bestType != curType) {\n                finalType[cell] = bestType;\n                rot[cell] = bestRot;\n                improved = true;\n                updateAround(cell);\n            }\n        }\n        if (!improved) break;\n    }\n\n    recomputeAll();\n\n    Evaluator evaluator;\n    EvalResult curEval = evaluator(finalType);\n    long long currentScore = curEval.score;\n    long long bestScore = currentScore;\n    vector<int> bestRot = rot;\n    vector<int> bestType = finalType;\n\n    double saStart = elapsed();\n    double saEnd = min(TIME_LIMIT - 0.02, TIME_LIMIT * 0.98);\n    if (saEnd <= saStart + 1e-4) saEnd = TIME_LIMIT - 0.02;\n\n    if (saEnd > saStart + 1e-4) {\n        double span = max(1e-6, saEnd - saStart);\n        const double T0 = 4.0;\n        const double T1 = 0.05;\n\n        while (elapsed() < saEnd) {\n            double progress = (elapsed() - saStart) / span;\n            progress = min(1.0, max(0.0, progress));\n            double temp = T0 + (T1 - T0) * progress;\n\n            int cell;\n            if (!badCells.empty() && dist01(rng) < 0.85) {\n                cell = badCells[rng() % badCells.size()];\n            } else {\n                cell = rng() % N;\n            }\n\n            int baseType = base[cell];\n            int oldRot = rot[cell];\n            int oldType = finalType[cell];\n\n            int newRot = oldRot;\n            int newType = oldType;\n            bool changed = false;\n            for (int tries = 0; tries < 4; ++tries) {\n                int diff = rng() % 3 + 1;\n                int candRot = (oldRot + diff) & 3;\n                int candType = ROT_TABLE[baseType][candRot];\n                if (candType != oldType) {\n                    newRot = candRot;\n                    newType = candType;\n                    changed = true;\n                    break;\n                }\n            }\n            if (!changed) {\n                for (int r = 0; r < 4; ++r) {\n                    int candType = ROT_TABLE[baseType][r];\n                    if (candType != oldType) {\n                        newRot = r;\n                        newType = candType;\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n            if (!changed) continue;\n\n            rot[cell] = newRot;\n            finalType[cell] = newType;\n\n            EvalResult nextEval = evaluator(finalType);\n            long long delta = nextEval.score - currentScore;\n            bool accept = (delta >= 0) || (exp(delta / temp) > dist01(rng));\n\n            if (accept) {\n                currentScore = nextEval.score;\n                updateAround(cell);\n                if (nextEval.score > bestScore) {\n                    bestScore = nextEval.score;\n                    bestRot = rot;\n                    bestType = finalType;\n                }\n            } else {\n                rot[cell] = oldRot;\n                finalType[cell] = oldType;\n            }\n        }\n    }\n\n    Solution sol;\n    sol.score = bestScore;\n    sol.rot = move(bestRot);\n    sol.type = move(bestType);\n    return sol;\n}\n\nvoid hill_climb_improve(Solution& sol, const vector<int>& base, double timeBudget, uint64_t seed) {\n    if (timeBudget <= 1e-4 || sol.score < 0) return;\n    auto start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    mt19937 rng(seed);\n    Evaluator evaluator;\n\n    while (elapsed() < timeBudget) {\n        int cell = rng() % N;\n        int baseType = base[cell];\n        int oldRot = sol.rot[cell];\n        int oldType = sol.type[cell];\n\n        long long bestScore = sol.score;\n        int bestRot = oldRot;\n        int bestType = oldType;\n\n        for (int diff = 1; diff <= 3; ++diff) {\n            int newRot = (oldRot + diff) & 3;\n            int newType = ROT_TABLE[baseType][newRot];\n            if (newType == bestType) continue;\n            sol.rot[cell] = newRot;\n            sol.type[cell] = newType;\n            EvalResult res = evaluator(sol.type);\n            if (res.score > bestScore) {\n                bestScore = res.score;\n                bestRot = newRot;\n                bestType = newType;\n            }\n        }\n\n        sol.rot[cell] = bestRot;\n        sol.type[cell] = bestType;\n        sol.score = bestScore;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> base(N);\n    for (int i = 0; i < H; ++i) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < W; ++j) {\n            base[i * W + j] = s[j] - '0';\n        }\n    }\n\n    for (int cell = 0; cell < N; ++cell) {\n        int i = cell / W;\n        int j = cell % W;\n        for (int d = 0; d < DIR; ++d) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            g_neighbors[cell][d] = (0 <= ni && ni < H && 0 <= nj && nj < W) ? ni * W + nj : -1;\n        }\n    }\n\n    for (int t = 0; t < 8; ++t) {\n        ROT_TABLE[t][0] = t;\n        for (int r = 1; r < 4; ++r) {\n            ROT_TABLE[t][r] = ROT_NEXT[ROT_TABLE[t][r - 1]];\n        }\n    }\n\n    const double TOTAL_LIMIT = 1.9;\n    const double FINAL_MARGIN = 0.02;\n    const double HILL_BUDGET = 0.18;\n\n    vector<double> baseRuns = {0.9, 0.65};\n\n    auto globalStart = chrono::steady_clock::now();\n    auto totalElapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - globalStart).count();\n    };\n\n    uint64_t seedBase = chrono::high_resolution_clock::now().time_since_epoch().count();\n    Solution bestOverall;\n    bestOverall.score = -1;\n\n    for (size_t attempt = 0; attempt < baseRuns.size(); ++attempt) {\n        double remain = TOTAL_LIMIT - totalElapsed();\n        if (remain <= FINAL_MARGIN + HILL_BUDGET + 0.25) break;\n        double limit = min(baseRuns[attempt], remain - (FINAL_MARGIN + HILL_BUDGET));\n        if (limit < 0.25) break;\n        Solution sol = solve_single(base, limit, seedBase + attempt * 9973 + 1);\n        if (sol.score > bestOverall.score) bestOverall = sol;\n    }\n\n    if (bestOverall.score < 0) {\n        double remain = TOTAL_LIMIT - totalElapsed();\n        double limit = max(0.4, remain - (HILL_BUDGET + FINAL_MARGIN));\n        Solution sol = solve_single(base, limit, seedBase ^ 0x9e3779b97f4a7c15ULL);\n        if (sol.score > bestOverall.score) bestOverall = sol;\n    }\n\n    double remainForReanneal = TOTAL_LIMIT - totalElapsed() - (HILL_BUDGET + FINAL_MARGIN);\n    if (bestOverall.score >= 0 && remainForReanneal > 0.25) {\n        double limit = min(0.6, remainForReanneal);\n        Solution reSol = solve_single(base, limit, seedBase + 0x12345, &bestOverall.rot);\n        if (reSol.score > bestOverall.score) bestOverall = reSol;\n    }\n\n    double hillBudget = TOTAL_LIMIT - totalElapsed() - FINAL_MARGIN;\n    if (hillBudget > 0) {\n        hill_climb_improve(bestOverall, base, min(hillBudget, HILL_BUDGET), seedBase + 0xabcdef);\n    }\n\n    Evaluator finalEval;\n    bestOverall.score = finalEval(bestOverall.type).score;\n\n    string output;\n    output.reserve(N);\n    for (int idx = 0; idx < N; ++idx) {\n        output.push_back(char('0' + bestOverall.rot[idx]));\n    }\n    cout << output << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAX_N = 10;\nconst int MAX_CELLS = MAX_N * MAX_N;\n\nint N, T;\nint total_cells, total_tiles;\n\nuint64_t zobrist[MAX_CELLS][16];\nuint8_t visited_buf[MAX_CELLS];\nint queue_buf[MAX_CELLS];\n\nconst int CONN_DX[4] = {0, -1, 0, 1};\nconst int CONN_DY[4] = {-1, 0, 1, 0};\nconst int CONN_BIT[4] = {1, 2, 4, 8};\nconst int CONN_OPP[4] = {2, 3, 0, 1};\n\nconst int BLANK_DX[4] = {-1, 1, 0, 0};\nconst int BLANK_DY[4] = {0, 0, -1, 1};\nconst char MOVE_CHAR[4] = {'U', 'D', 'L', 'R'};\nconst int MOVE_OPP[4] = {1, 0, 3, 2};\n\nstruct EvalResult {\n    int matched_edges;\n    int largest_tree;\n    int best_component_nodes;\n    int best_component_cycles;\n};\n\ninline bool evalBetter(const EvalResult& a, const EvalResult& b) {\n    if (a.largest_tree != b.largest_tree) return a.largest_tree > b.largest_tree;\n    if (a.best_component_nodes != b.best_component_nodes) return a.best_component_nodes > b.best_component_nodes;\n    if (a.best_component_cycles != b.best_component_cycles) return a.best_component_cycles < b.best_component_cycles;\n    if (a.matched_edges != b.matched_edges) return a.matched_edges > b.matched_edges;\n    return false;\n}\n\ninline bool evalEqual(const EvalResult& a, const EvalResult& b) {\n    return a.largest_tree == b.largest_tree &&\n           a.best_component_nodes == b.best_component_nodes &&\n           a.best_component_cycles == b.best_component_cycles &&\n           a.matched_edges == b.matched_edges;\n}\n\nEvalResult evaluateBoard(const uint8_t* board) {\n    EvalResult res;\n    res.matched_edges = 0;\n    res.largest_tree = 0;\n    res.best_component_nodes = 0;\n    res.best_component_cycles = INT_MAX;\n\n    for (int i = 0; i < N; ++i) {\n        int base = i * N;\n        for (int j = 0; j < N; ++j) {\n            int idx = base + j;\n            uint8_t val = board[idx];\n            if (!val) continue;\n            if (j + 1 < N) {\n                uint8_t nb = board[idx + 1];\n                if (nb && (val & 4) && (nb & 1)) res.matched_edges++;\n            }\n            if (i + 1 < N) {\n                uint8_t nb = board[idx + N];\n                if (nb && (val & 8) && (nb & 2)) res.matched_edges++;\n            }\n        }\n    }\n\n    fill(visited_buf, visited_buf + total_cells, 0);\n    for (int idx = 0; idx < total_cells; ++idx) {\n        uint8_t val = board[idx];\n        if (!val || visited_buf[idx]) continue;\n        int head = 0, tail = 0;\n        queue_buf[tail++] = idx;\n        visited_buf[idx] = 1;\n        int nodes = 0;\n        int edges = 0;\n        while (head < tail) {\n            int cur = queue_buf[head++];\n            nodes++;\n            int cx = cur / N;\n            int cy = cur % N;\n            uint8_t curv = board[cur];\n            for (int d = 0; d < 4; ++d) {\n                if (!(curv & CONN_BIT[d])) continue;\n                int nx = cx + CONN_DX[d];\n                int ny = cy + CONN_DY[d];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                int nidx = nx * N + ny;\n                uint8_t nval = board[nidx];\n                if (!nval) continue;\n                if (!(nval & CONN_BIT[CONN_OPP[d]])) continue;\n                if (cur < nidx) edges++;\n                if (!visited_buf[nidx]) {\n                    visited_buf[nidx] = 1;\n                    queue_buf[tail++] = nidx;\n                }\n            }\n        }\n        int cycles = max(0, edges - (nodes - 1));\n        if (cycles == 0) res.largest_tree = max(res.largest_tree, nodes);\n        if (nodes > res.best_component_nodes ||\n            (nodes == res.best_component_nodes && cycles < res.best_component_cycles)) {\n            res.best_component_nodes = nodes;\n            res.best_component_cycles = cycles;\n        }\n    }\n    if (res.best_component_nodes == 0) res.best_component_cycles = 0;\n    return res;\n}\n\nuint64_t computeHash(const array<uint8_t, MAX_CELLS>& board) {\n    uint64_t h = 0;\n    for (int i = 0; i < total_cells; ++i) h ^= zobrist[i][board[i]];\n    return h;\n}\n\ninline void applyMoveArray(array<uint8_t, MAX_CELLS>& board, int& blank, int dir) {\n    int x = blank / N;\n    int y = blank % N;\n    int nx = x + BLANK_DX[dir];\n    int ny = y + BLANK_DY[dir];\n    int nidx = nx * N + ny;\n    swap(board[blank], board[nidx]);\n    blank = nidx;\n}\n\nstruct NodeInfo { int parent; char move; };\n\nstruct SearchState {\n    array<uint8_t, MAX_CELLS> tiles;\n    uint16_t blank = 0;\n    uint64_t hash = 0;\n    EvalResult eval{};\n    uint16_t depth = 0;\n    int node_id = 0;\n    uint32_t rand_key = 0;\n};\n\nstruct AttemptResult {\n    EvalResult eval;\n    int depth;\n    string sequence;\n    array<uint8_t, MAX_CELLS> board;\n    int blank;\n};\n\nAttemptResult runAttempt(const array<uint8_t, MAX_CELLS>& start_tiles,\n                         int blank_pos,\n                         int beam_width,\n                         int depth_limit,\n                         double time_limit,\n                         const chrono::steady_clock::time_point& start_time,\n                         mt19937& rng) {\n    AttemptResult result;\n    result.board = start_tiles;\n    result.blank = blank_pos;\n    result.eval = evaluateBoard(start_tiles.data());\n    result.depth = 0;\n    result.sequence.clear();\n    if (depth_limit <= 0 || result.eval.largest_tree == total_tiles) {\n        return result;\n    }\n\n    vector<NodeInfo> nodes;\n    nodes.reserve(1 + beam_width * 64);\n    nodes.push_back({-1, '?'});\n\n    size_t reserve_est = (size_t)beam_width * min(depth_limit, 64);\n    unordered_map<uint64_t, uint16_t> visited;\n    visited.reserve(reserve_est + 16);\n\n    vector<SearchState> beam;\n    vector<SearchState> candidates;\n    beam.reserve(beam_width);\n    candidates.reserve(beam_width * 4 + 8);\n\n    SearchState init;\n    init.tiles = start_tiles;\n    init.blank = blank_pos;\n    init.hash = computeHash(start_tiles);\n    init.eval = result.eval;\n    init.depth = 0;\n    init.node_id = 0;\n    init.rand_key = rng();\n    beam.push_back(init);\n    visited.emplace(init.hash, 0);\n\n    EvalResult best_eval = init.eval;\n    int best_depth = 0;\n    int best_node = 0;\n    array<uint8_t, MAX_CELLS> best_tiles = start_tiles;\n    int best_blank = blank_pos;\n\n    auto stateComparator = [](const SearchState& a, const SearchState& b) {\n        if (evalBetter(a.eval, b.eval)) return true;\n        if (evalBetter(b.eval, a.eval)) return false;\n        if (a.depth != b.depth) return a.depth < b.depth;\n        return a.rand_key < b.rand_key;\n    };\n\n    int current_depth = 0;\n    bool terminate = false;\n\n    while (!beam.empty() && current_depth < depth_limit && !terminate) {\n        if ((current_depth & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n            if (elapsed > time_limit) break;\n        }\n        candidates.clear();\n        for (size_t si = 0; si < beam.size() && !terminate; ++si) {\n            if ((si & 3) == 0) {\n                double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n                if (elapsed > time_limit) { terminate = true; break; }\n            }\n            const SearchState& state = beam[si];\n            int blank = state.blank;\n            int bx = blank / N;\n            int by = blank % N;\n            int dir_order[4] = {0, 1, 2, 3};\n            for (int i = 3; i > 0; --i) {\n                int j = rng() % (i + 1);\n                swap(dir_order[i], dir_order[j]);\n            }\n            for (int k = 0; k < 4; ++k) {\n                int dir = dir_order[k];\n                int nx = bx + BLANK_DX[dir];\n                int ny = by + BLANK_DY[dir];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                int nidx = nx * N + ny;\n                if (state.tiles[nidx] == 0) continue;\n                SearchState child = state;\n                uint8_t tile_to_move = state.tiles[nidx];\n                child.tiles[blank] = tile_to_move;\n                child.tiles[nidx] = 0;\n                child.blank = nidx;\n                child.depth = state.depth + 1;\n                if (child.depth > depth_limit) continue;\n                child.hash ^= zobrist[blank][0];\n                child.hash ^= zobrist[nidx][tile_to_move];\n                child.hash ^= zobrist[blank][tile_to_move];\n                child.hash ^= zobrist[nidx][0];\n                auto it = visited.find(child.hash);\n                if (it != visited.end()) {\n                    if (child.depth >= it->second) continue;\n                    it->second = child.depth;\n                } else {\n                    visited.emplace(child.hash, child.depth);\n                }\n                child.node_id = static_cast<int>(nodes.size());\n                nodes.push_back({state.node_id, MOVE_CHAR[dir]});\n                child.eval = evaluateBoard(child.tiles.data());\n                child.rand_key = rng();\n                if (evalBetter(child.eval, best_eval) ||\n                    (evalEqual(child.eval, best_eval) && child.depth < best_depth)) {\n                    best_eval = child.eval;\n                    best_depth = child.depth;\n                    best_node = child.node_id;\n                    best_tiles = child.tiles;\n                    best_blank = child.blank;\n                    if (best_eval.largest_tree == total_tiles) {\n                        terminate = true;\n                        candidates.emplace_back(std::move(child));\n                        break;\n                    }\n                }\n                candidates.emplace_back(std::move(child));\n            }\n        }\n        if (terminate || candidates.empty()) break;\n        sort(candidates.begin(), candidates.end(), stateComparator);\n        if ((int)candidates.size() > beam_width) candidates.resize(beam_width);\n        beam.swap(candidates);\n        current_depth++;\n    }\n\n    string seq;\n    seq.reserve(best_depth);\n    int node = best_node;\n    while (node != 0) {\n        seq.push_back(nodes[node].move);\n        node = nodes[node].parent;\n    }\n    reverse(seq.begin(), seq.end());\n\n    result.sequence = seq;\n    result.eval = best_eval;\n    result.depth = best_depth;\n    result.board = best_tiles;\n    result.blank = best_blank;\n    return result;\n}\n\nvoid guidedRandomSearch(string& best_sequence,\n                        int& best_length,\n                        array<uint8_t, MAX_CELLS>& best_board,\n                        int& best_blank,\n                        EvalResult& best_eval,\n                        const chrono::steady_clock::time_point& start_time,\n                        double time_limit,\n                        mt19937& rng) {\n    if (best_length >= T) return;\n    string current_sequence = best_sequence;\n    array<uint8_t, MAX_CELLS> current_board = best_board;\n    int current_blank = best_blank;\n    EvalResult current_eval = best_eval;\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n    int prev_dir = -1;\n    int stagnation = 0;\n    const int reset_interval = max(80, 40 + 6 * N);\n\n    while ((int)current_sequence.size() < T) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n        if (elapsed > time_limit) break;\n\n        if (stagnation > reset_interval) {\n            current_sequence = best_sequence;\n            current_board = best_board;\n            current_blank = best_blank;\n            current_eval = best_eval;\n            prev_dir = -1;\n            stagnation = 0;\n        }\n\n        struct CandidateMove {\n            int dir;\n            EvalResult eval;\n            bool is_reverse;\n        };\n        CandidateMove candidates[4];\n        int candCount = 0;\n\n        int x = current_blank / N;\n        int y = current_blank % N;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = x + BLANK_DX[dir];\n            int ny = y + BLANK_DY[dir];\n            if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n            int nidx = nx * N + ny;\n            if (current_board[nidx] == 0) continue;\n            int temp_blank = current_blank;\n            applyMoveArray(current_board, temp_blank, dir);\n            EvalResult eval = evaluateBoard(current_board.data());\n            applyMoveArray(current_board, temp_blank, MOVE_OPP[dir]);\n            candidates[candCount++] = {dir, eval, (dir == MOVE_OPP[prev_dir])};\n        }\n\n        if (candCount == 0) break;\n\n        double progress = (double)best_eval.largest_tree / max(1, total_tiles);\n        double explore_prob = 0.08 + 0.25 * (1.0 - progress);\n        if (stagnation > reset_interval / 2) explore_prob += 0.05;\n        explore_prob = min(0.4, max(0.05, explore_prob));\n        bool explore = dist01(rng) < explore_prob;\n\n        int chosen_idx = 0;\n        if (!explore) {\n            for (int i = 1; i < candCount; ++i) {\n                if (evalBetter(candidates[i].eval, candidates[chosen_idx].eval)) {\n                    chosen_idx = i;\n                } else if (!evalBetter(candidates[chosen_idx].eval, candidates[i].eval)) {\n                    bool a_rev = candidates[chosen_idx].is_reverse;\n                    bool b_rev = candidates[i].is_reverse;\n                    if (a_rev != b_rev) {\n                        if (!b_rev) chosen_idx = i;\n                    } else if (rng() & 1) {\n                        chosen_idx = i;\n                    }\n                }\n            }\n        } else {\n            int nonRev[4];\n            int nonCnt = 0;\n            for (int i = 0; i < candCount; ++i) if (!candidates[i].is_reverse) nonRev[nonCnt++] = i;\n            if (nonCnt > 0) chosen_idx = nonRev[rng() % nonCnt];\n            else chosen_idx = rng() % candCount;\n        }\n\n        int dir = candidates[chosen_idx].dir;\n        applyMoveArray(current_board, current_blank, dir);\n        current_sequence.push_back(MOVE_CHAR[dir]);\n        prev_dir = dir;\n        current_eval = candidates[chosen_idx].eval;\n        stagnation++;\n\n        if (evalBetter(current_eval, best_eval)) {\n            best_eval = current_eval;\n            best_sequence = current_sequence;\n            best_board = current_board;\n            best_blank = current_blank;\n            best_length = (int)best_sequence.size();\n            stagnation = 0;\n            if (best_eval.largest_tree == total_tiles) break;\n        }\n\n        if ((int)current_sequence.size() >= T) break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T;\n    total_cells = N * N;\n    total_tiles = total_cells - 1;\n\n    array<uint8_t, MAX_CELLS> initial_tiles{};\n    int blank_pos = -1;\n    for (int i = 0; i < N; ++i) {\n        string row;\n        cin >> row;\n        for (int j = 0; j < N; ++j) {\n            char c = row[j];\n            int val = (c <= '9') ? c - '0' : 10 + (c - 'a');\n            int idx = i * N + j;\n            initial_tiles[idx] = static_cast<uint8_t>(val);\n            if (val == 0) blank_pos = idx;\n        }\n    }\n\n    mt19937_64 rng64(chrono::steady_clock::now().time_since_epoch().count());\n    for (int i = 0; i < MAX_CELLS; ++i)\n        for (int v = 0; v < 16; ++v) {\n            uint64_t x = rng64();\n            if (x == 0) x = 1;\n            zobrist[i][v] = x;\n        }\n    mt19937 rng(static_cast<uint32_t>(rng64()));\n\n    EvalResult best_eval = evaluateBoard(initial_tiles.data());\n    string best_sequence;\n    best_sequence.reserve(T);\n    array<uint8_t, MAX_CELLS> best_board = initial_tiles;\n    int best_blank = blank_pos;\n    int best_length = 0;\n\n    const double TIME_LIMIT = 2.80;\n    const double FIRST_RATIO = 0.55;\n    const double SECOND_RATIO = 0.92;\n\n    int base_width = 80 - 4 * N;\n    base_width = max(12, min(base_width, 90));\n    int local_base_width = max(8, base_width - 8);\n\n    int global_depth_cap = min(T, max(200, 10 * N * N));\n    int local_depth_cap = min(T, max(80, 4 * N * N));\n\n    auto start_time = chrono::steady_clock::now();\n\n    auto attemptBetter = [&](const AttemptResult& a, const AttemptResult& b) {\n        if (evalBetter(a.eval, b.eval)) return true;\n        if (evalBetter(b.eval, a.eval)) return false;\n        return a.depth < b.depth;\n    };\n\n    vector<AttemptResult> candidateStates;\n    const int MAX_CANDIDATES = 5;\n    AttemptResult initial_state;\n    initial_state.eval = best_eval;\n    initial_state.sequence = \"\";\n    initial_state.depth = 0;\n    initial_state.board = initial_tiles;\n    initial_state.blank = blank_pos;\n    candidateStates.push_back(initial_state);\n\n    auto addCandidate = [&](const AttemptResult& res) {\n        candidateStates.push_back(res);\n        sort(candidateStates.begin(), candidateStates.end(),\n             [&](const AttemptResult& x, const AttemptResult& y) {\n                 if (attemptBetter(x, y)) return true;\n                 if (attemptBetter(y, x)) return false;\n                 return x.sequence.size() < y.sequence.size();\n             });\n        vector<AttemptResult> filtered;\n        filtered.reserve(MAX_CANDIDATES);\n        for (const auto& cand : candidateStates) {\n            bool dup = false;\n            for (const auto& f : filtered) {\n                if (evalEqual(cand.eval, f.eval) && cand.depth == f.depth) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) {\n                filtered.push_back(cand);\n                if ((int)filtered.size() == MAX_CANDIDATES) break;\n            }\n        }\n        candidateStates.swap(filtered);\n    };\n\n    int attempt = 0;\n    while (true) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n        if (elapsed > TIME_LIMIT * FIRST_RATIO) break;\n        int width = base_width;\n        int mod = attempt % 4;\n        if (mod == 1) width += 8;\n        else if (mod == 2) width -= 6;\n        else if (mod == 3) width += 2;\n        width = max(10, min(width, 96));\n\n        AttemptResult res = runAttempt(initial_tiles, blank_pos, width, global_depth_cap,\n                                       TIME_LIMIT, start_time, rng);\n        attempt++;\n        addCandidate(res);\n        if (evalBetter(res.eval, best_eval) ||\n            (evalEqual(res.eval, best_eval) && (best_length == 0 || res.depth < best_length))) {\n            best_eval = res.eval;\n            best_sequence = res.sequence;\n            best_board = res.board;\n            best_blank = res.blank;\n            best_length = res.depth;\n            if (best_eval.largest_tree == total_tiles) break;\n        }\n    }\n\n    if (best_eval.largest_tree < total_tiles && best_length < T) {\n        vector<AttemptResult> snapshot = candidateStates;\n        for (size_t idx = 0; idx < snapshot.size(); ++idx) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n            if (elapsed > TIME_LIMIT * SECOND_RATIO) break;\n            AttemptResult base_state = snapshot[idx];\n            for (int iter = 0; iter < 2; ++iter) {\n                double elapsed2 = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n                if (elapsed2 > TIME_LIMIT * SECOND_RATIO) break;\n                int remaining = T - base_state.depth;\n                if (remaining <= 0) break;\n                int depth_cap = min(remaining, local_depth_cap);\n                int width = local_base_width;\n                int mod = (idx + iter) % 3;\n                if (mod == 1) width += 4;\n                else if (mod == 2) width -= 4;\n                width = max(8, min(width, 90));\n\n                AttemptResult res = runAttempt(base_state.board, base_state.blank, width, depth_cap,\n                                               TIME_LIMIT, start_time, rng);\n                if (res.depth == 0) continue;\n\n                AttemptResult combined;\n                combined.eval = res.eval;\n                combined.depth = base_state.depth + res.depth;\n                combined.sequence = base_state.sequence + res.sequence;\n                combined.board = res.board;\n                combined.blank = res.blank;\n\n                addCandidate(combined);\n\n                if (evalBetter(combined.eval, best_eval)) {\n                    best_eval = combined.eval;\n                    best_sequence = combined.sequence;\n                    best_board = combined.board;\n                    best_blank = combined.blank;\n                    best_length = combined.depth;\n                    if (best_eval.largest_tree == total_tiles || best_length >= T) break;\n                }\n                base_state = combined;\n            }\n            if (best_eval.largest_tree == total_tiles || best_length >= T) break;\n        }\n    }\n\n    best_length = (int)best_sequence.size();\n\n    if (best_eval.largest_tree < total_tiles && best_length < T) {\n        guidedRandomSearch(best_sequence, best_length, best_board, best_blank,\n                           best_eval, start_time, TIME_LIMIT, rng);\n    }\n\n    cout << best_sequence << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\nstruct Line { long long A, B, C; };\nstruct Key { unsigned long long lo, hi; };\nstruct PieceSegment { int start, len; };\nusing CountArr = array<int, 11>;\n\nconst long long COORD_LIMIT = 1'000'000'000LL;\nconst double TIME_LIMIT = 2.8;\nconst int DIR_LIMIT = 1000;\nconst int GENERATE_LINE_ATTEMPTS = 100;\n\nint N, K;\narray<int, 11> demand{};\nvector<Point> points;\n\nvector<unsigned long long> pattern_lo, pattern_hi;\nvector<Key> tmp_keys;\nvector<long long> proj_values;\nvector<long long> proj_sorted_buffer;\nvector<long long> piece_proj_buffer;\nvector<long long> unique_values_buffer;\nvector<int> targeted_gap_indices;\nvector<int> state_order;\nvector<int> eval_order;\nvector<int> piece_id;\nvector<PieceSegment> piece_segments;\nvector<int> gap_indices;\nvector<Line> lines_current;\n\nCountArr current_counts_state{};\nint bits_used = 0;\nbool piece_info_valid = false;\n\nmt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\nchrono::steady_clock::time_point start_time;\nbool time_up = false;\n\ninline long long absll(long long x) { return x >= 0 ? x : -x; }\n\nlong long floor_div(long long a, long long b) {\n    assert(b != 0);\n    if (b < 0) { a = -a; b = -b; }\n    if (a >= 0) return a / b;\n    return -(( -a + b - 1 ) / b);\n}\nlong long ceil_div(long long a, long long b) {\n    assert(b != 0);\n    if (b < 0) { a = -a; b = -b; }\n    if (a >= 0) return (a + b - 1) / b;\n    return -((-a) / b);\n}\n\nlong long ext_gcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) {\n        x = (a >= 0) ? 1 : -1;\n        y = 0;\n        return absll(a);\n    }\n    long long x1, y1;\n    long long g = ext_gcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\ninline bool check_time() {\n    if (time_up) return true;\n    double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    if (elapsed > TIME_LIMIT) time_up = true;\n    return time_up;\n}\n\nvoid reset_state() {\n    fill(pattern_lo.begin(), pattern_lo.end(), 0ULL);\n    fill(pattern_hi.begin(), pattern_hi.end(), 0ULL);\n    lines_current.clear();\n    lines_current.reserve(K);\n    bits_used = 0;\n    piece_info_valid = false;\n}\n\nint score_from_counts(const CountArr &cnt) {\n    int sc = 0;\n    for (int d = 1; d <= 10; ++d) sc += min(demand[d], cnt[d]);\n    return sc;\n}\n\nint recompute_state(CountArr &out_cnt, bool store_info) {\n    out_cnt.fill(0);\n    for (int i = 0; i < N; ++i) {\n        tmp_keys[i] = {pattern_lo[i], pattern_hi[i]};\n        state_order[i] = i;\n    }\n    auto cmp = [&](int lhs, int rhs) {\n        const Key &a = tmp_keys[lhs];\n        const Key &b = tmp_keys[rhs];\n        if (a.hi != b.hi) return a.hi < b.hi;\n        return a.lo < b.lo;\n    };\n    sort(state_order.begin(), state_order.end(), cmp);\n\n    if (store_info) {\n        piece_segments.clear();\n        piece_segments.reserve(N);\n        piece_info_valid = true;\n        current_counts_state = out_cnt; // temporary zero, will overwrite later\n    } else {\n        piece_info_valid = false;\n    }\n\n    int idx = 0;\n    while (idx < N) {\n        int j = idx + 1;\n        while (j < N) {\n            const Key &ka = tmp_keys[state_order[idx]];\n            const Key &kb = tmp_keys[state_order[j]];\n            if (ka.lo != kb.lo || ka.hi != kb.hi) break;\n            ++j;\n        }\n        int len = j - idx;\n        if (len <= 10) out_cnt[len]++;\n        if (store_info) {\n            piece_segments.push_back({idx, len});\n            int pid = (int)piece_segments.size() - 1;\n            for (int t = idx; t < j; ++t) piece_id[state_order[t]] = pid;\n        }\n        idx = j;\n    }\n    if (store_info) current_counts_state = out_cnt;\n    return score_from_counts(out_cnt);\n}\n\nint evaluate_candidate(const Line &line) {\n    if (bits_used >= 128) return -1;\n    for (int i = 0; i < N; ++i) {\n        long long val = line.A * points[i].x + line.B * points[i].y - line.C;\n        if (val == 0) return -1;\n        unsigned long long bit = (val > 0) ? 1ULL : 0ULL;\n        unsigned long long lo = pattern_lo[i];\n        unsigned long long hi = pattern_hi[i];\n        if (bits_used < 64) lo |= bit << bits_used;\n        else hi |= bit << (bits_used - 64);\n        tmp_keys[i] = {lo, hi};\n        eval_order[i] = i;\n    }\n    auto cmp = [&](int lhs, int rhs) {\n        const Key &a = tmp_keys[lhs];\n        const Key &b = tmp_keys[rhs];\n        if (a.hi != b.hi) return a.hi < b.hi;\n        return a.lo < b.lo;\n    };\n    sort(eval_order.begin(), eval_order.end(), cmp);\n    CountArr cnt;\n    cnt.fill(0);\n    int idx = 0;\n    while (idx < N) {\n        int j = idx + 1;\n        while (j < N) {\n            const Key &ka = tmp_keys[eval_order[idx]];\n            const Key &kb = tmp_keys[eval_order[j]];\n            if (ka.lo != kb.lo || ka.hi != kb.hi) break;\n            ++j;\n        }\n        int len = j - idx;\n        if (len <= 10) cnt[len]++;\n        idx = j;\n    }\n    return score_from_counts(cnt);\n}\n\ninline long long rand_ll(long long l, long long r) {\n    unsigned long long range = (unsigned long long)(r - l + 1);\n    return l + (long long)(rng() % range);\n}\n\nbool sample_pair_line_indices(int i, int j, Line &line) {\n    if (i == j) return false;\n    long long a = points[j].x - points[i].x;\n    long long b = points[j].y - points[i].y;\n    long long g = std::gcd(absll(a), absll(b));\n    if (g == 0) return false;\n    a /= g; b /= g;\n    if (a < 0 || (a == 0 && b < 0)) { a = -a; b = -b; }\n    long long vi = a * points[i].x + b * points[i].y;\n    long long vj = a * points[j].x + b * points[j].y;\n    if (vi == vj) return false;\n    long long lo = min(vi, vj);\n    long long hi = max(vi, vj);\n    if (hi - lo < 2) return false;\n    long long c = rand_ll(lo + 1, hi - 1);\n    line = {a, b, c};\n    return true;\n}\n\nbool sample_direction_line(Line &line) {\n    static const pair<int,int> preset[4] = {{1,0},{0,1},{1,1},{1,-1}};\n    for (int iter = 0; iter < 12; ++iter) {\n        long long a = 0, b = 0;\n        int mode = rng() % 6;\n        if (mode < 4) {\n            a = preset[mode].first;\n            b = preset[mode].second;\n        } else {\n            do {\n                a = rand_ll(-DIR_LIMIT, DIR_LIMIT);\n                b = rand_ll(-DIR_LIMIT, DIR_LIMIT);\n            } while (a == 0 && b == 0);\n        }\n        long long g = std::gcd(absll(a), absll(b));\n        if (g == 0) continue;\n        a /= g; b /= g;\n        if (a < 0 || (a == 0 && b < 0)) { a = -a; b = -b; }\n        for (int i = 0; i < N; ++i) proj_values[i] = a * points[i].x + b * points[i].y;\n        vector<long long> sorted_vals = proj_values;\n        sort(sorted_vals.begin(), sorted_vals.end());\n        gap_indices.clear();\n        for (int i = 1; i < N; ++i) {\n            if (sorted_vals[i] - sorted_vals[i - 1] >= 2) gap_indices.push_back(i);\n        }\n        if (gap_indices.empty()) continue;\n        int pos = gap_indices[rng() % gap_indices.size()];\n        long long left = sorted_vals[pos - 1];\n        long long right = sorted_vals[pos];\n        long long c = rand_ll(left + 1, right - 1);\n        line = {a, b, c};\n        return true;\n    }\n    return false;\n}\n\nbool sample_pair_line(Line &line) {\n    if (N < 2) return false;\n    for (int tries = 0; tries < 40; ++tries) {\n        int i = rng() % N;\n        int j = rng() % N;\n        if (i == j) continue;\n        if (sample_pair_line_indices(i, j, line)) return true;\n    }\n    return false;\n}\n\nbool piece_direction_split(const PieceSegment &seg, Line &line) {\n    if (seg.len < 2) return false;\n    for (int dir_try = 0; dir_try < 6; ++dir_try) {\n        int idx1 = state_order[seg.start + rng() % seg.len];\n        int idx2 = state_order[seg.start + rng() % seg.len];\n        if (idx1 == idx2) continue;\n        long long a = points[idx2].x - points[idx1].x;\n        long long b = points[idx2].y - points[idx1].y;\n        long long g = std::gcd(absll(a), absll(b));\n        if (g == 0) continue;\n        a /= g; b /= g;\n        if (a < 0 || (a == 0 && b < 0)) { a = -a; b = -b; }\n        for (int i = 0; i < N; ++i) proj_values[i] = a * points[i].x + b * points[i].y;\n        piece_proj_buffer.clear();\n        piece_proj_buffer.reserve(seg.len);\n        for (int t = 0; t < seg.len; ++t) {\n            piece_proj_buffer.push_back(proj_values[state_order[seg.start + t]]);\n        }\n        sort(piece_proj_buffer.begin(), piece_proj_buffer.end());\n        proj_sorted_buffer.assign(proj_values.begin(), proj_values.end());\n        sort(proj_sorted_buffer.begin(), proj_sorted_buffer.end());\n        unique_values_buffer.clear();\n        unique_values_buffer.reserve(proj_sorted_buffer.size());\n        for (long long val : proj_sorted_buffer) {\n            if (unique_values_buffer.empty() || unique_values_buffer.back() != val)\n                unique_values_buffer.push_back(val);\n        }\n        targeted_gap_indices.clear();\n        for (int k = 0; k + 1 < (int)unique_values_buffer.size(); ++k) {\n            long long left = unique_values_buffer[k];\n            long long right = unique_values_buffer[k + 1];\n            if (right - left < 2) continue;\n            auto itRight = lower_bound(piece_proj_buffer.begin(), piece_proj_buffer.end(), right);\n            if (itRight == piece_proj_buffer.end()) continue;\n            auto itLeft = upper_bound(piece_proj_buffer.begin(), piece_proj_buffer.end(), left);\n            if (itLeft == piece_proj_buffer.begin()) continue;\n            targeted_gap_indices.push_back(k);\n        }\n        if (targeted_gap_indices.empty()) continue;\n        int chosen_idx = targeted_gap_indices[rng() % targeted_gap_indices.size()];\n        long long left = unique_values_buffer[chosen_idx];\n        long long right = unique_values_buffer[chosen_idx + 1];\n        long long c = rand_ll(left + 1, right - 1);\n        line = {a, b, c};\n        return true;\n    }\n    return false;\n}\n\nbool sample_piece_line(Line &line) {\n    if (!piece_info_valid || piece_segments.empty()) return false;\n    int desired_size = 10;\n    for (int d = 1; d <= 10; ++d) {\n        if (current_counts_state[d] < demand[d]) {\n            desired_size = d;\n            break;\n        }\n    }\n    for (int tries = 0; tries < 80; ++tries) {\n        int idx = rng() % N;\n        int pid = piece_id[idx];\n        const auto &seg = piece_segments[pid];\n        if (seg.len < 2) continue;\n        if (seg.len <= desired_size && (rng() % 4 != 0)) continue;\n        bool try_direction = (seg.len >= 4) && (rng() % 2 == 0);\n        if (try_direction) {\n            if (piece_direction_split(seg, line)) return true;\n        }\n        int other = state_order[seg.start + rng() % seg.len];\n        if (other == idx) continue;\n        if (sample_pair_line_indices(idx, other, line)) return true;\n    }\n    return false;\n}\n\nbool generate_candidate_line(Line &line) {\n    for (int attempt = 0; attempt < GENERATE_LINE_ATTEMPTS; ++attempt) {\n        if (check_time()) break;\n        int choice = rng() % 100;\n        bool ok = false;\n        if (piece_info_valid && choice < 55) ok = sample_piece_line(line);\n        if (!ok && choice < 80) ok = sample_pair_line(line);\n        if (!ok) ok = sample_direction_line(line);\n        if (ok) return true;\n    }\n    return false;\n}\n\nvoid apply_line(const Line &line) {\n    for (int i = 0; i < N; ++i) {\n        long long val = line.A * points[i].x + line.B * points[i].y - line.C;\n        if (val == 0) val = 1;\n        unsigned long long bit = (val > 0) ? 1ULL : 0ULL;\n        if (bits_used < 64) pattern_lo[i] |= bit << bits_used;\n        else pattern_hi[i] |= bit << (bits_used - 64);\n    }\n    lines_current.push_back(line);\n    ++bits_used;\n}\n\nint candidate_trials(int iter) {\n    if (iter < 10) return 45;\n    if (iter < 25) return 35;\n    if (iter < 50) return 28;\n    if (iter < 80) return 22;\n    return 18;\n}\n\nstruct AttemptResult {\n    int score;\n    vector<Line> lines;\n};\n\nAttemptResult run_attempt(const vector<Line> &base_lines) {\n    reset_state();\n    for (const auto &ln : base_lines) {\n        if ((int)lines_current.size() >= K) break;\n        apply_line(ln);\n    }\n    CountArr current_counts;\n    int current_score = recompute_state(current_counts, true);\n    int best_score_local = current_score;\n    vector<Line> best_lines_local = lines_current;\n\n    while ((int)lines_current.size() < K && !check_time()) {\n        int trials = candidate_trials((int)lines_current.size());\n        Line chosen{};\n        int chosen_score = INT_MIN;\n        bool found = false;\n        for (int t = 0; t < trials && !check_time(); ++t) {\n            Line cand;\n            if (!generate_candidate_line(cand)) continue;\n            int sc = evaluate_candidate(cand);\n            if (sc < 0) continue;\n            if (!found || sc > chosen_score) {\n                found = true;\n                chosen_score = sc;\n                chosen = cand;\n            }\n        }\n        if (!found) break;\n        apply_line(chosen);\n        current_score = recompute_state(current_counts, true);\n        if (current_score > best_score_local) {\n            best_score_local = current_score;\n            best_lines_local = lines_current;\n        }\n    }\n    return {best_score_local, best_lines_local};\n}\n\nbool line_to_points(const Line &line, array<long long,4> &out) {\n    long long A = line.A, B = line.B, C = line.C;\n    if (A == 0 && B == 0) return false;\n    if (B == 0) {\n        long long x = C / A;\n        long long y1 = -COORD_LIMIT + 1;\n        long long y2 = y1 + 1;\n        out = {{x, y1, x, y2}};\n        return true;\n    }\n    if (A == 0) {\n        long long y = C / B;\n        long long x1 = -COORD_LIMIT + 1;\n        long long x2 = x1 + 1;\n        out = {{x1, y, x2, y}};\n        return true;\n    }\n    long long x0, y0;\n    long long g = ext_gcd(A, B, x0, y0);\n    if (g == 0 || C % g != 0) return false;\n    long long mult = C / g;\n    x0 *= mult;\n    y0 *= mult;\n    auto range_for = [&](long long base, long long coeff) -> pair<long long,long long> {\n        const long long INF = (1LL << 60);\n        if (coeff == 0) {\n            if (absll(base) > COORD_LIMIT) return {1, 0};\n            return {-INF, INF};\n        }\n        long long low = -INF, high = INF;\n        if (coeff > 0) {\n            low = max(low, ceil_div(-COORD_LIMIT - base, coeff));\n            high = min(high, floor_div(COORD_LIMIT - base, coeff));\n        } else {\n            high = min(high, floor_div(-COORD_LIMIT - base, coeff));\n            low = max(low, ceil_div(COORD_LIMIT - base, coeff));\n        }\n        return {low, high};\n    };\n    auto rx = range_for(x0, B);\n    auto ry = range_for(y0, -A);\n    long long low = max(rx.first, ry.first);\n    long long high = min(rx.second, ry.second);\n    if (low > high) return false;\n    auto point_from = [&](long long k) -> pair<long long,long long> {\n        return {x0 + B * k, y0 - A * k};\n    };\n    long long k0 = min(max(0LL, low), high);\n    auto P = point_from(k0);\n    if (absll(P.first) > COORD_LIMIT || absll(P.second) > COORD_LIMIT) {\n        P = point_from(low);\n        k0 = low;\n    }\n    long long qk = (k0 < high) ? k0 + 1 : k0 - 1;\n    auto Q = point_from(qk);\n    if (absll(Q.first) > COORD_LIMIT || absll(Q.second) > COORD_LIMIT || (Q.first == P.first && Q.second == P.second)) {\n        bool found = false;\n        for (long long delta = 1; delta <= 200000 && !found; ++delta) {\n            if (k0 + delta <= high) {\n                auto cand = point_from(k0 + delta);\n                if (absll(cand.first) <= COORD_LIMIT && absll(cand.second) <= COORD_LIMIT && (cand.first != P.first || cand.second != P.second)) {\n                    Q = cand;\n                    found = true;\n                    break;\n                }\n            }\n            if (k0 - delta >= low) {\n                auto cand = point_from(k0 - delta);\n                if (absll(cand.first) <= COORD_LIMIT && absll(cand.second) <= COORD_LIMIT && (cand.first != P.first || cand.second != P.second)) {\n                    Q = cand;\n                    found = true;\n                    break;\n                }\n            }\n        }\n        if (!found) return false;\n    }\n    out = {{P.first, P.second, Q.first, Q.second}};\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K;\n    for (int d = 1; d <= 10; ++d) cin >> demand[d];\n    points.resize(N);\n    for (int i = 0; i < N; ++i) cin >> points[i].x >> points[i].y;\n\n    pattern_lo.assign(N, 0ULL);\n    pattern_hi.assign(N, 0ULL);\n    tmp_keys.resize(N);\n    proj_values.resize(N);\n    proj_sorted_buffer.reserve(N);\n    piece_proj_buffer.reserve(N);\n    unique_values_buffer.reserve(N);\n    targeted_gap_indices.reserve(N);\n    state_order.resize(N);\n    eval_order.resize(N);\n    piece_id.resize(N);\n    lines_current.reserve(K);\n    gap_indices.reserve(N);\n\n    current_counts_state.fill(0);\n    start_time = chrono::steady_clock::now();\n\n    int global_best_score = -1;\n    vector<Line> global_best_lines;\n    vector<Line> base_prefix;\n    base_prefix.reserve(K);\n\n    while (!check_time()) {\n        base_prefix.clear();\n        if (!global_best_lines.empty()) {\n            int mode = rng() % 5;\n            if (mode <= 2) {\n                int drop = rng() % (global_best_lines.size() + 1);\n                int keep = (int)global_best_lines.size() - drop;\n                keep = min(keep, K);\n                base_prefix.insert(base_prefix.end(), global_best_lines.begin(), global_best_lines.begin() + keep);\n            } else {\n                int keep_percent = 55 + (rng() % 36);\n                for (const auto &ln : global_best_lines) {\n                    if ((int)base_prefix.size() >= K) break;\n                    if ((int)(rng() % 100) < keep_percent) base_prefix.push_back(ln);\n                }\n            }\n            if ((int)base_prefix.size() >= K) base_prefix.resize(max(0, K - 1));\n        }\n\n        AttemptResult res = run_attempt(base_prefix);\n        if (res.score > global_best_score) {\n            global_best_score = res.score;\n            global_best_lines = res.lines;\n        }\n        if (check_time()) break;\n    }\n\n    vector<array<long long,4>> output;\n    output.reserve(global_best_lines.size());\n    for (const auto &ln : global_best_lines) {\n        array<long long,4> pts;\n        if (!line_to_points(ln, pts)) {\n            pts = {{-COORD_LIMIT + 1, -COORD_LIMIT + 1, -COORD_LIMIT + 2, -COORD_LIMIT + 1}};\n        }\n        output.push_back(pts);\n    }\n\n    cout << output.size() << '\\n';\n    for (auto &v : output) {\n        cout << v[0] << ' ' << v[1] << ' ' << v[2] << ' ' << v[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    enum Direction : int {\n        DIR_UP = 0, DIR_DOWN = 1, DIR_RIGHT = 2, DIR_LEFT = 3,\n        DIR_NE = 4, DIR_SW = 5, DIR_NW = 6, DIR_SE = 7\n    };\n    static int dirBit(int dir) { return 1 << dir; }\n\n    struct Candidate {\n        array<int, 8> pts{};\n    };\n    struct CandidateScore {\n        Candidate cand;\n        double score = 0.0;\n        double perim = 0.0;\n        int len = 0;\n    };\n    struct NeighborInfo {\n        bool exists = false;\n        bool edgeFree = false;\n        int x = 0;\n        int y = 0;\n    };\n    struct PotentialCounts {\n        double axis = 0.0;\n        double diag = 0.0;\n    };\n    struct DirNeighbor {\n        int x = 0;\n        int y = 0;\n        int dir = -1;\n    };\n    struct RunResult {\n        long long totalWeight = 0;\n        vector<array<int, 8>> ops;\n    };\n    struct Param {\n        double lambdaStart;\n        double lambdaEnd;\n        double progressPower;\n        double noiseAmp;\n        double timeBudget;\n        double alphaAxis;\n        double alphaDiag;\n        int keepLimit;\n        double pickDecay;\n        double frontierCoeff;\n        double frontierDecay;\n    };\n\n    static bool betterCand(const CandidateScore &a, const CandidateScore &b) {\n        if (a.score != b.score) return a.score > b.score;\n        if (a.perim != b.perim) return a.perim < b.perim;\n        if (a.len != b.len) return a.len < b.len;\n        return a.cand.pts < b.cand.pts;\n    }\n    static bool worseCand(const CandidateScore &a, const CandidateScore &b) {\n        return betterCand(b, a);\n    }\n\n    static constexpr double ABS_TIME_LIMIT = 4.95;\n    static constexpr double SAFETY_MARGIN = 0.05;\n\n    int N = 0, M = 0;\n    vector<pair<int, int>> initialDots;\n\n    vector<vector<int>> rowDots, colDots;\n    vector<vector<int>> diagPosDots, diagNegDots;\n    vector<vector<char>> hasDot;\n    vector<vector<char>> usedH, usedV, usedDiagPos, usedDiagNeg;\n    vector<vector<int>> weight;\n    vector<array<int, 8>> currentOperations;\n\n    int center = 0;\n    int diagOffset = 0;\n    int totalCells = 0;\n\n    int dotCount = 0;\n    long long totalWeight = 0;\n    int baseInitialCount = 0;\n    int extraCapacity = 1;\n\n    int bMinX = 0, bMaxX = 0, bMinY = 0, bMaxY = 0;\n\n    chrono::steady_clock::time_point startTime;\n    double currentTimeLimit = ABS_TIME_LIMIT;\n\n    uint64_t baseSeed = 0;\n    mt19937 rng;\n\n    double elapsed() const {\n        using namespace chrono;\n        return duration<double>(steady_clock::now() - startTime).count();\n    }\n\n    pair<int, int> uvToXY(int u, int v) const {\n        int x = (u + v) / 2;\n        int y = (u - v) / 2;\n        return {x, y};\n    }\n\n    void insertSorted(vector<int> &vec, int val) {\n        vec.insert(lower_bound(vec.begin(), vec.end(), val), val);\n    }\n\n    bool addDot(int x, int y) {\n        if (hasDot[x][y]) return false;\n        hasDot[x][y] = 1;\n        insertSorted(rowDots[y], x);\n        insertSorted(colDots[x], y);\n        insertSorted(diagPosDots[x - y + diagOffset], x + y);\n        insertSorted(diagNegDots[x + y], x - y);\n        if (bMinX > bMaxX) {\n            bMinX = bMaxX = x;\n            bMinY = bMaxY = y;\n        } else {\n            bMinX = min(bMinX, x);\n            bMaxX = max(bMaxX, x);\n            bMinY = min(bMinY, y);\n            bMaxY = max(bMaxY, y);\n        }\n        return true;\n    }\n\n    void resetState() {\n        for (auto &row : rowDots) row.clear();\n        for (auto &col : colDots) col.clear();\n        for (auto &diag : diagPosDots) diag.clear();\n        for (auto &diag : diagNegDots) diag.clear();\n        for (auto &row : hasDot) fill(row.begin(), row.end(), 0);\n        for (auto &row : usedH) fill(row.begin(), row.end(), 0);\n        for (auto &row : usedV) fill(row.begin(), row.end(), 0);\n        for (auto &row : usedDiagPos) fill(row.begin(), row.end(), 0);\n        for (auto &row : usedDiagNeg) fill(row.begin(), row.end(), 0);\n        currentOperations.clear();\n        currentOperations.reserve(totalCells);\n\n        dotCount = 0;\n        totalWeight = 0;\n        bMinX = bMinY = N;\n        bMaxX = bMaxY = -1;\n\n        for (auto [x, y] : initialDots) {\n            if (addDot(x, y)) {\n                ++dotCount;\n                totalWeight += weight[x][y];\n            }\n        }\n        if (bMinX > bMaxX) {\n            bMinX = bMinY = 0;\n            bMaxX = bMaxY = N - 1;\n        }\n        baseInitialCount = dotCount;\n        extraCapacity = max(1, totalCells - baseInitialCount);\n    }\n\n    bool horizontalSegmentUnused(int y, int x1, int x2) const {\n        if (x1 == x2) return false;\n        int l = min(x1, x2);\n        int r = max(x1, x2);\n        for (int x = l; x < r; ++x) {\n            if (usedH[y][x]) return false;\n        }\n        return true;\n    }\n\n    bool verticalSegmentUnused(int x, int y1, int y2) const {\n        if (y1 == y2) return false;\n        int l = min(y1, y2);\n        int r = max(y1, y2);\n        for (int y = l; y < r; ++y) {\n            if (usedV[x][y]) return false;\n        }\n        return true;\n    }\n\n    bool diagPosSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return false;\n        if (x2 < x1) return diagPosSegmentsUnused(x2, y2, x1, y1);\n        if ((x2 - x1) != (y2 - y1)) return false;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            if (usedDiagPos[x1 + i][y1 + i]) return false;\n        }\n        return true;\n    }\n\n    bool diagNegSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return false;\n        if (x2 < x1) return diagNegSegmentsUnused(x2, y2, x1, y1);\n        if ((x2 - x1) != -(y2 - y1)) return false;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            int y = y1 - i;\n            if (y <= 0 || y > N - 1) return false;\n            if (usedDiagNeg[x1 + i][y - 1]) return false;\n        }\n        return true;\n    }\n\n    void markHorizontal(int y, int x1, int x2) {\n        if (x1 == x2) return;\n        int l = min(x1, x2);\n        int r = max(x1, x2);\n        for (int x = l; x < r; ++x) usedH[y][x] = 1;\n    }\n\n    void markVertical(int x, int y1, int y2) {\n        if (y1 == y2) return;\n        int l = min(y1, y2);\n        int r = max(y1, y2);\n        for (int y = l; y < r; ++y) usedV[x][y] = 1;\n    }\n\n    void markDiagPos(int x1, int y1, int x2, int y2) {\n        if (x2 < x1) {\n            markDiagPos(x2, y2, x1, y1);\n            return;\n        }\n        if ((x2 - x1) != (y2 - y1)) return;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) usedDiagPos[x1 + i][y1 + i] = 1;\n    }\n\n    void markDiagNeg(int x1, int y1, int x2, int y2) {\n        if (x2 < x1) {\n            markDiagNeg(x2, y2, x1, y1);\n            return;\n               }\n        if ((x2 - x1) != -(y2 - y1)) return;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            int y = y1 - i;\n            if (y > 0) usedDiagNeg[x1 + i][y - 1] = 1;\n        }\n    }\n\n    bool edgeSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return verticalSegmentUnused(x1, y1, y2);\n        if (y1 == y2) return horizontalSegmentUnused(y1, x1, x2);\n        if (x2 - x1 == y2 - y1) return diagPosSegmentsUnused(x1, y1, x2, y2);\n        if (x2 - x1 == -(y2 - y1)) return diagNegSegmentsUnused(x1, y1, x2, y2);\n        return false;\n    }\n\n    void markEdge(int x1, int y1, int x2, int y2) {\n        if (x1 == x2) markVertical(x1, y1, y2);\n        else if (y1 == y2) markHorizontal(y1, x1, x2);\n        else if (x2 - x1 == y2 - y1) markDiagPos(x1, y1, x2, y2);\n        else if (x2 - x1 == -(y2 - y1)) markDiagNeg(x1, y1, x2, y2);\n    }\n\n    bool edgeInteriorClear(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2 && y1 == y2) return false;\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n        int steps = max(abs(dx), abs(dy));\n        if (steps <= 1) return true;\n        int sx = (dx > 0) - (dx < 0);\n        int sy = (dy > 0) - (dy < 0);\n        int cx = x1 + sx;\n        int cy = y1 + sy;\n        for (int i = 1; i < steps; ++i) {\n            if (cx < 0 || cx >= N || cy < 0 || cy >= N) return false;\n            if (hasDot[cx][cy]) return false;\n            cx += sx;\n            cy += sy;\n        }\n        return true;\n    }\n\n    int directionFromTo(int x1, int y1, int x2, int y2) const {\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n        if (dx == 0 && dy == 0) return -1;\n        if (dx == 0) return dy > 0 ? DIR_UP : DIR_DOWN;\n        if (dy == 0) return dx > 0 ? DIR_RIGHT : DIR_LEFT;\n        if (dx == dy) return dx > 0 ? DIR_NE : DIR_SW;\n        if (dx == -dy) return dx > 0 ? DIR_SE : DIR_NW;\n        return -1;\n    }\n\n    PotentialCounts evaluatePotential(int dx, int dy, int blockedMask) const {\n        PotentialCounts result;\n        array<DirNeighbor, 2> verticals{};\n        array<DirNeighbor, 2> horizontals{};\n        array<DirNeighbor, 2> diagPlus{};\n        array<DirNeighbor, 2> diagMinus{};\n        int vCnt = 0, hCnt = 0, dpCnt = 0, dnCnt = 0;\n\n        auto tryAddVertical = [&](int ny, int dir) {\n            if (ny < 0 || ny >= N) return;\n            if (dir < 0) return;\n            if (blockedMask & dirBit(dir)) return;\n            if (!edgeSegmentsUnused(dx, dy, dx, ny)) return;\n            if (!edgeInteriorClear(dx, dy, dx, ny)) return;\n            if (vCnt < 2) verticals[vCnt++] = {dx, ny, dir};\n        };\n        auto tryAddHorizontal = [&](int nx, int dir) {\n            if (nx < 0 || nx >= N) return;\n            if (dir < 0) return;\n            if (blockedMask & dirBit(dir)) return;\n            if (!edgeSegmentsUnused(dx, dy, nx, dy)) return;\n            if (!edgeInteriorClear(dx, dy, nx, dy)) return;\n            if (hCnt < 2) horizontals[hCnt++] = {nx, dy, dir};\n        };\n        auto tryAddDiagPlus = [&](int nx, int ny, int dir) {\n            if (nx < 0 || nx >= N || ny < 0 || ny >= N) return;\n            if (dir < 0) return;\n            if (blockedMask & dirBit(dir)) return;\n            if (!edgeSegmentsUnused(dx, dy, nx, ny)) return;\n            if (!edgeInteriorClear(dx, dy, nx, ny)) return;\n            if (dpCnt < 2) diagPlus[dpCnt++] = {nx, ny, dir};\n        };\n        auto tryAddDiagMinus = [&](int nx, int ny, int dir) {\n            if (nx < 0 || nx >= N || ny < 0 || ny >= N) return;\n            if (dir < 0) return;\n            if (blockedMask & dirBit(dir)) return;\n            if (!edgeSegmentsUnused(dx, dy, nx, ny)) return;\n            if (!edgeInteriorClear(dx, dy, nx, ny)) return;\n            if (dnCnt < 2) diagMinus[dnCnt++] = {nx, ny, dir};\n        };\n\n        const auto &col = colDots[dx];\n        auto itUp = upper_bound(col.begin(), col.end(), dy);\n        if (itUp != col.end()) tryAddVertical(*itUp, DIR_UP);\n        auto itMid = lower_bound(col.begin(), col.end(), dy);\n        if (itMid != col.begin()) {\n            --itMid;\n            tryAddVertical(*itMid, DIR_DOWN);\n        }\n\n        const auto &row = rowDots[dy];\n        auto itRight = upper_bound(row.begin(), row.end(), dx);\n        if (itRight != row.end()) tryAddHorizontal(*itRight, DIR_RIGHT);\n        auto itRowMid = lower_bound(row.begin(), row.end(), dx);\n        if (itRowMid != row.begin()) {\n            --itRowMid;\n            tryAddHorizontal(*itRowMid, DIR_LEFT);\n        }\n\n        const auto &diagP = diagPosDots[dx - dy + diagOffset];\n        auto itDiagPHigh = upper_bound(diagP.begin(), diagP.end(), dx + dy);\n        if (itDiagPHigh != diagP.end()) {\n            auto [nx, ny] = uvToXY(*itDiagPHigh, dx - dy);\n            tryAddDiagPlus(nx, ny, DIR_NE);\n        }\n        auto itDiagPLow = lower_bound(diagP.begin(), diagP.end(), dx + dy);\n        if (itDiagPLow != diagP.begin()) {\n            --itDiagPLow;\n            auto [nx, ny] = uvToXY(*itDiagPLow, dx - dy);\n            tryAddDiagPlus(nx, ny, DIR_SW);\n        }\n\n        const auto &diagN = diagNegDots[dx + dy];\n        auto itDiagNHigh = upper_bound(diagN.begin(), diagN.end(), dx - dy);\n        if (itDiagNHigh != diagN.end()) {\n            auto [nx, ny] = uvToXY(dx + dy, *itDiagNHigh);\n            tryAddDiagMinus(nx, ny, DIR_SE);\n        }\n        auto itDiagNLow = lower_bound(diagN.begin(), diagN.end(), dx - dy);\n        if (itDiagNLow != diagN.begin()) {\n            --itDiagNLow;\n            auto [nx, ny] = uvToXY(dx + dy, *itDiagNLow);\n            tryAddDiagMinus(nx, ny, DIR_NW);\n        }\n\n        for (int i = 0; i < vCnt; ++i) {\n            for (int j = 0; j < hCnt; ++j) {\n                int nx = horizontals[j].x;\n                int ny = verticals[i].y;\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                if (hasDot[nx][ny]) continue;\n                if (!edgeInteriorClear(verticals[i].x, verticals[i].y, nx, ny)) continue;\n                if (!edgeInteriorClear(horizontals[j].x, horizontals[j].y, nx, ny)) continue;\n                if (!edgeSegmentsUnused(verticals[i].x, verticals[i].y, nx, ny)) continue;\n                if (!edgeSegmentsUnused(horizontals[j].x, horizontals[j].y, nx, ny)) continue;\n                result.axis += 1.0;\n            }\n        }\n\n        for (int i = 0; i < dpCnt; ++i) {\n            for (int j = 0; j < dnCnt; ++j) {\n                int nx = diagPlus[i].x + (diagMinus[j].x - dx);\n                int ny = diagPlus[i].y + (diagMinus[j].y - dy);\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                if (hasDot[nx][ny]) continue;\n                if (!edgeInteriorClear(diagPlus[i].x, diagPlus[i].y, nx, ny)) continue;\n                if (!edgeInteriorClear(diagMinus[j].x, diagMinus[j].y, nx, ny)) continue;\n                if (!edgeSegmentsUnused(diagPlus[i].x, diagPlus[i].y, nx, ny)) continue;\n                if (!edgeSegmentsUnused(diagMinus[j].x, diagMinus[j].y, nx, ny)) continue;\n                result.diag += 1.0;\n            }\n        }\n\n        return result;\n    }\n\n    double frontierGain(int x, int y) const {\n        if (bMinX > bMaxX) return 0.0;\n        double gain = 0.0;\n        if (x < bMinX) gain += double(bMinX - x);\n        else if (x > bMaxX) gain += double(x - bMaxX);\n        if (y < bMinY) gain += double(bMinY - y);\n        else if (y > bMaxY) gain += double(y - bMaxY);\n        return gain;\n    }\n\n    bool findCandidate(double lambda, double noiseAmp,\n                       double alphaAxis, double alphaDiag,\n                       double frontierCoef,\n                       int keepLimit, double pickDecay,\n                       Candidate &chosen, bool &timeoutFlag) {\n        keepLimit = max(1, keepLimit);\n        vector<CandidateScore> pool;\n        pool.reserve(keepLimit + 4);\n\n        timeoutFlag = false;\n        bool stop = false;\n        int processed = 0;\n\n        uniform_real_distribution<double> noiseDist(-noiseAmp, noiseAmp);\n        auto noise = [&]() -> double {\n            return (noiseAmp > 0.0) ? noiseDist(rng) : 0.0;\n        };\n\n        auto pushCandidate = [&](const CandidateScore &cs) {\n            if ((int)pool.size() < keepLimit) {\n                pool.push_back(cs);\n            } else {\n                int worst = 0;\n                for (int i = 1; i < (int)pool.size(); ++i) {\n                    if (worseCand(pool[i], pool[worst])) worst = i;\n                }\n                if (!worseCand(cs, pool[worst])) {\n                    pool[worst] = cs;\n                }\n            }\n        };\n\n        for (int y = 0; y < N && !stop; ++y) {\n            const auto &row = rowDots[y];\n            int rowSize = (int)row.size();\n            if (rowSize == 0) continue;\n            for (int idx = 0; idx < rowSize && !stop; ++idx) {\n                if ((processed & 63) == 0 && elapsed() > currentTimeLimit) {\n                    timeoutFlag = true;\n                    stop = true;\n                    break;\n                }\n                ++processed;\n                int ax = row[idx];\n                int ay = y;\n\n                NeighborInfo left, right, up, down, ne, sw, nw, se;\n\n                if (idx > 0) {\n                    left.exists = true;\n                    left.x = row[idx - 1];\n                    left.y = ay;\n                    left.edgeFree = edgeSegmentsUnused(ax, ay, left.x, left.y);\n                }\n                if (idx + 1 < rowSize) {\n                    right.exists = true;\n                    right.x = row[idx + 1];\n                    right.y = ay;\n                    right.edgeFree = edgeSegmentsUnused(ax, ay, right.x, right.y);\n                }\n\n                const auto &col = colDots[ax];\n                auto itCol = lower_bound(col.begin(), col.end(), ay);\n                if (itCol == col.end() || *itCol != ay) continue;\n                int posCol = int(itCol - col.begin());\n                if (posCol > 0) {\n                    down.exists = true;\n                    down.x = ax;\n                    down.y = col[posCol - 1];\n                    down.edgeFree = edgeSegmentsUnused(ax, ay, down.x, down.y);\n                }\n                if (posCol + 1 < (int)col.size()) {\n                    up.exists = true;\n                    up.x = ax;\n                    up.y = col[posCol + 1];\n                    up.edgeFree = edgeSegmentsUnused(ax, ay, up.x, up.y);\n                }\n\n                int uVal = ax + ay;\n                int vVal = ax - ay;\n\n                auto &diagV = diagPosDots[vVal + diagOffset];\n                auto itV = lower_bound(diagV.begin(), diagV.end(), uVal);\n                if (itV != diagV.end() && *itV == uVal) {\n                    int posV = int(itV - diagV.begin());\n                    if (posV > 0) {\n                        int uPrev = diagV[posV - 1];\n                        auto [nx, ny] = uvToXY(uPrev, vVal);\n                        sw.exists = true;\n                        sw.x = nx;\n                        sw.y = ny;\n                        sw.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                    if (posV + 1 < (int)diagV.size()) {\n                        int uNext = diagV[posV + 1];\n                        auto [nx, ny] = uvToXY(uNext, vVal);\n                        ne.exists = true;\n                        ne.x = nx;\n                        ne.y = ny;\n                        ne.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                }\n\n                auto &diagU = diagNegDots[uVal];\n                auto itU = lower_bound(diagU.begin(), diagU.end(), vVal);\n                if (itU != diagU.end() && *itU == vVal) {\n                    int posU = int(itU - diagU.begin());\n                    if (posU > 0) {\n                        int vPrev = diagU[posU - 1];\n                        auto [nx, ny] = uvToXY(uVal, vPrev);\n                        nw.exists = true;\n                        nw.x = nx;\n                        nw.y = ny;\n                        nw.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                    if (posU + 1 < (int)diagU.size()) {\n                        int vNext = diagU[posU + 1];\n                        auto [nx, ny] = uvToXY(uVal, vNext);\n                        se.exists = true;\n                        se.x = nx;\n                        se.y = ny;\n                        se.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                }\n\n                auto considerAxis = [&](const NeighborInfo &vert, const NeighborInfo &horiz) {\n                    if (!vert.exists || !horiz.exists) return;\n                    if (!vert.edgeFree || !horiz.edgeFree) return;\n                    int dx = horiz.x;\n                    int dy = vert.y;\n                    if (dx < 0 || dx >= N || dy < 0 || dy >= N) return;\n                    if (hasDot[dx][dy]) return;\n                    if (!edgeInteriorClear(vert.x, vert.y, dx, dy)) return;\n                    if (!edgeInteriorClear(horiz.x, horiz.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(vert.x, vert.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(horiz.x, horiz.y, dx, dy)) return;\n                    int width = abs(dx - ax);\n                    int height = abs(dy - ay);\n                    if (width <= 0 || height <= 0) return;\n                    double perim = 2.0 * (width + height);\n                    int len = width + height;\n                    int blockedMask = 0;\n                    int dir1 = directionFromTo(dx, dy, vert.x, vert.y);\n                    int dir2 = directionFromTo(dx, dy, horiz.x, horiz.y);\n                    if (dir1 >= 0) blockedMask |= dirBit(dir1);\n                    if (dir2 >= 0) blockedMask |= dirBit(dir2);\n                    PotentialCounts pot = evaluatePotential(dx, dy, blockedMask);\n                    double frontier = frontierCoef > 0.0 ? frontierCoef * frontierGain(dx, dy) : 0.0;\n                    double score = (double)weight[dx][dy]\n                                   + alphaAxis * pot.axis\n                                   + alphaDiag * pot.diag\n                                   + frontier\n                                   - lambda * perim + noise();\n                    Candidate cand{{dx, dy,\n                                    vert.x, vert.y,\n                                    ax, ay,\n                                    horiz.x, horiz.y}};\n                    pushCandidate({cand, score, perim, len});\n                };\n\n                auto considerDiag = [&](const NeighborInfo &diagP, const NeighborInfo &diagN) {\n                    if (!diagP.exists || !diagN.exists) return;\n                    if (!diagP.edgeFree || !diagN.edgeFree) return;\n                    int dx = diagP.x + (diagN.x - ax);\n                    int dy = diagP.y + (diagN.y - ay);\n                    if (dx < 0 || dx >= N || dy < 0 || dy >= N) return;\n                    if (hasDot[dx][dy]) return;\n                    if (!edgeInteriorClear(diagP.x, diagP.y, dx, dy)) return;\n                    if (!edgeInteriorClear(diagN.x, diagN.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(diagP.x, diagP.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(diagN.x, diagN.y, dx, dy)) return;\n                    int len1 = abs(diagP.x - ax);\n                    int len2 = abs(diagN.x - ax);\n                    if (len1 <= 0 || len2 <= 0) return;\n                    double perim = 2.0 * (len1 + len2);\n                    int len = len1 + len2;\n                    int blockedMask = 0;\n                    int dir1 = directionFromTo(dx, dy, diagP.x, diagP.y);\n                    int dir2 = directionFromTo(dx, dy, diagN.x, diagN.y);\n                    if (dir1 >= 0) blockedMask |= dirBit(dir1);\n                    if (dir2 >= 0) blockedMask |= dirBit(dir2);\n                    PotentialCounts pot = evaluatePotential(dx, dy, blockedMask);\n                    double frontier = frontierCoef > 0.0 ? frontierCoef * frontierGain(dx, dy) : 0.0;\n                    double score = (double)weight[dx][dy]\n                                   + alphaAxis * pot.axis\n                                   + alphaDiag * pot.diag\n                                   + frontier\n                                   - lambda * perim + noise();\n                    Candidate cand{{dx, dy,\n                                    diagP.x, diagP.y,\n                                    ax, ay,\n                                    diagN.x, diagN.y}};\n                    pushCandidate({cand, score, perim, len});\n                };\n\n                considerAxis(up, right);\n                considerAxis(up, left);\n                considerAxis(down, right);\n                considerAxis(down, left);\n\n                considerDiag(ne, nw);\n                considerDiag(ne, se);\n                considerDiag(sw, nw);\n                considerDiag(sw, se);\n            }\n        }\n\n        if (pool.empty()) return false;\n        sort(pool.begin(), pool.end(), betterCand);\n\n        double decay = max(0.0, min(1.0, pickDecay));\n        int size = (int)pool.size();\n        int chosenIdx = 0;\n        if (size > 1) {\n            if (decay <= 1e-6) {\n                chosenIdx = 0;\n            } else if (decay >= 0.999999) {\n                chosenIdx = rng() % size;\n            } else {\n                vector<double> prefix(size);\n                double weightAccum = 0.0;\n                double w = 1.0;\n                for (int i = 0; i < size; ++i) {\n                    if (i == 0) w = 1.0;\n                    else w *= decay;\n                    weightAccum += w;\n                    prefix[i] = weightAccum;\n                    if (w < 1e-18) {\n                        for (int j = i + 1; j < size; ++j) prefix[j] = weightAccum;\n                        break;\n                    }\n                }\n                uniform_real_distribution<double> dist(0.0, weightAccum);\n                double r = dist(rng);\n                chosenIdx = lower_bound(prefix.begin(), prefix.end(), r) - prefix.begin();\n                if (chosenIdx >= size) chosenIdx = size - 1;\n            }\n        }\n        chosen = pool[chosenIdx].cand;\n        return true;\n    }\n\n    void applyCandidate(const Candidate &cand) {\n        const auto &pts = cand.pts;\n        for (int i = 0; i < 4; ++i) {\n            int j = (i + 1) & 3;\n            markEdge(pts[2 * i], pts[2 * i + 1], pts[2 * j], pts[2 * j + 1]);\n        }\n        int dx = pts[0], dy = pts[1];\n        if (addDot(dx, dy)) {\n            ++dotCount;\n            totalWeight += weight[dx][dy];\n        }\n        currentOperations.push_back(pts);\n    }\n\n    RunResult runOne(const Param &param, double budget, uint64_t seedShift) {\n        resetState();\n        rng.seed(baseSeed + seedShift * 0x9e3779b97f4a7c15ULL + 0x7f4a7c15ULL);\n\n        double now = elapsed();\n        currentTimeLimit = min(ABS_TIME_LIMIT, now + max(0.0, budget));\n\n        while (true) {\n            double cur = elapsed();\n            if (cur > currentTimeLimit) break;\n            int gained = dotCount - baseInitialCount;\n            if (gained < 0) gained = 0;\n            double progress = (double)gained / (double)extraCapacity;\n            progress = min(1.0, max(0.0, progress));\n            double factor = (param.progressPower == 1.0)\n                                ? progress\n                                : pow(progress, param.progressPower);\n            double lambda = param.lambdaStart +\n                            (param.lambdaEnd - param.lambdaStart) * factor;\n            double noiseScale = max(0.0, 1.0 - 0.75 * progress);\n            double noiseAmp = param.noiseAmp * noiseScale;\n            double axisCoef = param.alphaAxis * (1.0 - 0.35 * progress);\n            double diagCoef = param.alphaDiag * (1.0 - 0.25 * progress);\n            axisCoef = max(axisCoef, param.alphaAxis * 0.3);\n            diagCoef = max(diagCoef, param.alphaDiag * 0.3);\n            double frontierCoef = param.frontierCoeff * max(0.0, 1.0 - param.frontierDecay * progress);\n            frontierCoef = max(frontierCoef, param.frontierCoeff * 0.2);\n\n            Candidate cand;\n            bool timeout = false;\n            if (!findCandidate(lambda, noiseAmp, axisCoef, diagCoef, frontierCoef,\n                               param.keepLimit, param.pickDecay,\n                               cand, timeout)) break;\n            applyCandidate(cand);\n            if (timeout) break;\n        }\n\n        RunResult res;\n        res.totalWeight = totalWeight;\n        res.ops = currentOperations;\n        return res;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M)) return;\n        initialDots.resize(M);\n        for (int i = 0; i < M; ++i) cin >> initialDots[i].first >> initialDots[i].second;\n\n        center = (N - 1) / 2;\n        diagOffset = N - 1;\n        totalCells = N * N;\n\n        weight.assign(N, vector<int>(N, 0));\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                int dx = x - center;\n                int dy = y - center;\n                weight[x][y] = dx * dx + dy * dy + 1;\n            }\n        }\n\n        rowDots.assign(N, {});\n        colDots.assign(N, {});\n        diagPosDots.assign(2 * N, {});\n        diagNegDots.assign(2 * N, {});\n        hasDot.assign(N, vector<char>(N, 0));\n        int seg = max(1, N - 1);\n        usedH.assign(N, vector<char>(seg, 0));\n        usedV.assign(N, vector<char>(seg, 0));\n        usedDiagPos.assign(seg, vector<char>(seg, 0));\n        usedDiagNeg.assign(seg, vector<char>(seg, 0));\n        currentOperations.reserve(totalCells);\n\n        baseSeed = 1469598103934665603ULL;\n        baseSeed ^= (uint64_t)(N + 0x9e3779b97f4a7c15ULL + (baseSeed << 6) + (baseSeed >> 2));\n        baseSeed ^= (uint64_t)(M + 0x9e3779b97f4a7c15ULL + (baseSeed << 6) + (baseSeed >> 2));\n        for (auto [x, y] : initialDots) {\n            uint64_t v = (uint64_t)(x + 1) * 1000003ULL + (uint64_t)(y + 1) * 998244353ULL;\n            baseSeed ^= v + 0x9e3779b97f4a7c15ULL + (baseSeed << 6) + (baseSeed >> 2);\n        }\n\n        startTime = chrono::steady_clock::now();\n\n        vector<Param> params = {\n            {52.0,  -8.0, 0.60, 0.90, 0.90,  80.0, 65.0, 52, 0.45, 48.0, 0.80},\n            {34.0, -36.0, 1.08, 1.70, 0.85,  62.0, 78.0, 60, 0.58, 55.0, 1.10},\n            {82.0,  12.0, 0.42, 0.45, 1.00, 110.0, 90.0, 42, 0.32, 38.0, 0.60},\n            {70.0, -22.0, 0.95, 0.38, 0.80,  68.0, 52.0, 64, 0.28, 60.0, 0.90},\n            {46.0, -24.0, 1.25, 2.10, 0.70,  58.0, 58.0, 38, 0.78, 45.0, 1.25},\n        };\n\n        vector<array<int, 8>> bestOps;\n        long long bestWeight = -1;\n        bool ran = false;\n\n        for (int idx = 0; idx < (int)params.size(); ++idx) {\n            double now = elapsed();\n            double timeLeft = ABS_TIME_LIMIT - now;\n            if (timeLeft <= SAFETY_MARGIN) break;\n            double available = max(0.0, timeLeft - SAFETY_MARGIN);\n            double budget = min(params[idx].timeBudget, available);\n            if (budget <= 0.02) break;\n            RunResult res = runOne(params[idx], budget, idx + 1);\n            ran = true;\n            if (res.totalWeight > bestWeight) {\n                bestWeight = res.totalWeight;\n                bestOps = move(res.ops);\n            }\n        }\n\n        if (!ran) {\n            double now = elapsed();\n            double left = max(0.02, ABS_TIME_LIMIT - now - 0.01);\n            RunResult res = runOne(params.front(), left, params.size() + 5);\n            bestOps = move(res.ops);\n        }\n\n        cout << bestOps.size() << '\\n';\n        for (auto &op : bestOps) {\n            for (int i = 0; i < 8; ++i) {\n                if (i) cout << ' ';\n                cout << op[i];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct MinCostFlow {\n    struct Edge { int to, rev, cap, cost; };\n    int N;\n    vector<vector<Edge>> graph;\n    MinCostFlow(int n = 0) : N(n), graph(n) {}\n    void add_edge(int fr, int to, int cap, int cost) {\n        Edge f{to, (int)graph[to].size(), cap, cost};\n        Edge b{fr, (int)graph[fr].size(), 0, -cost};\n        graph[fr].push_back(f);\n        graph[to].push_back(b);\n    }\n    pair<int,long long> min_cost_flow(int s, int t, int maxf) {\n        const long long INF = (1LL<<60);\n        vector<long long> potential(N,0), dist(N);\n        vector<int> prevv(N), preve(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            priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n            pq.emplace(0LL,s);\n            while(!pq.empty()){\n                auto [d,v]=pq.top(); pq.pop();\n                if(dist[v]<d) continue;\n                for(int i=0;i<(int)graph[v].size();++i){\n                    const Edge &e=graph[v][i];\n                    if(e.cap<=0) continue;\n                    long long nd=dist[v]+e.cost+potential[v]-potential[e.to];\n                    if(nd<dist[e.to]){\n                        dist[e.to]=nd;\n                        prevv[e.to]=v;\n                        preve[e.to]=i;\n                        pq.emplace(nd,e.to);\n                    }\n                }\n            }\n            if(dist[t]==INF) break;\n            for(int v=0;v<N;++v) if(dist[v]<INF) potential[v]+=dist[v];\n            int d=maxf-flow;\n            for(int v=t;v!=s;v=prevv[v]) d=min(d,graph[prevv[v]][preve[v]].cap);\n            flow+=d;\n            cost+=1LL*d*potential[t];\n            for(int v=t;v!=s;v=prevv[v]){\n                Edge &e=graph[prevv[v]][preve[v]];\n                e.cap-=d;\n                graph[v][e.rev].cap+=d;\n            }\n        }\n        return {flow,cost};\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 10;\n    using Grid = array<array<uint8_t,N>,N>;\n    using ZoneGrid = array<array<int8_t,N>,N>;\n    static constexpr char DIRS[4] = {'F','B','L','R'};\n    static constexpr double ZONE_ALPHA = 0.35;\n    static constexpr double W_COMPONENT = 1.0;\n    static constexpr double W_ADJ_SAME = 18.0;\n    static constexpr double W_ADJ_DIFF = 13.0;\n    static constexpr double W_ZONE = 60.0;\n    static constexpr double W_LARGEST = 12.0;\n    static constexpr double W_COMP_COUNT = 20.0;\n    static constexpr double W_ZONE_HIT = 6.0;\n    static constexpr double W_ZONE_DIST = 1.0;\n    static constexpr double LOOKAHEAD_WEIGHT = 0.35;\n    static constexpr double REVERSE_PENALTY = 0.35;\n    static constexpr int FULL_LOOKAHEAD_THRESHOLD = 36;\n\n    vector<int> flavors = vector<int>(100);\n    array<int,3> totalCounts{};\n    Grid board{};\n    int placed = 0;\n    mt19937 rng;\n    ZoneGrid targetZone{};\n    array<array<array<uint8_t,N>,N>,3> zoneDistance{};\n    array<int,3> zoneCellCount{};\n    array<pair<int,int>,N*N> cellOrder{};\n    bool hasLastMove=false;\n    char lastMove='F';\n\n    Solver(){\n        for(int idx=0;idx<N*N;++idx) cellOrder[idx]={idx/N,idx%N};\n    }\n\n    bool readInput(){\n        totalCounts.fill(0);\n        for(int i=0;i<100;++i){\n            if(!(cin>>flavors[i])) return false;\n            if(1<=flavors[i] && flavors[i]<=3) totalCounts[flavors[i]-1]++;\n        }\n        uint32_t seed=712387u;\n        for(int i=0;i<100;++i){\n            seed=seed*1000003u + (uint32_t)flavors[i]*239017u + i;\n        }\n        rng.seed(seed);\n        computeZones();\n        return true;\n    }\n\n    void solve(){\n        for(auto &row:board) row.fill(0);\n        placed=0;\n        hasLastMove=false;\n        for(int t=0;t<100;++t){\n            int p;\n            if(!(cin>>p)) return;\n            placeCandy(p,flavors[t]);\n            ++placed;\n            auto dec = chooseMove(placed);\n            board = dec.board;\n            lastMove = dec.dir;\n            hasLastMove = true;\n            cout << dec.dir << '\\n' << flush;\n        }\n    }\n\n    void placeCandy(int idx,int flavor){\n        int target = idx;\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c)\n                if(board[r][c]==0 && --target==0){\n                    board[r][c]=uint8_t(flavor);\n                    return;\n                }\n    }\n\n    void applyTilt(Grid &g,char dir) const{\n        if(dir=='F'){\n            for(int c=0;c<N;++c){\n                array<uint8_t,N> tmp{};\n                int k=0;\n                for(int r=0;r<N;++r) if(g[r][c]) tmp[k++]=g[r][c];\n                for(int r=0;r<N;++r) g[r][c]=(r<k?tmp[r]:0);\n            }\n        }else if(dir=='B'){\n            for(int c=0;c<N;++c){\n                array<uint8_t,N> tmp{};\n                int k=0;\n                for(int r=0;r<N;++r) if(g[r][c]) tmp[k++]=g[r][c];\n                int idx=k-1;\n                for(int r=N-1;r>=0;--r) g[r][c]=(idx>=0?tmp[idx--]:0);\n            }\n        }else if(dir=='L'){\n            for(int r=0;r<N;++r){\n                array<uint8_t,N> tmp{};\n                int k=0;\n                for(int c=0;c<N;++c) if(g[r][c]) tmp[k++]=g[r][c];\n                for(int c=0;c<N;++c) g[r][c]=(c<k?tmp[c]:0);\n            }\n        }else{\n            for(int r=0;r<N;++r){\n                array<uint8_t,N> tmp{};\n                int k=0;\n                for(int c=0;c<N;++c) if(g[r][c]) tmp[k++]=g[r][c];\n                int idx=k-1;\n                for(int c=N-1;c>=0;--c) g[r][c]=(idx>=0?tmp[idx--]:0);\n            }\n        }\n    }\n\n    struct Decision { char dir='F'; Grid board{}; };\n\n    Decision chooseMove(int filled){\n        Decision best;\n        double bestScore=-1e100;\n        bool first=true;\n        for(char dir:DIRS){\n            Grid cand=board;\n            applyTilt(cand,dir);\n            double score=evaluateWithLookahead(cand,filled);\n            if(hasLastMove && isOpposite(dir,lastMove)) score -= REVERSE_PENALTY;\n            score += randomNoise();\n            if(first || score>bestScore){\n                first=false;\n                bestScore=score;\n                best.dir=dir;\n                best.board=cand;\n            }\n        }\n        return best;\n    }\n\n    bool isOpposite(char a,char b) const{\n        return (a=='F'&&b=='B')||(a=='B'&&b=='F')||(a=='L'&&b=='R')||(a=='R'&&b=='L');\n    }\n\n    double evaluateWithLookahead(const Grid &state,int filled){\n        double base = evaluate(state,filled);\n        if(filled>=100 || LOOKAHEAD_WEIGHT<=1e-9) return base;\n        int nextIdx = filled;\n        if(nextIdx >= (int)flavors.size()) return base;\n\n        vector<int> empties;\n        empties.reserve(N*N);\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c)\n                if(!state[r][c]) empties.push_back(r*N+c);\n        if(empties.empty()) return base;\n\n        int emptiesSz = (int)empties.size();\n        bool useAll = (emptiesSz <= FULL_LOOKAHEAD_THRESHOLD);\n        int sampleCount;\n        if(useAll){\n            sampleCount = emptiesSz;\n        }else{\n            int limit = getSampleLimit(filled);\n            sampleCount = min(limit, emptiesSz);\n            for(int i=0;i<sampleCount;++i){\n                int span = emptiesSz - i;\n                int j = i + (int)(rng() % span);\n                swap(empties[i], empties[j]);\n            }\n        }\n\n        int nextFlavor = flavors[nextIdx];\n        double accum = 0.0;\n        for(int i=0;i<sampleCount;++i){\n            int idx = empties[i];\n            int r = idx / N, c = idx % N;\n            Grid tmp = state;\n            tmp[r][c] = (uint8_t)nextFlavor;\n            double bestNext = -1e100;\n            for(char dir:DIRS){\n                Grid fut = tmp;\n                applyTilt(fut,dir);\n                bestNext = max(bestNext, evaluate(fut,filled+1));\n            }\n            accum += bestNext;\n        }\n        double avg = accum / sampleCount;\n\n        double fillRatio = (double)filled / 100.0;\n        double adapt = 0.35 + 0.65 * (1.0 - fillRatio);\n        double coverage = useAll ? 1.0 : (double)sampleCount / emptiesSz;\n        double coverageFactor = sqrt(max(1e-9, coverage));\n        double lookFactor = LOOKAHEAD_WEIGHT * adapt * coverageFactor;\n        lookFactor = min(0.5, lookFactor);\n\n        return base*(1.0-lookFactor) + avg*lookFactor;\n    }\n\n    int getSampleLimit(int filled) const {\n        if(filled < 25) return 30;\n        if(filled < 50) return 20;\n        if(filled < 75) return 14;\n        if(filled < 90) return 10;\n        return 8;\n    }\n\n    double evaluate(const Grid &g, int filled) const{\n        array<int,3> cnt{};\n        array<double,3> sumR{}, sumC{};\n        array<int,3> zoneHitCnt{};\n        array<double,3> zoneDist{};\n        double sameAdj=0, diffAdj=0;\n\n        for(int r=0;r<N;++r){\n            for(int c=0;c<N;++c){\n                int val=g[r][c];\n                if(!val) continue;\n                int idx=val-1;\n                cnt[idx]++;\n                sumR[idx]+=r;\n                sumC[idx]+=c;\n                if(targetZone[r][c]==idx) zoneHitCnt[idx]++;\n                zoneDist[idx]+=zoneDistance[idx][r][c];\n                if(r+1<N && g[r+1][c]){\n                    if(g[r+1][c]==val) sameAdj += 1.0;\n                    else diffAdj += 1.0;\n                }\n                if(c+1<N && g[r][c+1]){\n                    if(g[r][c+1]==val) sameAdj += 1.0;\n                    else diffAdj += 1.0;\n                }\n            }\n        }\n\n        array<double,3> meanR{}, meanC{};\n        for(int i=0;i<3;++i) if(cnt[i]){\n            meanR[i]=sumR[i]/cnt[i];\n            meanC[i]=sumC[i]/cnt[i];\n        }\n\n        double centroidScore=0.0;\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c){\n                int val=g[r][c];\n                if(!val) continue;\n                int idx=val-1;\n                double dr=r-meanR[idx], dc=c-meanC[idx];\n                centroidScore += 1.0 / (1.0 + ZONE_ALPHA*(dr*dr+dc*dc));\n            }\n\n        array<array<uint8_t,N>,N> vis{};\n        array<int,3> compCounts{};\n        array<int,3> largest{};\n        double compScore=0.0;\n        const int dr4[4]={-1,1,0,0};\n        const int dc4[4]={0,0,-1,1};\n        for(int r=0;r<N;++r){\n            for(int c=0;c<N;++c){\n                if(!g[r][c] || vis[r][c]) continue;\n                int color=g[r][c];\n                queue<pair<int,int>> q;\n                q.emplace(r,c);\n                vis[r][c]=1;\n                int sz=0;\n                while(!q.empty()){\n                    auto [cr,cc]=q.front(); q.pop();\n                    ++sz;\n                    for(int d=0;d<4;++d){\n                        int nr=cr+dr4[d], nc=cc+dc4[d];\n                        if(nr<0||nr>=N||nc<0||nc>=N) continue;\n                        if(vis[nr][nc] || g[nr][nc]!=color) continue;\n                        vis[nr][nc]=1;\n                        q.emplace(nr,nc);\n                    }\n                }\n                compScore += 1.0 * sz * sz;\n                int idx=color-1;\n                compCounts[idx]++;\n                largest[idx]=max(largest[idx],sz);\n            }\n        }\n\n        int compCountSum = compCounts[0] + compCounts[1] + compCounts[2];\n        int largestSum = largest[0] + largest[1] + largest[2];\n        double fillRatio = (double)filled / 100.0;\n\n        double zoneWeight = W_ZONE * (0.4 + 0.6*(1.0 - fillRatio));\n        double adjFactor = 0.4 + 0.6*fillRatio;\n        double adjSameWeight = W_ADJ_SAME * adjFactor;\n        double adjDiffWeight = W_ADJ_DIFF * adjFactor;\n        double compCountWeight = W_COMP_COUNT * fillRatio * fillRatio;\n        double zoneHitBase = W_ZONE_HIT * (0.55 + 0.45*(1.0 - fillRatio));\n        double zoneDistBase = W_ZONE_DIST * (0.5 + 0.5*fillRatio);\n\n        double zoneHitVal=0.0, zoneDistVal=0.0;\n        for(int i=0;i<3;++i){\n            if(cnt[i]==0) continue;\n            double insideRatio = (double)zoneHitCnt[i] / cnt[i];\n            double factor = 0.4 + 0.6 * (1.0 - insideRatio);\n            zoneHitVal += factor * zoneHitCnt[i];\n            zoneDistVal += factor * zoneDist[i];\n        }\n\n        double score = W_COMPONENT*compScore\n                     + adjSameWeight*sameAdj\n                     - adjDiffWeight*diffAdj\n                     + zoneWeight*centroidScore\n                     + W_LARGEST*largestSum\n                     - compCountWeight*compCountSum\n                     + zoneHitBase*zoneHitVal\n                     - zoneDistBase*zoneDistVal;\n\n        return score;\n    }\n\n    double randomNoise(){\n        return (double(rng() & 0xffffu)/65535.0 - 0.5) * 1e-3;\n    }\n\n    void computeZones(){\n        ZoneGrid zone{};\n        if(!buildBestZone(zone)) fallbackZone(zone);\n        targetZone = zone;\n        zoneCellCount.fill(0);\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c)\n                zoneCellCount[targetZone[r][c]]++;\n        computeZoneDistances();\n    }\n\n    bool buildBestZone(ZoneGrid &outZone){\n        vector<array<pair<int,int>,3>> anchorSets;\n        auto addSet=[&](initializer_list<pair<int,int>> pts){\n            if(pts.size()!=3) return;\n            array<pair<int,int>,3> arr{};\n            int idx=0;\n            for(auto pt:pts) arr[idx++]=pt;\n            anchorSets.push_back(arr);\n        };\n        addSet({{1,1},{1,8},{7,4}});\n        addSet({{1,1},{8,1},{4,8}});\n        addSet({{1,8},{8,8},{4,1}});\n        addSet({{8,1},{8,8},{1,4}});\n        addSet({{0,0},{9,0},{4,9}});\n        addSet({{0,0},{0,9},{9,4}});\n        addSet({{0,4},{9,4},{4,9}});\n        addSet({{4,0},{4,9},{8,5}});\n        addSet({{2,2},{2,7},{7,5}});\n        addSet({{2,2},{7,2},{5,7}});\n        addSet({{1,1},{8,8},{5,5}});\n        addSet({{8,1},{1,8},{5,5}});\n        addSet({{0,0},{9,9},{4,5}});\n        addSet({{0,9},{9,0},{5,4}});\n        addSet({{2,2},{7,7},{4,4}});\n        for(int i=0;i<80;++i){\n            array<pair<int,int>,3> arr{};\n            for(int k=0;k<3;++k) arr[k]={int(rng()%N), int(rng()%N)};\n            anchorSets.push_back(arr);\n        }\n\n        bool success=false;\n        long long bestCost=(1LL<<60);\n        ZoneGrid bestZone{};\n        for(const auto &set:anchorSets){\n            array<int,3> perm={0,1,2};\n            do{\n                array<pair<int,int>,3> anchors{};\n                for(int i=0;i<3;++i) anchors[perm[i]] = set[i];\n                ZoneGrid cand{};\n                long long cost;\n                if(!buildZoneForAnchors(anchors,cand,cost)) continue;\n                if(!success || cost<bestCost){\n                    success=true;\n                    bestCost=cost;\n                    bestZone=cand;\n                }\n            }while(next_permutation(perm.begin(),perm.end()));\n        }\n        if(success) outZone=bestZone;\n        return success;\n    }\n\n    bool buildZoneForAnchors(const array<pair<int,int>,3> &anchors,\n                             ZoneGrid &outZone,long long &outCost){\n        const int totalCells=N*N;\n        const int SRC=0;\n        const int COLOR_BASE=1;\n        const int CELL_BASE=COLOR_BASE+3;\n        const int SINK=CELL_BASE+totalCells;\n        MinCostFlow mcf(SINK+1);\n        vector<vector<int>> edgeIndex(3, vector<int>(totalCells,-1));\n\n        int totalCandy = totalCounts[0]+totalCounts[1]+totalCounts[2];\n        if(totalCandy==0) return false;\n\n        for(int color=0;color<3;++color){\n            mcf.add_edge(SRC,COLOR_BASE+color,totalCounts[color],0);\n        }\n        for(int color=0;color<3;++color){\n            if(totalCounts[color]==0) continue;\n            auto [ar,ac]=anchors[color];\n            ar = clamp(ar,0,N-1);\n            ac = clamp(ac,0,N-1);\n            int node = COLOR_BASE+color;\n            for(int idx=0;idx<totalCells;++idx){\n                auto [r,c]=cellOrder[idx];\n                int cost = abs(r-ar)+abs(c-ac);\n                int pos = (int)mcf.graph[node].size();\n                mcf.add_edge(node,CELL_BASE+idx,1,cost);\n                edgeIndex[color][idx]=pos;\n            }\n        }\n        for(int idx=0;idx<totalCells;++idx)\n            mcf.add_edge(CELL_BASE+idx,SINK,1,0);\n\n        auto res = mcf.min_cost_flow(SRC,SINK,totalCandy);\n        if(res.first != totalCandy) return false;\n        outCost = res.second;\n\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c)\n                outZone[r][c]=0;\n\n        for(int idx=0;idx<totalCells;++idx){\n            int assigned=-1;\n            for(int color=0;color<3;++color){\n                int pos=edgeIndex[color][idx];\n                if(pos==-1) continue;\n                if(mcf.graph[COLOR_BASE+color][pos].cap==0){\n                    assigned=color;\n                    break;\n                }\n            }\n            if(assigned==-1) assigned=0;\n            auto [r,c]=cellOrder[idx];\n            outZone[r][c]=(int8_t)assigned;\n        }\n        return true;\n    }\n\n    void fallbackZone(ZoneGrid &zone){\n        array<int,3> remaining=totalCounts;\n        int color=0;\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c){\n                while(color<3 && remaining[color]==0) ++color;\n                if(color>=3) color=2;\n                zone[r][c]=(int8_t)color;\n                if(remaining[color]>0) --remaining[color];\n            }\n    }\n\n    void computeZoneDistances(){\n        const int INF=1e9;\n        for(int color=0;color<3;++color){\n            if(zoneCellCount[color]==0){\n                for(int r=0;r<N;++r)\n                    for(int c=0;c<N;++c)\n                        zoneDistance[color][r][c]=0;\n                continue;\n            }\n            array<array<int,N>,N> dist;\n            for(int r=0;r<N;++r)\n                for(int c=0;c<N;++c)\n                    dist[r][c]=INF;\n            queue<pair<int,int>> q;\n            for(int r=0;r<N;++r)\n                for(int c=0;c<N;++c)\n                    if(targetZone[r][c]==color){\n                        dist[r][c]=0;\n                        q.emplace(r,c);\n                    }\n            while(!q.empty()){\n                auto [r,c]=q.front(); q.pop();\n                const int dr4[4]={-1,1,0,0};\n                const int dc4[4]={0,0,-1,1};\n                for(int d=0;d<4;++d){\n                    int nr=r+dr4[d], nc=c+dc4[d];\n                    if(nr<0||nr>=N||nc<0||nc>=N) continue;\n                    if(dist[nr][nc]>dist[r][c]+1){\n                        dist[nr][nc]=dist[r][c]+1;\n                        q.emplace(nr,nc);\n                    }\n                }\n            }\n            for(int r=0;r<N;++r)\n                for(int c=0;c<N;++c){\n                    int d=dist[r][c];\n                    if(d==INF) d=250;\n                    if(d>250) d=250;\n                    zoneDistance[color][r][c]=(uint8_t)d;\n                }\n        }\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver solver;\n    if(!solver.readInput()) return 0;\n    solver.solve();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Hungarian {\n    int n;\n    vector<vector<int>> cost;\n    vector<int> assignment;\n    Hungarian(int n=0){ init(n); }\n    void init(int m){\n        n=m;\n        cost.assign(n, vector<int>(n,0));\n        assignment.assign(n,-1);\n    }\n    void solve(){\n        const int INF=1e9;\n        vector<int> u(n+1,0), v(n+1,0), p(n+1,0), way(n+1,0);\n        for(int i=1;i<=n;i++){\n            p[0]=i;\n            vector<int> minv(n+1, INF);\n            vector<char> used(n+1,false);\n            int j0=0;\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> ans(n,-1);\n        for(int j=1;j<=n;j++) if(p[j]>0) ans[p[j]-1]=j-1;\n        assignment=ans;\n    }\n};\n\nstruct Designer {\n    static constexpr int N=60;\n    static constexpr int A=32;\n    static constexpr int P=N-A;\n    int M;\n    double eps;\n    int payloadEdges=P*(P-1)/2;\n    int payloadWords=(payloadEdges+63)/64;\n    vector<vector<int>> anchorAdj;\n    vector<uint64_t> anchorAdjMask;\n    vector<uint64_t> payloadAnchorMask;\n    vector<int> degAA_can, degAP_can;\n    vector<vector<uint64_t>> graphCodes;\n    vector<pair<int,int>> payloadPairs;\n    vector<vector<int>> payloadPairIdx;\n    mt19937_64 rng;\n    uint64_t seedBase=0;\n    Designer(){\n        payloadPairIdx.assign(P, vector<int>(P,-1));\n        int idx=0;\n        for(int i=0;i<P;i++){\n            for(int j=i+1;j<P;j++){\n                payloadPairIdx[i][j]=idx++;\n                payloadPairs.emplace_back(i,j);\n            }\n        }\n    }\n    void generateAnchorAdj(double prob=0.82){\n        anchorAdj.assign(A, vector<int>(A,0));\n        anchorAdjMask.assign(A,0);\n        uniform_real_distribution<double> dist(0.0,1.0);\n        for(int i=0;i<A;i++){\n            for(int j=i+1;j<A;j++){\n                bool edge=dist(rng)<prob;\n                anchorAdj[i][j]=anchorAdj[j][i]=edge?1:0;\n            }\n        }\n        degAA_can.assign(A,0);\n        for(int i=0;i<A;i++){\n            uint64_t mask=0;\n            int cnt=0;\n            for(int j=0;j<A;j++){\n                if(anchorAdj[i][j]){\n                    mask|=(1ULL<<j);\n                    cnt++;\n                }\n            }\n            anchorAdjMask[i]=mask;\n            degAA_can[i]=cnt;\n        }\n    }\n    void generatePayloadRows(int minWeight=10,int maxWeight=22,int minDist=8){\n        payloadAnchorMask.clear();\n        int attempts=0;\n        const int limit=30000;\n        while((int)payloadAnchorMask.size()<P){\n            uint64_t mask=rng() & ((1ULL<<A)-1ULL);\n            int w=__builtin_popcountll(mask);\n            if(w<minWeight || w>maxWeight){ attempts++; }\n            else{\n                bool ok=true;\n                for(auto prev: payloadAnchorMask){\n                    if(__builtin_popcountll(mask ^ prev) < minDist){\n                        ok=false; break;\n                    }\n                }\n                if(ok) payloadAnchorMask.push_back(mask);\n                else attempts++;\n            }\n            if(attempts>limit){\n                if(minDist>5) minDist--;\n                else if(minWeight>6) minWeight--;\n                attempts=0;\n            }\n        }\n        degAP_can.assign(A,0);\n        for(int i=0;i<A;i++){\n            int cnt=0;\n            for(auto mask: payloadAnchorMask)\n                if((mask>>i)&1ULL) cnt++;\n            degAP_can[i]=cnt;\n        }\n    }\n    vector<uint64_t> randomPayloadBits(){\n        vector<uint64_t> bits(payloadWords,0);\n        for(auto &w: bits) w=rng();\n        if(payloadEdges%64) bits.back() &= (1ULL<<(payloadEdges%64))-1ULL;\n        return bits;\n    }\n    int hamming(const vector<uint64_t>&a,const vector<uint64_t>&b) const{\n        int s=0;\n        for(size_t i=0;i<a.size();i++) s+=__builtin_popcountll(a[i]^b[i]);\n        return s;\n    }\n    void generateGraphCodes(int M,int baseDist){\n        graphCodes.clear();\n        int curDist=min(baseDist,payloadEdges);\n        int minDist=min(max(70,baseDist-25),payloadEdges);\n        int attempts=0;\n        const int limit=50000;\n        while((int)graphCodes.size()<M){\n            auto cand=randomPayloadBits();\n            bool ok=true;\n            for(auto &ex: graphCodes){\n                if(hamming(cand,ex)<curDist){ ok=false; break; }\n            }\n            if(ok){\n                graphCodes.push_back(move(cand));\n            }else{\n                attempts++;\n                if(attempts>limit && curDist>minDist){\n                    curDist--;\n                    attempts=0;\n                }\n            }\n        }\n    }\n    void build(int M_, double eps_){\n        M=M_;\n        eps=eps_;\n        int epsInt = (int)round(eps*100 + 1e-9);\n        seedBase = 1234567ULL + 10007ULL*M + 7919ULL*epsInt;\n        rng.seed(seedBase);\n        generateAnchorAdj();\n        generatePayloadRows();\n        int baseDist = 110 + epsInt/4;\n        generateGraphCodes(M, baseDist);\n    }\n    string graphString(int idx){\n        string s;\n        s.reserve(N*(N-1)/2);\n        auto &code=graphCodes[idx];\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                bool val=false;\n                if(i<A && j<A) val=anchorAdj[i][j];\n                else if(i<A && j>=A){\n                    int p=j-A;\n                    val=((payloadAnchorMask[p]>>i)&1ULL);\n                }else{\n                    int u=i-A, v=j-A;\n                    int bitIdx=payloadPairIdx[u][v];\n                    val=(code[bitIdx>>6]>>(bitIdx&63))&1ULL;\n                }\n                s.push_back(val?'1':'0');\n            }\n        }\n        return s;\n    }\n};\n\nstruct Decoder {\n    Designer *des;\n    mt19937 rng;\n    Decoder(Designer* d): des(d){\n        rng.seed(des->seedBase ^ 0x9e3779b97f4a7c15ULL);\n    }\n    vector<uint64_t> parse(const string& s){\n        vector<uint64_t> adj(Designer::N,0);\n        int pos=0;\n        for(int i=0;i<Designer::N;i++){\n            for(int j=i+1;j<Designer::N;j++){\n                if(s[pos++]=='1'){\n                    adj[i] |= (1ULL<<j);\n                    adj[j] |= (1ULL<<i);\n                }\n            }\n        }\n        return adj;\n    }\n    vector<int> improveAnchors(vector<int> set, const vector<uint64_t>&adj){\n        int N=Designer::N,A=Designer::A;\n        if((int)set.size()!=A){\n            set.resize(A);\n            iota(set.begin(), set.end(), 0);\n        }\n        auto recompute=[&](const vector<int>&curr){\n            vector<int> deg(N,0);\n            for(int v=0; v<N; ++v){\n                int cnt=0;\n                for(int u: curr){\n                    if(u==v) continue;\n                    if((adj[v]>>u)&1ULL) cnt++;\n                }\n                deg[v]=cnt;\n            }\n            return deg;\n        };\n        vector<int> degIn=recompute(set);\n        vector<char> in(N,false);\n        for(int v:set) in[v]=true;\n        for(int iter=0; iter<6; ++iter){\n            int bestDelta=0, bestU=-1, bestV=-1;\n            for(int u: set){\n                for(int v=0; v<N; ++v){\n                    if(in[v]) continue;\n                    bool edge=(adj[u]>>v)&1ULL;\n                    int delta=(degIn[v] - (edge?1:0)) - degIn[u];\n                    if(delta>bestDelta){\n                        bestDelta=delta; bestU=u; bestV=v;\n                    }\n                }\n            }\n            if(bestDelta<=0) break;\n            in[bestU]=false; in[bestV]=true;\n            for(int &x: set) if(x==bestU){ x=bestV; break; }\n            degIn=recompute(set);\n        }\n        sort(set.begin(), set.end());\n        return set;\n    }\n    vector<vector<int>> generateAnchorCandidates(const vector<uint64_t>&adj){\n        int N=Designer::N,A=Designer::A;\n        vector<int> deg(N);\n        for(int i=0;i<N;i++) deg[i]=__builtin_popcountll(adj[i]);\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a,int b){\n            if(deg[a]!=deg[b]) return deg[a]>deg[b];\n            return a<b;\n        });\n        auto makeValid=[&](vector<int> cand){\n            vector<char> used(N,false);\n            vector<int> res;\n            res.reserve(A);\n            for(int v:cand){\n                if(v<0 || v>=N) continue;\n                if(!used[v]){\n                    used[v]=true;\n                    res.push_back(v);\n                    if((int)res.size()==A) break;\n                }\n            }\n            if((int)res.size()<A){\n                for(int v:order){\n                    if(!used[v]){\n                        used[v]=true;\n                        res.push_back(v);\n                        if((int)res.size()==A) break;\n                    }\n                }\n            }\n            return res;\n        };\n        vector<vector<int>> candidates;\n        auto addCandidate=[&](vector<int> cand){\n            vector<int> valid=makeValid(cand);\n            vector<int> improved=improveAnchors(valid,adj);\n            if(find(candidates.begin(),candidates.end(),improved)==candidates.end())\n                candidates.push_back(improved);\n        };\n        vector<int> base(order.begin(), order.begin()+A);\n        addCandidate(base);\n        int maxShift=min(6, N-A);\n        for(int s=1;s<=maxShift;s++){\n            vector<int> cand(order.begin()+s, order.begin()+s+A);\n            addCandidate(cand);\n        }\n        if(N-A>=4){\n            vector<int> cand=base;\n            for(int r=0;r<min(4,N-A);r++) cand[A-1-r]=order[A+r];\n            addCandidate(cand);\n        }\n        vector<int> perm(N);\n        iota(perm.begin(), perm.end(), 0);\n        int randStarts=5;\n        for(int t=0;t<randStarts;t++){\n            shuffle(perm.begin(), perm.end(), rng);\n            vector<int> cand(perm.begin(), perm.begin()+A);\n            addCandidate(cand);\n        }\n        if(candidates.empty()) addCandidate(base);\n        return candidates;\n    }\n    struct AnchorMapResult {\n        vector<int> anchorMap;\n        vector<int> payloadList;\n        int anchorCost;\n    };\n    AnchorMapResult mapAnchors(const vector<uint64_t>&adj, const vector<int>&cand){\n        int N=Designer::N,A=Designer::A;\n        vector<char> isAnchor(N,false);\n        for(int v:cand) isAnchor[v]=true;\n        vector<int> payloads;\n        for(int i=0;i<N;i++) if(!isAnchor[i]) payloads.push_back(i);\n        uint64_t payloadMask=0;\n        for(int v:payloads) payloadMask|=(1ULL<<v);\n        vector<vector<int>> obsAA(A, vector<int>(A,0));\n        vector<int> degAA_obs(A,0), degAP_obs(A,0);\n        for(int i=0;i<A;i++){\n            int vi=cand[i];\n            for(int j=0;j<A;j++){\n                if(i==j) continue;\n                if((adj[vi]>>cand[j])&1ULL){\n                    obsAA[i][j]=1;\n                    degAA_obs[i]++;\n                }\n            }\n            degAP_obs[i]=__builtin_popcountll(adj[vi] & payloadMask);\n        }\n        Hungarian hung(A);\n        const int W1=5, W2=1;\n        for(int i=0;i<A;i++){\n            for(int j=0;j<A;j++){\n                hung.cost[i][j]=W1*abs(des->degAA_can[i]-degAA_obs[j])\n                              +W2*abs(des->degAP_can[i]-degAP_obs[j]);\n            }\n        }\n        hung.solve();\n        vector<int> perm=hung.assignment;\n        auto calcCost=[&](const vector<int>&p){\n            int total=0;\n            for(int i=0;i<A;i++){\n                for(int j=i+1;j<A;j++){\n                    total += des->anchorAdj[i][j] ^ obsAA[p[i]][p[j]];\n                }\n            }\n            return total;\n        };\n        vector<int> best=perm;\n        int bestCost=calcCost(best);\n        vector<int> cur=perm;\n        int curCost=bestCost;\n        uniform_int_distribution<int> distIdx(0,A-1);\n        uniform_real_distribution<double> distReal(0.0,1.0);\n        double temp=4.0;\n        int iterations=3200 + A*60;\n        for(int iter=0; iter<iterations; ++iter){\n            int i=distIdx(rng), j=distIdx(rng);\n            if(i==j) continue;\n            if(i>j) swap(i,j);\n            int oi=cur[i], oj=cur[j];\n            int delta=0;\n            for(int k=0;k<A;k++){\n                if(k==i || k==j) continue;\n                int ok=cur[k];\n                delta += (des->anchorAdj[i][k] ^ obsAA[oj][ok]) - (des->anchorAdj[i][k] ^ obsAA[oi][ok]);\n                delta += (des->anchorAdj[j][k] ^ obsAA[oi][ok]) - (des->anchorAdj[j][k] ^ obsAA[oj][ok]);\n            }\n            delta += (des->anchorAdj[i][j] ^ obsAA[oj][oi]) - (des->anchorAdj[i][j] ^ obsAA[oi][oj]);\n            if(delta<0 || (temp>1e-6 && distReal(rng)<exp(-delta/temp))){\n                swap(cur[i],cur[j]);\n                curCost += delta;\n                if(curCost<bestCost){\n                    bestCost=curCost;\n                    best=cur;\n                }\n            }\n            temp*=0.996;\n            if(temp<0.15) temp=0.15;\n        }\n        vector<int> anchorMap(A);\n        for(int i=0;i<A;i++) anchorMap[i]=cand[best[i]];\n        sort(payloads.begin(), payloads.end());\n        return {anchorMap, payloads, bestCost};\n    }\n    vector<uint64_t> observedPayloadBits(const vector<uint64_t>&adj, const vector<int>&order){\n        vector<uint64_t> bits(des->payloadWords,0);\n        int idx=0;\n        for(int i=0;i<Designer::P;i++){\n            for(int j=i+1;j<Designer::P;j++){\n                bool bit=(adj[order[i]]>>order[j])&1ULL;\n                if(bit) bits[idx>>6] |= (1ULL<<(idx&63));\n                idx++;\n            }\n        }\n        return bits;\n    }\n    vector<int> refinePayloadOrder(const vector<int>&initial,\n                                   const vector<vector<int>>&anchorMismatch,\n                                   const vector<vector<int>>&realEdge,\n                                   int codeIdx){\n        if(codeIdx<0) return initial;\n        int P=Designer::P;\n        vector<int> assign=initial;\n        vector<vector<int>> codeEdge(P, vector<int>(P,0));\n        const auto &code = des->graphCodes[codeIdx];\n        for(int i=0;i<P;i++){\n            for(int j=i+1;j<P;j++){\n                int pos=des->payloadPairIdx[i][j];\n                int bit=(code[pos>>6]>>(pos&63))&1ULL;\n                codeEdge[i][j]=codeEdge[j][i]=bit;\n            }\n        }\n        const int wA=2, wE=3;\n        int anchorCost=0;\n        for(int i=0;i<P;i++) anchorCost += anchorMismatch[i][assign[i]];\n        int edgeCost=0;\n        for(int i=0;i<P;i++){\n            for(int j=i+1;j<P;j++){\n                edgeCost += (realEdge[assign[i]][assign[j]] ^ codeEdge[i][j]);\n            }\n        }\n        int totalCost=wA*anchorCost + wE*edgeCost;\n        vector<int> best=assign;\n        int bestCost=totalCost;\n        uniform_int_distribution<int> distIdx(0,P-1);\n        uniform_real_distribution<double> distReal(0.0,1.0);\n        double temp=3.0;\n        int iterations=4000 + P*120;\n        for(int iter=0; iter<iterations; ++iter){\n            int a=distIdx(rng), b=distIdx(rng);\n            if(a==b) continue;\n            if(a>b) swap(a,b);\n            int ra=assign[a], rb=assign[b];\n            if(ra==rb) continue;\n            int deltaA = anchorMismatch[a][rb] + anchorMismatch[b][ra]\n                       - anchorMismatch[a][ra] - anchorMismatch[b][rb];\n            int deltaE=0;\n            for(int t=0;t<P;t++){\n                if(t==a || t==b) continue;\n                int rt=assign[t];\n                int oldA = realEdge[ra][rt] ^ codeEdge[a][t];\n                int newA = realEdge[rb][rt] ^ codeEdge[a][t];\n                deltaE += newA - oldA;\n                int oldB = realEdge[rb][rt] ^ codeEdge[b][t];\n                int newB = realEdge[ra][rt] ^ codeEdge[b][t];\n                deltaE += newB - oldB;\n            }\n            int delta = wA*deltaA + wE*deltaE;\n            if(delta<0 || (temp>1e-6 && distReal(rng)<exp(-delta/temp))){\n                assign[a]=rb;\n                assign[b]=ra;\n                totalCost += delta;\n                if(totalCost<bestCost){\n                    bestCost=totalCost;\n                    best=assign;\n                }\n            }\n            temp*=0.995;\n            if(temp<0.2) temp=0.2;\n        }\n        return best;\n    }\n    struct DecodeResult{\n        int graphIdx;\n        int dist;\n        int anchorCost;\n    };\n    DecodeResult decodeWithAnchors(const vector<uint64_t>&adj, const vector<int>&cand){\n        if((int)cand.size()!=Designer::A) return {-1, INT_MAX, INT_MAX};\n        auto mapRes = mapAnchors(adj, cand);\n        if((int)mapRes.payloadList.size()!=Designer::P) return {-1, INT_MAX, INT_MAX};\n        int P=Designer::P, A=Designer::A;\n        const auto &payloadList = mapRes.payloadList;\n        vector<uint64_t> obsMask(P,0);\n        for(int r=0;r<P;r++){\n            uint64_t mask=0;\n            int v=payloadList[r];\n            for(int a=0;a<A;a++){\n                if((adj[v]>>mapRes.anchorMap[a])&1ULL) mask |= (1ULL<<a);\n            }\n            obsMask[r]=mask;\n        }\n        vector<vector<int>> anchorMismatch(P, vector<int>(P,0));\n        for(int c=0;c<P;c++) for(int r=0;r<P;r++)\n            anchorMismatch[c][r]=__builtin_popcountll(obsMask[r]^des->payloadAnchorMask[c]);\n        vector<vector<int>> realEdge(P, vector<int>(P,0));\n        for(int i=0;i<P;i++){\n            for(int j=i+1;j<P;j++){\n                bool bit=(adj[payloadList[i]]>>payloadList[j])&1ULL;\n                realEdge[i][j]=realEdge[j][i]=bit;\n            }\n        }\n        Hungarian hung(P);\n        for(int r=0;r<P;r++) for(int c=0;c<P;c++)\n            hung.cost[r][c]=anchorMismatch[c][r];\n        hung.solve();\n        vector<int> assign(P,-1);\n        vector<char> used(P,false);\n        for(int r=0;r<P;r++){\n            int c=hung.assignment[r];\n            if(c>=0 && c<P && assign[c]==-1){\n                assign[c]=r;\n                used[r]=true;\n            }\n        }\n        int ptr=0;\n        for(int c=0;c<P;c++){\n            if(assign[c]==-1){\n                while(ptr<P && used[ptr]) ptr++;\n                assign[c]=(ptr<P)?ptr:0;\n                if(ptr<P) used[ptr]=true;\n            }\n        }\n        auto orderFromAssign=[&](const vector<int>&as){\n            vector<int> order(P);\n            for(int i=0;i<P;i++) order[i]=payloadList[as[i]];\n            return order;\n        };\n        auto bitsFromAssign=[&](const vector<int>&as){\n            auto order=orderFromAssign(as);\n            return observedPayloadBits(adj, order);\n        };\n        auto bitsBase = bitsFromAssign(assign);\n        vector<pair<int,int>> codeDist;\n        codeDist.reserve(des->graphCodes.size());\n        for(int k=0;k<(int)des->graphCodes.size();k++){\n            int dist = des->hamming(bitsBase, des->graphCodes[k]);\n            codeDist.emplace_back(dist, k);\n        }\n        sort(codeDist.begin(), codeDist.end());\n        DecodeResult bestRes{codeDist[0].second, codeDist[0].first, mapRes.anchorCost};\n        const int topK = min(4, (int)codeDist.size());\n        for(int idx=0; idx<topK; ++idx){\n            int codeIdx = codeDist[idx].second;\n            auto refinedAssign = refinePayloadOrder(assign, anchorMismatch, realEdge, codeIdx);\n            auto refinedBits = bitsFromAssign(refinedAssign);\n            int bestCodeHere=-1, bestDistHere=INT_MAX;\n            for(int k=0;k<(int)des->graphCodes.size();k++){\n                int dist = des->hamming(refinedBits, des->graphCodes[k]);\n                if(dist<bestDistHere){\n                    bestDistHere=dist;\n                    bestCodeHere=k;\n                }\n            }\n            pair<int,int> keyRef = {bestDistHere, mapRes.anchorCost};\n            pair<int,int> keyBest = {bestRes.dist, bestRes.anchorCost};\n            if(keyRef < keyBest){\n                bestRes = {bestCodeHere, bestDistHere, mapRes.anchorCost};\n            }\n        }\n        return bestRes;\n    }\n    int decode(const string& s){\n        auto adj = parse(s);\n        auto candidates = generateAnchorCandidates(adj);\n        int best=-1;\n        pair<int,int> bestKey={INT_MAX, INT_MAX};\n        for(auto &cand: candidates){\n            auto res = decodeWithAnchors(adj, cand);\n            if(res.graphIdx==-1) continue;\n            pair<int,int> key={res.dist, res.anchorCost};\n            if(key<bestKey){\n                bestKey=key;\n                best=res.graphIdx;\n            }\n        }\n        if(best==-1){\n            uniform_int_distribution<int> dist(0,(int)des->graphCodes.size()-1);\n            best=dist(rng);\n        }\n        return best;\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int M;\n    double eps;\n    if(!(cin>>M>>eps)) return 0;\n    Designer designer;\n    designer.build(M, eps);\n    cout<<Designer::N<<\"\\n\";\n    for(int k=0;k<M;k++){\n        cout<<designer.graphString(k)<<\"\\n\";\n    }\n    cout.flush();\n    Decoder decoder(&designer);\n    for(int q=0;q<100;q++){\n        string H;\n        if(!(cin>>H)) break;\n        int ans = decoder.decode(H);\n        cout<<ans<<\"\\n\";\n        cout.flush();\n    }\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n};\n\nstruct DSU {\n    int n;\n    vector<int> parent, sz;\n    int components;\n    DSU(int n=0){ if(n) init(n); }\n    void init(int n_){\n        n = n_;\n        parent.resize(n);\n        sz.resize(n);\n        reset();\n    }\n    void reset(){\n        iota(parent.begin(), parent.end(), 0);\n        fill(sz.begin(), sz.end(), 1);\n        components = n;\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    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        parent[b]=a;\n        sz[a]+=sz[b];\n        --components;\n        return true;\n    }\n};\n\nconst double TOTAL_TIME_LIMIT = 5.8;\nconst double CENTRALITY_LIMIT = 2.9;\nconst double LOCAL_SEARCH_LIMIT = 5.0;\nconst double MOVE_EPS = 1e-9;\nconst double VERTEX_COEFF = 0.18;\nconst double DAYCOUNT_COEFF = 0.035;\nconst double LENGTH_COEFF_RATIO = 0.05;\nconst double MIN_REMAIN_FOR_NEW_RUN = 0.9;\nconst int MAX_RUNS = 3;\nconst int MAX_SAMPLE = 8;\nconst ll INFLL = (1LL<<60);\n\nint N,M,D,K;\nvector<int> U,V,W;\nvector<vector<pair<int,int>>> graphAdj;\n\nvector<double> edgeScore;\nvector<int> assignment;\nvector<vector<int>> dayEdges;\nvector<int> edgePos;\nvector<double> dayScore;\nvector<int> dayCount;\nvector<int> vertexDayCount;\nvector<vector<char>> dayBlocked;\n\nvector<int> sampleSources;\nvector<vector<ll>> baseDist;\n\nvector<vector<vector<ll>>> daySampleDist;\nvector<vector<double>> daySampleSum;\nvector<double> dayEval;\n\nmt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\n\ndouble alphaCoeff, betaCoeff;\n\nvoid dijkstra_with_block(int src, const vector<char>* blocked, vector<ll>& dist){\n    priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n    fill(dist.begin(), dist.end(), INFLL);\n    dist[src] = 0;\n    pq.emplace(0LL, src);\n    while(!pq.empty()){\n        auto [d,v] = pq.top();\n        pq.pop();\n        if(d != dist[v]) continue;\n        for(auto [to,eid] : graphAdj[v]){\n            if(blocked && (*blocked)[eid]) continue;\n            ll nd = d + W[eid];\n            if(nd < dist[to]){\n                dist[to] = nd;\n                pq.emplace(nd, to);\n            }\n        }\n    }\n}\n\nvoid select_samples_and_base(){\n    int sampleCnt = min(MAX_SAMPLE, N);\n    vector<int> deg(N,0);\n    for(int i=0;i<M;++i){\n        deg[U[i]]++;\n        deg[V[i]]++;\n    }\n    int first = 0;\n    for(int i=1;i<N;++i){\n        if(deg[i] > deg[first]) first = i;\n    }\n    sampleSources.clear();\n    baseDist.clear();\n    vector<ll> cover(N, INFLL);\n    vector<ll> dist(N);\n    int current = first;\n    for(int s=0; s<sampleCnt; ++s){\n        if(s==0) current = first;\n        else{\n            ll best = -1;\n            int bestNode = 0;\n            for(int v=0; v<N; ++v){\n                if(cover[v] > best){\n                    best = cover[v];\n                    bestNode = v;\n                }\n            }\n            current = bestNode;\n        }\n        sampleSources.push_back(current);\n        dijkstra_with_block(current, nullptr, dist);\n        baseDist.push_back(dist);\n        for(int v=0; v<N; ++v){\n            cover[v] = min(cover[v], dist[v]);\n        }\n        cover[current] = 0;\n    }\n}\n\nvector<double> compute_edge_scores(Timer &timer){\n    vector<double> score(M, 0.0);\n    vector<ll> dist(N);\n    vector<double> sigma(N), delta(N);\n    vector<vector<int>> preds(N);\n    for(int i=0;i<N;++i) preds[i].reserve(graphAdj[i].size());\n    vector<int> order;\n    order.reserve(N);\n    vector<int> nodes(N);\n    iota(nodes.begin(), nodes.end(), 0);\n    shuffle(nodes.begin(), nodes.end(), rng);\n    int processed = 0;\n    for(int idx=0; idx<N; ++idx){\n        if(timer.elapsed() > CENTRALITY_LIMIT) break;\n        int s = nodes[idx];\n        fill(dist.begin(), dist.end(), INFLL);\n        fill(sigma.begin(), sigma.end(), 0.0);\n        fill(delta.begin(), delta.end(), 0.0);\n        for(int i=0;i<N;++i) preds[i].clear();\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[s] = 0;\n        sigma[s] = 1.0;\n        pq.emplace(0LL, s);\n        order.clear();\n        while(!pq.empty()){\n            auto [d,v] = pq.top();\n            pq.pop();\n            if(d != dist[v]) continue;\n            order.push_back(v);\n            for(auto [to,eid] : graphAdj[v]){\n                ll nd = d + W[eid];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    pq.emplace(nd, to);\n                    sigma[to] = sigma[v];\n                    preds[to].clear();\n                    preds[to].push_back(eid);\n                }else if(nd == dist[to]){\n                    sigma[to] += sigma[v];\n                    preds[to].push_back(eid);\n                }\n            }\n        }\n        while(!order.empty()){\n            int w = order.back();\n            order.pop_back();\n            if(sigma[w] <= 0.0) continue;\n            double coeff = (1.0 + delta[w]) / sigma[w];\n            for(int eid : preds[w]){\n                int v = (U[eid]==w) ? V[eid] : U[eid];\n                double contrib = sigma[v] * coeff;\n                delta[v] += contrib;\n                score[eid] += contrib;\n            }\n        }\n        ++processed;\n    }\n    if(processed == 0) processed = 1;\n    if(processed < N){\n        double scale = (double)N / processed;\n        for(double &x : score) x *= scale;\n    }\n    double totalScore = 0.0;\n    for(double s : score) totalScore += s;\n    if(totalScore <= 0) totalScore = 1.0;\n    long double baseScale = (long double)totalScore * totalScore;\n    baseScale /= max(1, M);\n    baseScale /= max(1, D);\n    alphaCoeff = (double)(baseScale * VERTEX_COEFF);\n    betaCoeff  = (double)(baseScale * DAYCOUNT_COEFF);\n    if(!isfinite(alphaCoeff) || alphaCoeff < 1e-9) alphaCoeff = 1e-9;\n    if(!isfinite(betaCoeff)  || betaCoeff  < 1e-9) betaCoeff  = 1e-9;\n    alphaCoeff = min(alphaCoeff, 1e18);\n    betaCoeff  = min(betaCoeff , 1e18);\n\n    ll sumW = 0;\n    for(int w : W) sumW += w;\n    double avgScore = totalScore / M;\n    double avgW = (double)sumW / M;\n    double lengthCoeff = (avgW > 0) ? LENGTH_COEFF_RATIO * avgScore / avgW : 0.0;\n    for(int i=0;i<M;++i){\n        score[i] += lengthCoeff * W[i];\n        if(score[i] <= 0) score[i] = 1e-9;\n    }\n    return score;\n}\n\nvoid initialize_state(){\n    assignment.assign(M, -1);\n    dayEdges.assign(D, {});\n    edgePos.assign(M, -1);\n    dayScore.assign(D, 0.0);\n    dayCount.assign(D, 0);\n    vertexDayCount.assign(N*D, 0);\n    dayBlocked.assign(D, vector<char>(M, 0));\n}\n\nvoid move_edge(int eid, int newDay){\n    int oldDay = assignment[eid];\n    if(oldDay == newDay) return;\n    double s = edgeScore[eid];\n    if(oldDay != -1){\n        auto &vec = dayEdges[oldDay];\n        int pos = edgePos[eid];\n        int last = vec.back();\n        if(pos != (int)vec.size()-1){\n            vec[pos] = last;\n            edgePos[last] = pos;\n        }\n        vec.pop_back();\n        dayScore[oldDay] -= s;\n        dayCount[oldDay]--;\n        vertexDayCount[U[eid]*D + oldDay]--;\n        vertexDayCount[V[eid]*D + oldDay]--;\n        dayBlocked[oldDay][eid] = 0;\n    }\n    assignment[eid] = newDay;\n    if(newDay != -1){\n        auto &vec = dayEdges[newDay];\n        edgePos[eid] = vec.size();\n        vec.push_back(eid);\n        dayScore[newDay] += s;\n        dayCount[newDay]++;\n        vertexDayCount[U[eid]*D + newDay]++;\n        vertexDayCount[V[eid]*D + newDay]++;\n        dayBlocked[newDay][eid] = 1;\n    }else edgePos[eid] = -1;\n}\n\ndouble move_delta(int eid, int fromDay, int toDay){\n    double s = edgeScore[eid];\n    double delta = s * (dayScore[toDay] - dayScore[fromDay]);\n    int u = U[eid], v = V[eid];\n    delta += alphaCoeff * ((vertexDayCount[u*D + toDay] + vertexDayCount[v*D + toDay])\n                         - (vertexDayCount[u*D + fromDay] + vertexDayCount[v*D + fromDay]));\n    delta += betaCoeff * (dayCount[toDay] - dayCount[fromDay]);\n    return delta;\n}\n\nbool is_day_connected_plain(int day){\n    DSU dsu(N);\n    for(int eid=0; eid<M; ++eid){\n        if(assignment[eid] == day) continue;\n        dsu.unite(U[eid], V[eid]);\n    }\n    return dsu.components == 1;\n}\n\nint build_components_without_day(int day, vector<int> &comp){\n    DSU dsu(N);\n    for(int eid=0; eid<M; ++eid){\n        if(assignment[eid] == day) continue;\n        dsu.unite(U[eid], V[eid]);\n    }\n    if((int)comp.size()!=N) comp.assign(N, 0);\n    vector<int> rootId(N, -1);\n    int comps = 0;\n    for(int i=0;i<N;++i){\n        int r = dsu.find(i);\n        if(rootId[r]==-1) rootId[r]=comps++;\n        comp[i]=rootId[r];\n    }\n    return comps;\n}\n\nint pick_low_score_edge(int day){\n    if(dayEdges[day].empty()) return -1;\n    int best = dayEdges[day][0];\n    double bestScore = edgeScore[best];\n    for(int eid : dayEdges[day]){\n        if(edgeScore[eid] < bestScore){\n            bestScore = edgeScore[eid];\n            best = eid;\n        }\n    }\n    return best;\n}\n\nbool attempt_swap_move_basic(int eid, int targetDay){\n    int fromDay = assignment[eid];\n    int swapEdge = pick_low_score_edge(targetDay);\n    if(swapEdge == -1) return false;\n    move_edge(eid, -1);\n    move_edge(swapEdge, fromDay);\n    move_edge(eid, targetDay);\n    if(!is_day_connected_plain(targetDay) || !is_day_connected_plain(fromDay)){\n        move_edge(swapEdge, targetDay);\n        move_edge(eid, fromDay);\n        return false;\n    }\n    return true;\n}\n\nbool try_move_edge_from_day(int eid, int day){\n    vector<pair<double,int>> withSlot;\n    vector<pair<double,int>> noSlot;\n    for(int d=0; d<D; ++d){\n        if(d==day) continue;\n        double delta = move_delta(eid, day, d);\n        if(dayCount[d] < K) withSlot.emplace_back(delta, d);\n        else noSlot.emplace_back(delta, d);\n    }\n    sort(withSlot.begin(), withSlot.end());\n    for(auto [delta, d] : withSlot){\n        move_edge(eid, d);\n        if(is_day_connected_plain(day) && is_day_connected_plain(d)) return true;\n        move_edge(eid, day);\n    }\n    for(auto [delta, d] : withSlot){\n        move_edge(eid, d);\n        return true;\n    }\n    sort(noSlot.begin(), noSlot.end());\n    for(auto [delta, d] : noSlot){\n        if(attempt_swap_move_basic(eid, d)) return true;\n    }\n    return false;\n}\n\nvoid enforce_connectivity(Timer &timer){\n    vector<int> comp(N);\n    int outerGuard = 0;\n    while(timer.elapsed() < TOTAL_TIME_LIMIT - 0.4 && outerGuard < 4*D){\n        bool changed = false;\n        for(int day=0; day<D; ++day){\n            if(timer.elapsed() > TOTAL_TIME_LIMIT - 0.45) return;\n            int guard = 0;\n            while(guard < M){\n                int comps = build_components_without_day(day, comp);\n                if(comps <= 1) break;\n                vector<int> critical;\n                for(int eid : dayEdges[day]){\n                    if(comp[U[eid]] != comp[V[eid]]) critical.push_back(eid);\n                }\n                if(critical.empty()) break;\n                sort(critical.begin(), critical.end(), [&](int a,int b){\n                    if(edgeScore[a]!=edgeScore[b]) return edgeScore[a] > edgeScore[b];\n                    return a<b;\n                });\n                bool moved = false;\n                for(int eid : critical){\n                    if(try_move_edge_from_day(eid, day)){\n                        changed = true;\n                        moved = true;\n                        break;\n                    }\n                }\n                if(!moved) break;\n                ++guard;\n            }\n        }\n        if(!changed) break;\n        ++outerGuard;\n    }\n}\n\nvoid greedy_initial_assignment(const vector<int> &order){\n    for(int eid : order){\n        double bestVal = numeric_limits<double>::infinity();\n        int bestDay = -1;\n        double s = edgeScore[eid];\n        int u = U[eid], v = V[eid];\n        int baseU = u*D, baseV = v*D;\n        for(int day=0; day<D; ++day){\n            if(dayCount[day] >= K) continue;\n            double val = dayScore[day] * s\n                       + alphaCoeff * (vertexDayCount[baseU + day] + vertexDayCount[baseV + day])\n                       + betaCoeff  * dayCount[day];\n            if(val < bestVal - 1e-12){\n                bestVal = val;\n                bestDay = day;\n            }\n        }\n        if(bestDay == -1){\n            bestDay = min_element(dayCount.begin(), dayCount.end()) - dayCount.begin();\n        }\n        move_edge(eid, bestDay);\n    }\n}\n\nvoid local_search(Timer &timer){\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    bool improved = true;\n    while(improved && timer.elapsed() < LOCAL_SEARCH_LIMIT){\n        improved = false;\n        shuffle(idx.begin(), idx.end(), rng);\n        for(int eid : idx){\n            if(timer.elapsed() > LOCAL_SEARCH_LIMIT) return;\n            int oldDay = assignment[eid];\n            vector<pair<double,int>> cand;\n            cand.reserve(D-1);\n            for(int day=0; day<D; ++day){\n                if(day == oldDay) continue;\n                if(dayCount[day] >= K) continue;\n                double delta = move_delta(eid, oldDay, day);\n                cand.emplace_back(delta, day);\n            }\n            sort(cand.begin(), cand.end());\n            for(auto [delta, day] : cand){\n                if(delta >= -MOVE_EPS) break;\n                move_edge(eid, day);\n                if(is_day_connected_plain(oldDay) && is_day_connected_plain(day)){\n                    improved = true;\n                    break;\n                }else{\n                    move_edge(eid, oldDay);\n                }\n            }\n        }\n    }\n}\n\ndouble compute_full_eval(){\n    if(sampleSources.empty()) return 0.0;\n    int S = sampleSources.size();\n    daySampleDist.assign(D, vector<vector<ll>>(S, vector<ll>(N)));\n    daySampleSum.assign(D, vector<double>(S, 0.0));\n    dayEval.assign(D, 0.0);\n    vector<ll> dist(N);\n    double total = 0.0;\n    for(int day=0; day<D; ++day){\n        double sumSamples = 0.0;\n        for(int s=0; s<S; ++s){\n            dijkstra_with_block(sampleSources[s], &dayBlocked[day], dist);\n            daySampleDist[day][s] = dist;\n            long double diffSum = 0.0;\n            const auto &base = baseDist[s];\n            for(int v=0; v<N; ++v){\n                ll ref = base[v];\n                if(ref >= INFLL/4) ref = 1000000000LL;\n                ll cur = dist[v];\n                ll diff;\n                if(cur >= INFLL/4) diff = 1000000000LL - ref;\n                else diff = cur - ref;\n                if(diff < 0) diff = 0;\n                diffSum += diff;\n            }\n            double norm = diffSum / (double)max(1, N-1);\n            daySampleSum[day][s] = norm;\n            sumSamples += norm;\n        }\n        dayEval[day] = sumSamples / S;\n        total += dayEval[day];\n    }\n    return total / D;\n}\n\nvoid compute_day_temp(int day, vector<vector<ll>> &bufDist, vector<double> &bufSum, vector<ll> &scratch){\n    int S = sampleSources.size();\n    for(int s=0; s<S; ++s){\n        dijkstra_with_block(sampleSources[s], &dayBlocked[day], scratch);\n        bufDist[s] = scratch;\n        long double diffSum = 0.0;\n        const auto &base = baseDist[s];\n        for(int v=0; v<N; ++v){\n            ll ref = base[v];\n            if(ref >= INFLL/4) ref = 1000000000LL;\n            ll cur = scratch[v];\n            ll diff;\n            if(cur >= INFLL/4) diff = 1000000000LL - ref;\n            else diff = cur - ref;\n            if(diff < 0) diff = 0;\n            diffSum += diff;\n        }\n        bufSum[s] = diffSum / (double)max(1, N-1);\n    }\n}\n\nbool try_move_eval(int eid, int newDay, double &currentScore,\n                   vector<vector<ll>> &tempOld,\n                   vector<vector<ll>> &tempNew,\n                   vector<double> &tempSumOld,\n                   vector<double> &tempSumNew,\n                   vector<ll> &scratch){\n    int oldDay = assignment[eid];\n    if(oldDay == newDay) return false;\n    if(dayCount[newDay] >= K) return false;\n    move_edge(eid, newDay);\n    if(!is_day_connected_plain(oldDay) || !is_day_connected_plain(newDay)){\n        move_edge(eid, oldDay);\n        return false;\n    }\n    compute_day_temp(oldDay, tempOld, tempSumOld, scratch);\n    compute_day_temp(newDay, tempNew, tempSumNew, scratch);\n    double evalOld = accumulate(tempSumOld.begin(), tempSumOld.end(), 0.0) / sampleSources.size();\n    double evalNew = accumulate(tempSumNew.begin(), tempSumNew.end(), 0.0) / sampleSources.size();\n    double newTotal = currentScore - dayEval[oldDay] - dayEval[newDay] + evalOld + evalNew;\n    if(newTotal < currentScore - 1e-6){\n        for(size_t s=0; s<sampleSources.size(); ++s){\n            daySampleDist[oldDay][s] = tempOld[s];\n            daySampleDist[newDay][s] = tempNew[s];\n            daySampleSum[oldDay][s] = tempSumOld[s];\n            daySampleSum[newDay][s] = tempSumNew[s];\n        }\n        dayEval[oldDay] = evalOld;\n        dayEval[newDay] = evalNew;\n        currentScore = newTotal;\n        return true;\n    }else{\n        move_edge(eid, oldDay);\n        return false;\n    }\n}\n\nbool try_swap_eval(int eid, int targetDay, int swapEdge, double &currentScore,\n                   vector<vector<ll>> &tempOld,\n                   vector<vector<ll>> &tempNew,\n                   vector<double> &tempSumOld,\n                   vector<double> &tempSumNew,\n                   vector<ll> &scratch){\n    int oldDay = assignment[eid];\n    if(oldDay == targetDay) return false;\n    if(assignment[swapEdge] != targetDay) return false;\n    move_edge(eid, -1);\n    move_edge(swapEdge, oldDay);\n    move_edge(eid, targetDay);\n    if(!is_day_connected_plain(oldDay) || !is_day_connected_plain(targetDay)){\n        move_edge(swapEdge, targetDay);\n        move_edge(eid, oldDay);\n        return false;\n    }\n    compute_day_temp(oldDay, tempOld, tempSumOld, scratch);\n    compute_day_temp(targetDay, tempNew, tempSumNew, scratch);\n    double evalOld = accumulate(tempSumOld.begin(), tempSumOld.end(), 0.0) / sampleSources.size();\n    double evalNew = accumulate(tempSumNew.begin(), tempSumNew.end(), 0.0) / sampleSources.size();\n    double newTotal = currentScore - dayEval[oldDay] - dayEval[targetDay] + evalOld + evalNew;\n    if(newTotal < currentScore - 1e-6){\n        for(size_t s=0; s<sampleSources.size(); ++s){\n            daySampleDist[oldDay][s] = tempOld[s];\n            daySampleDist[targetDay][s] = tempNew[s];\n            daySampleSum[oldDay][s] = tempSumOld[s];\n            daySampleSum[targetDay][s] = tempSumNew[s];\n        }\n        dayEval[oldDay] = evalOld;\n        dayEval[targetDay] = evalNew;\n        currentScore = newTotal;\n        return true;\n    }else{\n        move_edge(swapEdge, targetDay);\n        move_edge(eid, oldDay);\n        return false;\n    }\n}\n\nvector<int> get_low_edges(int day, int limit){\n    vector<pair<double,int>> arr;\n    arr.reserve(dayEdges[day].size());\n    for(int eid : dayEdges[day]) arr.push_back({edgeScore[eid], eid});\n    if(arr.empty()) return {};\n    if((int)arr.size() > limit){\n        nth_element(arr.begin(), arr.begin()+limit, arr.end(),\n                    [](const auto &a, const auto &b){ return a.first < b.first; });\n        arr.resize(limit);\n    }\n    sort(arr.begin(), arr.end(),\n         [](const auto &a, const auto &b){ return a.first < b.first; });\n    vector<int> res;\n    res.reserve(arr.size());\n    for(auto &p : arr) res.push_back(p.second);\n    return res;\n}\n\nvoid sample_based_improve(double &currentScore, Timer &timer){\n    if(sampleSources.empty()) return;\n    const double TIME_MARGIN = 0.2;\n    int S = sampleSources.size();\n    vector<vector<ll>> tempDistA(S, vector<ll>(N));\n    vector<vector<ll>> tempDistB(S, vector<ll>(N));\n    vector<double> tempSumA(S), tempSumB(S);\n    vector<ll> scratch(N);\n    while(timer.elapsed() < TOTAL_TIME_LIMIT - TIME_MARGIN){\n        vector<int> dayOrder(D);\n        iota(dayOrder.begin(), dayOrder.end(), 0);\n        sort(dayOrder.begin(), dayOrder.end(), [&](int a,int b){\n            return dayEval[a] > dayEval[b];\n        });\n        bool improved = false;\n        int considerDays = min(D, 3);\n        for(int idx=0; idx<considerDays && !improved; ++idx){\n            int srcDay = dayOrder[idx];\n            auto edges = dayEdges[srcDay];\n            if(edges.empty()) continue;\n            sort(edges.begin(), edges.end(), [&](int a,int b){\n                return edgeScore[a] > edgeScore[b];\n            });\n            if((int)edges.size() > 15) edges.resize(15);\n            for(int eid : edges){\n                if(timer.elapsed() > TOTAL_TIME_LIMIT - TIME_MARGIN) break;\n                int oldDay = assignment[eid];\n                vector<pair<double,int>> candMove;\n                vector<pair<double,int>> candSwap;\n                for(int day=0; day<D; ++day){\n                    if(day==oldDay) continue;\n                    double approx = move_delta(eid, oldDay, day);\n                    if(dayCount[day] < K) candMove.emplace_back(approx, day);\n                    else candSwap.emplace_back(approx, day);\n                }\n                sort(candMove.begin(), candMove.end());\n                sort(candSwap.begin(), candSwap.end());\n                int moveLimit = min((int)candMove.size(), 6);\n                for(int i=0;i<moveLimit && timer.elapsed() < TOTAL_TIME_LIMIT - TIME_MARGIN; ++i){\n                    int day = candMove[i].second;\n                    if(try_move_eval(eid, day, currentScore,\n                                     tempDistA, tempDistB,\n                                     tempSumA, tempSumB, scratch)){\n                        improved = true;\n                        break;\n                    }\n                }\n                if(improved) break;\n                int swapDayLimit = min((int)candSwap.size(), 4);\n                for(int i=0;i<swapDayLimit && !improved && timer.elapsed() < TOTAL_TIME_LIMIT - TIME_MARGIN; ++i){\n                    int day = candSwap[i].second;\n                    auto lowEdges = get_low_edges(day, 4);\n                    for(int swapEdge : lowEdges){\n                        if(try_swap_eval(eid, day, swapEdge, currentScore,\n                                         tempDistA, tempDistB,\n                                         tempSumA, tempSumB, scratch)){\n                            improved = true;\n                            break;\n                        }\n                    }\n                }\n                if(improved) break;\n            }\n        }\n        if(!improved) break;\n    }\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Timer timer;\n    if(!(cin >> N >> M >> D >> K)) return 0;\n    U.resize(M); V.resize(M); W.resize(M);\n    graphAdj.assign(N, {});\n    for(int i=0;i<M;++i){\n        int u,v,w;\n        cin >> u >> v >> w;\n        --u; --v;\n        U[i]=u; V[i]=v; W[i]=w;\n        graphAdj[u].push_back({v,i});\n        graphAdj[v].push_back({u,i});\n    }\n    for(int i=0;i<N;++i){\n        int x,y;\n        cin >> x >> y;\n        (void)x; (void)y;\n    }\n\n    select_samples_and_base();\n    edgeScore = compute_edge_scores(timer);\n\n    vector<int> bestAssignment;\n    double bestApprox = 1e300;\n    uniform_real_distribution<double> noiseDist(-1.0, 1.0);\n\n    int run = 0;\n    while(run < MAX_RUNS){\n        if(run>0 && TOTAL_TIME_LIMIT - timer.elapsed() < MIN_REMAIN_FOR_NEW_RUN) break;\n\n        initialize_state();\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        vector<double> key(M);\n        double noiseLevel = (run==0 ? 0.0 : 0.2);\n        for(int i=0;i<M;++i){\n            double noise = noiseLevel * noiseDist(rng);\n            key[i] = edgeScore[i] * (1.0 + noise);\n        }\n        sort(order.begin(), order.end(), [&](int a,int b){\n            if(key[a]!=key[b]) return key[a] > key[b];\n            return a<b;\n        });\n\n        greedy_initial_assignment(order);\n        enforce_connectivity(timer);\n        local_search(timer);\n        enforce_connectivity(timer);\n\n        double approxScore = compute_full_eval();\n        sample_based_improve(approxScore, timer);\n\n        if(approxScore < bestApprox){\n            bestApprox = approxScore;\n            bestAssignment = assignment;\n        }\n        ++run;\n    }\n\n    if(bestAssignment.empty()) bestAssignment = assignment;\n\n    for(int i=0;i<M;++i){\n        if(i) cout << ' ';\n        cout << bestAssignment[i] + 1;\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Segment {\n    int x, y;\n    int z0;\n    int len;\n};\n\nstruct Builder {\n    bool active = false;\n    int start = 0;\n    int len = 0;\n};\n\nstruct LayerAssign {\n    vector<pair<int,int>> pairs;\n    vector<int> assigned_y_for_x;\n    vector<int> assigned_x_for_y;\n};\n\nLayerAssign assign_x_major(\n        int D,\n        const vector<int>& X,\n        const vector<int>& Y,\n        const vector<int>& prev_y_for_x,\n        const vector<int>& prev_x_for_y) {\n\n    LayerAssign res;\n    res.assigned_y_for_x.assign(D, -1);\n    res.assigned_x_for_y.assign(D, -1);\n    if (Y.empty()) return res;\n\n    vector<char> y_present(D, 0);\n    for (int y : Y) y_present[y] = 1;\n    vector<char> x_used(D, 0);\n\n    auto choose_with_prev = [&](int target_y) -> int {\n        for (int x : X) if (!x_used[x] && prev_y_for_x[x] == target_y) return x;\n        return -1;\n    };\n    auto choose_any = [&]() -> int {\n        for (int x : X) if (!x_used[x]) return x;\n        return -1;\n    };\n\n    for (int y : Y) {\n        int x = choose_with_prev(y);\n        if (x == -1) x = choose_any();\n        if (x == -1) x = X.front();\n        x_used[x] = 1;\n        res.assigned_y_for_x[x] = y;\n        res.assigned_x_for_y[y] = x;\n        res.pairs.emplace_back(x, y);\n    }\n\n    if (!Y.empty()) {\n        size_t ptr = 0;\n        for (int x : X) {\n            if (x_used[x]) continue;\n            int y = -1;\n            if (prev_y_for_x[x] != -1 && y_present[prev_y_for_x[x]]) y = prev_y_for_x[x];\n            else {\n                y = Y[ptr];\n                ptr = (ptr + 1) % Y.size();\n            }\n            x_used[x] = 1;\n            res.assigned_y_for_x[x] = y;\n            res.assigned_x_for_y[y] = x;\n            res.pairs.emplace_back(x, y);\n        }\n    }\n    return res;\n}\n\nLayerAssign assign_y_major(\n        int D,\n        const vector<int>& X,\n        const vector<int>& Y,\n        const vector<int>& prev_y_for_x,\n        const vector<int>& prev_x_for_y) {\n\n    LayerAssign res;\n    res.assigned_y_for_x.assign(D, -1);\n    res.assigned_x_for_y.assign(D, -1);\n    if (X.empty()) return res;\n\n    vector<char> x_present(D, 0);\n    for (int x : X) x_present[x] = 1;\n    vector<char> y_used(D, 0);\n\n    auto choose_with_prev = [&](int target_x) -> int {\n        for (int y : Y) if (!y_used[y] && prev_x_for_y[y] == target_x) return y;\n        return -1;\n    };\n    auto choose_any = [&]() -> int {\n        for (int y : Y) if (!y_used[y]) return y;\n        return -1;\n    };\n\n    for (int x : X) {\n        int y = choose_with_prev(x);\n        if (y == -1) y = choose_any();\n        if (y == -1) y = Y.front();\n        y_used[y] = 1;\n        res.assigned_y_for_x[x] = y;\n        res.assigned_x_for_y[y] = x;\n        res.pairs.emplace_back(x, y);\n    }\n\n    if (!X.empty()) {\n        size_t ptr = 0;\n        for (int y : Y) {\n            if (y_used[y]) continue;\n            int x = -1;\n            if (prev_x_for_y[y] != -1 && x_present[prev_x_for_y[y]]) x = prev_x_for_y[y];\n            else {\n                x = X[ptr];\n                ptr = (ptr + 1) % X.size();\n            }\n            y_used[y] = 1;\n            res.assigned_x_for_y[y] = x;\n            res.assigned_y_for_x[x] = y;\n            res.pairs.emplace_back(x, y);\n        }\n    }\n    return res;\n}\n\nvector<Segment> build_segments(int D, const vector<string>& front, const vector<string>& right) {\n    vector<Segment> segments;\n    vector<vector<Builder>> builder(D, vector<Builder>(D));\n    vector<vector<char>> stay(D, vector<char>(D, 0));\n    vector<int> prev_y_for_x(D, -1), prev_x_for_y(D, -1);\n\n    for (int z = 0; z < D; ++z) {\n        vector<int> X, Y;\n        for (int x = 0; x < D; ++x) if (front[z][x] == '1') X.push_back(x);\n        for (int y = 0; y < D; ++y) if (right[z][y] == '1') Y.push_back(y);\n\n        LayerAssign assign = (X.size() >= Y.size())\n            ? assign_x_major(D, X, Y, prev_y_for_x, prev_x_for_y)\n            : assign_y_major(D, X, Y, prev_y_for_x, prev_x_for_y);\n\n        for (int x = 0; x < D; ++x)\n            fill(stay[x].begin(), stay[x].end(), 0);\n\n        for (auto [x, y] : assign.pairs) {\n            if (!builder[x][y].active) {\n                builder[x][y].active = true;\n                builder[x][y].start = z;\n                builder[x][y].len = 0;\n            }\n            builder[x][y].len++;\n            stay[x][y] = 1;\n        }\n\n        for (int x = 0; x < D; ++x)\n            for (int y = 0; y < D; ++y)\n                if (builder[x][y].active && !stay[x][y]) {\n                    segments.push_back({x, y, builder[x][y].start, builder[x][y].len});\n                    builder[x][y].active = false;\n                }\n\n        prev_y_for_x = assign.assigned_y_for_x;\n        prev_x_for_y = assign.assigned_x_for_y;\n    }\n\n    for (int x = 0; x < D; ++x)\n        for (int y = 0; y < D; ++y)\n            if (builder[x][y].active) {\n                segments.push_back({x, y, builder[x][y].start, builder[x][y].len});\n                builder[x][y].active = false;\n            }\n    return segments;\n}\n\nstruct MatchResult {\n    vector<int> block_id0;\n    vector<int> block_id1;\n    int total_blocks;\n};\n\nstruct PQNode {\n    int len, idx;\n};\nstruct PQCmp {\n    bool operator()(const PQNode& a, const PQNode& b) const { return a.len < b.len; }\n};\n\nPQNode pop_valid(priority_queue<PQNode, vector<PQNode>, PQCmp>& pq,\n                 const vector<Segment>& segs,\n                 const vector<int>& blockId) {\n    while (!pq.empty()) {\n        auto node = pq.top(); pq.pop();\n        if (node.idx >= (int)segs.size()) continue;\n        if (blockId[node.idx] != -1) continue;\n        if (segs[node.idx].len != node.len) {\n            pq.push({segs[node.idx].len, node.idx});\n            continue;\n        }\n        return node;\n    }\n    return {-1,-1};\n}\n\nMatchResult match_segments(vector<Segment>& seg0, vector<Segment>& seg1) {\n    vector<int> blockId0(seg0.size(), -1), blockId1(seg1.size(), -1);\n    priority_queue<PQNode, vector<PQNode>, PQCmp> pq0, pq1;\n    for (int i = 0; i < (int)seg0.size(); ++i) pq0.push({seg0[i].len, i});\n    for (int i = 0; i < (int)seg1.size(); ++i) pq1.push({seg1[i].len, i});\n    int nextId = 1;\n\n    auto split_segment = [&](vector<Segment>& segs, vector<int>& blockId,\n                             int idx, int take_len) -> int {\n        Segment& seg = segs[idx];\n        Segment newSeg{seg.x, seg.y, seg.z0, take_len};\n        seg.z0 += take_len;\n        seg.len -= take_len;\n        int newIdx = segs.size();\n        segs.push_back(newSeg);\n        blockId.push_back(-1);\n        return newIdx;\n    };\n\n    while (true) {\n        auto node0 = pop_valid(pq0, seg0, blockId0);\n        if (node0.idx == -1) break;\n        auto node1 = pop_valid(pq1, seg1, blockId1);\n        if (node1.idx == -1) {\n            pq0.push({seg0[node0.idx].len, node0.idx});\n            break;\n        }\n        int idx0 = node0.idx, idx1 = node1.idx;\n        if (node0.len == node1.len) {\n            blockId0[idx0] = blockId1[idx1] = nextId++;\n        } else if (node0.len > node1.len) {\n            int newIdx = split_segment(seg0, blockId0, idx0, node1.len);\n            blockId0[newIdx] = blockId1[idx1] = nextId++;\n            pq0.push({seg0[idx0].len, idx0});\n        } else {\n            int newIdx = split_segment(seg1, blockId1, idx1, node0.len);\n            blockId0[idx0] = blockId1[newIdx] = nextId++;\n            pq1.push({seg1[idx1].len, idx1});\n        }\n    }\n\n    for (int i = 0; i < (int)seg0.size(); ++i)\n        if (blockId0[i] == -1) blockId0[i] = nextId++;\n    for (int i = 0; i < (int)seg1.size(); ++i)\n        if (blockId1[i] == -1) blockId1[i] = nextId++;\n\n    return {blockId0, blockId1, nextId - 1};\n}\n\nbool verify(int D, const vector<int>& grid,\n            const vector<string>& front, const vector<string>& right) {\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n    for (int z = 0; z < D; ++z) {\n        for (int x = 0; x < D; ++x) {\n            bool occ = false;\n            for (int y = 0; y < D; ++y)\n                if (grid[idx(x, y, z)]) { occ = true; break; }\n            if (occ != (front[z][x] == '1')) return false;\n        }\n        for (int y = 0; y < D; ++y) {\n            bool occ = false;\n            for (int x = 0; x < D; ++x)\n                if (grid[idx(x, y, z)]) { occ = true; break; }\n            if (occ != (right[z][y] == '1')) return false;\n        }\n    }\n    return true;\n}\n\nstruct Cell { int x, y, z; };\n\nvector<Cell> build_min_cells(int D, const vector<string>& front, const vector<string>& right) {\n    vector<Cell> cells;\n    for (int z = 0; z < D; ++z) {\n        vector<int> xs, ys;\n        for (int x = 0; x < D; ++x) if (front[z][x] == '1') xs.push_back(x);\n        for (int y = 0; y < D; ++y) if (right[z][y] == '1') ys.push_back(y);\n        if (xs.empty()) xs.push_back(0);\n        if (ys.empty()) ys.push_back(0);\n        if (xs.size() >= ys.size()) {\n            for (size_t i = 0; i < xs.size(); ++i)\n                cells.push_back({xs[i], ys[i % ys.size()], z});\n        } else {\n            for (size_t i = 0; i < ys.size(); ++i)\n                cells.push_back({xs[i % xs.size()], ys[i], z});\n        }\n    }\n    return cells;\n}\n\ntuple<int, vector<int>, vector<int>> baseline_solution(\n        int D,\n        const vector<string>& f0, const vector<string>& r0,\n        const vector<string>& f1, const vector<string>& r1) {\n\n    vector<Cell> c0 = build_min_cells(D, f0, r0);\n    vector<Cell> c1 = build_min_cells(D, f1, r1);\n    int n = max(c0.size(), c1.size());\n    vector<int> grid0(D*D*D, 0), grid1(D*D*D, 0);\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n    for (size_t i = 0; i < c0.size(); ++i) grid0[idx(c0[i].x, c0[i].y, c0[i].z)] = i + 1;\n    for (size_t i = 0; i < c1.size(); ++i) grid1[idx(c1[i].x, c1[i].y, c1[i].z)] = i + 1;\n    return {n, grid0, grid1};\n}\n\nstruct BlockUsage {\n    bool used = false;\n    int x = 0, y = 0;\n    int z0 = 0;\n    int len = 0;\n};\n\nbool overlap(const BlockUsage& a, const BlockUsage& b) {\n    int l = max(a.z0, b.z0);\n    int r = min(a.z0 + a.len, b.z0 + b.len);\n    return l < r;\n}\n\nvoid merge_shared_blocks(\n        int& n,\n        vector<int>& grid0,\n        vector<int>& grid1,\n        const vector<Segment>& seg0,\n        const vector<Segment>& seg1,\n        const vector<int>& blockId0,\n        const vector<int>& blockId1) {\n\n    vector<array<BlockUsage,2>> info(n + 1);\n    for (int i = 0; i < (int)seg0.size(); ++i) {\n        int bid = blockId0[i];\n        if (bid <= 0) continue;\n        info[bid][0] = {true, seg0[i].x, seg0[i].y, seg0[i].z0, seg0[i].len};\n    }\n    for (int i = 0; i < (int)seg1.size(); ++i) {\n        int bid = blockId1[i];\n        if (bid <= 0) continue;\n        info[bid][1] = {true, seg1[i].x, seg1[i].y, seg1[i].z0, seg1[i].len};\n    }\n\n    vector<tuple<int,int,int>> edges;\n    for (int a = 1; a <= n; ++a) {\n        auto& a0 = info[a][0];\n        auto& a1 = info[a][1];\n        if (!(a0.used && a1.used)) continue;\n        for (int b = a + 1; b <= n; ++b) {\n            auto& b0 = info[b][0];\n            auto& b1 = info[b][1];\n            if (!(b0.used && b1.used)) continue;\n            if (!overlap(a0, b0)) continue;\n            if (!overlap(a1, b1)) continue;\n            if (abs(a0.x - b0.x) + abs(a0.y - b0.y) != 1) continue;\n            if (abs(a1.x - b1.x) + abs(a1.y - b1.y) != 1) continue;\n            if ((b0.z0 - a0.z0) != (b1.z0 - a1.z0)) continue;\n            edges.emplace_back(-(a0.len + b0.len), a, b);\n        }\n    }\n    if (edges.empty()) return;\n\n    sort(edges.begin(), edges.end());\n\n    vector<int> parent(n + 1);\n    iota(parent.begin(), parent.end(), 0);\n\n    function<int(int)> findp = [&](int x) {\n        if (parent[x] == x) return x;\n        return parent[x] = findp(parent[x]);\n    };\n\n    for (auto [neg_score, a, b] : edges) {\n        int ra = findp(a);\n        int rb = findp(b);\n        if (ra == rb) continue;\n        parent[rb] = ra;\n    }\n\n    vector<int> newId(n + 1, -1);\n    int cnt = 0;\n    for (int i = 1; i <= n; ++i)\n        if (findp(i) == i) newId[i] = ++cnt;\n    for (int i = 1; i <= n; ++i)\n        newId[i] = newId[findp(i)];\n\n    for (int& v : grid0) if (v > 0) v = newId[v];\n    for (int& v : grid1) if (v > 0) v = newId[v];\n    n = cnt;\n}\n\nbool build_advanced(\n        int D,\n        const vector<string>& f0, const vector<string>& r0,\n        const vector<string>& f1, const vector<string>& r1,\n        int& n,\n        vector<int>& grid0,\n        vector<int>& grid1) {\n\n    vector<Segment> seg0 = build_segments(D, f0, r0);\n    vector<Segment> seg1 = build_segments(D, f1, r1);\n\n    MatchResult match = match_segments(seg0, seg1);\n    n = match.total_blocks;\n    grid0.assign(D*D*D, 0);\n    grid1.assign(D*D*D, 0);\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n\n    for (int i = 0; i < (int)seg0.size(); ++i) {\n        int bid = match.block_id0[i];\n        for (int dz = 0; dz < seg0[i].len; ++dz) {\n            int z = seg0[i].z0 + dz;\n            grid0[idx(seg0[i].x, seg0[i].y, z)] = bid;\n        }\n    }\n    for (int i = 0; i < (int)seg1.size(); ++i) {\n        int bid = match.block_id1[i];\n        for (int dz = 0; dz < seg1[i].len; ++dz) {\n            int z = seg1[i].z0 + dz;\n            grid1[idx(seg1[i].x, seg1[i].y, z)] = bid;\n        }\n    }\n    if (!verify(D, grid0, f0, r0)) return false;\n    if (!verify(D, grid1, f1, r1)) return false;\n\n    merge_shared_blocks(n, grid0, grid1, seg0, seg1, match.block_id0, match.block_id1);\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int D;\n    if (!(cin >> D)) return 0;\n    vector<vector<string>> front(2, vector<string>(D));\n    vector<vector<string>> right(2, vector<string>(D));\n    for (int i = 0; i < 2; ++i) {\n        for (int z = 0; z < D; ++z) cin >> front[i][z];\n        for (int z = 0; z < D; ++z) cin >> right[i][z];\n    }\n\n    int n;\n    vector<int> grid0, grid1;\n    if (!build_advanced(D, front[0], right[0], front[1], right[1], n, grid0, grid1)) {\n        tie(n, grid0, grid1) = baseline_solution(D, front[0], right[0], front[1], right[1]);\n    }\n\n    cout << n << '\\n';\n    for (int i = 0; i < D*D*D; ++i) {\n        if (i) cout << ' ';\n        cout << grid0[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < D*D*D; ++i) {\n        if (i) cout << ' ';\n        cout << grid1[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge { int u, v; long long w; };\nstruct AdjEdge { int to; long long w; int id; };\nstruct Candidate { long long dist; int to; };\nstruct MoveCandidate {\n    long long approxDelta;\n    int resident;\n    int station;\n    long long dist;\n    int oldStation;\n};\n\nstruct Solver {\n    static constexpr long long INF64 = (1LL << 60);\n    static constexpr long long MAX_RAD_SQ = 5000LL * 5000LL;\n\n    const double TIME_LIMIT = 1.93;\n    const double RESTART_LIMIT = 1.70;\n\n    int N, M, K;\n    vector<long long> xs, ys;\n    vector<long long> ax, ay;\n    vector<Edge> edges;\n    vector<vector<AdjEdge>> graph;\n\n    vector<vector<long long>> distMat;\n    vector<vector<int>> parentEdge;\n    vector<vector<int>> parentVertex;\n\n    vector<vector<Candidate>> resCandidates;\n\n    vector<int> assignStation;\n    vector<long long> distAssigned;\n\n    vector<vector<int>> residentsOfStation;\n    vector<long long> maxDist;\n    vector<long long> secondMaxDist;\n    vector<int> maxCount;\n    vector<int> P;\n    vector<char> broadcast;\n\n    long long currentPcost = 0;\n    long long currentTreeCost = 0;\n\n    chrono::steady_clock::time_point startTime;\n    mt19937_64 rng;\n\n    inline double elapsedSeconds() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n    inline bool timeLimitExceeded() const {\n        return elapsedSeconds() > TIME_LIMIT;\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M >> K)) return;\n        startTime = chrono::steady_clock::now();\n        rng.seed(startTime.time_since_epoch().count());\n\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; ++i) cin >> xs[i] >> ys[i];\n\n        edges.resize(M);\n        graph.assign(N, {});\n        for (int j = 0; j < M; ++j) {\n            int u, v;\n            long long w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[j] = {u, v, w};\n            graph[u].push_back({v, w, j});\n            graph[v].push_back({u, w, j});\n        }\n\n        ax.resize(K);\n        ay.resize(K);\n        for (int i = 0; i < K; ++i) cin >> ax[i] >> ay[i];\n\n        computeAllPairs();\n        buildResidentCandidates();\n        initialAssignment();\n\n        residentsOfStation.assign(N, {});\n        maxDist.assign(N, 0);\n        secondMaxDist.assign(N, 0);\n        maxCount.assign(N, 0);\n        P.assign(N, 0);\n        broadcast.assign(N, 0);\n\n        rebuildAll();\n        localImprove();\n\n        vector<int> bestAssign = assignStation;\n        vector<long long> bestDist = distAssigned;\n        long long bestTotal = totalCost();\n\n        while (elapsedSeconds() < RESTART_LIMIT && !timeLimitExceeded()) {\n            assignStation = bestAssign;\n            distAssigned = bestDist;\n            rebuildAll();\n\n            bool strong = (rng() & 1);\n            int baseMoves = max(25, K / 45);\n            int moves = strong ? baseMoves * 2 : baseMoves;\n            perturbAssignments(moves, strong);\n            rebuildAll();\n            localImprove();\n\n            long long cur = totalCost();\n            if (cur < bestTotal) {\n                bestTotal = cur;\n                bestAssign = assignStation;\n                bestDist = distAssigned;\n            }\n            if (timeLimitExceeded()) break;\n        }\n\n        assignStation = bestAssign;\n        distAssigned = bestDist;\n        rebuildAll();\n\n        vector<int> edgeOn(M, 0);\n        buildFinalEdges(edgeOn);\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << P[i];\n        }\n        cout << '\\n';\n        for (int j = 0; j < M; ++j) {\n            if (j) cout << ' ';\n            cout << edgeOn[j];\n        }\n        cout << '\\n';\n    }\n\n    void computeAllPairs() {\n        distMat.assign(N, vector<long long>(N, INF64));\n        parentEdge.assign(N, vector<int>(N, -1));\n        parentVertex.assign(N, vector<int>(N, -1));\n        for (int s = 0; s < N; ++s) {\n            vector<long long> dist(N, INF64);\n            vector<int> prevE(N, -1), prevV(N, -1);\n            dist[s] = 0;\n            using Node = pair<long long, int>;\n            priority_queue<Node, vector<Node>, greater<Node>> pq;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [d, v] = pq.top();\n                pq.pop();\n                if (d != dist[v]) continue;\n                for (const auto &ed : graph[v]) {\n                    int to = ed.to;\n                    long long nd = d + ed.w;\n                    if (nd < dist[to]) {\n                        dist[to] = nd;\n                        prevE[to] = ed.id;\n                        prevV[to] = v;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n            distMat[s] = dist;\n            parentEdge[s] = prevE;\n            parentVertex[s] = prevV;\n        }\n    }\n\n    void buildResidentCandidates() {\n        resCandidates.assign(K, {});\n        vector<pair<long long, int>> tmp;\n        tmp.reserve(N);\n        for (int k = 0; k < K; ++k) {\n            tmp.clear();\n            for (int i = 0; i < N; ++i) {\n                long long dx = xs[i] - ax[k];\n                long long dy = ys[i] - ay[k];\n                long long d = dx * dx + dy * dy;\n                tmp.emplace_back(d, i);\n            }\n            sort(tmp.begin(), tmp.end());\n            vector<Candidate> cand;\n            cand.reserve(N);\n            bool hasWithin = false;\n            for (auto &p : tmp) {\n                if (p.first <= MAX_RAD_SQ) {\n                    cand.push_back({p.first, p.second});\n                    hasWithin = true;\n                } else if (hasWithin) break;\n            }\n            if (cand.empty()) cand.push_back({tmp[0].first, tmp[0].second});\n            resCandidates[k] = move(cand);\n        }\n    }\n\n    void initialAssignment() {\n        assignStation.resize(K);\n        distAssigned.resize(K);\n        for (int k = 0; k < K; ++k) {\n            const auto &cand = resCandidates[k];\n            assignStation[k] = cand[0].to;\n            long long d = cand[0].dist;\n            if (d > MAX_RAD_SQ) d = MAX_RAD_SQ;\n            distAssigned[k] = d;\n        }\n    }\n\n    int ceil_sqrt_ll(long long v) const {\n        if (v <= 0) return 0;\n        long double r = sqrt((long double)v);\n        long long x = (long long)r;\n        while (x * x < v) ++x;\n        while (x > 0 && (x - 1) * (x - 1) >= v) --x;\n        if (x > 5000) x = 5000;\n        return (int)x;\n    }\n\n    void rebuildAll() {\n        for (int i = 0; i < N; ++i) {\n            residentsOfStation[i].clear();\n            maxDist[i] = 0;\n            secondMaxDist[i] = 0;\n            maxCount[i] = 0;\n        }\n        for (int k = 0; k < K; ++k) {\n            int st = assignStation[k];\n            residentsOfStation[st].push_back(k);\n            long long d = distAssigned[k];\n            if (d > maxDist[st]) {\n                secondMaxDist[st] = maxDist[st];\n                maxDist[st] = d;\n                maxCount[st] = 1;\n            } else if (d == maxDist[st]) {\n                maxCount[st]++;\n            } else if (d > secondMaxDist[st]) {\n                secondMaxDist[st] = d;\n            }\n        }\n        currentPcost = 0;\n        for (int i = 0; i < N; ++i) {\n            if (!residentsOfStation[i].empty()) {\n                broadcast[i] = 1;\n                P[i] = ceil_sqrt_ll(maxDist[i]);\n            } else {\n                broadcast[i] = 0;\n                P[i] = 0;\n                maxDist[i] = secondMaxDist[i] = 0;\n                maxCount[i] = 0;\n            }\n            currentPcost += 1LL * P[i] * P[i];\n        }\n        currentTreeCost = computeCurrentMST();\n    }\n\n    long long computeMSTNodes(const vector<int> &nodes) {\n        if (nodes.size() <= 1) return 0;\n        vector<long long> key(nodes.size(), INF64);\n        vector<char> used(nodes.size(), false);\n        key[0] = 0;\n        long long total = 0;\n        for (size_t it = 0; it < nodes.size(); ++it) {\n            int u = -1;\n            long long best = INF64;\n            for (size_t i = 0; i < nodes.size(); ++i) {\n                if (!used[i] && key[i] < best) {\n                    best = key[i];\n                    u = (int)i;\n                }\n            }\n            if (u == -1) break;\n            used[u] = true;\n            total += key[u];\n            for (size_t v = 0; v < nodes.size(); ++v) {\n                if (used[v]) continue;\n                long long d = distMat[nodes[u]][nodes[v]];\n                if (d < key[v]) key[v] = d;\n            }\n        }\n        return total;\n    }\n\n    long long computeCurrentMST() {\n        vector<int> nodes;\n        nodes.reserve(N);\n        nodes.push_back(0);\n        for (int i = 1; i < N; ++i) if (broadcast[i]) nodes.push_back(i);\n        return computeMSTNodes(nodes);\n    }\n\n    long long maxAfterRemovingDist(int station, long long distVal) const {\n        if (!broadcast[station]) return 0;\n        if (distVal < maxDist[station]) return maxDist[station];\n        if (distVal == maxDist[station]) {\n            if (maxCount[station] >= 2) return maxDist[station];\n            return secondMaxDist[station];\n        }\n        return maxDist[station];\n    }\n\n    bool tryRemove(int s) {\n        if (!broadcast[s]) return false;\n        auto resList = residentsOfStation[s];\n        if (resList.empty()) return false;\n\n        vector<long long> tempMax = maxDist;\n        vector<int> tempP = P;\n        vector<int> chosenStation(resList.size(), -1);\n        vector<long long> chosenDist(resList.size(), 0);\n\n        vector<int> order(resList.size());\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            long long da = distAssigned[resList[a]];\n            long long db = distAssigned[resList[b]];\n            if (da != db) return da > db;\n            return resList[a] < resList[b];\n        });\n\n        for (int ordIdx : order) {\n            int rid = resList[ordIdx];\n            long long bestDelta = INF64;\n            int bestTarget = -1;\n            long long bestDist = 0;\n            long long bestNewMax = 0;\n            int bestNewP = 0;\n            for (const auto &cand : resCandidates[rid]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                int t = cand.to;\n                if (t == s) continue;\n                if (!broadcast[t]) continue;\n                long long curMax = tempMax[t];\n                int curP = tempP[t];\n                long long newMax = curMax;\n                int newP = curP;\n                if (cand.dist > newMax) {\n                    newMax = cand.dist;\n                    newP = ceil_sqrt_ll(newMax);\n                }\n                long long delta = 1LL * newP * newP - 1LL * curP * curP;\n                if (bestTarget == -1 || delta < bestDelta ||\n                    (delta == bestDelta && newMax < bestNewMax)) {\n                    bestDelta = delta;\n                    bestTarget = t;\n                    bestDist = cand.dist;\n                    bestNewMax = newMax;\n                    bestNewP = newP;\n                }\n            }\n            if (bestTarget == -1) return false;\n            chosenStation[ordIdx] = bestTarget;\n            chosenDist[ordIdx] = bestDist;\n            tempMax[bestTarget] = bestNewMax;\n            tempP[bestTarget] = bestNewP;\n        }\n\n        tempMax[s] = 0;\n        tempP[s] = 0;\n\n        vector<int> nodesAfter;\n        nodesAfter.reserve(N);\n        nodesAfter.push_back(0);\n        long long newPcost = 0;\n        for (int i = 0; i < N; ++i) {\n            newPcost += 1LL * tempP[i] * tempP[i];\n            if (i > 0 && tempP[i] > 0) nodesAfter.push_back(i);\n        }\n        long long newTree = computeMSTNodes(nodesAfter);\n        if (newPcost + newTree >= totalCost()) return false;\n\n        for (size_t idx = 0; idx < resList.size(); ++idx) {\n            assignStation[resList[idx]] = chosenStation[idx];\n            distAssigned[resList[idx]] = chosenDist[idx];\n        }\n        rebuildAll();\n        return true;\n    }\n\n    bool tryReassignAll() {\n        vector<int> newAssign(K);\n        vector<long long> newDist(K);\n        bool changed = false;\n        for (int r = 0; r < K; ++r) {\n            int bestStation = -1;\n            long long bestDist = 0;\n            for (const auto &cand : resCandidates[r]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                if (!broadcast[cand.to]) continue;\n                bestStation = cand.to;\n                bestDist = cand.dist;\n                break;\n            }\n            if (bestStation == -1) return false;\n            newAssign[r] = bestStation;\n            newDist[r] = bestDist;\n            if (bestStation != assignStation[r]) changed = true;\n        }\n        if (!changed) return false;\n\n        vector<long long> newMax(N, 0);\n        vector<int> counts(N, 0);\n        for (int r = 0; r < K; ++r) {\n            int st = newAssign[r];\n            ++counts[st];\n            if (newDist[r] > newMax[st]) newMax[st] = newDist[r];\n        }\n        vector<int> newP(N, 0);\n        vector<char> newBroadcast(N, 0);\n        long long newPcost = 0;\n        for (int i = 0; i < N; ++i) {\n            if (counts[i] > 0) {\n                newBroadcast[i] = 1;\n                newP[i] = ceil_sqrt_ll(newMax[i]);\n            } else {\n                newBroadcast[i] = 0;\n                newP[i] = 0;\n            }\n            newPcost += 1LL * newP[i] * newP[i];\n        }\n        vector<int> nodes;\n        nodes.reserve(N);\n        nodes.push_back(0);\n        for (int i = 1; i < N; ++i) if (newBroadcast[i]) nodes.push_back(i);\n        long long newTree = computeMSTNodes(nodes);\n        if (newPcost + newTree >= totalCost()) return false;\n\n        assignStation.swap(newAssign);\n        distAssigned.swap(newDist);\n        rebuildAll();\n        return true;\n    }\n\n    bool improveSingleFarMove() {\n        vector<int> order;\n        order.reserve(N);\n        for (int i = 0; i < N; ++i) if (broadcast[i]) order.push_back(i);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (P[a] != P[b]) return P[a] > P[b];\n            return residentsOfStation[a].size() > residentsOfStation[b].size();\n        });\n        for (int s : order) {\n            if ((int)residentsOfStation[s].size() <= 1) continue;\n            int farRes = -1;\n            long long farDist = -1;\n            for (int r : residentsOfStation[s]) {\n                if (distAssigned[r] > farDist) {\n                    farDist = distAssigned[r];\n                    farRes = r;\n                }\n            }\n            if (farRes == -1) continue;\n            long long newMaxS = maxAfterRemovingDist(s, distAssigned[farRes]);\n            int newPs = ceil_sqrt_ll(newMaxS);\n            long long bestDelta = 0;\n            int bestTarget = -1;\n            long long bestDist = 0;\n            for (const auto &cand : resCandidates[farRes]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                int t = cand.to;\n                if (t == s) continue;\n                if (!broadcast[t]) continue;\n                long long newMaxT = max(maxDist[t], cand.dist);\n                int newPt = ceil_sqrt_ll(newMaxT);\n                long long delta = 1LL * newPs * newPs + 1LL * newPt * newPt\n                                  - (1LL * P[s] * P[s] + 1LL * P[t] * P[t]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestTarget = t;\n                    bestDist = cand.dist;\n                }\n            }\n            if (bestTarget != -1) {\n                if (applyMoveSingle(farRes, bestTarget, bestDist)) return true;\n            }\n            if (timeLimitExceeded()) break;\n        }\n        return false;\n    }\n\n    bool tryResidentReassignActive() {\n        if (timeLimitExceeded()) return false;\n        vector<int> order(K);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n        const int MAX_ATTEMPTS = 400;\n        int attempts = 0;\n        for (int idx = 0; idx < K && attempts < MAX_ATTEMPTS; ++idx) {\n            if (timeLimitExceeded()) break;\n            int r = order[idx];\n            int s = assignStation[r];\n            long long distR = distAssigned[r];\n            for (const auto &cand : resCandidates[r]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                int t = cand.to;\n                if (t == s) continue;\n                if (!broadcast[t]) continue;\n                long long newMaxS = maxAfterRemovingDist(s, distR);\n                int newPs = ceil_sqrt_ll(newMaxS);\n                long long dAdd = min(cand.dist, MAX_RAD_SQ);\n                long long newMaxT = max(maxDist[t], dAdd);\n                int newPt = ceil_sqrt_ll(newMaxT);\n                long long delta = 1LL * newPs * newPs + 1LL * newPt * newPt\n                                  - (1LL * P[s] * P[s] + 1LL * P[t] * P[t]);\n                if (delta < 0) {\n                    if (applyMoveSingle(r, t, dAdd)) {\n                        ++attempts;\n                        break;\n                    }\n                }\n                if (timeLimitExceeded()) break;\n            }\n        }\n        return attempts > 0;\n    }\n\n    bool optimizeExisting() {\n        bool overall = false;\n        while (!timeLimitExceeded()) {\n            bool changed = false;\n            while (!timeLimitExceeded()) {\n                vector<int> order;\n                order.reserve(N);\n                for (int i = 0; i < N; ++i) if (broadcast[i]) order.push_back(i);\n                sort(order.begin(), order.end(), [&](int a, int b) {\n                    if (residentsOfStation[a].size() != residentsOfStation[b].size())\n                        return residentsOfStation[a].size() < residentsOfStation[b].size();\n                    if (P[a] != P[b]) return P[a] < P[b];\n                    return a < b;\n                });\n                bool removed = false;\n                for (int s : order) {\n                    if (tryRemove(s)) {\n                        changed = true;\n                        removed = true;\n                        break;\n                    }\n                    if (timeLimitExceeded()) break;\n                }\n                if (!removed) break;\n            }\n            if (timeLimitExceeded()) break;\n            if (tryReassignAll()) changed = true;\n            if (timeLimitExceeded()) break;\n            if (improveSingleFarMove()) changed = true;\n            if (timeLimitExceeded()) break;\n            if (tryResidentReassignActive()) changed = true;\n            if (!changed) break;\n            overall = true;\n        }\n        return overall;\n    }\n\n    long long totalCost() const {\n        return currentPcost + currentTreeCost;\n    }\n\n    bool applyMoveSingle(int resident, int targetStation, long long distSq) {\n        int prevStation = assignStation[resident];\n        long long prevDist = distAssigned[resident];\n        if (prevStation == targetStation) return false;\n        long long oldCost = totalCost();\n        if (distSq > MAX_RAD_SQ) distSq = MAX_RAD_SQ;\n        assignStation[resident] = targetStation;\n        distAssigned[resident] = distSq;\n        rebuildAll();\n        if (totalCost() < oldCost) {\n            return true;\n        } else {\n            assignStation[resident] = prevStation;\n            distAssigned[resident] = prevDist;\n            rebuildAll();\n            return false;\n        }\n    }\n\n    void computeActiveDistances(vector<long long> &minToActive, vector<long long> &minExcl) {\n        vector<int> activeNodes;\n        activeNodes.reserve(N);\n        activeNodes.push_back(0);\n        for (int i = 1; i < N; ++i) if (broadcast[i]) activeNodes.push_back(i);\n\n        minToActive.assign(N, INF64);\n        for (int i = 0; i < N; ++i) {\n            long long best = INF64;\n            for (int v : activeNodes) {\n                long long d = distMat[i][v];\n                if (d < best) best = d;\n            }\n            minToActive[i] = best;\n        }\n\n        minExcl.assign(N, INF64);\n        for (int node : activeNodes) {\n            long long best = INF64;\n            for (int v : activeNodes) {\n                if (v == node) continue;\n                long long d = distMat[node][v];\n                if (d < best) best = d;\n            }\n            if (node == 0 && best == INF64) best = 0;\n            minExcl[node] = best;\n        }\n        for (int i = 0; i < N; ++i)\n            if (minExcl[i] == INF64) minExcl[i] = minToActive[i];\n    }\n\n    bool tryActivateStations() {\n        bool overall = false;\n        const int MAX_CAND_PER_RES = 6;\n        const int MAX_ATTEMPTS = 80;\n        while (!timeLimitExceeded()) {\n            vector<long long> minDistToActive, minDistExcl;\n            computeActiveDistances(minDistToActive, minDistExcl);\n\n            vector<MoveCandidate> candidates;\n            candidates.reserve(K * MAX_CAND_PER_RES);\n            for (int r = 0; r < K; ++r) {\n                int oldS = assignStation[r];\n                long long newMaxWithout = maxAfterRemovingDist(oldS, distAssigned[r]);\n                int newPOld = ceil_sqrt_ll(newMaxWithout);\n                long long newPOldSq = 1LL * newPOld * newPOld;\n                long long oldPOldSq = 1LL * P[oldS] * P[oldS];\n                long long removalGain = 0;\n                if (oldS != 0 && (int)residentsOfStation[oldS].size() == 1) {\n                    removalGain = minDistExcl[oldS];\n                }\n                int used = 0;\n                for (const auto &cand : resCandidates[r]) {\n                    if (cand.dist > MAX_RAD_SQ) break;\n                    int s = cand.to;\n                    if (broadcast[s]) continue;\n                    long long hook = minDistToActive[s];\n                    if (hook >= INF64 / 4) continue;\n                    int newPs = ceil_sqrt_ll(cand.dist);\n                    long long newPsSq = 1LL * newPs * newPs;\n                    long long approx = hook - removalGain + (newPsSq + newPOldSq - oldPOldSq);\n                    candidates.push_back({approx, r, s, cand.dist, oldS});\n                    if (++used >= MAX_CAND_PER_RES) break;\n                }\n            }\n            if (candidates.empty()) break;\n            sort(candidates.begin(), candidates.end(), [](const MoveCandidate &a, const MoveCandidate &b) {\n                if (a.approxDelta != b.approxDelta) return a.approxDelta < b.approxDelta;\n                if (a.resident != b.resident) return a.resident < b.resident;\n                return a.station < b.station;\n            });\n            bool applied = false;\n            int attempts = 0;\n            for (const auto &cand : candidates) {\n                if (cand.approxDelta >= 0) break;\n                if (assignStation[cand.resident] != cand.oldStation) continue;\n                if (broadcast[cand.station]) continue;\n                if (cand.dist > MAX_RAD_SQ) continue;\n                ++attempts;\n                if (attempts > MAX_ATTEMPTS) break;\n                if (applyMoveSingle(cand.resident, cand.station, cand.dist)) {\n                    overall = true;\n                    applied = true;\n                    break;\n                }\n                if (timeLimitExceeded()) break;\n            }\n            if (!applied || timeLimitExceeded()) break;\n        }\n        return overall;\n    }\n\n    void localImprove() {\n        while (!timeLimitExceeded()) {\n            bool changed = false;\n            if (optimizeExisting()) changed = true;\n            if (timeLimitExceeded()) break;\n            if (tryActivateStations()) changed = true;\n            if (!changed) break;\n        }\n    }\n\n    void perturbAssignments(int moves, bool strong) {\n        uniform_int_distribution<int> resDist(0, K - 1);\n        for (int it = 0; it < moves; ++it) {\n            int r = resDist(rng);\n            auto &cand = resCandidates[r];\n            if (cand.empty()) continue;\n            int limit = strong ? min<int>(cand.size(), 12) : min<int>(cand.size(), 6);\n            if (limit == 0) continue;\n            uniform_int_distribution<int> idxDist(0, limit - 1);\n            int idx = idxDist(rng);\n            assignStation[r] = cand[idx].to;\n            distAssigned[r] = min(cand[idx].dist, MAX_RAD_SQ);\n        }\n        if (strong) {\n            vector<int> act;\n            for (int i = 0; i < N; ++i)\n                if (broadcast[i] && residentsOfStation[i].size() >= 2) act.push_back(i);\n            if (!act.empty()) {\n                uniform_int_distribution<int> stDist(0, (int)act.size() - 1);\n                int pick = act[stDist(rng)];\n                for (int rid : residentsOfStation[pick]) {\n                    auto &cand = resCandidates[rid];\n                    if (cand.size() <= 1) continue;\n                    vector<int> opts;\n                    for (size_t idx = 1; idx < cand.size() && idx < 10; ++idx)\n                        if (cand[idx].to != assignStation[rid]) opts.push_back(idx);\n                    if (opts.empty()) continue;\n                    uniform_int_distribution<int> optDist(0, (int)opts.size() - 1);\n                    int idx = opts[optDist(rng)];\n                    assignStation[rid] = cand[idx].to;\n                    distAssigned[rid] = min(cand[idx].dist, MAX_RAD_SQ);\n                }\n            }\n        }\n    }\n\n    void recomputeSP(int s) {\n        vector<long long> dist(N, INF64);\n        vector<int> prevE(N, -1), prevV(N, -1);\n        dist[s] = 0;\n        using Node = pair<long long, int>;\n        priority_queue<Node, vector<Node>, greater<Node>> pq;\n        pq.push({0, s});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            for (const auto &ed : graph[v]) {\n                int to = ed.to;\n                long long nd = d + ed.w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    prevE[to] = ed.id;\n                    prevV[to] = v;\n                    pq.push({nd, to});\n                }\n            }\n        }\n        distMat[s] = dist;\n        parentEdge[s] = prevE;\n        parentVertex[s] = prevV;\n    }\n\n    bool followPath(int source, int target, vector<int> &edgeOn) {\n        int cur = target;\n        while (cur != source) {\n            int e = parentEdge[source][cur];\n            int pv = parentVertex[source][cur];\n            if (e == -1 || pv == -1) return false;\n            edgeOn[e] = 1;\n            cur = pv;\n        }\n        return true;\n    }\n\n    void addPath(int source, int target, vector<int> &edgeOn) {\n        if (source == target) return;\n        if (!followPath(source, target, edgeOn)) {\n            recomputeSP(source);\n            followPath(source, target, edgeOn);\n        }\n    }\n\n    vector<char> computeReachable(const vector<int> &edgeOn) {\n        vector<char> vis(N, 0);\n        queue<int> q;\n        vis[0] = 1;\n        q.push(0);\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            for (const auto &ed : graph[v]) {\n                if (!edgeOn[ed.id]) continue;\n                if (!vis[ed.to]) {\n                    vis[ed.to] = 1;\n                    q.push(ed.to);\n                }\n            }\n        }\n        return vis;\n    }\n\n    void buildFinalEdges(vector<int> &edgeOn) {\n        fill(edgeOn.begin(), edgeOn.end(), 0);\n        vector<int> nodes;\n        nodes.reserve(N);\n        nodes.push_back(0);\n        for (int i = 1; i < N; ++i) if (broadcast[i]) nodes.push_back(i);\n        if (nodes.size() <= 1) return;\n\n        int T = nodes.size();\n        vector<long long> key(T, INF64);\n        vector<int> parent(T, -1);\n        vector<char> used(T, false);\n        key[0] = 0;\n        for (int iter = 0; iter < T; ++iter) {\n            int u = -1;\n            long long best = INF64;\n            for (int i = 0; i < T; ++i) {\n                if (!used[i] && key[i] < best) {\n                    best = key[i];\n                    u = i;\n                }\n            }\n            if (u == -1) break;\n            used[u] = true;\n            if (parent[u] != -1) {\n                addPath(nodes[u], nodes[parent[u]], edgeOn);\n            }\n            for (int v = 0; v < T; ++v) {\n                if (used[v]) continue;\n                long long d = distMat[nodes[u]][nodes[v]];\n                if (d < key[v]) {\n                    key[v] = d;\n                    parent[v] = u;\n                }\n            }\n        }\n\n        auto vis = computeReachable(edgeOn);\n        for (int node : nodes) {\n            if (!vis[node]) {\n                addPath(0, node, edgeOn);\n                vis = computeReachable(edgeOn);\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 30;\nconstexpr int TOTAL = N * (N + 1) / 2;\nconstexpr int LIMIT = 10000;\nusing Tri = vector<vector<int>>;\n\nstruct Result {\n    vector<array<int, 4>> ops;\n    Tri board;\n};\n\ninline bool inRange(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y <= x;\n}\n\nbool adjacent(int x1, int y1, int x2, int y2) {\n    if (!inRange(x1, y1) || !inRange(x2, y2)) return false;\n    if (x1 == x2) return abs(y1 - y2) == 1;\n    if (x1 + 1 == x2) return (y1 == y2) || (y1 == y2 - 1);\n    if (x2 + 1 == x1) return (y2 == y1) || (y2 == y1 - 1);\n    return false;\n}\n\nint countViolations(const Tri& a) {\n    int cnt = 0;\n    for (int x = 0; x < N - 1; ++x)\n        for (int y = 0; y <= x; ++y) {\n            if (a[x][y] > a[x + 1][y]) ++cnt;\n            if (a[x][y] > a[x + 1][y + 1]) ++cnt;\n        }\n    return cnt;\n}\n\nbool applyOps(const Tri& initial, const vector<array<int, 4>>& ops, Tri& board) {\n    if ((int)ops.size() > LIMIT) return false;\n    board = initial;\n    for (const auto& op : ops) {\n        int x1 = op[0], y1 = op[1], x2 = op[2], y2 = op[3];\n        if (!adjacent(x1, y1, x2, y2)) return false;\n        swap(board[x1][y1], board[x2][y2]);\n    }\n    return true;\n}\n\nbool ensureValid(Result& res, const Tri& initial) {\n    Tri board;\n    if (!applyOps(initial, res.ops, board)) return false;\n    if (countViolations(board) != 0) return false;\n    res.board = move(board);\n    return true;\n}\n\nResult runBaseline(const Tri& initial) {\n    Result res;\n    res.board = initial;\n    res.ops.reserve(5000);\n    auto swapBall = [&](int x1, int y1, int x2, int y2) {\n        res.ops.push_back({x1, y1, x2, y2});\n        swap(res.board[x1][y1], res.board[x2][y2]);\n    };\n    for (int x = N - 2; x >= 0; --x) {\n        for (int y = 0; y <= x; ++y) {\n            int cx = x, cy = y;\n            while (cx < N - 1) {\n                int left = res.board[cx + 1][cy];\n                int right = res.board[cx + 1][cy + 1];\n                int mn = min(left, right);\n                if (res.board[cx][cy] <= mn) break;\n                int ny = (left < right ? cy : cy + 1);\n                swapBall(cx, cy, cx + 1, ny);\n                ++cx;\n                cy = ny;\n            }\n        }\n    }\n    return res;\n}\n\nstruct XorShift {\n    uint64_t state;\n    explicit XorShift(uint64_t seed) : state(seed ? seed : 1) {}\n    uint32_t next() {\n        uint64_t x = state;\n        x ^= x << 7;\n        x ^= x >> 9;\n        return state = x;\n    }\n};\n\nbool runPriorityFix(const Tri& startBoard, int upperBound, Result& out, XorShift& rng, int mode) {\n    if (upperBound <= 0) return false;\n    upperBound = min(upperBound, LIMIT);\n    Tri board = startBoard;\n    vector<array<int, 4>> ops;\n    ops.reserve(upperBound);\n\n    auto calcPriority = [&](int x, int diff) -> int {\n        int depth = N - 1 - x;\n        switch (mode % 8) {\n            case 0: return diff;\n            case 1: return diff * (depth + 1);\n            case 2: return diff * (depth + 1) + depth;\n            case 3: return diff * (depth + 1) * (depth + 1);\n            case 4: return diff * 2 + depth;\n            case 5: return diff * (depth + 2);\n            case 6: return diff * (depth + 1) + diff;\n            case 7: return diff + depth;\n            default: return diff;\n        }\n    };\n\n    struct Node {\n        int pri, x, y;\n        uint32_t rd;\n        bool operator<(const Node& other) const {\n            if (pri != other.pri) return pri < other.pri;\n            return rd < other.rd;\n        }\n    };\n    priority_queue<Node> pq;\n\n    auto pushNode = [&](int x, int y) {\n        if (x < 0 || x >= N - 1 || y < 0 || y > x) return;\n        int left = board[x + 1][y];\n        int right = board[x + 1][y + 1];\n        int diff = board[x][y] - min(left, right);\n        if (diff > 0) {\n            int pri = calcPriority(x, diff);\n            pq.push(Node{pri, x, y, rng.next()});\n        }\n    };\n\n    for (int x = 0; x < N - 1; ++x)\n        for (int y = 0; y <= x; ++y)\n            pushNode(x, y);\n\n    while (!pq.empty()) {\n        if ((int)ops.size() >= upperBound) return false;\n        Node cur = pq.top();\n        pq.pop();\n        int x = cur.x, y = cur.y;\n        if (x >= N - 1) continue;\n        int left = board[x + 1][y];\n        int right = board[x + 1][y + 1];\n        int mn = min(left, right);\n        if (board[x][y] <= mn) continue;\n        int childY = (left == right) ? ((rng.next() & 1) ? y : y + 1)\n                                     : (left < right ? y : y + 1);\n        int cx = x + 1, cy = childY;\n        ops.push_back({x, y, cx, cy});\n        swap(board[x][y], board[cx][cy]);\n        pushNode(x, y);\n        pushNode(cx, cy);\n        pushNode(x - 1, y - 1);\n        pushNode(x - 1, y);\n        if (childY == y) pushNode(x, y - 1);\n        else pushNode(x, y + 1);\n    }\n\n    if ((int)ops.size() >= upperBound) return false;\n    if (countViolations(board) != 0) return false;\n    out.board = move(board);\n    out.ops = move(ops);\n    return true;\n}\n\noptional<Result> preArrangeSimple(const Tri& start, int depth, int limit,\n                                  const vector<vector<int>>& adj,\n                                  const vector<pair<int, int>>& idx2coord,\n                                  const vector<vector<int>>& idxOf) {\n    if (limit <= 0) return nullopt;\n    depth = min(depth, N - 1);\n    vector<int> targets;\n    for (int x = 0; x <= depth && x < N; ++x)\n        for (int y = 0; y <= x; ++y)\n            targets.push_back(idxOf[x][y]);\n\n    Tri board = start;\n    vector<array<int, 4>> ops;\n    vector<char> blocked(TOTAL, false);\n    vector<int> parent(TOTAL, -1);\n    vector<char> visited(TOTAL, 0);\n\n    for (int target : targets) {\n        if ((int)ops.size() >= limit) return nullopt;\n        int bestIdx = -1;\n        int bestVal = INT_MAX;\n        for (int idx = 0; idx < TOTAL; ++idx) {\n            if (blocked[idx]) continue;\n            auto [x, y] = idx2coord[idx];\n            int val = board[x][y];\n            if (val < bestVal) {\n                bestVal = val;\n                bestIdx = idx;\n            }\n        }\n        if (bestIdx == -1) break;\n        if (bestIdx != target) {\n            fill(parent.begin(), parent.end(), -1);\n            fill(visited.begin(), visited.end(), 0);\n            queue<int> q;\n            visited[bestIdx] = 1;\n            parent[bestIdx] = -2;\n            q.push(bestIdx);\n            bool found = false;\n            while (!q.empty()) {\n                int v = q.front();\n                q.pop();\n                if (v == target) {\n                    found = true;\n                    break;\n                }\n                for (int nv : adj[v]) {\n                    if (visited[nv]) continue;\n                    if (blocked[nv] && nv != target) continue;\n                    visited[nv] = 1;\n                    parent[nv] = v;\n                    q.push(nv);\n                }\n            }\n            if (!found) return nullopt;\n            vector<int> path;\n            for (int cur = target; cur != -2; cur = parent[cur])\n                path.push_back(cur);\n            reverse(path.begin(), path.end());\n            if ((int)ops.size() + (int)path.size() - 1 > limit)\n                return nullopt;\n            for (size_t i = 0; i + 1 < path.size(); ++i) {\n                int u = path[i], v = path[i + 1];\n                auto [x1, y1] = idx2coord[u];\n                auto [x2, y2] = idx2coord[v];\n                ops.push_back({x1, y1, x2, y2});\n                swap(board[x1][y1], board[x2][y2]);\n            }\n        }\n        blocked[target] = true;\n    }\n\n    Result res;\n    res.board = move(board);\n    res.ops = move(ops);\n    return res;\n}\n\noptional<Result> preArrangeSmart(const Tri& start, int depth, int limit,\n                                 int candLimit, int baseRankWeight,\n                                 const vector<vector<int>>& adj,\n                                 const vector<pair<int, int>>& idx2coord,\n                                 const vector<vector<int>>& idxOf) {\n    if (limit <= 0 || candLimit <= 0) return nullopt;\n    depth = min(depth, N - 1);\n    vector<int> targets;\n    for (int x = 0; x <= depth && x < N; ++x)\n        for (int y = 0; y <= x; ++y)\n            targets.push_back(idxOf[x][y]);\n\n    Tri board = start;\n    vector<array<int, 4>> ops;\n    vector<char> blocked(TOTAL, false);\n    vector<int> dist(TOTAL), parent(TOTAL);\n    vector<int> order(TOTAL);\n    iota(order.begin(), order.end(), 0);\n    const int INF = 1e9;\n\n    for (int targetIdx : targets) {\n        if ((int)ops.size() >= limit) return nullopt;\n\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            auto [xa, ya] = idx2coord[a];\n            auto [xb, yb] = idx2coord[b];\n            return board[xa][ya] < board[xb][yb];\n        });\n\n        fill(dist.begin(), dist.end(), INF);\n        fill(parent.begin(), parent.end(), -1);\n        queue<int> q;\n        dist[targetIdx] = 0;\n        parent[targetIdx] = -2;\n        q.push(targetIdx);\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (blocked[v] && v != targetIdx) continue;\n                if (dist[v] != INF) continue;\n                dist[v] = dist[u] + 1;\n                parent[v] = u;\n                q.push(v);\n            }\n        }\n\n        vector<pair<int, int>> options;\n        int rank = 0;\n        for (int idx : order) {\n            if (blocked[idx]) continue;\n            if (dist[idx] != INF) {\n                options.push_back({idx, rank});\n                if ((int)options.size() >= candLimit) break;\n            }\n            ++rank;\n        }\n        if (options.empty()) return nullopt;\n        auto [tx, ty] = idx2coord[targetIdx];\n        int rankWeight = max(1, baseRankWeight * (depth - tx + 1));\n        int selected = -1;\n        long long bestScore = (1LL << 60);\n        for (auto [candIdx, candRank] : options) {\n            long long score = 1LL * dist[candIdx] + 1LL * rankWeight * candRank;\n            if (score < bestScore) {\n                bestScore = score;\n                selected = candIdx;\n            }\n        }\n        if (selected == -1) return nullopt;\n\n        vector<int> path;\n        int cur = selected;\n        path.push_back(cur);\n        while (cur != targetIdx) {\n            cur = parent[cur];\n            if (cur < 0) return nullopt;\n            path.push_back(cur);\n        }\n\n        for (size_t i = 0; i + 1 < path.size(); ++i) {\n            int u = path[i], v = path[i + 1];\n            auto [x1, y1] = idx2coord[u];\n            auto [x2, y2] = idx2coord[v];\n            if ((int)ops.size() >= limit) return nullopt;\n            ops.push_back({x1, y1, x2, y2});\n            swap(board[x1][y1], board[x2][y2]);\n        }\n        blocked[targetIdx] = true;\n    }\n\n    Result res;\n    res.board = move(board);\n    res.ops = move(ops);\n    return res;\n}\n\nstruct StagePlan {\n    int depth;\n    int stageLimit;\n    int candLimit;\n    int baseRank;\n};\n\noptional<Result> preArrangeStaged(const Tri& start, int totalLimit,\n                                  const vector<StagePlan>& stages,\n                                  const vector<vector<int>>& adj,\n                                  const vector<pair<int, int>>& idx2coord,\n                                  const vector<vector<int>>& idxOf) {\n    if (totalLimit <= 0) return nullopt;\n    Tri board = start;\n    vector<array<int, 4>> ops;\n    for (const auto& st : stages) {\n        if ((int)ops.size() >= totalLimit) return nullopt;\n        int stageCap = min(st.stageLimit, totalLimit - (int)ops.size());\n        if (stageCap <= 0) return nullopt;\n        auto sub = preArrangeSmart(board, st.depth, stageCap,\n                                   st.candLimit, st.baseRank,\n                                   adj, idx2coord, idxOf);\n        if (!sub) return nullopt;\n        if ((int)ops.size() + (int)sub->ops.size() > totalLimit) return nullopt;\n        ops.insert(ops.end(), sub->ops.begin(), sub->ops.end());\n        board = sub->board;\n    }\n    Result res;\n    res.board = move(board);\n    res.ops = move(ops);\n    return res;\n}\n\noptional<Result> preArrangeBottomSmart(const Tri& start, int depth, int limit,\n                                       int candLimit, int baseRankWeight,\n                                       const vector<vector<int>>& adj,\n                                       const vector<pair<int, int>>& idx2coord,\n                                       const vector<vector<int>>& idxOf) {\n    if (limit <= 0 || candLimit <= 0) return nullopt;\n    depth = max(1, min(depth, N));\n    int startX = max(0, N - depth);\n    vector<int> targets;\n    for (int x = N - 1; x >= startX; --x)\n        for (int y = 0; y <= x; ++y)\n            targets.push_back(idxOf[x][y]);\n\n    Tri board = start;\n    vector<array<int, 4>> ops;\n    vector<char> blocked(TOTAL, false);\n    vector<int> dist(TOTAL), parent(TOTAL);\n    vector<int> order(TOTAL);\n    iota(order.begin(), order.end(), 0);\n    const int INF = 1e9;\n\n    for (int targetIdx : targets) {\n        if ((int)ops.size() >= limit) return nullopt;\n\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            auto [xa, ya] = idx2coord[a];\n            auto [xb, yb] = idx2coord[b];\n            return board[xa][ya] > board[xb][yb];\n        });\n\n        fill(dist.begin(), dist.end(), INF);\n        fill(parent.begin(), parent.end(), -1);\n        queue<int> q;\n        dist[targetIdx] = 0;\n        parent[targetIdx] = -2;\n        q.push(targetIdx);\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (blocked[v] && v != targetIdx) continue;\n                if (dist[v] != INF) continue;\n                dist[v] = dist[u] + 1;\n                parent[v] = u;\n                q.push(v);\n            }\n        }\n\n        vector<pair<int, int>> options;\n        int rank = 0;\n        for (int idx : order) {\n            if (blocked[idx]) continue;\n            if (dist[idx] != INF) {\n                options.push_back({idx, rank});\n                if ((int)options.size() >= candLimit) break;\n            }\n            ++rank;\n        }\n        if (options.empty()) return nullopt;\n\n        auto [tx, ty] = idx2coord[targetIdx];\n        int depthWeight = (tx - startX + 1);\n        int rankWeight = max(1, baseRankWeight * depthWeight);\n        int selected = -1;\n        long long bestScore = (1LL << 60);\n        for (auto [candIdx, candRank] : options) {\n            long long score = 1LL * dist[candIdx] + 1LL * rankWeight * candRank;\n            if (score < bestScore) {\n                bestScore = score;\n                selected = candIdx;\n            }\n        }\n        if (selected == -1) return nullopt;\n\n        vector<int> path;\n        int cur = selected;\n        path.push_back(cur);\n        while (cur != targetIdx) {\n            cur = parent[cur];\n            if (cur < 0) return nullopt;\n            path.push_back(cur);\n        }\n\n        for (size_t i = 0; i + 1 < path.size(); ++i) {\n            int u = path[i], v = path[i + 1];\n            auto [x1, y1] = idx2coord[u];\n            auto [x2, y2] = idx2coord[v];\n            if ((int)ops.size() >= limit) return nullopt;\n            ops.push_back({x1, y1, x2, y2});\n            swap(board[x1][y1], board[x2][y2]);\n        }\n        blocked[targetIdx] = true;\n    }\n\n    Result res;\n    res.board = move(board);\n    res.ops = move(ops);\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Tri initial(N);\n    for (int x = 0; x < N; ++x) {\n        initial[x].resize(x + 1);\n        for (int y = 0; y <= x; ++y)\n            cin >> initial[x][y];\n    }\n\n    vector<vector<int>> idxOf(N);\n    vector<pair<int, int>> idx2coord(TOTAL);\n    int cur = 0;\n    for (int x = 0; x < N; ++x) {\n        idxOf[x].resize(x + 1);\n        for (int y = 0; y <= x; ++y) {\n            idxOf[x][y] = cur;\n            idx2coord[cur] = {x, y};\n            ++cur;\n        }\n    }\n\n    vector<vector<int>> adj(TOTAL);\n    for (int x = 0; x < N; ++x)\n        for (int y = 0; y <= x; ++y) {\n            int idx = idxOf[x][y];\n            auto add = [&](int nx, int ny) {\n                if (inRange(nx, ny))\n                    adj[idx].push_back(idxOf[nx][ny]);\n            };\n            add(x - 1, y - 1);\n            add(x - 1, y);\n            add(x, y - 1);\n            add(x, y + 1);\n            add(x + 1, y);\n            add(x + 1, y + 1);\n        }\n\n    Result baseline = runBaseline(initial);\n    ensureValid(baseline, initial);\n    Result best = baseline;\n    int bestK = best.ops.size();\n\n    uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n    seed ^= (uint64_t)initial[0][0] << 21;\n    XorShift rng(seed);\n\n    const double TIME_LIMIT = 1.88;\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n\n    vector<int> modes = {0, 1, 2, 3, 4, 5, 6, 7};\n\n    auto tryPriority = [&](const Tri& startBoard, const vector<array<int, 4>>& prefixOps, int maxAttempts) {\n        for (int t = 0; t < maxAttempts; ++t) {\n            if (elapsed() > TIME_LIMIT) break;\n            int remaining = bestK - (int)prefixOps.size();\n            if (remaining <= 1) break;\n            int bound = remaining - 1;\n            Result suffix;\n            int mode = modes[(rng.next() + t) % modes.size()];\n            if (runPriorityFix(startBoard, bound, suffix, rng, mode)) {\n                int total = prefixOps.size() + suffix.ops.size();\n                if (total >= bestK) continue;\n                Result cand;\n                cand.board = suffix.board;\n                cand.ops.reserve(total);\n                cand.ops.insert(cand.ops.end(), prefixOps.begin(), prefixOps.end());\n                cand.ops.insert(cand.ops.end(), suffix.ops.begin(), suffix.ops.end());\n                if (ensureValid(cand, initial)) {\n                    best = move(cand);\n                    bestK = best.ops.size();\n                }\n            }\n        }\n    };\n\n    tryPriority(initial, {}, 500);\n\n    auto processPre = [&](const Result& pre, int attemptsPriority) {\n        if ((int)pre.ops.size() >= bestK) return;\n        if (countViolations(pre.board) == 0) {\n            Result cand = pre;\n            if ((int)cand.ops.size() < bestK && ensureValid(cand, initial)) {\n                best = move(cand);\n                bestK = best.ops.size();\n            }\n        }\n        if (elapsed() > TIME_LIMIT) return;\n\n        Result baseAfterPre = runBaseline(pre.board);\n        int totalOps = pre.ops.size() + baseAfterPre.ops.size();\n        if (totalOps < bestK && totalOps <= LIMIT) {\n            Result cand;\n            cand.board = baseAfterPre.board;\n            cand.ops.reserve(totalOps);\n            cand.ops.insert(cand.ops.end(), pre.ops.begin(), pre.ops.end());\n            cand.ops.insert(cand.ops.end(), baseAfterPre.ops.begin(), baseAfterPre.ops.end());\n            if (ensureValid(cand, initial)) {\n                best = move(cand);\n                bestK = best.ops.size();\n            }\n        }\n        tryPriority(pre.board, pre.ops, attemptsPriority);\n    };\n\n    vector<int> simpleDepths = {4, 6, 8};\n    for (int depth : simpleDepths) {\n        if (elapsed() > TIME_LIMIT) break;\n        int limitForPre = bestK - 1;\n        if (limitForPre <= 0) break;\n        auto preOpt = preArrangeSimple(initial, depth, limitForPre, adj, idx2coord, idxOf);\n        if (preOpt) processPre(*preOpt, 90);\n    }\n\n    vector<int> smartDepths = {5, 6, 7, 8, 9, 10};\n    vector<pair<int, int>> smartParams = {{25, 3}, {30, 4}};\n    for (int depth : smartDepths) {\n        if (elapsed() > TIME_LIMIT) break;\n        for (auto [candLim, baseRank] : smartParams) {\n            if (elapsed() > TIME_LIMIT) break;\n            int limitForPre = bestK - 1;\n            if (limitForPre <= 0) break;\n            auto preOpt = preArrangeSmart(initial, depth, limitForPre,\n                                          candLim, baseRank, adj, idx2coord, idxOf);\n            if (preOpt) processPre(*preOpt, 130);\n        }\n    }\n\n    vector<vector<StagePlan>> stagePlans = {\n        {{4, 220, 18, 3}, {7, 360, 24, 4}},\n        {{5, 240, 18, 3}, {8, 360, 26, 4}},\n        {{4, 180, 16, 3}, {6, 220, 20, 3}, {9, 360, 28, 4}},\n        {{5, 200, 18, 3}, {7, 260, 22, 4}, {10, 360, 30, 5}}\n    };\n\n    for (const auto& plan : stagePlans) {\n        if (elapsed() > TIME_LIMIT) break;\n        int limitForPre = bestK - 1;\n        if (limitForPre <= 0) break;\n        auto preOpt = preArrangeStaged(initial, limitForPre, plan, adj, idx2coord, idxOf);\n        if (preOpt) processPre(*preOpt, 150);\n    }\n\n    vector<int> bottomDepths = {3, 4, 5};\n    vector<pair<int, int>> bottomParams = {{25, 3}, {30, 4}};\n    for (int depth : bottomDepths) {\n        if (elapsed() > TIME_LIMIT) break;\n        for (auto [candLim, baseRank] : bottomParams) {\n            if (elapsed() > TIME_LIMIT) break;\n            int limitForPre = bestK - 1;\n            if (limitForPre <= 0) break;\n            auto preOpt = preArrangeBottomSmart(initial, depth, limitForPre,\n                                                candLim, baseRank,\n                                                adj, idx2coord, idxOf);\n            if (preOpt) processPre(*preOpt, 110);\n        }\n    }\n\n    if (!ensureValid(best, initial)) {\n        best = baseline;\n        ensureValid(best, initial);\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (const auto& op : best.ops)\n        cout << op[0] << ' ' << op[1] << ' ' << op[2] << ' ' << op[3] << '\\n';\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int DX[4] = {1, -1, 0, 0};\nconst int DY[4] = {0, 0, 1, -1};\n\nconst int EMPTY     = -1;\nconst int ENTRANCE  = -2;\nconst int OBSTACLE  = -3;\nconst int TEMPBLOCK = -4;\n\nint D;\nint entrance_i, entrance_j;\nvector<vector<int>> grid;\nvector<vector<int>> dist_from_entrance;\nvector<pair<int,int>> target_order;\nvector<vector<int>> target_rank;\nvector<int> remaining_small;   // unseen IDs prefix counts\nvector<int> empty_prefix;      // empty ranks prefix counts\nint total_cells = 0;\nint empty_cells_remaining = 0;\nlong long tie_counter = 0;\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < D && 0 <= y && y < D;\n}\n\nvector<vector<int>> compute_dist(const vector<vector<int>>& base_grid) {\n    const int INF = 1e9;\n    vector<vector<int>> dist(D, vector<int>(D, INF));\n    queue<pair<int,int>> q;\n    q.push({entrance_i, entrance_j});\n    dist[entrance_i][entrance_j] = 0;\n    while (!q.empty()) {\n        auto [x, y] = q.front(); q.pop();\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = x + DX[dir];\n            int ny = y + DY[dir];\n            if (!inside(nx, ny)) continue;\n            if (base_grid[nx][ny] == OBSTACLE) continue;\n            if (dist[nx][ny] != INF) continue;\n            dist[nx][ny] = dist[x][y] + 1;\n            q.push({nx, ny});\n        }\n    }\n    return dist;\n}\n\nbool is_safe_offline(vector<vector<int>>& state, int x, int y, int remain) {\n    if (state[x][y] != 0) return false;\n    state[x][y] = -1;\n    queue<int> q;\n    vector<char> visited(D * D, 0);\n    int start = entrance_i * D + entrance_j;\n    q.push(start);\n    visited[start] = 1;\n    int reachable = 0;\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int cx = v / D;\n        int cy = v % D;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = cx + DX[dir];\n            int ny = cy + DY[dir];\n            if (!inside(nx, ny)) continue;\n            int nid = nx * D + ny;\n            if (visited[nid]) continue;\n            if (state[nx][ny] == -1) continue;\n            visited[nid] = 1;\n            q.push(nid);\n            if (state[nx][ny] == 0) ++reachable;\n        }\n    }\n    state[x][y] = 0;\n    return reachable == remain - 1;\n}\n\nvector<pair<int,int>> compute_target_order(const vector<vector<int>>& base_grid) {\n    vector<vector<int>> state(D, vector<int>(D, -1));\n    int remain = 0;\n    for (int i = 0; i < D; ++i) {\n        for (int j = 0; j < D; ++j) {\n            if (base_grid[i][j] == OBSTACLE) continue;\n            if (i == entrance_i && j == entrance_j) {\n                state[i][j] = -2;\n            } else {\n                state[i][j] = 0;\n                ++remain;\n            }\n        }\n    }\n\n    vector<pair<int,int>> elimination;\n    elimination.reserve(remain);\n\n    while (remain > 0) {\n        pair<int,int> best = {-1, -1};\n        int bestScore = INT_MIN;\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (state[i][j] != 0) continue;\n                if (!is_safe_offline(state, i, j, remain)) continue;\n                int score = dist_from_entrance[i][j] * 1000 - (abs(i - entrance_i) + abs(j - entrance_j));\n                if (score > bestScore) {\n                    bestScore = score;\n                    best = {i, j};\n                }\n            }\n        }\n        if (best.first == -1) {\n            for (int i = 0; i < D && best.first == -1; ++i) {\n                for (int j = 0; j < D; ++j) {\n                    if (state[i][j] == 0) {\n                        best = {i, j};\n                        break;\n                    }\n                }\n            }\n        }\n        elimination.push_back(best);\n        state[best.first][best.second] = -1;\n        --remain;\n    }\n\n    vector<pair<int,int>> retrieval = elimination;\n    reverse(retrieval.begin(), retrieval.end());\n    return retrieval;\n}\n\nbool is_safe_cell(int x, int y) {\n    grid[x][y] = TEMPBLOCK;\n    queue<int> q;\n    vector<char> visited(D * D, 0);\n    int start = entrance_i * D + entrance_j;\n    q.push(start);\n    visited[start] = 1;\n    int reachable = 0;\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int cx = v / D;\n        int cy = v % D;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = cx + DX[dir];\n            int ny = cy + DY[dir];\n            if (!inside(nx, ny)) continue;\n            int nid = nx * D + ny;\n            if (visited[nid]) continue;\n            int val = grid[nx][ny];\n            if (val == OBSTACLE || val == TEMPBLOCK) continue;\n            if (val >= 0) continue;\n            visited[nid] = 1;\n            q.push(nid);\n            if (val == EMPTY) ++reachable;\n        }\n    }\n    grid[x][y] = EMPTY;\n    return reachable == empty_cells_remaining - 1;\n}\n\npair<int,int> choose_cell(int number) {\n    const long long DIFF_WEIGHT  = 4000;\n    const long long NEG_EXTRA    = 25000;\n    const long long DIST_WEIGHT  = 200;\n    const long long DEGREE_WEIGHT = 80;\n\n    int bestDef = INT_MAX;\n    long long bestCost = (1LL << 60);\n    pair<int,int> best = {-1, -1};\n\n    for (int i = 0; i < D; ++i) {\n        for (int j = 0; j < D; ++j) {\n            if (grid[i][j] != EMPTY) continue;\n            if (!is_safe_cell(i, j)) continue;\n            int r = target_rank[i][j];\n            if (r < 0) continue;\n\n            int deficit = 0;\n            if (bestDef != 0) {\n                for (int q = r; q < total_cells; ++q) {\n                    int need = remaining_small[q];\n                    if (need == 0) continue;\n                    int avail = empty_prefix[q] - 1;\n                    if (avail < need) {\n                        deficit += need - avail;\n                        if (bestDef != INT_MAX && deficit > bestDef) break;\n                    }\n                }\n                if (bestDef != INT_MAX && deficit > bestDef) continue;\n            } else {\n                bool ok = true;\n                for (int q = r; q < total_cells; ++q) {\n                    int need = remaining_small[q];\n                    if (need == 0) continue;\n                    int avail = empty_prefix[q] - 1;\n                    if (avail < need) { ok = false; break; }\n                }\n                if (!ok) continue;\n                deficit = 0;\n            }\n\n            long long diff = (long long)r - number;\n            long long absdiff = llabs(diff);\n            long long cost = absdiff * absdiff * DIFF_WEIGHT;\n            if (diff < 0) cost += (-diff) * NEG_EXTRA;\n            cost += (long long)dist_from_entrance[i][j] * DIST_WEIGHT;\n\n            int degree = 0;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + DX[dir];\n                int nj = j + DY[dir];\n                if (!inside(ni, nj)) continue;\n                if (grid[ni][nj] == EMPTY) ++degree;\n            }\n            int leafScore = max(0, 3 - degree);\n            cost += (long long)leafScore * DEGREE_WEIGHT;\n\n            cost = (cost << 4) + (tie_counter++ & 15);\n\n            if (deficit < bestDef || (deficit == bestDef && cost < bestCost)) {\n                bestDef = deficit;\n                bestCost = cost;\n                best = {i, j};\n            }\n        }\n    }\n\n    if (best.first == -1) {\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (grid[i][j] == EMPTY && is_safe_cell(i, j)) {\n                    best = {i, j};\n                    break;\n                }\n            }\n            if (best.first != -1) break;\n        }\n    }\n\n    return best;\n}\n\nvector<pair<int,int>> build_retrieval_order() {\n    vector<pair<int,int>> order;\n    order.reserve(total_cells);\n    vector<vector<char>> cleared(D, vector<char>(D, 0));\n    vector<vector<char>> in_queue(D, vector<char>(D, 0));\n    cleared[entrance_i][entrance_j] = 1;\n\n    struct Node {\n        int value;\n        int rank;\n        long long tie;\n        int x, y;\n    };\n    struct Cmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.value != b.value) return a.value > b.value;\n            if (a.rank  != b.rank)  return a.rank > b.rank;\n            return a.tie > b.tie;\n        }\n    };\n\n    priority_queue<Node, vector<Node>, Cmp> pq;\n\n    auto push_node = [&](int x, int y) {\n        if (!inside(x, y)) return;\n        if (cleared[x][y]) return;\n        if (grid[x][y] < 0) return;\n        if (in_queue[x][y]) return;\n        pq.push(Node{grid[x][y], target_rank[x][y], tie_counter++, x, y});\n        in_queue[x][y] = 1;\n    };\n\n    for (int dir = 0; dir < 4; ++dir)\n        push_node(entrance_i + DX[dir], entrance_j + DY[dir]);\n\n    auto refill = [&]() {\n        if (!pq.empty()) return;\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (grid[i][j] < 0 || cleared[i][j] || in_queue[i][j]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + DX[dir];\n                    int nj = j + DY[dir];\n                    if (!inside(ni, nj)) continue;\n                    if (cleared[ni][nj]) {\n                        push_node(i, j);\n                        break;\n                    }\n                }\n            }\n        }\n    };\n\n    while ((int)order.size() < total_cells) {\n        refill();\n        if (pq.empty()) break;\n        Node cur = pq.top(); pq.pop();\n        if (cleared[cur.x][cur.y]) continue;\n        order.push_back({cur.x, cur.y});\n        cleared[cur.x][cur.y] = 1;\n        grid[cur.x][cur.y] = EMPTY;\n        for (int dir = 0; dir < 4; ++dir)\n            push_node(cur.x + DX[dir], cur.y + DY[dir]);\n    }\n    return order;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> D >> N)) return 0;\n    entrance_i = 0;\n    entrance_j = (D - 1) / 2;\n\n    grid.assign(D, vector<int>(D, EMPTY));\n    for (int k = 0; k < N; ++k) {\n        int r, c; cin >> r >> c;\n        grid[r][c] = OBSTACLE;\n    }\n    grid[entrance_i][entrance_j] = ENTRANCE;\n\n    vector<vector<int>> base_grid = grid;\n\n    dist_from_entrance = compute_dist(base_grid);\n    target_order = compute_target_order(base_grid);\n    total_cells = (int)target_order.size();\n\n    target_rank.assign(D, vector<int>(D, -1));\n    for (int idx = 0; idx < total_cells; ++idx) {\n        auto [x, y] = target_order[idx];\n        target_rank[x][y] = idx;\n    }\n\n    remaining_small.assign(total_cells, 0);\n    empty_prefix.assign(total_cells, 0);\n    for (int q = 0; q < total_cells; ++q) {\n        remaining_small[q] = q + 1;\n        empty_prefix[q] = q + 1;\n    }\n\n    empty_cells_remaining = total_cells;\n    int total_containers = total_cells;\n\n    for (int step = 0; step < total_containers; ++step) {\n        int t; cin >> t;\n        for (int q = t; q < total_cells; ++q)\n            --remaining_small[q];\n\n        auto cell = choose_cell(t);\n        grid[cell.first][cell.second] = t;\n        --empty_cells_remaining;\n\n        int r = target_rank[cell.first][cell.second];\n        for (int q = r; q < total_cells; ++q)\n            --empty_prefix[q];\n\n        cout << cell.first << ' ' << cell.second << '\\n' << flush;\n    }\n\n    auto retrieval = build_retrieval_order();\n    for (auto [x, y] : retrieval)\n        cout << x << ' ' << y << '\\n';\n    cout.flush();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr double TIME_LIMIT = 1.90;  // seconds\n    static constexpr double ZERO_WEIGHT = 4.0;  // weight of zero adjacency in priority score\n    static constexpr double ANCHOR_JITTER = 6.0;\n\n    int n, m, m1, N;\n    vector<int> initialBoard;\n    vector<int> initialColorCount;\n    vector<vector<int>> colorCells;\n    vector<double> centroidRow, centroidCol;\n    vector<int> baseAdjCount;\n    vector<char> canTouchZero;\n    vector<int> bestBoard;\n    int bestZero = 0;\n\n    chrono::steady_clock::time_point startTime;\n    mt19937_64 rng;\n\n    const array<int, 4> di{-1, 1, 0, 0};\n    const array<int, 4> dj{0, 0, -1, 1};\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    inline int adjIndex(int a, int b) const { return a * m1 + b; }\n\n    inline void changeAdj(vector<int>& adj, int a, int b, int delta) const {\n        if (a == b || delta == 0) return;\n        int idx1 = adjIndex(a, b);\n        int idx2 = adjIndex(b, a);\n        adj[idx1] += delta;\n        adj[idx2] += delta;\n    }\n\n    inline int getAdj(const vector<int>& adj, int a, int b) const {\n        return adj[adjIndex(a, b)];\n    }\n\n    bool checkConnectivity(int removeIdx, int color, const vector<int>& board,\n                           const vector<int>& colorCount, vector<int>& visitStamp,\n                           int& visitToken) const {\n        int remaining = colorCount[color] - 1;\n        if (remaining <= 0) return false;\n\n        int start = -1;\n        int ri = removeIdx / n;\n        int rj = removeIdx % n;\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = ri + di[dir];\n            int nj = rj + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n            int nidx = ni * n + nj;\n            if (board[nidx] == color) {\n                start = nidx;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        visitToken++;\n        if (visitToken == INT_MAX) {\n            fill(visitStamp.begin(), visitStamp.end(), 0);\n            visitToken = 1;\n        }\n        visitStamp[start] = visitToken;\n        queue<int> q;\n        q.push(start);\n        int reached = 0;\n        while (!q.empty()) {\n            int cur = q.front();\n            q.pop();\n            reached++;\n            if (reached == remaining) return true;\n            int ci = cur / n;\n            int cj = cur % n;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = ci + di[dir];\n                int nj = cj + dj[dir];\n                if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n                int nidx = ni * n + nj;\n                if (nidx == removeIdx) continue;\n                if (board[nidx] == color && visitStamp[nidx] != visitToken) {\n                    visitStamp[nidx] = visitToken;\n                    q.push(nidx);\n                }\n            }\n        }\n        return reached == remaining;\n    }\n\n    bool tryRemove(int idx, vector<int>& board, vector<int>& colorCount,\n                   vector<int>& adjCount, vector<int>& visitStamp, int& visitToken) const {\n        int c = board[idx];\n        if (c == 0 || !canTouchZero[c] || colorCount[c] <= 1) return false;\n\n        int i = idx / n;\n        int j = idx % n;\n\n        int zeroEdges = 0;\n        int sameNeighbors = 0;\n        int neighborColors[4];\n        int neighborEdges[4];\n        int neighborKinds = 0;\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                zeroEdges++;\n                continue;\n            }\n            int nidx = ni * n + nj;\n            int d = board[nidx];\n            if (d == 0) {\n                zeroEdges++;\n            } else if (d == c) {\n                sameNeighbors++;\n            } else {\n                if (!canTouchZero[d]) return false;\n                bool found = false;\n                for (int t = 0; t < neighborKinds; ++t) {\n                    if (neighborColors[t] == d) {\n                        neighborEdges[t]++;\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) {\n                    neighborColors[neighborKinds] = d;\n                    neighborEdges[neighborKinds] = 1;\n                    neighborKinds++;\n                }\n            }\n        }\n\n        if (zeroEdges == 0) return false;\n        if (getAdj(adjCount, c, 0) <= zeroEdges) return false;\n        for (int t = 0; t < neighborKinds; ++t) {\n            int d = neighborColors[t];\n            if (getAdj(adjCount, c, d) <= neighborEdges[t]) return false;\n        }\n\n        if (sameNeighbors >= 2) {\n            if (!checkConnectivity(idx, c, board, colorCount, visitStamp, visitToken)) {\n                return false;\n            }\n        }\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                changeAdj(adjCount, c, 0, -1);\n            } else {\n                int nidx = ni * n + nj;\n                int d = board[nidx];\n                if (d == c) continue;\n                changeAdj(adjCount, c, d, -1);\n            }\n        }\n\n        board[idx] = 0;\n        colorCount[c]--;\n        colorCount[0]++;\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n            int nidx = ni * n + nj;\n            int d = board[nidx];\n            if (d == 0) continue;\n            changeAdj(adjCount, 0, d, +1);\n        }\n\n        return true;\n    }\n\n    struct IterationResult {\n        vector<int> board;\n        int zeroCount;\n    };\n\n    IterationResult runIteration(bool usePriority, const vector<pair<double, double>>& anchors) {\n        vector<int> board = initialBoard;\n        vector<int> colorCount = initialColorCount;\n        vector<int> adjCount = baseAdjCount;\n        vector<int> visitStamp(N, 0);\n        int visitToken = 1;\n\n        auto zeroAdjCount = [&](int idx) -> int {\n            int i = idx / n;\n            int j = idx % n;\n            int cnt = 0;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + di[dir];\n                int nj = j + dj[dir];\n                if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                    cnt++;\n                } else if (board[ni * n + nj] == 0) {\n                    cnt++;\n                }\n            }\n            return cnt;\n        };\n\n        if (usePriority) {\n            struct Entry {\n                double score;\n                int idx;\n                int version;\n                bool operator<(const Entry& other) const { return score < other.score; }\n            };\n            priority_queue<Entry> pq;\n            vector<int> version(N, 0);\n            uniform_real_distribution<double> noiseDist(0.0, 1.0);\n\n            auto pushCandidate = [&](int idx) {\n                if (idx < 0 || idx >= N) return;\n                if (board[idx] == 0) return;\n                int c = board[idx];\n                if (!canTouchZero[c]) return;\n                int zeroAdj = zeroAdjCount(idx);\n                if (zeroAdj == 0) return;\n                int i = idx / n;\n                int j = idx % n;\n                double dist = fabs(i - anchors[c].first) + fabs(j - anchors[c].second);\n                double score = dist + ZERO_WEIGHT * zeroAdj + noiseDist(rng);\n                int ver = ++version[idx];\n                pq.push({score, idx, ver});\n            };\n\n            for (int i = 0; i < n; ++i) {\n                pushCandidate(i * n);\n                pushCandidate(i * n + (n - 1));\n            }\n            for (int j = 0; j < n; ++j) {\n                pushCandidate(j);\n                pushCandidate((n - 1) * n + j);\n            }\n\n            while (!pq.empty()) {\n                if (elapsed() > TIME_LIMIT) break;\n                auto cur = pq.top();\n                pq.pop();\n                if (cur.version != version[cur.idx]) continue;\n                int idx = cur.idx;\n                if (board[idx] == 0) continue;\n                int c = board[idx];\n                if (!canTouchZero[c]) continue;\n                if (zeroAdjCount(idx) == 0) continue;\n                if (!tryRemove(idx, board, colorCount, adjCount, visitStamp, visitToken)) continue;\n                int ci = idx / n;\n                int cj = idx % n;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = ci + di[dir];\n                    int nj = cj + dj[dir];\n                    if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n                    pushCandidate(ni * n + nj);\n                }\n            }\n        } else {\n            vector<int> frontier;\n            frontier.reserve(N);\n            vector<char> inFrontier(N, 0);\n\n            auto pushCandidate = [&](int idx) {\n                if (idx < 0 || idx >= N) return;\n                if (board[idx] == 0) return;\n                if (inFrontier[idx]) return;\n                int c = board[idx];\n                if (!canTouchZero[c]) return;\n                if (zeroAdjCount(idx) == 0) return;\n                inFrontier[idx] = 1;\n                frontier.push_back(idx);\n            };\n\n            for (int i = 0; i < n; ++i) {\n                pushCandidate(i * n);\n                pushCandidate(i * n + (n - 1));\n            }\n            for (int j = 0; j < n; ++j) {\n                pushCandidate(j);\n                pushCandidate((n - 1) * n + j);\n            }\n\n            while (!frontier.empty()) {\n                if (elapsed() > TIME_LIMIT) break;\n                int pos = rng() % frontier.size();\n                int idx = frontier[pos];\n                frontier[pos] = frontier.back();\n                frontier.pop_back();\n                inFrontier[idx] = 0;\n                if (board[idx] == 0) continue;\n                int c = board[idx];\n                if (!canTouchZero[c]) continue;\n                if (zeroAdjCount(idx) == 0) continue;\n                if (!tryRemove(idx, board, colorCount, adjCount, visitStamp, visitToken)) continue;\n                int ci = idx / n;\n                int cj = idx % n;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = ci + di[dir];\n                    int nj = cj + dj[dir];\n                    if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n                    pushCandidate(ni * n + nj);\n                }\n            }\n        }\n\n        return {std::move(board), colorCount[0]};\n    }\n\n    void readInput() {\n        cin >> n >> m;\n        m1 = m + 1;\n        N = n * n;\n        initialBoard.assign(N, 0);\n        colorCells.assign(m1, {});\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int c;\n                cin >> c;\n                initialBoard[i * n + j] = c;\n                colorCells[c].push_back(i * n + j);\n            }\n        }\n    }\n\n    void precompute() {\n        initialColorCount.assign(m1, 0);\n        centroidRow.assign(m1, 0.0);\n        centroidCol.assign(m1, 0.0);\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int idx = i * n + j;\n                int c = initialBoard[idx];\n                initialColorCount[c]++;\n                centroidRow[c] += i;\n                centroidCol[c] += j;\n            }\n        }\n        for (int c = 0; c <= m; ++c) {\n            if (initialColorCount[c] > 0) {\n                centroidRow[c] /= initialColorCount[c];\n                centroidCol[c] /= initialColorCount[c];\n            }\n        }\n\n        baseAdjCount.assign(m1 * m1, 0);\n        auto addEdge = [&](int a, int b) {\n            if (a == b) return;\n            int idx1 = adjIndex(a, b);\n            int idx2 = adjIndex(b, a);\n            baseAdjCount[idx1] += 1;\n            baseAdjCount[idx2] += 1;\n        };\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int idx = i * n + j;\n                int c = initialBoard[idx];\n                if (i + 1 < n) addEdge(c, initialBoard[(i + 1) * n + j]);\n                if (j + 1 < n) addEdge(c, initialBoard[i * n + (j + 1)]);\n                if (i == 0) addEdge(c, 0);\n                if (i == n - 1) addEdge(c, 0);\n                if (j == 0) addEdge(c, 0);\n                if (j == n - 1) addEdge(c, 0);\n            }\n        }\n\n        canTouchZero.assign(m1, 0);\n        canTouchZero[0] = 1;\n        for (int c = 1; c <= m; ++c) {\n            if (baseAdjCount[adjIndex(c, 0)] > 0) {\n                canTouchZero[c] = 1;\n            }\n        }\n\n        bestBoard = initialBoard;\n        bestZero = initialColorCount[0];\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        readInput();\n        precompute();\n\n        startTime = chrono::steady_clock::now();\n        rng.seed(startTime.time_since_epoch().count());\n\n        vector<pair<double, double>> anchors(m1, {0.0, 0.0});\n        vector<pair<double, double>> dummyAnchors(m1, {0.0, 0.0});\n        uniform_real_distribution<double> jitterDist(-ANCHOR_JITTER, ANCHOR_JITTER);\n\n        int iteration = 0;\n        while (elapsed() < TIME_LIMIT) {\n            bool usePriority = (iteration % 3 != 2);\n            if (usePriority) {\n                bool useRandomCellAnchor = (iteration % 6 == 0);\n                for (int c = 1; c <= m; ++c) {\n                    if (useRandomCellAnchor && !colorCells[c].empty()) {\n                        int pick = colorCells[c][rng() % colorCells[c].size()];\n                        anchors[c].first = pick / n;\n                        anchors[c].second = pick % n;\n                    } else {\n                        double baseR = centroidRow[c];\n                        double baseC = centroidCol[c];\n                        anchors[c].first = clamp(baseR + jitterDist(rng), 0.0, double(n - 1));\n                        anchors[c].second = clamp(baseC + jitterDist(rng), 0.0, double(n - 1));\n                    }\n                }\n            }\n            const auto& anchorRef = usePriority ? anchors : dummyAnchors;\n            IterationResult res = runIteration(usePriority, anchorRef);\n            if (res.zeroCount > bestZero) {\n                bestZero = res.zeroCount;\n                bestBoard = std::move(res.board);\n            }\n            iteration++;\n            if (elapsed() > TIME_LIMIT) break;\n        }\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                if (j) cout << ' ';\n                cout << bestBoard[i * n + j];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Query {\n    vector<int> idx;\n    vector<int8_t> coeff;\n    double scale = 1.0;\n    double invScale = 1.0;\n    double invScaleSq = 1.0;\n    int result = 0;\n};\n\nvector<double> estimate_weights(const vector<Query>& queries, int N, mt19937& rng) {\n    vector<double> w(N, 1.0);\n    if (queries.empty()) return w;\n    const double minW = 1e-6;\n    const double lr_main = 0.05;\n    const double lr_eq = 0.04;\n    const double reg = 1e-4;\n    uniform_int_distribution<int> qdist(0, (int)queries.size() - 1);\n    int iterations = min(200000, max(20000, 30 * (int)queries.size()));\n\n    for (int iter = 0; iter < iterations; ++iter) {\n        const Query& qu = queries[qdist(rng)];\n        if (qu.idx.empty()) continue;\n        double diff = 0.0;\n        for (size_t k = 0; k < qu.idx.size(); ++k) diff += w[qu.idx[k]] * qu.coeff[k];\n\n        if (qu.result == 0) {\n            double grad_base = diff * qu.invScaleSq;\n            for (size_t k = 0; k < qu.idx.size(); ++k) {\n                int idx = qu.idx[k];\n                double grad = grad_base * qu.coeff[k] + reg * w[idx];\n                w[idx] -= lr_eq * grad;\n                if (w[idx] < minW) w[idx] = minW;\n            }\n        } else {\n            int y = qu.result;\n            double score = diff * qu.invScale;\n            double s = y * score;\n            double sigma;\n            if (s >= 0) {\n                double e = exp(-s);\n                sigma = e / (1.0 + e);\n            } else {\n                double e = exp(s);\n                sigma = 1.0 / (1.0 + e);\n            }\n            double grad_base = -y * sigma * qu.invScale;\n            for (size_t k = 0; k < qu.idx.size(); ++k) {\n                int idx = qu.idx[k];\n                double grad = grad_base * qu.coeff[k] + reg * w[idx];\n                w[idx] -= lr_main * grad;\n                if (w[idx] < minW) w[idx] = minW;\n            }\n        }\n\n        if ((iter & 255) == 0) {\n            double mean = accumulate(w.begin(), w.end(), 0.0) / N;\n            if (mean > 0) for (double &val : w) val /= mean;\n        }\n    }\n\n    double perceptron_lr = 0.02;\n    for (int pass = 0; pass < 2; ++pass) {\n        for (const Query& qu : queries) {\n            if (qu.idx.empty()) continue;\n            double diff = 0.0;\n            for (size_t k = 0; k < qu.idx.size(); ++k) diff += w[qu.idx[k]] * qu.coeff[k];\n            double margin = 0.05 * qu.scale;\n            bool violation = false;\n            if (qu.result == 1) violation = diff < margin;\n            else if (qu.result == -1) violation = diff > -margin;\n            else violation = fabs(diff) > margin;\n            if (!violation) continue;\n\n            if (qu.result == 0) {\n                double grad_base = diff * qu.invScaleSq;\n                for (size_t k = 0; k < qu.idx.size(); ++k) {\n                    int idx = qu.idx[k];\n                    w[idx] -= perceptron_lr * grad_base * qu.coeff[k];\n                    if (w[idx] < minW) w[idx] = minW;\n                }\n            } else {\n                for (size_t k = 0; k < qu.idx.size(); ++k) {\n                    int idx = qu.idx[k];\n                    w[idx] += perceptron_lr * qu.result * qu.coeff[k];\n                    if (w[idx] < minW) w[idx] = minW;\n                }\n            }\n        }\n        double mean = accumulate(w.begin(), w.end(), 0.0) / N;\n        if (mean > 0) for (double &val : w) val /= mean;\n    }\n\n    double sum = accumulate(w.begin(), w.end(), 0.0);\n    if (sum > 0) {\n        double factor = (double)N / sum;\n        for (double &val : w) val *= factor;\n    }\n    return w;\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    vector<Query> queries;\n    queries.reserve(Q);\n    vector<double> biasScore(N, 0.0);\n\n    mt19937 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> uniform01(0.0, 1.0);\n\n    auto ask = [&](const vector<int>& L, const vector<int>& R) -> int {\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string resp;\n        if (!(cin >> resp)) exit(0);\n        int res = 0;\n        if (!resp.empty()) {\n            if (resp[0] == '>') res = 1;\n            else if (resp[0] == '<') res = -1;\n        }\n\n        Query q;\n        q.result = res;\n        q.idx.reserve(L.size() + R.size());\n        q.coeff.reserve(L.size() + R.size());\n        for (int x : L) { q.idx.push_back(x); q.coeff.push_back(1); }\n        for (int x : R) { q.idx.push_back(x); q.coeff.push_back(-1); }\n        int len = (int)q.idx.size();\n        if (len == 0) len = 1;\n        q.scale = sqrt((double)len);\n        q.invScale = 1.0 / q.scale;\n        q.invScaleSq = q.invScale * q.invScale;\n        queries.push_back(std::move(q));\n\n        if (res == 1) {\n            for (int x : L) biasScore[x] += 1.0;\n            for (int x : R) biasScore[x] -= 1.0;\n        } else if (res == -1) {\n            for (int x : L) biasScore[x] -= 1.0;\n            for (int x : R) biasScore[x] += 1.0;\n        }\n        return res;\n    };\n\n    int champion = 0;\n    for (int i = 1; i < N && (int)queries.size() < Q; ++i) {\n        vector<int> L = {champion};\n        vector<int> R = {i};\n        int res = ask(L, R);\n        if (res == -1) champion = i;\n    }\n\n    while ((int)queries.size() < Q) {\n        vector<int> L, R;\n        int type = rng() % 3;\n        if (type == 0) {\n            int a = rng() % N;\n            int b = rng() % N;\n            while (b == a) b = rng() % N;\n            L = {a};\n            R = {b};\n        } else if (type == 1) {\n            vector<int> picks;\n            picks.reserve(4);\n            while ((int)picks.size() < 4) {\n                int x = rng() % N;\n                bool ok = true;\n                for (int y : picks) if (y == x) { ok = false; break; }\n                if (ok) picks.push_back(x);\n            }\n            L = {picks[0], picks[1]};\n            R = {picks[2], picks[3]};\n        } else {\n            double density = 0.18 + 0.22 * (double)N / 100.0;\n            density = min(0.35, max(0.18, density));\n            for (int i = 0; i < N; ++i) {\n                double v = uniform01(rng);\n                if (v < density) L.push_back(i);\n                else if (v < 2.0 * density) R.push_back(i);\n            }\n            if (L.empty() && !R.empty()) {\n                L.push_back(R.back());\n                R.pop_back();\n            }\n            if (R.empty() && !L.empty()) {\n                R.push_back(L.back());\n                L.pop_back();\n            }\n            if (L.empty() || R.empty()) {\n                int a = rng() % N;\n                int b = rng() % N;\n                while (b == a) b = rng() % N;\n                L = {a};\n                R = {b};\n            }\n        }\n        ask(L, R);\n    }\n\n    vector<double> weights = estimate_weights(queries, N, rng);\n\n    double maxAbs = 0.0;\n    for (double s : biasScore) maxAbs = max(maxAbs, fabs(s));\n    if (maxAbs < 1e-9) maxAbs = 1.0;\n\n    const double alpha = 0.4;\n    for (int i = 0; i < N; ++i) {\n        double factor = 1.0 + alpha * (biasScore[i] / maxAbs);\n        weights[i] *= factor;\n        if (weights[i] < 1e-6) weights[i] = 1e-6;\n    }\n\n    double sumW = accumulate(weights.begin(), weights.end(), 0.0);\n    if (sumW > 0) {\n        double factor = (double)N / sumW;\n        for (double &w : weights) w *= factor;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        double noise = 0.98 + 0.04 * uniform01(rng);\n        weights[i] *= noise;\n    }\n    sumW = accumulate(weights.begin(), weights.end(), 0.0);\n    if (sumW > 0) {\n        double factor = (double)N / sumW;\n        for (double &w : weights) w *= factor;\n    }\n\n    double mean = accumulate(weights.begin(), weights.end(), 0.0) / N;\n    double var = 0.0;\n    for (double w : weights) {\n        double diff = w - mean;\n        var += diff * diff;\n    }\n    var /= N;\n    if (var < 1e-4) {\n        for (int i = 0; i < N; ++i) {\n            double factor = 1.0 + 0.5 * (biasScore[i] / maxAbs);\n            weights[i] = max(1e-6, factor);\n        }\n        double sum = accumulate(weights.begin(), weights.end(), 0.0);\n        if (sum > 0) {\n            double coeff = (double)N / sum;\n            for (double &w : weights) w *= coeff;\n        }\n    }\n\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (weights[a] != weights[b]) return weights[a] > weights[b];\n        return a < b;\n    });\n\n    vector<vector<int>> orders;\n    orders.push_back(order);\n    {\n        vector<int> rev = order;\n        reverse(rev.begin(), rev.end());\n        orders.push_back(rev);\n    }\n    {\n        vector<int> snake;\n        int l = 0, r = N - 1;\n        while (l <= r) {\n            snake.push_back(order[l++]);\n            if (l <= r) snake.push_back(order[r--]);\n        }\n        orders.push_back(snake);\n    }\n    {\n        vector<int> rnd = order;\n        shuffle(rnd.begin(), rnd.end(), rng);\n        orders.push_back(rnd);\n    }\n\n    double total = accumulate(weights.begin(), weights.end(), 0.0);\n    double target = (D == 0) ? 0.0 : total / D;\n\n    struct PartitionState {\n        vector<int> assign;\n        vector<double> sums;\n        vector<int> sizes;\n    };\n\n    auto build_state = [&](const vector<int>& seq) -> PartitionState {\n        PartitionState st;\n        st.assign.assign(N, 0);\n        st.sums.assign(D, 0.0);\n        st.sizes.assign(D, 0);\n        for (int idx : seq) {\n            int best = 0;\n            for (int d = 1; d < D; ++d) {\n                if (st.sums[d] + 1e-9 < st.sums[best]) best = d;\n                else if (fabs(st.sums[d] - st.sums[best]) <= 1e-9 &&\n                         st.sizes[d] < st.sizes[best]) best = d;\n            }\n            st.assign[idx] = best;\n            st.sums[best] += weights[idx];\n            st.sizes[best]++;\n        }\n        return st;\n    };\n\n    auto random_local = [&](PartitionState& st) {\n        if (D <= 1) return;\n        int LS_ITERS = 10000 + 200 * N;\n        uniform_int_distribution<int> distItem(0, N - 1);\n        uniform_int_distribution<int> distBucket(0, D - 1);\n        for (int iter = 0; iter < LS_ITERS; ++iter) {\n            if (rng() & 1) {\n                int i = distItem(rng);\n                int from = st.assign[i];\n                int to = distBucket(rng);\n                if (from == to) continue;\n                double wi = weights[i];\n                double sa = st.sums[from];\n                double sb = st.sums[to];\n                double oldScore = (sa - target) * (sa - target) + (sb - target) * (sb - target);\n                double na = sa - wi;\n                double nb = sb + wi;\n                double newScore = (na - target) * (na - target) + (nb - target) * (nb - target);\n                if (newScore + 1e-9 < oldScore) {\n                    st.assign[i] = to;\n                    st.sums[from] = na;\n                    st.sums[to] = nb;\n                    st.sizes[from]--;\n                    st.sizes[to]++;\n                }\n            } else {\n                int i = distItem(rng);\n                int j = distItem(rng);\n                if (st.assign[i] == st.assign[j]) continue;\n                int a = st.assign[i];\n                int b = st.assign[j];\n                double wi = weights[i];\n                double wj = weights[j];\n                double sa = st.sums[a];\n                double sb = st.sums[b];\n                double oldScore = (sa - target) * (sa - target) + (sb - target) * (sb - target);\n                double na = sa - wi + wj;\n                double nb = sb - wj + wi;\n                double newScore = (na - target) * (na - target) + (nb - target) * (nb - target);\n                if (newScore + 1e-9 < oldScore) {\n                    st.assign[i] = b;\n                    st.assign[j] = a;\n                    st.sums[a] = na;\n                    st.sums[b] = nb;\n                }\n            }\n        }\n    };\n\n    auto best_move = [&](PartitionState& st) -> bool {\n        const double EPS = 1e-7;\n        double bestDelta = -EPS;\n        int bestItem = -1, bestTo = -1;\n        for (int i = 0; i < N; ++i) {\n            int from = st.assign[i];\n            double wi = weights[i];\n            double sa = st.sums[from];\n            double baseA = (sa - target) * (sa - target);\n            for (int to = 0; to < D; ++to) {\n                if (to == from) continue;\n                double sb = st.sums[to];\n                double baseB = (sb - target) * (sb - target);\n                double na = sa - wi;\n                double nb = sb + wi;\n                double newScore = (na - target) * (na - target) + (nb - target) * (nb - target);\n                double delta = newScore - (baseA + baseB);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestItem = i;\n                    bestTo = to;\n                }\n            }\n        }\n        if (bestItem == -1) return false;\n        int from = st.assign[bestItem];\n        double wi = weights[bestItem];\n        st.assign[bestItem] = bestTo;\n        st.sums[from] -= wi;\n        st.sums[bestTo] += wi;\n        st.sizes[from]--;\n        st.sizes[bestTo]++;\n        return true;\n    };\n\n    auto best_swap = [&](PartitionState& st) -> bool {\n        const double EPS = 1e-7;\n        double bestDelta = -EPS;\n        int bestI = -1, bestJ = -1;\n        for (int i = 0; i < N; ++i) {\n            int a = st.assign[i];\n            double wi = weights[i];\n            double sa = st.sums[a];\n            double baseA = (sa - target) * (sa - target);\n            for (int j = i + 1; j < N; ++j) {\n                int b = st.assign[j];\n                if (a == b) continue;\n                double wj = weights[j];\n                double sb = st.sums[b];\n                double baseB = (sb - target) * (sb - target);\n                double na = sa - wi + wj;\n                double nb = sb - wj + wi;\n                double newScore = (na - target) * (na - target) + (nb - target) * (nb - target);\n                double delta = newScore - (baseA + baseB);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                }\n            }\n        }\n        if (bestI == -1) return false;\n        int a = st.assign[bestI];\n        int b = st.assign[bestJ];\n        double wi = weights[bestI];\n        double wj = weights[bestJ];\n        st.assign[bestI] = b;\n        st.assign[bestJ] = a;\n        st.sums[a] += -wi + wj;\n        st.sums[b] += -wj + wi;\n        return true;\n    };\n\n    auto improve_state = [&](PartitionState& st) {\n        const int MOVE_LIMIT1 = 250;\n        const int SWAP_LIMIT = 120;\n        const int MOVE_LIMIT2 = 120;\n        for (int i = 0; i < MOVE_LIMIT1; ++i) if (!best_move(st)) break;\n        for (int i = 0; i < SWAP_LIMIT; ++i) if (!best_swap(st)) break;\n        for (int i = 0; i < MOVE_LIMIT2; ++i) if (!best_move(st)) break;\n    };\n\n    auto compute_penalty = [&](const vector<double>& sums) -> double {\n        double pen = 0.0;\n        for (double s : sums) {\n            double diff = s - target;\n            pen += diff * diff;\n        }\n        return pen;\n    };\n\n    vector<int> bestAssign(N, 0);\n    double bestPenalty = numeric_limits<double>::infinity();\n    bool found = false;\n\n    for (size_t idx = 0; idx < orders.size(); ++idx) {\n        PartitionState st = build_state(orders[idx]);\n        if (idx == 0) random_local(st);\n        improve_state(st);\n        double pen = compute_penalty(st.sums);\n        if (!found || pen + 1e-6 < bestPenalty) {\n            found = true;\n            bestPenalty = pen;\n            bestAssign = st.assign;\n        }\n    }\n\n    if (!found) {\n        iota(bestAssign.begin(), bestAssign.end(), 0);\n        for (int i = 0; i < N; ++i) bestAssign[i] %= D;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << bestAssign[i];\n    }\n    cout << '\\n' << flush;\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int n, m, bucketSize;\n    vector<vector<int>> stacks;\n    struct Pos {\n        int stack = -1;\n        int idx = -1;\n    };\n    vector<Pos> pos;\n    vector<int> targetStack;\n    vector<pair<int,int>> operations;\n    long long energy = 0;\n\n    int stack_min(int idx) const {\n        if (stacks[idx].empty()) return 1e9;\n        int mn = stacks[idx][0];\n        for (int v : stacks[idx]) mn = min(mn, v);\n        return mn;\n    }\n\n    int choose_destination(int source, const vector<int>& chunk, int chunk_min) {\n        const int INF = 1e9;\n        struct Cand {\n            int idx;\n            bool safe;\n            int stackMin;\n            int match;\n            int height;\n            int top;\n        };\n        Cand bestSafe{ -1, false, -1, -1, -1, -1 };\n        Cand bestUnsafe{ -1, false, -1, -1, -1, -1 };\n        for (int i = 0; i < m; ++i) {\n            if (i == source) continue;\n            bool empty = stacks[i].empty();\n            int topVal = empty ? INF : stacks[i].back();\n            bool safe = empty || topVal >= chunk_min;\n            int smin = empty ? INF : stack_min(i);\n            int match = 0;\n            for (int v : chunk) if (targetStack[v] == i) ++match;\n            int height = (int)stacks[i].size();\n            Cand cand{i, safe, smin, match, height, empty ? INF : topVal};\n\n            if (safe) {\n                if (bestSafe.idx == -1) bestSafe = cand;\n                else {\n                    auto &b = bestSafe;\n                    if (cand.stackMin != b.stackMin) { if (cand.stackMin > b.stackMin) bestSafe = cand; continue; }\n                    if (cand.match != b.match) { if (cand.match > b.match) bestSafe = cand; continue; }\n                    if (cand.height != b.height) { if (cand.height < b.height) bestSafe = cand; continue; }\n                    if (cand.top != b.top) { if (cand.top > b.top) bestSafe = cand; continue; }\n                    if (cand.idx < b.idx) bestSafe = cand;\n                }\n            } else {\n                if (bestUnsafe.idx == -1) bestUnsafe = cand;\n                else {\n                    auto &b = bestUnsafe;\n                    if (cand.top != b.top) { if (cand.top > b.top) bestUnsafe = cand; continue; }\n                    if (cand.stackMin != b.stackMin) { if (cand.stackMin > b.stackMin) bestUnsafe = cand; continue; }\n                    if (cand.height != b.height) { if (cand.height < b.height) bestUnsafe = cand; continue; }\n                    if (cand.match != b.match) { if (cand.match > b.match) bestUnsafe = cand; continue; }\n                    if (cand.idx < b.idx) bestUnsafe = cand;\n                }\n            }\n        }\n        if (bestSafe.idx != -1) return bestSafe.idx;\n        if (bestUnsafe.idx != -1) return bestUnsafe.idx;\n        for (int i = 0; i < m; ++i) if (i != source) return i;\n        return source; // should never happen\n    }\n\n    void move_segment(int box, int dest) {\n        auto p = pos[box];\n        int s = p.stack;\n        int idx = p.idx;\n        if (s == -1 || dest == -1 || s == dest) return;\n        vector<int> segment;\n        segment.reserve(stacks[s].size() - idx);\n        for (int i = idx; i < (int)stacks[s].size(); ++i) segment.push_back(stacks[s][i]);\n        stacks[s].resize(idx);\n        int destStart = stacks[dest].size();\n        stacks[dest].insert(stacks[dest].end(), segment.begin(), segment.end());\n        for (int t = 0; t < (int)segment.size(); ++t) {\n            pos[segment[t]].stack = dest;\n            pos[segment[t]].idx = destStart + t;\n        }\n        operations.emplace_back(box, dest + 1);\n        energy += (long long)segment.size() + 1;\n    }\n\n    void remove_box(int box) {\n        auto p = pos[box];\n        int s = p.stack;\n        if (s == -1) return;\n        stacks[s].pop_back();\n        pos[box].stack = -1;\n        pos[box].idx = -1;\n        operations.emplace_back(box, 0);\n    }\n\n    void solve() {\n        cin >> n >> m;\n        bucketSize = n / m;\n        stacks.assign(m, {});\n        pos.assign(n + 1, {});\n        targetStack.assign(n + 1, 0);\n        for (int v = 1; v <= n; ++v) {\n            targetStack[v] = min(m - 1, (v - 1) / bucketSize);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            stacks[i].resize(bucketSize);\n            for (int j = 0; j < bucketSize; ++j) {\n                int v; cin >> v;\n                stacks[i][j] = v;\n                pos[v].stack = i;\n                pos[v].idx = j;\n            }\n        }\n\n        for (int v = 1; v <= n; ++v) {\n            while (true) {\n                auto p = pos[v];\n                int s = p.stack;\n                if (s == -1) break;\n                int idx = p.idx;\n                if (idx == (int)stacks[s].size() - 1) {\n                    remove_box(v);\n                    break;\n                } else {\n                    vector<int> chunk;\n                    chunk.reserve(stacks[s].size() - idx - 1);\n                    int chunk_min = INT_MAX;\n                    for (int t = idx + 1; t < (int)stacks[s].size(); ++t) {\n                        int val = stacks[s][t];\n                        chunk.push_back(val);\n                        chunk_min = min(chunk_min, val);\n                    }\n                    int dest = choose_destination(s, chunk, chunk_min);\n                    if (dest == s) {\n                        for (int i = 0; i < m; ++i) if (i != s) { dest = i; break; }\n                    }\n                    int box_to_move = stacks[s][idx + 1];\n                    move_segment(box_to_move, dest);\n                }\n            }\n        }\n\n        for (auto [v, i] : operations) {\n            cout << v << ' ' << i << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MOVE_LIMIT = 100000;\n    static constexpr double TIME_LIMIT = 1.95;\n    static constexpr double FINAL_MARGIN = 0.15;\n    static constexpr array<char, 4> DIR_CHARS = {'U', 'D', 'L', 'R'};\n    static constexpr double LOCAL_TWO = 0.03;\n    static constexpr double LOCAL_OR = 0.03;\n    static constexpr double LOCAL_RAND = 0.015;\n    static constexpr int POOL_LIMIT = 6;\n\n    struct Tour {\n        long long cost;\n        vector<int> perm;\n    };\n\n    int N;\n    int totalNodes;\n    vector<string> h, v;\n    vector<vector<int>> d;\n    vector<int> d_flat;\n    vector<vector<int>> adj;\n    vector<array<int, 4>> dirNeighbor;\n    vector<int> node_r, node_c;\n    vector<uint16_t> dist_all;\n    vector<uint16_t> next_all;\n    vector<vector<int>> visitTimes;\n    vector<vector<int>> candidates;\n\n    mt19937 rng;\n    chrono::steady_clock::time_point start_time;\n\n    Solver()\n        : rng(static_cast<uint32_t>(chrono::steady_clock::now().time_since_epoch().count())) {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n        read_input();\n    }\n\n    void read_input() {\n        cin >> N;\n        h.resize(max(0, N - 1));\n        for (int i = 0; i < N - 1; ++i) cin >> h[i];\n        v.resize(N);\n        for (int i = 0; i < N; ++i) cin >> v[i];\n        d.assign(N, vector<int>(N));\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                cin >> d[i][j];\n\n        totalNodes = N * N;\n        node_r.resize(totalNodes);\n        node_c.resize(totalNodes);\n        d_flat.resize(totalNodes);\n        int idx = 0;\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j, ++idx) {\n                node_r[idx] = i;\n                node_c[idx] = j;\n                d_flat[idx] = d[i][j];\n            }\n\n        adj.assign(totalNodes, {});\n        dirNeighbor.assign(totalNodes, array<int, 4>{-1, -1, -1, -1});\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int u = i * N + j;\n                if (i + 1 < N && h[i][j] == '0') {\n                    int w = (i + 1) * N + j;\n                    adj[u].push_back(w);\n                    adj[w].push_back(u);\n                    dirNeighbor[u][1] = w;\n                    dirNeighbor[w][0] = u;\n                }\n                if (j + 1 < N && v[i][j] == '0') {\n                    int w = i * N + (j + 1);\n                    adj[u].push_back(w);\n                    adj[w].push_back(u);\n                    dirNeighbor[u][3] = w;\n                    dirNeighbor[w][2] = u;\n                }\n            }\n        }\n        visitTimes.assign(totalNodes, {});\n    }\n\n    void solve() {\n        start_time = chrono::steady_clock::now();\n\n        string bestRoute = build_dfs_route();\n        long double bestScore = evaluate(bestRoute);\n\n        precompute_all_pairs();\n        build_candidates(min(35, max(1, totalNodes - 1)));\n\n        vector<vector<int>> perms;\n        perms.reserve(16);\n        auto add_perm = [&](vector<int> perm) {\n            if ((int)perm.size() != totalNodes) return;\n            normalize_order(perm);\n            perms.push_back(move(perm));\n        };\n\n        add_perm(order_snake_rows());\n        add_perm(order_snake_cols());\n        add_perm(order_morton());\n        add_perm(order_bfs(false));\n        add_perm(order_bfs(true));\n        add_perm(order_dfs(false));\n        add_perm(order_dfs(true));\n        add_perm(order_nearest());\n        add_perm(order_sorted_d());\n        add_perm(order_cheapest_insertion(false));\n        add_perm(order_cheapest_insertion(true));\n        add_perm(order_random());\n        add_perm(order_random());\n\n        if (perms.empty()) {\n            cout << bestRoute << '\\n';\n            return;\n        }\n\n        vector<pair<long long, int>> orderCost;\n        orderCost.reserve(perms.size());\n        for (int i = 0; i < (int)perms.size(); ++i) {\n            long long cost = tour_cost(perms[i]);\n            orderCost.emplace_back(cost, i);\n        }\n        sort(orderCost.begin(), orderCost.end());\n\n        vector<pair<long long, vector<int>>> candidatePerms;\n        candidatePerms.reserve(40);\n        vector<Tour> pool;\n\n        auto add_pool = [&](const vector<int>& perm, long long cost) {\n            for (auto& t : pool) {\n                if (t.cost == cost && t.perm == perm) return;\n            }\n            pool.push_back({cost, perm});\n            sort(pool.begin(), pool.end(),\n                 [](const Tour& a, const Tour& b) { return a.cost < b.cost; });\n            if ((int)pool.size() > POOL_LIMIT) pool.pop_back();\n        };\n\n        auto push_candidate = [&](vector<int> perm, long long cost) {\n            normalize_order(perm);\n            candidatePerms.emplace_back(cost, perm);\n            add_pool(perm, cost);\n        };\n\n        push_candidate(perms[orderCost[0].second], orderCost[0].first);\n        if (orderCost.size() >= 2) {\n            push_candidate(perms[orderCost[1].second], orderCost[1].first);\n        }\n\n        vector<int> bestPerm = perms[orderCost[0].second];\n        normalize_order(bestPerm);\n        long long bestPermCost = orderCost[0].first;\n\n        int localCount = min(6, (int)orderCost.size());\n        for (int t = 0; t < localCount; ++t) {\n            if (elapsed() > TIME_LIMIT - FINAL_MARGIN - 0.05) break;\n            int idx = orderCost[t].second;\n            vector<int> perm = perms[idx];\n            long long cost = orderCost[t].first;\n            improve_perm(perm, cost, LOCAL_TWO, LOCAL_OR, LOCAL_RAND);\n            push_candidate(perm, cost);\n            if (cost < bestPermCost) {\n                bestPermCost = cost;\n                bestPerm = perm;\n            }\n        }\n\n        if (!bestPerm.empty() && elapsed() < TIME_LIMIT - FINAL_MARGIN - 0.02) {\n            double now = elapsed();\n            double randStop = min(TIME_LIMIT - FINAL_MARGIN, now + 0.18);\n            random_two_opt(bestPerm, bestPermCost, randStop, 25000);\n            normalize_order(bestPerm);\n            now = elapsed();\n            double orStop = min(TIME_LIMIT - FINAL_MARGIN, now + 0.08);\n            or_opt_local(bestPerm, bestPermCost, orStop);\n            normalize_order(bestPerm);\n            now = elapsed();\n            double detStop = min(TIME_LIMIT - FINAL_MARGIN, now + 0.05);\n            two_opt_candidates(bestPerm, bestPermCost, detStop);\n            normalize_order(bestPerm);\n            push_candidate(bestPerm, bestPermCost);\n        }\n\n        if (!bestPerm.empty()) {\n            pool_iterated_search(pool, bestPerm, bestPermCost, candidatePerms);\n        }\n        push_candidate(bestPerm, bestPermCost);\n\n        sort(candidatePerms.begin(), candidatePerms.end(),\n             [](const auto& a, const auto& b) {\n                 if (a.first != b.first) return a.first < b.first;\n                 return a.second < b.second;\n             });\n\n        vector<pair<long long, vector<int>>> selected;\n        selected.reserve(8);\n        for (auto& cand : candidatePerms) {\n            bool duplicate = false;\n            for (auto& sel : selected) {\n                if (sel.first == cand.first && sel.second == cand.second) {\n                    duplicate = true;\n                    break;\n                }\n            }\n            if (!duplicate) selected.push_back(cand);\n            if ((int)selected.size() >= 6) break;\n        }\n\n        for (auto& cand : selected) {\n            if (cand.first > MOVE_LIMIT) continue;\n            if (elapsed() > TIME_LIMIT - 0.02) break;\n            vector<int> perm = cand.second;\n            normalize_order(perm);\n            string route;\n            if (!build_route_from_perm(perm, route)) continue;\n            long double score = evaluate(route);\n            if (score < bestScore) {\n                bestScore = score;\n                bestRoute = route;\n            }\n        }\n\n        if (bestRoute.empty()) bestRoute = build_dfs_route();\n        cout << bestRoute << '\\n';\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void normalize_order(vector<int>& perm) const {\n        if (perm.empty()) return;\n        auto it = find(perm.begin(), perm.end(), 0);\n        if (it != perm.end() && it != perm.begin()) {\n            rotate(perm.begin(), it, perm.end());\n        }\n    }\n\n    string build_dfs_route() const {\n        string route;\n        route.reserve(totalNodes * 2);\n        vector<char> visited(totalNodes, 0);\n        auto dfs = [&](auto&& self, int u) -> void {\n            visited[u] = 1;\n            for (int dir = 0; dir < 4; ++dir) {\n                int nxt = dirNeighbor[u][dir];\n                if (nxt == -1 || visited[nxt]) continue;\n                route.push_back(DIR_CHARS[dir]);\n                self(self, nxt);\n                route.push_back(DIR_CHARS[dir ^ 1]);\n            }\n        };\n        dfs(dfs, 0);\n        return route;\n    }\n\n    void precompute_all_pairs() {\n        int n = totalNodes;\n        dist_all.assign((size_t)n * n, 0);\n        next_all.assign((size_t)n * n, 0);\n        vector<int> dist(n);\n        vector<int> parent(n);\n        vector<int> order(n);\n        vector<int> queue_buf(n);\n        vector<int> rootChild(n);\n\n        for (int s = 0; s < n; ++s) {\n            fill(dist.begin(), dist.end(), -1);\n            int head = 0, tail = 0;\n            queue_buf[tail++] = s;\n            dist[s] = 0;\n            parent[s] = -1;\n            int qsize = 0;\n            while (head < tail) {\n                int u = queue_buf[head++];\n                order[qsize++] = u;\n                for (int vtx : adj[u]) {\n                    if (dist[vtx] != -1) continue;\n                    dist[vtx] = dist[u] + 1;\n                    parent[vtx] = u;\n                    queue_buf[tail++] = vtx;\n                }\n            }\n            rootChild[s] = s;\n            for (int k = 1; k < qsize; ++k) {\n                int u = order[k];\n                int p = parent[u];\n                rootChild[u] = (p == s) ? u : rootChild[p];\n            }\n            size_t base = (size_t)s * n;\n            for (int t = 0; t < n; ++t) {\n                dist_all[base + t] = static_cast<uint16_t>(dist[t]);\n                next_all[base + t] = static_cast<uint16_t>(rootChild[t]);\n            }\n        }\n    }\n\n    void build_candidates(int K) {\n        if (totalNodes <= 1 || K <= 0) {\n            candidates.assign(totalNodes, {});\n            return;\n        }\n        candidates.assign(totalNodes, {});\n        vector<int> indices(totalNodes - 1);\n        for (int u = 0; u < totalNodes; ++u) {\n            int m = 0;\n            for (int v = 0; v < totalNodes; ++v) {\n                if (v == u) continue;\n                indices[m++] = v;\n            }\n            int need = min(K, m);\n            auto comp = [&](int a, int b) {\n                return dist_idx(u, a) < dist_idx(u, b);\n            };\n            if (need < m) {\n                nth_element(indices.begin(), indices.begin() + need, indices.begin() + m, comp);\n            }\n            sort(indices.begin(), indices.begin() + need, comp);\n            candidates[u].assign(indices.begin(), indices.begin() + need);\n        }\n    }\n\n    inline int dist_idx(int a, int b) const {\n        return dist_all[(size_t)a * totalNodes + b];\n    }\n\n    inline int next_idx(int a, int b) const {\n        return next_all[(size_t)a * totalNodes + b];\n    }\n\n    vector<int> order_snake_rows() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        for (int i = 0; i < N; ++i) {\n            if (i % 2 == 0) {\n                for (int j = 0; j < N; ++j) perm.push_back(i * N + j);\n            } else {\n                for (int j = N - 1; j >= 0; --j) perm.push_back(i * N + j);\n            }\n        }\n        return perm;\n    }\n\n    vector<int> order_snake_cols() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        for (int j = 0; j < N; ++j) {\n            if (j % 2 == 0) {\n                for (int i = 0; i < N; ++i) perm.push_back(i * N + j);\n            } else {\n                for (int i = N - 1; i >= 0; --i) perm.push_back(i * N + j);\n            }\n        }\n        return perm;\n    }\n\n    vector<int> order_morton() const {\n        vector<pair<uint32_t, int>> nodes;\n        nodes.reserve(totalNodes - 1);\n        for (int idx = 1; idx < totalNodes; ++idx) {\n            nodes.emplace_back(morton_code(node_r[idx], node_c[idx]), idx);\n        }\n        sort(nodes.begin(), nodes.end());\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        for (auto& p : nodes) perm.push_back(p.second);\n        return perm;\n    }\n\n    uint32_t morton_code(int r, int c) const {\n        uint32_t code = 0;\n        for (int i = 0; i < 6; ++i) {\n            code |= ((uint32_t)((r >> i) & 1)) << (2 * i + 1);\n            code |= ((uint32_t)((c >> i) & 1)) << (2 * i);\n        }\n        return code;\n    }\n\n    vector<int> order_bfs(bool randomize) {\n        vector<int> order;\n        order.reserve(totalNodes);\n        vector<char> visited(totalNodes, 0);\n        queue<int> q;\n        q.push(0);\n        visited[0] = 1;\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            order.push_back(u);\n            vector<int> neighbors = adj[u];\n            if (randomize) shuffle(neighbors.begin(), neighbors.end(), rng);\n            for (int vtx : neighbors) {\n                if (visited[vtx]) continue;\n                visited[vtx] = 1;\n                q.push(vtx);\n            }\n        }\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (!visited[vtx]) order.push_back(vtx);\n        }\n        return order;\n    }\n\n    vector<int> order_dfs(bool randomize) {\n        vector<int> order;\n        order.reserve(totalNodes);\n        vector<char> visited(totalNodes, 0);\n        vector<int> stack = {0};\n        while (!stack.empty()) {\n            int u = stack.back();\n            stack.pop_back();\n            if (visited[u]) continue;\n            visited[u] = 1;\n            order.push_back(u);\n            vector<int> neighbors = adj[u];\n            if (randomize) shuffle(neighbors.begin(), neighbors.end(), rng);\n            for (int vtx : neighbors) {\n                if (!visited[vtx]) stack.push_back(vtx);\n            }\n        }\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (!visited[vtx]) order.push_back(vtx);\n        }\n        return order;\n    }\n\n    vector<int> order_nearest() {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        vector<char> used(totalNodes, 0);\n        int cur = 0;\n        perm.push_back(cur);\n        used[cur] = 1;\n        for (int step = 1; step < totalNodes; ++step) {\n            int best = -1;\n            int bestDist = INT_MAX;\n            for (int vtx = 0; vtx < totalNodes; ++vtx) {\n                if (used[vtx]) continue;\n                int dd = dist_idx(cur, vtx);\n                if (best == -1 || dd < bestDist ||\n                    (dd == bestDist && (d_flat[vtx] > d_flat[best] ||\n                                        ((rng() & 1) && d_flat[vtx] == d_flat[best])))) {\n                    best = vtx;\n                    bestDist = dd;\n                }\n            }\n            if (best == -1) break;\n            perm.push_back(best);\n            used[best] = 1;\n            cur = best;\n        }\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (!used[vtx]) perm.push_back(vtx);\n        }\n        return perm;\n    }\n\n    vector<int> order_sorted_d() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        vector<pair<int, int>> nodes;\n        nodes.reserve(totalNodes - 1);\n        for (int idx = 1; idx < totalNodes; ++idx) {\n            nodes.emplace_back(-d_flat[idx], idx);\n        }\n        sort(nodes.begin(), nodes.end());\n        for (auto& p : nodes) perm.push_back(p.second);\n        return perm;\n    }\n\n    vector<int> order_random() {\n        vector<int> perm(totalNodes);\n        iota(perm.begin(), perm.end(), 0);\n        if (totalNodes > 1) shuffle(perm.begin() + 1, perm.end(), rng);\n        return perm;\n    }\n\n    vector<int> order_cheapest_insertion(bool useFarthest) {\n        if (totalNodes == 1) return vector<int>{0};\n        vector<char> used(totalNodes, 0);\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        used[0] = 1;\n\n        int second = -1;\n        int bestVal = useFarthest ? -1 : INT_MAX;\n        for (int vtx = 1; vtx < totalNodes; ++vtx) {\n            int val = dist_idx(0, vtx);\n            if (second == -1 ||\n                (!useFarthest && val < bestVal) ||\n                (useFarthest && val > bestVal)) {\n                second = vtx;\n                bestVal = val;\n            }\n        }\n        if (second == -1) second = 1;\n        perm.push_back(second);\n        used[second] = 1;\n\n        vector<int> unvisited;\n        unvisited.reserve(totalNodes - 2);\n        vector<int> bestDist(totalNodes, INT_MAX);\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (used[vtx]) continue;\n            unvisited.push_back(vtx);\n            bestDist[vtx] = min(dist_idx(vtx, 0), dist_idx(vtx, second));\n        }\n\n        while (!unvisited.empty()) {\n            int bestNode = -1;\n            int bestMetric = useFarthest ? -1 : INT_MAX;\n            size_t bestIdx = 0;\n            for (size_t idx = 0; idx < unvisited.size(); ++idx) {\n                int node = unvisited[idx];\n                int val = bestDist[node];\n                if (bestNode == -1 ||\n                    (!useFarthest && (val < bestMetric ||\n                                      (val == bestMetric &&\n                                       (d_flat[node] > d_flat[bestNode] ||\n                                        ((rng() & 1) && d_flat[node] == d_flat[bestNode]))))) ||\n                    (useFarthest && (val > bestMetric ||\n                                     (val == bestMetric &&\n                                      (d_flat[node] > d_flat[bestNode] ||\n                                       ((rng() & 1) && d_flat[node] == d_flat[bestNode])))))) {\n                    bestNode = node;\n                    bestMetric = val;\n                    bestIdx = idx;\n                }\n            }\n            int node = bestNode;\n            unvisited[bestIdx] = unvisited.back();\n            unvisited.pop_back();\n\n            int m = perm.size();\n            int bestPos = 0;\n            int bestDelta = INT_MAX;\n            for (int i = 0; i < m; ++i) {\n                int a = perm[i];\n                int b = perm[(i + 1) % m];\n                int delta = dist_idx(a, node) + dist_idx(node, b) - dist_idx(a, b);\n                if (delta < bestDelta || (delta == bestDelta && (rng() & 1))) {\n                    bestDelta = delta;\n                    bestPos = i;\n                }\n            }\n            perm.insert(perm.begin() + bestPos + 1, node);\n            used[node] = 1;\n            for (int rest : unvisited) {\n                bestDist[rest] = min(bestDist[rest], dist_idx(rest, node));\n            }\n        }\n        return perm;\n    }\n\n    long long tour_cost(const vector<int>& perm) const {\n        if (perm.empty()) return (long long)4e18;\n        long long cost = 0;\n        for (int i = 0; i + 1 < (int)perm.size(); ++i) {\n            cost += dist_idx(perm[i], perm[i + 1]);\n        }\n        cost += dist_idx(perm.back(), perm.front());\n        return cost;\n    }\n\n    void improve_perm(vector<int>& perm, long long& cost,\n                      double twoBudget, double orBudget, double randBudget) {\n        if (perm.empty()) return;\n        if (elapsed() >= TIME_LIMIT - FINAL_MARGIN) {\n            normalize_order(perm);\n            return;\n        }\n        double now = elapsed();\n        double detStop = min(TIME_LIMIT - FINAL_MARGIN, now + twoBudget);\n        if (detStop > now) two_opt_candidates(perm, cost, detStop);\n        if (elapsed() >= TIME_LIMIT - FINAL_MARGIN) {\n            normalize_order(perm);\n            return;\n        }\n        now = elapsed();\n        double orStop = min(TIME_LIMIT - FINAL_MARGIN, now + orBudget);\n        if (orStop > now) or_opt_local(perm, cost, orStop);\n        if (elapsed() >= TIME_LIMIT - FINAL_MARGIN) {\n            normalize_order(perm);\n            return;\n        }\n        now = elapsed();\n        double randStop = min(TIME_LIMIT - FINAL_MARGIN, now + randBudget);\n        if (randStop > now) random_two_opt(perm, cost, randStop, 12000);\n        normalize_order(perm);\n    }\n\n    long long two_opt_delta(const vector<int>& perm, int ii, int jj) const {\n        int n = perm.size();\n        int prev_i = (ii == 0) ? n - 1 : ii - 1;\n        int next_j = (jj + 1 == n) ? 0 : jj + 1;\n        int a = perm[prev_i];\n        int b = perm[ii];\n        int c = perm[jj];\n        int d = perm[next_j];\n        return (long long)dist_idx(a, c) + dist_idx(b, d)\n             - dist_idx(a, b) - dist_idx(c, d);\n    }\n\n    void two_opt_candidates(vector<int>& perm, long long& cost, double stopTime) {\n        int n = perm.size();\n        if (n <= 3) return;\n        if (elapsed() >= stopTime) return;\n        vector<int> pos(n);\n        for (int i = 0; i < n; ++i) pos[perm[i]] = i;\n        while (elapsed() < stopTime) {\n            bool improved = false;\n            for (int i = 0; i < n; ++i) {\n                int a = perm[i];\n                for (int b : candidates[a]) {\n                    int j = pos[b];\n                    if (i == j) continue;\n                    int ii = i, jj = j;\n                    if (ii > jj) swap(ii, jj);\n                    if (jj == ii || jj == ii + 1) continue;\n                    if (ii == 0 && jj == n - 1) continue;\n                    long long delta = two_opt_delta(perm, ii, jj);\n                    if (delta < 0) {\n                        reverse(perm.begin() + ii, perm.begin() + jj + 1);\n                        for (int k = ii; k <= jj; ++k) pos[perm[k]] = k;\n                        cost += delta;\n                        improved = true;\n                        break;\n                    }\n                }\n                if (improved) break;\n                if ((i & 31) == 0 && elapsed() >= stopTime) return;\n            }\n            if (!improved) break;\n        }\n    }\n\n    void or_opt_local(vector<int>& perm, long long& cost, double stopTime) {\n        int n = perm.size();\n        if (n <= 4 || elapsed() >= stopTime) return;\n        vector<int> pos(n);\n        auto rebuild_pos = [&]() {\n            for (int i = 0; i < n; ++i) pos[perm[i]] = i;\n        };\n        rebuild_pos();\n        while (elapsed() < stopTime) {\n            bool moved = false;\n            for (int len = 1; len <= 3; ++len) {\n                for (int st = 1; st + len <= n; ++st) {\n                    if (elapsed() >= stopTime) return;\n                    int en = st + len - 1;\n                    bool hasZero = false;\n                    for (int k = st; k <= en; ++k) {\n                        if (perm[k] == 0) {\n                            hasZero = true;\n                            break;\n                        }\n                    }\n                    if (hasZero) continue;\n                    int a = perm[st - 1];\n                    int b = perm[st];\n                    int c = perm[en];\n                    int d = (en + 1 < n) ? perm[en + 1] : perm[0];\n                    long long removeDelta =\n                        (long long)dist_idx(a, d) - dist_idx(a, b) - dist_idx(c, d);\n\n                    vector<int> posList;\n                    posList.reserve(24);\n                    auto try_add = [&](int insertAfter) {\n                        if (insertAfter < 0 || insertAfter >= n) return;\n                        if (insertAfter == n - 1) return;\n                        if (insertAfter >= st - 1 && insertAfter <= en) return;\n                        if (insertAfter == st - 2 && st - 2 >= 0) return;\n                        for (int val : posList)\n                            if (val == insertAfter) return;\n                        posList.push_back(insertAfter);\n                    };\n                    for (int cand : candidates[b]) {\n                        try_add(pos[cand]);\n                        if ((int)posList.size() >= 18) break;\n                    }\n                    for (int cand : candidates[c]) {\n                        try_add(pos[cand]);\n                        if ((int)posList.size() >= 24) break;\n                    }\n                    try_add(st - 2);\n                    try_add(en + 1);\n                    for (int t = 0; t < 3; ++t) try_add(rng() % (n - 1));\n\n                    for (int insertAfter : posList) {\n                        if (insertAfter < 0 || insertAfter >= n) continue;\n                        if (insertAfter == n - 1) continue;\n                        int x = perm[insertAfter];\n                        int y = (insertAfter + 1 < n) ? perm[insertAfter + 1] : perm[0];\n                        long long insertDelta =\n                            (long long)dist_idx(x, b) + dist_idx(c, y) - dist_idx(x, y);\n                        long long delta = removeDelta + insertDelta;\n                        if (delta < 0) {\n                            vector<int> segment(perm.begin() + st, perm.begin() + en + 1);\n                            perm.erase(perm.begin() + st, perm.begin() + en + 1);\n                            int insertIndex =\n                                (insertAfter < st) ? insertAfter + 1 : insertAfter - len + 1;\n                            perm.insert(perm.begin() + insertIndex, segment.begin(),\n                                        segment.end());\n                            cost += delta;\n                            n = perm.size();\n                            rebuild_pos();\n                            moved = true;\n                            goto NEXT_OUTER;\n                        }\n                    }\n                }\n            }\n        NEXT_OUTER:\n            if (!moved || elapsed() >= stopTime) break;\n        }\n    }\n\n    void random_two_opt(vector<int>& perm, long long& cost, double stopTime, int idleLimit) {\n        int n = perm.size();\n        if (n <= 3) return;\n        if (elapsed() >= stopTime) return;\n        vector<int> pos(n);\n        for (int i = 0; i < n; ++i) pos[perm[i]] = i;\n        int idle = 0;\n        while (elapsed() < stopTime && idle < idleLimit) {\n            int i = rng() % n;\n            int j = rng() % n;\n            if (i == j) continue;\n            int ii = i, jj = j;\n            if (ii > jj) swap(ii, jj);\n            if (jj == ii || jj == ii + 1) continue;\n            if (ii == 0 && jj == n - 1) continue;\n            long long delta = two_opt_delta(perm, ii, jj);\n            if (delta < 0) {\n                reverse(perm.begin() + ii, perm.begin() + jj + 1);\n                for (int k = ii; k <= jj; ++k) pos[perm[k]] = k;\n                cost += delta;\n                idle = 0;\n            } else {\n                ++idle;\n            }\n        }\n    }\n\n    void double_bridge(vector<int>& perm) {\n        int n = perm.size();\n        if (n < 8) return;\n        array<int, 4> cuts;\n        for (int t = 0; t < 4; ++t) {\n            int x;\n            do {\n                x = 1 + rng() % (n - 1);\n                bool ok = true;\n                for (int k = 0; k < t; ++k)\n                    if (cuts[k] == x) ok = false;\n                if (ok) break;\n            } while (true);\n            cuts[t] = x;\n        }\n        sort(cuts.begin(), cuts.end());\n        int a = cuts[0], b = cuts[1], c = cuts[2], d = cuts[3];\n        vector<int> newPerm;\n        newPerm.reserve(n);\n        newPerm.insert(newPerm.end(), perm.begin(), perm.begin() + a);\n        newPerm.insert(newPerm.end(), perm.begin() + c, perm.begin() + d);\n        newPerm.insert(newPerm.end(), perm.begin() + b, perm.begin() + c);\n        newPerm.insert(newPerm.end(), perm.begin() + a, perm.begin() + b);\n        newPerm.insert(newPerm.end(), perm.begin() + d, perm.end());\n        perm.swap(newPerm);\n    }\n\n    void pool_iterated_search(vector<Tour>& pool,\n                              vector<int>& bestPerm, long long& bestCost,\n                              vector<pair<long long, vector<int>>>& cand) {\n        if (pool.empty()) return;\n        double limit = TIME_LIMIT - FINAL_MARGIN - 0.02;\n        while (elapsed() < limit) {\n            int choices = max(1, min((int)pool.size(), 4));\n            int pick = rng() % choices;\n            vector<int> perm = pool[pick].perm;\n            long long cost = pool[pick].cost;\n            double_bridge(perm);\n            if ((rng() & 3) == 0) double_bridge(perm);\n            normalize_order(perm);\n            cost = tour_cost(perm);\n            double remain = limit - elapsed();\n            if (remain <= 0) break;\n            double twoB = min(remain * 0.45, 0.02);\n            double orB = min(remain * 0.35, 0.02);\n            double randB = min(remain * 0.25, 0.012);\n            improve_perm(perm, cost, twoB, orB, randB);\n            normalize_order(perm);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestPerm = perm;\n            }\n            cand.emplace_back(cost, perm);\n            pool.push_back({cost, perm});\n            sort(pool.begin(), pool.end(),\n                 [](const Tour& a, const Tour& b) { return a.cost < b.cost; });\n            if ((int)pool.size() > POOL_LIMIT) pool.pop_back();\n            if ((int)cand.size() > 40) break;\n        }\n    }\n\n    bool build_route_from_perm(const vector<int>& perm, string& route) const {\n        if (perm.empty() || perm[0] != 0) return false;\n        route.clear();\n        route.reserve(min(MOVE_LIMIT, totalNodes * 4));\n        int cur = perm[0];\n        for (int idx = 1; idx < (int)perm.size(); ++idx) {\n            if (!append_path(cur, perm[idx], route)) return false;\n            cur = perm[idx];\n        }\n        if (!append_path(cur, perm[0], route)) return false;\n        return (int)route.size() <= MOVE_LIMIT;\n    }\n\n    bool append_path(int from, int to, string& route) const {\n        if (from == to) return true;\n        int safety = totalNodes * 4 + 10;\n        int cur = from;\n        while (cur != to && safety-- > 0) {\n            int nxt = next_idx(cur, to);\n            if (nxt == cur) return false;\n            char mv = move_char(cur, nxt);\n            if (mv == '?') return false;\n            route.push_back(mv);\n            cur = nxt;\n            if ((int)route.size() > MOVE_LIMIT) return false;\n        }\n        return cur == to;\n    }\n\n    char move_char(int from, int to) const {\n        int r1 = node_r[from], c1 = node_c[from];\n        int r2 = node_r[to], c2 = node_c[to];\n        if (r2 == r1 - 1 && c2 == c1) return 'U';\n        if (r2 == r1 + 1 && c2 == c1) return 'D';\n        if (r2 == r1 && c2 == c1 - 1) return 'L';\n        if (r2 == r1 && c2 == c1 + 1) return 'R';\n        return '?';\n    }\n\n    int char_dir(char c) const {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        if (c == 'R') return 3;\n        return -1;\n    }\n\n    long double evaluate(const string& route) {\n        if (route.empty() || (int)route.size() > MOVE_LIMIT) return 1e100L;\n        for (auto& vec : visitTimes) vec.clear();\n        int pos = 0;\n        for (int t = 0; t < (int)route.size(); ++t) {\n            int dir = char_dir(route[t]);\n            if (dir == -1) return 1e100L;\n            int nxt = dirNeighbor[pos][dir];\n            if (nxt == -1) return 1e100L;\n            pos = nxt;\n            visitTimes[pos].push_back(t + 1);\n       }\n        if (pos != 0) return 1e100L;\n\n        long double total = 0.0L;\n        long double L = (long double)route.size();\n        for (int idx = 0; idx < totalNodes; ++idx) {\n            auto& times = visitTimes[idx];\n            if (times.empty()) return 1e100L;\n            size_t m = times.size();\n            for (size_t j = 0; j < m; ++j) {\n                long long cur = times[j];\n                long long nxt = (j + 1 < m) ? times[j + 1] : (long long)times[0] + (long long)L;\n                long long delta = nxt - cur;\n                total += (long double)d_flat[idx] *\n                         (long double)delta * (long double)(delta - 1) / 2.0L;\n            }\n        }\n        return total / L;\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n};\n\nstruct XorShift64 {\n    unsigned long long x;\n    explicit XorShift64(unsigned long long seed = 88172645463393265ull) : x(seed) {}\n    unsigned long long next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return int(next() % n); }\n    double nextDouble() { return (next() >> 11) * (1.0 / (1ull << 53)); }\n};\n\nconstexpr int CODE_POWER = 26 * 26 * 26 * 26;\nconstexpr int GREEDY_K = 6;\n\nint encodeWord(const string &w) {\n    int code = 0;\n    for (char c : w) code = code * 26 + (c - 'A');\n    return code;\n}\n\nint calcOverlap(const string &a, const string &b) {\n    for (int len = 4; len >= 0; --len) {\n        bool ok = true;\n        for (int k = 0; k < len; ++k) {\n            if (a[5 - len + k] != b[k]) { ok = false; break; }\n        }\n        if (ok) return len;\n    }\n    return 0;\n}\n\nint computeOrderCost(const vector<int>& order, const vector<vector<int>>& cost) {\n    if (order.empty()) return 0;\n    int total = 5;\n    for (int i = 0; i + 1 < (int)order.size(); ++i) total += cost[order[i]][order[i + 1]];\n    return total;\n}\n\nvector<int> greedyOrderFromStart(int start, bool randomized,\n                                 const vector<vector<int>>& cost,\n                                 const vector<int>& sumOut,\n                                 XorShift64& rng) {\n    int n = cost.size();\n    vector<int> order;\n    vector<char> used(n, 0);\n    order.reserve(n);\n    int cur = start;\n    used[cur] = 1;\n    order.push_back(cur);\n    for (int step = 1; step < n; ++step) {\n        array<int, GREEDY_K> candNode;\n        array<int, GREEDY_K> candCost;\n        candNode.fill(-1);\n        candCost.fill(INT_MAX / 4);\n        for (int nxt = 0; nxt < n; ++nxt) {\n            if (used[nxt]) continue;\n            int c = cost[cur][nxt];\n            for (int pos = 0; pos < GREEDY_K; ++pos) {\n                if (candNode[pos] == -1 ||\n                    c < candCost[pos] ||\n                    (c == candCost[pos] &&\n                     (sumOut[nxt] < sumOut[candNode[pos]] ||\n                      (sumOut[nxt] == sumOut[candNode[pos]] && nxt < candNode[pos])))) {\n                    for (int q = GREEDY_K - 1; q > pos; --q) {\n                        candNode[q] = candNode[q - 1];\n                        candCost[q] = candCost[q - 1];\n                    }\n                    candNode[pos] = nxt;\n                    candCost[pos] = c;\n                    break;\n                }\n            }\n        }\n        int candCnt = 0;\n        while (candCnt < GREEDY_K && candNode[candCnt] != -1) ++candCnt;\n        int pick = 0;\n        if (randomized && candCnt > 1) {\n            double r = rng.nextDouble();\n            if (candCnt >= 3) {\n                if (r < 0.6) pick = 0;\n                else if (r < 0.85) pick = 1;\n                else if (r < 0.95) pick = 2;\n                else pick = rng.nextInt(candCnt);\n            } else {\n                pick = (r < 0.8) ? 0 : 1;\n            }\n        }\n        int nextNode = candNode[pick];\n        if (nextNode == -1) {\n            for (int nxt = 0; nxt < n; ++nxt) if (!used[nxt]) { nextNode = nxt; break; }\n        }\n        used[nextNode] = 1;\n        order.push_back(nextNode);\n        cur = nextNode;\n    }\n    return order;\n}\n\nvector<int> cheapestInsertionOrder(bool deterministicStart,\n                                   bool randomized,\n                                   const vector<vector<int>>& cost,\n                                   const vector<int>& sumOut,\n                                   XorShift64& rng) {\n    int n = cost.size();\n    vector<int> order;\n    vector<char> used(n, 0);\n    int a = 0, b = 1;\n    if (deterministicStart) {\n        int best = INT_MAX;\n        for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) if (i != j) {\n            int c = cost[i][j];\n            if (c < best || (c == best && sumOut[i] + sumOut[j] < sumOut[a] + sumOut[b])) {\n                best = c;\n                a = i;\n                b = j;\n            }\n        }\n    } else {\n        a = rng.nextInt(n);\n        b = rng.nextInt(n - 1);\n        if (b >= a) ++b;\n    }\n    order.push_back(a);\n    order.push_back(b);\n    used[a] = used[b] = 1;\n    while ((int)order.size() < n) {\n        int bestNode = -1, bestPos = 0;\n        int bestDelta = INT_MAX / 4;\n        for (int node = 0; node < n; ++node) if (!used[node]) {\n            for (int pos = 0; pos <= (int)order.size(); ++pos) {\n                int prev = (pos == 0) ? -1 : order[pos - 1];\n                int next = (pos == (int)order.size()) ? -1 : order[pos];\n                int delta;\n                if (prev == -1 && next == -1) delta = 0;\n                else if (prev == -1) delta = cost[node][next];\n                else if (next == -1) delta = cost[prev][node];\n                else delta = cost[prev][node] + cost[node][next] - cost[prev][next];\n                bool take = false;\n                if (delta < bestDelta) take = true;\n                else if (delta == bestDelta) {\n                    if (randomized) take = rng.nextDouble() < 0.5;\n                    else if (bestNode == -1 || sumOut[node] < sumOut[bestNode] ||\n                             (sumOut[node] == sumOut[bestNode] && node < bestNode)) take = true;\n                }\n                if (take) {\n                    bestDelta = delta;\n                    bestNode = node;\n                    bestPos = pos;\n                }\n            }\n        }\n        if (bestNode == -1) {\n            for (int node = 0; node < n; ++node) if (!used[node]) { bestNode = node; bestPos = order.size(); break; }\n        }\n        order.insert(order.begin() + bestPos, bestNode);\n        used[bestNode] = 1;\n    }\n    return order;\n}\n\nint swapDelta(const vector<int>& order, int i, int j, const vector<vector<int>>& cost) {\n    if (i == j) return 0;\n    if (i > j) swap(i, j);\n    int n = order.size();\n    auto edge = [&](int u, int v)->int { return (u < 0 || v < 0) ? 0 : cost[u][v]; };\n    int a = order[i];\n    int b = order[j];\n    if (j == i + 1) {\n        int li = (i > 0) ? order[i - 1] : -1;\n        int rj = (j + 1 < n) ? order[j + 1] : -1;\n        int before = 0, after = 0;\n        if (li != -1) before += edge(li, a);\n        before += edge(a, b);\n        if (rj != -1) before += edge(b, rj);\n        if (li != -1) after += edge(li, b);\n        after += edge(b, a);\n        if (rj != -1) after += edge(a, rj);\n        return after - before;\n    } else {\n        int li = (i > 0) ? order[i - 1] : -1;\n        int ri = (i + 1 < n) ? order[i + 1] : -1;\n        int lj = (j > 0) ? order[j - 1] : -1;\n        int rj = (j + 1 < n) ? order[j + 1] : -1;\n        int before = 0, after = 0;\n        if (li != -1) before += edge(li, a);\n        if (ri != -1) before += edge(a, ri);\n        if (lj != -1) before += edge(lj, b);\n        if (rj != -1) before += edge(b, rj);\n        if (li != -1) after += edge(li, b);\n        if (ri != -1) after += edge(b, ri);\n        if (lj != -1) after += edge(lj, a);\n        if (rj != -1) after += edge(a, rj);\n        return after - before;\n    }\n}\n\nint segmentMoveDelta(const vector<int>& order, int L, int len, int insertPos, const vector<vector<int>>& cost) {\n    int n = order.size();\n    int R = L + len - 1;\n    if (insertPos >= L && insertPos <= R + 1) return 0;\n    auto edge = [&](int u, int v)->int { return (u < 0 || v < 0) ? 0 : cost[u][v]; };\n    int segFront = order[L];\n    int segBack = order[R];\n    int left = (L > 0) ? order[L - 1] : -1;\n    int right = (R + 1 < n) ? order[R + 1] : -1;\n    int delta = 0;\n    if (left != -1) delta -= edge(left, segFront);\n    if (right != -1) delta -= edge(segBack, right);\n    if (left != -1 && right != -1) delta += edge(left, right);\n    int reducedTarget;\n    if (insertPos <= L) reducedTarget = insertPos;\n    else if (insertPos > R + 1) reducedTarget = insertPos - len;\n    else return 0;\n    int newSize = n - len;\n    auto getValue = [&](int idx)->int {\n        if (idx < 0) return -1;\n        if (idx >= newSize) return -1;\n        if (idx < L) return order[idx];\n        return order[idx + len];\n    };\n    int before = getValue(reducedTarget - 1);\n    int after = getValue(reducedTarget);\n    if (before != -1) delta += edge(before, segFront);\n    if (after != -1) delta += edge(segBack, after);\n    if (before != -1 && after != -1) delta -= edge(before, after);\n    return delta;\n}\n\nvoid applySegmentMove(vector<int>& order, int L, int len, int insertPos) {\n    vector<int> segment(order.begin() + L, order.begin() + L + len);\n    order.erase(order.begin() + L, order.begin() + L + len);\n    int pos = insertPos;\n    if (pos > L) pos -= len;\n    pos = max(0, min(pos, (int)order.size()));\n    order.insert(order.begin() + pos, segment.begin(), segment.end());\n}\n\nint twoOptDelta(const vector<int>& order, int l, int r, const vector<vector<int>>& cost) {\n    if (l >= r) return 0;\n    int n = order.size();\n    auto edge = [&](int u, int v)->int { return (u < 0 || v < 0) ? 0 : cost[u][v]; };\n    int delta = 0;\n    int left = (l > 0) ? order[l - 1] : -1;\n    int right = (r + 1 < n) ? order[r + 1] : -1;\n    if (left != -1) delta += edge(left, order[r]) - edge(left, order[l]);\n    if (right != -1) delta += edge(order[l], right) - edge(order[r], right);\n    for (int i = l; i < r; ++i) {\n        int u = order[i];\n        int v = order[i + 1];\n        delta += edge(v, u) - edge(u, v);\n    }\n    return delta;\n}\n\nbool improveSwap(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                 Timer& timer, double deadline) {\n    int n = order.size();\n    int bestI = -1, bestJ = -1;\n    int bestDelta = 0;\n    for (int i = 0; i < n; ++i) {\n        if (timer.elapsed() >= deadline) break;\n        for (int j = i + 1; j < n; ++j) {\n            int delta = swapDelta(order, i, j, cost);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestI = i;\n                bestJ = j;\n            }\n        }\n    }\n    if (bestDelta < 0) {\n        swap(order[bestI], order[bestJ]);\n        costVal += bestDelta;\n        return true;\n    }\n    return false;\n}\n\nbool improveSegmentMoveLen(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                           int len, Timer& timer, double deadline) {\n    int n = order.size();\n    if (n <= len) return false;\n    int bestL = -1, bestPos = -1;\n    int bestDelta = 0;\n    for (int L = 0; L + len <= n; ++L) {\n        if (timer.elapsed() >= deadline) break;\n        for (int pos = 0; pos <= n; ++pos) {\n            if (pos >= L && pos <= L + len) continue;\n            int delta = segmentMoveDelta(order, L, len, pos, cost);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestL = L;\n                bestPos = pos;\n            }\n        }\n    }\n    if (bestDelta < 0) {\n        applySegmentMove(order, bestL, len, bestPos);\n        costVal += bestDelta;\n        return true;\n    }\n    return false;\n}\n\nbool improveTwoOpt(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                   Timer& timer, double deadline) {\n    int n = order.size();\n    for (int l = 0; l < n; ++l) {\n        if (timer.elapsed() >= deadline) break;\n        for (int r = l + 1; r < n; ++r) {\n            int delta = twoOptDelta(order, l, r, cost);\n            if (delta < 0) {\n                reverse(order.begin() + l, order.begin() + r + 1);\n                costVal += delta;\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nvoid deterministicLocalSearch(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                              Timer& timer, double deadline) {\n    while (timer.elapsed() < deadline) {\n        if (improveSwap(order, costVal, cost, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveSegmentMoveLen(order, costVal, cost, 1, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveSegmentMoveLen(order, costVal, cost, 2, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveSegmentMoveLen(order, costVal, cost, 3, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveTwoOpt(order, costVal, cost, timer, deadline)) continue;\n        break;\n    }\n}\n\nvoid simulatedAnnealing(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                        XorShift64& rng, Timer& timer, double deadline) {\n    double startTime = timer.elapsed();\n    double totalTime = deadline - startTime;\n    if (totalTime <= 1e-4) return;\n    vector<int> bestOrder = order;\n    int bestCost = costVal;\n    int n = order.size();\n    const double START_TEMP = 4.0;\n    const double END_TEMP = 0.1;\n    while (true) {\n        double now = timer.elapsed();\n        if (now >= deadline) break;\n        double progress = (now - startTime) / totalTime;\n        progress = min(max(progress, 0.0), 1.0);\n        double temp = START_TEMP + (END_TEMP - START_TEMP) * progress;\n        temp = max(temp, 1e-4);\n        int op = rng.nextInt(4);\n        if (op == 0) {\n            if (n <= 1) continue;\n            int i = rng.nextInt(n);\n            int j = rng.nextInt(n - 1);\n            if (j >= i) ++j;\n            int delta = swapDelta(order, i, j, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                swap(order[i], order[j]);\n                costVal += delta;\n                if (costVal < bestCost) { bestCost = costVal; bestOrder = order; }\n            }\n        } else if (op == 1) {\n            int len = (n >= 4 && rng.nextDouble() < 0.5) ? 2 : 1;\n            if (n <= len) continue;\n            int L = rng.nextInt(n - len + 1);\n            int pos = rng.nextInt(n + 1);\n            if (pos >= L && pos <= L + len) continue;\n            int delta = segmentMoveDelta(order, L, len, pos, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                applySegmentMove(order, L, len, pos);\n                costVal += delta;\n                if (costVal < bestCost) { bestCost = costVal; bestOrder = order; }\n            }\n        } else if (op == 2) {\n            if (n < 3) continue;\n            int l = rng.nextInt(n - 1);\n            int r = rng.nextInt(n - l - 1) + l + 1;\n            int delta = twoOptDelta(order, l, r, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                reverse(order.begin() + l, order.begin() + r + 1);\n                costVal += delta;\n                if (costVal < bestCost) { bestCost = costVal; bestOrder = order; }\n            }\n        } else {\n            if (n < 5) continue;\n            int len = 3;\n            int L = rng.nextInt(n - len + 1);\n            int pos = rng.nextInt(n + 1);\n            if (pos >= L && pos <= L + len) continue;\n            int delta = segmentMoveDelta(order, L, len, pos, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                applySegmentMove(order, L, len, pos);\n                costVal += delta;\n                if (costVal < bestCost) { bestCost = costVal; bestOrder = order; }\n            }\n        }\n    }\n    if (bestCost < costVal) {\n        order = bestOrder;\n        costVal = bestCost;\n    }\n}\n\nbool applyDoubleBridge(vector<int>& order, XorShift64& rng) {\n    int n = order.size();\n    if (n < 8) return false;\n    for (int attempt = 0; attempt < 20; ++attempt) {\n        array<int,4> cuts;\n        for (int i = 0; i < 4; ++i) cuts[i] = rng.nextInt(n - 1) + 1;\n        sort(cuts.begin(), cuts.end());\n        bool ok = true;\n        for (int i = 1; i < 4; ++i) if (cuts[i] == cuts[i - 1]) { ok = false; break; }\n        if (!ok) continue;\n        if (cuts[0] == 0 || cuts[3] >= n) continue;\n        vector<int> newOrder;\n        newOrder.reserve(n);\n        newOrder.insert(newOrder.end(), order.begin(), order.begin() + cuts[0]);\n        newOrder.insert(newOrder.end(), order.begin() + cuts[2], order.begin() + cuts[3]);\n        newOrder.insert(newOrder.end(), order.begin() + cuts[1], order.begin() + cuts[2]);\n        newOrder.insert(newOrder.end(), order.begin() + cuts[0], order.begin() + cuts[1]);\n        newOrder.insert(newOrder.end(), order.begin() + cuts[3], order.end());\n        order.swap(newOrder);\n        return true;\n    }\n    return false;\n}\n\nbool randomSegmentMoveRaw(vector<int>& order, int len, XorShift64& rng) {\n    int n = order.size();\n    if (n <= len) {\n        len = max(1, n - 1);\n        if (len <= 0) return false;\n    }\n    int L = rng.nextInt(n - len + 1);\n    int pos = rng.nextInt(n + 1);\n    if (pos >= L && pos <= L + len) {\n        pos = (rng.nextDouble() < 0.5) ? 0 : n;\n        if (pos >= L && pos <= L + len) return false;\n    }\n    applySegmentMove(order, L, len, pos);\n    return true;\n}\n\nvoid randomPerturb(vector<int>& order, XorShift64& rng) {\n    int n = order.size();\n    if (n < 4) return;\n    bool dbApplied = false;\n    int ops = 6;\n    for (int k = 0; k < ops; ++k) {\n        double r = rng.nextDouble();\n        if (r < 0.35 && n >= 8) {\n            dbApplied |= applyDoubleBridge(order, rng);\n        } else {\n            int lenChoice = (rng.nextDouble() < 0.6) ? 1 : ((rng.nextDouble() < 0.5) ? 2 : 3);\n            randomSegmentMoveRaw(order, min(lenChoice, max(1, n - 1)), rng);\n        }\n    }\n    if (!dbApplied && n >= 8) applyDoubleBridge(order, rng);\n}\n\nstring buildLuckyString(const vector<int>& order,\n                        const vector<string>& words,\n                        const vector<vector<int>>& overlap) {\n    if (order.empty()) return \"\";\n    string result = words[order[0]];\n    for (int idx = 1; idx < (int)order.size(); ++idx) {\n        int u = order[idx - 1];\n        int v = order[idx];\n        int ov = overlap[u][v];\n        result.append(words[v].substr(ov));\n    }\n    return result;\n}\n\nvoid ensureCoverage(string &S, const vector<string>& words,\n                    const unordered_map<int,int>& codeToIdx) {\n    int M = words.size();\n    vector<char> seen(M, 0);\n    int covered = 0;\n    int windowLen = 0;\n    int code = 0;\n    for (char c : S) {\n        int val = c - 'A';\n        if (windowLen < 5) {\n            code = code * 26 + val;\n            ++windowLen;\n        } else {\n            code %= CODE_POWER;\n            code = code * 26 + val;\n        }\n        if (windowLen >= 5) {\n            auto it = codeToIdx.find(code);\n            if (it != codeToIdx.end() && !seen[it->second]) {\n                seen[it->second] = 1;\n                ++covered;\n                if (covered == M) return;\n            }\n        }\n    }\n    if (covered == M) return;\n    auto appendWord = [&](const string& w) {\n        int overlapLen = 0;\n        int limit = min(4, (int)S.size());\n        for (int len = limit; len >= 0; --len) {\n            bool ok = true;\n            for (int k = 0; k < len; ++k) {\n                if (S[S.size() - len + k] != w[k]) { ok = false; break; }\n            }\n            if (ok) { overlapLen = len; break; }\n        }\n        for (int k = overlapLen; k < 5; ++k) {\n            char c = w[k];\n            S.push_back(c);\n            int val = c - 'A';\n            if (windowLen < 5) {\n                code = code * 26 + val;\n                ++windowLen;\n            } else {\n                code %= CODE_POWER;\n                code = code * 26 + val;\n            }\n            if (windowLen >= 5) {\n                auto it = codeToIdx.find(code);\n                if (it != codeToIdx.end() && !seen[it->second]) {\n                    seen[it->second] = 1;\n                    ++covered;\n                }\n            }\n        }\n    };\n    for (int idx = 0; idx < M; ++idx) {\n        if (!seen[idx]) {\n            appendWord(words[idx]);\n            if (covered == M) break;\n        }\n    }\n}\n\nstruct TypingResult {\n    vector<int> path;\n    int cost;\n};\n\nTypingResult buildTypingPlan(const string& S, int si, int sj,\n                             const vector<vector<int>>& cellsByChar,\n                             const vector<int>& rowOfCell,\n                             const vector<int>& colOfCell) {\n    const int INF = 1e9;\n    if (S.empty()) return {{}, INF};\n    int L = S.size();\n    vector<vector<int>> dp(L);\n    vector<vector<int>> parent(L);\n    for (int pos = 0; pos < L; ++pos) {\n        int c = S[pos] - 'A';\n        const auto &cells = cellsByChar[c];\n        int m = cells.size();\n        dp[pos].assign(m, INF);\n        parent[pos].assign(m, -1);\n        if (pos == 0) {\n            for (int idx = 0; idx < m; ++idx) {\n                int cell = cells[idx];\n                dp[pos][idx] = abs(rowOfCell[cell] - si) + abs(colOfCell[cell] - sj) + 1;\n            }\n        } else {\n            int prevC = S[pos - 1] - 'A';\n            const auto &prevCells = cellsByChar[prevC];\n            for (int idx = 0; idx < m; ++idx) {\n                int cell = cells[idx];\n                int bestVal = INF;\n                int bestPrev = -1;\n                for (int p = 0; p < (int)prevCells.size(); ++p) {\n                    int prevCell = prevCells[p];\n                    int prevCost = dp[pos - 1][p];\n                    if (prevCost >= INF) continue;\n                    int dist = abs(rowOfCell[cell] - rowOfCell[prevCell]) +\n                               abs(colOfCell[cell] - colOfCell[prevCell]);\n                    int cand = prevCost + dist + 1;\n                    if (cand < bestVal) {\n                        bestVal = cand;\n                        bestPrev = p;\n                    }\n                }\n                dp[pos][idx] = bestVal;\n                parent[pos][idx] = bestPrev;\n            }\n        }\n    }\n    int lastPos = L - 1;\n    const auto &lastCells = cellsByChar[S[lastPos] - 'A'];\n    int bestIdx = -1;\n    int bestVal = INF;\n    for (int idx = 0; idx < (int)lastCells.size(); ++idx) {\n        if (dp[lastPos][idx] < bestVal) {\n            bestVal = dp[lastPos][idx];\n            bestIdx = idx;\n        }\n    }\n    if (bestIdx == -1) return {{}, INF};\n    vector<int> path(L);\n    int curIdx = bestIdx;\n    for (int pos = L - 1; pos >= 0; --pos) {\n        path[pos] = cellsByChar[S[pos] - 'A'][curIdx];\n        if (pos == 0) break;\n        curIdx = parent[pos][curIdx];\n        if (curIdx < 0) curIdx = 0;\n    }\n    return {path, bestVal};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TOTAL_LIMIT = 1.95;\n    const double RESERVED_TIME = 0.20;\n    double heurDeadline = min(1.70, TOTAL_LIMIT - RESERVED_TIME);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n    vector<string> words(M);\n    for (int i = 0; i < M; ++i) cin >> words[i];\n\n    vector<int> rowOfCell(N * N), colOfCell(N * N);\n    vector<vector<int>> cellsByChar(26);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int idx = i * N + j;\n            rowOfCell[idx] = i;\n            colOfCell[idx] = j;\n            cellsByChar[grid[i][j] - 'A'].push_back(idx);\n        }\n    }\n\n    unordered_map<int,int> codeToIdx;\n    codeToIdx.reserve(M * 2);\n    for (int i = 0; i < M; ++i) codeToIdx[encodeWord(words[i])] = i;\n\n    vector<vector<int>> overlap(M, vector<int>(M, 0));\n    vector<vector<int>> baseEdge(M, vector<int>(M, 5));\n    for (int i = 0; i < M; ++i) for (int j = 0; j < M; ++j) if (i != j) {\n        int ov = calcOverlap(words[i], words[j]);\n        overlap[i][j] = ov;\n        baseEdge[i][j] = 5 - ov;\n    }\n\n    vector<vector<int>> approxDist(26, vector<int>(26, INT_MAX));\n    for (int a = 0; a < 26; ++a) {\n        for (int b = 0; b < 26; ++b) {\n            int best = INT_MAX;\n            for (int cellA : cellsByChar[a]) {\n                for (int cellB : cellsByChar[b]) {\n                    int dist = abs(rowOfCell[cellA] - rowOfCell[cellB]) +\n                               abs(colOfCell[cellA] - colOfCell[cellB]) + 1;\n                    if (dist < best) best = dist;\n                }\n            }\n            approxDist[a][b] = best;\n        }\n    }\n\n    vector<vector<int>> approxEdge(M, vector<int>(M, 0));\n    double sumBase = 0.0, sumApprox = 0.0;\n    long long pairCnt = 0;\n    for (int u = 0; u < M; ++u) {\n        for (int v = 0; v < M; ++v) if (u != v) {\n            int ov = overlap[u][v];\n            if (ov >= 5) { approxEdge[u][v] = 0; }\n            else {\n                int prevChar = words[u].back() - 'A';\n                int first = words[v][ov] - 'A';\n                int cost = approxDist[prevChar][first];\n                for (int k = ov + 1; k < 5; ++k) {\n                    int a = words[v][k - 1] - 'A';\n                    int b = words[v][k] - 'A';\n                    cost += approxDist[a][b];\n                }\n                approxEdge[u][v] = cost;\n            }\n            sumBase += baseEdge[u][v];\n            sumApprox += approxEdge[u][v];\n            ++pairCnt;\n        }\n    }\n    double avgBase = sumBase / max(1ll, pairCnt);\n    double avgApprox = sumApprox / max(1ll, pairCnt);\n    double ratio = (avgApprox > 1e-9) ? avgBase / avgApprox : 0.2;\n    ratio = max(0.05, min(1.0, ratio * 1.1)); // slightly emphasise keyboard\n    vector<vector<int>> heurCost(M, vector<int>(M, 0));\n    for (int i = 0; i < M; ++i) {\n        for (int j = 0; j < M; ++j) if (i != j) {\n            double val = baseEdge[i][j] + ratio * approxEdge[i][j];\n            heurCost[i][j] = (int)llround(val * 100.0);\n        }\n    }\n\n    vector<int> sumOut(M, 0);\n    for (int i = 0; i < M; ++i) {\n        long long s = 0;\n        for (int j = 0; j < M; ++j) if (i != j) s += heurCost[i][j];\n        sumOut[i] = (int)s;\n    }\n\n    uint64_t seed = 1469598103934665603ull;\n    seed = seed * 1000003 + si * 911 + sj * 1013;\n    for (const auto &row : grid) for (char c : row) seed = seed * 1000003 + (unsigned char)c;\n    for (const auto &w : words) for (char c : w) seed = seed * 1000003 + (unsigned char)c;\n    XorShift64 rng(seed);\n\n    vector<uint64_t> randWord(M);\n    for (int i = 0; i < M; ++i) randWord[i] = rng.next();\n\n    auto computeHash = [&](const vector<int>& ord) -> uint64_t {\n        uint64_t h = 1469598103934665603ull;\n        for (int v : ord) {\n            h ^= randWord[v];\n            h *= 1099511628211ull;\n        }\n        return h;\n    };\n\n    struct EvalCandidate {\n        vector<int> order;\n        int heurCost;\n        uint64_t hash;\n    };\n    vector<EvalCandidate> evalCands;\n    unordered_set<uint64_t> evalHashes;\n    const int MAX_EVAL = 24;\n\n    auto addEvalCandidate = [&](const vector<int>& ord, int costVal) {\n        uint64_t h = computeHash(ord);\n        if (!evalHashes.insert(h).second) return;\n        evalCands.push_back({ord, costVal, h});\n        if ((int)evalCands.size() > MAX_EVAL) {\n            int worst = 0;\n            for (int i = 1; i < (int)evalCands.size(); ++i) {\n                if (evalCands[i].heurCost > evalCands[worst].heurCost) worst = i;\n            }\n            evalHashes.erase(evalCands[worst].hash);\n            evalCands.erase(evalCands.begin() + worst);\n        }\n    };\n\n    vector<vector<int>> candidateOrders;\n    vector<int> candidateCosts;\n    const int MAX_CAND = 12;\n    auto addCandidateOrder = [&](const vector<int>& ord, int costVal) {\n        if ((int)candidateOrders.size() < MAX_CAND) {\n            candidateOrders.push_back(ord);\n            candidateCosts.push_back(costVal);\n        } else {\n            int worstIdx = max_element(candidateCosts.begin(), candidateCosts.end()) - candidateCosts.begin();\n            if (costVal < candidateCosts[worstIdx]) {\n                candidateOrders[worstIdx] = ord;\n                candidateCosts[worstIdx] = costVal;\n            }\n        }\n    };\n\n    vector<int> bestOrder;\n    int bestCost = INT_MAX;\n\n    for (int start = 0; start < M; ++start) {\n        if (timer.elapsed() > heurDeadline && !candidateOrders.empty()) break;\n        auto ord = greedyOrderFromStart(start, false, heurCost, sumOut, rng);\n        int c = computeOrderCost(ord, heurCost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidateOrder(ord, c);\n    }\n\n    int randomGreedyRuns = 100;\n    for (int iter = 0; iter < randomGreedyRuns; ++iter) {\n        if (timer.elapsed() > heurDeadline) break;\n        int start = rng.nextInt(M);\n        auto ord = greedyOrderFromStart(start, true, heurCost, sumOut, rng);\n        int c = computeOrderCost(ord, heurCost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidateOrder(ord, c);\n    }\n\n    if (timer.elapsed() < heurDeadline) {\n        auto ord = cheapestInsertionOrder(true, false, heurCost, sumOut, rng);\n        int c = computeOrderCost(ord, heurCost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidateOrder(ord, c);\n    }\n\n    int insertionRuns = 12;\n    for (int iter = 0; iter < insertionRuns; ++iter) {\n        if (timer.elapsed() > heurDeadline) break;\n        auto ord = cheapestInsertionOrder(false, true, heurCost, sumOut, rng);\n        int c = computeOrderCost(ord, heurCost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidateOrder(ord, c);\n    }\n\n    if (bestOrder.empty()) {\n        bestOrder.resize(M);\n        iota(bestOrder.begin(), bestOrder.end(), 0);\n        bestCost = computeOrderCost(bestOrder, heurCost);\n        addCandidateOrder(bestOrder, bestCost);\n    }\n\n    vector<int> currentOrder = bestOrder;\n    int currentCost = bestCost;\n    deterministicLocalSearch(currentOrder, currentCost, heurCost, timer, heurDeadline);\n    addEvalCandidate(currentOrder, currentCost);\n    if (currentCost < bestCost) { bestCost = currentCost; bestOrder = currentOrder; }\n\n    vector<int> idx(candidateOrders.size());\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int a, int b) { return candidateCosts[a] < candidateCosts[b]; });\n\n    for (int id : idx) {\n        if (timer.elapsed() > heurDeadline) break;\n        vector<int> ord = candidateOrders[id];\n        int c = candidateCosts[id];\n        deterministicLocalSearch(ord, c, heurCost, timer, heurDeadline);\n        addEvalCandidate(ord, c);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n    }\n\n    if (timer.elapsed() < heurDeadline - 0.05) {\n        vector<int> ord = bestOrder;\n        int c = bestCost;\n        double saDeadline = heurDeadline - 0.03;\n        simulatedAnnealing(ord, c, heurCost, rng, timer, saDeadline);\n        deterministicLocalSearch(ord, c, heurCost, timer, heurDeadline);\n        addEvalCandidate(ord, c);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n    }\n\n    while (timer.elapsed() < heurDeadline - 0.05) {\n        vector<int> ord = bestOrder;\n        randomPerturb(ord, rng);\n        int c = computeOrderCost(ord, heurCost);\n        double localDeadline = min(heurDeadline, timer.elapsed() + 0.12);\n        deterministicLocalSearch(ord, c, heurCost, timer, localDeadline);\n        addEvalCandidate(ord, c);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n    }\n\n    addEvalCandidate(bestOrder, bestCost);\n    if (evalCands.empty()) addEvalCandidate(bestOrder, bestCost);\n\n    sort(evalCands.begin(), evalCands.end(),\n         [](const EvalCandidate& a, const EvalCandidate& b) { return a.heurCost < b.heurCost; });\n\n    vector<int> bestPath;\n    int bestTypingCost = INT_MAX;\n\n    for (const auto& cand : evalCands) {\n        string S = buildLuckyString(cand.order, words, overlap);\n        ensureCoverage(S, words, codeToIdx);\n        if ((int)S.size() > 5000) continue;\n        TypingResult res = buildTypingPlan(S, si, sj, cellsByChar, rowOfCell, colOfCell);\n        if (res.cost >= INT_MAX / 2) continue;\n        if (res.cost < bestTypingCost) {\n            bestTypingCost = res.cost;\n            bestPath = move(res.path);\n        }\n    }\n\n    if (bestPath.empty()) {\n        string S = buildLuckyString(bestOrder, words, overlap);\n        ensureCoverage(S, words, codeToIdx);\n        if ((int)S.size() > 5000) S.resize(5000);\n        TypingResult res = buildTypingPlan(S, si, sj, cellsByChar, rowOfCell, colOfCell);\n        bestPath = move(res.path);\n    }\n\n    for (int cell : bestPath) {\n        cout << rowOfCell[cell] << ' ' << colOfCell[cell] << '\\n';\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAX_N = 20;\nconstexpr int MAX_CELLS = MAX_N * MAX_N;\nconstexpr double LOG_SEARCH_LIMIT = 12.0;             // exp(12) \u2248 1.6e5 combinations\nconstexpr long long SEARCH_NODE_LIMIT = 1'000'000;    // DFS node cap\nconstexpr long long SEARCH_SOLUTION_LIMIT = 120'000;  // solution enumeration cap\n\nstruct Candidate {\n    vector<int> cells;\n    bitset<MAX_CELLS> mask;\n};\n\nstruct FieldState {\n    vector<Candidate> candidates;\n    vector<char> alive;\n    int rem = 0;\n    vector<int> cellCoverCount;\n    vector<unsigned char> possibleFlag;\n    vector<unsigned char> guaranteedFlag;\n    bool fixed = false;\n    int fixedCandidate = -1;\n    vector<vector<int>> cellToCand;\n};\n\nint N, M;\ndouble eps;\nint nCells;\nvector<FieldState> fields;\nvector<int> assigned_total;\nvector<int> observed;\nvector<char> drilled;\nvector<int> observed_cells;\nvector<int> possible_sum;\nvector<int> guaranteed_sum;\nvector<int> cellStatus;   // -1 unknown, 0 zero, 1 positive\nvector<char> zeroProcessed;\nvector<int> zero_queue;\nint fixed_fields = 0;\nbool contradiction = false;\nmt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\ninline int cell_id(int i, int j) { return i * N + j; }\n\ninline bool set_status(int idx, int val) {\n    if (cellStatus[idx] == val) return false;\n    cellStatus[idx] = val;\n    if (val == 0) zero_queue.push_back(idx);\n    return true;\n}\n\nbool update_trivial_positions();\nbool process_zero_queue();\nbool apply_propagation();\nvoid fix_field(int k);\nvoid eliminate_candidate(int k, int t);\n\nvoid recompute_field_flags(int k) {\n    FieldState &F = fields[k];\n    if (F.fixed) return;\n    for (int idx = 0; idx < nCells; ++idx) {\n        unsigned char newPossible = (F.cellCoverCount[idx] > 0) ? 1 : 0;\n        unsigned char newGuaranteed = (F.rem > 0 && F.cellCoverCount[idx] == F.rem) ? 1 : 0;\n        if (newPossible != F.possibleFlag[idx]) {\n            possible_sum[idx] += int(newPossible) - int(F.possibleFlag[idx]);\n            F.possibleFlag[idx] = newPossible;\n        }\n        if (newGuaranteed != F.guaranteedFlag[idx]) {\n            guaranteed_sum[idx] += int(newGuaranteed) - int(F.guaranteedFlag[idx]);\n            F.guaranteedFlag[idx] = newGuaranteed;\n        }\n    }\n}\n\nvoid fix_field(int k) {\n    FieldState &F = fields[k];\n    if (F.fixed) return;\n    int t = -1;\n    for (int i = 0; i < (int)F.candidates.size(); ++i) if (F.alive[i]) { t = i; break; }\n    if (t == -1) { contradiction = true; return; }\n    F.fixed = true;\n    F.fixedCandidate = t;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (F.possibleFlag[idx]) { possible_sum[idx] -= 1; F.possibleFlag[idx] = 0; }\n        if (F.guaranteedFlag[idx]) { guaranteed_sum[idx] -= 1; F.guaranteedFlag[idx] = 0; }\n    }\n    F.alive.assign(F.candidates.size(), 0);\n    F.alive[t] = 1;\n    F.rem = 0;\n    for (int idx : F.candidates[t].cells) {\n        assigned_total[idx]++;\n        set_status(idx, 1);\n    }\n    fixed_fields++;\n}\n\nvoid eliminate_candidate(int k, int t) {\n    FieldState &F = fields[k];\n    if (F.fixed || !F.alive[t]) return;\n    F.alive[t] = false;\n    F.rem--;\n    for (int idx : F.candidates[t].cells) F.cellCoverCount[idx]--;\n    recompute_field_flags(k);\n    if (F.rem < 0) contradiction = true;\n    else if (F.rem == 0) contradiction = true;\n    else if (F.rem == 1) fix_field(k);\n}\n\nbool check_candidate(int k, int t) {\n    FieldState &F = fields[k];\n    const Candidate &cand = F.candidates[t];\n    for (int idx : observed_cells) {\n        if (!F.possibleFlag[idx]) continue;\n        int cover = cand.mask.test(idx) ? 1 : 0;\n        int need = observed[idx] - (assigned_total[idx] + cover);\n        int min_other = guaranteed_sum[idx];\n        int max_other = possible_sum[idx];\n        if (F.guaranteedFlag[idx]) min_other -= 1;\n        if (F.possibleFlag[idx]) max_other -= 1;\n        if (need < min_other || need > max_other) return false;\n    }\n    return true;\n}\n\nbool validate_bounds() {\n    for (int idx : observed_cells) {\n        int min_total = assigned_total[idx] + guaranteed_sum[idx];\n        int max_total = assigned_total[idx] + possible_sum[idx];\n        if (observed[idx] < min_total || observed[idx] > max_total) return false;\n    }\n    return true;\n}\n\nbool run_propagation() {\n    bool changed = true;\n    while (!contradiction && changed) {\n        changed = false;\n        for (int k = 0; k < M; ++k) {\n            FieldState &F = fields[k];\n            if (F.fixed) continue;\n            for (int t = 0; t < (int)F.candidates.size(); ++t) {\n                if (!F.alive[t]) continue;\n                if (!check_candidate(k, t)) {\n                    eliminate_candidate(k, t);\n                    changed = true;\n                    if (contradiction) return false;\n                }\n            }\n        }\n        if (!validate_bounds()) return false;\n    }\n    return true;\n}\n\nbool update_trivial_positions() {\n    bool changed = false;\n    for (int idx = 0; idx < nCells; ++idx) {\n        int oldStatus = cellStatus[idx];\n        int newStatus = oldStatus;\n        if (drilled[idx] && observed[idx] >= 0) newStatus = (observed[idx] > 0) ? 1 : 0;\n        else {\n            if (assigned_total[idx] > 0 || guaranteed_sum[idx] > 0) newStatus = 1;\n            else if (possible_sum[idx] == 0) newStatus = 0;\n        }\n        if (newStatus != oldStatus) {\n            cellStatus[idx] = newStatus;\n            changed = true;\n            if (newStatus == 0) zero_queue.push_back(idx);\n        }\n    }\n    return changed;\n}\n\nbool process_zero_queue() {\n    bool changed = false;\n    while (!zero_queue.empty()) {\n        int idx = zero_queue.back();\n        zero_queue.pop_back();\n        if (cellStatus[idx] != 0 || zeroProcessed[idx]) continue;\n        zeroProcessed[idx] = 1;\n        for (int k = 0; k < M; ++k) {\n            FieldState &F = fields[k];\n            if (F.fixed) continue;\n            for (int t : F.cellToCand[idx]) {\n                if (!F.alive[t]) continue;\n                eliminate_candidate(k, t);\n                changed = true;\n                if (contradiction) return true;\n            }\n        }\n    }\n    return changed;\n}\n\nbool apply_propagation() {\n    while (true) {\n        if (!run_propagation()) return false;\n        bool statusChanged = update_trivial_positions();\n        bool zeroEffect = process_zero_queue();\n        if (contradiction) return false;\n        if (!statusChanged && !zeroEffect) break;\n    }\n    return true;\n}\n\nint drill_cell(int idx) {\n    if (drilled[idx]) return observed[idx];\n    int i = idx / N, j = idx % N;\n    cout << \"q 1 \" << i << ' ' << j << '\\n' << flush;\n    int val;\n    if (!(cin >> val)) exit(0);\n    drilled[idx] = 1;\n    observed[idx] = val;\n    set_status(idx, (val > 0) ? 1 : 0);\n    observed_cells.push_back(idx);\n    return val;\n}\n\nbool all_cells_determined() {\n    for (int idx = 0; idx < nCells; ++idx) if (cellStatus[idx] == -1) return false;\n    return true;\n}\n\nint select_any_undetermined_cell() {\n    for (int idx = 0; idx < nCells; ++idx) if (cellStatus[idx] == -1) return idx;\n    return -1;\n}\n\nint select_next_cell() {\n    long long bestScore = -1;\n    int bestIdx = -1;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (drilled[idx] || cellStatus[idx] != -1) continue;\n        long long score = 0;\n        for (int k = 0; k < M; ++k) {\n            FieldState &F = fields[k];\n            if (F.fixed || F.rem <= 1) continue;\n            int cnt = F.cellCoverCount[idx];\n            if (cnt == 0 || cnt == F.rem) continue;\n            score += min(cnt, F.rem - cnt);\n        }\n        if (score > bestScore) { bestScore = score; bestIdx = idx; }\n        else if (score == bestScore && score > 0 && (rng() & 1)) bestIdx = idx;\n    }\n    if (bestIdx != -1 && bestScore > 0) return bestIdx;\n    long long fallbackScore = -1;\n    int fallbackIdx = -1;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (drilled[idx] || cellStatus[idx] != -1) continue;\n        long long s = possible_sum[idx] - guaranteed_sum[idx];\n        if (s < 0) s = 0;\n        if (s > fallbackScore) { fallbackScore = s; fallbackIdx = idx; }\n    }\n    return fallbackIdx;\n}\n\nstruct AttemptResult { bool progress = false, needPropagation = false; };\n\nAttemptResult attempt_search() {\n    AttemptResult result;\n    if (contradiction || observed_cells.empty()) return result;\n\n    vector<int> order;\n    order.reserve(M);\n    double logSum = 0.0;\n    for (int k = 0; k < M; ++k) {\n        FieldState &F = fields[k];\n        if (F.fixed || F.rem <= 0) continue;\n        bool touches = false;\n        for (int idx : observed_cells) if (F.possibleFlag[idx]) { touches = true; break; }\n        if (!touches) continue;\n        order.push_back(k);\n        logSum += log((double)F.rem);\n    }\n    if (order.empty() || logSum > LOG_SEARCH_LIMIT) return result;\n\n    int K = (int)order.size();\n    int obsCount = observed_cells.size();\n    vector<int> obsIndex(nCells, -1);\n    for (int i = 0; i < obsCount; ++i) obsIndex[observed_cells[i]] = i;\n    vector<int> residual(obsCount);\n    for (int i = 0; i < obsCount; ++i) {\n        residual[i] = observed[observed_cells[i]] - assigned_total[observed_cells[i]];\n        if (residual[i] < 0) { contradiction = true; return result; }\n    }\n    vector<vector<int>> suffixPossible(K + 1, vector<int>(obsCount, 0));\n    for (int pos = K - 1; pos >= 0; --pos) {\n        suffixPossible[pos] = suffixPossible[pos + 1];\n        FieldState &F = fields[order[pos]];\n        for (int i = 0; i < obsCount; ++i) if (F.possibleFlag[observed_cells[i]]) suffixPossible[pos][i]++;\n    }\n    for (int i = 0; i < obsCount; ++i) if (residual[i] > suffixPossible[0][i]) { contradiction = true; return result; }\n\n    vector<vector<int>> candList(K);\n    vector<vector<vector<int>>> candObs(K);\n    for (int pos = 0; pos < K; ++pos) {\n        FieldState &F = fields[order[pos]];\n        for (int t = 0; t < (int)F.candidates.size(); ++t) if (F.alive[t]) {\n            candList[pos].push_back(t);\n            vector<int> obsVec;\n            for (int cell : F.candidates[t].cells) {\n                int map = obsIndex[cell];\n                if (map != -1) obsVec.push_back(map);\n            }\n            candObs[pos].push_back(move(obsVec));\n        }\n        if (candList[pos].empty()) { contradiction = true; return result; }\n    }\n\n    vector<int> enumPossible(nCells, 0);\n    for (int fk : order) {\n        FieldState &F = fields[fk];\n        for (int idx = 0; idx < nCells; ++idx) if (F.possibleFlag[idx]) enumPossible[idx]++;\n    }\n\n    vector<vector<char>> used(K);\n    for (int pos = 0; pos < K; ++pos) used[pos].assign(candList[pos].size(), 0);\n    vector<uint16_t> curTotal(nCells, 0);\n    for (int idx = 0; idx < nCells; ++idx) curTotal[idx] = assigned_total[idx];\n    vector<char> alwaysPos(nCells, 1), everPos(nCells, 0);\n    vector<int> chosenLocal(K, -1);\n\n    long long nodeCount = 0, solutionCount = 0;\n    bool aborted = false;\n\n    auto dfs = [&](auto&& self, int pos) -> void {\n        if (aborted) return;\n        if (++nodeCount > SEARCH_NODE_LIMIT) { aborted = true; return; }\n        for (int i = 0; i < obsCount; ++i) if (residual[i] > suffixPossible[pos][i]) return;\n        if (pos == K) {\n            for (int i = 0; i < obsCount; ++i) if (residual[i] != 0) return;\n            solutionCount++;\n            if (solutionCount > SEARCH_SOLUTION_LIMIT) { aborted = true; return; }\n            for (int idx = 0; idx < nCells; ++idx) {\n                bool positive = curTotal[idx] > 0;\n                if (!positive) alwaysPos[idx] = 0;\n                else everPos[idx] = 1;\n            }\n            for (int p = 0; p < K; ++p) {\n                int loc = chosenLocal[p];\n                if (loc >= 0) used[p][loc] = 1;\n            }\n            return;\n        }\n        int fk = order[pos];\n        auto &candIdxs = candList[pos];\n        auto &candObsList = candObs[pos];\n        for (int ci = 0; ci < (int)candIdxs.size(); ++ci) {\n            auto &obsVec = candObsList[ci];\n            bool ok = true;\n            for (int obsId : obsVec) if (residual[obsId] == 0) { ok = false; break; }\n            if (!ok) continue;\n            for (int obsId : obsVec) residual[obsId]--;\n            for (int cell : fields[fk].candidates[candIdxs[ci]].cells) curTotal[cell]++;\n            chosenLocal[pos] = ci;\n            self(self, pos + 1);\n            chosenLocal[pos] = -1;\n            for (int cell : fields[fk].candidates[candIdxs[ci]].cells) curTotal[cell]--;\n            for (int obsId : obsVec) residual[obsId]++;\n            if (aborted) return;\n        }\n    };\n\n    dfs(dfs, 0);\n    if (aborted) return result;\n    if (solutionCount == 0) { contradiction = true; return result; }\n\n    bool statusChange = false;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (alwaysPos[idx]) {\n            if (set_status(idx, 1)) statusChange = true;\n        } else if (!everPos[idx] && enumPossible[idx] == possible_sum[idx]) {\n            if (set_status(idx, 0)) statusChange = true;\n        }\n    }\n\n    bool fieldsChanged = false;\n    for (int pos = 0; pos < K; ++pos) {\n        int fk = order[pos];\n        for (int ci = 0; ci < (int)candList[pos].size(); ++ci) {\n            if (!used[pos][ci]) {\n                int candIdx = candList[pos][ci];\n                if (fields[fk].alive[candIdx]) {\n                    eliminate_candidate(fk, candIdx);\n                    fieldsChanged = true;\n                    if (contradiction) return result;\n                }\n            }\n        }\n    }\n\n    result.progress = statusChange || fieldsChanged;\n    result.needPropagation = fieldsChanged || statusChange;\n    return result;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> M >> eps)) return 0;\n    nCells = N * N;\n    fields.resize(M);\n    assigned_total.assign(nCells, 0);\n    observed.assign(nCells, -1);\n    drilled.assign(nCells, 0);\n    possible_sum.assign(nCells, 0);\n    guaranteed_sum.assign(nCells, 0);\n    cellStatus.assign(nCells, -1);\n    zeroProcessed.assign(nCells, 0);\n    observed_cells.reserve(nCells);\n\n    for (int k = 0; k < M; ++k) {\n        int d;\n        cin >> d;\n        vector<pair<int,int>> shape(d);\n        int max_i = 0, max_j = 0;\n        for (int t = 0; t < d; ++t) {\n            int a,b; cin >> a >> b;\n            shape[t] = {a,b};\n            max_i = max(max_i, a);\n            max_j = max(max_j, b);\n        }\n        FieldState &F = fields[k];\n        for (int di = 0; di + max_i < N; ++di) {\n            for (int dj = 0; dj + max_j < N; ++dj) {\n                Candidate cand;\n                cand.cells.reserve(d);\n                cand.mask.reset();\n                bool ok = true;\n                for (auto [a,b] : shape) {\n                    int ii = di + a, jj = dj + b;\n                    if (ii < 0 || ii >= N || jj < 0 || jj >= N) { ok = false; break; }\n                    int idx = cell_id(ii,jj);\n                    cand.cells.push_back(idx);\n                    cand.mask.set(idx);\n                }\n                if (ok) F.candidates.push_back(move(cand));\n            }\n        }\n        F.rem = (int)F.candidates.size();\n        if (F.rem == 0) contradiction = true;\n        F.alive.assign(F.rem, 1);\n        F.cellCoverCount.assign(nCells, 0);\n        for (int t = 0; t < F.rem; ++t)\n            for (int idx : F.candidates[t].cells)\n                F.cellCoverCount[idx]++;\n        F.cellToCand.assign(nCells, {});\n        for (int t = 0; t < F.rem; ++t)\n            for (int idx : F.candidates[t].cells)\n                F.cellToCand[idx].push_back(t);\n        F.possibleFlag.assign(nCells, 0);\n        F.guaranteedFlag.assign(nCells, 0);\n        for (int idx = 0; idx < nCells; ++idx) {\n            if (F.cellCoverCount[idx] > 0) { F.possibleFlag[idx] = 1; possible_sum[idx] += 1; }\n            if (F.rem > 0 && F.cellCoverCount[idx] == F.rem) { F.guaranteedFlag[idx] = 1; guaranteed_sum[idx] += 1; }\n        }\n    }\n\n    for (int k = 0; k < M; ++k)\n        if (!fields[k].fixed && fields[k].rem == 1)\n            fix_field(k);\n\n    update_trivial_positions();\n    process_zero_queue();\n\n    while (!contradiction && !all_cells_determined()) {\n        AttemptResult sr = attempt_search();\n        if (contradiction) break;\n        if (sr.needPropagation) {\n            if (!apply_propagation()) break;\n            continue;\n        }\n        if (sr.progress) continue;\n        int next = select_next_cell();\n        if (next == -1) next = select_any_undetermined_cell();\n        if (next == -1) break;\n        drill_cell(next);\n        if (!apply_propagation()) break;\n    }\n\n    if (contradiction || !all_cells_determined()) {\n        for (int idx = 0; idx < nCells; ++idx)\n            if (!drilled[idx]) drill_cell(idx);\n        apply_propagation();\n    }\n\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (cellStatus[idx] == -1) {\n            if (observed[idx] >= 0) set_status(idx, (observed[idx] > 0) ? 1 : 0);\n            else if (assigned_total[idx] > 0 || guaranteed_sum[idx] > 0) set_status(idx, 1);\n            else set_status(idx, 0);\n        }\n    }\n\n    vector<pair<int,int>> answer;\n    for (int idx = 0; idx < nCells; ++idx)\n        if (cellStatus[idx] == 1)\n            answer.emplace_back(idx / N, idx % N);\n\n    cout << \"a \" << answer.size();\n    for (auto [i,j] : answer) cout << ' ' << i << ' ' << j;\n    cout << '\\n' << flush;\n\n    int verdict;\n    if (!(cin >> verdict)) return 0;\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RectInfo {\n    int i0 = 0, j0 = 0, i1 = 1, j1 = 1;\n};\n\nstruct TreeNode {\n    int left = -1;\n    int right = -1;\n    int leaf = -1;\n    bool isLeaf = false;\n    bool splitHorizontal = false;\n};\n\nint W, D, N;\nlong long TOT;\n\nvector<vector<int>> demands;\nvector<long long> baseArea;\nvector<int> orderIdx;\n\nvector<TreeNode> nodes;\nint rootNode = -1;\n\nvector<RectInfo> currentRects;\nvector<long long> leafActualArea;\nvector<long double> subtreeWeight;\n\nvector<long long> compute_base_area() {\n    const long long baseMin = 1;\n    vector<long long> area(N, baseMin);\n    vector<vector<int>> stats(N, vector<int>(D));\n    for (int d = 0; d < D; ++d)\n        for (int k = 0; k < N; ++k)\n            stats[k][d] = demands[d][N - 1 - k];\n    for (int k = 0; k < N; ++k) sort(stats[k].begin(), stats[k].end());\n\n    struct NodeWF { int benefit; long long len; int idx; };\n    struct CmpWF {\n        bool operator()(const NodeWF& a, const NodeWF& b) const {\n            if (a.benefit != b.benefit) return a.benefit < b.benefit;\n            if (a.len != b.len) return a.len < b.len;\n            return a.idx > b.idx;\n        }\n    };\n    vector<int> ptr(N, 0);\n    priority_queue<NodeWF, vector<NodeWF>, CmpWF> pq;\n    auto push = [&](int j) {\n        while (ptr[j] < D && (long long)stats[j][ptr[j]] <= area[j]) ptr[j]++;\n        if (ptr[j] >= D) return;\n        long long len = (long long)stats[j][ptr[j]] - area[j];\n        if (len <= 0) return;\n        int benefit = D - ptr[j];\n        if (benefit <= 0) return;\n        pq.push(NodeWF{benefit, len, j});\n    };\n    for (int j = 0; j < N; ++j) push(j);\n\n    long long used = baseMin * N;\n    long long remaining = TOT - used;\n    while (remaining > 0 && !pq.empty()) {\n        NodeWF cur = pq.top(); pq.pop();\n        long long take = min(cur.len, remaining);\n        area[cur.idx] += take;\n        remaining -= take;\n        cur.len -= take;\n        if (cur.len > 0) pq.push(cur);\n        else push(cur.idx);\n    }\n    long long sum = accumulate(area.begin(), area.end(), 0LL);\n    if (sum < TOT) {\n        long long leftover = TOT - sum;\n        long long addEach = leftover / N;\n        if (addEach > 0) {\n            for (int i = 0; i < N; ++i) area[i] += addEach;\n            leftover -= addEach * N;\n        }\n        for (int i = 0; i < N && leftover > 0; ++i) {\n            area[i] += 1;\n            leftover -= 1;\n        }\n    }\n    return area;\n}\n\nint build_tree(const vector<int>& ids, int x0, int y0, int x1, int y1) {\n    int nodeId = (int)nodes.size();\n    nodes.push_back(TreeNode());\n    TreeNode &node = nodes.back();\n    if ((int)ids.size() == 1) {\n        node.isLeaf = true;\n        node.leaf = ids[0];\n        return nodeId;\n    }\n    int h = x1 - x0;\n    int w = y1 - y0;\n\n    vector<long long> prefix(ids.size() + 1, 0);\n    for (int i = 0; i < (int)ids.size(); ++i)\n        prefix[i + 1] = prefix[i] + baseArea[ids[i]];\n    long long total = prefix.back();\n    int bestMid = 1;\n    long long bestDiff = (1LL << 62);\n    for (int mid = 1; mid < (int)ids.size(); ++mid) {\n        long long diff = llabs(prefix[mid] * 2 - total);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestMid = mid;\n        }\n    }\n    vector<int> leftIds(ids.begin(), ids.begin() + bestMid);\n    vector<int> rightIds(ids.begin() + bestMid, ids.end());\n    long long sumLeft = prefix[bestMid];\n\n    bool preferHoriz = (h >= w);\n    int splitLen = -1;\n    bool ok = false;\n\n    auto try_split_horizontal = [&](long long needLeft) -> bool {\n        if (h < 2) return false;\n        long double ratio = total > 0 ? (long double)needLeft / (long double)total : 0.5L;\n        int split = (int)llround((long double)h * ratio);\n        split = max(1, min(h - 1, split));\n        splitLen = split;\n        return true;\n    };\n    auto try_split_vertical = [&](long long needLeft) -> bool {\n        if (w < 2) return false;\n        long double ratio = total > 0 ? (long double)needLeft / (long double)total : 0.5L;\n        int split = (int)llround((long double)w * ratio);\n        split = max(1, min(w - 1, split));\n        splitLen = split;\n        return true;\n    };\n\n    if (preferHoriz) {\n        ok = try_split_horizontal(sumLeft);\n        if (ok) node.splitHorizontal = true;\n    }\n    if (!ok) {\n        ok = try_split_vertical(sumLeft);\n        if (ok) node.splitHorizontal = false;\n    }\n    if (!ok) {\n        if (h >= 2) {\n            node.splitHorizontal = true;\n            splitLen = max(1, min(h - 1, h / 2));\n        } else {\n            node.splitHorizontal = false;\n            splitLen = max(1, min(w - 1, w / 2));\n        }\n    }\n\n    if (node.splitHorizontal) {\n        node.left = build_tree(leftIds, x0, y0, x0 + splitLen, y1);\n        node.right = build_tree(rightIds, x0 + splitLen, y0, x1, y1);\n    } else {\n        node.left = build_tree(leftIds, x0, y0, x1, y0 + splitLen);\n        node.right = build_tree(rightIds, x0, y0 + splitLen, x1, y1);\n    }\n    return nodeId;\n}\n\nlong double build_weights(int node, const vector<long double>& weights) {\n    TreeNode &nd = nodes[node];\n    if (nd.isLeaf) {\n        long double val = max<long double>(weights[nd.leaf], 1e-9L);\n        subtreeWeight[node] = val;\n        return val;\n    }\n    long double left = build_weights(nd.left, weights);\n    long double right = build_weights(nd.right, weights);\n    subtreeWeight[node] = left + right;\n    return subtreeWeight[node];\n}\n\nint calc_split_len(int len, long double leftWeight, long double totalWeight) {\n    if (len <= 1) return 1;\n    if (totalWeight <= 0) totalWeight = 1.0L;\n    long double ratio = leftWeight / totalWeight;\n    ratio = max((long double)0.0L, min((long double)1.0L, ratio));\n    int split = (int)llround((long double)len * ratio);\n    split = max(1, min(len - 1, split));\n    return split;\n}\n\nvoid assign_geometry(int node, int x0, int y0, int x1, int y1) {\n    TreeNode &nd = nodes[node];\n    if (nd.isLeaf) {\n        currentRects[nd.leaf].i0 = x0;\n        currentRects[nd.leaf].j0 = y0;\n        currentRects[nd.leaf].i1 = x1;\n        currentRects[nd.leaf].j1 = y1;\n        long long area = 1LL * (x1 - x0) * (y1 - y0);\n        if (area <= 0) area = 1;\n        leafActualArea[nd.leaf] = area;\n        return;\n    }\n    int h = x1 - x0;\n    int w = y1 - y0;\n    bool canHoriz = (h >= 2);\n    bool canVert = (w >= 2);\n    bool useHoriz = nd.splitHorizontal;\n    if (useHoriz && !canHoriz) useHoriz = false;\n    if (!useHoriz && !canVert) useHoriz = true;\n\n    long double leftW = subtreeWeight[nd.left];\n    long double rightW = subtreeWeight[nd.right];\n    long double total = leftW + rightW;\n    if (total <= 0) { leftW = rightW = 1.0L; total = 2.0L; }\n\n    if (useHoriz) {\n        int split = calc_split_len(h, leftW, total);\n        assign_geometry(nd.left, x0, y0, x0 + split, y1);\n        assign_geometry(nd.right, x0 + split, y0, x1, y1);\n    } else {\n        int split = calc_split_len(w, leftW, total);\n        assign_geometry(nd.left, x0, y0, x1, y0 + split);\n        assign_geometry(nd.right, x0, y0 + split, x1, y1);\n    }\n}\n\nvoid apply_layout(const vector<long long>& leafWeights, vector<long long>& actualAreas) {\n    vector<long double> weightLD(N);\n    for (int i = 0; i < N; ++i)\n        weightLD[i] = max<long double>((long double)leafWeights[i], 1.0L);\n    subtreeWeight.assign(nodes.size(), 0.0L);\n    build_weights(rootNode, weightLD);\n    assign_geometry(rootNode, 0, 0, W, W);\n    actualAreas = leafActualArea;\n}\n\nvoid adjust_working(const vector<long long>& base,\n                    const vector<long long>& target,\n                    vector<long long>& working) {\n    working = base;\n    vector<long long> curTarget = target;\n    int n = base.size();\n    long long need = 0;\n    vector<pair<long long,int>> donors;\n    donors.reserve(n);\n    for (int i = 0; i < n; ++i) {\n        if (working[i] < curTarget[i]) {\n            need += curTarget[i] - working[i];\n            working[i] = curTarget[i];\n        }\n    }\n    for (int i = 0; i < n; ++i) {\n        long long slack = working[i] - curTarget[i];\n        if (slack > 0) donors.emplace_back(slack, i);\n    }\n    sort(donors.begin(), donors.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 : donors) {\n        if (need == 0) break;\n        int idx = p.second;\n        long long avail = working[idx] - curTarget[idx];\n        if (avail <= 0) continue;\n        long long take = min(avail, need);\n        working[idx] -= take;\n        need -= take;\n    }\n    if (need > 0) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b){\n            if (working[a] != working[b]) return working[a] > working[b];\n            return a < b;\n        });\n        for (int idx : ord) {\n            if (need == 0) break;\n            long long can = working[idx] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, need);\n            working[idx] -= take;\n            need -= take;\n        }\n    }\n    if (need > 0) {\n        for (int idx : orderIdx) {\n            if (need == 0) break;\n            long long can = working[idx] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, need);\n            working[idx] -= take;\n            need -= take;\n        }\n    }\n    if (need > 0) {\n        for (int i = 0; i < n && need > 0; ++i) {\n            long long can = working[i] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, need);\n            working[i] -= take;\n            need -= take;\n        }\n    }\n    for (int i = 0; i < n; ++i) working[i] = max(1LL, working[i]);\n\n    long long sum = accumulate(working.begin(), working.end(), 0LL);\n    if (sum > TOT) {\n        long long excess = sum - TOT;\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b){\n            if (working[a] != working[b]) return working[a] > working[b];\n            return a < b;\n        });\n        for (int idx : ord) {\n            if (excess == 0) break;\n            long long can = working[idx] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, excess);\n            working[idx] -= take;\n            excess -= take;\n        }\n        if (excess > 0) {\n            for (int i = 0; i < n && excess > 0; ++i) {\n                long long can = working[i] - 1;\n                if (can <= 0) continue;\n                long long take = min(can, excess);\n                working[i] -= take;\n                excess -= take;\n            }\n        }\n    } else if (sum < TOT) {\n        long long deficit = TOT - sum;\n        while (deficit > 0) {\n            for (int idx : orderIdx) {\n                if (deficit == 0) break;\n                long long add = min(deficit, 1LL);\n                working[idx] += add;\n                deficit -= add;\n            }\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    if (!(cin >> W >> D >> N)) return 0;\n    TOT = 1LL * W * W;\n    demands.assign(D, vector<int>(N));\n    for (int d = 0; d < D; ++d)\n        for (int k = 0; k < N; ++k)\n            cin >> demands[d][k];\n\n    baseArea = compute_base_area();\n\n    orderIdx.resize(N);\n    iota(orderIdx.begin(), orderIdx.end(), 0);\n    sort(orderIdx.begin(), orderIdx.end(), [&](int a, int b) {\n        if (baseArea[a] != baseArea[b]) return baseArea[a] > baseArea[b];\n        return a < b;\n    });\n\n    nodes.reserve(2 * N + 5);\n    rootNode = build_tree(orderIdx, 0, 0, W, W);\n\n    currentRects.assign(N, RectInfo());\n    leafActualArea.assign(N, 1);\n\n    apply_layout(baseArea, leafActualArea);\n    vector<long long> lastAreas = leafActualArea;\n\n    vector<long long> desiredLeaf(N, 1);\n    vector<long long> effectiveTarget(N, 1);\n    vector<long long> baseVec(N), working(N), actual(N);\n    vector<pair<int,int>> req(N);\n    vector<int> reqToLeaf(N);\n    const int MAX_ITER = 6;\n\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) req[k] = {demands[d][k], k};\n        sort(req.begin(), req.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 pos = 0; pos < N; ++pos) {\n            int leaf = orderIdx[pos];\n            desiredLeaf[leaf] = req[pos].first;\n            reqToLeaf[req[pos].second] = leaf;\n        }\n\n        effectiveTarget = desiredLeaf;\n        baseVec = lastAreas;\n        for (int iter = 0; iter < MAX_ITER; ++iter) {\n            adjust_working(baseVec, effectiveTarget, working);\n            apply_layout(working, actual);\n            bool ok = true;\n            for (int i = 0; i < N; ++i) {\n                long long deficit = desiredLeaf[i] - actual[i];\n                if (deficit > 0) {\n                    effectiveTarget[i] += deficit + 1;\n                    ok = false;\n                }\n            }\n            baseVec = actual;\n            if (ok) break;\n        }\n        lastAreas = actual;\n\n        for (int k = 0; k < N; ++k) {\n            const RectInfo &r = currentRects[reqToLeaf[k]];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Operation {\n    int stamp;\n    int p, q;\n    array<int, 9> cells;\n    array<int, 9> adds;\n};\n\nstruct Solver {\n    static constexpr int MOD = 998244353;\n    int N, M, K;\n    vector<int> board_mod;\n    vector<Operation> ops;\n    vector<char> used;\n    vector<int> used_ops;\n    vector<int> pos_in_used;\n    long long current_score = 0;\n    long long best_score = 0;\n    vector<int> best_ops;\n\n    mt19937 rng;\n    uniform_real_distribution<double> dist01;\n\n    Solver() : rng(random_device{}()), dist01(0.0, 1.0) {}\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        auto global_start = chrono::steady_clock::now();\n\n        cin >> N >> M >> K;\n        vector<int> initial(N * N);\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                cin >> initial[i * N + j];\n            }\n        }\n        vector<array<array<int, 3>, 3>> stamps(M);\n        for (int m = 0; m < M; ++m) {\n            for (int i = 0; i < 3; ++i) {\n                for (int j = 0; j < 3; ++j) {\n                    cin >> stamps[m][i][j];\n                }\n            }\n        }\n\n        build_operations(stamps);\n\n        board_mod = initial;\n        used.assign(ops.size(), 0);\n        pos_in_used.assign(ops.size(), -1);\n        used_ops.clear();\n        used_ops.reserve(K);\n\n        current_score = 0;\n        for (int v : board_mod) current_score += v;\n        best_score = current_score;\n        best_ops = used_ops;\n\n        greedy_init();\n\n        constexpr double TOTAL_TIME_LIMIT = 1.90; // seconds\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n        double remaining = TOTAL_TIME_LIMIT - elapsed;\n        if (remaining > 0.05 && !ops.empty()) {\n            simulated_annealing(max(0.01, remaining - 0.01));\n        }\n\n        output_best();\n    }\n\n    void build_operations(const vector<array<array<int, 3>, 3>>& stamps) {\n        ops.clear();\n        int placements = (N - 2) * (N - 2);\n        ops.reserve(M * placements);\n        for (int m = 0; m < M; ++m) {\n            for (int p = 0; p <= N - 3; ++p) {\n                for (int q = 0; q <= N - 3; ++q) {\n                    Operation op;\n                    op.stamp = m;\n                    op.p = p;\n                    op.q = q;\n                    int idx = 0;\n                    for (int i = 0; i < 3; ++i) {\n                        for (int j = 0; j < 3; ++j) {\n                            op.cells[idx] = (p + i) * N + (q + j);\n                            op.adds[idx] = stamps[m][i][j];\n                            ++idx;\n                        }\n                    }\n                    ops.push_back(op);\n                }\n            }\n        }\n    }\n\n    long long apply_operation(int op_idx) {\n        const Operation& op = ops[op_idx];\n        long long delta = 0;\n        for (int t = 0; t < 9; ++t) {\n            int add = op.adds[t];\n            if (add == 0) continue;\n            int idx = op.cells[t];\n            int before = board_mod[idx];\n            int after = before + add;\n            if (after >= MOD) after -= MOD;\n            board_mod[idx] = after;\n            delta += after - before;\n        }\n        return delta;\n    }\n\n    long long remove_operation(int op_idx) {\n        const Operation& op = ops[op_idx];\n        long long delta = 0;\n        for (int t = 0; t < 9; ++t) {\n            int add = op.adds[t];\n            if (add == 0) continue;\n            int idx = op.cells[t];\n            int before = board_mod[idx];\n            int after = before - add;\n            if (after < 0) after += MOD;\n            board_mod[idx] = after;\n            delta += after - before;\n        }\n        return delta;\n    }\n\n    void greedy_init() {\n        for (int iter = 0; iter < K; ++iter) {\n            long long best_delta = 0;\n            int best_idx = -1;\n            for (int op_idx = 0; op_idx < (int)ops.size(); ++op_idx) {\n                if (used[op_idx]) continue;\n                const Operation& op = ops[op_idx];\n                long long delta = 0;\n                for (int t = 0; t < 9; ++t) {\n                    int add = op.adds[t];\n                    if (add == 0) continue;\n                    int idx = op.cells[t];\n                    int before = board_mod[idx];\n                    int after = before + add;\n                    if (after >= MOD) after -= MOD;\n                    delta += after - before;\n                }\n                if (delta > best_delta) {\n                    best_delta = delta;\n                    best_idx = op_idx;\n                }\n            }\n            if (best_idx == -1 || best_delta <= 0) break;\n            long long delta = apply_operation(best_idx);\n            current_score += delta;\n            used[best_idx] = 1;\n            pos_in_used[best_idx] = used_ops.size();\n            used_ops.push_back(best_idx);\n            if (current_score > best_score) {\n                best_score = current_score;\n                best_ops = used_ops;\n            }\n        }\n    }\n\n    int pick_random_unused() {\n        if ((int)used_ops.size() >= (int)ops.size()) return -1;\n        for (int attempt = 0; attempt < 32; ++attempt) {\n            int idx = rng() % ops.size();\n            if (!used[idx]) return idx;\n        }\n        for (int idx = 0; idx < (int)ops.size(); ++idx) {\n            if (!used[idx]) return idx;\n        }\n        return -1;\n    }\n\n    bool accept_move(long long delta, double temp) {\n        if (delta >= 0) return true;\n        if (temp <= 1e-9) return false;\n        double ratio = delta / temp;\n        if (ratio < -50.0) return false;\n        double prob = exp(ratio);\n        return dist01(rng) < prob;\n    }\n\n    void simulated_annealing(double time_limit) {\n        auto start = chrono::steady_clock::now();\n        auto end_time = start + chrono::duration<double>(time_limit);\n        const double START_TEMP = 5e8;\n        const double END_TEMP = 5e2;\n        double temp = START_TEMP;\n        long long iter = 0;\n\n        while (true) {\n            if ((iter & 63) == 0) {\n                auto now = chrono::steady_clock::now();\n                if (now >= end_time) break;\n                double elapsed = chrono::duration<double>(now - start).count();\n                double progress = min(1.0, max(0.0, elapsed / time_limit));\n                temp = START_TEMP + (END_TEMP - START_TEMP) * progress;\n                if (temp < 1.0) temp = 1.0;\n            }\n            ++iter;\n\n            int used_cnt = (int)used_ops.size();\n            int move_type;\n            if (used_cnt == 0) {\n                move_type = 0;\n            } else if (used_cnt >= K) {\n                move_type = (rng() & 1) ? 1 : 2;\n            } else {\n                move_type = rng() % 3;\n            }\n\n            if (move_type == 0) { // add\n                int op_idx = pick_random_unused();\n                if (op_idx == -1) continue;\n                long long delta = apply_operation(op_idx);\n                current_score += delta;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    used[op_idx] = 1;\n                    pos_in_used[op_idx] = used_ops.size();\n                    used_ops.push_back(op_idx);\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev = remove_operation(op_idx);\n                    current_score += rev;\n                }\n            } else if (move_type == 1) { // remove\n                if (used_cnt == 0) continue;\n                int pos = rng() % used_cnt;\n                int op_idx = used_ops[pos];\n                long long delta = remove_operation(op_idx);\n                current_score += delta;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    int last_op = used_ops.back();\n                    used_ops[pos] = last_op;\n                    pos_in_used[last_op] = pos;\n                    used_ops.pop_back();\n                    used[op_idx] = 0;\n                    pos_in_used[op_idx] = -1;\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev = apply_operation(op_idx);\n                    current_score += rev;\n                }\n            } else { // swap\n                if (used_cnt == 0) continue;\n                int op_add = pick_random_unused();\n                if (op_add == -1) continue;\n                int pos = rng() % used_cnt;\n                int op_remove = used_ops[pos];\n\n                long long delta_remove = remove_operation(op_remove);\n                current_score += delta_remove;\n\n                long long delta_add = apply_operation(op_add);\n                current_score += delta_add;\n\n                long long delta = delta_remove + delta_add;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    int last_op = used_ops.back();\n                    used_ops[pos] = last_op;\n                    pos_in_used[last_op] = pos;\n                    used_ops.pop_back();\n                    used[op_remove] = 0;\n                    pos_in_used[op_remove] = -1;\n\n                    used[op_add] = 1;\n                    pos_in_used[op_add] = used_ops.size();\n                    used_ops.push_back(op_add);\n\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev_add = remove_operation(op_add);\n                    current_score += rev_add;\n                    long long rev_remove = apply_operation(op_remove);\n                    current_score += rev_remove;\n                }\n            }\n        }\n    }\n\n    void output_best() const {\n        cout << best_ops.size() << '\\n';\n        for (int idx : best_ops) {\n            const Operation& op = ops[idx];\n            cout << op.stamp << ' ' << op.p << ' ' << op.q << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int LIMIT = 10000;\n\nstruct Params {\n    int rowWeight;\n    int colWeight;\n    int gateColBias;\n    int diffWeight;\n    int backlogWeight;\n    int distWeight;\n    int forcedGapWeight;\n    int sameRowBonus;\n};\n\nstruct ImprovedSolver {\n    int N;\n    const vector<vector<int>>& A;\n    const Params& params;\n\n    string mainOps;\n    int cr = 0, cc = 0;\n    int holding = -1;\n    bool ok = true;\n\n    vector<int> gate_idx;\n    vector<int> next_needed;\n    vector<bool> id_done;\n    vector<pair<int,int>> stored_loc;\n    vector<vector<int>> stored_ids;\n    vector<int> stored_pos;\n    vector<vector<int>> grid;\n    vector<pair<int,int>> storage_cells;\n    vector<vector<pair<int,int>>> rowPrefCells;\n\n    int empty_slots = 0;\n    int stored_total = 0;\n    int total_dispatched = 0;\n\n    ImprovedSolver(int N_, const vector<vector<int>>& A_, const Params& p)\n        : N(N_), A(A_), params(p) {\n        init();\n    }\n\n    void init() {\n        mainOps.clear();\n        cr = 0; cc = 0; holding = -1; ok = true;\n        int total = N * N;\n        gate_idx.assign(N, 0);\n        next_needed.resize(N);\n        for (int r = 0; r < N; ++r) next_needed[r] = r * N;\n        id_done.assign(total, false);\n        stored_loc.assign(total, {-1, -1});\n        stored_ids.assign(N, {});\n        stored_pos.assign(total, -1);\n        grid.assign(N, vector<int>(N, -99));\n        storage_cells.clear();\n        rowPrefCells.assign(N, {});\n        empty_slots = 0;\n        stored_total = 0;\n        total_dispatched = 0;\n\n        for (int r = 0; r < N; ++r) {\n            grid[r][0] = -10; // receiving gate (still active)\n            for (int c = 1; c <= N - 2; ++c) {\n                grid[r][c] = -1;\n                storage_cells.push_back({r, c});\n                rowPrefCells[r].push_back({r, c});\n                ++empty_slots;\n            }\n            grid[r][N - 1] = -11; // dispatch gate\n        }\n    }\n\n    inline int dist(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    bool apply_action(char c) {\n        if (!ok) return false;\n        mainOps.push_back(c);\n        if ((int)mainOps.size() > LIMIT) {\n            ok = false;\n            return false;\n        }\n        return true;\n    }\n\n    bool move_char(char c) {\n        if (!apply_action(c)) return false;\n        if (c == 'U') --cr;\n        else if (c == 'D') ++cr;\n        else if (c == 'L') --cc;\n        else if (c == 'R') ++cc;\n        else { ok = false; return false; }\n        if (cr < 0 || cr >= N || cc < 0 || cc >= N) { ok = false; return false; }\n        return true;\n    }\n\n    bool move_to(int tr, int tc) {\n        while (cr < tr) if (!move_char('D')) return false;\n        while (cr > tr) if (!move_char('U')) return false;\n        while (cc < tc) if (!move_char('R')) return false;\n        while (cc > tc) if (!move_char('L')) return false;\n        return true;\n    }\n\n    bool pick_action(int id) {\n        if (holding != -1) { ok = false; return false; }\n        if (!apply_action('P')) return false;\n        holding = id;\n        return true;\n    }\n\n    bool drop_action() {\n        if (holding == -1) { ok = false; return false; }\n        if (!apply_action('Q')) return false;\n        holding = -1;\n        return true;\n    }\n\n    void advance_next(int row) {\n        int row_end = (row + 1) * N;\n        while (next_needed[row] < row_end && id_done[next_needed[row]]) {\n            ++next_needed[row];\n        }\n    }\n\n    void add_storage_cell(int r, int c) {\n        if (grid[r][c] == -10) {\n            grid[r][c] = -1;\n            storage_cells.push_back({r, c});\n            rowPrefCells[r].push_back({r, c});\n            ++empty_slots;\n        }\n    }\n\n    pair<int,int> choose_storage_cell(int target_row) {\n        for (auto [r, c] : rowPrefCells[target_row]) {\n            if (grid[r][c] == -1) return {r, c};\n        }\n        int best_cost = INT_MAX;\n        pair<int,int> best = {-1, -1};\n        for (auto [r, c] : storage_cells) {\n            if (grid[r][c] == -1) {\n                int cost = params.rowWeight * abs(r - target_row)\n                         + params.colWeight * (N - 1 - c);\n                if (c == 0) cost += params.gateColBias;\n                if (cost < best_cost) {\n                    best_cost = cost;\n                    best = {r, c};\n                }\n            }\n        }\n        return best;\n    }\n\n    bool store_current(int id) {\n        int row = id / N;\n        auto cell = choose_storage_cell(row);\n        if (cell.first == -1) { ok = false; return false; }\n        if (!move_to(cell.first, cell.second)) return false;\n        if (grid[cell.first][cell.second] != -1) { ok = false; return false; }\n        if (!drop_action()) return false;\n        grid[cell.first][cell.second] = id;\n        stored_loc[id] = cell;\n        stored_pos[id] = (int)stored_ids[row].size();\n        stored_ids[row].push_back(id);\n        --empty_slots;\n        ++stored_total;\n        return true;\n    }\n\n    bool pickup_from_storage(int id) {\n        auto [r, c] = stored_loc[id];\n        if (r == -1) { ok = false; return false; }\n        if (!move_to(r, c)) return false;\n        if (grid[r][c] != id) { ok = false; return false; }\n        if (!pick_action(id)) return false;\n        grid[r][c] = -1;\n        stored_loc[id] = {-1, -1};\n        ++empty_slots;\n        --stored_total;\n        int row = id / N;\n        int idx = stored_pos[id];\n        if (idx < 0) { ok = false; return false; }\n        int last = stored_ids[row].back();\n        stored_ids[row][idx] = last;\n        stored_pos[last] = idx;\n        stored_ids[row].pop_back();\n        stored_pos[id] = -1;\n        return true;\n    }\n\n    bool deliver_after_pick(int id) {\n        int row = id / N;\n        if (!move_to(row, N - 1)) return false;\n        if (!drop_action()) return false;\n        id_done[id] = true;\n        ++total_dispatched;\n        advance_next(row);\n        return true;\n    }\n\n    bool deliver_from_storage(int id) {\n        if (!pickup_from_storage(id)) return false;\n        return deliver_after_pick(id);\n    }\n\n    long long row_bonus(int row) const {\n        int dr = abs(row - cr);\n        if (dr == 0) return params.sameRowBonus;\n        if (dr == 1) return params.sameRowBonus / 2;\n        return 0;\n    }\n\n    bool fetch_gate(int gate) {\n        if (gate_idx[gate] >= N) { ok = false; return false; }\n        int id = A[gate][gate_idx[gate]];\n        int row = id / N;\n        if (!move_to(gate, 0)) return false;\n        if (!pick_action(id)) return false;\n        ++gate_idx[gate];\n        if (gate_idx[gate] == N) add_storage_cell(gate, 0);\n\n        int row_end = (row + 1) * N;\n        bool immediate = (next_needed[row] < row_end && id == next_needed[row]);\n        if (immediate) return deliver_after_pick(id);\n        if (empty_slots <= 0) { ok = false; return false; }\n        return store_current(id);\n    }\n\n    bool deliver_ready_from_storage() {\n        int best_id = -1;\n        int best_cost = INT_MAX;\n        long long best_bonus = -1;\n        for (int r = 0; r < N; ++r) {\n            int need = next_needed[r];\n            int row_end = (r + 1) * N;\n            if (need >= row_end) continue;\n            if (stored_pos[need] == -1) continue;\n            auto [sr, sc] = stored_loc[need];\n            int cost = dist(cr, cc, sr, sc) + dist(sr, sc, r, N - 1);\n            long long bonus = row_bonus(r);\n            if (cost < best_cost ||\n                (cost == best_cost && (bonus > best_bonus ||\n                (bonus == best_bonus && need < best_id)))) {\n                best_cost = cost;\n                best_bonus = bonus;\n                best_id = need;\n            }\n        }\n        if (best_id != -1) {\n            return deliver_from_storage(best_id);\n        }\n        return false;\n    }\n\n    bool fetch_gate_immediate() {\n        int best_gate = -1;\n        int best_id = -1;\n        int best_cost = INT_MAX;\n        long long best_bonus = -1;\n        for (int g = 0; g < N; ++g) {\n            if (gate_idx[g] >= N) continue;\n            int id = A[g][gate_idx[g]];\n            int row = id / N;\n            int row_end = (row + 1) * N;\n            if (!(next_needed[row] < row_end && id == next_needed[row])) continue;\n            int cost = dist(cr, cc, g, 0) + dist(g, 0, row, N - 1);\n            long long bonus = row_bonus(row);\n            if (cost < best_cost ||\n                (cost == best_cost && (bonus > best_bonus ||\n                 (bonus == best_bonus && id < best_id)))) {\n                best_cost = cost;\n                best_bonus = bonus;\n                best_gate = g;\n                best_id = id;\n            }\n        }\n        if (best_gate != -1) {\n            return fetch_gate(best_gate);\n        }\n        return false;\n    }\n\n    int select_forced_id_cost() {\n        int best_id = -1;\n        long long best_score = (1LL << 60);\n        for (int r = 0; r < N; ++r) {\n            if (stored_ids[r].empty()) continue;\n            int need = next_needed[r];\n            for (int id : stored_ids[r]) {\n                auto [sr, sc] = stored_loc[id];\n                if (sr == -1) continue;\n                int gap = max(id - need, 0);\n                int cost = dist(cr, cc, sr, sc) + dist(sr, sc, r, N - 1);\n                long long score = 1LL * params.forcedGapWeight * gap + cost - row_bonus(r);\n                if (score < best_score || (score == best_score && id < best_id)) {\n                    best_score = score;\n                    best_id = id;\n                }\n            }\n        }\n        return best_id;\n    }\n\n    bool fetch_general_gate() {\n        long long best_score = (1LL << 60);\n        int best_gate = -1;\n        int best_diff = INT_MAX;\n        int best_distgate = INT_MAX;\n        int best_id = INT_MAX;\n        for (int g = 0; g < N; ++g) {\n            if (gate_idx[g] >= N) continue;\n            int id = A[g][gate_idx[g]];\n            int row = id / N;\n            int need = next_needed[row];\n            int row_end = (row + 1) * N;\n            int diff = (need < row_end) ? max(id - need, 0) : max(id - row_end, 0) + 5;\n            int backlog = (int)stored_ids[row].size();\n            int distGate = dist(cr, cc, g, 0);\n            long long score = 1LL * params.diffWeight * diff\n                            + 1LL * params.backlogWeight * backlog\n                            + 1LL * params.distWeight * distGate\n                            - row_bonus(row);\n            if (score < best_score ||\n                (score == best_score &&\n                 (diff < best_diff ||\n                  (diff == best_diff &&\n                   (distGate < best_distgate ||\n                    (distGate == best_distgate && id < best_id))))))\n            {\n                best_score = score;\n                best_gate = g;\n                best_diff = diff;\n                best_distgate = distGate;\n                best_id = id;\n            }\n        }\n        if (best_gate != -1) {\n            return fetch_gate(best_gate);\n        }\n        return false;\n    }\n\n    bool step() {\n        if (!ok) return false;\n        if (deliver_ready_from_storage()) return true;\n        if (fetch_gate_immediate()) return true;\n        if (empty_slots == 0) {\n            int forced_id = select_forced_id_cost();\n            if (forced_id == -1) { ok = false; return false; }\n            return deliver_from_storage(forced_id);\n        }\n        if (fetch_general_gate()) return true;\n        if (stored_total > 0) {\n            int forced_id = select_forced_id_cost();\n            if (forced_id == -1) { ok = false; return false; }\n            return deliver_from_storage(forced_id);\n        }\n        ok = false;\n        return false;\n    }\n\n    vector<string> run() {\n        int guard = 0;\n        while (ok && total_dispatched < N * N && guard < 200000) {\n            if (!step()) break;\n            ++guard;\n        }\n        if (!ok || total_dispatched != N * N || holding != -1) return {};\n        string big = mainOps;\n        if (big.empty()) big.push_back('.');\n        int L = big.size();\n        vector<string> ops(N);\n        ops[0] = big;\n        for (int i = 1; i < N; ++i) {\n            string s(L, '.');\n            if (!s.empty()) s[0] = 'B';\n            ops[i] = move(s);\n        }\n        return ops;\n    }\n};\n\nvector<string> solve_baseline(int N, const vector<vector<int>>& A) {\n    string mainOps;\n    int cr = 0, cc = 0;\n    auto move_char = [&](char c) {\n        mainOps.push_back(c);\n        if (c == 'U') --cr;\n        else if (c == 'D') ++cr;\n        else if (c == 'L') --cc;\n        else if (c == 'R') ++cc;\n    };\n    auto move_to = [&](int tr, int tc) {\n        while (cr < tr) move_char('D');\n        while (cr > tr) move_char('U');\n        while (cc < tc) move_char('R');\n        while (cc > tc) move_char('L');\n    };\n    for (int src = 0; src < N; ++src) {\n        for (int idx = 0; idx < N; ++idx) {\n            move_to(src, 0);\n            mainOps.push_back('P');\n            int id = A[src][idx];\n            int row = id / N;\n            move_to(row, N - 1);\n            mainOps.push_back('Q');\n        }\n    }\n    if (mainOps.empty()) mainOps.push_back('.');\n    vector<string> ops(N);\n    int L = mainOps.size();\n    ops[0] = mainOps;\n    for (int i = 1; i < N; ++i) {\n        string s(L, '.');\n        if (!s.empty()) s[0] = 'B';\n        ops[i] = move(s);\n    }\n    return ops;\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>> A(N, vector<int>(N));\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            cin >> A[i][j];\n\n    vector<Params> baseParams = {\n        {40, 6, 80, 70, 10, 2, 90, 18},\n        {50, 7, 70, 80, 12, 1, 100, 20},\n        {35, 5, 90, 60, 8, 3, 80, 16},\n        {45, 8, 60, 55, 6, 4, 70, 14},\n        {30, 9, 85, 75, 9, 2, 110, 22},\n        {60, 5, 95, 65, 11, 1, 120, 25},\n        {38, 7, 75, 68, 9, 3, 95, 17},\n        {55, 6, 85, 72, 10, 2, 105, 21}\n    };\n\n    uint64_t seed = 0;\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            seed = seed * 1000003ULL + (uint64_t)(A[i][j] + 1);\n    mt19937_64 rng(seed);\n\n    auto randInt = [&](int l, int r) {\n        return l + (int)(rng() % (uint64_t)(r - l + 1));\n    };\n\n    const int extraRuns = 12;\n    for (int t = 0; t < extraRuns; ++t) {\n        Params p;\n        p.rowWeight       = randInt(30, 65);\n        p.colWeight       = randInt(4, 10);\n        p.gateColBias     = randInt(60, 110);\n        p.diffWeight      = randInt(45, 90);\n        p.backlogWeight   = randInt(5, 15);\n        p.distWeight      = randInt(1, 4);\n        p.forcedGapWeight = randInt(70, 130);\n        p.sameRowBonus    = randInt(10, 30);\n        baseParams.push_back(p);\n    }\n\n    vector<string> best_ops;\n    size_t best_len = numeric_limits<size_t>::max();\n\n    for (const auto& par : baseParams) {\n        ImprovedSolver solver(N, A, par);\n        auto ops = solver.run();\n        if (ops.empty()) continue;\n        size_t len = ops[0].size();\n        if (len > (size_t)LIMIT) continue;\n        if (len < best_len) {\n            best_len = len;\n            best_ops = ops;\n        }\n    }\n\n    if (best_ops.empty()) {\n        best_ops = solve_baseline(N, A);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << best_ops[i] << '\\n';\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Cell {\n    int r, c, val;\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    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j) cin >> h[i][j];\n\n    vector<string> ops;\n    ops.reserve(120000);\n\n    int cur_r = 0, cur_c = 0;\n    long long load = 0;\n\n    auto moveTo = [&](int tr, int tc) {\n        while (cur_r < tr) { ops.emplace_back(\"D\"); ++cur_r; }\n        while (cur_r > tr) { ops.emplace_back(\"U\"); --cur_r; }\n        while (cur_c < tc) { ops.emplace_back(\"R\"); ++cur_c; }\n        while (cur_c > tc) { ops.emplace_back(\"L\"); --cur_c; }\n    };\n\n    vector<Cell> positives, negatives;\n    positives.reserve(N * N);\n    negatives.reserve(N * N);\n\n    auto collectCells = [&]() {\n        positives.clear();\n        negatives.clear();\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int val = h[i][j];\n                if (val > 0) positives.push_back({i, j, val});\n                else if (val < 0) negatives.push_back({i, j, val});\n            }\n        }\n    };\n\n    auto selectPositive = [&]() -> pair<int,int> {\n        long long bestScore = (1LL << 60);\n        int bestVal = -1;\n        pair<int,int> best{-1,-1};\n        for (const auto& p : positives) {\n            long long distTruck = abs(cur_r - p.r) + abs(cur_c - p.c);\n            long long nearestNeg = 0;\n            if (!negatives.empty()) {\n                int dmin = INT_MAX;\n                for (const auto& n : negatives) {\n                    int d = abs(p.r - n.r) + abs(p.c - n.c);\n                    if (d < dmin) dmin = d;\n                }\n                nearestNeg = dmin;\n            }\n            long long score = distTruck * 1000 + nearestNeg * 350 - 20LL * p.val;\n            if (score < bestScore || (score == bestScore && p.val > bestVal)) {\n                bestScore = score;\n                bestVal = p.val;\n                best = {p.r, p.c};\n            }\n        }\n        return best;\n    };\n\n    auto selectNegative = [&]() -> pair<int,int> {\n        long long bestScore = (1LL << 60);\n        long long bestDeliver = -1;\n        pair<int,int> best{-1,-1};\n        for (const auto& n : negatives) {\n            long long dist = abs(cur_r - n.r) + abs(cur_c - n.c);\n            long long need = -n.val;\n            long long deliver = min<long long>(load, need);\n            if (deliver <= 0) continue;\n            long long score = dist * 1000 - deliver * 25;\n            if (score < bestScore || (score == bestScore && deliver > bestDeliver)) {\n                bestScore = score;\n                bestDeliver = deliver;\n                best = {n.r, n.c};\n            }\n        }\n        return best;\n    };\n\n    const int MAX_OPS = 100000;\n    const int CLEANUP_RESERVE = 36000; // leave room for final gather/distribute\n    const int MAX_ITER = 200000;\n    int iter = 0;\n\n    while ((int)ops.size() < MAX_OPS - CLEANUP_RESERVE && iter < MAX_ITER) {\n        collectCells();\n        if (positives.empty() && negatives.empty() && load == 0) break;\n\n        if (load == 0) {\n            if (positives.empty()) break;\n            auto tgt = selectPositive();\n            if (tgt.first == -1) break;\n            moveTo(tgt.first, tgt.second);\n            int amount = h[tgt.first][tgt.second];\n            if (amount <= 0) { ++iter; continue; }\n            ops.emplace_back(\"+\" + to_string(amount));\n            load += amount;\n            h[tgt.first][tgt.second] = 0;\n        } else {\n            if (negatives.empty()) break;\n            auto tgt = selectNegative();\n            if (tgt.first == -1) break;\n            moveTo(tgt.first, tgt.second);\n            int need = -h[tgt.first][tgt.second];\n            if (need <= 0) { ++iter; continue; }\n            int amount = (int)min<long long>(load, need);\n            if (amount <= 0) { ++iter; continue; }\n            ops.emplace_back(\"-\" + to_string(amount));\n            load -= amount;\n            h[tgt.first][tgt.second] += amount;\n        }\n        ++iter;\n    }\n\n    if (load > 0) {\n        moveTo(0, 0);\n        ops.emplace_back(\"-\" + to_string(load));\n        h[0][0] += (int)load;\n        load = 0;\n    }\n\n    auto gatherPositivesToOrigin = [&]() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (i == 0 && j == 0) continue;\n                int val = h[i][j];\n                if (val <= 0) continue;\n                moveTo(i, j);\n                ops.emplace_back(\"+\" + to_string(val));\n                load += val;\n                h[i][j] = 0;\n                moveTo(0, 0);\n                ops.emplace_back(\"-\" + to_string(val));\n                load -= val;\n                h[0][0] += val;\n            }\n        }\n    };\n\n    auto distributeFromOrigin = [&]() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (h[i][j] >= 0) continue;\n                int need = -h[i][j];\n                if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n                ops.emplace_back(\"+\" + to_string(need));\n                load += need;\n                h[0][0] -= need;\n                moveTo(i, j);\n                ops.emplace_back(\"-\" + to_string(need));\n                load -= need;\n                h[i][j] = 0;\n            }\n        }\n    };\n\n    gatherPositivesToOrigin();\n    distributeFromOrigin();\n\n    if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n\n    if (h[0][0] > 0) {\n        int val = h[0][0];\n        ops.emplace_back(\"+\" + to_string(val));\n        load += val;\n        h[0][0] = 0;\n        ops.emplace_back(\"-\" + to_string(val));\n        load -= val;\n    } else if (h[0][0] < 0) {\n        int val = -h[0][0];\n        ops.emplace_back(\"-\" + to_string(val));\n        load -= val;\n        h[0][0] = 0;\n        ops.emplace_back(\"+\" + to_string(val));\n        load += val;\n    }\n\n    if (load > 0) {\n        if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n        ops.emplace_back(\"-\" + to_string(load));\n        h[0][0] += (int)load;\n        load = 0;\n    }\n\n    for (const string& op : ops) cout << op << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAX_M = 15;\nconstexpr int MAX_TOTAL = 2000;\nconstexpr int MAX_TARGETS = 5;\n\nstruct Seed {\n    array<int, MAX_M> attr;\n    int value;\n    Seed() {\n        attr.fill(0);\n        value = 0;\n    }\n};\n\ndouble computePairScore(const Seed& A, const Seed& B,\n                        const vector<int>& targets,\n                        const vector<double>& weights,\n                        const vector<double>& probWeights,\n                        int M,\n                        int bestValue,\n                        double potentialWeight,\n                        const vector<int>& attrTargets,\n                        const vector<double>& attrWeights,\n                        double attrComponentScale) {\n    static array<double, MAX_TOTAL> dp{};\n    static array<double, MAX_TOTAL> ndp{};\n\n    double attrScore = 0.0;\n    if (!attrWeights.empty()) {\n        for (int l = 0; l < M; ++l) {\n            double w = attrWeights[l];\n            if (w <= 1e-9) continue;\n            int target = attrTargets[l];\n            bool aGood = A.attr[l] >= target;\n            bool bGood = B.attr[l] >= target;\n            if (!aGood && !bGood) continue;\n            attrScore += (aGood && bGood) ? w : (w * 0.5);\n        }\n    }\n    double total = attrScore * attrComponentScale;\n\n    int maxSum = 0;\n    for (int l = 0; l < M; ++l) {\n        maxSum += max(A.attr[l], B.attr[l]);\n    }\n    if (maxSum + 1 > MAX_TOTAL) maxSum = MAX_TOTAL - 1;\n\n    fill(dp.begin(), dp.begin() + (maxSum + 1), 0.0);\n    dp[0] = 1.0;\n    int currentMax = 0;\n    for (int l = 0; l < M; ++l) {\n        int aVal = A.attr[l];\n        int bVal = B.attr[l];\n        int add = max(aVal, bVal);\n        int nextMax = currentMax + add;\n        if (nextMax > MAX_TOTAL - 1) nextMax = MAX_TOTAL - 1;\n        fill(ndp.begin(), ndp.begin() + (nextMax + 1), 0.0);\n        for (int s = 0; s <= currentMax; ++s) {\n            double prob = dp[s];\n            if (prob == 0.0) continue;\n            if (s + aVal <= nextMax) ndp[s + aVal] += prob * 0.5;\n            if (s + bVal <= nextMax) ndp[s + bVal] += prob * 0.5;\n        }\n        currentMax = nextMax;\n        dp.swap(ndp);\n    }\n\n    int K = targets.size();\n    if (K == 0) {\n        double potential = currentMax - bestValue;\n        if (potential > 0) total += potentialWeight * potential;\n        return total;\n    }\n\n    array<double, MAX_TARGETS> tailProb{};\n    array<double, MAX_TARGETS> tailSum{};\n    int minTarget = targets.front();\n    if (minTarget < 0) minTarget = 0;\n    if (currentMax > minTarget) {\n        for (int s = currentMax; s > minTarget; --s) {\n            double prob = dp[s];\n            if (prob == 0.0) continue;\n            for (int idx = 0; idx < K; ++idx) {\n                if (s > targets[idx]) {\n                    tailProb[idx] += prob;\n                    tailSum[idx] += prob * s;\n                } else {\n                    break;\n                }\n            }\n        }\n    }\n\n    for (int idx = 0; idx < K; ++idx) {\n        double sc = tailSum[idx] - static_cast<double>(targets[idx]) * tailProb[idx];\n        if (sc < 0) sc = 0;\n        total += weights[idx] * sc + probWeights[idx] * tailProb[idx];\n    }\n\n    double potential = currentMax - bestValue;\n    if (potential > 0) total += potentialWeight * potential;\n    return total;\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    int seedCount = 2 * N * (N - 1);\n    int selectCount = N * N;\n    vector<Seed> seeds(seedCount);\n    for (int i = 0; i < seedCount; ++i) {\n        int sum = 0;\n        for (int j = 0; j < M; ++j) {\n            int val;\n            cin >> val;\n            seeds[i].attr[j] = val;\n            sum += val;\n        }\n        for (int j = M; j < MAX_M; ++j) seeds[i].attr[j] = 0;\n        seeds[i].value = sum;\n    }\n\n    const int cellCount = selectCount;\n    vector<vector<int>> neighbors(cellCount);\n    vector<pair<int, int>> edges;\n    edges.reserve(2 * N * (N - 1));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int pos = i * N + j;\n            if (j + 1 < N) {\n                int q = pos + 1;\n                neighbors[pos].push_back(q);\n                neighbors[q].push_back(pos);\n                edges.emplace_back(pos, q);\n            }\n            if (i + 1 < N) {\n                int q = pos + N;\n                neighbors[pos].push_back(q);\n                neighbors[q].push_back(pos);\n                edges.emplace_back(pos, q);\n            }\n        }\n    }\n    vector<int> cellDegree(cellCount, 0);\n    for (int pos = 0; pos < cellCount; ++pos) {\n        sort(neighbors[pos].begin(), neighbors[pos].end());\n        neighbors[pos].erase(unique(neighbors[pos].begin(), neighbors[pos].end()), neighbors[pos].end());\n        cellDegree[pos] = (int)neighbors[pos].size();\n    }\n\n    vector<int> positionOrder(cellCount);\n    iota(positionOrder.begin(), positionOrder.end(), 0);\n    double center = (N - 1) / 2.0;\n    vector<double> cellDist(cellCount, 0.0);\n    for (int pos = 0; pos < cellCount; ++pos) {\n        int r = pos / N;\n        int c = pos % N;\n        cellDist[pos] = fabs(r - center) + fabs(c - center);\n    }\n    sort(positionOrder.begin(), positionOrder.end(), [&](int a, int b) {\n        if (fabs(cellDist[a] - cellDist[b]) > 1e-9) return cellDist[a] < cellDist[b];\n        if (cellDegree[a] != cellDegree[b]) return cellDegree[a] > cellDegree[b];\n        return a < b;\n    });\n    vector<int> positionOrderReverse = positionOrder;\n    reverse(positionOrderReverse.begin(), positionOrderReverse.end());\n    vector<int> positionOrderRow(cellCount);\n    iota(positionOrderRow.begin(), positionOrderRow.end(), 0);\n\n    mt19937 rng(712367);\n    uniform_real_distribution<double> realDist(0.0, 1.0);\n    uniform_int_distribution<int> posDist(0, cellCount - 1);\n\n    vector<int> orderIndices(seedCount);\n\n    for (int turn = 0; turn < T; ++turn) {\n        vector<int> bestAttrValue(M, -1);\n        vector<int> secondAttrValue(M, -1);\n        vector<int> bestAttrIndex(M, -1);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            for (int l = 0; l < M; ++l) {\n                int val = seeds[idx].attr[l];\n                if (val > bestAttrValue[l]) {\n                    secondAttrValue[l] = bestAttrValue[l];\n                    bestAttrValue[l] = val;\n                    bestAttrIndex[l] = idx;\n                } else if (val == bestAttrValue[l]) {\n                    if (bestAttrIndex[l] == -1 || seeds[idx].value > seeds[bestAttrIndex[l]].value) {\n                        secondAttrValue[l] = bestAttrValue[l];\n                        bestAttrValue[l] = val;\n                        bestAttrIndex[l] = idx;\n                    } else if (val > secondAttrValue[l]) {\n                        secondAttrValue[l] = val;\n                    }\n                } else if (val > secondAttrValue[l]) {\n                    secondAttrValue[l] = val;\n                }\n            }\n        }\n\n        vector<int> seedChampionCount(seedCount, 0);\n        vector<int> attrTopCount(M, 0);\n        for (int l = 0; l < M; ++l) {\n            if (bestAttrValue[l] < 0) continue;\n            for (int idx = 0; idx < seedCount; ++idx) {\n                if (seeds[idx].attr[l] == bestAttrValue[l]) {\n                    ++attrTopCount[l];\n                    ++seedChampionCount[idx];\n                }\n            }\n        }\n\n        vector<vector<int>> attrOrder(M, vector<int>(seedCount));\n        for (int l = 0; l < M; ++l) {\n            auto& arr = attrOrder[l];\n            iota(arr.begin(), arr.end(), 0);\n            int attrIdx = l;\n            sort(arr.begin(), arr.end(), [&](int a, int b) {\n                if (seeds[a].attr[attrIdx] != seeds[b].attr[attrIdx]) return seeds[a].attr[attrIdx] > seeds[b].attr[attrIdx];\n                if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n                return a < b;\n            });\n        }\n\n        int bestValue = 0;\n        for (const auto& s : seeds) bestValue = max(bestValue, s.value);\n\n        int targetMax = 0;\n        for (int l = 0; l < M; ++l) targetMax += max(0, bestAttrValue[l]);\n\n        const int maintainMargin = 8;\n        int maintainTarget = max(0, bestValue - maintainMargin);\n        int gap = max(0, targetMax - bestValue);\n        double phase = (T <= 1) ? 1.0 : (double)turn / (T - 1);\n        double gapFactor = min(1.0, (gap + 5.0) / 60.0);\n        int improveMargin1 = max(3, (int)round(min(gap * 0.35, 40.0)));\n        int improveMargin2 = max(improveMargin1 + 3, (int)round(min(gap * 0.65, 80.0)));\n        int targetImprove1 = min(bestValue + improveMargin1, targetMax);\n        int targetImprove2 = min(bestValue + improveMargin2, targetMax);\n\n        double improvementScale = (0.5 + 0.5 * (1.0 - phase)) * (0.4 + 0.6 * gapFactor);\n        improvementScale = clamp(improvementScale, 0.25, 1.2);\n        double maintainWeight = 0.8 + 0.5 * phase;\n        double maintainProbWeight = 0.05;\n        double improve1Weight = 4.0 * improvementScale;\n        double improve2Weight = 8.0 * improvementScale;\n        double improve1ProbWeight = 0.8 * improvementScale;\n        double improve2ProbWeight = 1.6 * improvementScale;\n        double potentialWeight = 0.02 + 0.04 * improvementScale;\n\n        vector<int> targets;\n        vector<double> weights, probWeights;\n        targets.reserve(MAX_TARGETS);\n        weights.reserve(MAX_TARGETS);\n        probWeights.reserve(MAX_TARGETS);\n        auto addTarget = [&](int target, double w, double pw) {\n            target = clamp(target, 0, targetMax);\n            if (!targets.empty() && target <= targets.back()) return;\n            if ((int)targets.size() >= MAX_TARGETS) return;\n            targets.push_back(target);\n            weights.push_back(w);\n            probWeights.push_back(pw);\n        };\n        addTarget(maintainTarget, maintainWeight, maintainProbWeight);\n        if (targetImprove1 > maintainTarget) addTarget(targetImprove1, improve1Weight, improve1ProbWeight);\n        if (targetImprove2 > targetImprove1) addTarget(targetImprove2, improve2Weight, improve2ProbWeight);\n\n        vector<int> attrTargets(M, 0);\n        vector<double> attrWeights(M, 0.0);\n        for (int l = 0; l < M; ++l) {\n            int bestVal = bestAttrValue[l];\n            if (bestVal <= 0) {\n                attrTargets[l] = 0;\n                attrWeights[l] = 0.0;\n                continue;\n            }\n            if (bestVal <= 8) {\n                attrTargets[l] = bestVal;\n                attrWeights[l] = 0.0;\n                continue;\n            }\n            int secondVal = max(0, secondAttrValue[l]);\n            int gapAttr = max(0, bestVal - secondVal);\n            int approx = (bestVal * 92 + 50) / 100;\n            int margin = max(1, gapAttr / 2);\n            int target = bestVal - margin;\n            target = max(target, approx);\n            target = max(target, bestVal - 6);\n            target = min(target, bestVal);\n            attrTargets[l] = max(0, target);\n            int bestCount = max(1, attrTopCount[l]);\n            double rarity = 1.0;\n            if (bestVal >= 90) rarity += 0.3;\n            else if (bestVal >= 80) rarity += 0.2;\n            if (gapAttr >= 5) rarity += 0.25;\n            if (gapAttr >= 10) rarity += 0.25;\n            if (bestCount <= 3) rarity += 0.25;\n            if (bestCount == 1) rarity += 0.35;\n            attrWeights[l] = rarity;\n        }\n        double attrComponentScale = (4.0 + 3.0 * (1.0 - phase)) * (0.85 + 0.25 * gapFactor);\n\n        vector<char> attrConsider(M, false);\n        vector<int> coverageThreshold(M, 0);\n        for (int l = 0; l < M; ++l) {\n            int bestVal = bestAttrValue[l];\n            if (bestVal >= 4) attrConsider[l] = true;\n            if (bestVal <= 1) {\n                coverageThreshold[l] = max(0, bestVal);\n            } else {\n                int base = max(attrTargets[l], bestVal - 4);\n                base = min(base, bestVal - 1);\n                coverageThreshold[l] = max(0, base);\n            }\n        }\n\n        vector<int> attrCoverage(seedCount, 0);\n        vector<int> nearBestCount(seedCount, 0);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            int sum = 0;\n            int near = 0;\n            for (int l = 0; l < M; ++l) {\n                if (!attrConsider[l]) continue;\n                int thr = coverageThreshold[l];\n                int diff = seeds[idx].attr[l] - thr;\n                if (diff >= 0) ++near;\n                if (diff > 0) sum += diff;\n            }\n            attrCoverage[idx] = sum;\n            nearBestCount[idx] = near;\n        }\n\n        double wValue = 1.0;\n        double wAttr = 4.5 + 6.0 * gapFactor;\n        double wNear = 8.0 + 6.0 * gapFactor;\n        double wChampion = 150.0 + 40.0 * gapFactor;\n\n        vector<double> combinedScore(seedCount, 0.0);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            combinedScore[idx] = wValue * seeds[idx].value +\n                                 wAttr * attrCoverage[idx] +\n                                 wChampion * seedChampionCount[idx] +\n                                 wNear * nearBestCount[idx];\n        }\n\n        vector<int> attrImportance(M);\n        iota(attrImportance.begin(), attrImportance.end(), 0);\n        sort(attrImportance.begin(), attrImportance.end(), [&](int a, int b) {\n            if (attrWeights[a] > attrWeights[b] + 1e-9) return true;\n            if (attrWeights[b] > attrWeights[a] + 1e-9) return false;\n            if (bestAttrValue[a] != bestAttrValue[b]) return bestAttrValue[a] > bestAttrValue[b];\n            return a < b;\n        });\n\n        vector<int> selectedIndices;\n        selectedIndices.reserve(selectCount);\n        vector<char> used(seedCount, false);\n\n        for (int l = 0; l < M; ++l) {\n            int idx = bestAttrIndex[l];\n            if (idx >= 0 && !used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n\n        int extraPerAttr = (gapFactor >= 0.65 ? 3 : 2);\n        for (int attrIdx : attrImportance) {\n            if ((int)selectedIndices.size() >= selectCount) break;\n            if (!attrConsider[attrIdx] && attrWeights[attrIdx] < 0.05) continue;\n            int added = 0;\n            for (int seedIdx : attrOrder[attrIdx]) {\n                if ((int)selectedIndices.size() >= selectCount) break;\n                if (used[seedIdx]) continue;\n                if (attrConsider[attrIdx]) {\n                    int thr = coverageThreshold[attrIdx];\n                    if (seeds[seedIdx].attr[attrIdx] + 2 < thr) break;\n                }\n                used[seedIdx] = true;\n                selectedIndices.push_back(seedIdx);\n                ++added;\n                if (added >= extraPerAttr) break;\n            }\n        }\n\n        iota(orderIndices.begin(), orderIndices.end(), 0);\n        sort(orderIndices.begin(), orderIndices.end(), [&](int a, int b) {\n            if (combinedScore[a] > combinedScore[b] + 1e-9) return true;\n            if (combinedScore[b] > combinedScore[a] + 1e-9) return false;\n            if (seedChampionCount[a] != seedChampionCount[b]) return seedChampionCount[a] > seedChampionCount[b];\n            if (attrCoverage[a] != attrCoverage[b]) return attrCoverage[a] > attrCoverage[b];\n            if (nearBestCount[a] != nearBestCount[b]) return nearBestCount[a] > nearBestCount[b];\n            if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n            return a < b;\n        });\n        for (int idx : orderIndices) {\n            if ((int)selectedIndices.size() >= selectCount) break;\n            if (!used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n        if ((int)selectedIndices.size() < selectCount) {\n            for (int idx = 0; idx < seedCount && (int)selectedIndices.size() < selectCount; ++idx) {\n                if (!used[idx]) {\n                    used[idx] = true;\n                    selectedIndices.push_back(idx);\n                }\n            }\n        }\n\n        vector<int> selectedValues(selectCount);\n        vector<int> selectedAttrCount(selectCount);\n        vector<int> selectedCoverage(selectCount);\n        vector<int> selectedNearCount(selectCount);\n        for (int i = 0; i < selectCount; ++i) {\n            int idx = selectedIndices[i];\n            selectedValues[i] = seeds[idx].value;\n            selectedAttrCount[i] = seedChampionCount[idx];\n            selectedCoverage[i] = attrCoverage[idx];\n            selectedNearCount[i] = nearBestCount[idx];\n        }\n\n        vector<int> targetsLocal = targets;\n        vector<double> weightsLocal = weights;\n        vector<double> probWeightsLocal = probWeights;\n\n        vector<int> attrTargetsLocal = attrTargets;\n        vector<double> attrWeightsLocal = attrWeights;\n\n        double attrComponentScaleLocal = attrComponentScale;\n\n        int S = selectCount;\n        vector<double> pairScore((size_t)S * S, 0.0);\n        for (int i = 0; i < S; ++i) {\n            pairScore[i * S + i] = 0.0;\n            for (int j = i + 1; j < S; ++j) {\n                double val = computePairScore(seeds[selectedIndices[i]],\n                                              seeds[selectedIndices[j]],\n                                              targetsLocal, weightsLocal, probWeightsLocal,\n                                              M, bestValue, potentialWeight,\n                                              attrTargetsLocal, attrWeightsLocal, attrComponentScaleLocal);\n                pairScore[i * S + j] = val;\n                pairScore[j * S + i] = val;\n            }\n        }\n\n        auto makeOrder = [&](auto comparator) {\n            vector<int> ord(S);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), comparator);\n            return ord;\n        };\n\n        auto cmpChampion = [&](int a, int b) {\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            if (selectedNearCount[a] != selectedNearCount[b]) return selectedNearCount[a] > selectedNearCount[b];\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n        auto cmpCoverage = [&](int a, int b) {\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedNearCount[a] != selectedNearCount[b]) return selectedNearCount[a] > selectedNearCount[b];\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n        auto cmpValue = [&](int a, int b) {\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            if (selectedNearCount[a] != selectedNearCount[b]) return selectedNearCount[a] > selectedNearCount[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n        vector<double> hybridScore(selectCount);\n        for (int i = 0; i < selectCount; ++i) {\n            hybridScore[i] = selectedValues[i] * 1.0 +\n                             selectedCoverage[i] * 6.5 +\n                             selectedAttrCount[i] * 220.0 +\n                             selectedNearCount[i] * 18.0;\n        }\n        auto cmpHybrid = [&](int a, int b) {\n            if (hybridScore[a] > hybridScore[b] + 1e-9) return true;\n            if (hybridScore[b] > hybridScore[a] + 1e-9) return false;\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n\n        vector<int> orderChampion = makeOrder(cmpChampion);\n        vector<int> orderHybrid = makeOrder(cmpHybrid);\n        vector<int> orderCoverage = makeOrder(cmpCoverage);\n        vector<int> orderValue = makeOrder(cmpValue);\n        vector<int> orderRandom(selectCount);\n        iota(orderRandom.begin(), orderRandom.end(), 0);\n        shuffle(orderRandom.begin(), orderRandom.end(), rng);\n        vector<int> orderRandom2 = orderRandom;\n        shuffle(orderRandom2.begin(), orderRandom2.end(), rng);\n\n        vector<vector<int>> seedOrders;\n        seedOrders.reserve(6);\n        seedOrders.push_back(orderChampion);\n        seedOrders.push_back(orderHybrid);\n        seedOrders.push_back(orderCoverage);\n        seedOrders.push_back(orderValue);\n        seedOrders.push_back(orderRandom);\n        seedOrders.push_back(orderRandom2);\n\n        vector<vector<int>> cellOrders = {positionOrder, positionOrderReverse, positionOrderRow};\n\n        const int MAX_INITIAL = 8;\n        vector<pair<int, int>> comboPriority = {\n            {0, 0}, {1, 0}, {2, 0}, {3, 0},\n            {0, 1}, {1, 2}, {2, 1}, {3, 2},\n            {4, 0}, {5, 0}, {4, 1}, {5, 1}\n        };\n\n        vector<vector<int>> initialAssignments;\n        for (auto [si, ci] : comboPriority) {\n            if ((int)initialAssignments.size() >= MAX_INITIAL) break;\n            if (si >= (int)seedOrders.size() || ci >= (int)cellOrders.size()) continue;\n            vector<int> assign(cellCount, -1);\n            const auto& order = seedOrders[si];\n            const auto& placement = cellOrders[ci];\n            for (int idx = 0; idx < cellCount; ++idx) {\n                assign[placement[idx]] = order[idx];\n            }\n            initialAssignments.push_back(assign);\n        }\n        if (initialAssignments.empty()) {\n            vector<int> assign(cellCount, -1);\n            for (int idx = 0; idx < cellCount; ++idx) {\n                assign[positionOrder[idx]] = orderChampion[idx];\n            }\n            initialAssignments.push_back(assign);\n        }\n\n        double degWeight = 0.02 * (0.9 - 0.4 * phase);\n        int initialCount = initialAssignments.size();\n        int totalBudget = (int)(15000 + 6000 * (1.0 - phase));\n        int iterPerInit = max(2000, totalBudget / max(1, initialCount));\n\n        vector<int> bestAssignGlobal;\n        double bestScoreGlobal = -1e100;\n\n        auto runSA = [&](const vector<int>& initialAssign) {\n            vector<int> assign = initialAssign;\n            double edgeScore = 0.0;\n            for (auto [u, v] : edges) {\n                edgeScore += pairScore[assign[u] * S + assign[v]];\n            }\n            double degTerm = 0.0;\n            for (int pos = 0; pos < cellCount; ++pos) {\n                degTerm += cellDegree[pos] * selectedValues[assign[pos]];\n            }\n            double currentScore = edgeScore + degWeight * degTerm;\n            double bestScore = currentScore;\n            vector<int> bestAssign = assign;\n\n            double Tstart = 1.2 * improvementScale + 0.3;\n            double Tend = 0.01;\n            array<pair<int, int>, 32> impacted{};\n\n            for (int iter = 0; iter < iterPerInit; ++iter) {\n                int pos1 = posDist(rng);\n                int pos2 = posDist(rng);\n                if (pos1 == pos2) continue;\n                int seed1 = assign[pos1];\n                int seed2 = assign[pos2];\n                if (seed1 == seed2) continue;\n\n                int cnt = 0;\n                auto addEdgeLocal = [&](int a, int b) {\n                    if (a > b) swap(a, b);\n                    for (int k = 0; k < cnt; ++k) {\n                        if (impacted[k].first == a && impacted[k].second == b) return;\n                    }\n                    impacted[cnt++] = {a, b};\n                };\n                for (int nb : neighbors[pos1]) addEdgeLocal(pos1, nb);\n                for (int nb : neighbors[pos2]) addEdgeLocal(pos2, nb);\n\n                double beforeEdge = 0.0;\n                for (int k = 0; k < cnt; ++k) {\n                    int a = impacted[k].first;\n                    int b = impacted[k].second;\n                    beforeEdge += pairScore[assign[a] * S + assign[b]];\n                }\n\n                double deltaPos = degWeight * (double)(selectedValues[seed2] - selectedValues[seed1]) *\n                                  (cellDegree[pos1] - cellDegree[pos2]);\n\n                swap(assign[pos1], assign[pos2]);\n\n                double afterEdge = 0.0;\n                for (int k = 0; k < cnt; ++k) {\n                    int a = impacted[k].first;\n                    int b = impacted[k].second;\n                    afterEdge += pairScore[assign[a] * S + assign[b]];\n                }\n\n                double delta = (afterEdge - beforeEdge) + deltaPos;\n                double progress = (double)iter / iterPerInit;\n                double temperature = Tstart + (Tend - Tstart) * progress;\n                bool accept = false;\n                if (delta >= 0) {\n                    accept = true;\n                } else if (temperature > 0) {\n                    double prob = exp(delta / temperature);\n                    if (realDist(rng) < prob) accept = true;\n                }\n                if (accept) {\n                    currentScore += delta;\n                    if (currentScore > bestScore) {\n                        bestScore = currentScore;\n                        bestAssign = assign;\n                    }\n                } else {\n                    swap(assign[pos1], assign[pos2]);\n                }\n            }\n\n            if (bestScore > bestScoreGlobal) {\n                bestScoreGlobal = bestScore;\n                bestAssignGlobal = bestAssign;\n            }\n        };\n\n        for (const auto& initAssign : initialAssignments) {\n            runSA(initAssign);\n        }\n\n        if (bestAssignGlobal.empty()) bestAssignGlobal = initialAssignments[0];\n\n        vector<vector<int>> grid(N, vector<int>(N, 0));\n        for (int pos = 0; pos < cellCount; ++pos) {\n            int r = pos / N;\n            int c = pos % N;\n            grid[r][c] = selectedIndices[bestAssignGlobal[pos]];\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (j) cout << ' ';\n                cout << grid[i][j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        if (turn + 1 == T) break;\n        for (int i = 0; i < seedCount; ++i) {\n            int sum = 0;\n            for (int j = 0; j < M; ++j) {\n                int val;\n                cin >> val;\n                seeds[i].attr[j] = val;\n                sum += val;\n            }\n            seeds[i].value = sum;\n        }\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Cell {\n    int x, y;\n};\n\nvector<int> hungarian(const vector<vector<int>>& a) {\n    int n = (int)a.size();\n    const int INF = 1e9;\n    vector<int> u(n + 1, 0), v(n + 1, 0), p(n + 1, 0), way(n + 1, 0);\n    for (int i = 1; i <= n; ++i) {\n        p[0] = i;\n        vector<int> minv(n + 1, INF);\n        vector<char> used(n + 1, false);\n        int j0 = 0;\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 = a[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= n; ++j) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    v[j] -= delta;\n                } else {\n                    minv[j] -= delta;\n                }\n            }\n            j0 = j1;\n        } while (p[j0] != 0);\n        do {\n            int j1 = way[j0];\n            p[j0] = p[j1];\n            j0 = j1;\n        } while (j0);\n    }\n    vector<int> match(n, -1);\n    for (int j = 1; j <= n; ++j)\n        if (p[j] != 0) match[p[j] - 1] = j - 1;\n    return match;\n}\n\nuint64_t hilbertOrder(int x, int y, int pow2) {\n    uint64_t d = 0;\n    for (int s = pow2 / 2; s > 0; s >>= 1) {\n        int rx = (x & s) ? 1 : 0;\n        int ry = (y & s) ? 1 : 0;\n        d += (uint64_t)s * s * ((3 * rx) ^ ry);\n        if (ry == 0) {\n            if (rx == 1) {\n                x = pow2 - 1 - x;\n                y = pow2 - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n    return d;\n}\n\nll bridging_cost(const vector<int> &ord, const vector<vector<int>> &C) {\n    ll res = 0;\n    for (int i = 1; i < (int)ord.size(); ++i)\n        res += C[ord[i - 1]][ord[i]];\n    return res;\n}\n\nvector<int> relocate_full(vector<int> ord, const vector<vector<int>> &C) {\n    int n = ord.size();\n    if (n <= 2) return ord;\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        n = ord.size();\n        for (int i = 0; i < n; ++i) {\n            int node = ord[i];\n            int left = (i > 0) ? ord[i - 1] : -1;\n            int right = (i + 1 < n) ? ord[i + 1] : -1;\n            ll removal = 0;\n            if (left != -1) removal -= C[left][node];\n            if (right != -1) removal -= C[node][right];\n            if (left != -1 && right != -1) removal += C[left][right];\n            int newSize = n - 1;\n            int bestPos = -1;\n            ll bestDelta = 0;\n            for (int pos = 0; pos <= newSize; ++pos) {\n                if (pos == i) continue;\n                int prev = -1;\n                if (pos > 0) {\n                    int idx = pos - 1;\n                    prev = (idx < i) ? ord[idx] : ord[idx + 1];\n                }\n                int next = -1;\n                if (pos < newSize) {\n                    int idx = pos;\n                    next = (idx < i) ? ord[idx] : ord[idx + 1];\n                }\n                ll delta = removal;\n                if (prev != -1) delta += C[prev][node];\n                if (next != -1) delta += C[node][next];\n                if (prev != -1 && next != -1) delta -= C[prev][next];\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPos = pos;\n                }\n            }\n            if (bestPos != -1) {\n                int val = ord[i];\n                ord.erase(ord.begin() + i);\n                ord.insert(ord.begin() + bestPos, val);\n                improved = true;\n                break;\n            }\n        }\n    }\n    return ord;\n}\n\nvector<int> two_opt_full(vector<int> ord, const vector<vector<int>> &C) {\n    int n = ord.size();\n    if (n <= 2) return ord;\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int l = 0; l < n - 1; ++l) {\n            for (int r = l + 1; r < n; ++r) {\n                ll before = 0;\n                if (l > 0) before += C[ord[l - 1]][ord[l]];\n                for (int k = l + 1; k <= r; ++k)\n                    before += C[ord[k - 1]][ord[k]];\n                if (r + 1 < n) before += C[ord[r]][ord[r + 1]];\n                ll after = 0;\n                if (l > 0) after += C[ord[l - 1]][ord[r]];\n                for (int k = r; k > l; --k)\n                    after += C[ord[k]][ord[k - 1]];\n                if (r + 1 < n) after += C[ord[l]][ord[r + 1]];\n                if (after < before) {\n                    reverse(ord.begin() + l, ord.begin() + r + 1);\n                    improved = true;\n                    break;\n                }\n            }\n            if (improved) break;\n        }\n    }\n    return ord;\n}\n\nvector<int> swap_full(vector<int> ord, const vector<vector<int>> &C) {\n    int n = ord.size();\n    if (n <= 2) return ord;\n    auto getEdge = [&](const vector<int> &arr, int pos) -> ll {\n        if (pos <= 0 || pos >= (int)arr.size()) return 0;\n        return C[arr[pos - 1]][arr[pos]];\n    };\n    bool done = false;\n    while (!done) {\n        done = true;\n        for (int i = 0; i < n - 1 && done; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                vector<int> idxs = {i, i + 1, j, j + 1};\n                sort(idxs.begin(), idxs.end());\n                idxs.erase(unique(idxs.begin(), idxs.end()), idxs.end());\n                ll before = 0, after = 0;\n                for (int pos : idxs) before += getEdge(ord, pos);\n                swap(ord[i], ord[j]);\n                for (int pos : idxs) after += getEdge(ord, pos);\n                if (after < before) {\n                    done = false;\n                    break;\n                } else swap(ord[i], ord[j]);\n            }\n        }\n    }\n    return ord;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, M, V;\n    if (!(cin >> N >> M >> V)) return 0;\n    vector<string> s(N), t(N);\n    for (int i = 0; i < N; ++i) cin >> s[i];\n    for (int i = 0; i < N; ++i) cin >> t[i];\n\n    vector<vector<int>> occ(N, vector<int>(N, 0));\n    vector<Cell> surplus, deficit;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            occ[i][j] = s[i][j] - '0';\n            int ti = t[i][j] - '0';\n            if (occ[i][j] == 1 && ti == 0) surplus.push_back({i, j});\n            else if (occ[i][j] == 0 && ti == 1) deficit.push_back({i, j});\n        }\n    }\n\n    int K = surplus.size();\n    vector<int> match;\n    if (K > 0) {\n        vector<vector<int>> cost(K, vector<int>(K));\n        for (int i = 0; i < K; ++i)\n            for (int j = 0; j < K; ++j)\n                cost[i][j] = abs(surplus[i].x - deficit[j].x) +\n                             abs(surplus[i].y - deficit[j].y);\n        match = hungarian(cost);\n    }\n\n    vector<int> pickX(K), pickY(K), dropX(K), dropY(K);\n    for (int i = 0; i < K; ++i) {\n        pickX[i] = surplus[i].x;\n        pickY[i] = surplus[i].y;\n        dropX[i] = deficit[match[i]].x;\n        dropY[i] = deficit[match[i]].y;\n    }\n\n    vector<vector<int>> C(K, vector<int>(K, 0));\n    for (int i = 0; i < K; ++i)\n        for (int j = 0; j < K; ++j)\n            C[i][j] = abs(dropX[i] - pickX[j]) + abs(dropY[i] - pickY[j]);\n\n    vector<vector<int>> candidates;\n    if (K > 0) {\n        vector<int> idx(K);\n        iota(idx.begin(), idx.end(), 0);\n\n        vector<int> greedy;\n        vector<char> used(K, false);\n        pair<int,int> cur = {N / 2, N / 2};\n        for (int iter = 0; iter < K; ++iter) {\n            int best = -1, bestDist = INT_MAX, bestPair = INT_MAX;\n            for (int i = 0; i < K; ++i) if (!used[i]) {\n                int dist = abs(cur.first - pickX[i]) + abs(cur.second - pickY[i]);\n                int pairDist = abs(pickX[i] - dropX[i]) + abs(pickY[i] - dropY[i]);\n                if (dist < bestDist || (dist == bestDist && pairDist < bestPair)) {\n                    best = i;\n                    bestDist = dist;\n                    bestPair = pairDist;\n                }\n            }\n            used[best] = true;\n            greedy.push_back(best);\n            cur = {dropX[best], dropY[best]};\n        }\n        candidates.push_back(greedy);\n\n        int pow2 = 1;\n        while (pow2 < max(N, 1)) pow2 <<= 1;\n        vector<uint64_t> hilb(K);\n        for (int i = 0; i < K; ++i) hilb[i] = hilbertOrder(pickX[i], pickY[i], pow2);\n        vector<int> hilbertIdx = idx;\n        sort(hilbertIdx.begin(), hilbertIdx.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            if (pickX[a] != pickX[b]) return pickX[a] < pickX[b];\n            return pickY[a] < pickY[b];\n        });\n        candidates.push_back(hilbertIdx);\n\n        vector<int> rowIdx = idx;\n        sort(rowIdx.begin(), rowIdx.end(), [&](int a, int b) {\n            if (pickX[a] != pickX[b]) return pickX[a] < pickX[b];\n            return pickY[a] < pickY[b];\n        });\n        candidates.push_back(rowIdx);\n\n        vector<int> rndIdx = idx;\n        mt19937 rng_seed(1234567);\n        shuffle(rndIdx.begin(), rndIdx.end(), rng_seed);\n        candidates.push_back(rndIdx);\n    }\n\n    vector<int> bestOrder;\n    ll bestScore = (1LL << 60);\n    if (K > 0) {\n        for (auto cand : candidates) {\n            cand = relocate_full(cand, C);\n            cand = two_opt_full(cand, C);\n            cand = swap_full(cand, C);\n            ll cost = bridging_cost(cand, C);\n            if (bestOrder.empty() || cost < bestScore) {\n                bestScore = cost;\n                bestOrder = cand;\n            }\n        }\n        if (bestOrder.empty()) {\n            bestOrder.resize(K);\n            iota(bestOrder.begin(), bestOrder.end(), 0);\n            bestScore = bridging_cost(bestOrder, C);\n        }\n        mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());\n        vector<int> curOrder = bestOrder;\n        ll curScore = bestScore;\n        vector<int> globalBest = bestOrder;\n        ll globalBestScore = bestScore;\n        int maxIter = 60000 + 300 * K;\n        double T0 = 2000.0, T1 = 1e-3;\n        uniform_real_distribution<double> dist01(0.0, 1.0);\n        auto getEdge = [&](const vector<int> &ord, int pos) -> ll {\n            if (pos <= 0 || pos >= (int)ord.size()) return 0;\n            return C[ord[pos - 1]][ord[pos]];\n        };\n        for (int iter = 0; iter < maxIter; ++iter) {\n            double progress = (double)iter / maxIter;\n            double temp = T0 * pow(T1 / T0, progress);\n            if (temp < 1e-9) temp = 1e-9;\n            int op = rng() % 3;\n            bool changed = false;\n            ll delta = 0;\n            int n = curOrder.size();\n            if (op == 0 && n >= 2) {\n                int i = rng() % n;\n                int j = rng() % n;\n                if (i == j) continue;\n                if (i > j) swap(i, j);\n                vector<int> idxs = {i, i + 1, j, j + 1};\n                sort(idxs.begin(), idxs.end());\n                idxs.erase(unique(idxs.begin(), idxs.end()), idxs.end());\n                ll before = 0, after = 0;\n                for (int pos : idxs) before += getEdge(curOrder, pos);\n                swap(curOrder[i], curOrder[j]);\n                for (int pos : idxs) after += getEdge(curOrder, pos);\n                delta = after - before;\n                if (delta <= 0 || dist01(rng) < exp(-delta / temp)) {\n                    curScore += delta;\n                    changed = true;\n                } else swap(curOrder[i], curOrder[j]);\n            } else if (op == 1 && n >= 3) {\n                int l = rng() % (n - 1);\n                int lenMax = min(n - l, 40);\n                if (lenMax < 2) continue;\n                int len = 2 + (lenMax > 2 ? rng() % (lenMax - 1) : 0);\n                int r = l + len - 1;\n                if (r >= n) r = n - 1;\n                if (r - l < 1) continue;\n                ll before = 0, after = 0;\n                if (l > 0) before += C[curOrder[l - 1]][curOrder[l]];\n                for (int k = l + 1; k <= r; ++k) before += C[curOrder[k - 1]][curOrder[k]];\n                if (r + 1 < n) before += C[curOrder[r]][curOrder[r + 1]];\n                if (l > 0) after += C[curOrder[l - 1]][curOrder[r]];\n                for (int k = r; k > l; --k) after += C[curOrder[k]][curOrder[k - 1]];\n                if (r + 1 < n) after += C[curOrder[l]][curOrder[r + 1]];\n                delta = after - before;\n                if (delta <= 0 || dist01(rng) < exp(-delta / temp)) {\n                    reverse(curOrder.begin() + l, curOrder.begin() + r + 1);\n                    curScore += delta;\n                    changed = true;\n                }\n            } else if (op == 2 && n >= 3) {\n                int i = rng() % n;\n                int newSize = n - 1;\n                if (newSize <= 0) continue;\n                int pos = rng() % n;\n                if (pos == i) continue;\n                int node = curOrder[i];\n                int left = (i > 0) ? curOrder[i - 1] : -1;\n                int right = (i + 1 < n) ? curOrder[i + 1] : -1;\n                ll deltaRem = 0;\n                if (left != -1) deltaRem -= C[left][node];\n                if (right != -1) deltaRem -= C[node][right];\n                if (left != -1 && right != -1) deltaRem += C[left][right];\n                int prev = -1;\n                if (pos > 0) {\n                    int idx = pos - 1;\n                    prev = (idx < i) ? curOrder[idx] : curOrder[idx + 1];\n                }\n                int next = -1;\n                if (pos < newSize) {\n                    int idx = pos;\n                    next = (idx < i) ? curOrder[idx] : curOrder[idx + 1];\n                }\n                ll deltaIns = 0;\n                if (prev != -1) deltaIns += C[prev][node];\n                if (next != -1) deltaIns += C[node][next];\n                if (prev != -1 && next != -1) deltaIns -= C[prev][next];\n                delta = deltaRem + deltaIns;\n                if (delta <= 0 || dist01(rng) < exp(-delta / temp)) {\n                    int val = curOrder[i];\n                    curOrder.erase(curOrder.begin() + i);\n                    if (pos > (int)curOrder.size()) pos = curOrder.size();\n                    curOrder.insert(curOrder.begin() + pos, val);\n                    curScore += delta;\n                    changed = true;\n                }\n            }\n            if (changed && curScore < globalBestScore) {\n                globalBestScore = curScore;\n                globalBest = curOrder;\n            }\n        }\n        bestOrder = globalBest;\n        bestScore = globalBestScore;\n    }\n\n    int root_x = (K > 0) ? pickX[bestOrder[0]] : 0;\n    int root_y = (K > 0) ? pickY[bestOrder[0]] : 0;\n\n    cout << 1 << '\\n';\n    cout << root_x << ' ' << root_y << '\\n';\n\n    if (K == 0) return 0;\n\n    const int LIMIT = 100000;\n    vector<string> ops;\n    ops.reserve(2 * K);\n    bool limitReached = false;\n    int rx = root_x, ry = root_y;\n    bool holding = false;\n\n    auto emit = [&](char moveChar, char actionChar) -> bool {\n        if ((int)ops.size() >= LIMIT) {\n            limitReached = true;\n            return false;\n        }\n        string op(2, '.');\n        op[0] = moveChar;\n        op[1] = actionChar;\n        ops.push_back(op);\n        if (moveChar == 'U') --rx;\n        else if (moveChar == 'D') ++rx;\n        else if (moveChar == 'L') --ry;\n        else if (moveChar == 'R') ++ry;\n        return true;\n    };\n\n    auto move_with_action = [&](int tx, int ty, bool doAction, bool isPick) {\n        if (limitReached) return;\n        vector<char> path;\n        int cx = rx, cy = ry;\n        while (cx < tx) { path.push_back('D'); ++cx; }\n        while (cx > tx) { path.push_back('U'); --cx; }\n        while (cy < ty) { path.push_back('R'); ++cy; }\n        while (cy > ty) { path.push_back('L'); --cy; }\n        if (path.empty()) {\n            if (doAction) emit('.', 'P');\n        } else {\n            for (size_t i = 0; i < path.size(); ++i) {\n                char act = (doAction && i + 1 == path.size()) ? 'P' : '.';\n                if (!emit(path[i], act)) return;\n            }\n        }\n        if (doAction && !limitReached) {\n            if (isPick) {\n                if (!holding && occ[tx][ty] == 1) {\n                    occ[tx][ty] = 0;\n                    holding = true;\n                }\n            } else {\n                if (holding && occ[tx][ty] == 0) {\n                    occ[tx][ty] = 1;\n                    holding = false;\n                }\n            }\n        }\n    };\n\n    for (int idx : bestOrder) {\n        move_with_action(pickX[idx], pickY[idx], true, true);\n        if (limitReached) break;\n        move_with_action(dropX[idx], dropY[idx], true, false);\n        if (limitReached) break;\n    }\n\n    for (const string &line : ops) cout << line << '\\n';\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAX_COORD = 100000;\nconst int NEG_INF = -1000000000;\nconstexpr double TIME_LIMIT = 1.92;\n\nstruct Score {\n    int diff;\n    int m;\n    int s;\n};\n\nstruct RectAns {\n    int x1 = 0, x2 = 0, y1 = 0, y2 = 0;\n    Score sc{NEG_INF, 0, 0};\n};\n\nstruct ShapeAns {\n    vector<pair<int,int>> poly;\n    Score sc{NEG_INF, 0, 0};\n    long long area2 = 0;\n};\n\nstruct BIT2D {\n    int n = 0;\n    vector<int> xs_sorted;\n    vector<vector<int>> ys;\n    vector<vector<int>> bitM, bitS;\n\n    void build(const vector<int>& px, const vector<int>& py, const vector<int>& type) {\n        xs_sorted = px;\n        sort(xs_sorted.begin(), xs_sorted.end());\n        xs_sorted.erase(unique(xs_sorted.begin(), xs_sorted.end()), xs_sorted.end());\n        n = xs_sorted.size();\n        ys.assign(n + 1, {});\n        for (size_t idx = 0; idx < px.size(); ++idx) {\n            int xi = lower_bound(xs_sorted.begin(), xs_sorted.end(), px[idx]) - xs_sorted.begin() + 1;\n            for (int i = xi; i <= n; i += i & -i) ys[i].push_back(py[idx]);\n        }\n        bitM.assign(n + 1, {});\n        bitS.assign(n + 1, {});\n        for (int i = 1; i <= n; ++i) {\n            auto &vec = ys[i];\n            sort(vec.begin(), vec.end());\n            vec.erase(unique(vec.begin(), vec.end()), vec.end());\n            bitM[i].assign(vec.size() + 1, 0);\n            bitS[i].assign(vec.size() + 1, 0);\n        }\n        for (size_t idx = 0; idx < px.size(); ++idx) {\n            int xi = lower_bound(xs_sorted.begin(), xs_sorted.end(), px[idx]) - xs_sorted.begin() + 1;\n            int y = py[idx];\n            int addM = type[idx] == 1 ? 1 : 0;\n            int addS = type[idx] == -1 ? 1 : 0;\n            for (int i = xi; i <= n; i += i & -i) {\n                if (ys[i].empty()) continue;\n                int yi = lower_bound(ys[i].begin(), ys[i].end(), y) - ys[i].begin() + 1;\n                if (addM) {\n                    for (int j = yi; j < (int)bitM[i].size(); j += j & -j) bitM[i][j] += addM;\n                }\n                if (addS) {\n                    for (int j = yi; j < (int)bitS[i].size(); j += j & -j) bitS[i][j] += addS;\n                }\n            }\n        }\n    }\n\n    pair<int,int> prefix(int xVal, int yVal) const {\n        if (n == 0) return {0,0};\n        int xi = upper_bound(xs_sorted.begin(), xs_sorted.end(), xVal) - xs_sorted.begin();\n        int sumM = 0, sumS = 0;\n        for (int i = xi; i > 0; i -= i & -i) {\n            const auto &vec = ys[i];\n            if (vec.empty()) continue;\n            int yi = upper_bound(vec.begin(), vec.end(), yVal) - vec.begin();\n            for (int j = yi; j > 0; j -= j & -j) {\n                sumM += bitM[i][j];\n                sumS += bitS[i][j];\n            }\n        }\n        return {sumM, sumS};\n    }\n};\n\nBIT2D bit2d;\nint N;\nvector<int> xs, ys, types;\nvector<pair<int,int>> m_coords;\nRectAns best_rect;\nvector<RectAns> top_rects;\nconst int TOP_LIMIT = 24;\nShapeAns best_shape;\nvector<int> unique_x_vals, unique_y_vals;\n\nmt19937 rng(chrono::steady_clock::now().time_since_epoch().count());\nchrono::steady_clock::time_point start_time;\n\ninline double elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n}\n\ninline bool normalize_rect(int &x1, int &x2, int &y1, int &y2) {\n    if (x1 > x2) swap(x1, x2);\n    if (y1 > y2) swap(y1, y2);\n    x1 = clamp(x1, 0, MAX_COORD);\n    x2 = clamp(x2, 0, MAX_COORD);\n    y1 = clamp(y1, 0, MAX_COORD);\n    y2 = clamp(y2, 0, MAX_COORD);\n    if (x1 == x2) {\n        if (x2 < MAX_COORD) ++x2;\n        else if (x1 > 0) --x1;\n    }\n    if (y1 == y2) {\n        if (y2 < MAX_COORD) ++y2;\n        else if (y1 > 0) --y1;\n    }\n    return x1 != x2 && y1 != y2;\n}\n\ninline long long rect_area(int x1, int x2, int y1, int y2) {\n    return 1LL * (x2 - x1) * (y2 - y1);\n}\n\nbool better_rect(const RectAns &a, const RectAns &b) {\n    if (b.sc.diff == NEG_INF) return true;\n    if (a.sc.diff != b.sc.diff) return a.sc.diff > b.sc.diff;\n    if (a.sc.m != b.sc.m) return a.sc.m > b.sc.m;\n    if (a.sc.s != b.sc.s) return a.sc.s < b.sc.s;\n    return rect_area(a.x1,a.x2,a.y1,a.y2) < rect_area(b.x1,b.x2,b.y1,b.y2);\n}\n\nScore compute_score(int x1, int x2, int y1, int y2) {\n    auto A = bit2d.prefix(x2, y2);\n    auto B = bit2d.prefix(x1 - 1, y2);\n    auto C = bit2d.prefix(x2, y1 - 1);\n    auto D = bit2d.prefix(x1 - 1, y1 - 1);\n    int m = A.first - B.first - C.first + D.first;\n    int s = A.second - B.second - C.second + D.second;\n    return {m - s, m, s};\n}\n\nvoid push_candidate(const RectAns &cand) {\n    if (better_rect(cand, best_rect)) best_rect = cand;\n    for (auto &r : top_rects) {\n        if (r.x1 == cand.x1 && r.x2 == cand.x2 && r.y1 == cand.y1 && r.y2 == cand.y2) {\n            if (better_rect(cand, r)) r = cand;\n            return;\n        }\n    }\n    auto it = top_rects.begin();\n    while (it != top_rects.end() && !better_rect(cand, *it)) ++it;\n    top_rects.insert(it, cand);\n    if ((int)top_rects.size() > TOP_LIMIT) top_rects.pop_back();\n}\n\nvoid consider_rect(int x1, int x2, int y1, int y2) {\n    if (!normalize_rect(x1,x2,y1,y2)) return;\n    Score sc = compute_score(x1,x2,y1,y2);\n    RectAns cand{x1,x2,y1,y2,sc};\n    push_candidate(cand);\n}\n\nvoid add_vertex(vector<pair<int,int>>& poly, int x, int y) {\n    if (!poly.empty() && poly.back().first == x && poly.back().second == y) return;\n    poly.emplace_back(x,y);\n}\n\nlong long polygon_area2(const vector<pair<int,int>>& poly) {\n    int m = poly.size();\n    long long area2 = 0;\n    for (int i = 0; i < m; ++i) {\n        const auto &a = poly[i];\n        const auto &b = poly[(i + 1) % m];\n        area2 += 1LL * a.first * b.second - 1LL * a.second * b.first;\n    }\n    return llabs(area2);\n}\n\nbool point_on_segment(int x1,int y1,int x2,int y2,int px,int py){\n    if (x1==x2 && px==x1) {\n        if (min(y1,y2)<=py && py<=max(y1,y2)) return true;\n    }\n    if (y1==y2 && py==y1) {\n        if (min(x1,x2)<=px && px<=max(x1,x2)) return true;\n    }\n    return false;\n}\n\nbool point_in_poly_axis(const vector<pair<int,int>>& poly, int x, int y) {\n    bool inside = false;\n    int m = poly.size();\n    for (int i = 0; i < m; ++i) {\n        const auto &a = poly[i];\n        const auto &b = poly[(i + 1) % m];\n        if (point_on_segment(a.first,a.second,b.first,b.second,x,y)) return true;\n        bool cond = ((a.second > y) != (b.second > y));\n        if (cond) {\n            long double atX = (long double)(b.first - a.first) * (y - a.second) / (b.second - a.second) + a.first;\n            if ((long double)x < atX) inside = !inside;\n        }\n    }\n    return inside;\n}\n\nScore evaluate_polygon_points(const vector<pair<int,int>>& poly) {\n    if (poly.size() < 3) return {NEG_INF,0,0};\n    int minx = INT_MAX, maxx = INT_MIN, miny = INT_MAX, maxy = INT_MIN;\n    for (auto [x,y] : poly) {\n        minx = min(minx, x);\n        maxx = max(maxx, x);\n        miny = min(miny, y);\n        maxy = max(maxy, y);\n       }\n    Score sc{0,0,0};\n    for (size_t i = 0; i < xs.size(); ++i) {\n        int px = xs[i], py = ys[i];\n        if (px < minx || px > maxx || py < miny || py > maxy) continue;\n        if (point_in_poly_axis(poly, px, py)) {\n            sc.diff += types[i];\n            if (types[i] == 1) ++sc.m;\n            else ++sc.s;\n        }\n    }\n    return sc;\n}\n\nbool better_shape(const ShapeAns &a, const ShapeAns &b) {\n    if (b.sc.diff == NEG_INF) return true;\n    if (a.sc.diff != b.sc.diff) return a.sc.diff > b.sc.diff;\n    if (a.sc.m != b.sc.m) return a.sc.m > b.sc.m;\n    if (a.sc.s != b.sc.s) return a.sc.s < b.sc.s;\n    return a.area2 < b.area2;\n}\n\nvoid consider_shape(const vector<pair<int,int>>& poly, const Score &sc) {\n    if (sc.diff == NEG_INF || poly.size() < 3) return;\n    long long area2 = polygon_area2(poly);\n    if (area2 <= 0) return;\n    ShapeAns cand{poly, sc, area2};\n    if (better_shape(cand, best_shape)) best_shape = cand;\n}\n\nvoid ensure_shape_from_rect(const RectAns &rect) {\n    if (rect.sc.diff == NEG_INF) return;\n    vector<pair<int,int>> poly;\n    add_vertex(poly, rect.x1, rect.y1);\n    add_vertex(poly, rect.x2, rect.y1);\n    add_vertex(poly, rect.x2, rect.y2);\n    add_vertex(poly, rect.x1, rect.y2);\n    consider_shape(poly, rect.sc);\n}\n\n// candidate gathering helpers\nvector<int> gather_candidates(const vector<int>& coords, int low, int high, int current) {\n    vector<int> cand;\n    if (low > high) return cand;\n    auto clampv = [&](int v) {\n        if (v < low) v = low;\n        if (v > high) v = high;\n        return v;\n    };\n    static const int OFFSETS[] = {-20000,-10000,-5000,-2500,-1200,-600,-300,-150,-70,-30,-12,-5,0,\n                                  5,12,30,70,150,300,600,1200,2500,5000,10000,20000};\n    cand.reserve(150);\n    cand.push_back(clampv(current));\n    for (int off : OFFSETS) cand.push_back(clampv(current + off));\n    cand.push_back(low);\n    cand.push_back(high);\n    if (!coords.empty()) {\n        auto itL = lower_bound(coords.begin(), coords.end(), low);\n        auto itR = upper_bound(coords.begin(), coords.end(), high);\n        int len = itR - itL;\n        if (len > 0) {\n            int step = max(1, len / 18);\n            for (int idx = 0; idx < len && (int)cand.size() < 160; idx += step) cand.push_back(*(itL + idx));\n            int random_samples = min(15, len);\n            for (int i = 0; i < random_samples; ++i) cand.push_back(*(itL + (rng() % len)));\n        }\n    }\n    if (high - low >= 1) {\n        for (int i = 0; i < 10; ++i) cand.push_back(low + (int)(rng() % (high - low + 1)));\n    }\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n    const int LIMIT = 80;\n    if ((int)cand.size() > LIMIT) {\n        vector<int> reduced;\n        reduced.reserve(LIMIT);\n        reduced.push_back(cand.front());\n        reduced.push_back(cand.back());\n        int cur = clampv(current);\n        auto it = lower_bound(cand.begin(), cand.end(), cur);\n        int pos = it - cand.begin();\n        for (int k = -4; k <= 4; ++k) {\n            int idx = pos + k;\n            if (idx >= 0 && idx < (int)cand.size()) reduced.push_back(cand[idx]);\n        }\n        while ((int)reduced.size() < LIMIT) reduced.push_back(cand[rng() % cand.size()]);\n        sort(reduced.begin(), reduced.end());\n        reduced.erase(unique(reduced.begin(), reduced.end()), reduced.end());\n        if ((int)reduced.size() > LIMIT) reduced.resize(LIMIT);\n        cand.swap(reduced);\n    }\n    return cand;\n}\n\nvector<int> limit_values(vector<int> cand, int limit) {\n    if ((int)cand.size() <= limit) return cand;\n    vector<int> res;\n    int step = max(1, (int)cand.size() / limit);\n    for (int i = 0; i < (int)cand.size() && (int)res.size() < limit; i += step) res.push_back(cand[i]);\n    while ((int)res.size() < limit) res.push_back(cand[rng() % cand.size()]);\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    if ((int)res.size() > limit) {\n        shuffle(res.begin(), res.end(), rng);\n        res.resize(limit);\n        sort(res.begin(), res.end());\n    }\n    return res;\n}\n\nvector<pair<int,int>> build_interval_candidates(const vector<int>& vals, int limit) {\n    vector<pair<int,int>> res;\n    int sz = vals.size();\n    if (sz < 2 || limit <= 0) return res;\n    vector<int> idxs;\n    idxs.push_back(0);\n    if (sz > 1) idxs.push_back(sz - 1);\n    int step = max(1, sz / 6);\n    for (int i = step; i < sz - 1 && (int)idxs.size() < 16; i += step) idxs.push_back(i);\n    sort(idxs.begin(), idxs.end());\n    idxs.erase(unique(idxs.begin(), idxs.end()), idxs.end());\n    auto add_pair = [&](int a, int b) {\n        if (a >= b) return;\n        res.emplace_back(a, b);\n    };\n    for (size_t i = 0; i < idxs.size(); ++i)\n        for (size_t j = i + 1; j < idxs.size(); ++j)\n            add_pair(vals[idxs[i]], vals[idxs[j]]);\n    int tries = 0;\n    while ((int)res.size() < limit && tries < limit * 8) {\n        ++tries;\n        int i = rng() % sz;\n        int j = rng() % sz;\n        if (i == j) continue;\n        if (i > j) swap(i, j);\n        add_pair(vals[i], vals[j]);\n    }\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    if ((int)res.size() > limit) {\n        shuffle(res.begin(), res.end(), rng);\n        res.resize(limit);\n        sort(res.begin(), res.end());\n    }\n    return res;\n}\n\n// boundary adjustments\nbool adjust_left(RectAns &rect) {\n    int low = 0;\n    int high = rect.x2 - 1;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(unique_x_vals, low, high, rect.x1);\n    RectAns best = rect;\n    bool improved = false;\n    for (int x1 : cand) {\n        if (x1 >= rect.x2) continue;\n        Score sc = compute_score(x1, rect.x2, rect.y1, rect.y2);\n        RectAns candRect{x1, rect.x2, rect.y1, rect.y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect);\n    }\n    return improved;\n}\n\nbool adjust_right(RectAns &rect) {\n    int low = rect.x1 + 1;\n    int high = MAX_COORD;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(unique_x_vals, low, high, rect.x2);\n    RectAns best = rect;\n    bool improved = false;\n    for (int x2 : cand) {\n        if (x2 <= rect.x1) continue;\n        Score sc = compute_score(rect.x1, x2, rect.y1, rect.y2);\n        RectAns candRect{rect.x1, x2, rect.y1, rect.y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect);\n    }\n    return improved;\n}\n\nbool adjust_bottom(RectAns &rect) {\n    int low = 0;\n    int high = rect.y2 - 1;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(unique_y_vals, low, high, rect.y1);\n    RectAns best = rect;\n    bool improved = false;\n    for (int y1 : cand) {\n        if (y1 >= rect.y2) continue;\n        Score sc = compute_score(rect.x1, rect.x2, y1, rect.y2);\n        RectAns candRect{rect.x1, rect.x2, y1, rect.y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect);\n    }\n    return improved;\n}\n\nbool adjust_top(RectAns &rect) {\n    int low = rect.y1 + 1;\n    int high = MAX_COORD;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(unique_y_vals, low, high, rect.y2);\n    RectAns best = rect;\n    bool improved = false;\n    for (int y2 : cand) {\n        if (y2 <= rect.y1) continue;\n        Score sc = compute_score(rect.x1, rect.x2, rect.y1, y2);\n        RectAns candRect{rect.x1, rect.x2, rect.y1, y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect);\n    }\n    return improved;\n}\n\nvoid refine_rectangle(RectAns rect, int cycles) {\n    if (rect.sc.diff == NEG_INF) rect.sc = compute_score(rect.x1, rect.x2, rect.y1, rect.y2);\n    RectAns current = rect;\n    for (int iter = 0; iter < cycles && elapsed() < TIME_LIMIT; ++iter) {\n        bool changed = false;\n        changed |= adjust_left(current);\n        if (elapsed() > TIME_LIMIT) break;\n        changed |= adjust_right(current);\n        if (elapsed() > TIME_LIMIT) break;\n        changed |= adjust_bottom(current);\n        if (elapsed() > TIME_LIMIT) break;\n        changed |= adjust_top(current);\n        if (!changed) break;\n    }\n}\n\nvoid refine_top_rects(int count, int cycles) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min(count, (int)seeds.size());\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        refine_rectangle(seeds[i], cycles);\n    }\n}\n\n// Heuristic rectangle generation\nvector<int> build_lines(const vector<int>& coords, int segments) {\n    vector<int> lines;\n    int extras = segments / 3 + 2;\n    lines.reserve(segments + extras + 4);\n    lines.push_back(0);\n    if (!coords.empty()) {\n        int size = coords.size();\n        for (int i = 1; i < segments; ++i) {\n            long long idx = 1LL * size * i / segments;\n            idx = min<long long>(idx, size - 1);\n            lines.push_back(coords[idx]);\n        }\n        uniform_int_distribution<int> dist(0, size - 1);\n        int extra = min(extras, size);\n        for (int i = 0; i < extra; ++i) lines.push_back(coords[dist(rng)]);\n    }\n    lines.push_back(MAX_COORD + 1);\n    sort(lines.begin(), lines.end());\n    lines.erase(unique(lines.begin(), lines.end()), lines.end());\n    if (lines.front() != 0) lines.insert(lines.begin(), 0);\n    if (lines.back() != MAX_COORD + 1) lines.push_back(MAX_COORD + 1);\n    return lines;\n}\n\nvoid grid_search(int segments, const vector<int>& sorted_x, const vector<int>& sorted_y) {\n    if (elapsed() > TIME_LIMIT) return;\n    auto lines_x = build_lines(sorted_x, segments);\n    auto lines_y = build_lines(sorted_y, segments);\n    int W = (int)lines_x.size() - 1;\n    int H = (int)lines_y.size() - 1;\n    if (W <= 0 || H <= 0) return;\n\n    vector<int> grid(W * H, 0);\n    for (size_t i = 0; i < xs.size(); ++i) {\n        int cx = upper_bound(lines_x.begin(), lines_x.end(), xs[i]) - lines_x.begin() - 1;\n        int cy = upper_bound(lines_y.begin(), lines_y.end(), ys[i]) - lines_y.begin() - 1;\n        cx = clamp(cx, 0, W - 1);\n        cy = clamp(cy, 0, H - 1);\n        grid[cy * W + cx] += types[i];\n    }\n\n    vector<int> arr(W, 0);\n    int best_sum = NEG_INF;\n    int best_top = 0, best_bottom = 0, best_left = 0, best_right = 0;\n    for (int top = 0; top < H; ++top) {\n        fill(arr.begin(), arr.end(), 0);\n        for (int bottom = top; bottom < H; ++bottom) {\n            int row_offset = bottom * W;\n            for (int col = 0; col < W; ++col) arr[col] += grid[row_offset + col];\n            int cur = 0, start = 0;\n            for (int col = 0; col < W; ++col) {\n                if (cur <= 0) {\n                    cur = arr[col];\n                    start = col;\n                } else {\n                    cur += arr[col];\n                }\n                if (cur > best_sum) {\n                    best_sum = cur;\n                    best_top = top;\n                    best_bottom = bottom;\n                    best_left = start;\n                    best_right = col;\n                }\n            }\n        }\n    }\n\n    auto convert = [&](int left, int right, int top, int bottom) {\n        int x1 = lines_x[left];\n        int x2 = lines_x[right + 1] - 1;\n        int y1 = lines_y[top];\n        int y2 = lines_y[bottom + 1] - 1;\n        consider_rect(x1, x2, y1, y2);\n    };\n\n    convert(best_left, best_right, best_top, best_bottom);\n\n    array<pair<int,int>,3> top_cells;\n    int filled = 0;\n    for (int idx = 0; idx < H * W; ++idx) {\n        int val = grid[idx];\n        if (filled < 3) {\n            top_cells[filled++] = {val, idx};\n        } else {\n            int pos = 0;\n            for (int j = 1; j < 3; ++j) if (top_cells[j].first < top_cells[pos].first) pos = j;\n            if (val > top_cells[pos].first) top_cells[pos] = {val, idx};\n        }\n    }\n    for (int i = 0; i < filled; ++i) {\n        int idx = top_cells[i].second;\n        int cy = idx / W;\n        int cx = idx % W;\n        for (int rad = 0; rad <= 1; ++rad) {\n            int left = max(0, cx - rad);\n            int right = min(W - 1, cx + rad);\n            int top = max(0, cy - rad);\n            int bottom = min(H - 1, cy + rad);\n            convert(left, right, top, bottom);\n        }\n    }\n}\n\nint sample_half_span() {\n    static const int options[] = {0, 20, 40, 80, 150, 250, 400, 600, 900, 1300, 1800,\n                                  2500, 3400, 4500, 6000, 8000, 10500, 13500, 17000,\n                                  21000, 26000, 32000, 39000, 47000};\n    static const int SZ = sizeof(options)/sizeof(int);\n    int base = options[rng() % SZ];\n    int extra_range = base / 3 + 1;\n    if (base == 0) extra_range = 60;\n    int extra = rng() % extra_range;\n    return base + extra;\n}\n\nint sample_span() {\n    static const pair<int,int> ranges[] = {\n        {1, 400}, {200, 1200}, {800, 3200}, {2000, 7000}, {5000, 15000},\n        {12000, 30000}, {25000, 50000}, {40000, 80000}, {70000, 100000}\n    };\n    static const int SZ = sizeof(ranges)/sizeof(ranges[0]);\n    auto [lo, hi] = ranges[rng() % SZ];\n    hi = min(hi, MAX_COORD);\n    lo = min(lo, hi);\n    int width = lo;\n    if (hi > lo) width += rng() % (hi - lo + 1);\n    return max(1, width);\n}\n\nvoid random_centered(int iterations) {\n    if (m_coords.empty()) return;\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        const auto &p = m_coords[dist(rng)];\n        int dx = sample_half_span();\n        int dy = sample_half_span();\n        consider_rect(p.first - dx, p.first + dx, p.second - dy, p.second + dy);\n    }\n}\n\nvoid random_global(int iterations) {\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int width = sample_span();\n        int height = sample_span();\n        int x1_max = max(0, MAX_COORD - width);\n        int y1_max = max(0, MAX_COORD - height);\n        int x1 = x1_max ? (int)(rng() % (x1_max + 1)) : 0;\n        int y1 = y1_max ? (int)(rng() % (y1_max + 1)) : 0;\n        consider_rect(x1, x1 + width, y1, y1 + height);\n    }\n}\n\nvoid random_pair_rects(int iterations) {\n    if (m_coords.empty()) return;\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        const auto &a = m_coords[dist(rng)];\n        const auto &b = m_coords[dist(rng)];\n        int x1 = min(a.first, b.first) - sample_half_span();\n        int x2 = max(a.first, b.first) + sample_half_span();\n        const auto &c = m_coords[dist(rng)];\n        const auto &d = m_coords[dist(rng)];\n        int y1 = min(c.second, d.second) - sample_half_span();\n        int y2 = max(c.second, d.second) + sample_half_span();\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_cluster_rects(int iterations) {\n    if (m_coords.empty()) return;\n    vector<int> cluster_sizes = {2,3,4,5,7,9,12,16};\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int k = cluster_sizes[rng() % cluster_sizes.size()];\n        k = min(k, (int)m_coords.size());\n        if (k == 0) break;\n        int minx = INT_MAX, miny = INT_MAX;\n        int maxx = INT_MIN, maxy = INT_MIN;\n        for (int j = 0; j < k; ++j) {\n            const auto &p = m_coords[rng() % m_coords.size()];\n            minx = min(minx, p.first);\n            maxx = max(maxx, p.first);\n            miny = min(miny, p.second);\n            maxy = max(maxy, p.second);\n        }\n        int marginx = sample_half_span();\n        int marginy = sample_half_span();\n        consider_rect(minx - marginx, maxx + marginx, miny - marginy, maxy + marginy);\n    }\n}\n\nvoid quantile_rects(int iterations, const vector<int>& sorted_x, const vector<int>& sorted_y) {\n    if (sorted_x.empty() || sorted_y.empty()) return;\n    uniform_int_distribution<int> dist_x(0, (int)sorted_x.size() - 1);\n    uniform_int_distribution<int> dist_y(0, (int)sorted_y.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int li = dist_x(rng);\n        int ri = dist_x(rng);\n        if (li > ri) swap(li, ri);\n        int marginx = sample_half_span() / 2 + rng() % 200;\n        int x1 = sorted_x[li] - marginx;\n        int x2 = sorted_x[ri] + marginx;\n        int lj = dist_y(rng);\n        int rj = dist_y(rng);\n        if (lj > rj) swap(lj, rj);\n        int marginy = sample_half_span() / 2 + rng() % 200;\n        int y1 = sorted_y[lj] - marginy;\n        int y2 = sorted_y[rj] + marginy;\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid slender_rects(int iterations) {\n    if (m_coords.empty()) return;\n    static const int widths[] = {150, 300, 600, 1000, 1600, 2500, 4000, 6000, 9000};\n    static const int SZ = sizeof(widths)/sizeof(widths[0]);\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        bool vertical = (rng() & 1);\n        const auto &center = m_coords[dist(rng)];\n        int span = widths[rng() % SZ];\n        int half = span / 2;\n        if (vertical) {\n            int x1 = center.first - half;\n            int x2 = center.first + half;\n            int height = sample_span();\n            int y_mid = rng() % (MAX_COORD + 1);\n            int y1 = y_mid - height / 2;\n            int y2 = y1 + height;\n            consider_rect(x1, x2, y1, y2);\n        } else {\n            int y1 = center.second - half;\n            int y2 = center.second + half;\n            int width = sample_span();\n            int x_mid = rng() % (MAX_COORD + 1);\n            int x1 = x_mid - width / 2;\n            int x2 = x1 + width;\n            consider_rect(x1, x2, y1, y2);\n        }\n    }\n}\n\nconst int BIG_PERTURB[] = {5, 15, 30, 60, 120, 250, 400, 700, 1100, 1700,\n                           2500, 3600, 5000, 7500, 10000, 13500, 17000};\nconst int SMALL_PERTURB[] = {2,4,8,16,32,64,128,256,512,1024,2048,3072,4096};\nconst int BIG_PSZ = sizeof(BIG_PERTURB)/sizeof(int);\nconst int SMALL_PSZ = sizeof(SMALL_PERTURB)/sizeof(int);\nconst int LOCAL_STEPS[] = {1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946};\nconst int LOCAL_SZ = sizeof(LOCAL_STEPS)/sizeof(int);\n\nvoid random_perturb_rect(const RectAns &base, int iterations, const int *options, int opt_sz) {\n    if (base.sc.diff == NEG_INF) return;\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int delta = options[rng() % opt_sz];\n        int x1 = base.x1 - (int)(rng() % (delta + 1));\n        int x2 = base.x2 + (int)(rng() % (delta + 1));\n        int y1 = base.y1 - (int)(rng() % (delta + 1));\n        int y2 = base.y2 + (int)(rng() % (delta + 1));\n        int shiftx = delta ? (int)(rng() % (2 * delta + 1)) - delta : 0;\n        int shifty = delta ? (int)(rng() % (2 * delta + 1)) - delta : 0;\n        x1 += shiftx; x2 += shiftx;\n        y1 += shifty; y2 += shifty;\n        if (rng() & 1) x1 += rng() % (delta + 1);\n        if (rng() & 1) x2 -= rng() % (delta + 1);\n        if (rng() & 1) y1 += rng() % (delta + 1);\n        if (rng() & 1) y2 -= rng() % (delta + 1);\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_perturb_best(int iterations) {\n    random_perturb_rect(best_rect, iterations, BIG_PERTURB, BIG_PSZ);\n}\n\nvoid random_around_top_rects(int iterations_each) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min<int>(seeds.size(), 6);\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        random_perturb_rect(seeds[i], iterations_each, SMALL_PERTURB, SMALL_PSZ);\n    }\n}\n\nvoid local_search_from(const RectAns &seed, int iterations) {\n    if (seed.sc.diff == NEG_INF) return;\n    RectAns current = seed;\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int step = LOCAL_STEPS[rng() % LOCAL_SZ];\n        int op = rng() % 12;\n        int x1 = current.x1;\n        int x2 = current.x2;\n        int y1 = current.y1;\n        int y2 = current.y2;\n        switch (op) {\n            case 0: x1 -= step; break;\n            case 1: x1 += step; break;\n            case 2: x2 += step; break;\n            case 3: x2 -= step; break;\n            case 4: y1 -= step; break;\n            case 5: y1 += step; break;\n            case 6: y2 += step; break;\n            case 7: y2 -= step; break;\n            case 8: { int shift = (int)(rng() % (2 * step + 1)) - step; x1 += shift; x2 += shift; break; }\n            case 9: { int shift = (int)(rng() % (2 * step + 1)) - step; y1 += shift; y2 += shift; break; }\n            case 10: x1 -= step; x2 += step; break;\n            case 11: y1 -= step; y2 += step; break;\n        }\n        if (!normalize_rect(x1,x2,y1,y2)) continue;\n        Score sc = compute_score(x1,x2,y1,y2);\n        RectAns cand{x1,x2,y1,y2,sc};\n        push_candidate(cand);\n        if (better_rect(cand, current)) current = cand;\n        if ((it & 63) == 63 && better_rect(best_rect, current)) current = best_rect;\n    }\n}\n\nvoid run_local_search_pool(int iterations_per_seed) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min<int>(seeds.size(), 4);\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        local_search_from(seeds[i], iterations_per_seed);\n    }\n}\n\n// notch generation\nvoid attempt_top_notch(const RectAns& base, int limit_attempts) {\n    if (elapsed() > TIME_LIMIT) return;\n    if (base.y2 - base.y1 < 2) return;\n    auto candX = limit_values(gather_candidates(unique_x_vals, base.x1 + 1, base.x2 - 1, (base.x1 + base.x2) / 2), 40);\n    auto candY = limit_values(gather_candidates(unique_y_vals, base.y1 + 1, base.y2 - 1, base.y2 - (base.y2 - base.y1) / 4), 30);\n    auto intervals = build_interval_candidates(candX, 60);\n    if (intervals.empty() || candY.empty()) return;\n    int attempts = 0, guard = 0;\n    while (attempts < limit_attempts && guard < limit_attempts * 6 && elapsed() < TIME_LIMIT) {\n        ++guard;\n        auto interval = intervals[rng() % intervals.size()];\n        int ycut = candY[rng() % candY.size()];\n        int lx = interval.first;\n        int rx = interval.second;\n        if (!(base.x1 < lx && rx < base.x2)) continue;\n        if (ycut <= base.y1 || ycut >= base.y2) continue;\n        vector<pair<int,int>> poly;\n        add_vertex(poly, base.x1, base.y1);\n        add_vertex(poly, base.x2, base.y1);\n        add_vertex(poly, base.x2, base.y2);\n        add_vertex(poly, rx, base.y2);\n        add_vertex(poly, rx, ycut);\n        add_vertex(poly, lx, ycut);\n        add_vertex(poly, lx, base.y2);\n        add_vertex(poly, base.x1, base.y2);\n        Score sc = evaluate_polygon_points(poly);\n        consider_shape(poly, sc);\n        ++attempts;\n    }\n}\n\nvoid attempt_bottom_notch(const RectAns& base, int limit_attempts) {\n    if (elapsed() > TIME_LIMIT) return;\n    if (base.y2 - base.y1 < 2) return;\n    auto candX = limit_values(gather_candidates(unique_x_vals, base.x1 + 1, base.x2 - 1, (base.x1 + base.x2) / 2), 40);\n    auto candY = limit_values(gather_candidates(unique_y_vals, base.y1 + 1, base.y2 - 1, base.y1 + (base.y2 - base.y1) / 4), 30);\n    auto intervals = build_interval_candidates(candX, 60);\n    if (intervals.empty() || candY.empty()) return;\n    int attempts = 0, guard = 0;\n    while (attempts < limit_attempts && guard < limit_attempts * 6 && elapsed() < TIME_LIMIT) {\n        ++guard;\n        auto interval = intervals[rng() % intervals.size()];\n        int ycut = candY[rng() % candY.size()];\n        int lx = interval.first;\n        int rx = interval.second;\n        if (!(base.x1 < lx && rx < base.x2)) continue;\n        if (ycut <= base.y1 || ycut >= base.y2) continue;\n        vector<pair<int,int>> poly;\n        add_vertex(poly, base.x1, base.y1);\n        add_vertex(poly, lx, base.y1);\n        add_vertex(poly, lx, ycut);\n        add_vertex(poly, rx, ycut);\n        add_vertex(poly, rx, base.y1);\n        add_vertex(poly, base.x2, base.y1);\n        add_vertex(poly, base.x2, base.y2);\n        add_vertex(poly, base.x1, base.y2);\n        Score sc = evaluate_polygon_points(poly);\n        consider_shape(poly, sc);\n        ++attempts;\n    }\n}\n\nvoid attempt_left_notch(const RectAns& base, int limit_attempts) {\n    if (elapsed() > TIME_LIMIT) return;\n    if (base.x2 - base.x1 < 2) return;\n    auto candCut = limit_values(gather_candidates(unique_x_vals, base.x1 + 1, base.x2 - 1, base.x1 + (base.x2 - base.x1) / 4), 40);\n    auto candY = limit_values(gather_candidates(unique_y_vals, base.y1 + 1, base.y2 - 1, (base.y1 + base.y2) / 2), 40);\n    auto intervalsY = build_interval_candidates(candY, 60);\n    if (candCut.empty() || intervalsY.empty()) return;\n    int attempts = 0, guard = 0;\n    while (attempts < limit_attempts && guard < limit_attempts * 6 && elapsed() < TIME_LIMIT) {\n        ++guard;\n        int xcut = candCut[rng() % candCut.size()];\n        auto interval = intervalsY[rng() % intervalsY.size()];\n        int ly = interval.first;\n        int ry = interval.second;\n        if (!(base.x1 < xcut && xcut < base.x2)) continue;\n        if (!(base.y1 < ly && ry < base.y2)) continue;\n        vector<pair<int,int>> poly;\n        add_vertex(poly, base.x1, base.y1);\n        add_vertex(poly, base.x2, base.y1);\n        add_vertex(poly, base.x2, base.y2);\n        add_vertex(poly, base.x1, base.y2);\n        add_vertex(poly, base.x1, ry);\n        add_vertex(poly, xcut, ry);\n        add_vertex(poly, xcut, ly);\n        add_vertex(poly, base.x1, ly);\n        Score sc = evaluate_polygon_points(poly);\n        consider_shape(poly, sc);\n        ++attempts;\n    }\n}\n\nvoid attempt_right_notch(const RectAns& base, int limit_attempts) {\n    if (elapsed() > TIME_LIMIT) return;\n    if (base.x2 - base.x1 < 2) return;\n    auto candCut = limit_values(gather_candidates(unique_x_vals, base.x1 + 1, base.x2 - 1, base.x2 - (base.x2 - base.x1) / 4), 40);\n    auto candY = limit_values(gather_candidates(unique_y_vals, base.y1 + 1, base.y2 - 1, (base.y1 + base.y2) / 2), 40);\n    auto intervalsY = build_interval_candidates(candY, 60);\n    if (candCut.empty() || intervalsY.empty()) return;\n    int attempts = 0, guard = 0;\n    while (attempts < limit_attempts && guard < limit_attempts * 6 && elapsed() < TIME_LIMIT) {\n        ++guard;\n        int xcut = candCut[rng() % candCut.size()];\n        auto interval = intervalsY[rng() % intervalsY.size()];\n        int ly = interval.first;\n        int ry = interval.second;\n        if (!(base.x1 < xcut && xcut < base.x2)) continue;\n        if (!(base.y1 < ly && ry < base.y2)) continue;\n        vector<pair<int,int>> poly;\n        add_vertex(poly, base.x1, base.y1);\n        add_vertex(poly, base.x2, base.y1);\n        add_vertex(poly, base.x2, ly);\n        add_vertex(poly, xcut, ly);\n        add_vertex(poly, xcut, ry);\n        add_vertex(poly, base.x2, ry);\n        add_vertex(poly, base.x2, base.y2);\n        add_vertex(poly, base.x1, base.y2);\n        Score sc = evaluate_polygon_points(poly);\n        consider_shape(poly, sc);\n        ++attempts;\n    }\n}\n\nvoid notch_on_rect(const RectAns& base) {\n    if (base.sc.diff == NEG_INF || elapsed() > TIME_LIMIT) return;\n    const int LIMIT_SIDE = 70;\n    attempt_top_notch(base, LIMIT_SIDE);\n    if (elapsed() > TIME_LIMIT) return;\n    attempt_bottom_notch(base, LIMIT_SIDE);\n    if (elapsed() > TIME_LIMIT) return;\n    attempt_left_notch(base, LIMIT_SIDE);\n    if (elapsed() > TIME_LIMIT) return;\n    attempt_right_notch(base, LIMIT_SIDE);\n}\n\nvoid try_notch_improvements() {\n    if (elapsed() > TIME_LIMIT) return;\n    vector<RectAns> seeds = top_rects;\n    if (seeds.empty() && best_rect.sc.diff != NEG_INF) seeds.push_back(best_rect);\n    int limit = min<int>(6, seeds.size());\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        notch_on_rect(seeds[i]);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    start_time = chrono::steady_clock::now();\n\n    cin >> N;\n    xs.reserve(2 * N);\n    ys.reserve(2 * N);\n    types.reserve(2 * N);\n    m_coords.reserve(N);\n\n    for (int i = 0; i < N; ++i) {\n        int x,y; cin >> x >> y;\n        xs.push_back(x); ys.push_back(y); types.push_back(1);\n        m_coords.emplace_back(x,y);\n    }\n    for (int i = 0; i < N; ++i) {\n        int x,y; cin >> x >> y;\n        xs.push_back(x); ys.push_back(y); types.push_back(-1);\n    }\n\n    vector<int> sorted_x = xs;\n    vector<int> sorted_y = ys;\n    sort(sorted_x.begin(), sorted_x.end());\n    sort(sorted_y.begin(), sorted_y.end());\n    unique_x_vals = sorted_x;\n    unique_y_vals = sorted_y;\n    unique_x_vals.erase(unique(unique_x_vals.begin(), unique_x_vals.end()), unique_x_vals.end());\n    unique_y_vals.erase(unique(unique_y_vals.begin(), unique_y_vals.end()), unique_y_vals.end());\n\n    bit2d.build(xs, ys, types);\n    best_rect.sc.diff = NEG_INF;\n    best_shape.sc.diff = NEG_INF;\n    top_rects.clear();\n\n    // Basic rectangles\n    consider_rect(0, MAX_COORD, 0, MAX_COORD);\n    int half = MAX_COORD / 2;\n    consider_rect(0, half, 0, half);\n    consider_rect(half, MAX_COORD, 0, half);\n    consider_rect(0, half, half, MAX_COORD);\n    consider_rect(half, MAX_COORD, half, MAX_COORD);\n    consider_rect(MAX_COORD/4, 3*MAX_COORD/4, MAX_COORD/4, 3*MAX_COORD/4);\n\n    // Grid searches\n    vector<int> segments = {12, 18, 26, 35, 48, 64, 85, 110, 140};\n    for (int seg : segments) {\n        if (elapsed() > TIME_LIMIT) break;\n        grid_search(seg, sorted_x, sorted_y);\n    }\n\n    // Heuristic sampling and refinement pipeline\n    random_centered(2200);\n    random_pair_rects(1800);\n    random_cluster_rects(1200);\n    random_global(1500);\n    quantile_rects(1400, sorted_x, sorted_y);\n    slender_rects(1000);\n    random_centered(600);\n    random_perturb_best(2000);\n    random_around_top_rects(400);\n    run_local_search_pool(360);\n    refine_top_rects(6, 11);\n    random_around_top_rects(250);\n    random_perturb_best(800);\n    run_local_search_pool(240);\n    refine_top_rects(4, 9);\n\n    if (best_rect.sc.diff == NEG_INF) {\n        consider_rect(0, MAX_COORD, 0, MAX_COORD);\n    }\n\n    ensure_shape_from_rect(best_rect);\n    try_notch_improvements();\n    if (best_shape.sc.diff == NEG_INF) ensure_shape_from_rect(best_rect);\n    if (best_shape.sc.diff == NEG_INF) {\n        vector<pair<int,int>> fallback = {{0,0}, {MAX_COORD,0}, {MAX_COORD,MAX_COORD}, {0,MAX_COORD}};\n        Score sc = evaluate_polygon_points(fallback);\n        consider_shape(fallback, sc);\n    }\n\n    const auto &poly = best_shape.poly;\n    int m = poly.size();\n    cout << m << '\\n';\n    for (const auto &p : poly) {\n        cout << p.first << ' ' << p.second << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst long long INFLL = (long long)4e18;\n\nstruct Profile {\n    vector<long long> widths;\n    vector<long long> heights; // non-increasing\n};\n\nstruct Solution {\n    vector<int> orientation;\n    vector<int> column_id;\n    vector<long long> column_widths;\n    vector<long long> column_heights;\n    vector<int> anchor;\n    vector<int> idx_max_width;\n    vector<pair<int,int>> ranges;\n    long long total_width = 0;\n    long long total_height = 0;\n    long long score = INFLL;\n};\n\nstruct DPState {\n    long long width_sum;\n    long long max_height;\n    int prev_idx;\n    int prev_state;\n    int block_end;\n    int choice_idx;\n    uint32_t tiebreak;\n};\n\nuint64_t hash_solution(const Solution &sol) {\n    uint64_t h = 1469598103934665603ULL;\n    const uint64_t prime = 1099511628211ULL;\n    int N = sol.orientation.size();\n    for (int i = 0; i < N; ++i) {\n        uint64_t val = (uint64_t)(sol.orientation[i] & 1);\n        val |= (uint64_t)(sol.column_id[i] & 0xFFFF) << 1;\n        h ^= val;\n        h *= prime;\n    }\n    return h;\n}\n\nstruct ColumnPackingSolver {\n    int N = 0;\n    vector<long long> w, h;\n    vector<array<long long,2>> widthOpt, heightOpt;\n    vector<long long> minHeight, maxHeight;\n    long long H_lower = 0;\n    long long H_upper = 0;\n    long long total_min_height = 0;\n    vector<vector<Profile>> profiles;\n\n    void init(const vector<long long>& W, const vector<long long>& H) {\n        w = W; h = H;\n        N = (int)w.size();\n        widthOpt.assign(N, {0,0});\n        heightOpt.assign(N, {0,0});\n        minHeight.resize(N);\n        maxHeight.resize(N);\n        total_min_height = 0;\n        H_lower = 0;\n        H_upper = 0;\n        for (int i = 0; i < N; ++i) {\n            widthOpt[i][0] = w[i];\n            heightOpt[i][0] = h[i];\n            widthOpt[i][1] = h[i];\n            heightOpt[i][1] = w[i];\n            minHeight[i] = min(heightOpt[i][0], heightOpt[i][1]);\n            maxHeight[i] = max(heightOpt[i][0], heightOpt[i][1]);\n            total_min_height += minHeight[i];\n            H_lower = max(H_lower, minHeight[i]);\n            H_upper += maxHeight[i];\n        }\n        if (H_upper < H_lower) H_upper = H_lower;\n        build_profiles();\n    }\n\n    long long lower() const { return H_lower; }\n    long long upper() const { return H_upper; }\n    long long minHeightSum() const { return total_min_height; }\n\n    void build_profiles() {\n        const int PROFILE_LIMIT = 80;\n        profiles.assign(N + 1, vector<Profile>(N + 1));\n        for (int l = 0; l < N; ++l) {\n            for (int r = l + 1; r <= N; ++r) {\n                vector<long long> widths;\n                widths.reserve(2 * (r - l));\n                for (int k = l; k < r; ++k) {\n                    widths.push_back(widthOpt[k][0]);\n                    widths.push_back(widthOpt[k][1]);\n                }\n                sort(widths.begin(), widths.end());\n                widths.erase(unique(widths.begin(), widths.end()), widths.end());\n                vector<long long> heights(widths.size(), INFLL);\n                for (size_t idx = 0; idx < widths.size(); ++idx) {\n                    long long limit = widths[idx];\n                    long long sumH = 0;\n                    bool ok = true;\n                    for (int k = l; k < r; ++k) {\n                        long long best = INFLL;\n                        if (widthOpt[k][0] <= limit) best = min(best, heightOpt[k][0]);\n                        if (widthOpt[k][1] <= limit) best = min(best, heightOpt[k][1]);\n                        if (best >= INFLL/2) { ok = false; break; }\n                        sumH += best;\n                    }\n                    if (ok) heights[idx] = sumH;\n                }\n                long long last = INFLL;\n                for (size_t idx = 0; idx < heights.size(); ++idx) {\n                    if (heights[idx] < last) last = heights[idx];\n                    else heights[idx] = last;\n                }\n                if ((int)widths.size() > PROFILE_LIMIT) {\n                    vector<long long> newW, newH;\n                    newW.reserve(PROFILE_LIMIT);\n                    newH.reserve(PROFILE_LIMIT);\n                    for (int i = 0; i < PROFILE_LIMIT; ++i) {\n                        int idx = (int)llround((long double)i * (widths.size() - 1) / (PROFILE_LIMIT - 1));\n                        newW.push_back(widths[idx]);\n                        newH.push_back(heights[idx]);\n                    }\n                    for (int i = 1; i < (int)newH.size(); ++i)\n                        newH[i] = min(newH[i], newH[i-1]);\n                    widths.swap(newW);\n                    heights.swap(newH);\n                }\n                profiles[l][r] = Profile{move(widths), move(heights)};\n            }\n        }\n    }\n\n    long long min_width_for_height(int l, int r, long long Hmax) const {\n        const Profile &prof = profiles[l][r];\n        if (prof.heights.empty()) return INFLL;\n        const auto &hv = prof.heights;\n        int lo = 0, hi = (int)hv.size();\n        while (lo < hi) {\n            int mid = (lo + hi) / 2;\n            if (hv[mid] <= Hmax) hi = mid;\n            else lo = mid + 1;\n        }\n        if (lo >= (int)hv.size()) return INFLL;\n        return prof.widths[lo];\n    }\n\n    int choose_orientation(int idx, long long width_limit) const {\n        int best = -1;\n        long long best_h = INFLL;\n        long long best_w = INFLL;\n        for (int o = 0; o < 2; ++o) {\n            if (widthOpt[idx][o] <= width_limit) {\n                long long hval = heightOpt[idx][o];\n                long long wval = widthOpt[idx][o];\n                if (best == -1 || hval < best_h || (hval == best_h && wval < best_w)) {\n                    best = o;\n                    best_h = hval;\n                    best_w = wval;\n                }\n            }\n        }\n        if (best == -1) best = (heightOpt[idx][0] <= heightOpt[idx][1]) ? 0 : 1;\n        return best;\n    }\n\n    vector<long long> generate_candidate_heights(mt19937 &rng, int limit) const {\n        limit = max(limit, 2);\n        vector<long long> cand;\n        auto clampH = [&](long long v) {\n            if (v < H_lower) v = H_lower;\n            if (v > H_upper) v = H_upper;\n            return v;\n        };\n        auto add = [&](long long v) {\n            cand.push_back(clampH(v));\n        };\n\n        add(H_lower);\n        add(H_upper);\n        add(total_min_height);\n        add((H_lower + H_upper) / 2);\n\n        vector<double> fudge = {0.65, 0.75, 0.85, 0.95, 1.0, 1.05, 1.15, 1.3, 1.5};\n        int maxCols = min(N, 60);\n        for (int c = 1; c <= maxCols; ++c) {\n            double base = (double)total_min_height / max(1, c);\n            for (double f : fudge) add((long long)llround(base * f));\n        }\n\n        long double val = (long double)H_lower;\n        for (int i = 0; i < 100 && val <= (long double)H_upper; ++i) {\n            add((long long)llround(val));\n            val *= 1.05L;\n            if (val > (long double)H_upper * 1.01L) break;\n        }\n\n        if (H_upper > H_lower) {\n            int linearCnt = min(limit, 200);\n            for (int i = 0; i < linearCnt; ++i) {\n                long double ratio = (long double)i / max(1, linearCnt - 1);\n                add((long long)llround(H_lower + ratio * (H_upper - H_lower)));\n            }\n            uniform_int_distribution<long long> dist(H_lower, H_upper);\n            int randomSamples = min(limit, 200);\n            for (int i = 0; i < randomSamples; ++i) add(dist(rng));\n        }\n\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n        if ((int)cand.size() > limit) {\n            vector<long long> reduced;\n            reduced.reserve(limit);\n            for (int i = 0; i < limit; ++i) {\n                size_t idx = (size_t)llround((long double)i * (cand.size() - 1) / max(1, limit - 1));\n                reduced.push_back(cand[idx]);\n            }\n            sort(reduced.begin(), reduced.end());\n            reduced.erase(unique(reduced.begin(), reduced.end()), reduced.end());\n            cand.swap(reduced);\n        }\n        if (cand.empty()) cand.push_back(H_lower);\n        return cand;\n    }\n\n    bool build_height_solution(long long Hmax, Solution &sol, mt19937 &rng) const {\n        vector<long long> dp(N + 1, INFLL);\n        vector<int> prv(N + 1, -1);\n        vector<long long> width_choice(N + 1, -1);\n        vector<uint32_t> jitter(N + 1);\n        vector<uint32_t> best_jitter(N + 1, UINT_MAX);\n        for (int i = 0; i <= N; ++i) jitter[i] = rng();\n        dp[0] = 0;\n        best_jitter[0] = jitter[0];\n\n        for (int i = 1; i <= N; ++i) {\n            for (int j = 0; j < i; ++j) {\n                if (dp[j] >= INFLL/2) continue;\n                long long width = min_width_for_height(j, i, Hmax);\n                if (width >= INFLL/2) continue;\n                long long cand = dp[j] + width;\n                if (cand < dp[i] || (cand == dp[i] && jitter[j] < best_jitter[i])) {\n                    dp[i] = cand;\n                    prv[i] = j;\n                    width_choice[i] = width;\n                    best_jitter[i] = jitter[j];\n                }\n            }\n        }\n        if (dp[N] >= INFLL/2) return false;\n\n        vector<int> cuts;\n        int cur = N;\n        while (cur > 0) {\n            cuts.push_back(cur);\n            cur = prv[cur];\n            if (cur < 0) return false;\n        }\n        cuts.push_back(0);\n        reverse(cuts.begin(), cuts.end());\n        int cols = (int)cuts.size() - 1;\n\n        sol.orientation.assign(N, 0);\n        sol.column_id.assign(N, 0);\n        sol.column_widths.assign(cols, 0);\n        sol.column_heights.assign(cols, 0);\n        sol.anchor.assign(cols, -1);\n        sol.idx_max_width.assign(cols, -1);\n        sol.ranges.resize(cols);\n\n        for (int c = 0; c < cols; ++c) {\n            int l = cuts[c];\n            int r = cuts[c + 1];\n            long long width_limit = width_choice[r];\n            long long sumH = 0;\n            long long maxW = 0;\n            int idxMax = l;\n            for (int k = l; k < r; ++k) {\n                int orient = choose_orientation(k, width_limit);\n                sol.orientation[k] = orient;\n                sol.column_id[k] = c;\n                long long wval = widthOpt[k][orient];\n                long long hval = heightOpt[k][orient];\n                sumH += hval;\n                if (wval > maxW || (wval == maxW && k < idxMax)) {\n                    maxW = wval;\n                    idxMax = k;\n                }\n            }\n            if (maxW < width_limit) maxW = width_limit;\n            sol.column_widths[c] = maxW;\n            sol.column_heights[c] = sumH;\n            sol.idx_max_width[c] = idxMax;\n            sol.ranges[c] = {l, r};\n            sol.anchor[c] = (c == 0) ? -1 : sol.idx_max_width[c - 1];\n        }\n\n        long long total_w = 0;\n        long long total_h = 0;\n        for (auto wcol : sol.column_widths) total_w += wcol;\n        for (auto hcol : sol.column_heights) total_h = max(total_h, hcol);\n        sol.total_width = total_w;\n        sol.total_height = total_h;\n        sol.score = total_w + total_h;\n        return true;\n    }\n};\n\nvoid prune_states(vector<DPState> &states, int limit) {\n    if (states.empty()) return;\n    sort(states.begin(), states.end(), [](const DPState &a, const DPState &b){\n        if (a.width_sum != b.width_sum) return a.width_sum < b.width_sum;\n        if (a.max_height != b.max_height) return a.max_height < b.max_height;\n        return a.tiebreak < b.tiebreak;\n    });\n    vector<DPState> pareto;\n    pareto.reserve(states.size());\n    long long best_height = INFLL;\n    for (const auto &st : states) {\n        if (st.max_height < best_height) {\n            pareto.push_back(st);\n            best_height = st.max_height;\n        }\n    }\n    if ((int)pareto.size() > limit) {\n        sort(pareto.begin(), pareto.end(), [](const DPState &a, const DPState &b){\n            long long sa = a.width_sum + a.max_height;\n            long long sb = b.width_sum + b.max_height;\n            if (sa != sb) return sa < sb;\n            if (a.width_sum != b.width_sum) return a.width_sum < b.width_sum;\n            if (a.max_height != b.max_height) return a.max_height < b.max_height;\n            return a.tiebreak < b.tiebreak;\n        });\n        pareto.resize(limit);\n        sort(pareto.begin(), pareto.end(), [](const DPState &a, const DPState &b){\n            if (a.width_sum != b.width_sum) return a.width_sum < b.width_sum;\n            if (a.max_height != b.max_height) return a.max_height < b.max_height;\n            return a.tiebreak < b.tiebreak;\n        });\n    }\n    states.swap(pareto);\n}\n\nSolution reconstruct_solution(const vector<vector<DPState>> &dp, int final_idx, const ColumnPackingSolver &solver) {\n    int N = solver.N;\n    vector<int> starts, ends, choices;\n    int cur_idx = final_idx;\n    int cur_pos = N;\n    while (cur_pos > 0) {\n        const DPState &st = dp[cur_pos][cur_idx];\n        starts.push_back(st.prev_idx);\n        ends.push_back(cur_pos);\n        choices.push_back(st.choice_idx);\n        cur_idx = st.prev_state;\n        cur_pos = st.prev_idx;\n        if (cur_pos < 0) break;\n    }\n    reverse(starts.begin(), starts.end());\n    reverse(ends.begin(), ends.end());\n    reverse(choices.begin(), choices.end());\n    int cols = starts.size();\n    Solution sol;\n    sol.orientation.assign(N, 0);\n    sol.column_id.assign(N, 0);\n    sol.column_widths.assign(cols, 0);\n    sol.column_heights.assign(cols, 0);\n    sol.anchor.assign(cols, -1);\n    sol.idx_max_width.assign(cols, -1);\n    sol.ranges.resize(cols);\n\n    for (int c = 0; c < cols; ++c) {\n        int l = starts[c];\n        int r = ends[c];\n        int choice = choices[c];\n        const Profile &prof = solver.profiles[l][r];\n        long long width_limit = prof.widths[choice];\n        long long sumH = 0;\n        long long maxW = 0;\n        int idxMax = l;\n        for (int k = l; k < r; ++k) {\n            int orient = solver.choose_orientation(k, width_limit);\n            sol.orientation[k] = orient;\n            sol.column_id[k] = c;\n            long long wval = solver.widthOpt[k][orient];\n            long long hval = solver.heightOpt[k][orient];\n            sumH += hval;\n            if (wval > maxW || (wval == maxW && k < idxMax)) {\n                maxW = wval;\n                idxMax = k;\n            }\n        }\n        sol.column_widths[c] = maxW;\n        sol.column_heights[c] = sumH;\n        sol.idx_max_width[c] = idxMax;\n        sol.ranges[c] = {l, r};\n        sol.anchor[c] = (c == 0) ? -1 : sol.idx_max_width[c - 1];\n    }\n\n    long long total_w = 0;\n    long long total_h = 0;\n    for (auto wcol : sol.column_widths) total_w += wcol;\n    for (auto hcol : sol.column_heights) total_h = max(total_h, hcol);\n    sol.total_width = total_w;\n    sol.total_height = total_h;\n    sol.score = total_w + total_h;\n    return sol;\n}\n\nSolution build_row_solution(const ColumnPackingSolver &solver) {\n    int N = solver.N;\n    Solution sol;\n    sol.orientation.assign(N, 0);\n    sol.column_id.assign(N, 0);\n    sol.column_widths.assign(N, 0);\n    sol.column_heights.assign(N, 0);\n    sol.anchor.assign(N, -1);\n    sol.idx_max_width.resize(N);\n    sol.ranges.resize(N);\n    for (int i = 0; i < N; ++i) {\n        int best = 0;\n        if (solver.widthOpt[i][1] < solver.widthOpt[i][0]) best = 1;\n        else if (solver.widthOpt[i][1] == solver.widthOpt[i][0] && solver.heightOpt[i][1] < solver.heightOpt[i][0]) best = 1;\n        sol.orientation[i] = best;\n        sol.column_id[i] = i;\n        sol.column_widths[i] = solver.widthOpt[i][best];\n        sol.column_heights[i] = solver.heightOpt[i][best];\n        sol.idx_max_width[i] = i;\n        sol.anchor[i] = (i == 0) ? -1 : i - 1;\n        sol.ranges[i] = {i, i + 1};\n    }\n    long long total_w = accumulate(sol.column_widths.begin(), sol.column_widths.end(), 0LL);\n    long long total_h = 0;\n    for (auto hv : sol.column_heights) total_h = max(total_h, hv);\n    sol.total_width = total_w;\n    sol.total_height = total_h;\n    sol.score = total_w + total_h;\n    return sol;\n}\n\nvoid postprocess_solution(Solution &sol) {\n    int cols = sol.column_widths.size();\n    if (cols <= 1) return;\n    for (int c = 0; c + 1 < cols; ++c) {\n        long long w1 = sol.total_width - sol.column_widths[c];\n        long long w2 = sol.total_width - sol.column_widths[c + 1];\n        long long candidate = max(sol.column_heights[c], sol.column_heights[c + 1]);\n        long long combinedHeight = sol.column_heights[c] + sol.column_heights[c + 1];\n        if (combinedHeight < candidate && sol.column_widths[c] == sol.column_widths[c + 1]) {\n            sol.column_heights[c] = combinedHeight;\n            sol.column_widths[c + 1] = sol.column_widths[c];\n            sol.anchor[c + 1] = sol.idx_max_width[c];\n        }\n    }\n    long long total_w = 0;\n    long long total_h = 0;\n    for (auto wv : sol.column_widths) total_w += wv;\n    for (auto hv : sol.column_heights) total_h = max(total_h, hv);\n    sol.total_width = total_w;\n    sol.total_height = total_h;\n    sol.score = total_w + total_h;\n}\n\ntemplate <class AddFunc>\nvoid run_trial(const ColumnPackingSolver &solver, mt19937 &rng, int state_limit,\n               int take_top, int take_rand, AddFunc add_solution) {\n    int N = solver.N;\n    vector<vector<DPState>> dp(N + 1);\n    DPState init;\n    init.width_sum = 0;\n    init.max_height = 0;\n    init.prev_idx = -1;\n    init.prev_state = -1;\n    init.block_end = 0;\n    init.choice_idx = -1;\n    init.tiebreak = rng();\n    dp[0].push_back(init);\n\n    for (int i = 1; i <= N; ++i) {\n        vector<DPState> cand;\n        for (int j = 0; j < i; ++j) {\n            if (dp[j].empty()) continue;\n            const Profile &prof = solver.profiles[j][i];\n            if (prof.widths.empty()) continue;\n            for (int sid = 0; sid < (int)dp[j].size(); ++sid) {\n                const DPState &st = dp[j][sid];\n                for (int k = 0; k < (int)prof.widths.size(); ++k) {\n                    long long height = prof.heights[k];\n                    if (height >= INFLL/2) continue;\n                    DPState ns;\n                    ns.width_sum = st.width_sum + prof.widths[k];\n                    ns.max_height = max(st.max_height, height);\n                    ns.prev_idx = j;\n                    ns.prev_state = sid;\n                    ns.block_end = i;\n                    ns.choice_idx = k;\n                    ns.tiebreak = rng();\n                    cand.push_back(ns);\n                }\n            }\n        }\n        prune_states(cand, state_limit);\n        dp[i] = move(cand);\n        if (dp[i].empty()) return;\n    }\n    const auto &final_states = dp[N];\n    if (final_states.empty()) return;\n    vector<int> order(final_states.size());\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b){\n        long long sa = final_states[a].width_sum + final_states[a].max_height;\n        long long sb = final_states[b].width_sum + final_states[b].max_height;\n        if (sa != sb) return sa < sb;\n        if (final_states[a].width_sum != final_states[b].width_sum)\n            return final_states[a].width_sum < final_states[b].width_sum;\n        if (final_states[a].max_height != final_states[b].max_height)\n            return final_states[a].max_height < final_states[b].max_height;\n        return final_states[a].tiebreak < final_states[b].tiebreak;\n    });\n    auto add_state = [&](int idx) {\n        Solution sol = reconstruct_solution(dp, idx, solver);\n        postprocess_solution(sol);\n        add_solution(move(sol));\n    };\n    int take_top_eff = min(take_top, (int)order.size());\n    for (int i = 0; i < take_top_eff; ++i) add_state(order[i]);\n    if (take_rand > 0 && (int)order.size() > take_top_eff) {\n        vector<int> rest(order.begin() + take_top_eff, order.end());\n        shuffle(rest.begin(), rest.end(), rng);\n        int take_rand_eff = min(take_rand, (int)rest.size());\n        for (int i = 0; i < take_rand_eff; ++i) add_state(rest[i]);\n    }\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_obs(N), h_obs(N);\n    for (int i = 0; i < N; ++i) cin >> w_obs[i] >> h_obs[i];\n\n    uint64_t seed = 1469598103934665603ULL;\n    auto mix = [&](uint64_t x) {\n        seed ^= x + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(N); mix(T); mix((uint64_t)sigma);\n    for (int i = 0; i < N; ++i) { mix((uint64_t)w_obs[i]); mix((uint64_t)h_obs[i]); }\n    mt19937 rng(seed);\n\n    ColumnPackingSolver solver;\n    solver.init(w_obs, h_obs);\n\n    vector<Solution> pool;\n    pool.reserve(T * 2 + 20);\n    unordered_set<uint64_t> seen;\n    seen.reserve(T * 4 + 40);\n\n    auto add_solution = [&](Solution sol) {\n        uint64_t h = hash_solution(sol);\n        if (seen.insert(h).second) pool.push_back(move(sol));\n    };\n\n    int height_limit = min(400, max(150, T * 3));\n    vector<long long> candidate_heights = solver.generate_candidate_heights(rng, height_limit);\n    for (long long H : candidate_heights) {\n        Solution sol;\n        if (solver.build_height_solution(H, sol, rng)) add_solution(move(sol));\n    }\n\n    const int STATE_LIMIT = 55;\n    int runs = min(7, max(3, T / 25 + 1));\n    runs = min(runs, T);\n    if (runs < 1) runs = 1;\n    int base_take = max(5, T / max(1, runs));\n    base_take = min(base_take, STATE_LIMIT);\n    for (int iter = 0; iter < runs; ++iter) {\n        int take_top = base_take;\n        int take_rand = max(2, take_top / 2);\n        run_trial(solver, rng, STATE_LIMIT, take_top, take_rand, add_solution);\n    }\n\n    add_solution(build_row_solution(solver));\n    if (pool.empty()) pool.push_back(build_row_solution(solver));\n\n    sort(pool.begin(), pool.end(), [](const Solution &a, const Solution &b){\n        if (a.score != b.score) return a.score < b.score;\n        if (a.total_width != b.total_width) return a.total_width < b.total_width;\n        if (a.total_height != b.total_height) return a.total_height < b.total_height;\n        return a.column_widths.size() < b.column_widths.size();\n    });\n\n    vector<const Solution*> plan(T);\n    int use = min((int)pool.size(), T);\n    for (int i = 0; i < use; ++i) plan[i] = &pool[i];\n    for (int i = use; i < T; ++i) plan[i] = &pool[i % use];\n\n    for (int t = 0; t < T; ++t) {\n        const Solution &sol = *plan[t];\n        cout << N << '\\n';\n        for (int i = 0; i < N; ++i) {\n            int col = sol.column_id[i];\n            int b = sol.anchor[col];\n            cout << i << ' ' << sol.orientation[i] << ' ' << 'U' << ' ' << b << '\\n';\n        }\n        cout.flush();\n        long long Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n    }\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct BuildParams {\n    double rootBeautyWeight;\n    double rootCenterWeight;\n    double rootRandomWeight;\n    int candidateMode;\n    int shallowThreshold;\n    long long depthWeight;\n    long long shallowBonus;\n    long long deepBonus;\n    long long beautyWeight;\n    int candidateRandomRange;\n};\n\nstruct Solution {\n    vector<int> parent;\n    vector<int> depth;\n    long long score;\n    Solution() : score(-(1LL << 60)) {}\n};\n\nlong long compute_score(const vector<int>& depth, const vector<int>& A) {\n    long long sum = 0;\n    for (size_t i = 0; i < depth.size(); ++i) {\n        sum += 1LL * (depth[i] + 1) * A[i];\n    }\n    return sum;\n}\n\ndouble randDouble(mt19937& rng, double low, double high) {\n    uniform_real_distribution<double> dist(low, high);\n    return dist(rng);\n}\n\nint randInt(mt19937& rng, int low, int high) {\n    uniform_int_distribution<int> dist(low, high);\n    return dist(rng);\n}\n\nBuildParams random_params(mt19937& rng, int H) {\n    BuildParams p;\n    p.rootBeautyWeight = randDouble(rng, 0.25, 1.35);\n    p.rootCenterWeight = randDouble(rng, -0.05, 0.12);\n    p.rootRandomWeight = randDouble(rng, 0.0, 4.0);\n    p.candidateMode = rng() % 2;\n\n    if (p.candidateMode == 0) {\n        int lowThr = max(1, H / 4);\n        int highThr = max(lowThr, H - 2);\n        p.shallowThreshold = randInt(rng, lowThr, highThr);\n        p.depthWeight = randInt(rng, 9000, 17000);\n        p.shallowBonus = randInt(rng, 2500, 6000);\n        p.deepBonus = randInt(rng, 100, 700);\n        p.beautyWeight = 0;\n    } else {\n        p.shallowThreshold = 0;\n        p.depthWeight = randInt(rng, 5000, 11000);\n        p.shallowBonus = 0;\n        p.deepBonus = 0;\n        p.beautyWeight = randInt(rng, 300, 450);\n    }\n    p.candidateRandomRange = randInt(rng, 30, 200);\n    return p;\n}\n\nvector<int> select_roots(const vector<vector<int>>& adj,\n                         const vector<int>& A,\n                         const vector<double>& distCenter,\n                         int H,\n                         const BuildParams& params,\n                         mt19937& rng) {\n    const int N = adj.size();\n    const int INF = 1e9;\n    vector<int> minDist(N, INF);\n    vector<double> tieValue(N, 0.0);\n    uniform_real_distribution<double> rand01(0.0, 1.0);\n\n    for (int v = 0; v < N; ++v) {\n        double rnd = (params.rootRandomWeight > 0.0) ? rand01(rng) : 0.0;\n        tieValue[v] = params.rootBeautyWeight * A[v]\n                    + params.rootCenterWeight * distCenter[v]\n                    + params.rootRandomWeight * rnd;\n    }\n\n    vector<int> dist_local(N, INF);\n    vector<int> touched;\n    touched.reserve(N);\n    vector<int> roots;\n\n    auto add_root = [&](int start) {\n        queue<int> q;\n        touched.clear();\n        dist_local[start] = 0;\n        touched.push_back(start);\n        q.push(start);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int d = dist_local[v];\n            if (d < minDist[v]) minDist[v] = d;\n            if (d == H) continue;\n            for (int nb : adj[v]) {\n                if (dist_local[nb] != INF) continue;\n                int nd = d + 1;\n                if (nd > H) continue;\n                dist_local[nb] = nd;\n                touched.push_back(nb);\n                q.push(nb);\n            }\n        }\n        for (int v : touched) dist_local[v] = INF;\n    };\n\n    while (true) {\n        int best = -1;\n        for (int v = 0; v < N; ++v) {\n            if (minDist[v] > H) {\n                if (best == -1 || minDist[v] > minDist[best] ||\n                    (minDist[v] == minDist[best] && tieValue[v] < tieValue[best])) {\n                    best = v;\n                }\n            }\n        }\n        if (best == -1) break;\n        add_root(best);\n        roots.push_back(best);\n    }\n    if (roots.empty()) {\n        int best = min_element(A.begin(), A.end()) - A.begin();\n        add_root(best);\n        roots.push_back(best);\n    }\n    return roots;\n}\n\nSolution build_solution(const vector<vector<int>>& adj,\n                        const vector<int>& A,\n                        const vector<double>& distCenter,\n                        int H,\n                        const BuildParams& params,\n                        mt19937& rng) {\n    const int N = adj.size();\n    Solution sol;\n    sol.parent.assign(N, -1);\n    sol.depth.assign(N, -1);\n\n    vector<int> roots = select_roots(adj, A, distCenter, H, params, rng);\n\n    vector<char> assigned(N, 0);\n    vector<int> bestDepth(N, -1);\n    vector<int> bestParent(N, -1);\n    vector<long long> bestKey(N, numeric_limits<long long>::min());\n\n    struct Candidate {\n        long long key;\n        int depth;\n        int node;\n        bool operator<(const Candidate& other) const {\n            if (key != other.key) return key < other.key;\n            if (depth != other.depth) return depth < other.depth;\n            return node > other.node;\n        }\n    };\n    priority_queue<Candidate> pq;\n\n    auto randContribution = [&](int range) -> long long {\n        if (range <= 0) return 0LL;\n        return static_cast<long long>(rng() % range);\n    };\n\n    int threshold = params.shallowThreshold;\n    threshold = max(0, min(threshold, H));\n\n    auto computeKey = [&](int v, int depth) -> long long {\n        long long key = 1LL * depth * params.depthWeight;\n        if (params.candidateMode == 0) {\n            if (depth <= threshold) key += params.shallowBonus - A[v];\n            else key += params.deepBonus + A[v];\n        } else {\n            key += 1LL * A[v] * params.beautyWeight;\n        }\n        key += randContribution(params.candidateRandomRange);\n        return key;\n    };\n\n    auto pushCandidate = [&](int child, int par) {\n        if (assigned[child]) return;\n        int parentDepth = sol.depth[par];\n        if (parentDepth < 0) return;\n        int newDepth = parentDepth + 1;\n        if (newDepth > H) return;\n        long long key = computeKey(child, newDepth);\n        if (newDepth > bestDepth[child] || (newDepth == bestDepth[child] && key > bestKey[child])) {\n            bestDepth[child] = newDepth;\n            bestParent[child] = par;\n            bestKey[child] = key;\n            pq.push({key, newDepth, child});\n        }\n    };\n\n    int assignedCount = 0;\n    for (int r : roots) {\n        if (!assigned[r]) {\n            assigned[r] = 1;\n            sol.depth[r] = 0;\n            sol.parent[r] = -1;\n            assignedCount++;\n        }\n    }\n    if (assignedCount == 0) {\n        int best = min_element(A.begin(), A.end()) - A.begin();\n        assigned[best] = 1;\n        sol.depth[best] = 0;\n        sol.parent[best] = -1;\n        assignedCount = 1;\n        roots.push_back(best);\n    }\n    for (int r : roots) {\n        for (int nb : adj[r]) if (!assigned[nb]) pushCandidate(nb, r);\n    }\n\n    while (assignedCount < N) {\n        if (pq.empty()) {\n            int choice = -1;\n            int bestBeauty = INT_MAX;\n            for (int v = 0; v < N; ++v) {\n                if (!assigned[v] && A[v] < bestBeauty) {\n                    bestBeauty = A[v];\n                    choice = v;\n                }\n            }\n            if (choice == -1) break;\n            assigned[choice] = 1;\n            sol.depth[choice] = 0;\n            sol.parent[choice] = -1;\n            assignedCount++;\n            for (int nb : adj[choice]) if (!assigned[nb]) pushCandidate(nb, choice);\n            continue;\n        }\n        Candidate cur = pq.top(); pq.pop();\n        int v = cur.node;\n        if (assigned[v]) continue;\n        if (cur.depth != bestDepth[v]) continue;\n        if (cur.key != bestKey[v]) continue;\n        int par = bestParent[v];\n        if (par == -1) {\n            assigned[v] = 1;\n            sol.depth[v] = 0;\n            sol.parent[v] = -1;\n        } else {\n            assigned[v] = 1;\n            sol.depth[v] = cur.depth;\n            sol.parent[v] = par;\n        }\n        assignedCount++;\n        for (int nb : adj[v]) if (!assigned[nb]) pushCandidate(nb, v);\n    }\n\n    for (int v = 0; v < N; ++v) {\n        if (sol.depth[v] < 0) {\n            sol.depth[v] = 0;\n            sol.parent[v] = -1;\n        }\n    }\n    sol.score = compute_score(sol.depth, A);\n    return sol;\n}\n\nvoid improve_leaves(const vector<vector<int>>& adj,\n                    const vector<int>& A,\n                    int H,\n                    const vector<int>& beautyOrder,\n                    Solution& sol,\n                    int maxIterations = 8) {\n    const int N = adj.size();\n    vector<int> childCnt(N, 0);\n    for (int v = 0; v < N; ++v) {\n        int p = sol.parent[v];\n        if (p >= 0) childCnt[p]++;\n    }\n\n    for (int iter = 0; iter < maxIterations; ++iter) {\n        bool changed = false;\n        for (int v : beautyOrder) {\n            if (childCnt[v] != 0) continue;\n            int curDepth = sol.depth[v];\n            int bestParent = -1;\n            int bestDepth = curDepth;\n            for (int nb : adj[v]) {\n                int parentDepth = sol.depth[nb];\n                if (parentDepth < 0) continue;\n                int newDepth = parentDepth + 1;\n                if (newDepth > H) continue;\n                if (newDepth > bestDepth) {\n                    bestDepth = newDepth;\n                    bestParent = nb;\n                } else if (newDepth == bestDepth && bestParent >= 0 && A[nb] > A[bestParent]) {\n                    bestParent = nb;\n                }\n            }\n            if (bestParent >= 0 && bestDepth > curDepth) {\n                int oldParent = sol.parent[v];\n                if (oldParent >= 0) childCnt[oldParent]--;\n                sol.parent[v] = bestParent;\n                sol.depth[v] = bestDepth;\n                childCnt[bestParent]++;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n    sol.score = compute_score(sol.depth, A);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    cin >> N >> M >> H;\n    vector<int> A(N);\n    for (int i = 0; i < N; ++i) cin >> A[i];\n\n    vector<vector<int>> adj(N);\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; ++i) cin >> xs[i] >> ys[i];\n\n    double cx = 0.0, cy = 0.0;\n    for (int i = 0; i < N; ++i) {\n        cx += xs[i];\n        cy += ys[i];\n    }\n    cx /= N;\n    cy /= N;\n\n    vector<double> distCenter(N, 0.0);\n    for (int i = 0; i < N; ++i) {\n        double dx = xs[i] - cx;\n        double dy = ys[i] - cy;\n        distCenter[i] = sqrt(dx * dx + dy * dy);\n    }\n\n    vector<int> beautyOrder(N);\n    iota(beautyOrder.begin(), beautyOrder.end(), 0);\n    sort(beautyOrder.begin(), beautyOrder.end(), [&](int lhs, int rhs) {\n        if (A[lhs] != A[rhs]) return A[lhs] > A[rhs];\n        return lhs < rhs;\n    });\n\n    vector<BuildParams> baseParams = {\n        {1.00,  0.02, 0.80, 0, 4, 15000, 4500, 350,   0,  80},\n        {0.80,  0.08, 2.50, 0, 5, 12000, 4200, 600,   0, 110},\n        {1.20, -0.02, 0.40, 0, 3, 17000, 5200, 250,   0,  70},\n        {0.60,  0.10, 3.00, 1, 0,  7000,    0,   0, 360, 120},\n        {0.45, -0.03, 4.40, 1, 0,  6200,    0,   0, 420, 150},\n        {0.95,  0.05, 1.50, 0, 2, 14000, 3600, 500,   0,  60}\n    };\n\n    mt19937 rng(123456789);\n    auto start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.80;\n\n    Solution best;\n    bool hasBest = false;\n\n    auto runAttempt = [&](const BuildParams& params) {\n        Solution sol = build_solution(adj, A, distCenter, H, params, rng);\n        improve_leaves(adj, A, H, beautyOrder, sol);\n        if (!hasBest || sol.score > best.score) {\n            best = sol;\n            hasBest = true;\n        }\n    };\n\n    for (const auto& params : baseParams) {\n        runAttempt(params);\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        if (elapsed > TIME_LIMIT) break;\n    }\n\n    while (chrono::duration<double>(chrono::steady_clock::now() - start).count() < TIME_LIMIT) {\n        BuildParams params = random_params(rng, H);\n        runAttempt(params);\n    }\n\n    if (!hasBest) {\n        BuildParams fallback = baseParams.front();\n        Solution sol = build_solution(adj, A, distCenter, H, fallback, rng);\n        improve_leaves(adj, A, H, beautyOrder, sol);\n        best = sol;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << best.parent[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Candidate {\n    char dir;\n    int idx;\n    int shifts;\n    int removal;\n};\n\nstruct PlanResult {\n    vector<Candidate> seq;\n    int cost = 0;\n    bool success = false;\n};\n\nstruct GreedyConfig {\n    double tolerance;\n    double valuePower;\n    double costPower;\n    double valueBias;\n    double hardBias;\n    double focusHardProb;\n    double noiseAmp;\n};\n\nstruct CandidateData {\n    char dir;\n    int idx;\n    int shifts;\n    int removal;\n    int hardCount;\n    double value;\n    int cost;\n    double ratio;\n};\n\nstruct SetOperation {\n    char dir;\n    int idx;\n    int shifts;\n    int cost;\n    uint64_t mask;\n    vector<int> oniList;\n};\n\nstruct PlanOps {\n    vector<int> opIndices;\n    int cost = 0;\n    bool success = false;\n};\n\nint N;\nint LIMIT_OPS;\nvector<vector<double>> cellWeight;\nvector<vector<int>> cellHard;\nvector<int> rowFirstF, rowLastF, colFirstF, colLastF;\n\nint countOni(const vector<string>& board) {\n    int cnt = 0;\n    for (const auto& row : board)\n        for (char c : row)\n            if (c == 'x') ++cnt;\n    return cnt;\n}\n\nchar oppositeDir(char dir) {\n    if (dir == 'U') return 'D';\n    if (dir == 'D') return 'U';\n    if (dir == 'L') return 'R';\n    return 'L';\n}\n\nint removeCells(vector<string>& board, const Candidate& cand) {\n    int removed = 0;\n    if (cand.dir == 'U') {\n        for (int r = 0; r < cand.shifts; ++r) {\n            char& cell = board[r][cand.idx];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'D') {\n        for (int r = N - cand.shifts; r < N; ++r) {\n            char& cell = board[r][cand.idx];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'L') {\n        for (int c = 0; c < cand.shifts; ++c) {\n            char& cell = board[cand.idx][c];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else {\n        for (int c = N - cand.shifts; c < N; ++c) {\n            char& cell = board[cand.idx][c];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    }\n    return removed;\n}\n\nGreedyConfig sampleConfig(mt19937& rng, double tolerance) {\n    uniform_real_distribution<double> dist(0.0, 1.0);\n    GreedyConfig cfg;\n    cfg.tolerance = tolerance;\n    cfg.valuePower = 1.0 + 1.4 * dist(rng);\n    cfg.costPower = 0.2 + 0.8 * dist(rng);\n    cfg.valueBias = 0.05 + 0.45 * dist(rng);\n    cfg.hardBias = 0.3 + 1.0 * dist(rng);\n    cfg.focusHardProb = 0.05 + 0.35 * pow(dist(rng), 1.5);\n    cfg.noiseAmp = 0.005 + 0.02 * dist(rng);\n    return cfg;\n}\n\nGreedyConfig deterministicConfig() {\n    GreedyConfig cfg;\n    cfg.tolerance = 0.0;\n    cfg.valuePower = 1.0;\n    cfg.costPower = 1.0;\n    cfg.valueBias = 0.0;\n    cfg.hardBias = 0.0;\n    cfg.focusHardProb = 0.0;\n    cfg.noiseAmp = 0.0;\n    return cfg;\n}\n\nPlanResult greedyPlan(const vector<string>& initial,\n                      const GreedyConfig& cfg,\n                      mt19937& rng,\n                      int costLimit,\n                      bool deterministic = false) {\n    PlanResult result;\n    vector<string> board = initial;\n    int remaining = countOni(board);\n    if (remaining == 0) {\n        result.success = true;\n        return result;\n    }\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    while (remaining > 0) {\n        vector<CandidateData> candidates;\n        int remainingBudget = costLimit - result.cost;\n        if (remainingBudget <= 0) return PlanResult();\n\n        auto addCandidate = [&](char dir, int idx, int shifts,\n                                int removal, double baseValue, int hardCount) {\n            if (removal <= 0 || shifts <= 0) return;\n            int opCost = shifts * 2;\n            if (opCost > remainingBudget) return;\n            double value = baseValue + cfg.valueBias * removal + cfg.hardBias * hardCount;\n            if (value <= 1e-9) value = removal;\n            double ratio = opCost / value;\n            if (!deterministic && cfg.noiseAmp > 0.0) {\n                double noise = (dist01(rng) * 2.0 - 1.0) * cfg.noiseAmp;\n                ratio *= max(0.05, 1.0 + noise);\n            }\n            candidates.push_back({dir, idx, shifts, removal, hardCount, value, opCost, ratio});\n        };\n\n        for (int j = 0; j < N; ++j) {\n            int limit = min(colFirstF[j], N);\n            int removal = 0, hard = 0, deepest = -1;\n            double val = 0.0;\n            for (int r = 0; r < limit; ++r) {\n                if (board[r][j] == 'x') {\n                    ++removal;\n                    deepest = r;\n                    val += cellWeight[r][j];\n                    hard += cellHard[r][j];\n                }\n            }\n            if (removal > 0) addCandidate('U', j, deepest + 1, removal, val, hard);\n\n            int start = colLastF[j];\n            int removal2 = 0, hard2 = 0, top = N;\n            double val2 = 0.0;\n            for (int r = N - 1; r > start; --r) {\n                if (board[r][j] == 'x') {\n                    ++removal2;\n                    top = min(top, r);\n                    val2 += cellWeight[r][j];\n                    hard2 += cellHard[r][j];\n                }\n            }\n            if (removal2 > 0) addCandidate('D', j, N - top, removal2, val2, hard2);\n        }\n\n        for (int i = 0; i < N; ++i) {\n            int limit = min(rowFirstF[i], N);\n            int removal = 0, hard = 0, farthest = -1;\n            double val = 0.0;\n            for (int c = 0; c < limit; ++c) {\n                if (board[i][c] == 'x') {\n                    ++removal;\n                    farthest = c;\n                    val += cellWeight[i][c];\n                    hard += cellHard[i][c];\n                }\n            }\n            if (removal > 0) addCandidate('L', i, farthest + 1, removal, val, hard);\n\n            int start = rowLastF[i];\n            int removal2 = 0, hard2 = 0, leftmost = N;\n            double val2 = 0.0;\n            for (int c = N - 1; c > start; --c) {\n                if (board[i][c] == 'x') {\n                    ++removal2;\n                    leftmost = min(leftmost, c);\n                    val2 += cellWeight[i][c];\n                    hard2 += cellHard[i][c];\n                }\n            }\n            if (removal2 > 0) addCandidate('R', i, N - leftmost, removal2, val2, hard2);\n        }\n\n        if (candidates.empty()) return PlanResult();\n\n        double minRatio = candidates.front().ratio;\n        for (const auto& cand : candidates) minRatio = min(minRatio, cand.ratio);\n        double threshold = minRatio * (1.0 + cfg.tolerance);\n\n        vector<int> eligible, hardEligible;\n        for (int idx = 0; idx < (int)candidates.size(); ++idx) {\n            if (candidates[idx].ratio <= threshold + 1e-9) {\n                eligible.push_back(idx);\n                if (candidates[idx].hardCount > 0) hardEligible.push_back(idx);\n            }\n        }\n        if (eligible.empty()) {\n            int bestIdx = 0;\n            for (int idx = 1; idx < (int)candidates.size(); ++idx)\n                if (candidates[idx].ratio + 1e-9 < candidates[bestIdx].ratio)\n                    bestIdx = idx;\n            eligible.push_back(bestIdx);\n        }\n\n        int chosenIdx = eligible.front();\n        if (deterministic) {\n            for (int idx : eligible) {\n                const auto& cur = candidates[idx];\n                const auto& best = candidates[chosenIdx];\n                if (cur.ratio + 1e-9 < best.ratio) chosenIdx = idx;\n                else if (fabs(cur.ratio - best.ratio) <= 1e-9) {\n                    if (cur.cost < best.cost) chosenIdx = idx;\n                    else if (cur.cost == best.cost && cur.removal > best.removal) chosenIdx = idx;\n                    else if (cur.cost == best.cost && cur.removal == best.removal &&\n                             cur.value > best.value + 1e-9) chosenIdx = idx;\n                }\n            }\n        } else {\n            vector<int>* pool = &eligible;\n            if (!hardEligible.empty() && dist01(rng) < cfg.focusHardProb) pool = &hardEligible;\n            vector<double> weights;\n            weights.reserve(pool->size());\n            double totalW = 0.0;\n            for (int idx : *pool) {\n                double w = pow(max(candidates[idx].value, 1e-6), cfg.valuePower);\n                if (cfg.costPower > 1e-9)\n                    w /= pow((double)candidates[idx].cost, cfg.costPower);\n                w = max(w, 1e-12);\n                weights.push_back(w);\n                totalW += w;\n            }\n            if (totalW <= 0.0) {\n                for (int idx : *pool)\n                    if (candidates[idx].ratio + 1e-9 < candidates[chosenIdx].ratio)\n                        chosenIdx = idx;\n            } else {\n                double pick = dist01(rng) * totalW;\n                for (int k = 0; k < (int)pool->size(); ++k) {\n                    pick -= weights[k];\n                    if (pick <= 1e-12) {\n                        chosenIdx = (*pool)[k];\n                        break;\n                    }\n                }\n            }\n        }\n\n        const auto& chosen = candidates[chosenIdx];\n        Candidate op{chosen.dir, chosen.idx, chosen.shifts, chosen.removal};\n        int removed = removeCells(board, op);\n        if (removed <= 0) return PlanResult();\n        op.removal = removed;\n        result.seq.push_back(op);\n        result.cost += chosen.cost;\n        remaining -= removed;\n        if (result.cost > costLimit) return PlanResult();\n    }\n    result.success = true;\n    return result;\n}\n\nPlanResult sequentialPlan(const vector<string>& initial) {\n    vector<string> board = initial;\n    PlanResult res;\n    int remaining = countOni(board);\n    while (remaining > 0) {\n        Candidate best{};\n        bool found = false;\n        int bestShift = INT_MAX;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (board[i][j] != 'x') continue;\n                auto consider = [&](char dir, int shifts, int idx) {\n                    if (shifts <= 0) return;\n                    if (shifts < bestShift) {\n                        bestShift = shifts;\n                        best = Candidate{dir, idx, shifts, 0};\n                        found = true;\n                    }\n                };\n                bool ok = true;\n                for (int r = 0; r < i; ++r) if (board[r][j] == 'o') { ok = false; break; }\n                if (ok) consider('U', i + 1, j);\n                ok = true;\n                for (int r = i + 1; r < N; ++r) if (board[r][j] == 'o') { ok = false; break; }\n                if (ok) consider('D', N - i, j);\n                ok = true;\n                for (int c = 0; c < j; ++c) if (board[i][c] == 'o') { ok = false; break; }\n                if (ok) consider('L', j + 1, i);\n                ok = true;\n                for (int c = j + 1; c < N; ++c) if (board[i][c] == 'o') { ok = false; break; }\n                if (ok) consider('R', N - j, i);\n            }\n        }\n        if (!found) break;\n        int removed = removeCells(board, best);\n        if (removed <= 0) break;\n        best.removal = removed;\n        res.seq.push_back(best);\n        res.cost += 2 * best.shifts;\n        remaining -= removed;\n        if (res.cost > LIMIT_OPS) break;\n    }\n    if (remaining == 0 && res.cost <= LIMIT_OPS) res.success = true;\n    return res;\n}\n\nbool applyPrefix(const vector<string>& initial, const vector<Candidate>& seq,\n                 int keep, vector<string>& boardOut, int& costOut) {\n    boardOut = initial;\n    costOut = 0;\n    keep = min(keep, (int)seq.size());\n    for (int i = 0; i < keep; ++i) {\n        costOut += 2 * seq[i].shifts;\n        if (costOut > LIMIT_OPS) return false;\n        int removed = removeCells(boardOut, seq[i]);\n        if (removed <= 0) return false;\n    }\n    return true;\n}\n\nvoid localSearch(const vector<string>& initial, PlanResult& best,\n                 mt19937& rng, int iterations, double maxTol) {\n    if (!best.success || best.seq.empty()) return;\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n    vector<string> board;\n    int prefixCost = 0;\n    for (int iter = 0; iter < iterations; ++iter) {\n        if (best.seq.empty()) break;\n        double r = dist01(rng);\n        int keep;\n        if (r < 0.2) keep = 0;\n        else if (r < 0.5) keep = rng() % min<int>(best.seq.size(), 5);\n        else if (r < 0.85) keep = rng() % max<int>(1, (int)best.seq.size() / 2);\n        else keep = rng() % best.seq.size();\n        if (!applyPrefix(initial, best.seq, keep, board, prefixCost)) continue;\n        int budget = LIMIT_OPS - prefixCost;\n        if (budget <= 0) continue;\n        double tol = pow(dist01(rng), 1.3) * maxTol;\n        GreedyConfig cfg = sampleConfig(rng, tol);\n        PlanResult tail = greedyPlan(board, cfg, rng, budget, false);\n        if (!tail.success) continue;\n        PlanResult candidate;\n        candidate.success = true;\n        candidate.cost = prefixCost + tail.cost;\n        candidate.seq.reserve(keep + tail.seq.size());\n        candidate.seq.insert(candidate.seq.end(), best.seq.begin(), best.seq.begin() + keep);\n        candidate.seq.insert(candidate.seq.end(), tail.seq.begin(), tail.seq.end());\n        if (!best.success || candidate.cost < best.cost ||\n            (candidate.cost == best.cost && candidate.seq.size() < best.seq.size())) {\n            best = move(candidate);\n        }\n    }\n}\n\nbool simulatePlan(const vector<string>& initial, const PlanResult& plan,\n                  vector<pair<char,int>>& output) {\n    if (!plan.success) return false;\n    if (plan.cost > LIMIT_OPS) return false;\n    vector<string> board = initial;\n    int remaining = countOni(board);\n    output.clear();\n    output.reserve(plan.cost + 5);\n\n    auto doShift = [&](char dir, int idx) -> bool {\n        if ((int)output.size() >= LIMIT_OPS) return false;\n        output.emplace_back(dir, idx);\n        if (dir == 'U') {\n            char removed = board[0][idx];\n            for (int r = 0; r < N - 1; ++r) board[r][idx] = board[r + 1][idx];\n            board[N - 1][idx] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else if (dir == 'D') {\n            char removed = board[N - 1][idx];\n            for (int r = N - 1; r >= 1; --r) board[r][idx] = board[r - 1][idx];\n            board[0][idx] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else if (dir == 'L') {\n            char removed = board[idx][0];\n            for (int c = 0; c < N - 1; ++c) board[idx][c] = board[idx][c + 1];\n            board[idx][N - 1] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else {\n            char removed = board[idx][N - 1];\n            for (int c = N - 1; c >= 1; --c) board[idx][c] = board[idx][c - 1];\n            board[idx][0] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        }\n        return true;\n    };\n\n    for (const auto& cand : plan.seq) {\n        for (int s = 0; s < cand.shifts; ++s)\n            if (!doShift(cand.dir, cand.idx)) { output.clear(); return false; }\n        char opp = oppositeDir(cand.dir);\n        for (int s = 0; s < cand.shifts; ++s)\n            if (!doShift(opp, cand.idx)) { output.clear(); return false; }\n    }\n    if (remaining != 0) { output.clear(); return false; }\n    if ((int)output.size() > LIMIT_OPS) { output.clear(); return false; }\n    return true;\n}\n\nvoid buildPrecomputations(const vector<string>& board) {\n    rowFirstF.assign(N, N);\n    rowLastF.assign(N, -1);\n    colFirstF.assign(N, N);\n    colLastF.assign(N, -1);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (board[i][j] == 'o') {\n                rowFirstF[i] = min(rowFirstF[i], j);\n                rowLastF[i] = max(rowLastF[i], j);\n                colFirstF[j] = min(colFirstF[j], i);\n                colLastF[j] = max(colLastF[j], i);\n            }\n        }\n    }\n\n    cellWeight.assign(N, vector<double>(N, 0.0));\n    cellHard.assign(N, vector<int>(N, 0));\n    vector<vector<int>> colPrev(N, vector<int>(N));\n    vector<vector<int>> colNext(N, vector<int>(N));\n    vector<vector<int>> rowPrev(N, vector<int>(N));\n    vector<vector<int>> rowNext(N, vector<int>(N));\n    for (int j = 0; j < N; ++j) {\n        int prev = -1;\n        for (int i = 0; i < N; ++i) {\n            colPrev[j][i] = prev;\n            if (board[i][j] == 'o') prev = i;\n        }\n        int next = N;\n        for (int i = N - 1; i >= 0; --i) {\n            colNext[j][i] = next;\n            if (board[i][j] == 'o') next = i;\n        }\n    }\n    for (int i = 0; i < N; ++i) {\n        int prev = -1;\n        for (int j = 0; j < N; ++j) {\n            rowPrev[i][j] = prev;\n            if (board[i][j] == 'o') prev = j;\n        }\n        int next = N;\n        for (int j = N - 1; j >= 0; --j) {\n            rowNext[i][j] = next;\n            if (board[i][j] == 'o') next = j;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (board[i][j] != 'x') continue;\n            bool safeUp = (colPrev[j][i] == -1);\n            bool safeDown = (colNext[j][i] == N);\n            bool safeLeft = (rowPrev[i][j] == -1);\n            bool safeRight = (rowNext[i][j] == N);\n            int deg = safeUp + safeDown + safeLeft + safeRight;\n            int minShift = INT_MAX;\n            if (safeUp) minShift = min(minShift, i + 1);\n            if (safeDown) minShift = min(minShift, N - i);\n            if (safeLeft) minShift = min(minShift, j + 1);\n            if (safeRight) minShift = min(minShift, N - j);\n            if (deg == 0) minShift = min({i + 1, N - i, j + 1, N - j});\n            double degBonus = 0.0;\n            if (deg <= 1) degBonus = 1.2;\n            else if (deg == 2) degBonus = 0.6;\n            else if (deg == 3) degBonus = 0.25;\n            else degBonus = 0.1;\n            double distBonus = 0.03 * minShift;\n            int edgeDist = min({i, j, N - 1 - i, N - 1 - j});\n            double edgeBonus = (edgeDist <= 1 ? 0.2 : 0.0);\n            double weight = 1.0 + degBonus + distBonus + edgeBonus;\n            cellWeight[i][j] = weight;\n            cellHard[i][j] = (deg <= 2) ? 1 : 0;\n        }\n    }\n}\n\nvoid buildPieceData(const vector<string>& board,\n                    vector<pair<int,int>>& oniPos,\n                    vector<vector<int>>& oniId,\n                    vector<vector<pair<int,int>>>& rowOni,\n                    vector<vector<pair<int,int>>>& colOni,\n                    vector<double>& oniWeight) {\n    oniPos.clear();\n    oniWeight.clear();\n    oniId.assign(N, vector<int>(N, -1));\n    rowOni.assign(N, {});\n    colOni.assign(N, {});\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (board[i][j] != 'x') continue;\n            int id = oniPos.size();\n            oniPos.emplace_back(i, j);\n            oniId[i][j] = id;\n            oniWeight.push_back(cellWeight[i][j]);\n            rowOni[i].push_back({j, id});\n            colOni[j].push_back({i, id});\n        }\n    }\n    for (int i = 0; i < N; ++i) sort(rowOni[i].begin(), rowOni[i].end());\n    for (int j = 0; j < N; ++j) sort(colOni[j].begin(), colOni[j].end());\n}\n\ninline long long encodeKey(char dir, int idx, int shifts) {\n    int dirId = (dir == 'U' ? 0 : dir == 'D' ? 1 : dir == 'L' ? 2 : 3);\n    return ( (long long)dirId << 32 ) ^ ( (long long)idx << 16 ) ^ (long long)shifts;\n}\n\nvector<SetOperation> buildSetOperations(\n        const vector<pair<int,int>>& oniPos,\n        const vector<vector<pair<int,int>>>& rowOni,\n        const vector<vector<pair<int,int>>>& colOni,\n        const vector<double>& oniWeight,\n        unordered_map<long long,int>& keyMap) {\n    vector<SetOperation> ops;\n    keyMap.clear();\n    auto addOp = [&](char dir, int idx, int shifts, const vector<int>& cover) {\n        if (cover.empty() || shifts <= 0) return;\n        long long key = encodeKey(dir, idx, shifts);\n        if (keyMap.count(key)) return;\n        SetOperation op;\n        op.dir = dir;\n        op.idx = idx;\n        op.shifts = shifts;\n        op.cost = shifts * 2;\n        op.mask = 0;\n        op.oniList = cover;\n        for (int id : cover) op.mask |= (1ULL << id);\n        if (op.mask == 0) return;\n        ops.push_back(move(op));\n        keyMap[key] = (int)ops.size() - 1;\n    };\n\n    int K = oniPos.size();\n    for (int id = 0; id < K; ++id) {\n        auto [i, j] = oniPos[id];\n        if (colFirstF[j] >= i) {\n            vector<int> cover;\n            for (auto [row, oid] : colOni[j]) {\n                if (row > i) break;\n                cover.push_back(oid);\n            }\n            addOp('U', j, i + 1, cover);\n        }\n        if (colLastF[j] <= i) {\n            vector<int> cover;\n            for (auto [row, oid] : colOni[j])\n                if (row >= i) cover.push_back(oid);\n            addOp('D', j, N - i, cover);\n        }\n        if (rowFirstF[i] >= j) {\n            vector<int> cover;\n            for (auto [col, oid] : rowOni[i]) {\n                if (col > j) break;\n                cover.push_back(oid);\n            }\n            addOp('L', i, j + 1, cover);\n        }\n        if (rowLastF[i] <= j) {\n            vector<int> cover;\n            for (auto [col, oid] : rowOni[i])\n                if (col >= j) cover.push_back(oid);\n            addOp('R', i, N - j, cover);\n        }\n    }\n    return ops;\n}\n\nPlanOps convertPlanToOps(const PlanResult& plan,\n                         const unordered_map<long long,int>& keyMap,\n                         const vector<SetOperation>& ops) {\n    PlanOps res;\n    if (!plan.success) return res;\n    for (const auto& cand : plan.seq) {\n        long long key = encodeKey(cand.dir, cand.idx, cand.shifts);\n        auto it = keyMap.find(key);\n        if (it == keyMap.end()) {\n            res.success = false;\n            res.opIndices.clear();\n            res.cost = 0;\n            return res;\n        }\n        res.opIndices.push_back(it->second);\n        res.cost += ops[it->second].cost;\n    }\n    if (res.cost != plan.cost) {\n        res.success = false;\n        res.opIndices.clear();\n        res.cost = 0;\n        return res;\n    }\n    res.success = true;\n    return res;\n}\n\nPlanResult convertSetPlanToPlanResult(const PlanOps& planOps,\n                                      const vector<SetOperation>& ops) {\n    PlanResult res;\n    if (!planOps.success) return res;\n    res.success = true;\n    res.cost = 0;\n    res.seq.reserve(planOps.opIndices.size());\n    for (int idx : planOps.opIndices) {\n        const auto& op = ops[idx];\n        res.seq.push_back({op.dir, op.idx, op.shifts, 0});\n        res.cost += op.cost;\n    }\n    return res;\n}\n\nstruct SetCoverSolver {\n    const vector<SetOperation>& ops;\n    const vector<vector<int>>& oniToOps;\n    const vector<double>& weights;\n    uint64_t fullMask;\n    int limit;\n    vector<int> bestPlan;\n    int bestCost;\n    vector<int> curPlan;\n    unordered_map<uint64_t,int> memo;\n    chrono::steady_clock::time_point start;\n    double timeLimit;\n    bool timeExceeded = false;\n\n    SetCoverSolver(const vector<SetOperation>& ops_,\n                   const vector<vector<int>>& oniToOps_,\n                   const vector<double>& weights_,\n                   uint64_t fullMask_,\n                   int limit_,\n                   const PlanOps& initial,\n                   double timeLimitSec)\n        : ops(ops_), oniToOps(oniToOps_), weights(weights_),\n          fullMask(fullMask_), limit(limit_),\n          bestPlan(initial.opIndices), bestCost(initial.cost),\n          timeLimit(timeLimitSec) {\n        start = chrono::steady_clock::now();\n    }\n\n    double sumWeight(uint64_t mask) const {\n        double sum = 0.0;\n        while (mask) {\n            int id = __builtin_ctzll(mask);\n            sum += weights[id];\n            mask &= mask - 1;\n        }\n        return sum;\n    }\n\n    double computeMinRatio(uint64_t mask) const {\n        double best = numeric_limits<double>::infinity();\n        for (size_t i = 0; i < ops.size(); ++i) {\n            uint64_t cover = ops[i].mask & mask;\n            if (!cover) continue;\n            double w = sumWeight(cover);\n            if (w <= 1e-9) continue;\n            double ratio = ops[i].cost / w;\n            if (ratio < best) best = ratio;\n        }\n        return best;\n    }\n\n    int selectPivot(uint64_t mask) const {\n        int bestOni = -1;\n        int bestCnt = INT_MAX;\n        uint64_t temp = mask;\n        while (temp) {\n            int id = __builtin_ctzll(temp);\n            temp &= temp - 1;\n            int cnt = oniToOps[id].size();\n            if (cnt == 0) return -1;\n            if (cnt < bestCnt) {\n                bestCnt = cnt;\n                bestOni = id;\n                if (cnt == 1) break;\n            }\n        }\n        return bestOni;\n    }\n\n    void dfs(uint64_t mask, int cost) {\n        if (timeExceeded) return;\n        if (cost >= bestCost) return;\n        if (mask == 0) {\n            bestCost = cost;\n            bestPlan = curPlan;\n            return;\n        }\n        if (cost >= limit) return;\n        if (chrono::duration<double>(chrono::steady_clock::now() - start).count() > timeLimit) {\n            timeExceeded = true;\n            return;\n        }\n        auto it = memo.find(mask);\n        if (it != memo.end() && it->second <= cost) return;\n        memo[mask] = cost;\n        double remWeight = sumWeight(mask);\n        double minRatio = computeMinRatio(mask);\n        if (!isfinite(minRatio)) return;\n        if (cost + remWeight * minRatio >= bestCost - 1e-9) return;\n\n        int pivot = selectPivot(mask);\n        if (pivot == -1) return;\n        vector<pair<double,int>> options;\n        options.reserve(oniToOps[pivot].size());\n        for (int opIdx : oniToOps[pivot]) {\n            uint64_t cover = ops[opIdx].mask & mask;\n            if (!(cover & (1ULL << pivot))) continue;\n            double w = sumWeight(cover);\n            if (w <= 1e-9) continue;\n            double ratio = ops[opIdx].cost / w;\n            options.emplace_back(ratio, opIdx);\n        }\n        sort(options.begin(), options.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 [ratio, opIdx] : options) {\n            curPlan.push_back(opIdx);\n            dfs(mask & ~ops[opIdx].mask, cost + ops[opIdx].cost);\n            curPlan.pop_back();\n            if (timeExceeded) return;\n        }\n    }\n\n    PlanOps solve() {\n        memo.reserve(4096);\n        dfs(fullMask, 0);\n        PlanOps res;\n        res.success = true;\n        res.cost = bestCost;\n        res.opIndices = bestPlan;\n        return res;\n    }\n};\n\nPlanResult improveWithSetCover(const PlanResult& basePlan,\n                               const vector<SetOperation>& ops,\n                               const unordered_map<long long,int>& keyMap,\n                               const vector<vector<int>>& oniToOps,\n                               const vector<double>& oniWeight,\n                               uint64_t fullMask) {\n    PlanResult res;\n    if (!basePlan.success) return res;\n    if (fullMask == 0 || ops.empty()) return res;\n    PlanOps baseOps = convertPlanToOps(basePlan, keyMap, ops);\n    if (!baseOps.success) return res;\n    uint64_t coverage = 0;\n    for (int idx : baseOps.opIndices) coverage |= ops[idx].mask;\n    if (coverage != fullMask) return res;\n    double timeLimit = (ops.size() <= 90 ? 0.08 : 0.05);\n    SetCoverSolver solver(ops, oniToOps, oniWeight, fullMask, LIMIT_OPS, baseOps, timeLimit);\n    PlanOps solved = solver.solve();\n    if (!solved.success) return res;\n    if (solved.cost >= basePlan.cost) return res;\n    return convertSetPlanToPlanResult(solved, ops);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N)) return 0;\n    vector<string> board(N);\n    for (int i = 0; i < N; ++i) cin >> board[i];\n    LIMIT_OPS = 4 * N * N;\n\n    buildPrecomputations(board);\n\n    vector<pair<int,int>> oniPos;\n    vector<vector<int>> oniId;\n    vector<vector<pair<int,int>>> rowOni, colOni;\n    vector<double> oniWeight;\n    buildPieceData(board, oniPos, oniId, rowOni, colOni, oniWeight);\n\n    unordered_map<long long,int> opKeyMap;\n    vector<SetOperation> setOps = buildSetOperations(oniPos, rowOni, colOni, oniWeight, opKeyMap);\n    vector<vector<int>> oniToOps(oniPos.size());\n    for (int idx = 0; idx < (int)setOps.size(); ++idx)\n        for (int id : setOps[idx].oniList)\n            oniToOps[id].push_back(idx);\n    uint64_t fullMask = oniPos.empty() ? 0ULL : ((1ULL << oniPos.size()) - 1);\n\n    uint64_t seed = 1469598103934665603ULL;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < N; ++i)\n        for (char c : board[i]) {\n            seed ^= (uint64_t)(unsigned char)c + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    mt19937 rng(seed);\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    const int MAX_TRIALS = 180;\n    const double MAX_TOL = 0.38;\n    PlanResult best;\n    best.cost = numeric_limits<int>::max();\n\n    for (int t = 0; t < MAX_TRIALS; ++t) {\n        double tol = (t == 0) ? 0.0 : pow(dist01(rng), 1.4) * MAX_TOL;\n        GreedyConfig cfg = sampleConfig(rng, tol);\n        PlanResult plan = greedyPlan(board, cfg, rng, LIMIT_OPS, false);\n        if (!plan.success) continue;\n        if (!best.success || plan.cost < best.cost ||\n            (plan.cost == best.cost && plan.seq.size() < best.seq.size())) {\n            best = plan;\n        }\n    }\n\n    if (!best.success) {\n        GreedyConfig detCfg = deterministicConfig();\n        PlanResult detPlan = greedyPlan(board, detCfg, rng, LIMIT_OPS, true);\n        if (detPlan.success) best = detPlan;\n    }\n\n    if (best.success) {\n        localSearch(board, best, rng, 100, 0.3);\n    } else {\n        PlanResult seqPlan = sequentialPlan(board);\n        if (seqPlan.success) best = seqPlan;\n    }\n\n    if (best.success && !oniPos.empty() && !setOps.empty() && setOps.size() <= 160) {\n        PlanResult bnbPlan = improveWithSetCover(best, setOps, opKeyMap, oniToOps, oniWeight, fullMask);\n        if (bnbPlan.success && (bnbPlan.cost < best.cost ||\n            (bnbPlan.cost == best.cost && bnbPlan.seq.size() < best.seq.size()))) {\n            best = bnbPlan;\n        }\n    }\n\n    vector<pair<char,int>> opsOutput;\n    if (!simulatePlan(board, best, opsOutput)) {\n        GreedyConfig detCfg = deterministicConfig();\n        PlanResult detPlan = greedyPlan(board, detCfg, rng, LIMIT_OPS, true);\n        if (!detPlan.success || !simulatePlan(board, detPlan, opsOutput)) {\n            PlanResult seqPlan = sequentialPlan(board);\n            simulatePlan(board, seqPlan, opsOutput);\n        }\n    }\n\n    for (auto& op : opsOutput) {\n        cout << op.first << ' ' << op.second << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\ndouble elapsedSec(const chrono::steady_clock::time_point &start) {\n    return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n}\n\nstruct AssignState {\n    int N = 0;\n    int totalItems = 0;\n    vector<int> src;\n    vector<int> weights;\n    vector<int> dest;\n    vector<int> itemPos;\n    vector<vector<int>> binItems;\n    vector<long long> cap;\n    vector<long long> sum;\n    vector<long long> rem;\n    vector<char> locked;\n    long long penalty = 0;\n\n    void setup(int n, const vector<int> &supply, const vector<int> &demand) {\n        N = n;\n        totalItems = 2 * N;\n        src.resize(totalItems);\n        weights.resize(totalItems);\n        dest.assign(totalItems, -1);\n        itemPos.assign(totalItems, -1);\n        binItems.assign(N, {});\n        cap.resize(N);\n        sum.assign(N, 0);\n        rem.assign(N, 0);\n        locked.assign(totalItems, 0);\n        penalty = 0;\n        for (int i = 0; i < N; ++i) {\n            long long w = (i < (int)supply.size() ? supply[i] : 0);\n            if (w < 0) w = 0;\n            src[2 * i] = src[2 * i + 1] = i;\n            weights[2 * i] = weights[2 * i + 1] = (int)w;\n            long long tgt = (i < (int)demand.size() ? demand[i] : 0);\n            if (tgt < 0) tgt = 0;\n            cap[i] = 2LL * tgt;\n            rem[i] = cap[i];\n        }\n    }\n};\n\nvoid initialAssign(AssignState &st, mt19937 &rng) {\n    for (int j = 0; j < st.N; ++j) {\n        st.binItems[j].clear();\n        st.sum[j] = 0;\n        st.rem[j] = st.cap[j];\n    }\n    fill(st.dest.begin(), st.dest.end(), -1);\n    fill(st.itemPos.begin(), st.itemPos.end(), -1);\n    fill(st.locked.begin(), st.locked.end(), 0);\n    vector<int> order(st.totalItems);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (st.weights[a] != st.weights[b]) return st.weights[a] > st.weights[b];\n        return a < b;\n    });\n    priority_queue<pair<long long, int>> pq;\n    for (int j = 0; j < st.N; ++j) pq.push({st.rem[j], j});\n    auto popValid = [&]() {\n        while (true) {\n            auto [val, idx] = pq.top();\n            pq.pop();\n            if (val == st.rem[idx]) return idx;\n        }\n    };\n    for (int item : order) {\n        int bin = popValid();\n        st.dest[item] = bin;\n        st.itemPos[item] = st.binItems[bin].size();\n        st.binItems[bin].push_back(item);\n        st.sum[bin] += st.weights[item];\n        st.rem[bin] = st.cap[bin] - st.sum[bin];\n        pq.push({st.rem[bin], bin});\n    }\n    st.penalty = 0;\n    for (int j = 0; j < st.N; ++j) st.penalty += llabs(st.rem[j]);\n}\n\nlong long penaltyDelta(const AssignState &st, int item, int newBin) {\n    int oldBin = st.dest[item];\n    if (oldBin == newBin) return 0;\n    long long w = st.weights[item];\n    long long before = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n    long long after = llabs(st.rem[oldBin] + w) + llabs(st.rem[newBin] - w);\n    return after - before;\n}\n\nvoid moveItem(AssignState &st, int item, int newBin) {\n    int oldBin = st.dest[item];\n    if (oldBin == newBin) return;\n    long long w = st.weights[item];\n    long long oldContribution = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n\n    int pos = st.itemPos[item];\n    int last = st.binItems[oldBin].back();\n    st.binItems[oldBin][pos] = last;\n    st.itemPos[last] = pos;\n    st.binItems[oldBin].pop_back();\n\n    st.sum[oldBin] -= w;\n    st.rem[oldBin] += w;\n\n    st.sum[newBin] += w;\n    st.rem[newBin] -= w;\n\n    st.itemPos[item] = st.binItems[newBin].size();\n    st.binItems[newBin].push_back(item);\n    st.dest[item] = newBin;\n\n    long long newContribution = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n    st.penalty += newContribution - oldContribution;\n}\n\nvoid balance(AssignState &st, bool respectLocked,\n             const chrono::steady_clock::time_point &start, double limitTime) {\n    while (true) {\n        if (elapsedSec(start) > limitTime) break;\n        vector<int> posBins;\n        for (int j = 0; j < st.N; ++j) if (st.rem[j] > 0) posBins.push_back(j);\n        if (posBins.empty()) break;\n        sort(posBins.begin(), posBins.end(),\n             [&](int a, int b) { return st.rem[a] > st.rem[b]; });\n        bool moved = false;\n        for (int pos : posBins) {\n            long long remPos = st.rem[pos];\n            long long bestDiff = 0;\n            int bestItem = -1;\n            for (int neg = 0; neg < st.N; ++neg) {\n                if (st.rem[neg] >= 0) continue;\n                long long remNeg = st.rem[neg];\n                for (int item : st.binItems[neg]) {\n                    if (respectLocked && st.locked[item]) continue;\n                    long long w = st.weights[item];\n                    long long newPos = remPos - w;\n                    long long newNeg = remNeg + w;\n                    long long diff = llabs(newPos) + llabs(newNeg)\n                                   - (llabs(remPos) + llabs(remNeg));\n                    if (diff < bestDiff) {\n                        bestDiff = diff;\n                        bestItem = item;\n                    }\n                }\n            }\n            if (bestItem != -1) {\n                moveItem(st, bestItem, pos);\n                moved = true;\n                break;\n            }\n        }\n        if (!moved) break;\n    }\n}\n\nvoid randomImprove(AssignState &st, bool respectLocked, int maxIter,\n                   const chrono::steady_clock::time_point &start,\n                   double limitTime, mt19937 &rng) {\n    for (int iter = 0; iter < maxIter; ++iter) {\n        if ((iter & 511) == 0 && elapsedSec(start) > limitTime) break;\n        int item = rng() % st.totalItems;\n        if (respectLocked) {\n            int tries = 0;\n            while (tries < 30 && st.locked[item]) {\n                item = rng() % st.totalItems;\n                ++tries;\n            }\n            if (st.locked[item]) continue;\n        }\n        int from = st.dest[item];\n        int bestBin = -1;\n        long long bestDelta = 0;\n        for (int attempt = 0; attempt < 6; ++attempt) {\n            int cand = rng() % st.N;\n            if (cand == from) continue;\n            long long delta = penaltyDelta(st, item, cand);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestBin = cand;\n            }\n        }\n        if (bestBin == -1) continue;\n        moveItem(st, item, bestBin);\n    }\n}\n\nstruct SCCResult {\n    vector<int> comp;\n    int cnt;\n};\n\nSCCResult computeSCC(const vector<int> &a, const vector<int> &b) {\n    int N = a.size();\n    vector<vector<int>> g(N), gr(N);\n    for (int i = 0; i < N; ++i) {\n        g[i].push_back(a[i]);\n        g[i].push_back(b[i]);\n        gr[a[i]].push_back(i);\n        gr[b[i]].push_back(i);\n    }\n    vector<int> used(N, 0), order;\n    auto dfs1 = [&](auto self, int v) -> void {\n        used[v] = 1;\n        for (int to : g[v]) if (!used[to]) self(self, to);\n        order.push_back(v);\n    };\n    for (int i = 0; i < N; ++i) if (!used[i]) dfs1(dfs1, i);\n    vector<int> comp(N, -1);\n    int compId = 0;\n    auto dfs2 = [&](auto self, int v) -> void {\n        comp[v] = compId;\n        for (int to : gr[v]) if (comp[to] == -1) self(self, to);\n    };\n    for (int i = N - 1; i >= 0; --i) {\n        int v = order[i];\n        if (comp[v] == -1) {\n            dfs2(dfs2, v);\n            ++compId;\n        }\n    }\n    return {comp, compId};\n}\n\nint ensureConnectivity(AssignState &st,\n                       const chrono::steady_clock::time_point &start,\n                       double limitTime) {\n    vector<int> a(st.N), b(st.N);\n    for (int i = 0; i < st.N; ++i) {\n        a[i] = st.dest[2 * i];\n        b[i] = st.dest[2 * i + 1];\n    }\n    auto scc = computeSCC(a, b);\n    int K = scc.cnt;\n    if (K == 1) return 0;\n    vector<vector<int>> nodesIn(K);\n    for (int i = 0; i < st.N; ++i) nodesIn[scc.comp[i]].push_back(i);\n    vector<int> order(K);\n    iota(order.begin(), order.end(), 0);\n    int lockedAdded = 0;\n    for (int idx = 0; idx < K; ++idx) {\n        if (elapsedSec(start) > limitTime) break;\n        int fromC = order[idx];\n        int toC = order[(idx + 1) % K];\n        vector<int> existing;\n        for (int node : nodesIn[fromC]) {\n            for (int t = 0; t < 2; ++t) {\n                int item = 2 * node + t;\n                if (st.dest[item] >= 0 && scc.comp[st.dest[item]] == toC) {\n                    existing.push_back(item);\n                }\n            }\n        }\n        if (!existing.empty()) {\n            int bestEdge = existing[0];\n            for (int item : existing) {\n                if (st.weights[item] < st.weights[bestEdge]) bestEdge = item;\n            }\n            st.locked[bestEdge] = 1;\n            ++lockedAdded;\n            continue;\n        }\n        long long bestDelta = (1LL << 60);\n        int bestEdge = -1, bestDest = -1;\n        for (int node : nodesIn[fromC]) {\n            for (int t = 0; t < 2; ++t) {\n                int item = 2 * node + t;\n                if (st.locked[item]) continue;\n                for (int destNode : nodesIn[toC]) {\n                    long long delta = penaltyDelta(st, item, destNode);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestEdge = item;\n                        bestDest = destNode;\n                    }\n                }\n            }\n        }\n        if (bestEdge == -1) continue;\n        moveItem(st, bestEdge, bestDest);\n        st.locked[bestEdge] = 1;\n        ++lockedAdded;\n    }\n    return lockedAdded;\n}\n\nlong long simulatePlan(const vector<int> &a, const vector<int> &b, int L,\n                       const vector<int> &target, vector<int> &cnt) {\n    int N = a.size();\n    if ((int)cnt.size() != N) cnt.assign(N, 0);\n    else fill(cnt.begin(), cnt.end(), 0);\n    int cur = 0;\n    cnt[cur] = 1;\n    for (int step = 1; step < L; ++step) {\n        int nxt = (cnt[cur] & 1) ? a[cur] : b[cur];\n        cur = nxt;\n        cnt[cur]++;\n    }\n    long long err = 0;\n    for (int i = 0; i < N; ++i) err += llabs(1LL * cnt[i] - target[i]);\n    return err;\n}\n\nvoid localSearch(vector<int> &a, vector<int> &b, const vector<int> &target, int L,\n                 const chrono::steady_clock::time_point &start, double limitTime,\n                 mt19937 &rng) {\n    int N = a.size();\n    if (N == 0) return;\n    if (elapsedSec(start) >= limitTime) return;\n\n    vector<int> curCnt(N), bestCnt(N), testCnt(N), diff(N);\n    long long curErr = simulatePlan(a, b, L, target, curCnt);\n    long long bestErr = curErr;\n    bestCnt = curCnt;\n    vector<int> bestA = a, bestB = b;\n\n    auto refreshDiff = [&]() {\n        for (int i = 0; i < N; ++i) diff[i] = curCnt[i] - target[i];\n    };\n    refreshDiff();\n    if (bestErr == 0) {\n        a = bestA;\n        b = bestB;\n        return;\n    }\n\n    while (elapsedSec(start) < limitTime) {\n        vector<int> over, under;\n        for (int i = 0; i < N; ++i) {\n            if (diff[i] > 0) over.push_back(i);\n            else if (diff[i] < 0) under.push_back(i);\n        }\n        if (over.empty() || under.empty()) break;\n\n        int destOver;\n        if ((rng() & 7) != 0) {\n            destOver = over[0];\n            for (int idx : over) if (diff[idx] > diff[destOver]) destOver = idx;\n        } else destOver = over[rng() % over.size()];\n\n        int destUnder;\n        if ((rng() & 7) != 0) {\n            destUnder = under[0];\n            for (int idx : under) if (diff[idx] < diff[destUnder]) destUnder = idx;\n        } else destUnder = under[rng() % under.size()];\n\n        vector<pair<int, int>> edges;\n        for (int u = 0; u < N; ++u) {\n            if (a[u] == destOver) edges.emplace_back(u, 0);\n            if (b[u] == destOver) edges.emplace_back(u, 1);\n        }\n        if (edges.empty()) {\n            edges.emplace_back(destOver, 0);\n            edges.emplace_back(destOver, 1);\n        }\n\n        pair<int, int> chosen = edges[rng() % edges.size()];\n        if ((rng() & 3) != 0) {\n            pair<int, int> bestEdge = edges[0];\n            int bestVal = diff[bestEdge.first];\n            for (auto &e : edges) {\n                if (diff[e.first] > bestVal) {\n                    bestVal = diff[e.first];\n                    bestEdge = e;\n                }\n            }\n            chosen = bestEdge;\n        }\n\n        int src = chosen.first;\n        int which = chosen.second;\n        int oldDest = (which == 0) ? a[src] : b[src];\n        if (oldDest == destUnder) continue;\n\n        if (which == 0) a[src] = destUnder;\n        else b[src] = destUnder;\n\n        long long newErr = simulatePlan(a, b, L, target, testCnt);\n        if (newErr <= curErr) {\n            curErr = newErr;\n            curCnt = testCnt;\n            refreshDiff();\n            if (newErr < bestErr) {\n                bestErr = newErr;\n                bestA = a;\n                bestB = b;\n                bestCnt = testCnt;\n                if (bestErr == 0) break;\n            }\n        } else {\n            if (which == 0) a[src] = oldDest;\n            else b[src] = oldDest;\n        }\n\n        if (elapsedSec(start) >= limitTime) break;\n    }\n    a = bestA;\n    b = bestB;\n}\n\nvector<int> buildAdjustedDemand(const vector<int> &base,\n                                const vector<int> &counts,\n                                long long bestErr, int L) {\n    int N = base.size();\n    vector<int> demand(N);\n    double scale = min(1.0, max(0.0, bestErr / 65000.0));\n    double beta = 0.55 + 0.35 * scale;\n    long long total = 0;\n    for (int i = 0; i < N; ++i) {\n        long long diff = (long long)counts[i] - base[i];\n        long long val = (long long)llround((double)base[i] - beta * diff);\n        val = max(0LL, min((long long)L, val));\n        demand[i] = (int)val;\n        total += val;\n    }\n    vector<int> ordAdd(N), ordSub(N);\n    iota(ordAdd.begin(), ordAdd.end(), 0);\n    iota(ordSub.begin(), ordSub.end(), 0);\n    sort(ordAdd.begin(), ordAdd.end(), [&](int i, int j) {\n        long long di = (long long)counts[i] - base[i];\n        long long dj = (long long)counts[j] - base[j];\n        if (di != dj) return di < dj;\n        return i < j;\n    });\n    sort(ordSub.begin(), ordSub.end(), [&](int i, int j) {\n        long long di = (long long)counts[i] - base[i];\n        long long dj = (long long)counts[j] - base[j];\n        if (di != dj) return di > dj;\n        return i < j;\n    });\n\n    auto distributeAdd = [&](long long need, const vector<int> &order) -> long long {\n        long long remain = need;\n        if (remain <= 0) return remain;\n        for (int pass = 0; pass < 3 && remain > 0; ++pass) {\n            int left = order.size();\n            bool changed = false;\n            for (int idx : order) {\n                if (remain == 0) break;\n                long long cap = (long long)L - demand[idx];\n                if (cap <= 0) { --left; continue; }\n                long long share = max(1LL, remain / max(1, left));\n                share = min(share, cap);\n                if (share <= 0) continue;\n                demand[idx] += (int)share;\n                remain -= share;\n                changed = true;\n                --left;\n            }\n            if (!changed) break;\n        }\n        return remain;\n    };\n    auto distributeRemove = [&](long long need, const vector<int> &order) -> long long {\n        long long remain = need;\n        if (remain <= 0) return remain;\n        for (int pass = 0; pass < 3 && remain > 0; ++pass) {\n            int left = order.size();\n            bool changed = false;\n            for (int idx : order) {\n                if (remain == 0) break;\n                long long cap = demand[idx];\n                if (cap <= 0) { --left; continue; }\n                long long share = max(1LL, remain / max(1, left));\n                share = min(share, cap);\n                if (share <= 0) continue;\n                demand[idx] -= (int)share;\n                remain -= share;\n                changed = true;\n                --left;\n            }\n            if (!changed) break;\n        }\n        return remain;\n    };\n\n    long long gap = (long long)L - total;\n    if (gap > 0) {\n        long long leftover = distributeAdd(gap, ordAdd);\n        gap = leftover;\n    } else if (gap < 0) {\n        long long leftover = distributeRemove(-gap, ordSub);\n        gap = -leftover;\n    } else gap = 0;\n\n    long long finalSum = 0;\n    for (int v : demand) finalSum += v;\n    long long diffSum = (long long)L - finalSum;\n    if (diffSum > 0) {\n        for (int idx : ordAdd) {\n            if (diffSum == 0) break;\n            long long cap = (long long)L - demand[idx];\n            if (cap <= 0) continue;\n            long long delta = min(cap, diffSum);\n            demand[idx] += (int)delta;\n            diffSum -= delta;\n        }\n        for (int i = 0; i < N && diffSum > 0; ++i) {\n            long long cap = (long long)L - demand[i];\n            if (cap <= 0) continue;\n            long long delta = min(cap, diffSum);\n            demand[i] += (int)delta;\n            diffSum -= delta;\n        }\n    } else if (diffSum < 0) {\n        long long need = -diffSum;\n        for (int idx : ordSub) {\n            if (need == 0) break;\n            long long cap = demand[idx];\n            if (cap <= 0) continue;\n            long long delta = min(cap, need);\n            demand[idx] -= (int)delta;\n            need -= delta;\n        }\n        for (int i = 0; i < N && need > 0; ++i) {\n            long long cap = demand[i];\n            if (cap <= 0) continue;\n            long long delta = min(cap, need);\n            demand[i] -= (int)delta;\n            need -= delta;\n        }\n    }\n    return demand;\n}\n\nstruct AttemptResult {\n    vector<int> a, b;\n    vector<int> counts;\n    long long err = (1LL << 60);\n    long long weightPenalty = (1LL << 60);\n};\n\nAttemptResult runAttempt(const vector<int> &supply, const vector<int> &demand,\n                         const vector<int> &target,\n                         const chrono::steady_clock::time_point &start,\n                         double limitTime, int L, uint64_t seed) {\n    AttemptResult res;\n    int N = supply.size();\n    AssignState st;\n    st.setup(N, supply, demand);\n    mt19937 rng(seed);\n\n    initialAssign(st, rng);\n    balance(st, false, start, limitTime);\n    randomImprove(st, false, 200000, start, limitTime, rng);\n    balance(st, false, start, limitTime);\n\n    ensureConnectivity(st, start, limitTime);\n    balance(st, true, start, limitTime);\n    randomImprove(st, true, 120000, start, limitTime, rng);\n    balance(st, true, start, limitTime);\n\n    vector<int> a(N), b(N);\n    for (int i = 0; i < N; ++i) {\n        int da = st.dest[2 * i];\n        int db = st.dest[2 * i + 1];\n        if (da < 0 || da >= N) da = i;\n        if (db < 0 || db >= N) db = i;\n        a[i] = da;\n        b[i] = db;\n    }\n    vector<int> cnt(N);\n    long long err = simulatePlan(a, b, L, target, cnt);\n    res.a = move(a);\n    res.b = move(b);\n    res.counts = move(cnt);\n    res.err = err;\n    res.weightPenalty = st.penalty;\n    return res;\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    auto start = chrono::steady_clock::now();\n    const double TOTAL_LIMIT = 1.95;\n    const double FINAL_RESERVE = 0.02;\n    const double LS_WINDOW = 0.30;\n\n    double attemptWindow = TOTAL_LIMIT - LS_WINDOW - FINAL_RESERVE;\n    attemptWindow = max(0.45, min(attemptWindow, TOTAL_LIMIT - FINAL_RESERVE - 0.02));\n\n    vector<double> attemptLimits;\n    double first = min(0.65, attemptWindow);\n    attemptLimits.push_back(first);\n    if (attemptWindow - first > 0.20) {\n        double second = min(1.05, attemptWindow);\n        if (second - first > 0.05) attemptLimits.push_back(second);\n    }\n    if (attemptLimits.empty() || attemptLimits.back() + 0.15 < attemptWindow - 1e-3)\n        attemptLimits.push_back(attemptWindow);\n\n    mt19937 baseRng(chrono::steady_clock::now().time_since_epoch().count());\n    auto nextSeed = [&]() -> uint64_t {\n        return ((uint64_t)baseRng() << 32) ^ baseRng() ^\n               chrono::steady_clock::now().time_since_epoch().count();\n    };\n\n    vector<int> baseDemand = T;\n    vector<int> bestA(N), bestB(N), bestCounts(N, 0);\n    long long bestErr = (1LL << 60), bestPenalty = (1LL << 60);\n    bool haveBest = false;\n\n    for (size_t idx = 0; idx < attemptLimits.size(); ++idx) {\n        double limit = min(attemptLimits[idx], TOTAL_LIMIT - FINAL_RESERVE - 0.02);\n        if (elapsedSec(start) >= limit - 0.01) continue;\n        vector<int> demandUse = baseDemand;\n        bool useAdjusted = false;\n        if (haveBest) {\n            if (bestErr > 52000) useAdjusted = true;\n            else if (bestErr > 36000 && idx + 1 == attemptLimits.size()) useAdjusted = true;\n        }\n        if (useAdjusted) demandUse = buildAdjustedDemand(baseDemand, bestCounts, bestErr, L);\n\n        uint64_t seed = nextSeed() ^ (0x9e3779b97f4a7c15ULL * (idx + 1));\n        AttemptResult res = runAttempt(T, demandUse, T, start, limit, L, seed);\n        if (!haveBest || res.err < bestErr ||\n            (res.err == bestErr && res.weightPenalty < bestPenalty)) {\n            bestA = res.a;\n            bestB = res.b;\n            bestCounts = res.counts;\n            bestErr = res.err;\n            bestPenalty = res.weightPenalty;\n            haveBest = true;\n        }\n        if (elapsedSec(start) > attemptWindow + 0.05) break;\n    }\n\n    if (!haveBest) {\n        uint64_t seed = nextSeed();\n        double fallbackLimit = min(TOTAL_LIMIT - FINAL_RESERVE - 0.05, TOTAL_LIMIT - FINAL_RESERVE - 0.01);\n        AttemptResult res = runAttempt(T, baseDemand, T, start, fallbackLimit, L, seed);\n        bestA = res.a;\n        bestB = res.b;\n        bestCounts = res.counts;\n        bestErr = res.err;\n        bestPenalty = res.weightPenalty;\n        haveBest = true;\n    }\n\n    double lsLimit = TOTAL_LIMIT - FINAL_RESERVE;\n    if (lsLimit > elapsedSec(start) + 0.01) {\n        localSearch(bestA, bestB, T, L, start, lsLimit, baseRng);\n        vector<int> cnt(N);\n        bestErr = simulatePlan(bestA, bestB, L, T, cnt);\n        bestCounts = cnt;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << bestA[i] << ' ' << bestB[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\n// ----------------- Geometry / MST utilities -----------------\nlong long hilbertOrder(long long x, long long y, int pow = 15, int rot = 0) {\n    if (pow == 0) return 0;\n    long long h = 1LL << (pow - 1);\n    long long seg = ((x < h) ? 0 : 1) | ((y < h) ? 0 : 2);\n    seg = (seg + rot) & 3;\n    static const int rotateDelta[4] = {3, 0, 0, 1};\n    long long nx = x & (h - 1);\n    long long ny = y & (h - 1);\n    int nrot = (rot + rotateDelta[seg]) & 3;\n    long long subSize = 1LL << (2 * pow - 2);\n    long long add = hilbertOrder(nx, ny, pow - 1, nrot);\n    if (seg == 1 || seg == 2) {\n        return seg * subSize + add;\n    } else {\n        return seg * subSize + (subSize - add - 1);\n    }\n}\n\nvector<int> build_global_parent(const vector<double>& px, const vector<double>& py) {\n    int n = (int)px.size();\n    const double INF = 1e100;\n    vector<double> best(n, INF);\n    vector<int> parent(n, -1);\n    vector<char> used(n, 0);\n    best[0] = 0.0;\n    for (int it = 0; it < n; ++it) {\n        int v = -1;\n        double bv = INF;\n        for (int i = 0; i < n; ++i)\n            if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n        if (v == -1) break;\n        used[v] = 1;\n        for (int u = 0; u < n; ++u) if (!used[u]) {\n            double dx = px[v] - px[u];\n            double dy = py[v] - py[u];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[u]) {\n                best[u] = dist;\n                parent[u] = v;\n            }\n        }\n    }\n    for (int i = 1; i < n; ++i) if (parent[i] == -1) parent[i] = 0;\n    return parent;\n}\n\ndouble group_cost(const vector<int>& nodes, const vector<double>& px, const vector<double>& py) {\n    int k = (int)nodes.size();\n    if (k <= 1) return 0.0;\n    static vector<double> best;\n    static vector<char> used;\n    best.assign(k, 1e100);\n    used.assign(k, 0);\n    best[0] = 0.0;\n    double total = 0.0;\n    for (int iter = 0; iter < k; ++iter) {\n        int v = -1;\n        double bv = 1e100;\n        for (int i = 0; i < k; ++i)\n            if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n        if (v == -1) break;\n        used[v] = 1;\n        if (iter > 0) total += sqrt(max(0.0, bv));\n        for (int j = 0; j < k; ++j) if (!used[j]) {\n            double dx = px[nodes[v]] - px[nodes[j]];\n            double dy = py[nodes[v]] - py[nodes[j]];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[j]) best[j] = dist;\n        }\n    }\n    return total;\n}\n\nvector<pair<int,int>> build_group_mst(const vector<int>& nodes,\n                                      const vector<double>& px,\n                                      const vector<double>& py) {\n    int k = (int)nodes.size();\n    vector<pair<int,int>> edges;\n    if (k <= 1) return edges;\n    vector<double> best(k, 1e100);\n    vector<int> parent(k, -1);\n    vector<char> used(k, 0);\n    best[0] = 0.0;\n    for (int iter = 0; iter < k; ++iter) {\n        int v = -1;\n        double bv = 1e100;\n        for (int i = 0; i < k; ++i)\n            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[v], nodes[parent[v]]);\n        for (int j = 0; j < k; ++j) if (!used[j]) {\n            double dx = px[nodes[v]] - px[nodes[j]];\n            double dy = py[nodes[v]] - py[nodes[j]];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[j]) {\n                best[j] = dist;\n                parent[j] = v;\n            }\n        }\n    }\n    if ((int)edges.size() != k - 1) {\n        edges.clear();\n        for (int i = 1; i < k; ++i)\n            edges.emplace_back(nodes[i - 1], nodes[i]);\n    }\n    return edges;\n}\n\n// ---------------- Pair grouping helper ----------------\ndouble pair_sequence_cost(const vector<int>& ord,\n                          const vector<double>& px,\n                          const vector<double>& py) {\n    double sum = 0.0;\n    for (size_t i = 0; i + 1 < ord.size(); i += 2) {\n        int a = ord[i], b = ord[i + 1];\n        double dx = px[a] - px[b];\n        double dy = py[a] - py[b];\n        sum += sqrt(max(0.0, dx * dx + dy * dy));\n    }\n    return sum;\n}\n\nvector<int> best_pair_sequence(vector<int> nodes,\n                               const vector<double>& px,\n                               const vector<double>& py,\n                               const vector<long long>& hilb,\n                               uint64_t key) {\n    if (nodes.empty()) return nodes;\n    if (nodes.size() % 2) nodes.pop_back();\n    vector<int> best = nodes;\n    double bestCost = pair_sequence_cost(best, px, py);\n    auto try_order = [&](vector<int> cand) {\n        if (cand.size() != nodes.size()) return;\n        double cost = pair_sequence_cost(cand, px, py);\n        if (cost + 1e-9 < bestCost) {\n            bestCost = cost;\n            best = std::move(cand);\n        }\n    };\n\n    vector<int> tmp;\n\n    tmp = nodes;\n    sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n        if (px[a] != px[b]) return px[a] < px[b];\n        return a < b;\n    });\n    try_order(tmp);\n\n    tmp = nodes;\n    sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n        if (py[a] != py[b]) return py[a] < py[b];\n        return a < b;\n    });\n    try_order(tmp);\n\n    tmp = nodes;\n    sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n        if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n        return a < b;\n    });\n    try_order(tmp);\n\n    tmp = nodes;\n    sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n        double va = px[a] + py[a];\n        double vb = px[b] + py[b];\n        if (va != vb) return va < vb;\n        return a < b;\n    });\n    try_order(tmp);\n\n    tmp = nodes;\n    sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n        double va = px[a] - py[a];\n        double vb = px[b] - py[b];\n        if (va != vb) return va < vb;\n        return a < b;\n    });\n    try_order(tmp);\n\n    tmp.clear();\n    {\n        vector<int> rem = nodes;\n        while (rem.size() >= 2) {\n            int a = rem.back();\n            rem.pop_back();\n            int bestIdx = 0;\n            double bestDist = 1e100;\n            for (int i = 0; i < (int)rem.size(); ++i) {\n                int b = rem[i];\n                double dx = px[a] - px[b];\n                double dy = py[a] - py[b];\n                double dist = dx * dx + dy * dy;\n                if (dist < bestDist) {\n                    bestDist = dist;\n                    bestIdx = i;\n                }\n            }\n            int b = rem[bestIdx];\n            rem.erase(rem.begin() + bestIdx);\n            tmp.push_back(a);\n            tmp.push_back(b);\n        }\n        if (tmp.size() == nodes.size()) try_order(tmp);\n    }\n\n    mt19937 rng_local((uint32_t)(key ^ 0x9e3779b97f4a7c15ULL));\n    tmp = nodes;\n    for (int t = 0; t < 4; ++t) {\n        shuffle(tmp.begin(), tmp.end(), rng_local);\n        try_order(tmp);\n    }\n\n    return best;\n}\n\nvoid improve_pairs(vector<vector<int>>& groups,\n                   const vector<int>& sizeOrder,\n                   const vector<double>& px,\n                   const vector<double>& py,\n                   const vector<long long>& hilb,\n                   uint64_t key) {\n    vector<int> idx;\n    vector<int> nodes;\n    for (int i = 0; i < (int)groups.size(); ++i) {\n        if ((int)groups[i].size() == 2 && sizeOrder[i] == 2) {\n            idx.push_back(i);\n            nodes.push_back(groups[i][0]);\n            nodes.push_back(groups[i][1]);\n        }\n    }\n    if (idx.empty()) return;\n    double curCost = pair_sequence_cost(nodes, px, py);\n    vector<int> bestOrder = best_pair_sequence(nodes, px, py, hilb, key ^ 0xabcdef123456789ULL);\n    double bestCost = pair_sequence_cost(bestOrder, px, py);\n    if (bestCost + 1e-9 >= curCost) return;\n    for (size_t t = 0; t < idx.size(); ++t) {\n        groups[idx[t]][0] = bestOrder[2 * t];\n        groups[idx[t]][1] = bestOrder[2 * t + 1];\n    }\n}\n\n// ---------------- Group builders ----------------\nbool build_groups_contiguous(const vector<int>& ord, const vector<int>& sizes,\n                             vector<vector<int>>& groups) {\n    int M = sizes.size();\n    groups.assign(M, {});\n    size_t pos = 0;\n    for (int i = 0; i < M; ++i) {\n        int need = sizes[i];\n        if (need < 0 || pos + need > ord.size()) return false;\n        groups[i].assign(ord.begin() + pos, ord.begin() + pos + need);\n        pos += need;\n    }\n    return pos == ord.size();\n}\n\nbool build_groups_greedy(const vector<int>& prefer, int offset,\n                         const vector<int>& sizes,\n                         vector<vector<int>>& groups,\n                         const vector<double>& px,\n                         const vector<double>& py) {\n    int N = prefer.size();\n    int M = sizes.size();\n    if (N == 0) return false;\n    vector<int> order(N);\n    for (int i = 0; i < N; ++i) order[i] = prefer[(i + offset) % N];\n    vector<char> used(N, 0);\n    int ptr = 0;\n    auto pick_seed = [&]() -> int {\n        for (int iter = 0; iter < N; ++iter) {\n            int idx = order[ptr];\n            ptr++;\n            if (ptr == N) ptr = 0;\n            if (!used[idx]) return idx;\n        }\n        for (int idx = 0; idx < N; ++idx)\n            if (!used[idx]) return idx;\n        return -1;\n    };\n    groups.assign(M, {});\n    for (int gi = 0; gi < M; ++gi) {\n        int need = sizes[gi];\n        if (need <= 0) return false;\n        int seed = pick_seed();\n        if (seed == -1) return false;\n        vector<int> grp;\n        grp.reserve(need);\n        used[seed] = 1;\n        grp.push_back(seed);\n        double cx = px[seed], cy = py[seed];\n        while ((int)grp.size() < need) {\n            int best = -1;\n            double bestDist = 1e100;\n            for (int city = 0; city < N; ++city) if (!used[city]) {\n                double dx = px[city] - cx;\n                double dy = py[city] - cy;\n                double dist = dx * dx + dy * dy;\n                if (dist < bestDist) {\n                    bestDist = dist;\n                    best = city;\n                }\n            }\n            if (best == -1) return false;\n            used[best] = 1;\n            grp.push_back(best);\n            double sz = grp.size();\n            cx = (cx * (sz - 1) + px[best]) / sz;\n            cy = (cy * (sz - 1) + py[best]) / sz;\n        }\n        groups[gi] = std::move(grp);\n    }\n    return true;\n}\n\nbool build_groups_two_phase(const vector<int>& prefer, int offset,\n                            const vector<int>& sizes,\n                            vector<vector<int>>& groups,\n                            const vector<double>& px,\n                            const vector<double>& py,\n                            const vector<long long>& hilb,\n                            uint64_t key) {\n    int N = prefer.size();\n    int M = sizes.size();\n    if (N == 0) return false;\n    vector<int> order(N);\n    for (int i = 0; i < N; ++i) order[i] = prefer[(i + offset) % N];\n    vector<char> used(N, 0);\n    groups.assign(M, {});\n    vector<int> idxLarge, idxTwo, idxOne;\n    for (int i = 0; i < M; ++i) {\n        if (sizes[i] >= 3) idxLarge.push_back(i);\n        else if (sizes[i] == 2) idxTwo.push_back(i);\n        else if (sizes[i] == 1) idxOne.push_back(i);\n        else return false;\n    }\n    sort(idxLarge.begin(), idxLarge.end(), [&](int a, int b) {\n        if (sizes[a] != sizes[b]) return sizes[a] > sizes[b];\n        return a < b;\n    });\n    int ptr = 0;\n    auto pick_seed = [&]() -> int {\n        for (int iter = 0; iter < N; ++iter) {\n            int idx = order[ptr];\n            ptr++;\n            if (ptr == N) ptr = 0;\n            if (!used[idx]) return idx;\n        }\n        for (int idx = 0; idx < N; ++idx)\n            if (!used[idx]) return idx;\n        return -1;\n    };\n    for (int idx : idxLarge) {\n        int need = sizes[idx];\n        int seed = pick_seed();\n        if (seed == -1) return false;\n        vector<int> grp;\n        grp.reserve(need);\n        used[seed] = 1;\n        grp.push_back(seed);\n        double cx = px[seed], cy = py[seed];\n        while ((int)grp.size() < need) {\n            int best = -1;\n            double bestDist = 1e100;\n            for (int city = 0; city < N; ++city) if (!used[city]) {\n                double dx = px[city] - cx;\n                double dy = py[city] - cy;\n                double dist = dx * dx + dy * dy;\n                if (dist < bestDist) {\n                    bestDist = dist;\n                    best = city;\n                }\n            }\n            if (best == -1) return false;\n            used[best] = 1;\n            grp.push_back(best);\n            double sz = grp.size();\n            cx = (cx * (sz - 1) + px[best]) / sz;\n            cy = (cy * (sz - 1) + py[best]) / sz;\n        }\n        groups[idx] = std::move(grp);\n    }\n    vector<int> leftover;\n    leftover.reserve(N);\n    for (int idx : order) if (!used[idx]) leftover.push_back(idx);\n    int needPairs = idxTwo.size() * 2;\n    int needSingles = idxOne.size();\n    if ((int)leftover.size() != needPairs + needSingles) return false;\n    vector<int> pairNodes(leftover.begin(), leftover.begin() + needPairs);\n    vector<int> singleNodes(leftover.begin() + needPairs, leftover.end());\n    vector<int> pairOrder = best_pair_sequence(pairNodes, px, py, hilb, key ^ 0xabcdefULL);\n    if (pairOrder.size() != pairNodes.size()) return false;\n    for (size_t t = 0; t < idxTwo.size(); ++t) {\n        groups[idxTwo[t]] = {pairOrder[2 * t], pairOrder[2 * t + 1]};\n        used[pairOrder[2 * t]] = used[pairOrder[2 * t + 1]] = 1;\n    }\n    for (size_t t = 0; t < idxOne.size(); ++t) {\n        groups[idxOne[t]] = {singleNodes[t]};\n        used[singleNodes[t]] = 1;\n    }\n    return true;\n}\n\n// ---------------- Size permutation helper ----------------\nvector<int> build_perm_from_size_order(const vector<int>& sizeSeq,\n                                       const vector<int>& baseG) {\n    int maxSize = *max_element(baseG.begin(), baseG.end());\n    vector<vector<int>> pos(maxSize + 1);\n    for (int i = 0; i < (int)baseG.size(); ++i) {\n        int s = baseG[i];\n        if (s > maxSize) {\n            pos.resize(s + 1);\n            maxSize = s;\n        }\n        pos[s].push_back(i);\n    }\n    for (auto &vec : pos) reverse(vec.begin(), vec.end());\n    vector<int> perm(sizeSeq.size(), -1);\n    for (int i = 0; i < (int)sizeSeq.size(); ++i) {\n        int s = sizeSeq[i];\n        if (s >= (int)pos.size() || pos[s].empty()) return {};\n        perm[i] = pos[s].back();\n        pos[s].pop_back();\n    }\n    return perm;\n}\n\n// ---------------- Main ----------------\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    auto global_start = chrono::steady_clock::now();\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) cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n\n    vector<double> px(N), py(N);\n    vector<int> ix(N), iy(N);\n    for (int i = 0; i < N; ++i) {\n        px[i] = 0.5 * (lx[i] + rx[i]);\n        py[i] = 0.5 * (ly[i] + ry[i]);\n        ix[i] = (lx[i] + rx[i]) / 2;\n        iy[i] = (ly[i] + ry[i]) / 2;\n    }\n\n    vector<long long> hilb(N);\n    for (int i = 0; i < N; ++i) hilb[i] = hilbertOrder(ix[i], iy[i], 15, 0);\n\n    vector<int> parent = build_global_parent(px, py);\n    vector<vector<int>> adj(N);\n    for (int v = 1; v < N; ++v) {\n        int p = parent[v];\n        if (p < 0 || p >= N || p == v) p = 0;\n        adj[v].push_back(p);\n        adj[p].push_back(v);\n    }\n    for (int v = 0; v < N; ++v) {\n        auto &nbr = adj[v];\n        sort(nbr.begin(), nbr.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n        nbr.erase(unique(nbr.begin(), nbr.end()), nbr.end());\n    }\n    vector<int> order_mst;\n    order_mst.reserve(N);\n    vector<char> vis(N, 0);\n    auto dfs = [&](auto self, int u, int p) -> void {\n        vis[u] = 1;\n        order_mst.push_back(u);\n        for (int v : adj[u]) if (v != p && !vis[v]) self(self, v, u);\n    };\n    for (int i = 0; i < N; ++i) if (!vis[i]) dfs(dfs, i, -1);\n\n    vector<int> base(N);\n    iota(base.begin(), base.end(), 0);\n\n    uint64_t seed = 314159265;\n    seed = seed * 1000003ULL + N;\n    seed = seed * 1000003ULL + M;\n    seed = seed * 1000003ULL + Q;\n    seed = seed * 1000003ULL + L;\n    seed = seed * 1000003ULL + W;\n    for (int i = 0; i < min(N, 20); ++i) {\n        seed = seed * 1000003ULL + (uint64_t)(ix[i] + 10001);\n        seed = seed * 1000003ULL + (uint64_t)(iy[i] + 10001);\n    }\n    mt19937 rng(static_cast<uint32_t>(seed));\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    auto hash_seq = [&](const vector<int>& seq) -> uint64_t {\n        uint64_t h = 1469598103934665603ULL;\n        for (int v : seq) {\n            h ^= (uint64_t)(v + 1000003);\n            h *= 1099511628211ULL;\n        }\n        return h;\n    };\n\n    vector<vector<int>> cityOrders;\n    vector<uint64_t> cityHashes;\n    unordered_set<uint64_t> cityHashSet;\n\n    auto add_city_order = [&](vector<int> ord) {\n        uint64_t h = hash_seq(ord);\n        if (cityHashSet.insert(h).second) {\n            cityHashes.push_back(h);\n            cityOrders.push_back(std::move(ord));\n        }\n    };\n\n    add_city_order(base);\n    {\n        vector<int> tmp = base;\n        reverse(tmp.begin(), tmp.end());\n        add_city_order(tmp);\n    }\n    add_city_order(order_mst);\n    {\n        vector<int> tmp = order_mst;\n        reverse(tmp.begin(), tmp.end());\n        add_city_order(tmp);\n    }\n    {\n        vector<int> tmp = base;\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n        add_city_order(tmp);\n        reverse(tmp.begin(), tmp.end());\n        add_city_order(tmp);\n    }\n    auto add_sorted = [&](auto cmp) {\n        vector<int> ord = base;\n        sort(ord.begin(), ord.end(), cmp);\n        add_city_order(ord);\n    };\n    add_sorted([&](int a, int b) {\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        if (iy[a] != iy[b]) return iy[a] < iy[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        if (iy[a] != iy[b]) return iy[a] < iy[b];\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] + iy[a];\n        long long kb = (long long)ix[b] + iy[b];\n        if (ka != kb) return ka < kb;\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] - iy[a];\n        long long kb = (long long)ix[b] - iy[b];\n        if (ka != kb) return ka < kb;\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    for (int iter = 0; iter < 6; ++iter) {\n        vector<int> ord = base;\n        shuffle(ord.begin(), ord.end(), rng);\n        add_city_order(ord);\n    }\n\n    vector<vector<int>> sizeOrders;\n    vector<uint64_t> sizeHashes;\n    vector<vector<int>> sizePerms;\n    unordered_set<uint64_t> sizeHashSet;\n\n    auto add_size_order = [&](vector<int> sizes) {\n        uint64_t h = hash_seq(sizes);\n        auto perm = build_perm_from_size_order(sizes, G);\n        if (perm.empty()) return;\n        if (sizeHashSet.insert(h).second) {\n            sizeHashes.push_back(h);\n            sizeOrders.push_back(std::move(sizes));\n            sizePerms.push_back(std::move(perm));\n        }\n    };\n\n    add_size_order(G);\n    {\n        vector<int> tmp = G;\n        sort(tmp.begin(), tmp.end(), greater<int>());\n        add_size_order(tmp);\n    }\n    {\n        vector<int> tmp = G;\n        sort(tmp.begin(), tmp.end());\n        add_size_order(tmp);\n    }\n    {\n        vector<int> tmp = G;\n        sort(tmp.begin(), tmp.end());\n        vector<int> alt;\n        alt.reserve(M);\n        int l = 0, r = M - 1;\n        while (l <= r) {\n            alt.push_back(tmp[r]);\n            if (l != r) alt.push_back(tmp[l]);\n            ++l; --r;\n        }\n        add_size_order(alt);\n    }\n    for (int i = 0; i < 3; ++i) {\n        vector<int> tmp = G;\n        shuffle(tmp.begin(), tmp.end(), rng);\n        add_size_order(tmp);\n    }\n\n    unordered_set<uint64_t> seenStates;\n    seenStates.reserve(4096);\n    seenStates.max_load_factor(0.7f);\n\n    vector<vector<int>> bestGroups;\n    vector<int> bestSizeOrder;\n    vector<int> bestPerm;\n    double bestCost = 1e100;\n    bool haveBest = false;\n\n    auto evaluate_candidate = [&](const vector<int>& ord, uint64_t hOrd,\n                                  const vector<int>& sizes, uint64_t hSize,\n                                  const vector<int>& perm, int mode) {\n        uint64_t key = ((hOrd ^ (hSize * 1000003ULL) ^ (uint64_t)mode * 0x9e3779b97f4a7c15ULL));\n        if (!seenStates.insert(key).second) return;\n        vector<vector<int>> groups(M);\n        bool ok = false;\n        int offset = 0;\n        if (N > 0) {\n            uint64_t mix = hOrd ^ (hSize * 911382323ULL) ^ (uint64_t)mode * 1234567ULL;\n            offset = (int)(mix % N);\n            if (offset < 0) offset += N;\n            if (mode == 0) ok = build_groups_contiguous(ord, sizes, groups);\n            else if (mode == 1) ok = build_groups_greedy(ord, offset, sizes, groups, px, py);\n            else if (mode == 2) ok = build_groups_two_phase(ord, offset, sizes, groups, px, py, hilb, mix);\n        } else ok = false;\n        if (!ok) return;\n        double total = 0.0;\n        for (int i = 0; i < M; ++i) total += group_cost(groups[i], px, py);\n        if (!haveBest || total < bestCost) {\n            haveBest = true;\n            bestCost = total;\n            bestGroups = std::move(groups);\n            bestSizeOrder = sizes;\n            bestPerm = perm;\n        }\n    };\n\n    for (size_t i = 0; i < cityOrders.size(); ++i)\n        for (size_t j = 0; j < sizeOrders.size(); ++j)\n            evaluate_candidate(cityOrders[i], cityHashes[i],\n                               sizeOrders[j], sizeHashes[j],\n                               sizePerms[j], 0);\n\n    vector<int> greedyCityIdx;\n    int limitCity = min<int>(6, cityOrders.size());\n    for (int i = 0; i < limitCity; ++i) greedyCityIdx.push_back(i);\n    for (int t = 0; t < 4 && (int)cityOrders.size() > limitCity; ++t) {\n        int idx = rng() % cityOrders.size();\n        greedyCityIdx.push_back(idx);\n    }\n    sort(greedyCityIdx.begin(), greedyCityIdx.end());\n    greedyCityIdx.erase(unique(greedyCityIdx.begin(), greedyCityIdx.end()), greedyCityIdx.end());\n\n    vector<int> greedySizeIdx;\n    int limitSize = min<int>(5, sizeOrders.size());\n    for (int i = 0; i < limitSize; ++i) greedySizeIdx.push_back(i);\n    for (int t = 0; t < 3 && (int)sizeOrders.size() > limitSize; ++t) {\n        int idx = rng() % sizeOrders.size();\n        greedySizeIdx.push_back(idx);\n    }\n    sort(greedySizeIdx.begin(), greedySizeIdx.end());\n    greedySizeIdx.erase(unique(greedySizeIdx.begin(), greedySizeIdx.end()), greedySizeIdx.end());\n\n    for (int ci : greedyCityIdx) {\n        for (int si : greedySizeIdx) {\n            evaluate_candidate(cityOrders[ci], cityHashes[ci],\n                               sizeOrders[si], sizeHashes[si],\n                               sizePerms[si], 1);\n            evaluate_candidate(cityOrders[ci], cityHashes[ci],\n                               sizeOrders[si], sizeHashes[si],\n                               sizePerms[si], 2);\n        }\n    }\n\n    if (!haveBest) {\n        vector<vector<int>> groups(M);\n        if (!build_groups_contiguous(base, G, groups)) {\n            cout << \"!\\n\";\n            for (int i = 0; i < M; ++i) {\n                cout << '\\n';\n            }\n            return 0;\n        }\n        bestGroups = groups;\n        bestSizeOrder = G;\n        bestPerm.resize(M);\n        iota(bestPerm.begin(), bestPerm.end(), 0);\n        bestCost = 0.0;\n        for (int i = 0; i < M; ++i) bestCost += group_cost(bestGroups[i], px, py);\n    }\n\n    if (bestPerm.empty()) {\n        bestPerm.resize(M);\n        iota(bestPerm.begin(), bestPerm.end(), 0);\n    }\n    if (bestSizeOrder.empty()) bestSizeOrder = G;\n\n    improve_pairs(bestGroups, bestSizeOrder, px, py, hilb, seed);\n\n    vector<vector<int>> groups = bestGroups;\n    vector<double> groupCost(M, 0.0);\n    vector<double> sum_x(M, 0.0), sum_y(M, 0.0);\n    double curCost = 0.0;\n    for (int i = 0; i < M; ++i) {\n        groupCost[i] = group_cost(groups[i], px, py);\n        curCost += groupCost[i];\n        for (int v : groups[i]) {\n            sum_x[i] += px[v];\n            sum_y[i] += py[v];\n        }\n    }\n    bestCost = curCost;\n    bestGroups = groups;\n\n    auto recompute_stats = [&](int idx) {\n        double sx = 0.0, sy = 0.0;\n        for (int v : groups[idx]) {\n            sx += px[v];\n            sy += py[v];\n        }\n        sum_x[idx] = sx;\n        sum_y[idx] = sy;\n    };\n\n    const int MAX_CLUSTER_SIZE = 8;\n\n    auto local_reassign = [&](const vector<int>& idxs) -> bool {\n        int k = idxs.size();\n        vector<int> limits(k);\n        vector<int> nodes;\n        nodes.reserve(MAX_CLUSTER_SIZE);\n        double base = 0.0;\n        for (int i = 0; i < k; ++i) {\n            int idx = idxs[i];\n            limits[i] = groups[idx].size();\n            base += groupCost[idx];\n            nodes.insert(nodes.end(), groups[idx].begin(), groups[idx].end());\n        }\n        int total = nodes.size();\n        if (total <= 1 || total > MAX_CLUSTER_SIZE) return false;\n        vector<int> order = nodes;\n        shuffle(order.begin(), order.end(), rng);\n        vector<vector<int>> cur(k), bestAssign(k);\n        vector<double> curCosts(k, 0.0), bestCosts(k, 0.0);\n        double bestVal = base - 1e-9;\n        bool improved = false;\n\n        function<void(int)> dfs_assign = [&](int pos) {\n            if (pos == total) {\n                double sum = 0.0;\n                for (int i = 0; i < k; ++i) {\n                    curCosts[i] = group_cost(cur[i], px, py);\n                    sum += curCosts[i];\n                    if (sum >= bestVal - 1e-9) return;\n                }\n                improved = true;\n                bestVal = sum;\n                bestAssign = cur;\n                bestCosts = curCosts;\n                return;\n            }\n            int node = order[pos];\n            for (int gi = 0; gi < k; ++gi) {\n                if ((int)cur[gi].size() >= limits[gi]) continue;\n                cur[gi].push_back(node);\n                dfs_assign(pos + 1);\n                cur[gi].pop_back();\n            }\n        };\n        dfs_assign(0);\n        if (!improved || bestVal >= base - 1e-9) return false;\n        double delta = bestVal - base;\n        for (int i = 0; i < k; ++i) {\n            int idx = idxs[i];\n            groups[idx] = bestAssign[i];\n            groupCost[idx] = bestCosts[i];\n            recompute_stats(idx);\n        }\n        curCost += delta;\n        if (curCost + 1e-9 < bestCost) {\n            bestCost = curCost;\n            bestGroups = groups;\n        }\n        return true;\n    };\n\n    auto try_local_reassign = [&]() -> bool {\n        if (M <= 1) return false;\n        const int attempts = 30;\n        for (int t = 0; t < attempts; ++t) {\n            int g = rng() % M;\n            int h = rng() % M;\n            if (h == g) continue;\n            vector<int> idxs = {g, h};\n            if (M >= 3 && uni01(rng) < 0.5) {\n                int j = rng() % M;\n                if (j == g || j == h) continue;\n                idxs.push_back(j);\n            }\n            sort(idxs.begin(), idxs.end());\n            idxs.erase(unique(idxs.begin(), idxs.end()), idxs.end());\n            int total = 0;\n            for (int idx : idxs) total += groups[idx].size();\n            if (total <= 1 || total > MAX_CLUSTER_SIZE) continue;\n            if (local_reassign(idxs)) return true;\n        }\n        return false;\n    };\n\n    const double TOTAL_LIMIT = 1.65;\n    auto deadline = global_start + chrono::duration<double>(TOTAL_LIMIT);\n\n    if (M > 1) {\n        for (int k = 0; k < 40 && chrono::steady_clock::now() < deadline; ++k) {\n            if (!try_local_reassign()) break;\n        }\n        const double T0 = 400.0;\n        const double T1 = 1e-3;\n        const double clusterProb = 0.15;\n\n        while (chrono::steady_clock::now() < deadline) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n            double progress = min(1.0, elapsed / TOTAL_LIMIT);\n            double temperature = T0 * pow(T1 / T0, progress);\n\n            if (uni01(rng) < clusterProb) {\n                if (try_local_reassign()) continue;\n            }\n\n            int g = rng() % M;\n            auto choose_partner = [&](int gidx) -> int {\n                if (M <= 1) return gidx;\n                if (uni01(rng) < 0.35) {\n                    int cand = rng() % (M - 1);\n                    if (cand >= gidx) ++cand;\n                    return cand;\n                }\n                double cgx = sum_x[gidx] / groups[gidx].size();\n                double cgy = sum_y[gidx] / groups[gidx].size();\n                double bestd = 1e300;\n                int best = -1;\n                int samples = min(M - 1, 10);\n                for (int t = 0; t < samples; ++t) {\n                    int cand = rng() % M;\n                    if (cand == gidx) continue;\n                    double csx = sum_x[cand] / groups[cand].size();\n                    double csy = sum_y[cand] / groups[cand].size();\n                    double dx = cgx - csx;\n                    double dy = cgy - csy;\n                    double dist = dx * dx + dy * dy;\n                    if (dist < bestd) {\n                        bestd = dist;\n                        best = cand;\n                    }\n                }\n                if (best == -1) best = (gidx + 1 + (rng() % (M - 1))) % M;\n                return best;\n            };\n            int h = choose_partner(g);\n            if (h == g) continue;\n\n            auto pick_index = [&](int grp) -> int {\n                int sz = (int)groups[grp].size();\n                if (sz <= 1) return 0;\n                if ((rng() & 1) == 0) return rng() % sz;\n                double cx = sum_x[grp] / sz;\n                double cy = sum_y[grp] / sz;\n                int bestIdx = rng() % sz;\n                double bestScore = -1.0;\n                int samples = min(sz, 6);\n                for (int t = 0; t < samples; ++t) {\n                    int idx = rng() % sz;\n                    double dx = px[groups[grp][idx]] - cx;\n                    double dy = py[groups[grp][idx]] - cy;\n                    double sc = dx * dx + dy * dy;\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestIdx = idx;\n                    }\n                }\n                return bestIdx;\n            };\n\n            if (groups[g].empty() || groups[h].empty()) continue;\n            int idx_g = pick_index(g);\n            int idx_h = pick_index(h);\n            int node_g = groups[g][idx_g];\n            int node_h = groups[h][idx_h];\n            if (node_g == node_h) continue;\n\n            swap(groups[g][idx_g], groups[h][idx_h]);\n            double newCostG = group_cost(groups[g], px, py);\n            double newCostH = group_cost(groups[h], px, py);\n            double delta = (newCostG + newCostH) - (groupCost[g] + groupCost[h]);\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-delta / max(temperature, 1e-12));\n                if (uni01(rng) < prob) accept = true;\n            }\n            if (accept) {\n                groupCost[g] = newCostG;\n                groupCost[h] = newCostH;\n                curCost += delta;\n                sum_x[g] += px[node_h] - px[node_g];\n                sum_y[g] += py[node_h] - py[node_g];\n                sum_x[h] += px[node_g] - px[node_h];\n                sum_y[h] += py[node_g] - py[node_h];\n                if (curCost + 1e-9 < bestCost) {\n                    bestCost = curCost;\n                    bestGroups = groups;\n                }\n            } else {\n                swap(groups[g][idx_g], groups[h][idx_h]);\n            }\n        }\n    }\n\n    if (M > 0) {\n        improve_pairs(groups, bestSizeOrder, px, py, hilb, seed ^ 0x777777ULL);\n        double newTotal = 0.0;\n        for (int i = 0; i < M; ++i) newTotal += group_cost(groups[i], px, py);\n        if (newTotal + 1e-9 < bestCost) {\n            bestCost = newTotal;\n            bestGroups = groups;\n        }\n    }\n\n    improve_pairs(bestGroups, bestSizeOrder, px, py, hilb, seed ^ 0x12345ULL);\n    double finalCheck = 0.0;\n    for (int i = 0; i < M; ++i) finalCheck += group_cost(bestGroups[i], px, py);\n    bestCost = finalCheck;\n\n    vector<int> invPerm(M);\n    for (int i = 0; i < M; ++i) invPerm[bestPerm[i]] = i;\n    vector<vector<int>> finalGroups(M);\n    for (int i = 0; i < M; ++i) finalGroups[i] = bestGroups[invPerm[i]];\n\n    vector<vector<pair<int,int>>> edges(M);\n    for (int i = 0; i < M; ++i) edges[i] = build_group_mst(finalGroups[i], px, py);\n\n    cout << \"!\\n\";\n    for (int i = 0; i < M; ++i) {\n        for (size_t j = 0; j < finalGroups[i].size(); ++j) {\n            if (j) cout << ' ';\n            cout << finalGroups[i][j];\n        }\n        cout << '\\n';\n        for (auto &e : edges[i]) cout << e.first << ' ' << e.second << '\\n';\n    }\n    cout.flush();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int DIRS = 4;\nconst int dr[DIRS] = {-1, 1, 0, 0};\nconst int dc[DIRS] = {0, 0, -1, 1};\nconst char dirc[DIRS] = {'U', 'D', 'L', 'R'};\n\nstruct Planner {\n    int N, B, BLOCK_NONE, TOT, chunk_max;\n    vector<int> row, col;\n    vector<array<vector<int>, DIRS>> rays;\n\n    vector<int> dist, prev_state;\n    vector<char> prev_act, prev_dir;\n    vector<int> touched;\n\n    static constexpr int PEN_BLOCK_BASE = 1;\n    static constexpr int PEN_BLOCK_DIST_DIV = 6;\n\n    Planner(int N_, int chunk_max_) : N(N_), chunk_max(chunk_max_) {\n        B = N * N;\n        BLOCK_NONE = B;\n        TOT = B * (B + 1);\n        int state_count = TOT * (chunk_max + 1);\n\n        row.resize(B);\n        col.resize(B);\n        for (int idx = 0; idx < B; ++idx) {\n            row[idx] = idx / N;\n            col[idx] = idx % N;\n        }\n\n        rays.resize(B);\n        for (int pos = 0; pos < B; ++pos) {\n            int r = row[pos], c = col[pos];\n            for (int d = 0; d < DIRS; ++d) {\n                auto &line = rays[pos][d];\n                int nr = r + dr[d], nc = c + dc[d];\n                while (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                    line.push_back(nr * N + nc);\n                    nr += dr[d];\n                    nc += dc[d];\n                }\n            }\n        }\n\n        dist.assign(state_count, -1);\n        prev_state.assign(state_count, -1);\n        prev_act.assign(state_count, 0);\n        prev_dir.assign(state_count, 0);\n        touched.reserve(state_count);\n    }\n\n    int penalty_for_state(int state, int prog, const vector<int>& next_after) const {\n        int rem = state % TOT;\n        int block = rem % (B + 1);\n        if (block == BLOCK_NONE) return 0;\n        if (prog >= (int)next_after.size()) return PEN_BLOCK_BASE;\n        int penalty = PEN_BLOCK_BASE;\n        int nxt = next_after[prog];\n        if (nxt != -1) {\n            int dist_to_next = abs(row[block] - row[nxt]) + abs(col[block] - col[nxt]);\n            penalty += dist_to_next / PEN_BLOCK_DIST_DIV;\n        }\n        return penalty;\n    }\n\n    bool run_chunk(int chunk_len, int start_pos, int start_block,\n                   const vector<int>& targets, const vector<int>& next_after,\n                   vector<pair<char, char>>& seq,\n                   int& end_block, int& achieved_len) {\n        seq.clear();\n        achieved_len = 0;\n        if (chunk_len <= 0) {\n            end_block = start_block;\n            return true;\n        }\n\n        queue<int> q;\n        touched.clear();\n        auto state_id = [&](int prog, int pos, int block) -> int {\n            return prog * TOT + pos * (B + 1) + block;\n        };\n\n        vector<int> best_state(chunk_len + 1, -1);\n\n        int start_state = state_id(0, start_pos, start_block);\n        q.push(start_state);\n        touched.push_back(start_state);\n        dist[start_state] = 0;\n        prev_state[start_state] = -1;\n\n        while (!q.empty()) {\n            int st = q.front();\n            q.pop();\n            int prog = st / TOT;\n            if (prog > chunk_len) continue;\n\n            if (prog > 0 && best_state[prog] == -1) {\n                best_state[prog] = st;\n                if (prog == chunk_len) break;\n            }\n            if (prog == chunk_len) continue;\n\n            int rem = st % TOT;\n            int pos = rem / (B + 1);\n            int block = rem % (B + 1);\n            int r = row[pos], c = col[pos];\n            int block_idx = (block == BLOCK_NONE ? -1 : block);\n\n            auto push_state = [&](int npos, int nblock, bool can_visit,\n                                  char act, char dir) {\n                int nprog = prog;\n                if (can_visit && nprog < chunk_len && npos == targets[nprog]) {\n                    ++nprog;\n                }\n                int nid = state_id(nprog, npos, nblock);\n                if (dist[nid] != -1) return;\n                dist[nid] = dist[st] + 1;\n                prev_state[nid] = st;\n                prev_act[nid] = act;\n                prev_dir[nid] = dir;\n                q.push(nid);\n                touched.push_back(nid);\n            };\n\n            // Move\n            for (int d = 0; d < DIRS; ++d) {\n                int nr = r + dr[d], nc = c + dc[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int npos = nr * N + nc;\n                if (block_idx == npos) continue;\n                push_state(npos, block, true, 'M', dirc[d]);\n            }\n\n            // Slide\n            for (int d = 0; d < DIRS; ++d) {\n                const auto &line = rays[pos][d];\n                if (line.empty()) continue;\n                int dest = -1;\n                if (block_idx == -1) {\n                    dest = line.back();\n                } else {\n                    int prev_cell = pos;\n                    bool hit = false;\n                    for (int cell : line) {\n                        if (cell == block_idx) {\n                            hit = true;\n                            dest = (prev_cell == pos) ? -1 : prev_cell;\n                            break;\n                        }\n                        prev_cell = cell;\n                    }\n                    if (hit && dest == -1) continue;\n                    if (!hit) dest = line.back();\n                }\n                if (dest == -1 || dest == pos) continue;\n                push_state(dest, block, true, 'S', dirc[d]);\n            }\n\n            // Alter\n            for (int d = 0; d < DIRS; ++d) {\n                int ar = r + dr[d], ac = c + dc[d];\n                if (ar < 0 || ar >= N || ac < 0 || ac >= N) continue;\n                int adj = ar * N + ac;\n                if (block == BLOCK_NONE) {\n                    push_state(pos, adj, false, 'A', dirc[d]);\n                } else if (block_idx == adj) {\n                    push_state(pos, BLOCK_NONE, false, 'A', dirc[d]);\n                }\n            }\n        }\n\n        int chosen_len = 0;\n        int chosen_state = -1;\n        long long chosen_eff = LLONG_MAX;\n        int chosen_penalty = INT_MAX;\n\n        for (int k = 1; k <= chunk_len; ++k) {\n            if (best_state[k] == -1) continue;\n            int state = best_state[k];\n            int d = dist[state];\n            int penalty = penalty_for_state(state, k, next_after);\n            int effective = d + penalty;\n            if (chosen_len == 0) {\n                chosen_len = k;\n                chosen_state = state;\n                chosen_eff = effective;\n                chosen_penalty = penalty;\n                continue;\n            }\n            long long lhs = 1LL * effective * chosen_len;\n            long long rhs = chosen_eff * k;\n            if (lhs < rhs ||\n                (lhs == rhs && (k > chosen_len ||\n                                (k == chosen_len &&\n                                 (effective < chosen_eff ||\n                                  (effective == chosen_eff &&\n                                   penalty < chosen_penalty)))))) {\n                chosen_len = k;\n                chosen_state = state;\n                chosen_eff = effective;\n                chosen_penalty = penalty;\n            }\n        }\n\n        if (chosen_len == 0) {\n            for (int id : touched) dist[id] = -1;\n            touched.clear();\n            return false;\n        }\n\n        vector<pair<char, char>> rev;\n        for (int cur = chosen_state; cur != start_state; cur = prev_state[cur]) {\n            rev.emplace_back(prev_act[cur], prev_dir[cur]);\n        }\n        reverse(rev.begin(), rev.end());\n        seq = move(rev);\n\n        int rem = chosen_state % TOT;\n        end_block = rem % (B + 1);\n        achieved_len = chosen_len;\n\n        for (int id : touched) dist[id] = -1;\n        touched.clear();\n        return true;\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>> pts(M);\n    for (int i = 0; i < M; ++i) cin >> pts[i].first >> pts[i].second;\n\n    const int LIMIT = 2 * N * M;\n    const int CHUNK_MAX = 7;\n\n    Planner planner(N, CHUNK_MAX);\n\n    vector<int> idx(M);\n    for (int i = 0; i < M; ++i) idx[i] = pts[i].first * N + pts[i].second;\n\n    vector<pair<char,char>> answer;\n    answer.reserve(LIMIT);\n    vector<pair<char,char>> segment;\n    vector<int> chunk_targets;\n    vector<int> next_after;\n\n    int current_idx = 0;\n    int block_state = planner.BLOCK_NONE;\n\n    while (current_idx < M - 1 && (int)answer.size() < LIMIT) {\n        int remaining = (M - 1) - current_idx;\n        int chunk_len = min(CHUNK_MAX, remaining);\n\n        chunk_targets.clear();\n        for (int t = 1; t <= chunk_len; ++t) {\n            chunk_targets.push_back(idx[current_idx + t]);\n        }\n\n        next_after.assign(chunk_len + 1, -1);\n        for (int k = 1; k <= chunk_len; ++k) {\n            int global_idx = current_idx + k + 1;\n            if (global_idx < M) next_after[k] = idx[global_idx];\n        }\n\n        int used_len = 0;\n        int next_block = block_state;\n        bool ok = planner.run_chunk(chunk_len, idx[current_idx], block_state,\n                                    chunk_targets, next_after,\n                                    segment, next_block, used_len);\n\n        if (!ok || used_len == 0) {\n            // Fallback: force a single target chunk (should rarely happen)\n            chunk_targets.assign(1, idx[current_idx + 1]);\n            next_after.assign(2, -1);\n            if (current_idx + 2 < M) next_after[1] = idx[current_idx + 2];\n            ok = planner.run_chunk(1, idx[current_idx], block_state,\n                                   chunk_targets, next_after,\n                                   segment, next_block, used_len);\n            if (!ok || used_len == 0) break;\n        }\n\n        if ((int)answer.size() + (int)segment.size() > LIMIT) break;\n\n        answer.insert(answer.end(), segment.begin(), segment.end());\n        block_state = next_block;\n        current_idx += used_len;\n    }\n\n    for (auto [a, d] : answer) {\n        cout << a << ' ' << d << '\\n';\n    }\n    return 0;\n}"},"16":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Rect {\n    int x1, y1, x2, y2;\n};\n\nconst int BOARD_SIZE = 10000;\nconst int GROW_ITER_PER_RECT = 20;\nconst int SHRINK_ITER_PER_RECT = 12;\nconst int EXPAND_STEP_LIMIT = 5000;\nconst int SHRINK_STEP_LIMIT = 5000;\nconst int RANDOM_SHRINK_STEP_LIMIT = 120;\nconst int STAGNATION_LIMIT = 28;\n\nlong long rect_area(const Rect &r) {\n    return 1LL * (r.x2 - r.x1) * (r.y2 - r.y1);\n}\n\ndouble single_score_from_area(long long s, long long r) {\n    if (s <= 0 || r <= 0) return 0.0;\n    long long mn = min(s, r);\n    long long mx = max(s, r);\n    double ratio = (double)mn / (double)mx;\n    return 2.0 * ratio - ratio * ratio;\n}\n\narray<int, 4> compute_expand_limits(const vector<Rect> &rects, int idx) {\n    const Rect &ri = rects[idx];\n    array<int, 4> lim = {ri.x1, BOARD_SIZE - ri.x2, ri.y1, BOARD_SIZE - ri.y2};\n    int n = rects.size();\n    for (int j = 0; j < n; ++j) if (j != idx) {\n        const Rect &rj = rects[j];\n        bool overlapY = (ri.y1 < rj.y2) && (ri.y2 > rj.y1);\n        bool overlapX = (ri.x1 < rj.x2) && (ri.x2 > rj.x1);\n        if (overlapY) {\n            if (rj.x2 <= ri.x1) lim[0] = min(lim[0], max(0, ri.x1 - rj.x2));\n            if (rj.x1 >= ri.x2) lim[1] = min(lim[1], max(0, rj.x1 - ri.x2));\n        }\n        if (overlapX) {\n            if (rj.y2 <= ri.y1) lim[2] = min(lim[2], max(0, ri.y1 - rj.y2));\n            if (rj.y1 >= ri.y2) lim[3] = min(lim[3], max(0, rj.y1 - ri.y2));\n        }\n    }\n    for (int d = 0; d < 4; ++d) lim[d] = max(lim[d], 0);\n    return lim;\n}\n\nbool grow_rect(int idx, vector<Rect> &rects, const vector<int> &target, mt19937 &rng) {\n    bool changed = false;\n    for (int iter = 0; iter < GROW_ITER_PER_RECT; ++iter) {\n        Rect &rc = rects[idx];\n        long long width = rc.x2 - rc.x1;\n        long long height = rc.y2 - rc.y1;\n        long long area = width * height;\n        long long deficit = (long long)target[idx] - area;\n        if (deficit <= 0) break;\n\n        auto lim = compute_expand_limits(rects, idx);\n        long long unit[4] = {height, height, width, width};\n\n        double bestScore = -1;\n        vector<int> dirs;\n        for (int dir = 0; dir < 4; ++dir) {\n            if (lim[dir] <= 0 || unit[dir] <= 0) continue;\n            long long potential = 1LL * lim[dir] * unit[dir];\n            long long effective = min(deficit, potential);\n            if (effective <= 0) continue;\n            double score = (double)effective;\n            if (score > bestScore + 1e-9) {\n                bestScore = score;\n                dirs.clear();\n                dirs.push_back(dir);\n            } else if (fabs(score - bestScore) <= 1e-9) {\n                dirs.push_back(dir);\n            }\n        }\n        if (dirs.empty()) break;\n        int dir = dirs[rng() % dirs.size()];\n        long long u = unit[dir];\n        long long need = (deficit + u - 1) / u;\n        long long limit = min<long long>(lim[dir], EXPAND_STEP_LIMIT);\n        if (limit <= 0) break;\n        long long w = max(1LL, min(limit, need));\n        if (dir == 0) rc.x1 -= (int)w;\n        else if (dir == 1) rc.x2 += (int)w;\n        else if (dir == 2) rc.y1 -= (int)w;\n        else rc.y2 += (int)w;\n        changed = true;\n    }\n    return changed;\n}\n\nbool shrink_rect(int idx, vector<Rect> &rects, const vector<int> &target,\n                 const vector<int> &xs, const vector<int> &ys, mt19937 &rng) {\n    bool changed = false;\n    for (int iter = 0; iter < SHRINK_ITER_PER_RECT; ++iter) {\n        Rect &rc = rects[idx];\n        long long width = rc.x2 - rc.x1;\n        long long height = rc.y2 - rc.y1;\n        long long area = width * height;\n        long long surplus = area - (long long)target[idx];\n        if (surplus <= 0) break;\n\n        int avail[4] = {\n            xs[idx] - rc.x1,\n            rc.x2 - (xs[idx] + 1),\n            ys[idx] - rc.y1,\n            rc.y2 - (ys[idx] + 1)\n        };\n        long long unit[4] = {height, height, width, width};\n\n        double bestScore = -1;\n        vector<int> dirs;\n        for (int dir = 0; dir < 4; ++dir) {\n            if (avail[dir] <= 0 || unit[dir] <= 0) continue;\n            long long potential = 1LL * avail[dir] * unit[dir];\n            long long effective = min(surplus, potential);\n            if (effective <= 0) continue;\n            double score = (double)effective;\n            if (score > bestScore + 1e-9) {\n                bestScore = score;\n                dirs.clear();\n                dirs.push_back(dir);\n            } else if (fabs(score - bestScore) <= 1e-9) {\n                dirs.push_back(dir);\n            }\n        }\n        if (dirs.empty()) break;\n        int dir = dirs[rng() % dirs.size()];\n        long long u = unit[dir];\n        long long need = (surplus + u - 1) / u;\n        long long limit = min<long long>(avail[dir], SHRINK_STEP_LIMIT);\n        if (limit <= 0) break;\n        long long w = max(1LL, min(limit, need));\n        if (dir == 0) rc.x1 += (int)w;\n        else if (dir == 1) rc.x2 -= (int)w;\n        else if (dir == 2) rc.y1 += (int)w;\n        else rc.y2 -= (int)w;\n        changed = true;\n    }\n    return changed;\n}\n\nbool shrink_phase(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                  const vector<int> &target, mt19937 &rng) {\n    int n = rects.size();\n    vector<pair<long long, int>> overs;\n    overs.reserve(n);\n    for (int i = 0; i < n; ++i) {\n        long long def = rect_area(rects[i]) - (long long)target[i];\n        if (def > 0) overs.emplace_back(def, i);\n    }\n    sort(overs.begin(), overs.end(), greater<>());\n    bool changed = false;\n    for (auto &p : overs) {\n        if (shrink_rect(p.second, rects, target, xs, ys, rng)) changed = true;\n    }\n    return changed;\n}\n\nbool random_shrink(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                   const vector<int> &target, mt19937 &rng,\n                   int operations, bool prefer_surplus) {\n    int n = rects.size();\n    if (operations <= 0 || n == 0) return false;\n    vector<int> pool;\n    pool.reserve(n);\n    if (prefer_surplus) {\n        for (int i = 0; i < n; ++i)\n            if (rect_area(rects[i]) > (long long)target[i]) pool.push_back(i);\n    }\n    if (pool.empty()) {\n        pool.resize(n);\n        iota(pool.begin(), pool.end(), 0);\n    }\n    bool changed = false;\n    for (int t = 0; t < operations; ++t) {\n        int idx = pool[rng() % pool.size()];\n        Rect &rc = rects[idx];\n        int avail[4] = {\n            xs[idx] - rc.x1,\n            rc.x2 - (xs[idx] + 1),\n            ys[idx] - rc.y1,\n            rc.y2 - (ys[idx] + 1)\n        };\n        vector<int> dirs;\n        for (int d = 0; d < 4; ++d) if (avail[d] > 0) dirs.push_back(d);\n        if (dirs.empty()) continue;\n        int dir = dirs[rng() % dirs.size()];\n        int cap = min(avail[dir], RANDOM_SHRINK_STEP_LIMIT);\n        if (cap <= 0) continue;\n        int amount = 1 + (cap > 1 ? rng() % cap : 0);\n        if (dir == 0) rc.x1 += amount;\n        else if (dir == 1) rc.x2 -= amount;\n        else if (dir == 2) rc.y1 += amount;\n        else rc.y2 -= amount;\n        changed = true;\n    }\n    return changed;\n}\n\ndouble compute_score(const vector<Rect> &rects, const vector<int> &target) {\n    double sum = 0.0;\n    for (int i = 0; i < (int)rects.size(); ++i)\n        sum += single_score_from_area(rect_area(rects[i]), target[i]);\n    return sum;\n}\n\nbool validate_rects(const vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys) {\n    int n = rects.size();\n    for (int i = 0; i < n; ++i) {\n        const Rect &r = rects[i];\n        if (r.x1 < 0 || r.x1 >= r.x2 || r.x2 > BOARD_SIZE) return false;\n        if (r.y1 < 0 || r.y1 >= r.y2 || r.y2 > BOARD_SIZE) return false;\n        if (!(r.x1 <= xs[i] && xs[i] + 1 <= r.x2)) return false;\n        if (!(r.y1 <= ys[i] && ys[i] + 1 <= r.y2)) return false;\n    }\n    for (int i = 0; i < n; ++i)\n        for (int j = i + 1; j < n; ++j) {\n            const Rect &a = rects[i];\n            const Rect &b = rects[j];\n            if (max(a.x1, b.x1) < min(a.x2, b.x2) &&\n                max(a.y1, b.y1) < min(a.y2, b.y2)) return false;\n        }\n    return true;\n}\n\nbool reset_worst(vector<Rect> &rects, const vector<Rect> &base_rects,\n                 const vector<int> &target, int count) {\n    int n = rects.size();\n    if (count <= 0) return false;\n    vector<pair<double, int>> order;\n    order.reserve(n);\n    for (int i = 0; i < n; ++i)\n        order.emplace_back(single_score_from_area(rect_area(rects[i]), target[i]), i);\n    sort(order.begin(), order.end(), [&](const auto &a, const auto &b) {\n        if (fabs(a.first - b.first) > 1e-9) return a.first < b.first;\n        long long da = llabs(rect_area(rects[a.second]) - (long long)target[a.second]);\n        long long db = llabs(rect_area(rects[b.second]) - (long long)target[b.second]);\n        if (da != db) return da > db;\n        return a.second < b.second;\n    });\n    bool changed = false;\n    count = min(count, n);\n    for (int k = 0; k < count; ++k) {\n        int idx = order[k].second;\n        if (rects[idx].x1 == base_rects[idx].x1 &&\n            rects[idx].x2 == base_rects[idx].x2 &&\n            rects[idx].y1 == base_rects[idx].y1 &&\n            rects[idx].y2 == base_rects[idx].y2) continue;\n        rects[idx] = base_rects[idx];\n        changed = true;\n    }\n    return changed;\n}\n\nbool vertical_move(vector<Rect> &rects, vector<long long> &areas,\n                   const vector<int> &xs, const vector<int> &target,\n                   int left, int right, bool left_gets) {\n    long long height = rects[left].y2 - rects[left].y1;\n    if (height <= 0) return false;\n    int maxUnits;\n    if (left_gets) {\n        int limit_point = xs[right] - rects[right].x1;\n        int limit_width = rects[right].x2 - rects[right].x1 - 1;\n        maxUnits = min(limit_point, limit_width);\n    } else {\n        int limit_point_left = rects[left].x2 - (xs[left] + 1);\n        int limit_width_left = rects[left].x2 - rects[left].x1 - 1;\n        int limit_right_expand = rects[right].x1;\n        maxUnits = min({limit_point_left, limit_width_left, limit_right_expand});\n    }\n    if (maxUnits <= 0) return false;\n\n    vector<int> cand = {1, maxUnits};\n    long long diff = left_gets ? ((long long)target[left] - areas[left])\n                               : (areas[left] - (long long)target[left]);\n    if (diff < 0) diff = 0;\n    long long approx = height > 0 ? diff / height : 0;\n    if (approx > 0)\n        cand.push_back((int)min<long long>(maxUnits, max<long long>(1, approx)));\n    if (approx + 1 <= maxUnits)\n        cand.push_back((int)min<long long>(maxUnits, approx + 1));\n    if (maxUnits >= 3) cand.push_back(maxUnits / 3);\n    if (maxUnits >= 2) cand.push_back((maxUnits + 1) / 2);\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n    double baseScore = single_score_from_area(areas[left], target[left]) +\n                       single_score_from_area(areas[right], target[right]);\n    double bestDelta = 1e-12;\n    int bestUnits = 0;\n    for (int units : cand) {\n        if (units <= 0 || units > maxUnits) continue;\n        long long delta = 1LL * units * height;\n        long long newL = left_gets ? areas[left] + delta : areas[left] - delta;\n        long long newR = left_gets ? areas[right] - delta : areas[right] + delta;\n        if (newL <= 0 || newR <= 0) continue;\n        double newScore = single_score_from_area(newL, target[left]) +\n                          single_score_from_area(newR, target[right]);\n        double diffScore = newScore - baseScore;\n        if (diffScore > bestDelta) {\n            bestDelta = diffScore;\n            bestUnits = units;\n        }\n    }\n    if (bestUnits > 0) {\n        long long delta = 1LL * bestUnits * height;\n        if (left_gets) {\n            rects[left].x2 += bestUnits;\n            rects[right].x1 += bestUnits;\n            areas[left] += delta;\n            areas[right] -= delta;\n        } else {\n            rects[left].x2 -= bestUnits;\n            rects[right].x1 -= bestUnits;\n            areas[left] -= delta;\n            areas[right] += delta;\n        }\n        return true;\n    }\n    return false;\n}\n\nbool horizontal_move(vector<Rect> &rects, vector<long long> &areas,\n                     const vector<int> &ys, const vector<int> &target,\n                     int bottom, int top, bool bottom_gets) {\n    long long width = rects[bottom].x2 - rects[bottom].x1;\n    if (width <= 0) return false;\n    int maxUnits;\n    if (bottom_gets) {\n        int limit_point = ys[top] - rects[top].y1;\n        int limit_height = rects[top].y2 - rects[top].y1 - 1;\n        maxUnits = min(limit_point, limit_height);\n    } else {\n        int limit_point_bottom = rects[bottom].y2 - (ys[bottom] + 1);\n        int limit_height_bottom = rects[bottom].y2 - rects[bottom].y1 - 1;\n        int limit_top_expand = rects[top].y1;\n        maxUnits = min({limit_point_bottom, limit_height_bottom, limit_top_expand});\n    }\n    if (maxUnits <= 0) return false;\n\n    vector<int> cand = {1, maxUnits};\n    long long diff = bottom_gets ? ((long long)target[bottom] - areas[bottom])\n                                 : (areas[bottom] - (long long)target[bottom]);\n    if (diff < 0) diff = 0;\n    long long approx = width > 0 ? diff / width : 0;\n    if (approx > 0)\n        cand.push_back((int)min<long long>(maxUnits, max<long long>(1, approx)));\n    if (approx + 1 <= maxUnits)\n        cand.push_back((int)min<long long>(maxUnits, approx + 1));\n    if (maxUnits >= 3) cand.push_back(maxUnits / 3);\n    if (maxUnits >= 2) cand.push_back((maxUnits + 1) / 2);\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n    double baseScore = single_score_from_area(areas[bottom], target[bottom]) +\n                       single_score_from_area(areas[top], target[top]);\n    double bestDelta = 1e-12;\n    int bestUnits = 0;\n    for (int units : cand) {\n        if (units <= 0 || units > maxUnits) continue;\n        long long delta = 1LL * units * width;\n        long long newB = bottom_gets ? areas[bottom] + delta : areas[bottom] - delta;\n        long long newT = bottom_gets ? areas[top] - delta : areas[top] + delta;\n        if (newB <= 0 || newT <= 0) continue;\n        double newScore = single_score_from_area(newB, target[bottom]) +\n                          single_score_from_area(newT, target[top]);\n        double diffScore = newScore - baseScore;\n        if (diffScore > bestDelta) {\n            bestDelta = diffScore;\n            bestUnits = units;\n        }\n    }\n    if (bestUnits > 0) {\n        long long delta = 1LL * bestUnits * width;\n        if (bottom_gets) {\n            rects[bottom].y2 += bestUnits;\n            rects[top].y1 += bestUnits;\n            areas[bottom] += delta;\n            areas[top] -= delta;\n        } else {\n            rects[bottom].y2 -= bestUnits;\n            rects[top].y1 -= bestUnits;\n            areas[bottom] -= delta;\n            areas[top] += delta;\n        }\n        return true;\n    }\n    return false;\n}\n\nbool boundary_balance(vector<Rect> &rects, const vector<int> &xs, const vector<int> &ys,\n                      const vector<int> &target, mt19937 &rng, int rounds = 3) {\n    int n = rects.size();\n    if (n <= 1) return false;\n    vector<long long> areas(n);\n    vector<long long> deficit(n);\n    for (int i = 0; i < n; ++i) {\n        areas[i] = rect_area(rects[i]);\n        deficit[i] = (long long)target[i] - areas[i];\n    }\n    struct VEdge { int L, R; };\n    struct HEdge { int B, T; };\n    bool changed = false;\n    for (int round = 0; round < rounds; ++round) {\n        vector<VEdge> vEdges;\n        vector<HEdge> hEdges;\n        for (int i = 0; i < n; ++i) for (int j = i + 1; j < n; ++j) {\n            if (rects[i].y1 == rects[j].y1 && rects[i].y2 == rects[j].y2) {\n                if (rects[i].x2 == rects[j].x1) vEdges.push_back({i, j});\n                else if (rects[j].x2 == rects[i].x1) vEdges.push_back({j, i});\n            }\n            if (rects[i].x1 == rects[j].x1 && rects[i].x2 == rects[j].x2) {\n                if (rects[i].y2 == rects[j].y1) hEdges.push_back({i, j});\n                else if (rects[j].y2 == rects[i].y1) hEdges.push_back({j, i});\n            }\n        }\n        if (vEdges.empty() && hEdges.empty()) break;\n\n        auto process_vertical = [&]() -> bool {\n            if (vEdges.empty()) return false;\n            vector<int> order(vEdges.size());\n            iota(order.begin(), order.end(), 0);\n            shuffle(order.begin(), order.end(), rng);\n            auto priority = [&](int idx) -> long long {\n                auto &e = vEdges[idx];\n                long long need1 = max(0LL, deficit[e.L]) * max(0LL, -deficit[e.R]);\n                long long need2 = max(0LL, deficit[e.R]) * max(0LL, -deficit[e.L]);\n                return max(need1, need2);\n            };\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                long long pa = priority(a);\n                long long pb = priority(b);\n                if (pa != pb) return pa > pb;\n                return a < b;\n            });\n            bool local = false;\n            for (int idx : order) {\n                auto &e = vEdges[idx];\n                if (deficit[e.L] > 0 && deficit[e.R] < 0) {\n                    if (vertical_move(rects, areas, xs, target, e.L, e.R, true)) {\n                        deficit[e.L] = (long long)target[e.L] - areas[e.L];\n                        deficit[e.R] = (long long)target[e.R] - areas[e.R];\n                        local = true;\n                    }\n                }\n                if (deficit[e.L] < 0 && deficit[e.R] > 0) {\n                    if (vertical_move(rects, areas, xs, target, e.L, e.R, false)) {\n                        deficit[e.L] = (long long)target[e.L] - areas[e.L];\n                        deficit[e.R] = (long long)target[e.R] - areas[e.R];\n                        local = true;\n                    }\n                }\n            }\n            return local;\n        };\n\n        auto process_horizontal = [&]() -> bool {\n            if (hEdges.empty()) return false;\n            vector<int> order(hEdges.size());\n            iota(order.begin(), order.end(), 0);\n            shuffle(order.begin(), order.end(), rng);\n            auto priority = [&](int idx) -> long long {\n                auto &e = hEdges[idx];\n                long long need1 = max(0LL, deficit[e.B]) * max(0LL, -deficit[e.T]);\n                long long need2 = max(0LL, deficit[e.T]) * max(0LL, -deficit[e.B]);\n                return max(need1, need2);\n            };\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                long long pa = priority(a);\n                long long pb = priority(b);\n                if (pa != pb) return pa > pb;\n                return a < b;\n            });\n            bool local = false;\n            for (int idx : order) {\n                auto &e = hEdges[idx];\n                if (deficit[e.B] > 0 && deficit[e.T] < 0) {\n                    if (horizontal_move(rects, areas, ys, target, e.B, e.T, true)) {\n                        deficit[e.B] = (long long)target[e.B] - areas[e.B];\n                        deficit[e.T] = (long long)target[e.T] - areas[e.T];\n                        local = true;\n                    }\n                }\n                if (deficit[e.B] < 0 && deficit[e.T] > 0) {\n                    if (horizontal_move(rects, areas, ys, target, e.B, e.T, false)) {\n                        deficit[e.B] = (long long)target[e.B] - areas[e.B];\n                        deficit[e.T] = (long long)target[e.T] - areas[e.T];\n                        local = true;\n                    }\n                }\n            }\n            return local;\n        };\n\n        bool roundChanged = false;\n        roundChanged |= process_vertical();\n        roundChanged |= process_horizontal();\n        if (!roundChanged) break;\n        changed = true;\n    }\n    return changed;\n}\n\nvector<Rect> build_initial_rects_randomized(const vector<int> &xs, const vector<int> &ys,\n                                            const vector<int> &rs, mt19937 &rng,\n                                            double noise_strength);\n\nstruct AttemptResult {\n    vector<Rect> rects;\n    double score;\n};\n\nAttemptResult run_attempt(const vector<Rect> &start_rects, const vector<Rect> &base_rects,\n                          const vector<int> &xs, const vector<int> &ys,\n                          const vector<int> &target, mt19937 &rng,\n                          chrono::steady_clock::time_point deadline) {\n    vector<Rect> rects = start_rects;\n    vector<Rect> best_rect = rects;\n    double best_score = compute_score(rects, target);\n    int n = rects.size();\n    vector<long long> defs(n);\n    int stagnation = 0;\n    int pass = 0;\n\n    while (true) {\n        if ((pass & 7) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n        for (int i = 0; i < n; ++i) defs[i] = (long long)target[i] - rect_area(rects[i]);\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (defs[a] != defs[b]) return defs[a] > defs[b];\n            return a < b;\n        });\n\n        bool changedExp = false;\n        for (int idx : order) if (grow_rect(idx, rects, target, rng)) changedExp = true;\n        bool changedShrink = shrink_phase(rects, xs, ys, target, rng);\n        bool changed = changedExp || changedShrink;\n\n        if (!changed) {\n            stagnation++;\n            if (stagnation % 4 == 0) {\n                int ops = max(1, n / 3);\n                if (random_shrink(rects, xs, ys, target, rng, ops, true)) {\n                    changed = true;\n                    stagnation = max(0, stagnation - 2);\n                }\n            }\n            if (!changed && stagnation > STAGNATION_LIMIT) {\n                int batch = max(1, n / 8);\n                if (reset_worst(rects, base_rects, target, batch)) {\n                    stagnation = 0;\n                    pass++;\n                    continue;\n                } else {\n                    rects = best_rect;\n                    random_shrink(rects, xs, ys, target, rng, max(1, n / 2), false);\n                    stagnation = 0;\n                    pass++;\n                    continue;\n                }\n            }\n        } else stagnation = 0;\n\n        double cur_score = compute_score(rects, target);\n        if (cur_score > best_score + 1e-9) {\n            best_score = cur_score;\n            best_rect = rects;\n        }\n        pass++;\n        if (chrono::steady_clock::now() >= deadline) break;\n    }\n\n    if (boundary_balance(rects, xs, ys, target, rng, 3)) {\n        double sc = compute_score(rects, target);\n        if (sc > best_score + 1e-9) {\n            best_score = sc;\n            best_rect = rects;\n        }\n    }\n    return {best_rect, best_score};\n}\n\nvector<Rect> build_initial_rects_randomized(const vector<int> &xs, const vector<int> &ys,\n                                            const vector<int> &rs, mt19937 &rng,\n                                            double noise_strength) {\n    int n = xs.size();\n    vector<Rect> res(n);\n    uniform_real_distribution<double> uni(0.0, 1.0);\n    function<void(const vector<int>&, int, int, int, int)> dfs =\n        [&](const vector<int> &idxs, int x1, int y1, int x2, int y2) {\n            if (idxs.empty()) return;\n            if (idxs.size() == 1) {\n                res[idxs[0]] = {x1, y1, x2, y2};\n                return;\n            }\n            long long total = 0;\n            for (int id : idxs) total += rs[id];\n            int width = x2 - x1;\n            int height = y2 - y1;\n\n            auto attempt_split = [&](bool useX) -> bool {\n                if (useX ? width < 2 : height < 2) return false;\n                vector<int> order = idxs;\n                if (useX) {\n                    sort(order.begin(), order.end(), [&](int a, int b) {\n                        if (xs[a] != xs[b]) return xs[a] < xs[b];\n                        return ys[a] < ys[b];\n                    });\n                } else {\n                    sort(order.begin(), order.end(), [&](int a, int b) {\n                        if (ys[a] != ys[b]) return ys[a] < ys[b];\n                        return xs[a] < xs[b];\n                    });\n                }\n                vector<long long> pref(order.size() + 1, 0);\n                for (int i = 0; i < (int)order.size(); ++i) pref[i + 1] = pref[i] + rs[order[i]];\n                double ratio_target = 0.5;\n                if (noise_strength > 1e-9) {\n                    double val = (uni(rng) - 0.5) * 2.0;\n                    ratio_target += val * 0.15 * noise_strength;\n                    ratio_target = min(0.85, max(0.15, ratio_target));\n                }\n                long long desired_sum = (long long)llround(total * ratio_target);\n                desired_sum = max(1LL, min(total - 1, desired_sum));\n                int cut = int(lower_bound(pref.begin(), pref.end(), desired_sum) - pref.begin());\n                if (cut <= 0 || cut >= (int)order.size()) cut = (int)order.size() / 2;\n                long long sum_left = pref[cut];\n                if (sum_left == 0 || sum_left == total) return false;\n                vector<int> left(order.begin(), order.begin() + cut);\n                vector<int> right(order.begin() + cut, order.end());\n                if (useX) {\n                    int max_left = -1, min_right = BOARD_SIZE + 1;\n                    for (int id : left) max_left = max(max_left, xs[id]);\n                    for (int id : right) min_right = min(min_right, xs[id]);\n                    int low = max(x1 + 1, max_left + 1);\n                    int high = min(x2 - 1, min_right);\n                    if (low > high) return false;\n                    long double ratio = (long double)sum_left / total;\n                    if (noise_strength > 1e-9) {\n                        double jitter = (uni(rng) - 0.5) * 2.0 * 0.25 * noise_strength;\n                        ratio = min(0.9L, max(0.1L, ratio + jitter));\n                    }\n                    int desired = x1 + (int)llround(width * ratio);\n                    desired = min(max(desired, low), high);\n                    dfs(left, x1, y1, desired, y2);\n                    dfs(right, desired, y1, x2, y2);\n                } else {\n                    int max_left = -1, min_right = BOARD_SIZE + 1;\n                    for (int id : left) max_left = max(max_left, ys[id]);\n                    for (int id : right) min_right = min(min_right, ys[id]);\n                    int low = max(y1 + 1, max_left + 1);\n                    int high = min(y2 - 1, min_right);\n                    if (low > high) return false;\n                    long double ratio = (long double)sum_left / total;\n                    if (noise_strength > 1e-9) {\n                        double jitter = (uni(rng) - 0.5) * 2.0 * 0.25 * noise_strength;\n                        ratio = min(0.9L, max(0.1L, ratio + jitter));\n                    }\n                    int desired = y1 + (int)llround(height * ratio);\n                    desired = min(max(desired, low), high);\n                    dfs(left, x1, y1, x2, desired);\n                    dfs(right, x1, desired, x2, y2);\n                }\n                return true;\n            };\n\n            bool axis = (width >= height);\n            if (noise_strength > 1e-9) {\n                double flip_prob = min(0.35, 0.1 + 0.25 * noise_strength);\n                if (uni(rng) < flip_prob) axis = !axis;\n            }\n            if (attempt_split(axis)) return;\n            if (attempt_split(!axis)) return;\n            if (attempt_split(true)) return;\n            if (attempt_split(false)) return;\n\n            for (int id : idxs)\n                res[id] = {xs[id], ys[id], xs[id] + 1, ys[id] + 1};\n        };\n\n    vector<int> root(n);\n    iota(root.begin(), root.end(), 0);\n    dfs(root, 0, 0, BOARD_SIZE, BOARD_SIZE);\n    return res;\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> xs(n), ys(n), rs(n);\n    for (int i = 0; i < n; ++i) cin >> xs[i] >> ys[i] >> rs[i];\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    vector<double> noise_levels = {0.0, 0.15, 0.3, 0.45, 0.6, 0.75, 0.9};\n    vector<vector<Rect>> base_candidates;\n    for (double noise : noise_levels) {\n        int repeats = (noise < 1e-9) ? 1 : 2;\n        for (int rep = 0; rep < repeats; ++rep)\n            base_candidates.push_back(build_initial_rects_randomized(xs, ys, rs, rng, noise));\n    }\n    if (base_candidates.empty())\n        base_candidates.push_back(build_initial_rects_randomized(xs, ys, rs, rng, 0.0));\n\n    int base_count = base_candidates.size();\n    const int MAX_BASES = 20;\n\n    int primary_idx = 0;\n    double primary_score = -1.0;\n    for (int i = 0; i < base_count; ++i) {\n        double sc = compute_score(base_candidates[i], rs);\n        if (sc > primary_score) {\n            primary_score = sc;\n            primary_idx = i;\n        }\n    }\n    const vector<Rect> &primary_base = base_candidates[primary_idx];\n    vector<Rect> best = primary_base;\n    double best_score = primary_score;\n\n    const double GLOBAL_LIMIT = 4.85;\n    auto global_start = chrono::steady_clock::now();\n    auto global_deadline = global_start + chrono::duration_cast<chrono::steady_clock::duration>(\n                                           chrono::duration<double>(GLOBAL_LIMIT));\n\n    int attempt = 0;\n    while (true) {\n        auto now = chrono::steady_clock::now();\n        if (now >= global_deadline) break;\n        double remain = chrono::duration<double>(global_deadline - now).count();\n        const double SAFETY = 0.05;\n        if (remain <= SAFETY) break;\n\n        double best_ratio = best_score / n;\n        if ((int)base_candidates.size() < MAX_BASES && remain > 1.0 && best_ratio < 0.94) {\n            double noise = 0.45 + 0.55 * uni01(rng);\n            base_candidates.push_back(build_initial_rects_randomized(xs, ys, rs, rng, noise));\n            base_count = base_candidates.size();\n        }\n\n        double base_budget = 0.35 + 0.12 * (attempt % 5);\n        double budget = min(remain - SAFETY, base_budget);\n        budget = max(0.12, min(budget, remain * 0.6));\n        if (budget <= 0.05) break;\n        auto attempt_deadline = now + chrono::duration_cast<chrono::steady_clock::duration>(\n                                        chrono::duration<double>(budget));\n        if (attempt_deadline > global_deadline) attempt_deadline = global_deadline;\n\n        int base_idx = attempt % base_count;\n        const vector<Rect> &base_cur = base_candidates[base_idx];\n        vector<Rect> seed = base_cur;\n        random_shrink(seed, xs, ys, rs, rng, max(1, n / 2), false);\n\n        AttemptResult res = run_attempt(seed, base_cur, xs, ys, rs, rng, attempt_deadline);\n        if (res.score > best_score + 1e-9) {\n            best_score = res.score;\n            best = res.rects;\n        }\n        attempt++;\n    }\n\n    auto now = chrono::steady_clock::now();\n    if (now < global_deadline - chrono::duration_cast<chrono::steady_clock::duration>(\n                                 chrono::duration<double>(0.04))) {\n        double remain = chrono::duration<double>(global_deadline - now).count();\n        double budget = min(0.35, remain - 0.02);\n        if (budget > 0.05) {\n            auto polish_deadline = now + chrono::duration_cast<chrono::steady_clock::duration>(\n                                             chrono::duration<double>(budget));\n            AttemptResult res = run_attempt(best, primary_base, xs, ys, rs, rng, polish_deadline);\n            if (res.score > best_score + 1e-9) {\n                best_score = res.score;\n                best = res.rects;\n            }\n        }\n    }\n\n    boundary_balance(best, xs, ys, rs, rng, 5);\n\n    now = chrono::steady_clock::now();\n    if (now < global_deadline - chrono::duration_cast<chrono::steady_clock::duration>(\n                                 chrono::duration<double>(0.015))) {\n        double remain = chrono::duration<double>(global_deadline - now).count();\n        double budget = min(0.25, remain - 0.01);\n        if (budget > 0.04) {\n            auto extra_deadline = now + chrono::duration_cast<chrono::steady_clock::duration>(\n                                            chrono::duration<double>(budget));\n            AttemptResult res = run_attempt(best, best, xs, ys, rs, rng, extra_deadline);\n            if (res.score > best_score + 1e-9) {\n                best_score = res.score;\n                best = res.rects;\n            }\n        }\n    }\n\n    if (!validate_rects(best, xs, ys)) best = primary_base;\n\n    for (const auto &r : best) {\n        cout << r.x1 << ' ' << r.y1 << ' ' << r.x2 << ' ' << r.y2 << '\\n';\n    }\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int N2 = N * N;\n    static constexpr int MAX_TILES = 2500;\n    using VisitBitset = bitset<MAX_TILES>;\n\n    struct Neighbor {\n        int to;\n        char dir;\n    };\n    struct Node {\n        VisitBitset visited;\n        int pos = 0;\n        int score = 0;\n        int parent = -1;\n        char move = '?';\n        int depth = 0;\n    };\n    struct Candidate {\n        double eval;\n        int idx;\n    };\n    struct Features {\n        int mobility = 0;\n        int nei1 = 0;\n        int nei2 = 0;\n        int two = 0;\n    };\n\n    vector<int> tileOf;\n    vector<int> value;\n    vector<vector<Neighbor>> adj;\n    int startIdx = 0;\n\n    mt19937_64 rng;\n    chrono::steady_clock::time_point timeStart;\n    string bestPath;\n    int bestScore = 0;\n\n    const double TIME_LIMIT = 1.95;\n    const double LENGTH_WEIGHT = 8.0;\n    const double MOBILITY_WEIGHT = 16.0;\n    const double NEI1_WEIGHT = 1.1;\n    const double NEI2_WEIGHT = 0.4;\n    const double TWO_WEIGHT = 0.6;\n    const double RANDOM_WEIGHT = 0.8;\n\n    const double GREEDY_VALUE_WEIGHT = 1.0;\n    const double GREEDY_MOB_WEIGHT = 20.0;\n    const double GREEDY_NEI_WEIGHT = 0.9;\n    const double GREEDY_TWO_WEIGHT = 0.4;\n    const double GREEDY_RANDOM_WEIGHT = 0.4;\n    const int MAX_GREEDY_STEPS = 1500;\n    const int MAX_GREEDY_CANDIDATES = 3;\n\n    inline double rand01() {\n        static constexpr double INV = 1.0 / (1ULL << 53);\n        return (rng() >> 11) * INV;\n    }\n    inline double elapsed() const {\n        using namespace chrono;\n        return duration<double>(steady_clock::now() - timeStart).count();\n    }\n    inline bool timeUp() const {\n        return elapsed() > TIME_LIMIT;\n    }\n\n    Features calcFeatures(const VisitBitset &vis, int pos) const {\n        Features feat;\n        for (const auto &nb : adj[pos]) {\n            if (vis.test(tileOf[nb.to])) continue;\n            ++feat.mobility;\n            int val = value[nb.to];\n            if (val >= feat.nei1) {\n                feat.nei2 = feat.nei1;\n                feat.nei1 = val;\n            } else if (val > feat.nei2) {\n                feat.nei2 = val;\n            }\n            for (const auto &nb2 : adj[nb.to]) {\n                if (vis.test(tileOf[nb2.to])) continue;\n                int val2 = value[nb2.to];\n                if (val2 > feat.two) feat.two = val2;\n            }\n        }\n        return feat;\n    }\n\n    string buildPath(const vector<Node> &pool, int idx) const {\n        string res;\n        res.reserve(pool[idx].depth);\n        int cur = idx;\n        while (cur != -1) {\n            const Node &node = pool[cur];\n            if (node.parent == -1) break;\n            res.push_back(node.move);\n            cur = node.parent;\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    void greedyExtend(const Node &startNode, string path) {\n        VisitBitset vis = startNode.visited;\n        int pos = startNode.pos;\n        int score = startNode.score;\n        array<Neighbor, 4> moveBuf;\n        int steps = 0;\n        while (!timeUp() && steps < MAX_GREEDY_STEPS) {\n            int moveCount = 0;\n            for (const auto &nb : adj[pos]) {\n                if (vis.test(tileOf[nb.to])) continue;\n                moveBuf[moveCount++] = nb;\n            }\n            if (moveCount == 0) break;\n            double bestEval = -1e100;\n            int bestIdx = -1;\n            VisitBitset bestVis;\n            for (int i = 0; i < moveCount; ++i) {\n                VisitBitset nextVis = vis;\n                nextVis.set(tileOf[moveBuf[i].to]);\n                Features feat = calcFeatures(nextVis, moveBuf[i].to);\n                double eval = GREEDY_VALUE_WEIGHT * value[moveBuf[i].to]\n                            + GREEDY_MOB_WEIGHT * feat.mobility\n                            + GREEDY_NEI_WEIGHT * feat.nei1\n                            + GREEDY_TWO_WEIGHT * feat.two\n                            + GREEDY_RANDOM_WEIGHT * rand01();\n                if (eval > bestEval) {\n                    bestEval = eval;\n                    bestIdx = i;\n                    bestVis = nextVis;\n                }\n            }\n            if (bestIdx == -1) break;\n            const Neighbor &chosen = moveBuf[bestIdx];\n            vis = bestVis;\n            pos = chosen.to;\n            score += value[pos];\n            path.push_back(chosen.dir);\n            ++steps;\n        }\n        if (score > bestScore || (score == bestScore && path.size() > bestPath.size())) {\n            bestScore = score;\n            bestPath = std::move(path);\n        }\n    }\n\n    void runBeam(int beamWidth) {\n        if (timeUp()) return;\n        const size_t MAX_POOL_RESERVE = 220000;\n        vector<Node> pool;\n        size_t reserveSize = min<size_t>(static_cast<size_t>(beamWidth) * 900 + 1000ULL, MAX_POOL_RESERVE);\n        pool.reserve(reserveSize);\n\n        pool.emplace_back();\n        Node &root = pool.back();\n        root.visited.reset();\n        root.visited.set(tileOf[startIdx]);\n        root.pos = startIdx;\n        root.score = value[startIdx];\n        root.parent = -1;\n        root.move = '?';\n        root.depth = 0;\n\n        int runBestIdx = 0;\n        int runBestScore = root.score;\n\n        vector<int> current;\n        current.reserve(beamWidth);\n        current.push_back(0);\n\n        vector<Candidate> candBuf;\n        candBuf.reserve(beamWidth * 4 + 10);\n\n        array<Neighbor, 4> moveBuf;\n        bool forceStop = false;\n\n        while (!current.empty() && !forceStop) {\n            if (timeUp()) break;\n            candBuf.clear();\n            for (int idx : current) {\n                if (timeUp()) { forceStop = true; break; }\n                VisitBitset parentVis = pool[idx].visited;\n                int pos = pool[idx].pos;\n                int baseScore = pool[idx].score;\n                int depth = pool[idx].depth;\n\n                int moveCount = 0;\n                for (const auto &nb : adj[pos]) {\n                    if (parentVis.test(tileOf[nb.to])) continue;\n                    moveBuf[moveCount++] = nb;\n                }\n                if (moveCount == 0) continue;\n                if (moveCount > 1) {\n                    shuffle(moveBuf.begin(), moveBuf.begin() + moveCount, rng);\n                }\n                for (int mi = 0; mi < moveCount; ++mi) {\n                    if (timeUp()) { forceStop = true; break; }\n                    const Neighbor &nb = moveBuf[mi];\n                    pool.emplace_back();\n                    Node &child = pool.back();\n                    child.visited = parentVis;\n                    child.visited.set(tileOf[nb.to]);\n                    child.pos = nb.to;\n                    child.score = baseScore + value[nb.to];\n                    child.parent = idx;\n                    child.move = nb.dir;\n                    child.depth = depth + 1;\n                    int childIdx = (int)pool.size() - 1;\n\n                    Features feat = calcFeatures(child.visited, child.pos);\n                    double eval = child.score\n                                + LENGTH_WEIGHT * child.depth\n                                + MOBILITY_WEIGHT * feat.mobility\n                                + NEI1_WEIGHT * feat.nei1\n                                + NEI2_WEIGHT * feat.nei2\n                                + TWO_WEIGHT * feat.two\n                                + RANDOM_WEIGHT * rand01();\n\n                    candBuf.push_back({eval, childIdx});\n\n                    if (child.score > runBestScore ||\n                        (child.score == runBestScore && child.depth > pool[runBestIdx].depth)) {\n                        runBestScore = child.score;\n                        runBestIdx = childIdx;\n                    }\n                }\n                if (forceStop) break;\n            }\n            if (forceStop || candBuf.empty()) break;\n\n            auto cmp = [](const Candidate &a, const Candidate &b) { return a.eval > b.eval; };\n            if ((int)candBuf.size() > beamWidth) {\n                partial_sort(candBuf.begin(), candBuf.begin() + beamWidth, candBuf.end(), cmp);\n                candBuf.resize(beamWidth);\n            } else {\n                sort(candBuf.begin(), candBuf.end(), cmp);\n            }\n\n            current.clear();\n            current.reserve(candBuf.size());\n            for (const auto &cand : candBuf) current.push_back(cand.idx);\n        }\n\n        string runBestPath = buildPath(pool, runBestIdx);\n        if (runBestScore > bestScore ||\n            (runBestScore == bestScore && runBestPath.size() > bestPath.size())) {\n            bestScore = runBestScore;\n            bestPath = runBestPath;\n        }\n\n        if (!timeUp()) {\n            vector<int> greedies;\n            greedies.reserve(MAX_GREEDY_CANDIDATES);\n            greedies.push_back(runBestIdx);\n            for (int idx : current) {\n                if ((int)greedies.size() >= MAX_GREEDY_CANDIDATES) break;\n                bool dup = false;\n                for (int g : greedies) if (g == idx) { dup = true; break; }\n                if (!dup) greedies.push_back(idx);\n            }\n            for (int idx : greedies) {\n                if (timeUp()) break;\n                string path = buildPath(pool, idx);\n                greedyExtend(pool[idx], std::move(path));\n            }\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        int si, sj;\n        if (!(cin >> si >> sj)) return;\n        tileOf.resize(N2);\n        int maxTile = -1;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int t;\n                cin >> t;\n                int idx = i * N + j;\n                tileOf[idx] = t;\n                maxTile = max(maxTile, t);\n            }\n        }\n        [[maybe_unused]] int tileCount = maxTile + 1;\n        value.resize(N2);\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int p;\n                cin >> p;\n                value[i * N + j] = p;\n            }\n        }\n        startIdx = si * N + sj;\n\n        adj.assign(N2, {});\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n        const char dirChar[4] = {'U', 'D', 'L', 'R'};\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int idx = i * N + j;\n                for (int d = 0; d < 4; ++d) {\n                    int ni = i + di[d];\n                    int nj = j + dj[d];\n                    if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                    int nidx = ni * N + nj;\n                    adj[idx].push_back({nidx, dirChar[d]});\n                }\n            }\n        }\n\n        bestScore = value[startIdx];\n        bestPath.clear();\n\n        timeStart = chrono::steady_clock::now();\n        rng.seed(chrono::steady_clock::now().time_since_epoch().count());\n\n        vector<int> beamOptions = {60, 80, 100};\n        int iteration = 0;\n        while (!timeUp()) {\n            int bw = beamOptions[iteration % beamOptions.size()];\n            runBeam(bw);\n            ++iteration;\n        }\n\n        cout << bestPath << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\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    static constexpr int HOR = H * (W - 1);\n    static constexpr int VER = (H - 1) * W;\n    static constexpr int EDGE_CNT = HOR + VER;\n\n    const double INIT_MEAN = 5000.0;\n    const double INIT_PERT = 200.0;\n\n    const double BASE_VAR = 1.0e7;\n    const double INFO_OFFSET = 0.5;\n    const double MIN_VAR = 1.0e4;\n    const double MAX_INFO = 600.0;\n    const double INFO_GAIN_BASE = 1.2;\n\n    const double MEAS_NOISE_COEFF = (0.2 * 0.2) / 12.0;\n    const double MEAS_VAR_FLOOR = 1e5;\n\n    const double MIN_EDGE_WEIGHT = 900.0;\n    const double MAX_EDGE_WEIGHT = 9200.0;\n    const double MIN_SEARCH_WEIGHT = 1.0;\n\n    const double ALPHA_MIN = 0.05;\n    const double ALPHA_MAX = 0.9;\n\n    const double USE_EXPLORE_COEFF = 520.0;\n    const double INFO_EXPLORE_COEFF = 360.0;\n    const double EXPLORE_BASE = 1.0;\n\n    const double AGE_BIAS_MAX = 420.0;\n    const double AGE_BIAS_BASE = 20.0;\n    const double AGE_PROGRESS_DECAY = 0.55;\n    const int AGE_HUGE = 1'000'000;\n\n    const double SMOOTH_SELF_BIAS = 0.6;\n    const double SMOOTH_NEIGH_BIAS = 1.5;\n    const double SMOOTH_PULL = 0.55;\n    const double SMOOTH_DENOM = 0.8;\n    const double SMOOTH_MAX_PUSH = 0.45;\n    const double GLOBAL_SMOOTH_SCALE = 800.0;\n    const double GLOBAL_SMOOTH_MIN = 0.25;\n    const double SMOOTH_INFO_REQ = 1.0;\n    const int ROUGH_MIN_COUNT = 80;\n    const double LOCAL_DIFF_SCALE = 900.0;\n    const double MIN_LOCAL_GATE = 0.08;\n    const double LOW_INFO_THRESHOLD = 0.25;\n    const double LOW_INFO_MULT = 1.35;\n\n    const double SEG_WEIGHT_CAP = 4.0;\n    const double SEG_WEIGHT_EPS = 0.05;\n    const double SEG_TOTAL_WEIGHT_MIN = 0.25;\n    const double SEG_PART_MIN_WEIGHT = 0.1;\n    const double SEG_GAIN_REL = 0.02;\n    const double SEG_GAIN_ABS_PER_EDGE = 2.0e4;\n\n    const double SEG_BLEND_INFO_LIMIT = 1.8;\n    const double SEG_BLEND_COEFF = 0.55;\n    const double SEG_BLEND_DENOM = 0.35;\n    const double SEG_BLEND_MAX = 0.70;\n    const double SEG_BLEND_GATE_SCALE = 1200.0;\n    const double SEG_BLEND_LOW_INFO = 0.35;\n    const double SEG_BLEND_LOW_MULT = 1.30;\n\n    vector<double> edgeWeight;\n    vector<int> edgeUse;\n    vector<double> edgeInfo;\n    vector<int> lastUsed;\n\n    vector<double> dist;\n    vector<int> prevNode;\n    vector<int> prevEdge;\n    vector<char> prevMove;\n\n    vector<double> tmpHor;\n    vector<double> tmpVer;\n\n    mt19937 rng;\n    int currentQuery;\n\n    Solver()\n        : edgeWeight(EDGE_CNT),\n          edgeUse(EDGE_CNT, 0),\n          edgeInfo(EDGE_CNT, 0.0),\n          lastUsed(EDGE_CNT, -AGE_HUGE),\n          dist(N),\n          prevNode(N),\n          prevEdge(N),\n          prevMove(N),\n          tmpHor(HOR),\n          tmpVer(VER),\n          currentQuery(0) {\n        rng.seed(chrono::steady_clock::now().time_since_epoch().count());\n        uniform_real_distribution<double> perturb(-INIT_PERT, INIT_PERT);\n        for (int i = 0; i < EDGE_CNT; ++i) {\n            edgeWeight[i] = INIT_MEAN + perturb(rng);\n        }\n    }\n\n    inline void setCurrentQuery(int q) { currentQuery = q; }\n\n    inline int nodeId(int i, int j) const { return i * W + j; }\n    inline int horId(int i, int j) const { return i * (W - 1) + j; }\n    inline int verId(int i, int j) const { return HOR + i * W + j; }\n\n    inline double clampWeight(double v) const {\n        if (v < MIN_EDGE_WEIGHT) return MIN_EDGE_WEIGHT;\n        if (v > MAX_EDGE_WEIGHT) return MAX_EDGE_WEIGHT;\n        return v;\n    }\n\n    double ageBiasCoeff() const {\n        double progress = min(currentQuery, 1000) / 1000.0;\n        double coeff = AGE_BIAS_MAX * (1.0 - AGE_PROGRESS_DECAY * progress);\n        return max(coeff, 0.0);\n    }\n\n    double edgeCostForSearch(int eid) {\n        double useBias = USE_EXPLORE_COEFF / sqrt(edgeUse[eid] + EXPLORE_BASE);\n        double infoBias = INFO_EXPLORE_COEFF / sqrt(edgeInfo[eid] + 1.0);\n\n        int age = currentQuery - lastUsed[eid];\n        if (lastUsed[eid] <= -AGE_HUGE / 2) age = AGE_HUGE;\n        if (age < 0) age = 0;\n        double coeff = ageBiasCoeff();\n        double denom = max<double>(age + AGE_BIAS_BASE, 1.0);\n        double ageBias = coeff * (double)age / denom;\n\n        double w = edgeWeight[eid] - useBias - infoBias - ageBias;\n        if (w < MIN_SEARCH_WEIGHT) w = MIN_SEARCH_WEIGHT;\n        return w;\n    }\n\n    void buildFallback(int si, int sj, int ti, int tj, string &path, vector<int> &pathEdges) {\n        path.clear();\n        pathEdges.clear();\n        int ci = si, cj = sj;\n        auto pushStep = [&](char mv) {\n            path.push_back(mv);\n            if (mv == 'U') {\n                pathEdges.push_back(verId(ci - 1, cj));\n                --ci;\n            } else if (mv == 'D') {\n                pathEdges.push_back(verId(ci, cj));\n                ++ci;\n            } else if (mv == 'L') {\n                pathEdges.push_back(horId(ci, cj - 1));\n                --cj;\n            } else {\n                pathEdges.push_back(horId(ci, cj));\n                ++cj;\n            }\n        };\n        while (ci < ti) pushStep('D');\n        while (ci > ti) pushStep('U');\n        while (cj < tj) pushStep('R');\n        while (cj > tj) pushStep('L');\n    }\n\n    void computePath(int si, int sj, int ti, int tj, string &path, vector<int> &pathEdges) {\n        path.clear();\n        pathEdges.clear();\n        int start = nodeId(si, sj);\n        int target = nodeId(ti, tj);\n        const double INF = 1e100;\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevNode.begin(), prevNode.end(), -1);\n        fill(prevEdge.begin(), prevEdge.end(), -1);\n        fill(prevMove.begin(), prevMove.end(), 0);\n\n        struct PQNode {\n            double dist;\n            int node;\n            bool operator<(const PQNode &o) const { return dist > o.dist; }\n        };\n\n        priority_queue<PQNode> pq;\n        dist[start] = 0.0;\n        pq.push({0.0, start});\n\n        while (!pq.empty()) {\n            auto cur = pq.top();\n            pq.pop();\n            if (cur.dist > dist[cur.node]) continue;\n            if (cur.node == target) break;\n            int i = cur.node / W;\n            int j = cur.node % W;\n\n            if (i > 0) {\n                int nb = cur.node - W;\n                int eid = verId(i - 1, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'U';\n                    pq.push({nd, nb});\n                }\n            }\n            if (i + 1 < H) {\n                int nb = cur.node + W;\n                int eid = verId(i, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'D';\n                    pq.push({nd, nb});\n                }\n            }\n            if (j > 0) {\n                int nb = cur.node - 1;\n                int eid = horId(i, j - 1);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'L';\n                    pq.push({nd, nb});\n                }\n            }\n            if (j + 1 < W) {\n                int nb = cur.node + 1;\n                int eid = horId(i, j);\n                double nd = cur.dist + edgeCostForSearch(eid);\n                if (nd < dist[nb]) {\n                    dist[nb] = nd;\n                    prevNode[nb] = cur.node;\n                    prevEdge[nb] = eid;\n                    prevMove[nb] = 'R';\n                    pq.push({nd, nb});\n                }\n            }\n        }\n\n        if (start != target && prevEdge[target] == -1) {\n            buildFallback(si, sj, ti, tj, path, pathEdges);\n            return;\n        }\n        int cur = target;\n        while (cur != start) {\n            int pe = prevEdge[cur];\n            if (pe == -1) {\n                buildFallback(si, sj, ti, tj, path, pathEdges);\n                return;\n            }\n            path.push_back(prevMove[cur]);\n            pathEdges.push_back(pe);\n            cur = prevNode[cur];\n        }\n        reverse(path.begin(), path.end());\n        reverse(pathEdges.begin(), pathEdges.end());\n    }\n\n    double computeSmoothFactor() const {\n        double sumDiff = 0.0;\n        int cnt = 0;\n\n        for (int i = 0; i < H; ++i) {\n            for (int j = 1; j < W - 1; ++j) {\n                int eid = horId(i, j);\n                int left = horId(i, j - 1);\n                double minInfo = min(edgeInfo[eid], edgeInfo[left]);\n                if (minInfo < SMOOTH_INFO_REQ) continue;\n                sumDiff += fabs(edgeWeight[eid] - edgeWeight[left]);\n                ++cnt;\n            }\n        }\n        for (int j = 0; j < W; ++j) {\n            for (int i = 1; i < H - 1; ++i) {\n                int eid = verId(i, j);\n                int up = verId(i - 1, j);\n                double minInfo = min(edgeInfo[eid], edgeInfo[up]);\n                if (minInfo < SMOOTH_INFO_REQ) continue;\n                sumDiff += fabs(edgeWeight[eid] - edgeWeight[up]);\n                ++cnt;\n            }\n        }\n\n        if (cnt < ROUGH_MIN_COUNT) return 1.0;\n        double avg = sumDiff / cnt;\n        double factor = 1.0 / (1.0 + avg / GLOBAL_SMOOTH_SCALE);\n        if (factor < GLOBAL_SMOOTH_MIN) factor = GLOBAL_SMOOTH_MIN;\n        if (factor > 1.0) factor = 1.0;\n        return factor;\n    }\n\n    void smoothHorizontal(double globalFactor) {\n        for (int i = 0; i < H; ++i) {\n            for (int j = 0; j < W - 1; ++j) {\n                int eid = horId(i, j);\n                double sum = (edgeInfo[eid] + SMOOTH_SELF_BIAS) * edgeWeight[eid];\n                double denom = edgeInfo[eid] + SMOOTH_SELF_BIAS;\n\n                auto addNeighbor = [&](int nj) {\n                    int nid = horId(i, nj);\n                    double diff = fabs(edgeWeight[eid] - edgeWeight[nid]);\n                    double gate = 1.0 / (1.0 + diff / LOCAL_DIFF_SCALE);\n                    if (gate < MIN_LOCAL_GATE) gate = MIN_LOCAL_GATE;\n                    double w = (edgeInfo[nid] + SMOOTH_NEIGH_BIAS) * gate;\n                    sum += w * edgeWeight[nid];\n                    denom += w;\n                };\n\n                if (j > 0) addNeighbor(j - 1);\n                if (j + 1 < W - 1) addNeighbor(j + 1);\n\n                double avg = sum / denom;\n                double push = SMOOTH_PULL / (edgeInfo[eid] + SMOOTH_DENOM);\n                if (edgeInfo[eid] < LOW_INFO_THRESHOLD) push *= LOW_INFO_MULT;\n                if (push > SMOOTH_MAX_PUSH) push = SMOOTH_MAX_PUSH;\n                push *= globalFactor;\n\n                double newVal = edgeWeight[eid] + push * (avg - edgeWeight[eid]);\n                tmpHor[eid] = clampWeight(newVal);\n            }\n        }\n        for (int i = 0; i < HOR; ++i) edgeWeight[i] = tmpHor[i];\n    }\n\n    void smoothVertical(double globalFactor) {\n        for (int j = 0; j < W; ++j) {\n            for (int i = 0; i < H - 1; ++i) {\n                int eid = verId(i, j);\n                double sum = (edgeInfo[eid] + SMOOTH_SELF_BIAS) * edgeWeight[eid];\n                double denom = edgeInfo[eid] + SMOOTH_SELF_BIAS;\n\n                auto addNeighbor = [&](int ni) {\n                    int nid = verId(ni, j);\n                    double diff = fabs(edgeWeight[eid] - edgeWeight[nid]);\n                    double gate = 1.0 / (1.0 + diff / LOCAL_DIFF_SCALE);\n                    if (gate < MIN_LOCAL_GATE) gate = MIN_LOCAL_GATE;\n                    double w = (edgeInfo[nid] + SMOOTH_NEIGH_BIAS) * gate;\n                    sum += w * edgeWeight[nid];\n                    denom += w;\n                };\n\n                if (i > 0) addNeighbor(i - 1);\n                if (i + 1 < H - 1) addNeighbor(i + 1);\n\n                double avg = sum / denom;\n                double push = SMOOTH_PULL / (edgeInfo[eid] + SMOOTH_DENOM);\n                if (edgeInfo[eid] < LOW_INFO_THRESHOLD) push *= LOW_INFO_MULT;\n                if (push > SMOOTH_MAX_PUSH) push = SMOOTH_MAX_PUSH;\n                push *= globalFactor;\n\n                double newVal = edgeWeight[eid] + push * (avg - edgeWeight[eid]);\n                int idx = i * W + j;\n                tmpVer[idx] = clampWeight(newVal);\n            }\n        }\n        for (int i = 0; i < VER; ++i) edgeWeight[HOR + i] = tmpVer[i];\n    }\n\n    void smoothEstimates() {\n        double factor = computeSmoothFactor();\n        smoothHorizontal(factor);\n        smoothVertical(factor);\n    }\n\n    template<int M>\n    void applySegmentBlend(bool isRow, int idx, double globalAvg) {\n        array<double, M> values;\n        array<double, M> weights;\n        array<double, M> baseline;\n        array<double, M + 1> prefW{};\n        array<double, M + 1> prefSum{};\n        array<double, M + 1> prefSq{};\n\n        for (int p = 0; p < M; ++p) {\n            int eid = isRow ? horId(idx, p) : verId(p, idx);\n            double info = edgeInfo[eid];\n            values[p] = edgeWeight[eid];\n            weights[p] = (info > 0) ? min(info, SEG_WEIGHT_CAP) + SEG_WEIGHT_EPS : 0.0;\n        }\n\n        for (int p = 0; p < M; ++p) {\n            prefW[p + 1] = prefW[p] + weights[p];\n            double prod = weights[p] * values[p];\n            prefSum[p + 1] = prefSum[p] + prod;\n            prefSq[p + 1] = prefSq[p] + prod * values[p];\n        }\n\n        double totalW = prefW[M];\n        double infoLimit = SEG_BLEND_INFO_LIMIT;\n        double coeffScale = 1.0;\n\n        if (totalW < SEG_TOTAL_WEIGHT_MIN) {\n            baseline.fill(globalAvg);\n            infoLimit *= 0.7;\n            coeffScale = 0.9;\n        } else {\n            double totalSum = prefSum[M];\n            double totalSq = prefSq[M];\n            double meanAll = totalSum / totalW;\n            double sseAll = max(0.0, totalSq - totalSum * totalSum / totalW);\n            double requiredBase = SEG_GAIN_REL * sseAll +\n                                  SEG_GAIN_ABS_PER_EDGE * (totalW / double(M));\n            double bestSSE = sseAll;\n            double bestImprovement = 0.0;\n            int bestSplit = -1;\n            double bestLeftMean = meanAll;\n            double bestRightMean = meanAll;\n\n            for (int k = 1; k < M; ++k) {\n                double wL = prefW[k];\n                double wR = totalW - wL;\n                if (wL < SEG_PART_MIN_WEIGHT || wR < SEG_PART_MIN_WEIGHT) continue;\n                double sumL = prefSum[k];\n                double sumR = totalSum - sumL;\n                double sqL = prefSq[k];\n                double sqR = totalSq - sqL;\n                double meanL = sumL / wL;\n                double meanR = sumR / wR;\n                double sseL = max(0.0, sqL - sumL * sumL / wL);\n                double sseR = max(0.0, sqR - sumR * sumR / wR);\n                double sse = sseL + sseR;\n                double improvement = sseAll - sse;\n                if (improvement > requiredBase && sse < bestSSE) {\n                    bestSSE = sse;\n                    bestSplit = k;\n                    bestLeftMean = meanL;\n                    bestRightMean = meanR;\n                    bestImprovement = improvement;\n                }\n            }\n\n            if (bestSplit == -1) {\n                baseline.fill(meanAll);\n                double conf = min(1.5, totalW / 1.2);\n                infoLimit *= (0.75 + 0.2 * conf);\n                coeffScale = 0.85 + 0.25 * conf;\n            } else {\n                for (int p = 0; p < M; ++p) {\n                    baseline[p] = (p < bestSplit ? bestLeftMean : bestRightMean);\n                }\n                double ratio = bestImprovement /\n                               max(requiredBase, 1e-6);\n                ratio = min(ratio, 3.0);\n                infoLimit *= min(2.5, 0.85 + 0.45 * ratio);\n                coeffScale = min(2.2, 0.9 + 0.4 * ratio);\n            }\n        }\n\n        for (int p = 0; p < M; ++p) {\n            int eid = isRow ? horId(idx, p) : verId(p, idx);\n            double info = edgeInfo[eid];\n            if (info >= infoLimit) continue;\n            double target = baseline[p];\n            double diff = target - edgeWeight[eid];\n            double coeff = (SEG_BLEND_COEFF * coeffScale) / (info + SEG_BLEND_DENOM);\n            if (info < SEG_BLEND_LOW_INFO) coeff *= SEG_BLEND_LOW_MULT;\n            double gate = 1.0 / (1.0 + fabs(diff) / SEG_BLEND_GATE_SCALE);\n            coeff *= gate;\n            if (coeff > SEG_BLEND_MAX) coeff = SEG_BLEND_MAX;\n            edgeWeight[eid] = clampWeight(edgeWeight[eid] + coeff * diff);\n        }\n    }\n\n    void segmentBlend() {\n        double globalHorSum = 0.0, globalHorW = 0.0;\n        for (int eid = 0; eid < HOR; ++eid) {\n            if (edgeInfo[eid] <= 0) continue;\n            double w = min(edgeInfo[eid], SEG_WEIGHT_CAP) + SEG_WEIGHT_EPS;\n            globalHorSum += edgeWeight[eid] * w;\n            globalHorW += w;\n        }\n        double globalHorAvg = (globalHorW > 0) ? globalHorSum / globalHorW : INIT_MEAN;\n\n        double globalVerSum = 0.0, globalVerW = 0.0;\n        for (int eid = 0; eid < VER; ++eid) {\n            int idx = HOR + eid;\n            if (edgeInfo[idx] <= 0) continue;\n            double w = min(edgeInfo[idx], SEG_WEIGHT_CAP) + SEG_WEIGHT_EPS;\n            globalVerSum += edgeWeight[idx] * w;\n            globalVerW += w;\n        }\n        double globalVerAvg = (globalVerW > 0) ? globalVerSum / globalVerW : INIT_MEAN;\n\n        for (int i = 0; i < H; ++i) applySegmentBlend<W - 1>(true, i, globalHorAvg);\n        for (int j = 0; j < W; ++j) applySegmentBlend<H - 1>(false, j, globalVerAvg);\n    }\n\n    void update(const vector<int> &pathEdges, double measurement) {\n        if (pathEdges.empty()) return;\n\n        size_t m = pathEdges.size();\n        vector<double> vars;\n        vars.reserve(m);\n\n        double predicted = 0.0;\n        double sumVar = 0.0;\n        for (int eid : pathEdges) {\n            predicted += edgeWeight[eid];\n            double var = BASE_VAR / (edgeInfo[eid] + INFO_OFFSET);\n            if (var < MIN_VAR) var = MIN_VAR;\n            vars.push_back(var);\n            sumVar += var;\n        }\n        if (sumVar <= 0.0) sumVar = MIN_VAR;\n\n        double residual = measurement - predicted;\n        double safePred = max(predicted, 1.0);\n        double measurementVar = MEAS_NOISE_COEFF * safePred * safePred + MEAS_VAR_FLOOR;\n        double alpha = sumVar / (sumVar + measurementVar);\n        if (alpha < ALPHA_MIN) alpha = ALPHA_MIN;\n        if (alpha > ALPHA_MAX) alpha = ALPHA_MAX;\n\n        double scale = alpha * residual / sumVar;\n        for (size_t idx = 0; idx < m; ++idx) {\n            int eid = pathEdges[idx];\n            double delta = vars[idx] * scale;\n            edgeWeight[eid] = clampWeight(edgeWeight[eid] + delta);\n        }\n\n        double invSumVar = 1.0 / sumVar;\n        for (size_t idx = 0; idx < m; ++idx) {\n            int eid = pathEdges[idx];\n            double infoGain = INFO_GAIN_BASE * vars[idx] * invSumVar;\n            edgeInfo[eid] = min(edgeInfo[eid] + infoGain, MAX_INFO);\n            edgeUse[eid] = min(edgeUse[eid] + 1, 1'000'000'000);\n            lastUsed[eid] = currentQuery;\n        }\n\n        smoothEstimates();\n        segmentBlend();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    string path;\n    path.reserve(128);\n    vector<int> pathEdges;\n    pathEdges.reserve(128);\n\n    for (int q = 0; q < 1000; ++q) {\n        solver.setCurrentQuery(q);\n\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        solver.computePath(si, sj, ti, tj, path, pathEdges);\n        cout << path << '\\n' << flush;\n\n        int measurement;\n        if (!(cin >> measurement)) return 0;\n        if (measurement < 0) return 0;\n\n        solver.update(pathEdges, static_cast<double>(measurement));\n    }\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 20;\nconstexpr int MAXLEN = 12;\nconstexpr int ORIENT = 2;\nconstexpr int PL_PER_ORIENT = N * N;\nconstexpr int PL = ORIENT * PL_PER_ORIENT;\nconstexpr uint8_t EMPTY = 0xFF;\nconst double TIME_LIMIT = 2.9;\nconst double LOCAL_SEARCH_MARGIN = 0.6;\nconst int MAX_CANDIDATES = 16;\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 Placement {\n    array<uint8_t, MAXLEN> rows;\n    array<uint8_t, MAXLEN> cols;\n    array<int, MAXLEN> cellIndex;\n};\n\nstruct Read {\n    string s;\n    vector<uint8_t> codes;\n    int len;\n};\n\nusing Grid = array<array<uint8_t, N>, N>;\n\nstruct Candidate {\n    Grid grid;\n    int score;\n};\n\ninline double vote_weight(int match, int len) {\n    if (match <= 0) return 0.0;\n    if (match >= len) return 6.5;\n    if (match == len - 1) return 2.3;\n    if (match == len - 2) return 0.9;\n    if (match >= len - 3) return 0.4;\n    if (match * 2 >= len) return 0.12;\n    return 0.03;\n}\n\nstruct LetterSampler {\n    array<double, 8> pref;\n    double total;\n    LetterSampler() {\n        pref.fill(0.0);\n        total = 8.0;\n        for (int i = 0; i < 8; ++i) pref[i] = i + 1;\n    }\n    explicit LetterSampler(const array<double, 8> &freq) {\n        double sum = 0.0;\n        for (int i = 0; i < 8; ++i) {\n            sum += max(1e-9, freq[i]);\n            pref[i] = sum;\n        }\n        total = sum;\n        if (total <= 0.0) {\n            total = 8.0;\n            for (int i = 0; i < 8; ++i) pref[i] = i + 1;\n        }\n    }\n    inline double rand01(mt19937_64 &rng) const {\n        return std::generate_canonical<double, 53>(rng);\n    }\n    int sample(mt19937_64 &rng) const {\n        double r = rand01(rng) * total;\n        for (int i = 0; i < 8; ++i)\n            if (r < pref[i]) return i;\n        return 7;\n    }\n};\n\nvector<Placement> build_placements() {\n    vector<Placement> placements(PL);\n    int idx = 0;\n    for (int ori = 0; ori < ORIENT; ++ori) {\n        for (int fixed = 0; fixed < N; ++fixed) {\n            for (int start = 0; start < N; ++start) {\n                Placement &p = placements[idx++];\n                for (int t = 0; t < MAXLEN; ++t) {\n                    int r, c;\n                    if (ori == 0) {\n                        r = fixed;\n                        c = (start + t) % N;\n                    } else {\n                        r = (start + t) % N;\n                        c = fixed;\n                    }\n                    p.rows[t] = static_cast<uint8_t>(r);\n                    p.cols[t] = static_cast<uint8_t>(c);\n                    p.cellIndex[t] = ((r * N + c) << 3);\n                }\n            }\n        }\n    }\n    return placements;\n}\n\nGrid seed_grid(const vector<Read> &reads, const vector<Placement> &placements,\n               mt19937_64 &rng, const LetterSampler &sampler) {\n    Grid grid;\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            grid[i][j] = EMPTY;\n\n    vector<int> order(reads.size());\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (reads[a].len != reads[b].len) return reads[a].len > reads[b].len;\n        return a < b;\n    });\n\n    for (int idx : order) {\n        const Read &rd = reads[idx];\n        int len = rd.len;\n        int chosen = -1;\n        int cnt = 0;\n        for (int pid = 0; pid < PL; ++pid) {\n            bool ok = true;\n            for (int t = 0; t < len; ++t) {\n                uint8_t cur = grid[placements[pid].rows[t]][placements[pid].cols[t]];\n                if (cur != EMPTY && cur != rd.codes[t]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) {\n                ++cnt;\n                if ((uint64_t)rng() % cnt == 0) chosen = pid;\n            }\n        }\n        if (chosen != -1) {\n            for (int t = 0; t < len; ++t) {\n                grid[placements[chosen].rows[t]][placements[chosen].cols[t]] = rd.codes[t];\n            }\n        }\n    }\n\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            if (grid[i][j] == EMPTY)\n                grid[i][j] = static_cast<uint8_t>(sampler.sample(rng));\n    return grid;\n}\n\nint compute_delta(int iter, int total) {\n    if (total <= 4) return 1;\n    if (iter * 3 >= total * 2) return 1;\n    if (iter * 3 >= total) return 2;\n    return 3;\n}\n\nvoid run_em(Grid &grid, int iterations, const vector<Read> &reads,\n            const vector<Placement> &placements, vector<double> &counts,\n            array<uint8_t, PL> &matchBuf, const vector<double> &weights,\n            double inertia, Timer &timer) {\n    for (int iter = 0; iter < iterations; ++iter) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n        fill(counts.begin(), counts.end(), 0.0);\n        int delta = compute_delta(iter, iterations);\n\n        for (const Read &rd : reads) {\n            const uint8_t *codes = rd.codes.data();\n            int len = rd.len;\n            int best = 0;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = 0;\n                for (int t = 0; t < len; ++t)\n                    if (grid[placements[pid].rows[t]][placements[pid].cols[t]] == codes[t]) ++match;\n                matchBuf[pid] = static_cast<uint8_t>(match);\n                if (match > best) best = match;\n            }\n            if (best == 0) continue;\n            int threshold = max(0, best - delta);\n            double totalWeight = 0.0;\n            for (int pid = 0; pid < PL; ++pid) {\n                if (matchBuf[pid] < threshold) continue;\n                totalWeight += weights[matchBuf[pid]];\n            }\n            if (totalWeight <= 0.0) continue;\n            double inv = 1.0 / totalWeight;\n            for (int pid = 0; pid < PL; ++pid) {\n                int match = matchBuf[pid];\n                if (match < threshold) continue;\n                double w = weights[match];\n                if (w <= 0) continue;\n                double scaled = w * inv;\n                for (int t = 0; t < len; ++t)\n                    counts[placements[pid].cellIndex[t] + codes[t]] += scaled;\n            }\n        }\n\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                counts[((r * N + c) << 3) + grid[r][c]] += inertia;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int base = ((r * N + c) << 3);\n                double bestVal = counts[base];\n                int bestLetter = 0;\n                for (int letter = 1; letter < 8; ++letter) {\n                    double v = counts[base + letter];\n                    if (v > bestVal) {\n                        bestVal = v;\n                        bestLetter = letter;\n                    }\n                }\n                grid[r][c] = static_cast<uint8_t>(bestLetter);\n            }\n        }\n    }\n}\n\nint compute_best_matches(const Grid &grid, const vector<Read> &reads,\n                         vector<int> &bestPid, vector<uint8_t> &bestMatch,\n                         vector<uint8_t> *sat = nullptr) {\n    array<array<uint8_t, N * 2>, N> rowBuf, colBuf;\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            uint8_t val = grid[r][c];\n            rowBuf[r][c] = val;\n            rowBuf[r][c + N] = val;\n            colBuf[c][r] = val;\n            colBuf[c][r + N] = val;\n        }\n    }\n\n    int M = reads.size();\n    if ((int)bestPid.size() != M) bestPid.assign(M, 0);\n    if ((int)bestMatch.size() != M) bestMatch.assign(M, 0);\n    if (sat && (int)sat->size() != M) sat->assign(M, 0);\n\n    int satisfied = 0;\n    for (int idx = 0; idx < M; ++idx) {\n        const Read &rd = reads[idx];\n        int len = rd.len;\n        const uint8_t *codes = rd.codes.data();\n        int best = -1;\n        int bestPlacement = 0;\n        bool perfect = false;\n\n        for (int r = 0; r < N && !perfect; ++r) {\n            const uint8_t *rowPtr = rowBuf[r].data();\n            for (int start = 0; start < N; ++start) {\n                const uint8_t *seg = rowPtr + start;\n                int match = 0;\n                for (int t = 0; t < len; ++t)\n                    match += (seg[t] == codes[t]);\n                if (match > best) {\n                    best = match;\n                    bestPlacement = r * N + start;\n                    if (match == len) { perfect = true; break; }\n                }\n            }\n        }\n        if (!perfect) {\n            for (int c = 0; c < N && !perfect; ++c) {\n                const uint8_t *colPtr = colBuf[c].data();\n                for (int start = 0; start < N; ++start) {\n                    const uint8_t *seg = colPtr + start;\n                    int match = 0;\n                    for (int t = 0; t < len; ++t)\n                        match += (seg[t] == codes[t]);\n                    if (match > best) {\n                        best = match;\n                        bestPlacement = PL_PER_ORIENT + c * N + start;\n                        if (match == len) { perfect = true; break; }\n                    }\n                }\n            }\n        }\n        if (best < 0) best = 0;\n        bestPid[idx] = bestPlacement;\n        bestMatch[idx] = static_cast<uint8_t>(best);\n        bool ok = (best == len);\n        if (sat) (*sat)[idx] = static_cast<uint8_t>(ok);\n        if (ok) ++satisfied;\n    }\n    return satisfied;\n}\n\nvoid repair_grid(Grid &grid, const vector<Read> &reads, const vector<Placement> &placements,\n                 Timer &timer, const vector<int> &bestPid, const vector<uint8_t> &bestMatch,\n                 int threshold) {\n    int M = reads.size();\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        int ma = reads[a].len - bestMatch[a];\n        int mb = reads[b].len - bestMatch[b];\n        if (ma != mb) return ma < mb;\n        return reads[a].len > reads[b].len;\n    });\n    for (int idx : order) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n        int mismatch = reads[idx].len - bestMatch[idx];\n        if (mismatch <= 0 || mismatch > threshold) continue;\n        int pid = bestPid[idx];\n        if (pid < 0 || pid >= PL) continue;\n        const Placement &pl = placements[pid];\n        const Read &rd = reads[idx];\n        for (int t = 0; t < rd.len; ++t)\n            grid[pl.rows[t]][pl.cols[t]] = rd.codes[t];\n    }\n}\n\nvoid local_search(Grid &grid, const vector<Read> &reads,\n                  const vector<Placement> &placements, Timer &timer,\n                  Grid &globalBest, int &globalBestScore, mt19937_64 &rng,\n                  int maxIter = 220) {\n    int M = reads.size();\n    vector<int> curBestPid(M), tmpBestPid(M);\n    vector<uint8_t> curBestMatch(M), tmpBestMatch(M);\n    vector<uint8_t> curSat(M), tmpSat(M);\n\n    int curScore = compute_best_matches(grid, reads, curBestPid, curBestMatch, &curSat);\n    if (curScore > globalBestScore) {\n        globalBestScore = curScore;\n        globalBest = grid;\n    }\n\n    array<vector<int>, MAXLEN + 1> buckets;\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    for (int iter = 0; iter < maxIter; ++iter) {\n        if (timer.elapsed() > TIME_LIMIT - 0.02) break;\n        if (curScore == M) break;\n\n        for (auto &vec : buckets) vec.clear();\n        for (int i = 0; i < M; ++i) {\n            if (curSat[i]) continue;\n            int mismatch = reads[i].len - curBestMatch[i];\n            if (mismatch < 1) mismatch = 1;\n            if (mismatch > MAXLEN) mismatch = MAXLEN;\n            buckets[mismatch].push_back(i);\n        }\n        int chosenMis = -1;\n        for (int mis = 1; mis <= MAXLEN; ++mis) {\n            if (!buckets[mis].empty()) { chosenMis = mis; break; }\n        }\n        if (chosenMis == -1) break;\n\n        int range = min(MAXLEN, chosenMis + 3);\n        for (int mis = chosenMis + 1; mis <= range; ++mis) {\n            if (!buckets[mis].empty() && uni01(rng) < 0.25) {\n                chosenMis = mis;\n                break;\n            }\n        }\n        const vector<int> &bucket = buckets[chosenMis];\n        int pick = bucket[rng() % bucket.size()];\n        int pid = curBestPid[pick];\n        if (pid < 0 || pid >= PL) continue;\n        const Placement &pl = placements[pid];\n        const Read &rd = reads[pick];\n\n        array<uint8_t, MAXLEN> backup;\n        bool changed = false;\n        for (int t = 0; t < rd.len; ++t) {\n            int r = pl.rows[t], c = pl.cols[t];\n            backup[t] = grid[r][c];\n            uint8_t desired = rd.codes[t];\n            if (grid[r][c] != desired) {\n                grid[r][c] = desired;\n                changed = true;\n            }\n        }\n        if (!changed) continue;\n\n        int newScore = compute_best_matches(grid, reads, tmpBestPid, tmpBestMatch, &tmpSat);\n        double progress = max(0.0, min(1.0, static_cast<double>(iter) / max(1, maxIter - 1)));\n        double temp = 2.8 + (0.25 - 2.8) * progress;\n        int diff = newScore - curScore;\n        bool accept = diff >= 0;\n        if (!accept) {\n            double prob = exp(diff / temp);\n            if (prob > uni01(rng)) accept = true;\n        }\n\n        if (accept) {\n            curScore = newScore;\n            swap(curBestPid, tmpBestPid);\n            swap(curBestMatch, tmpBestMatch);\n            swap(curSat, tmpSat);\n            if (curScore > globalBestScore) {\n                globalBestScore = curScore;\n                globalBest = grid;\n            }\n        } else {\n            for (int t = 0; t < rd.len; ++t)\n                grid[pl.rows[t]][pl.cols[t]] = backup[t];\n        }\n    }\n}\n\nint placement_vote_refine(Grid &grid, const vector<Read> &reads,\n                          const vector<Placement> &placements,\n                          vector<int> &bestPid, vector<uint8_t> &bestMatch,\n                          vector<double> &counts, Timer &timer, int iterations) {\n    int bestScore = compute_best_matches(grid, reads, bestPid, bestMatch);\n    Grid bestGrid = grid;\n\n    for (int it = 0; it < iterations; ++it) {\n        if (timer.elapsed() > TIME_LIMIT - 0.02) break;\n        vector<int> dummyPid = bestPid;\n        vector<uint8_t> dummyMatch = bestMatch;\n        fill(counts.begin(), counts.end(), 0.0);\n\n        for (int i = 0; i < (int)reads.size(); ++i) {\n            double weight = vote_weight(dummyMatch[i], reads[i].len);\n            if (weight <= 0) continue;\n            int pid = dummyPid[i];\n            if (pid < 0 || pid >= PL) continue;\n            const Placement &pl = placements[pid];\n            const Read &rd = reads[i];\n            for (int t = 0; t < rd.len; ++t)\n                counts[pl.cellIndex[t] + rd.codes[t]] += weight;\n        }\n\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                counts[((r * N + c) << 3) + grid[r][c]] += 0.25;\n\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c) {\n                int base = ((r * N + c) << 3);\n                double bestVal = counts[base];\n                int bestLetter = 0;\n                for (int letter = 1; letter < 8; ++letter) {\n                    double v = counts[base + letter];\n                    if (v > bestVal) {\n                        bestVal = v;\n                        bestLetter = letter;\n                    }\n                }\n                grid[r][c] = static_cast<uint8_t>(bestLetter);\n            }\n\n        int currentScore = compute_best_matches(grid, reads, bestPid, bestMatch);\n        if (currentScore > bestScore) {\n            bestScore = currentScore;\n            bestGrid = grid;\n        }\n    }\n\n    compute_best_matches(bestGrid, reads, bestPid, bestMatch);\n    grid = bestGrid;\n    return bestScore;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N_input, M;\n    if (!(cin >> N_input >> M)) return 0;\n    vector<Read> reads(M);\n    array<double, 8> freq{};\n    for (int i = 0; i < M; ++i) {\n        string s; cin >> s;\n        reads[i].s = s;\n        reads[i].len = s.size();\n        reads[i].codes.resize(s.size());\n        for (int j = 0; j < (int)s.size(); ++j) {\n            uint8_t code = static_cast<uint8_t>(s[j] - 'A');\n            reads[i].codes[j] = code;\n            freq[code] += 1.0;\n        }\n    }\n    LetterSampler sampler(freq);\n\n    auto placements = build_placements();\n    vector<double> counts(N * N * 8, 0.0);\n    array<uint8_t, PL> matchBuf{};\n    vector<double> weights(MAXLEN + 1, 0.0);\n    weights[1] = 0.05;\n    double w = 1.0;\n    for (int m = 2; m <= MAXLEN; ++m) {\n        weights[m] = w;\n        w *= 1.75;\n    }\n\n    Timer timer;\n    mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    Grid bestGrid{};\n    int bestScore = -1;\n    vector<int> workBestPid(M);\n    vector<uint8_t> workBestMatch(M);\n    vector<Candidate> candidates;\n\n    int restarts = 0;\n    while (timer.elapsed() < TIME_LIMIT - LOCAL_SEARCH_MARGIN) {\n        Grid grid = seed_grid(reads, placements, rng, sampler);\n        run_em(grid, 30, reads, placements, counts, matchBuf, weights, 0.35, timer);\n        int score = compute_best_matches(grid, reads, workBestPid, workBestMatch);\n        candidates.push_back({grid, score});\n        if (score > bestScore) {\n            bestScore = score;\n            bestGrid = grid;\n        }\n        if (TIME_LIMIT - timer.elapsed() > 0.35) {\n            repair_grid(grid, reads, placements, timer, workBestPid, workBestMatch, 2);\n            run_em(grid, 8, reads, placements, counts, matchBuf, weights, 0.25, timer);\n            score = compute_best_matches(grid, reads, workBestPid, workBestMatch);\n            candidates.push_back({grid, score});\n            if (score > bestScore) {\n                bestScore = score;\n                bestGrid = grid;\n            }\n        }\n        ++restarts;\n        if (timer.elapsed() > TIME_LIMIT - LOCAL_SEARCH_MARGIN) break;\n    }\n    if (restarts == 0) {\n        Grid grid = seed_grid(reads, placements, rng, sampler);\n        run_em(grid, 30, reads, placements, counts, matchBuf, weights, 0.35, timer);\n        int score = compute_best_matches(grid, reads, workBestPid, workBestMatch);\n        candidates.push_back({grid, score});\n        bestScore = score;\n        bestGrid = grid;\n    }\n\n    while ((int)candidates.size() > MAX_CANDIDATES) {\n        sort(candidates.begin(), candidates.end(), [](const Candidate &a, const Candidate &b) {\n            return a.score > b.score;\n        });\n        candidates.pop_back();\n    }\n\n    const int MAX_LOCAL_CANDS = 5;\n    sort(candidates.begin(), candidates.end(), [](const Candidate &a, const Candidate &b) {\n        return a.score > b.score;\n    });\n    int localRuns = min(MAX_LOCAL_CANDS, (int)candidates.size());\n    for (int i = 0; i < localRuns; ++i) {\n        if (timer.elapsed() > TIME_LIMIT - 0.08) break;\n        Grid start = candidates[i].grid;\n        int iter = max(120, 220 - i * 30);\n        local_search(start, reads, placements, timer, bestGrid, bestScore, rng, iter);\n    }\n\n    if (timer.elapsed() < TIME_LIMIT - 0.08) {\n        Grid candidate = bestGrid;\n        int refined = placement_vote_refine(candidate, reads, placements,\n                                            workBestPid, workBestMatch,\n                                            counts, timer, 2);\n        if (refined > bestScore) {\n            bestScore = refined;\n            bestGrid = candidate;\n        }\n    }\n\n    if (timer.elapsed() < TIME_LIMIT - 0.03) {\n        Grid start = bestGrid;\n        local_search(start, reads, placements, timer, bestGrid, bestScore, rng, 110);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        string line(N, 'A');\n        for (int j = 0; j < N; ++j)\n            line[j] = static_cast<char>('A' + bestGrid[i][j]);\n        cout << line << '\\n';\n    }\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst long long INFLL = (1LL << 60);\nconst long long INF_CAP = (1LL << 55);\nconst long long MAX_WEIGHT = (1LL << 50);\nconst int PLAN_KEEP = 6;\nconst int TSP_PLAN_LIMIT = 7;\nconst int TSP_TARGET_LIMIT = 260;\nconst int EXACT_TSP_LIMIT = 17;\n\nconst int di[4] = {-1, 1, 0, 0};\nconst int dj[4] = {0, 0, -1, 1};\n\nstruct Dinic {\n    struct Edge { int to; long long cap; int rev; };\n    int N;\n    vector<vector<Edge>> G;\n    vector<int> level, prog;\n    Dinic(int n = 0) { init(n); }\n    void init(int n) { N = n; G.assign(n, {}); }\n    void add_edge(int fr, int to, long long cap) {\n        Edge f{to, cap, (int)G[to].size()};\n        Edge b{fr, 0, (int)G[fr].size()};\n        G[fr].push_back(f);\n        G[to].push_back(b);\n    }\n    bool bfs(int s, int t) {\n        level.assign(N, -1);\n        queue<int> q;\n        level[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            for (const auto &e : G[v])\n                if (e.cap > 0 && level[e.to] < 0) {\n                    level[e.to] = level[v] + 1;\n                    q.push(e.to);\n                }\n        }\n        return level[t] >= 0;\n    }\n    long long dfs(int v, int t, long long f) {\n        if (v == t) return f;\n        for (int &i = prog[v]; i < (int)G[v].size(); ++i) {\n            Edge &e = G[v][i];\n            if (e.cap > 0 && level[v] < level[e.to]) {\n                long long d = dfs(e.to, t, min(f, e.cap));\n                if (d > 0) {\n                    e.cap -= d;\n                    G[e.to][e.rev].cap += d;\n                    return d;\n                }\n            }\n        }\n        return 0;\n    }\n    long long max_flow(int s, int t) {\n        long long flow = 0;\n        while (bfs(s, t)) {\n            prog.assign(N, 0);\n            while (true) {\n                long long f = dfs(s, t, (1LL << 60));\n                if (!f) break;\n                flow += f;\n            }\n        }\n        return flow;\n    }\n};\n\nstruct SideParam {\n    long long base = 10;\n    long long coeffStart = 1;\n    int anchor1 = -1;\n    long long coeffAnchor1 = 0;\n    int anchor2 = -1;\n    long long coeffAnchor2 = 0;\n    long long lenFactor = 0;\n    int noiseRange = 0;\n};\nstruct WeightParam {\n    SideParam row;\n    SideParam col;\n};\nstruct Cover {\n    vector<char> row_cover;\n    vector<char> col_cover;\n};\nstruct Plan {\n    vector<int> targets;\n    long long approx;\n};\nstruct CandidatePlan {\n    long long approx;\n    vector<int> targets;\n};\n\nstruct SPCache {\n    int N, total;\n    const vector<int> &cost;\n    unordered_map<int,int> idx;\n    vector<vector<long long>> dist;\n    vector<vector<int>> parent;\n    SPCache(int N, const vector<int> &cost) : N(N), total(N * N), cost(cost) {\n        idx.reserve(512);\n    }\n    int get(int root) {\n        auto it = idx.find(root);\n        if (it != idx.end()) return it->second;\n        vector<long long> d(total, INFLL);\n        vector<int> p(total, -1);\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        d[root] = 0;\n        pq.emplace(0, root);\n        while (!pq.empty()) {\n            auto [distU, u] = pq.top(); pq.pop();\n            if (distU != d[u]) continue;\n            int ui = u / N, uj = u % N;\n            for (int dir = 0; dir < 4; ++dir) {\n                int vi = ui + di[dir];\n                int vj = uj + dj[dir];\n                if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n                int v = vi * N + vj;\n                if (cost[v] < 0) continue;\n                long long nd = distU + cost[v];\n                if (nd < d[v]) {\n                    d[v] = nd;\n                    p[v] = u;\n                    pq.emplace(nd, v);\n                }\n            }\n        }\n        int id = dist.size();\n        idx[root] = id;\n        dist.push_back(move(d));\n        parent.push_back(move(p));\n        return id;\n    }\n};\n\nchar dir_char(int from, int to, int N) {\n    int fi = from / N, fj = from % N;\n    int ti = to / N, tj = to % N;\n    if (ti == fi - 1 && tj == fj) return 'U';\n    if (ti == fi + 1 && tj == fj) return 'D';\n    if (tj == fj - 1 && ti == fi) return 'L';\n    if (tj == fj + 1 && ti == fi) return 'R';\n    return 'U';\n}\n\nvoid run_dijkstra(int source, const vector<int> &cost, int N,\n                  vector<long long> &dist, vector<int> *parent) {\n    int total = N * N;\n    dist.assign(total, INFLL);\n    if (parent) parent->assign(total, -1);\n    using P = pair<long long,int>;\n    priority_queue<P, vector<P>, greater<P>> pq;\n    dist[source] = 0;\n    pq.emplace(0, source);\n    while (!pq.empty()) {\n        auto [d, u] = pq.top(); pq.pop();\n        if (d != dist[u]) continue;\n        int ui = u / N, uj = u % N;\n        for (int dir = 0; dir < 4; ++dir) {\n            int vi = ui + di[dir];\n            int vj = uj + dj[dir];\n            if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n            int v = vi * N + vj;\n            if (cost[v] < 0) continue;\n            long long nd = d + cost[v];\n            if (nd < dist[v]) {\n                dist[v] = nd;\n                if (parent) (*parent)[v] = u;\n                pq.emplace(nd, v);\n            }\n        }\n    }\n}\n\nCover solve_weighted_cover(const vector<vector<int>> &adj,\n                           const vector<long long> &w_row,\n                           const vector<long long> &w_col) {\n    int R = (int)w_row.size();\n    int C = (int)w_col.size();\n    Dinic din(R + C + 2);\n    int SRC = 0, SNK = R + C + 1;\n    for (int r = 0; r < R; ++r) din.add_edge(SRC, 1 + r, min(MAX_WEIGHT, w_row[r]));\n    for (int r = 0; r < R; ++r)\n        for (int c : adj[r]) din.add_edge(1 + r, 1 + R + c, INF_CAP);\n    for (int c = 0; c < C; ++c) din.add_edge(1 + R + c, SNK, min(MAX_WEIGHT, w_col[c]));\n    din.max_flow(SRC, SNK);\n    vector<char> vis(din.N, 0);\n    queue<int> q;\n    q.push(SRC);\n    vis[SRC] = 1;\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        for (const auto &e : din.G[v]) if (e.cap > 0 && !vis[e.to]) {\n            vis[e.to] = 1;\n            q.push(e.to);\n        }\n    }\n    vector<char> row_cover(R, 0), col_cover(C, 0);\n    for (int r = 0; r < R; ++r) row_cover[r] = !vis[1 + r];\n    for (int c = 0; c < C; ++c) col_cover[c] = vis[1 + R + c];\n    return {row_cover, col_cover};\n}\n\nvoid reduce_targets(vector<int> &targets,\n                    const vector<char> &row_cover,\n                    const vector<char> &col_cover,\n                    const vector<int> &row_id,\n                    const vector<int> &col_id,\n                    const vector<long long> &distStart,\n                    int start_id,\n                    int R, int C) {\n    if (targets.empty()) {\n        targets.push_back(start_id);\n        return;\n    }\n    vector<int> row_cnt(R, 0), col_cnt(C, 0);\n    for (int cell : targets) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && r < R && row_cover[r]) ++row_cnt[r];\n        if (c >= 0 && c < C && col_cover[c]) ++col_cnt[c];\n    }\n    vector<int> order(targets.size());\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        long long da = distStart[targets[a]];\n        long long db = distStart[targets[b]];\n        if (da != db) return da > db;\n        return targets[a] < targets[b];\n    });\n    vector<char> keep(targets.size(), 1);\n    for (int idx : order) {\n        int cell = targets[idx];\n        int r = row_id[cell];\n        int c = col_id[cell];\n        bool essential = false;\n        if (r >= 0 && r < R && row_cover[r] && row_cnt[r] <= 1) essential = true;\n        if (c >= 0 && c < C && col_cover[c] && col_cnt[c] <= 1) essential = true;\n        if (!essential) {\n            keep[idx] = 0;\n            if (r >= 0 && r < R && row_cover[r]) --row_cnt[r];\n            if (c >= 0 && c < C && col_cover[c]) --col_cnt[c];\n        }\n    }\n    vector<int> newTargets;\n    for (int i = 0; i < (int)targets.size(); ++i)\n        if (keep[i]) newTargets.push_back(targets[i]);\n    if (newTargets.empty()) newTargets.push_back(start_id);\n    targets.swap(newTargets);\n}\n\nPlan build_plan(const vector<char> &row_cover,\n                const vector<char> &col_cover,\n                const vector<vector<int>> &row_cells,\n                const vector<vector<int>> &col_cells,\n                const vector<int> &row_id,\n                const vector<int> &col_id,\n                const vector<int> &best_row_cell,\n                const vector<int> &best_col_cell,\n                const vector<int> &sorted_cells,\n                const vector<long long> &distStart,\n                int total, int start_id, int R, int C) {\n    vector<char> row_need = row_cover;\n    vector<char> col_need = col_cover;\n    vector<char> is_target(total, 0);\n    vector<int> targets;\n    targets.reserve(R + C);\n    auto add_target = [&](int cell) {\n        if (cell < 0) return;\n        if (!is_target[cell]) {\n            is_target[cell] = 1;\n            targets.push_back(cell);\n        }\n    };\n    for (int cell : sorted_cells) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && c >= 0 && r < R && c < C && row_need[r] && col_need[c]) {\n            add_target(cell);\n            row_need[r] = 0;\n            col_need[c] = 0;\n        }\n    }\n    for (int r = 0; r < R; ++r) if (row_need[r]) {\n        int cell = best_row_cell[r];\n        if (cell == -1 && !row_cells[r].empty()) cell = row_cells[r][0];\n        add_target(cell);\n        row_need[r] = 0;\n    }\n    for (int c = 0; c < C; ++c) if (col_need[c]) {\n        int cell = best_col_cell[c];\n        if (cell == -1 && !col_cells[c].empty()) cell = col_cells[c][0];\n        add_target(cell);\n        col_need[c] = 0;\n    }\n    vector<char> row_hit(R, 0), col_hit(C, 0);\n    for (int cell : targets) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && r < R) row_hit[r] = 1;\n        if (c >= 0 && c < C) col_hit[c] = 1;\n    }\n    for (int r = 0; r < R; ++r) if (row_cover[r] && !row_hit[r]) {\n        int cell = best_row_cell[r];\n        if (cell == -1 && !row_cells[r].empty()) cell = row_cells[r][0];\n        add_target(cell);\n        row_hit[r] = 1;\n        int c = col_id[cell];\n        if (c >= 0 && c < C) col_hit[c] = 1;\n    }\n    for (int c = 0; c < C; ++c) if (col_cover[c] && !col_hit[c]) {\n        int cell = best_col_cell[c];\n        if (cell == -1 && !col_cells[c].empty()) cell = col_cells[c][0];\n        add_target(cell);\n        col_hit[c] = 1;\n        int r = row_id[cell];\n        if (r >= 0 && r < R) row_hit[r] = 1;\n    }\n    reduce_targets(targets, row_cover, col_cover, row_id, col_id, distStart, start_id, R, C);\n    long long approx = 0;\n    for (int cell : targets) {\n        long long d = distStart[cell];\n        if (d >= INFLL / 4) d = INFLL / 4;\n        approx += d;\n    }\n    approx += 20LL * targets.size();\n    if (targets.empty()) targets.push_back(start_id);\n    return {targets, approx};\n}\n\nbool buildSteinerTree(const vector<int> &targets, vector<vector<int>> &treeAdj,\n                      int start_id, const vector<int> &cost, int N) {\n    int total = (int)cost.size();\n    vector<char> need(total, 0);\n    int remaining = 0;\n    for (int cell : targets) if (!need[cell]) { need[cell] = 1; ++remaining; }\n    vector<char> in_tree(total, 0);\n    vector<int> treeNodes;\n    treeNodes.reserve(total);\n    in_tree[start_id] = 1;\n    treeNodes.push_back(start_id);\n    if (need[start_id]) { need[start_id] = 0; --remaining; }\n    vector<long long> dist(total, INFLL);\n    vector<int> parent(total, -1);\n    while (remaining > 0) {\n        fill(dist.begin(), dist.end(), INFLL);\n        fill(parent.begin(), parent.end(), -1);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        for (int node : treeNodes) {\n            dist[node] = 0;\n            parent[node] = -1;\n            pq.emplace(0, node);\n        }\n        int best = -1;\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (need[u]) { best = u; break; }\n            int ui = u / N, uj = u % N;\n            for (int dir = 0; dir < 4; ++dir) {\n                int vi = ui + di[dir];\n                int vj = uj + dj[dir];\n                if (vi < 0 || vi >= N || vj < 0 || vj >= N) continue;\n                int v = vi * N + vj;\n                if (cost[v] < 0) continue;\n                long long nd = d + cost[v];\n                if (nd < dist[v]) {\n                    dist[v] = nd;\n                    parent[v] = u;\n                    pq.emplace(nd, v);\n                }\n            }\n        }\n        if (best == -1) return false;\n        need[best] = 0;\n        --remaining;\n        if (in_tree[best]) continue;\n        vector<int> path;\n        int cur = best;\n        while (!in_tree[cur]) {\n            path.push_back(cur);\n            cur = parent[cur];\n            if (cur == -1) return false;\n        }\n        int prev = cur;\n        for (int i = (int)path.size() - 1; i >= 0; --i) {\n            int node = path[i];\n            treeAdj[node].push_back(prev);\n            treeAdj[prev].push_back(node);\n            if (!in_tree[node]) {\n                in_tree[node] = 1;\n                treeNodes.push_back(node);\n            }\n            if (need[node]) {\n                need[node] = 0;\n                --remaining;\n            }\n            prev = node;\n        }\n    }\n    return true;\n}\n\nvoid buildTreeSP(const vector<int> &targets, vector<vector<int>> &treeAdj,\n                 int start_id, const vector<int> &parent, int total) {\n    vector<char> required(total, 0);\n    required[start_id] = 1;\n    for (int cell : targets) {\n        int cur = cell;\n        while (cur != -1 && !required[cur]) {\n            required[cur] = 1;\n            if (cur == start_id) break;\n            cur = parent[cur];\n        }\n    }\n    for (int v = 0; v < total; ++v) {\n        if (!required[v]) continue;\n        int p = parent[v];\n        if (p == -1 || !required[p]) continue;\n        treeAdj[v].push_back(p);\n        treeAdj[p].push_back(v);\n    }\n}\n\nstring buildRoute(const vector<vector<int>> &treeAdj, int start_id, int N) {\n    string route;\n    route.reserve(treeAdj.size() * 2);\n    struct Frame { int node, parent, idx; };\n    vector<Frame> st;\n    st.push_back({start_id, -1, 0});\n    while (!st.empty()) {\n        Frame &fr = st.back();\n        if (fr.idx == (int)treeAdj[fr.node].size()) {\n            st.pop_back();\n            if (fr.parent != -1) route.push_back(dir_char(fr.node, fr.parent, N));\n            continue;\n        }\n        int nxt = treeAdj[fr.node][fr.idx++];\n        if (nxt == fr.parent) continue;\n        route.push_back(dir_char(fr.node, nxt, N));\n        st.push_back({nxt, fr.node, 0});\n    }\n    return route;\n}\n\nlong long simulateRoute(const string &route, const vector<int> &cost,\n                        int N, int si, int sj) {\n    int i = si, j = sj;\n    long long total = 0;\n    for (char mv : route) {\n        if (mv == 'U') --i;\n        else if (mv == 'D') ++i;\n        else if (mv == 'L') --j;\n        else if (mv == 'R') ++j;\n        if (i < 0 || i >= N || j < 0 || j >= N) return INFLL;\n        int id = i * N + j;\n        if (cost[id] < 0) return INFLL;\n        total += cost[id];\n    }\n    if (i != si || j != sj) return INFLL;\n    return total;\n}\n\nint nearestRoadByManhattan(int ti, int tj, const vector<int> &road_cells, int N) {\n    int best = -1;\n    int bestDist = INT_MAX;\n    for (int cell : road_cells) {\n        int ci = cell / N, cj = cell % N;\n        int d = abs(ci - ti) + abs(cj - tj);\n        if (d < bestDist) {\n            bestDist = d;\n            best = cell;\n        }\n    }\n    if (best == -1 && !road_cells.empty()) best = road_cells[0];\n    return best;\n}\n\nvoid add_plan_candidate(const Plan &plan, vector<CandidatePlan> &pool) {\n    pool.push_back({plan.approx, plan.targets});\n    sort(pool.begin(), pool.end(), [](const CandidatePlan &a, const CandidatePlan &b) {\n        if (a.approx != b.approx) return a.approx < b.approx;\n        return a.targets.size() < b.targets.size();\n    });\n    if ((int)pool.size() > PLAN_KEEP) pool.resize(PLAN_KEEP);\n}\n\ntemplate<class Visitor>\nbool append_shortest_path_collect(int from, int to, string &route,\n                                  SPCache &cache, int N, Visitor &&visit) {\n    if (from == to) return true;\n    int idx = cache.get(from);\n    const auto &parent = cache.parent[idx];\n    int cur = to;\n    vector<int> path;\n    while (true) {\n        if (cur == from) break;\n        int p = parent[cur];\n        if (p == -1) return false;\n        path.push_back(cur);\n        cur = p;\n    }\n    int prev = from;\n    for (int i = (int)path.size() - 1; i >= 0; --i) {\n        int node = path[i];\n        route.push_back(dir_char(prev, node, N));\n        visit(node);\n        prev = node;\n    }\n    return true;\n}\n\nbool exact_tsp_cycle(const vector<vector<long long>> &dist,\n                     vector<int> &order, long long &bestLen, long long best_limit) {\n    int T = dist.size();\n    if (T > EXACT_TSP_LIMIT) return false;\n    int FULL = 1 << T;\n    vector<vector<long long>> dp(FULL, vector<long long>(T, INFLL));\n    vector<vector<int>> prv(FULL, vector<int>(T, -1));\n    dp[1][0] = 0;\n    for (int mask = 1; mask < FULL; ++mask) {\n        if ((mask & 1) == 0) continue;\n        for (int last = 0; last < T; ++last) {\n            if (!(mask & (1 << last))) continue;\n            long long cur = dp[mask][last];\n            if (cur >= INFLL / 4) continue;\n            for (int nxt = 1; nxt < T; ++nxt) {\n                if (mask & (1 << nxt)) continue;\n                long long nd = cur + dist[last][nxt];\n                int nmask = mask | (1 << nxt);\n                if (nd < dp[nmask][nxt]) {\n                    dp[nmask][nxt] = nd;\n                    prv[nmask][nxt] = last;\n                }\n            }\n        }\n    }\n    int full = FULL - 1;\n    long long best = INFLL;\n    int bestLast = -1;\n    for (int last = 1; last < T; ++last) {\n        long long val = dp[full][last];\n        if (val >= INFLL / 4) continue;\n        val += dist[last][0];\n        if (val < best) {\n            best = val;\n            bestLast = last;\n        }\n    }\n    if (bestLast == -1) return false;\n    if (best_limit < INFLL / 4 && best >= best_limit) return false;\n    vector<int> ord(T);\n    int mask = full;\n    int cur = bestLast;\n    for (int i = T - 1; i >= 1; --i) {\n        ord[i] = cur;\n        int prev = prv[mask][cur];\n        mask ^= (1 << cur);\n        cur = prev;\n    }\n    ord[0] = 0;\n    order = ord;\n    bestLen = best;\n    return true;\n}\n\nlong long cycle_len(const vector<vector<long long>> &dist,\n                    const vector<int> &ord, long long best_limit) {\n    int T = ord.size();\n    long long len = 0;\n    for (int i = 0; i < T; ++i) {\n        long long d = dist[ord[i]][ord[(i + 1) % T]];\n        len += d;\n        if (best_limit < INFLL / 4 && len >= best_limit) return INFLL;\n    }\n    return len;\n}\n\nvoid two_opt(vector<int> &ord, const vector<vector<long long>> &dist) {\n    int T = ord.size();\n    bool improved = true;\n    int iter = 0;\n    while (improved && iter < 40) {\n        improved = false;\n        ++iter;\n        for (int i = 1; i < T - 1; ++i) {\n            for (int j = i + 1; j < T; ++j) {\n                int a = ord[i - 1];\n                int b = ord[i];\n                int c = ord[j];\n                int d = ord[(j + 1) % T];\n                long long delta = (dist[a][c] + dist[b][d]) - (dist[a][b] + dist[c][d]);\n                if (delta < 0) {\n                    reverse(ord.begin() + i, ord.begin() + j + 1);\n                    improved = true;\n                }\n            }\n        }\n    }\n}\n\nbool heuristic_tsp(const vector<vector<long long>> &dist, vector<int> &bestOrd,\n                   long long &bestLen, long long best_limit, mt19937 &rng) {\n    int T = dist.size();\n    vector<int> order(T);\n    iota(order.begin(), order.end(), 0);\n    vector<char> used(T, 0);\n    order[0] = 0;\n    used[0] = 1;\n    for (int pos = 1; pos < T; ++pos) {\n        int prev = order[pos - 1];\n        long long bestd = INFLL;\n        int best = -1;\n        for (int j = 1; j < T; ++j) if (!used[j]) {\n            long long d = dist[prev][j];\n            if (d < bestd) {\n                bestd = d;\n                best = j;\n            }\n        }\n        if (best == -1) return false;\n        order[pos] = best;\n        used[best] = 1;\n    }\n    two_opt(order, dist);\n    bestOrd = order;\n    bestLen = cycle_len(dist, order, best_limit);\n    if (bestLen >= INFLL / 4) return false;\n\n    int restarts = max(6, min(12, T / 12 + 4));\n    for (int r = 0; r < restarts; ++r) {\n        vector<int> cur(T);\n        cur[0] = 0;\n        for (int i = 1; i < T; ++i) cur[i] = i;\n        shuffle(cur.begin() + 1, cur.end(), rng);\n        two_opt(cur, dist);\n        long long len = cycle_len(dist, cur, min(bestLen, best_limit));\n        if (len < bestLen) {\n            bestLen = len;\n            bestOrd = cur;\n        }\n    }\n    return true;\n}\n\nbool build_cycle_route(const vector<int> &nodes, const vector<int> &order,\n                       SPCache &cache, int N, string &route) {\n    int T = nodes.size();\n    vector<int> pos(cache.total, -1);\n    for (int i = 0; i < T; ++i) pos[nodes[i]] = i;\n    vector<char> visited(T, 0);\n    auto visitor = [&](int cell) {\n        int idx = pos[cell];\n        if (idx != -1 && !visited[idx]) visited[idx] = 1;\n    };\n    visitor(nodes[0]);\n    int current = nodes[0];\n    for (int idxPos = 1; idxPos < T; ++idxPos) {\n        int idx = order[idxPos];\n        if (idx == 0 || visited[idx]) continue;\n        if (!append_shortest_path_collect(current, nodes[idx], route, cache, N, visitor))\n            return false;\n        current = nodes[idx];\n    }\n    for (int idx = 1; idx < T; ++idx) {\n        if (visited[idx]) continue;\n        if (!append_shortest_path_collect(current, nodes[idx], route, cache, N, visitor))\n            return false;\n        current = nodes[idx];\n    }\n    if (!append_shortest_path_collect(current, nodes[0], route, cache, N, visitor))\n        return false;\n    return true;\n}\n\nbool try_tsp_route(const vector<int> &planTargets, int start_id, const vector<int> &cost,\n                   int N, int si, int sj, string &best_route, long long &best_cost,\n                   SPCache &cache, mt19937 &rng) {\n    vector<int> nodes = planTargets;\n    nodes.push_back(start_id);\n    sort(nodes.begin(), nodes.end());\n    nodes.erase(unique(nodes.begin(), nodes.end()), nodes.end());\n    int start_pos = find(nodes.begin(), nodes.end(), start_id) - nodes.begin();\n    if (start_pos != 0) swap(nodes[0], nodes[start_pos]);\n    int T = nodes.size();\n    if (T <= 1) {\n        if (best_cost > 0) {\n            best_cost = 0;\n            best_route.clear();\n        }\n        return true;\n    }\n    if (T > TSP_TARGET_LIMIT) return false;\n    vector<vector<long long>> dist(T, vector<long long>(T, INFLL));\n    for (int i = 0; i < T; ++i) {\n        int idx = cache.get(nodes[i]);\n        const auto &d = cache.dist[idx];\n        for (int j = 0; j < T; ++j) dist[i][j] = d[nodes[j]];\n    }\n    for (int i = 0; i < T; ++i)\n        for (int j = 0; j < T; ++j)\n            if (dist[i][j] >= INFLL / 4) return false;\n\n    vector<int> order;\n    long long bestLen = INFLL;\n    if (!exact_tsp_cycle(dist, order, bestLen, best_cost)) {\n        if (!heuristic_tsp(dist, order, bestLen, best_cost, rng)) return false;\n    }\n    if (bestLen >= INFLL / 4) return false;\n\n    string route;\n    route.reserve((size_t)bestLen + 32);\n    if (!build_cycle_route(nodes, order, cache, N, route)) return false;\n\n    long long travel = simulateRoute(route, cost, N, si, sj);\n    if (travel < best_cost) {\n        best_cost = travel;\n        best_route = route;\n        return true;\n    }\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, si, sj;\n    if (!(cin >> N >> si >> sj)) return 0;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n    int total = N * N;\n    auto idx = [&](int i, int j) { return i * N + j; };\n    vector<int> cost(total, -1);\n    vector<int> road_cells;\n    road_cells.reserve(total);\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            if (grid[i][j] != '#') {\n                int id = idx(i, j);\n                cost[id] = grid[i][j] - '0';\n                road_cells.push_back(id);\n            }\n    int start_id = idx(si, sj);\n\n    vector<int> row_id(total, -1);\n    vector<vector<int>> row_cells;\n    for (int i = 0; i < N; ++i) {\n        int j = 0;\n        while (j < N) {\n            if (grid[i][j] == '#') { ++j; continue; }\n            vector<int> cells;\n            while (j < N && grid[i][j] != '#') {\n                int cell = idx(i, j);\n                row_id[cell] = (int)row_cells.size();\n                cells.push_back(cell);\n                ++j;\n            }\n            row_cells.push_back(move(cells));\n        }\n    }\n    int R = (int)row_cells.size();\n\n    vector<int> col_id(total, -1);\n    vector<vector<int>> col_cells;\n    for (int j = 0; j < N; ++j) {\n        int i = 0;\n        while (i < N) {\n            if (grid[i][j] == '#') { ++i; continue; }\n            vector<int> cells;\n            while (i < N && grid[i][j] != '#') {\n                int cell = idx(i, j);\n                col_id[cell] = (int)col_cells.size();\n                cells.push_back(cell);\n                ++i;\n            }\n            col_cells.push_back(move(cells));\n        }\n    }\n    int C = (int)col_cells.size();\n\n    vector<vector<int>> row_adj(R);\n    for (int cell : road_cells) {\n        int r = row_id[cell];\n        int c = col_id[cell];\n        if (r >= 0 && c >= 0) row_adj[r].push_back(c);\n    }\n    for (auto &vec : row_adj) {\n        sort(vec.begin(), vec.end());\n        vec.erase(unique(vec.begin(), vec.end()), vec.end());\n    }\n    vector<int> row_len(R), col_len(C);\n    for (int r = 0; r < R; ++r) row_len[r] = (int)row_cells[r].size();\n    for (int c = 0; c < C; ++c) col_len[c] = (int)col_cells[c].size();\n\n    vector<long long> distStart(total, INFLL);\n    vector<int> parentStart(total, -1);\n    run_dijkstra(start_id, cost, N, distStart, &parentStart);\n\n    vector<int> sorted_cells = road_cells;\n    sort(sorted_cells.begin(), sorted_cells.end(), [&](int a, int b) {\n        if (distStart[a] != distStart[b]) return distStart[a] < distStart[b];\n        return a < b;\n    });\n\n    vector<int> best_row_cell(R, -1), best_col_cell(C, -1);\n    for (int r = 0; r < R; ++r)\n        for (int cell : row_cells[r])\n            if (best_row_cell[r] == -1 || distStart[cell] < distStart[best_row_cell[r]])\n                best_row_cell[r] = cell;\n    for (int c = 0; c < C; ++c)\n        for (int cell : col_cells[c])\n            if (best_col_cell[c] == -1 || distStart[cell] < distStart[best_col_cell[c]])\n                best_col_cell[c] = cell;\n\n    vector<int> anchor_cells;\n    anchor_cells.push_back(start_id);\n    vector<pair<int,int>> points = {{N/2, N/2}, {0,0}, {0,N-1}, {N-1,0}, {N-1,N-1}};\n    for (auto [pi, pj] : points) {\n        int cell = nearestRoadByManhattan(pi, pj, road_cells, N);\n        if (cell != -1 && find(anchor_cells.begin(), anchor_cells.end(), cell) == anchor_cells.end())\n            anchor_cells.push_back(cell);\n    }\n    mt19937 rng(712367 + N * 131 + si * 37 + sj);\n    while ((int)anchor_cells.size() < 7 && (int)anchor_cells.size() < (int)road_cells.size()) {\n        int cell = road_cells[rng() % road_cells.size()];\n        if (find(anchor_cells.begin(), anchor_cells.end(), cell) == anchor_cells.end())\n            anchor_cells.push_back(cell);\n    }\n\n    int numAnchors = (int)anchor_cells.size();\n    vector<vector<long long>> distAnchors;\n    distAnchors.reserve(numAnchors);\n    distAnchors.push_back(distStart);\n    for (int a = 1; a < numAnchors; ++a) {\n        vector<long long> dist(total, INFLL);\n        run_dijkstra(anchor_cells[a], cost, N, dist, nullptr);\n        distAnchors.push_back(dist);\n    }\n\n    vector<vector<long long>> bestRowDistAnchor(numAnchors, vector<long long>(R, INFLL));\n    vector<vector<long long>> bestColDistAnchor(numAnchors, vector<long long>(C, INFLL));\n    for (int a = 0; a < numAnchors; ++a) {\n        const auto &dist = distAnchors[a];\n        for (int r = 0; r < R; ++r) {\n            long long best = INFLL;\n            for (int cell : row_cells[r]) best = min(best, dist[cell]);\n            bestRowDistAnchor[a][r] = best;\n        }\n        for (int c = 0; c < C; ++c) {\n            long long best = INFLL;\n            for (int cell : col_cells[c]) best = min(best, dist[cell]);\n            bestColDistAnchor[a][c] = best;\n        }\n    }\n\n    vector<long long> wRow(R), wCol(C);\n\n    auto assign_weights = [&](const SideParam &param,\n                              const vector<vector<long long>> &bestDistByAnchor,\n                              const vector<int> &lengths,\n                              vector<long long> &weights) {\n        uniform_int_distribution<int> noiseDist(0, max(0, param.noiseRange));\n        for (int s = 0; s < (int)weights.size(); ++s) {\n            long long w = param.base;\n            auto add = [&](int anchor, long long coeff) {\n                if (anchor < 0 || coeff == 0) return;\n                long long d = bestDistByAnchor[anchor][s];\n                if (d >= INFLL / 4) d = INFLL / 4;\n                w += coeff * d;\n            };\n            add(0, param.coeffStart);\n            add(param.anchor1, param.coeffAnchor1);\n            add(param.anchor2, param.coeffAnchor2);\n            w += param.lenFactor * (long long)lengths[s];\n            if (param.noiseRange > 0) w += noiseDist(rng);\n            if (w < 1) w = 1;\n            if (w > MAX_WEIGHT) w = MAX_WEIGHT;\n            weights[s] = w;\n        }\n    };\n\n    auto apply_spec = [&](const WeightParam &spec) {\n        assign_weights(spec.row, bestRowDistAnchor, row_len, wRow);\n        assign_weights(spec.col, bestColDistAnchor, col_len, wCol);\n    };\n\n    WeightParam base_spec;\n    base_spec.row.base = 40;\n    base_spec.row.coeffStart = 1;\n    base_spec.col = base_spec.row;\n\n    WeightParam unweighted_spec;\n    unweighted_spec.row.base = 1;\n    unweighted_spec.row.coeffStart = 0;\n    unweighted_spec.col = unweighted_spec.row;\n\n    auto random_side = [&](int numAnchors) {\n        SideParam sp;\n        uniform_int_distribution<int> baseDist(15, 120);\n        uniform_int_distribution<int> coeffStartDist(0, 2);\n        uniform_int_distribution<int> lenDist(-4, 4);\n        uniform_int_distribution<int> noiseDist(0, 80);\n        sp.base = baseDist(rng);\n        sp.coeffStart = coeffStartDist(rng);\n        sp.lenFactor = lenDist(rng);\n        sp.noiseRange = noiseDist(rng);\n        if (numAnchors >= 2 && uniform_int_distribution<int>(0, 99)(rng) < 70) {\n            sp.anchor1 = uniform_int_distribution<int>(0, numAnchors - 1)(rng);\n            sp.coeffAnchor1 = uniform_int_distribution<int>(1, 3)(rng);\n        }\n        if (numAnchors >= 3 && uniform_int_distribution<int>(0, 99)(rng) < 35) {\n            do {\n                sp.anchor2 = uniform_int_distribution<int>(0, numAnchors - 1)(rng);\n            } while (sp.anchor2 == sp.anchor1);\n            sp.coeffAnchor2 = uniform_int_distribution<int>(1, 2)(rng);\n        }\n        return sp;\n    };\n\n    auto random_spec = [&](int numAnchors) {\n        WeightParam spec;\n        spec.row = random_side(numAnchors);\n        spec.col = random_side(numAnchors);\n        int bias = uniform_int_distribution<int>(0, 2)(rng);\n        if (bias == 0) {\n            spec.row.base = max(5LL, spec.row.base / 2);\n            spec.col.base += 30;\n        } else if (bias == 1) {\n            spec.col.base = max(5LL, spec.col.base / 2);\n            spec.row.base += 30;\n        }\n        return spec;\n    };\n\n    vector<int> matchRow(R, -1), matchCol(C, -1);\n    vector<char> seen(C, 0);\n    function<bool(int)> dfs_match = [&](int u) -> bool {\n        for (int v : row_adj[u]) {\n            if (seen[v]) continue;\n            seen[v] = 1;\n            if (matchCol[v] == -1 || dfs_match(matchCol[v])) {\n                matchRow[u] = v;\n                matchCol[v] = u;\n                return true;\n            }\n        }\n        return false;\n    };\n    for (int u = 0; u < R; ++u) {\n        fill(seen.begin(), seen.end(), 0);\n        dfs_match(u);\n    }\n    vector<char> visRow(R, 0), visCol(C, 0);\n    queue<int> qq;\n    for (int u = 0; u < R; ++u) if (matchRow[u] == -1) {\n        visRow[u] = 1;\n        qq.push(u);\n    }\n    while (!qq.empty()) {\n        int u = qq.front(); qq.pop();\n        for (int v : row_adj[u]) {\n            if (matchRow[u] == v) continue;\n            if (visCol[v]) continue;\n            visCol[v] = 1;\n            int mu = matchCol[v];\n            if (mu != -1 && !visRow[mu]) {\n                visRow[mu] = 1;\n                qq.push(mu);\n            }\n        }\n    }\n    vector<char> row_cover_un(R, 0), col_cover_un(C, 0);\n    for (int r = 0; r < R; ++r) row_cover_un[r] = !visRow[r];\n    for (int c = 0; c < C; ++c) col_cover_un[c] = visCol[c];\n\n    vector<CandidatePlan> planPool;\n    planPool.reserve(PLAN_KEEP + 5);\n    long long best_cost = INFLL;\n    string best_route;\n\n    auto evaluate_spec = [&](const WeightParam &spec) {\n        apply_spec(spec);\n        Cover cover = solve_weighted_cover(row_adj, wRow, wCol);\n        Plan plan = build_plan(cover.row_cover, cover.col_cover, row_cells, col_cells,\n                               row_id, col_id, best_row_cell, best_col_cell,\n                               sorted_cells, distStart, total, start_id, R, C);\n        add_plan_candidate(plan, planPool);\n        if (best_cost < INFLL / 4 && plan.approx > best_cost * 3 + 50000) return;\n        vector<vector<int>> treeAdj(total);\n        if (!buildSteinerTree(plan.targets, treeAdj, start_id, cost, N)) {\n            treeAdj.assign(total, {});\n            buildTreeSP(plan.targets, treeAdj, start_id, parentStart, total);\n        }\n        string route = buildRoute(treeAdj, start_id, N);\n        long long travel = simulateRoute(route, cost, N, si, sj);\n        if (travel < best_cost) {\n            best_cost = travel;\n            best_route = route;\n        }\n    };\n\n    auto startClock = chrono::steady_clock::now();\n    const double RANDOM_TIME_LIMIT = 2.7;\n\n    evaluate_spec(base_spec);\n    evaluate_spec(unweighted_spec);\n\n    int randomIter = 0;\n    const int MAX_RANDOM = 45;\n    while (randomIter < MAX_RANDOM) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startClock).count();\n        if (elapsed > RANDOM_TIME_LIMIT) break;\n        WeightParam spec = random_spec(numAnchors);\n        evaluate_spec(spec);\n        ++randomIter;\n    }\n\n    SPCache spCache(N, cost);\n    const double TSP_LIMIT = 2.98;\n    for (int i = 0; i < (int)planPool.size() && i < TSP_PLAN_LIMIT; ++i) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startClock).count();\n        if (elapsed > TSP_LIMIT) break;\n        try_tsp_route(planPool[i].targets, start_id, cost, N, si, sj,\n                      best_route, best_cost, spCache, rng);\n    }\n\n    if (best_route.empty()) {\n        vector<vector<int>> treeAdj(total);\n        vector<int> fallbackTargets = road_cells;\n        buildTreeSP(fallbackTargets, treeAdj, start_id, parentStart, total);\n        best_route = buildRoute(treeAdj, start_id, N);\n    }\n\n    cout << best_route << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Node {\n    long long priority;\n    int task;\n    bool operator<(const Node& other) const {\n        if (priority != other.priority) return priority < other.priority; // max-heap\n        return task > other.task;\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>> req(N, vector<int>(K));\n    for (int i = 0; i < N; ++i)\n        for (int k = 0; k < K; ++k)\n            cin >> req[i][k];\n\n    vector<vector<int>> adj(N);\n    vector<int> indeg(N, 0), outdeg(N, 0);\n    for (int i = 0; i < R; ++i) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        adj[u].push_back(v);\n        indeg[v]++;\n        outdeg[u]++;\n    }\n\n    vector<int> sum_d(N, 0), max_d(N, 0);\n    long long total_diff = 0;\n    for (int i = 0; i < N; ++i) {\n        int s = 0, m = 0;\n        for (int k = 0; k < K; ++k) {\n            s += req[i][k];\n            m = max(m, req[i][k]);\n        }\n        sum_d[i] = s;\n        max_d[i] = m;\n        total_diff += s;\n    }\n\n    vector<int> level(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        int best = 0;\n        for (int v : adj[i]) best = max(best, level[v] + 1);\n        level[i] = best;\n    }\n\n    vector<int> sorted_diff = sum_d;\n    sort(sorted_diff.begin(), sorted_diff.end());\n    auto quantile = [&](double q) {\n        int idx = min(N - 1, (int)round(q * (N - 1)));\n        return max(1, sorted_diff[idx]);\n    };\n    int thr_easy = quantile(0.50);\n    int thr_medium = quantile(0.80);\n\n    auto category_of = [&](int task) -> int {\n        int val = sum_d[task];\n        if (val <= thr_easy) return 0;\n        if (val <= thr_medium) return 1;\n        return 2;\n    };\n\n    vector<int> ready_since(N, (int)1e9);\n    vector<int> task_state(N, 0);\n    priority_queue<Node> pq;\n\n    auto calc_priority = [&](int task, int day) -> long long {\n        long long wait = max(0, day - ready_since[task]);\n        long long val = 2'000'000LL * level[task];\n        val += 15'000LL * outdeg[task];\n        val += 80'000LL * wait;\n        val += 300LL * sum_d[task];\n        val += 1'200LL * max_d[task];\n        val += (1000 - task);\n        return val;\n    };\n    auto push_task = [&](int task, int day) {\n        pq.push({calc_priority(task, day), task});\n    };\n\n    for (int i = 0; i < N; ++i)\n        if (indeg[i] == 0) {\n            task_state[i] = 1;\n            ready_since[i] = 1;\n            push_task(i, 1);\n        }\n\n    vector<int> worker_task(M, -1), worker_start(M, -1);\n    double avg_diff = (double)total_diff / max(1, N);\n    double baseAbility = max(1.0, avg_diff / 8.0);\n    const double MIN_ABILITY = 0.3;\n    const double MAX_ABILITY = 520.0;\n    const double alpha_all = 0.33;\n    const double alpha_cat = 0.45;\n    const double alpha_recent = 0.60;\n\n    vector<double> ability_all(M, baseAbility);\n    vector<array<double,3>> ability_cat(M, {baseAbility, baseAbility, baseAbility});\n    vector<array<int,3>> ability_cnt(M, {0,0,0});\n    vector<double> ability_recent(M, baseAbility);\n\n    auto clamp = [&](double &x) {\n        if (x < MIN_ABILITY) x = MIN_ABILITY;\n        if (x > MAX_ABILITY) x = MAX_ABILITY;\n    };\n\n    vector<char> assignedFlag(N, 0);\n    vector<int> assignedList;\n\n    auto predict_time = [&](int worker, int task, int day) -> double {\n        int cat = category_of(task);\n        int cnt = ability_cnt[worker][cat];\n        double weight_cat = min(0.55, 0.25 + 0.08 * cnt);\n        double weight_recent = 0.20;\n        double weight_all = max(0.0, 1.0 - weight_cat - weight_recent);\n        if (weight_all < 0.15) {\n            weight_recent += weight_all - 0.15;\n            weight_all = 0.15;\n            if (weight_recent < 0.10) {\n                weight_cat += weight_recent - 0.10;\n                weight_recent = 0.10;\n            }\n        }\n        double ability = weight_cat * ability_cat[worker][cat]\n                       + weight_all * ability_all[worker]\n                       + weight_recent * ability_recent[worker];\n        ability = max(ability, MIN_ABILITY);\n        double predicted = max(1.0, sum_d[task] / ability);\n        predicted += 0.09 * max(0, level[task] - 3);\n        predicted -= 0.065 * max(0, day - ready_since[task]);\n        double penalty = 0.35 / (cnt + 1.0);\n        predicted *= (1.0 + penalty);\n        return predicted;\n    };\n\n    int day = 1;\n    while (true) {\n        vector<int> idle_workers;\n        for (int j = 0; j < M; ++j)\n            if (worker_task[j] == -1)\n                idle_workers.push_back(j);\n\n        vector<int> readyTasks;\n        if (!idle_workers.empty()) {\n            int limit = max(25, (int)idle_workers.size() * 4);\n            limit = min(limit, 200);\n            readyTasks.reserve(limit);\n            while ((int)readyTasks.size() < limit && !pq.empty()) {\n                Node cur = pq.top();\n                long long real = calc_priority(cur.task, day);\n                if (cur.priority != real) {\n                    pq.pop();\n                    if (task_state[cur.task] == 1)\n                        pq.push({real, cur.task});\n                    continue;\n                }\n                pq.pop();\n                if (task_state[cur.task] != 1) continue;\n                readyTasks.push_back(cur.task);\n            }\n        }\n\n        vector<int> task_order = readyTasks;\n        sort(task_order.begin(), task_order.end(), [&](int a, int b) {\n            if (level[a] != level[b]) return level[a] > level[b];\n            int waitA = max(0, day - ready_since[a]);\n            int waitB = max(0, day - ready_since[b]);\n            if (waitA != waitB) return waitA > waitB;\n            if (outdeg[a] != outdeg[b]) return outdeg[a] > outdeg[b];\n            if (sum_d[a] != sum_d[b]) return sum_d[a] > sum_d[b];\n            return a < b;\n        });\n\n        vector<char> workerUsed(M, 0);\n        vector<pair<int,int>> assignments;\n        assignedList.clear();\n\n        int remaining = idle_workers.size();\n        for (int task : task_order) {\n            if (remaining == 0) break;\n            double bestScore = 1e100;\n            int bestWorker = -1;\n            for (int w : idle_workers) {\n                if (workerUsed[w]) continue;\n                double predicted = predict_time(w, task, day);\n                if (predicted + 1e-9 < bestScore ||\n                    (fabs(predicted - bestScore) <= 1e-9 &&\n                     (bestWorker == -1 || ability_all[w] > ability_all[bestWorker]))) {\n                    bestScore = predicted;\n                    bestWorker = w;\n                }\n            }\n            if (bestWorker != -1) {\n                worker_task[bestWorker] = task;\n                worker_start[bestWorker] = day;\n                task_state[task] = 2;\n                workerUsed[bestWorker] = 1;\n                assignments.emplace_back(bestWorker, task);\n                assignedFlag[task] = 1;\n                assignedList.push_back(task);\n                remaining--;\n            }\n        }\n\n        for (int task : readyTasks)\n            if (!assignedFlag[task])\n                push_task(task, day);\n        for (int task : assignedList) assignedFlag[task] = 0;\n\n        cout << assignments.size();\n        for (auto &p : assignments) cout << ' ' << (p.first + 1) << ' ' << (p.second + 1);\n        cout << '\\n';\n        cout.flush();\n\n        int n_finish;\n        if (!(cin >> n_finish)) return 0;\n        if (n_finish == -1) break;\n\n        vector<int> finished_workers(n_finish);\n        for (int i = 0; i < n_finish; ++i) {\n            cin >> finished_workers[i];\n            finished_workers[i]--;\n        }\n\n        for (int w : finished_workers) {\n            if (w < 0 || w >= M) continue;\n            int task = worker_task[w];\n            if (task == -1) continue;\n            int duration = day - worker_start[w] + 1;\n            duration = max(duration, 1);\n            double difficulty = max(1, sum_d[task]);\n            double ratio = difficulty / duration;\n\n            ability_all[w] = ability_all[w] * (1.0 - alpha_all) + ratio * alpha_all;\n            clamp(ability_all[w]);\n\n            int cat = category_of(task);\n            ability_cat[w][cat] = ability_cat[w][cat] * (1.0 - alpha_cat) + ratio * alpha_cat;\n            clamp(ability_cat[w][cat]);\n            ability_cnt[w][cat] = min(1000, ability_cnt[w][cat] + 1);\n\n            ability_recent[w] = ability_recent[w] * (1.0 - alpha_recent) + ratio * alpha_recent;\n            clamp(ability_recent[w]);\n\n            worker_task[w] = -1;\n            worker_start[w] = -1;\n            task_state[task] = 3;\n\n            for (int nxt : adj[task]) {\n                if (--indeg[nxt] == 0) {\n                    task_state[nxt] = 1;\n                    ready_since[nxt] = day + 1;\n                    push_task(nxt, day + 1);\n                }\n            }\n        }\n\n        day++;\n        if (day > 2100) break;\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int ORDER_COUNT = 1000;\nconst int K = 50;\nconst int OFFICE = 400;\n\nstruct Order {\n    int ax, ay, cx, cy;\n    int len;\n    int base;\n    int officeScore;\n};\n\nstruct Node {\n    int order;\n    int type; // 0: pickup, 1: drop\n};\n\nstruct Point {\n    int x, y;\n};\n\ninline int manhattan(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\ninline int manhattan(const Point& a, const Point& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nconst Point OFFICE_POINT{OFFICE, OFFICE};\n\nstruct XorShift {\n    uint64_t state;\n    XorShift(uint64_t seed = 88172645463393265ULL) {\n        if (seed == 0) seed = 88172645463393265ULL;\n        state = seed;\n    }\n    inline uint64_t nextU64() {\n        state ^= state << 7;\n        state ^= state >> 9;\n        return state;\n    }\n    inline int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nPoint nodePoint(const Node& node, const vector<Order>& orders) {\n    const Order& ord = orders[node.order];\n    if (node.type == 0) return {ord.ax, ord.ay};\n    return {ord.cx, ord.cy};\n}\n\nlong long calcCostFromCoords(const vector<Point>& coords) {\n    Point cur = OFFICE_POINT;\n    long long cost = 0;\n    for (const Point& p : coords) {\n        cost += manhattan(cur, p);\n        cur = p;\n    }\n    cost += manhattan(cur, OFFICE_POINT);\n    return cost;\n}\n\nlong long calcNodeRouteCost(const vector<Node>& nodes, const vector<Order>& orders) {\n    vector<Point> coords;\n    coords.reserve(nodes.size());\n    for (const Node& node : nodes) coords.push_back(nodePoint(node, orders));\n    return calcCostFromCoords(coords);\n}\n\nvector<int> buildInitialRoute(const vector<int>& selected, const vector<Order>& orders, XorShift& rng) {\n    vector<int> remaining = selected;\n    vector<int> route;\n    route.reserve(selected.size());\n    Point cur = OFFICE_POINT;\n    while (!remaining.empty()) {\n        int bestIdx = 0;\n        int bestDist = INT_MAX;\n        for (int i = 0; i < (int)remaining.size(); ++i) {\n            int id = remaining[i];\n            int dist = manhattan(cur.x, cur.y, orders[id].ax, orders[id].ay);\n            if (dist < bestDist ||\n                (dist == bestDist && orders[id].len < orders[remaining[bestIdx]].len) ||\n                (dist == bestDist && orders[id].len == orders[remaining[bestIdx]].len && rng.nextInt(2))) {\n                bestDist = dist;\n                bestIdx = i;\n            }\n        }\n        int chosen = remaining[bestIdx];\n        route.push_back(chosen);\n        cur = {orders[chosen].cx, orders[chosen].cy};\n        remaining[bestIdx] = remaining.back();\n        remaining.pop_back();\n    }\n    return route;\n}\n\nlong long calcOrderRouteCost(const vector<int>& sequence, const vector<Order>& orders) {\n    Point cur = OFFICE_POINT;\n    long long cost = 0;\n    for (int id : sequence) {\n        const Order& ord = orders[id];\n        Point pick{ord.ax, ord.ay};\n        Point drop{ord.cx, ord.cy};\n        cost += manhattan(cur, pick);\n        cost += manhattan(pick, drop);\n        cur = drop;\n    }\n    cost += manhattan(cur, OFFICE_POINT);\n    return cost;\n}\n\nlong long twoOptImprove(vector<int>& route, const vector<Order>& orders) {\n    int n = route.size();\n    if (n <= 1) return calcOrderRouteCost(route, orders);\n    long long bestCost = calcOrderRouteCost(route, orders);\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int i = 0; i < n - 1; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                reverse(route.begin() + i, route.begin() + j + 1);\n                long long newCost = calcOrderRouteCost(route, orders);\n                if (newCost < bestCost) {\n                    bestCost = newCost;\n                    improved = true;\n                } else {\n                    reverse(route.begin() + i, route.begin() + j + 1);\n                }\n            }\n        }\n    }\n    return bestCost;\n}\n\nvector<Node> buildNodesFromSequence(const vector<int>& sequence) {\n    vector<Node> nodes;\n    nodes.reserve(sequence.size() * 2);\n    for (int id : sequence) {\n        nodes.push_back({id, 0});\n        nodes.push_back({id, 1});\n    }\n    return nodes;\n}\n\nvoid recomputePositions(const vector<Node>& nodes,\n                        const vector<int>& selected,\n                        vector<int>& pickPos,\n                        vector<int>& dropPos) {\n    for (int id : selected) {\n        pickPos[id] = -1;\n        dropPos[id] = -1;\n    }\n    for (int i = 0; i < (int)nodes.size(); ++i) {\n        if (nodes[i].type == 0) pickPos[nodes[i].order] = i;\n        else dropPos[nodes[i].order] = i;\n    }\n}\n\ninline void removeNode(vector<Node>& nodes, vector<Point>& coords, int pos, long long& cost) {\n    int sz = coords.size();\n    Point prev = (pos == 0 ? OFFICE_POINT : coords[pos - 1]);\n    Point curr = coords[pos];\n    Point next = (pos + 1 == sz ? OFFICE_POINT : coords[pos + 1]);\n    cost += manhattan(prev, next) - manhattan(prev, curr) - manhattan(curr, next);\n    nodes.erase(nodes.begin() + pos);\n    coords.erase(coords.begin() + pos);\n}\n\ninline void insertNode(vector<Node>& nodes, vector<Point>& coords, int pos,\n                       const Node& node, const Point& point, long long& cost) {\n    Point prev = (pos == 0 ? OFFICE_POINT : coords[pos - 1]);\n    Point next = (pos == (int)coords.size() ? OFFICE_POINT : coords[pos]);\n    cost += -manhattan(prev, next) + manhattan(prev, point) + manhattan(point, next);\n    nodes.insert(nodes.begin() + pos, node);\n    coords.insert(coords.begin() + pos, point);\n}\n\nbool saMoveSingle(vector<Node>& nodes,\n                  vector<Point>& coords,\n                  vector<int>& pickPos,\n                  vector<int>& dropPos,\n                  const vector<int>& selected,\n                  long long& currCost,\n                  long long& bestCost,\n                  vector<Node>& bestNodes,\n                  vector<Point>& bestCoords,\n                  double temp,\n                  XorShift& rng) {\n    int L = nodes.size();\n    if (L <= 1) return false;\n    int origPos = rng.nextInt(L);\n    Node node = nodes[origPos];\n    Point point = coords[origPos];\n    long long prevCost = currCost;\n\n    removeNode(nodes, coords, origPos, currCost);\n    int n = nodes.size();\n    int insertPos = rng.nextInt(n + 1);\n\n    bool feasible = true;\n    if (node.type == 0) {\n        int dropIdx = dropPos[node.order];\n        if (dropIdx == -1) feasible = false;\n        else {\n            if (dropIdx > origPos) dropIdx--;\n            if (insertPos > dropIdx) feasible = false;\n        }\n    } else {\n        int pickIdx = pickPos[node.order];\n        if (pickIdx == -1) feasible = false;\n        else {\n            if (pickIdx > origPos) pickIdx--;\n            if (insertPos <= pickIdx) feasible = false;\n        }\n    }\n\n    if (!feasible) {\n        insertNode(nodes, coords, origPos, node, point, currCost);\n        currCost = prevCost;\n        return false;\n    }\n\n    insertNode(nodes, coords, insertPos, node, point, currCost);\n    long long newCost = currCost;\n    bool accept = false;\n    if (newCost <= prevCost) accept = true;\n    else {\n        double prob = exp((double)(prevCost - newCost) / temp);\n        if (prob > rng.nextDouble()) accept = true;\n    }\n    if (accept) {\n        if (newCost < bestCost) {\n            bestCost = newCost;\n            bestNodes = nodes;\n            bestCoords = coords;\n        }\n        recomputePositions(nodes, selected, pickPos, dropPos);\n    } else {\n        removeNode(nodes, coords, insertPos, currCost);\n        insertNode(nodes, coords, origPos, node, point, currCost);\n        currCost = prevCost;\n    }\n    return true;\n}\n\nbool saMovePair(vector<Node>& nodes,\n                vector<Point>& coords,\n                vector<int>& pickPos,\n                vector<int>& dropPos,\n                const vector<int>& selected,\n                long long& currCost,\n                long long& bestCost,\n                vector<Node>& bestNodes,\n                vector<Point>& bestCoords,\n                double temp,\n                XorShift& rng) {\n    if (selected.empty()) return false;\n    int orderId = selected[rng.nextInt(selected.size())];\n    int posPick = pickPos[orderId];\n    int posDrop = dropPos[orderId];\n    if (posPick == -1 || posDrop == -1) return false;\n    if (posPick > posDrop) swap(posPick, posDrop);\n\n    Node pickNode = nodes[posPick];\n    Point pickPoint = coords[posPick];\n    Node dropNode = nodes[posDrop];\n    Point dropPoint = coords[posDrop];\n    long long prevCost = currCost;\n\n    removeNode(nodes, coords, posDrop, currCost);\n    removeNode(nodes, coords, posPick, currCost);\n\n    int n = nodes.size();\n    int insertPick = rng.nextInt(n + 1);\n    insertNode(nodes, coords, insertPick, pickNode, pickPoint, currCost);\n\n    int sizeAfterPick = nodes.size();\n    int insertDrop = rng.nextInt(sizeAfterPick - insertPick) + insertPick + 1;\n    insertNode(nodes, coords, insertDrop, dropNode, dropPoint, currCost);\n\n    long long newCost = currCost;\n    bool accept = false;\n    if (newCost <= prevCost) accept = true;\n    else {\n        double prob = exp((double)(prevCost - newCost) / temp);\n        if (prob > rng.nextDouble()) accept = true;\n    }\n    if (accept) {\n        if (newCost < bestCost) {\n            bestCost = newCost;\n            bestNodes = nodes;\n            bestCoords = coords;\n        }\n        recomputePositions(nodes, selected, pickPos, dropPos);\n    } else {\n        removeNode(nodes, coords, insertDrop, currCost);\n        removeNode(nodes, coords, insertPick, currCost);\n        insertNode(nodes, coords, posPick, pickNode, pickPoint, currCost);\n        insertNode(nodes, coords, posDrop, dropNode, dropPoint, currCost);\n        currCost = prevCost;\n    }\n    return true;\n}\n\nlong long runNodeSA(vector<Node>& nodes,\n                    const vector<int>& selected,\n                    const vector<Order>& orders,\n                    double timeLimit,\n                    XorShift& rng,\n                    chrono::steady_clock::time_point globalStart,\n                    double globalLimit) {\n    vector<Point> coords(nodes.size());\n    for (int i = 0; i < (int)nodes.size(); ++i) coords[i] = nodePoint(nodes[i], orders);\n    long long currCost = calcCostFromCoords(coords);\n    long long bestCost = currCost;\n    vector<Node> bestNodes = nodes;\n    vector<Point> bestCoords = coords;\n\n    vector<int> pickPos(ORDER_COUNT, -1), dropPos(ORDER_COUNT, -1);\n    recomputePositions(nodes, selected, pickPos, dropPos);\n\n    if (timeLimit <= 1e-6) {\n        nodes = bestNodes;\n        return bestCost;\n    }\n\n    const double START_TEMP = 2000.0;\n    const double END_TEMP = 5.0;\n    const double LOG_RATIO = std::log(END_TEMP / START_TEMP);\n    auto localStart = chrono::steady_clock::now();\n    double temp = START_TEMP;\n    long long iter = 0;\n    while (true) {\n        if ((iter & 0x3FFLL) == 0) {\n            auto now = chrono::steady_clock::now();\n            double elapsed = chrono::duration<double>(now - localStart).count();\n            double globalElapsed = chrono::duration<double>(now - globalStart).count();\n            if (elapsed > timeLimit || globalElapsed > globalLimit) break;\n            double progress = min(1.0, elapsed / timeLimit);\n            temp = START_TEMP * exp(LOG_RATIO * progress);\n        }\n        ++iter;\n        int op = rng.nextInt(100);\n        if (op < 70) {\n            saMoveSingle(nodes, coords, pickPos, dropPos, selected,\n                         currCost, bestCost, bestNodes, bestCoords, temp, rng);\n        } else {\n            saMovePair(nodes, coords, pickPos, dropPos, selected,\n                       currCost, bestCost, bestNodes, bestCoords, temp, rng);\n        }\n    }\n    nodes = bestNodes;\n    return bestCost;\n}\n\nvector<pair<int, int>> buildPathFromNodes(const vector<Node>& nodes, const vector<Order>& orders) {\n    vector<pair<int, int>> path;\n    path.reserve(nodes.size() + 2);\n    path.emplace_back(OFFICE_POINT.x, OFFICE_POINT.y);\n    for (const Node& node : nodes) {\n        Point p = nodePoint(node, orders);\n        path.emplace_back(p.x, p.y);\n    }\n    path.emplace_back(OFFICE_POINT.x, OFFICE_POINT.y);\n    return path;\n}\n\nstruct RouteSolution {\n    vector<int> selectedOrders;\n    vector<Node> nodes;\n    long long cost = (1LL << 60);\n};\n\nvector<int> extractSelectedOrders(const vector<Node>& nodes) {\n    vector<int> res;\n    vector<char> seen(ORDER_COUNT, 0);\n    for (const Node& node : nodes) {\n        if (node.type == 0 && !seen[node.order]) {\n            seen[node.order] = 1;\n            res.push_back(node.order);\n        }\n    }\n    return res;\n}\n\nRouteSolution optimizeSet(const vector<int>& selected,\n                          double saTime,\n                          const vector<Order>& orders,\n                          XorShift& rng,\n                          chrono::steady_clock::time_point globalStart,\n                          double globalLimit) {\n    RouteSolution sol;\n    sol.selectedOrders = selected;\n    vector<int> route = buildInitialRoute(selected, orders, rng);\n    twoOptImprove(route, orders);\n    vector<Node> nodes = buildNodesFromSequence(route);\n    long long cost = runNodeSA(nodes, selected, orders, saTime, rng, globalStart, globalLimit);\n    sol.cost = cost;\n    sol.nodes = nodes;\n    return sol;\n}\n\nstruct PosDelta {\n    int pos;\n    int delta;\n};\n\nvector<PosDelta> enumerateInsertOptions(const vector<Point>& coords,\n                                        const Point& insertPoint,\n                                        int startPos,\n                                        int limit,\n                                        int randomExtra,\n                                        XorShift& rng) {\n    int M = coords.size();\n    startPos = max(0, min(startPos, M));\n    vector<PosDelta> opts;\n    opts.reserve(M - startPos + 1);\n    for (int pos = startPos; pos <= M; ++pos) {\n        const Point& prev = (pos == 0 ? OFFICE_POINT : coords[pos - 1]);\n        const Point& next = (pos == M ? OFFICE_POINT : coords[pos]);\n        int delta = manhattan(prev, insertPoint) + manhattan(insertPoint, next) - manhattan(prev, next);\n        opts.push_back({pos, delta});\n    }\n    sort(opts.begin(), opts.end(), [](const PosDelta& a, const PosDelta& b) {\n        if (a.delta != b.delta) return a.delta < b.delta;\n        return a.pos < b.pos;\n    });\n    vector<PosDelta> res;\n    int take = min(limit, (int)opts.size());\n    for (int i = 0; i < take; ++i) res.push_back(opts[i]);\n    int attempts = randomExtra;\n    while (attempts-- > 0 && (int)res.size() < (int)opts.size()) {\n        int idx = rng.nextInt(opts.size());\n        int pos = opts[idx].pos;\n        bool exist = false;\n        for (const auto& pd : res) if (pd.pos == pos) { exist = true; break; }\n        if (!exist) res.push_back(opts[idx]);\n    }\n    return res;\n}\n\ntemplate <class T>\nvoid shuffleWithRNG(vector<T>& vec, XorShift& rng) {\n    for (int i = (int)vec.size() - 1; i > 0; --i) {\n        int j = rng.nextInt(i + 1);\n        swap(vec[i], vec[j]);\n    }\n}\n\nvoid swapImprove(RouteSolution& sol,\n                 const vector<Order>& orders,\n                 const vector<int>& ranking,\n                 double timeLimit,\n                 chrono::steady_clock::time_point globalStart,\n                 double globalLimit,\n                 XorShift& rng) {\n    if (timeLimit <= 1e-4) return;\n    auto localStart = chrono::steady_clock::now();\n    vector<Node>& bestNodes = sol.nodes;\n    long long bestCost = sol.cost;\n\n    vector<int> selectedOrders = extractSelectedOrders(bestNodes);\n    vector<char> inSelected(ORDER_COUNT, 0);\n    for (int id : selectedOrders) inSelected[id] = 1;\n\n    const int CAND_LIMIT = 100;\n    const int PICK_LIMIT = 10;\n    const int DROP_LIMIT = 12;\n    const int RANDOM_PICK = 3;\n    const int RANDOM_DROP = 3;\n\n    auto timeExceeded = [&]() -> bool {\n        auto now = chrono::steady_clock::now();\n        double localElapsed = chrono::duration<double>(now - localStart).count();\n        double globalElapsed = chrono::duration<double>(now - globalStart).count();\n        return (localElapsed > timeLimit) || (globalElapsed > globalLimit);\n    };\n\n    bool timeup = false;\n    while (!timeup) {\n        if (timeExceeded()) break;\n        vector<int> candidatePool;\n        candidatePool.reserve(CAND_LIMIT);\n        for (int idx : ranking) {\n            if (!inSelected[idx]) {\n                candidatePool.push_back(idx);\n                if ((int)candidatePool.size() >= CAND_LIMIT) break;\n            }\n        }\n        if (candidatePool.empty()) break;\n        shuffleWithRNG(candidatePool, rng);\n        vector<int> removalOrder = selectedOrders;\n        shuffleWithRNG(removalOrder, rng);\n\n        bool improvement = false;\n\n        for (int removeId : removalOrder) {\n            if (timeExceeded()) { timeup = true; break; }\n\n            vector<Node> baseNodes;\n            baseNodes.reserve(bestNodes.size() - 2);\n            for (const Node& node : bestNodes) {\n                if (node.order == removeId) continue;\n                baseNodes.push_back(node);\n            }\n            if ((int)baseNodes.size() != (int)bestNodes.size() - 2) continue;\n\n            long long baseCost = calcNodeRouteCost(baseNodes, orders);\n\n            vector<Point> baseCoords;\n            baseCoords.reserve(baseNodes.size());\n            for (const Node& node : baseNodes) {\n                baseCoords.push_back(nodePoint(node, orders));\n            }\n\n            for (int candId : candidatePool) {\n                if (inSelected[candId]) continue;\n                if (timeExceeded()) { timeup = true; break; }\n\n                Point pickPoint{orders[candId].ax, orders[candId].ay};\n                auto pickOptions = enumerateInsertOptions(baseCoords, pickPoint, 0, PICK_LIMIT, RANDOM_PICK, rng);\n                if (pickOptions.empty()) continue;\n\n                for (const auto& pickOpt : pickOptions) {\n                    if (timeExceeded()) { timeup = true; break; }\n\n                    int pickPos = pickOpt.pos;\n                    int deltaPick = pickOpt.delta;\n\n                    vector<Point> coordsWithPick = baseCoords;\n                    coordsWithPick.insert(coordsWithPick.begin() + pickPos, pickPoint);\n\n                    Point dropPoint{orders[candId].cx, orders[candId].cy};\n                    auto dropOptions = enumerateInsertOptions(coordsWithPick, dropPoint, pickPos + 1, DROP_LIMIT, RANDOM_DROP, rng);\n                    if (dropOptions.empty()) continue;\n\n                    if ((long long)baseCost + deltaPick + dropOptions[0].delta >= bestCost) continue;\n\n                    for (const auto& dropOpt : dropOptions) {\n                        long long candidateCost = (long long)baseCost + deltaPick + dropOpt.delta;\n                        if (candidateCost >= bestCost) continue;\n\n                        vector<Node> improved = baseNodes;\n                        improved.insert(improved.begin() + pickPos, Node{candId, 0});\n                        improved.insert(improved.begin() + dropOpt.pos, Node{candId, 1});\n\n                        bestNodes = move(improved);\n                        bestCost = candidateCost;\n                        inSelected[removeId] = 0;\n                        inSelected[candId] = 1;\n                        for (int& x : selectedOrders) if (x == removeId) { x = candId; break; }\n                        improvement = true;\n                        break;\n                    }\n                    if (timeExceeded()) { timeup = true; break; }\n                    if (improvement) break;\n                }\n                if (timeExceeded()) { timeup = true; break; }\n                if (improvement) break;\n            }\n            if (timeExceeded()) { timeup = true; break; }\n            if (improvement) break;\n        }\n        if (timeExceeded()) break;\n        if (!improvement) break;\n    }\n\n    sol.nodes = bestNodes;\n    sol.cost = calcNodeRouteCost(sol.nodes, orders);\n    sol.selectedOrders = extractSelectedOrders(sol.nodes);\n}\n\nvector<pair<int, int>> pathFromNodes(const vector<Node>& nodes, const vector<Order>& orders) {\n    return buildPathFromNodes(nodes, orders);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<Order> orders(ORDER_COUNT);\n    for (int i = 0; i < ORDER_COUNT; ++i) {\n        cin >> orders[i].ax >> orders[i].ay >> orders[i].cx >> orders[i].cy;\n        orders[i].len = manhattan(orders[i].ax, orders[i].ay, orders[i].cx, orders[i].cy);\n        orders[i].base = manhattan(OFFICE, OFFICE, orders[i].ax, orders[i].ay) +\n                         orders[i].len +\n                         manhattan(orders[i].cx, orders[i].cy, OFFICE, OFFICE);\n        orders[i].officeScore = manhattan(OFFICE, OFFICE, orders[i].ax, orders[i].ay) +\n                                manhattan(OFFICE, OFFICE, orders[i].cx, orders[i].cy);\n    }\n\n    vector<int> idx(ORDER_COUNT);\n    iota(idx.begin(), idx.end(), 0);\n\n    vector<int> byBase = idx;\n    sort(byBase.begin(), byBase.end(), [&](int a, int b) {\n        if (orders[a].base != orders[b].base) return orders[a].base < orders[b].base;\n        return a < b;\n    });\n    vector<int> byOffice = idx;\n    sort(byOffice.begin(), byOffice.end(), [&](int a, int b) {\n        if (orders[a].officeScore != orders[b].officeScore) return orders[a].officeScore < orders[b].officeScore;\n        return a < b;\n    });\n    vector<int> byLen = idx;\n    sort(byLen.begin(), byLen.end(), [&](int a, int b) {\n        if (orders[a].len != orders[b].len) return orders[a].len < orders[b].len;\n        return a < b;\n    });\n\n    auto firstK = [&](const vector<int>& arr) {\n        vector<int> res;\n        for (int i = 0; i < K; ++i) res.push_back(arr[i]);\n        return res;\n    };\n\n    XorShift rng(chrono::steady_clock::now().time_since_epoch().count());\n\n    vector<vector<int>> candidateSets;\n    candidateSets.push_back(firstK(byBase));\n    candidateSets.push_back(firstK(byOffice));\n    candidateSets.push_back(firstK(byLen));\n\n    auto makeRandomSet = [&](const vector<int>& pool, int noiseRange) -> vector<int> {\n        vector<pair<long long, int>> tmp;\n        tmp.reserve(pool.size());\n        for (int id : pool) {\n            long long noise = (long long)(rng.nextU64() % (noiseRange + 1));\n            long long score = (long long)orders[id].base + noise;\n            tmp.emplace_back(score, id);\n        }\n        sort(tmp.begin(), tmp.end());\n        vector<int> res;\n        for (int i = 0; i < K && i < (int)tmp.size(); ++i) res.push_back(tmp[i].second);\n        return res;\n    };\n\n    vector<int> poolTop;\n    int poolTopSize = min(300, ORDER_COUNT);\n    for (int i = 0; i < poolTopSize; ++i) poolTop.push_back(byBase[i]);\n    if (!poolTop.empty()) candidateSets.push_back(makeRandomSet(poolTop, 4000));\n    candidateSets.push_back(makeRandomSet(idx, 8000));\n\n    auto globalStart = chrono::steady_clock::now();\n    const double GLOBAL_LIMIT = 1.95;\n    const double STAGE1_LIMIT = 1.35;\n\n    int maxSets = min(5, (int)candidateSets.size());\n    RouteSolution bestSolution;\n    for (int setIdx = 0; setIdx < maxSets; ++setIdx) {\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - globalStart).count();\n        if (elapsed >= STAGE1_LIMIT || elapsed >= GLOBAL_LIMIT - 0.4) break;\n        double remainingStage = STAGE1_LIMIT - elapsed;\n        double globalRemaining = GLOBAL_LIMIT - elapsed;\n        if (remainingStage <= 0.05 || globalRemaining <= 0.4) break;\n        int setsLeft = maxSets - setIdx;\n        double saTime = min(0.35, remainingStage / setsLeft);\n        saTime = max(saTime, 0.02);\n        RouteSolution sol = optimizeSet(candidateSets[setIdx], saTime, orders, rng, globalStart, GLOBAL_LIMIT);\n        if (sol.cost < bestSolution.cost) bestSolution = sol;\n    }\n    if (bestSolution.cost == (1LL << 60)) {\n        bestSolution = optimizeSet(candidateSets[0], 0.2, orders, rng, globalStart, GLOBAL_LIMIT);\n    }\n\n    auto ensureSelectedOrders = [&]() {\n        bestSolution.selectedOrders = extractSelectedOrders(bestSolution.nodes);\n    };\n    ensureSelectedOrders();\n    bestSolution.cost = calcNodeRouteCost(bestSolution.nodes, orders);\n\n    auto now = chrono::steady_clock::now();\n    double elapsed = chrono::duration<double>(now - globalStart).count();\n    double remaining = GLOBAL_LIMIT - elapsed;\n\n    if (remaining > 0.1) {\n        double swapTime = min(0.45, remaining - 0.05);\n        swapImprove(bestSolution, orders, byBase, swapTime, globalStart, GLOBAL_LIMIT, rng);\n        ensureSelectedOrders();\n    }\n\n    now = chrono::steady_clock::now();\n    elapsed = chrono::duration<double>(now - globalStart).count();\n    remaining = GLOBAL_LIMIT - elapsed;\n    if (remaining > 0.08) {\n        double finalTime = min(0.2, remaining - 0.03);\n        if (finalTime > 0.0) {\n            vector<int> selected = extractSelectedOrders(bestSolution.nodes);\n            long long newCost = runNodeSA(bestSolution.nodes, selected, orders, finalTime, rng, globalStart, GLOBAL_LIMIT);\n            bestSolution.cost = newCost;\n            ensureSelectedOrders();\n        }\n    }\n\n    vector<int> orderOutput = extractSelectedOrders(bestSolution.nodes);\n    orderOutput.resize(K);\n\n    vector<pair<int, int>> path = buildPathFromNodes(bestSolution.nodes, orders);\n\n    cout << K;\n    for (int id : orderOutput) cout << ' ' << (id + 1);\n    cout << '\\n';\n    cout << path.size();\n    for (auto [x, y] : path) cout << ' ' << x << ' ' << y;\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 400;\nconstexpr int M = 1995;\nconstexpr int LIGHT_LIMIT = 135;\n\nstruct Edge {\n    int u, v;\n    int d;\n    bool in_ref = false;\n};\n\nstruct DSU {\n    vector<int> parent;\n    vector<int> sz;\n    int comp;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        parent.resize(n);\n        sz.assign(n, 1);\n        iota(parent.begin(), parent.end(), 0);\n        comp = n;\n    }\n    int find(int x) {\n        if (parent[x] == x) return x;\n        return parent[x] = find(parent[x]);\n    }\n    int root_size(int r) const { return sz[r]; }\n    int merge_roots(int a, int b, int &loser) {\n        a = find(a);\n        b = find(b);\n        if (a == b) {\n            loser = -1;\n            return a;\n        }\n        if (sz[a] < sz[b]) swap(a, b);\n        parent[b] = a;\n        sz[a] += sz[b];\n        sz[b] = 0;\n        comp--;\n        loser = b;\n        return a;\n    }\n};\n\nstruct CompStats {\n    int best_d;\n    int second_d;\n    int light_cnt;\n    int total;\n};\n\nint rounded_distance(const pair<int,int>& A, const pair<int,int>& B) {\n    long long dx = (long long)A.first - B.first;\n    long long dy = (long long)A.second - B.second;\n    double dist = std::sqrt((double)dx * dx + (double)dy * dy);\n    return (int)std::llround(dist);\n}\n\nvoid remove_future_edge(int ru, int rv,\n                        vector<vector<int>>& adj, vector<int>& out_deg) {\n    if (ru == rv) return;\n    if (adj[ru][rv] > 0) {\n        --adj[ru][rv];\n        --adj[rv][ru];\n    } else {\n        adj[ru][rv] = adj[rv][ru] = 0;\n    }\n    if (out_deg[ru] > 0) --out_deg[ru];\n    if (out_deg[rv] > 0) --out_deg[rv];\n}\n\nvoid merge_adj(int keep, int lose,\n               vector<vector<int>>& adj, vector<int>& out_deg) {\n    if (lose < 0 || keep == lose) return;\n    int between = adj[keep][lose];\n    adj[keep][lose] = adj[lose][keep] = 0;\n    out_deg[keep] = max(0, out_deg[keep] + out_deg[lose] - 2 * between);\n    out_deg[lose] = 0;\n    for (int c = 0; c < N; ++c) {\n        if (c == keep || c == lose) continue;\n        int add = adj[lose][c];\n        if (!add) continue;\n        adj[keep][c] += add;\n        adj[c][keep] = adj[keep][c];\n        adj[lose][c] = adj[c][lose] = 0;\n    }\n    adj[keep][keep] = 0;\n}\n\nvoid merge_edge_lists(int keep, int lose, vector<vector<int>>& comp_edges) {\n    if (lose < 0 || keep == lose) return;\n    if (comp_edges[keep].size() < comp_edges[lose].size())\n        comp_edges[keep].swap(comp_edges[lose]);\n    comp_edges[keep].insert(comp_edges[keep].end(),\n                            comp_edges[lose].begin(),\n                            comp_edges[lose].end());\n    vector<int>().swap(comp_edges[lose]);\n}\n\nCompStats get_comp_stats(int root, DSU &dsu,\n                         const vector<Edge>& edges,\n                         const vector<char>& processed,\n                         const vector<vector<int>>& comp_edges,\n                         int target = -1,\n                         int* best_cross = nullptr,\n                         int* cross_light = nullptr) {\n    const int INF_D = 1e9;\n    if (best_cross) *best_cross = INF_D;\n    if (cross_light) *cross_light = 0;\n\n    int best = INF_D;\n    int second = INF_D;\n    int lights = 0;\n    int total = 0;\n\n    for (int idx : comp_edges[root]) {\n        if (processed[idx]) continue;\n        const Edge &e = edges[idx];\n        int a = dsu.find(e.u);\n        int b = dsu.find(e.v);\n        if (a == b) continue;\n        if (a != root && b != root) continue;\n\n        ++total;\n        int d = e.d;\n        if (d < best) {\n            second = best;\n            best = d;\n        } else if (d < second) {\n            second = d;\n        }\n        if (d <= LIGHT_LIMIT) ++lights;\n\n        if (target != -1 && best_cross) {\n            int other = (a == root) ? b : a;\n            if (other == target) {\n                if (d < *best_cross) *best_cross = d;\n                if (cross_light && d <= LIGHT_LIMIT) ++(*cross_light);\n            }\n        }\n    }\n    if (best == INF_D) second = INF_D;\n    return {best, second, lights, total};\n}\n\ndouble compute_threshold(double progress, double comp_frac,\n                         const Edge& edge, double len,\n                         int sizeA, int sizeB,\n                         int outA, int outB,\n                         const CompStats& statsA,\n                         const CompStats& statsB,\n                         int best_cross, int cross_light,\n                         int direct_remaining,\n                         double slack_ratio, double slack_norm,\n                         int k_any, int k_direct) {\n    using std::clamp;\n    using std::pow;\n\n    constexpr double BASE_START = 1.03;\n    constexpr double BASE_END = 2.08;\n    constexpr double BASE_POWER = 0.78;\n    constexpr double COMP_COEFF = 0.32;\n    constexpr double COMP_POWER = 0.82;\n    constexpr double LAG_COEFF = 0.44;\n    constexpr double LEAD_COEFF = 0.11;\n    constexpr double SIZE_COEFF = 0.28;\n    constexpr double SIZE_POWER = 0.62;\n    constexpr double SMALLD_LIMIT = 150.0;\n    constexpr double SMALLD_COEFF = 0.30;\n    constexpr double LARGE_LIMIT = 260.0;\n    constexpr double LARGE_SPAN = 360.0;\n    constexpr double LARGE_COEFF = 0.11;\n    constexpr double REF_BONUS = 0.22;\n    constexpr double DENSITY_TARGET = 1.8;\n    constexpr double DENSITY_COEFF = 0.42;\n    constexpr double OUT_TARGET = 8.0;\n    constexpr double OUT_COEFF = 0.31;\n    constexpr double LEN_REFERENCE = 200.0;\n    constexpr double LEN_COEFF = 0.15;\n    constexpr double SCARCITY_COEFF = 0.17;\n    constexpr double LIGHT_NONE_BONUS = 0.18;\n    constexpr double LIGHT_FEW_BONUS = 0.09;\n    constexpr double LIGHT_MANY_PENALTY = 0.06;\n    constexpr double FUTURE_COEFF = 0.35;\n    constexpr double NO_FUTURE_BONUS = 0.33;\n    constexpr double GAP_COEFF = 0.13;\n    constexpr double GAP_WINDOW = 60.0;\n    constexpr double DIRECT_BONUS = 0.18;\n    constexpr double DIRECT_PENALTY = 0.03;\n    constexpr double CROSS_NONE_BONUS = 0.28;\n    constexpr double CROSS_ADV_COEFF = 0.33;\n    constexpr double CROSS_SUP_COEFF = 0.11;\n    constexpr double CROSS_LIGHT_COEFF = 0.05;\n    constexpr double SLACK_LOW_LIMIT = 0.25;\n    constexpr double SLACK_HIGH_LIMIT = 0.95;\n    constexpr double SLACK_LOW_COEFF = 0.30;\n    constexpr double SLACK_HIGH_COEFF = 0.17;\n    constexpr double SLACK_ABS_COEFF = 0.22;\n    constexpr double EXPECT_ANY_PULL = 0.18;\n    constexpr double EXPECT_DIRECT_PULL = 0.14;\n    constexpr double MIN_THRESHOLD = 0.92;\n    constexpr double MAX_THRESHOLD = 2.65;\n    constexpr int INF_D = 1e9;\n\n    progress = clamp(progress, 0.0, 1.0);\n    comp_frac = clamp(comp_frac, 0.0, 1.0);\n\n    double base = BASE_START + (BASE_END - BASE_START) * pow(progress, BASE_POWER);\n    base += COMP_COEFF * pow(comp_frac, COMP_POWER);\n    double lag = clamp(progress - comp_frac, 0.0, 1.0);\n    double lead = clamp(comp_frac - progress, 0.0, 1.0);\n    base += LAG_COEFF * lag;\n    base -= LEAD_COEFF * lead;\n\n    double thr = base;\n    double size_frac = double(sizeA + sizeB) / double(N);\n    thr += SIZE_COEFF * pow(size_frac, SIZE_POWER);\n\n    double small_factor = clamp((SMALLD_LIMIT - double(edge.d)) / SMALLD_LIMIT, -1.0, 1.0);\n    thr += SMALLD_COEFF * small_factor;\n    double large_factor = clamp((double(edge.d) - LARGE_LIMIT) / LARGE_SPAN, 0.0, 1.0);\n    thr -= LARGE_COEFF * large_factor;\n\n    if (edge.in_ref) thr += REF_BONUS;\n\n    double densityA = sizeA > 0 ? double(outA) / double(sizeA) : 0.0;\n    double densityB = sizeB > 0 ? double(outB) / double(sizeB) : 0.0;\n    double density = min(densityA, densityB);\n    double density_need = clamp((DENSITY_TARGET - density) / DENSITY_TARGET, 0.0, 1.5);\n    thr += DENSITY_COEFF * density_need;\n\n    int min_out = min(outA, outB);\n    double scarcity = clamp((OUT_TARGET - double(min_out)) / OUT_TARGET, 0.0, 1.5);\n    thr += OUT_COEFF * scarcity;\n\n    double len_effect = clamp((LEN_REFERENCE - len) / LEN_REFERENCE, -1.0, 1.0);\n    thr += LEN_COEFF * len_effect;\n\n    if (statsA.total <= 2) thr += SCARCITY_COEFF;\n    if (statsB.total <= 2) thr += SCARCITY_COEFF;\n\n    int light_total = statsA.light_cnt + statsB.light_cnt;\n    if (light_total == 0) thr += LIGHT_NONE_BONUS;\n    else if (light_total <= 2) thr += LIGHT_FEW_BONUS;\n    else if (light_total >= 7) thr -= LIGHT_MANY_PENALTY;\n\n    int best_future = min(statsA.best_d, statsB.best_d);\n    if (best_future >= INF_D / 2) {\n        thr += NO_FUTURE_BONUS;\n    } else {\n        double future_rel = (double(best_future) - double(edge.d)) /\n                            max(60.0, double(edge.d));\n        thr += FUTURE_COEFF * future_rel;\n    }\n\n    auto gap_value = [&](const CompStats& st) -> double {\n        if (st.second_d >= INF_D / 2 || st.best_d >= INF_D / 2) return GAP_WINDOW;\n        return double(st.second_d - st.best_d);\n    };\n    double gap = min(gap_value(statsA), gap_value(statsB));\n    if (gap < GAP_WINDOW) {\n        double gap_term = clamp((GAP_WINDOW - gap) / GAP_WINDOW, 0.0, 1.0);\n        thr -= GAP_COEFF * gap_term;\n    }\n\n    if (best_cross >= INF_D / 2) {\n        thr += CROSS_NONE_BONUS;\n    } else {\n        double diff = double(edge.d) - double(best_cross);\n        if (diff > 0) {\n            double norm = clamp(diff / max(40.0, double(edge.d)), 0.0, 1.5);\n            thr -= CROSS_ADV_COEFF * norm;\n            if (cross_light > 0) {\n                thr -= CROSS_LIGHT_COEFF * min(3, cross_light);\n            }\n        } else if (diff < 0) {\n            double norm = clamp((-diff) / max(40.0, double(edge.d)), 0.0, 1.0);\n            thr += CROSS_SUP_COEFF * norm;\n        }\n    }\n\n    if (direct_remaining == 0) {\n        thr += DIRECT_BONUS * (0.6 + 0.4 * size_frac);\n    } else {\n        thr -= DIRECT_PENALTY * min(direct_remaining, 4);\n    }\n\n    slack_ratio = clamp(slack_ratio, 0.0, 2.0);\n    slack_norm = clamp(slack_norm, 0.0, 1.0);\n    double low_term = clamp((SLACK_LOW_LIMIT - slack_ratio) / SLACK_LOW_LIMIT, 0.0, 1.0);\n    thr += SLACK_LOW_COEFF * low_term;\n    double high_term = clamp((slack_ratio - SLACK_HIGH_LIMIT) / (1.35 - SLACK_HIGH_LIMIT), 0.0, 1.0);\n    thr -= SLACK_HIGH_COEFF * high_term;\n    thr -= SLACK_ABS_COEFF * slack_norm;\n\n    if (k_any > 0) {\n        double exp_any = 1.0 + 2.0 / double(k_any + 1);\n        exp_any = clamp(exp_any, 1.0, 3.0);\n        thr -= EXPECT_ANY_PULL * (thr - exp_any);\n    }\n    if (k_direct > 0) {\n        double exp_direct = 1.0 + 2.0 / double(k_direct + 1);\n        exp_direct = clamp(exp_direct, 1.0, 3.0);\n        thr -= EXPECT_DIRECT_PULL * (thr - exp_direct);\n    }\n\n    return clamp(thr, MIN_THRESHOLD, MAX_THRESHOLD);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<pair<int,int>> pos(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> pos[i].first >> pos[i].second;\n    }\n\n    vector<Edge> edges(M);\n    vector<vector<int>> adj(N, vector<int>(N, 0));\n    vector<int> out_deg(N, 0);\n    vector<vector<int>> comp_edges(N);\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        edges[i].d = rounded_distance(pos[u], pos[v]);\n        adj[u][v] += 1;\n        adj[v][u] += 1;\n        out_deg[u] += 1;\n        out_deg[v] += 1;\n        comp_edges[u].push_back(i);\n        comp_edges[v].push_back(i);\n    }\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n    DSU mst_dsu(N);\n    int need = N - 1;\n    for (int idx : order) {\n        int loser;\n        mst_dsu.merge_roots(edges[idx].u, edges[idx].v, loser);\n        if (loser != -1) {\n            edges[idx].in_ref = true;\n            if (--need == 0) break;\n        }\n    }\n\n    DSU dsu(N);\n    vector<char> processed(M, false);\n    std::mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n    std::uniform_real_distribution<double> noise_dist(-0.012, 0.012);\n\n    for (int i = 0; i < M; ++i) {\n        int len;\n        if (!(cin >> len)) return 0;\n        Edge &edge = edges[i];\n        int ru = dsu.find(edge.u);\n        int rv = dsu.find(edge.v);\n        processed[i] = true;\n\n        if (ru == rv) {\n            cout << 0 << '\\n' << flush;\n            continue;\n        }\n\n        remove_future_edge(ru, rv, adj, out_deg);\n        int direct_after = adj[ru][rv];\n\n        bool accept = false;\n        if (out_deg[ru] == 0 || out_deg[rv] == 0) {\n            accept = true;\n        }\n\n        int future_edges = M - i - 1;\n        int need_edges = dsu.comp - 1;\n        int slack_edges = max(future_edges - need_edges, 0);\n        double slack_ratio = double(slack_edges + 1) / double(need_edges + 1);\n        double slack_norm = double(slack_edges) / double(M);\n\n        CompStats statsA{}, statsB{};\n        int best_cross = 1e9;\n        int cross_light = 0;\n\n        if (!accept) {\n            statsA = get_comp_stats(ru, dsu, edges, processed, comp_edges,\n                                    rv, &best_cross, &cross_light);\n            statsB = get_comp_stats(rv, dsu, edges, processed, comp_edges);\n\n            int sizeA = dsu.root_size(ru);\n            int sizeB = dsu.root_size(rv);\n            int outA = out_deg[ru];\n            int outB = out_deg[rv];\n            double progress = double(i) / double(M);\n            double comp_frac = double(N - dsu.comp) / double(N - 1);\n\n            int k_any = min(statsA.total, statsB.total);\n            int k_direct = direct_after;\n\n            double threshold = compute_threshold(progress, comp_frac, edge, double(len),\n                                                 sizeA, sizeB, outA, outB,\n                                                 statsA, statsB,\n                                                 best_cross, cross_light,\n                                                 direct_after,\n                                                 slack_ratio, slack_norm,\n                                                 k_any, k_direct);\n            threshold += noise_dist(rng);\n            threshold = std::clamp(threshold, 0.90, 2.70);\n\n            double ratio = double(len) / double(max(edge.d, 1));\n            if (ratio <= threshold) accept = true;\n\n            if (!accept && future_edges <= need_edges) accept = true;\n        }\n\n        if (accept) {\n            cout << 1 << '\\n' << flush;\n            int loser;\n            int keep = dsu.merge_roots(ru, rv, loser);\n            merge_adj(keep, loser, adj, out_deg);\n            merge_edge_lists(keep, loser, comp_edges);\n        } else {\n            cout << 0 << '\\n' << flush;\n        }\n    }\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\n\nstruct BlockCell {\n    int x, y;\n    char action;\n    int rx, ry;   // required human position when blocking\n};\n\nstruct Candidate {\n    Point home;\n    vector<BlockCell> blocks;\n    int final_block_index;\n};\n\nconst int H = 30;\nconst int W = 30;\nconst int DX[4] = {-1, 1, 0, 0};\nconst int DY[4] = {0, 0, -1, 1};\nconst char MOVE_CH[4] = {'U', 'D', 'L', 'R'};\n\nconst int DIST_WEIGHT = 10;\nconst int PET_RADIUS = 6;\nconst int PET_WEIGHT = 50;\nconst int REASSIGN_WAIT = 25;\nconst int REASSIGN_BUFFER = 6;\nconst int MIN_REMAINING_FOR_REASSIGN = 50;\nconst int MAX_REASSIGN = 3;\nconst int PET_ON_ME_WAIT = 12;\nconst int MOVE_STUCK_WAIT = 12;\nconst int CAND_COOLDOWN = 18;\n\ninline bool inside(int x, int y) { return 0 <= x && x < H && 0 <= y && y < W; }\n\nint dir_from_char(char c) {\n    if (c == 'U' || c == 'u') return 0;\n    if (c == 'D' || c == 'd') return 1;\n    if (c == 'L' || c == 'l') return 2;\n    if (c == 'R' || c == 'r') return 3;\n    return -1;\n}\n\nint bfs_next_dir(const vector<vector<int>>& impassable, const Point& start, const Point& goal) {\n    if (start.x == goal.x && start.y == goal.y) return -1;\n    array<array<int, W>, H> dist;\n    for (int i = 0; i < H; ++i) dist[i].fill(-1);\n    queue<Point> q;\n    dist[start.x][start.y] = 0;\n    q.push(start);\n    while (!q.empty()) {\n        Point cur = q.front(); q.pop();\n        for (int d = 0; d < 4; ++d) {\n            int nx = cur.x + DX[d], ny = cur.y + DY[d];\n            if (!inside(nx, ny) || impassable[nx][ny] || dist[nx][ny] != -1) continue;\n            dist[nx][ny] = dist[cur.x][cur.y] + 1;\n            q.push({nx, ny});\n        }\n    }\n    if (dist[goal.x][goal.y] == -1) return -1;\n    Point cur = goal;\n    while (true) {\n        for (int d = 0; d < 4; ++d) {\n            int px = cur.x - DX[d], py = cur.y - DY[d];\n            if (!inside(px, py)) continue;\n            if (dist[px][py] == dist[cur.x][cur.y] - 1) {\n                if (px == start.x && py == start.y) return d;\n                cur = {px, py};\n                break;\n            }\n        }\n    }\n}\n\nvector<int> hungarian(const vector<vector<int>>& a) {\n    int n = (int)a.size();\n    int m = (int)a[0].size();\n    const int INF = 1e9;\n    vector<int> u(n + 1), v(m + 1), p(m + 1), way(m + 1);\n    for (int i = 1; i <= n; ++i) {\n        p[0] = i;\n        vector<int> minv(m + 1, INF);\n        vector<char> used(m + 1, false);\n        int j0 = 0;\n        do {\n            used[j0] = true;\n            int i0 = p[j0], delta = INF, j1 = 0;\n            for (int j = 1; j <= m; ++j) if (!used[j]) {\n                int cur = a[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= m; ++j) {\n                if (used[j]) u[p[j]] += delta, v[j] -= delta;\n                else minv[j] -= delta;\n            }\n            j0 = j1;\n        } while (p[j0]);\n        do {\n            int j1 = way[j0];\n            p[j0] = p[j1];\n            j0 = j1;\n        } while (j0);\n    }\n    vector<int> ans(n, -1);\n    for (int j = 1; j <= m; ++j) if (p[j]) ans[p[j] - 1] = j - 1;\n    return ans;\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<Point> pets(N);\n    vector<int> pet_type(N);\n    for (int i = 0; i < N; ++i) {\n        int px, py, pt;\n        cin >> px >> py >> pt;\n        pets[i] = {px - 1, py - 1};\n        pet_type[i] = pt;\n    }\n    int M;\n    cin >> M;\n    vector<Point> humans(M);\n    for (int i = 0; i < M; ++i) {\n        int hx, hy;\n        cin >> hx >> hy;\n        humans[i] = {hx - 1, hy - 1};\n    }\n\n    vector<vector<int>> blocked(H, vector<int>(W, 0));\n    vector<vector<int>> pet_count(H, vector<int>(W, 0));\n    for (auto &p : pets) if (inside(p.x, p.y)) pet_count[p.x][p.y]++;\n\n    vector<int> edge = {2, 6, 10, 14, 18, 22, 26};\n    vector<Candidate> candidates;\n\n    auto add_block = [](vector<BlockCell>& vec, int x, int y, char act, int rx, int ry) {\n        vec.push_back({x, y, act, rx, ry});\n    };\n\n    auto add_top = [&](int y) {\n        Candidate c;\n        c.home = {0, y};\n        vector<BlockCell> b;\n        add_block(b, 2, y, 'd', 1, y);\n        add_block(b, 1, y + 1, 'd', 0, y + 1);\n        add_block(b, 0, y + 1, 'r', 0, y);\n        add_block(b, 1, y - 1, 'd', 0, y - 1);\n        add_block(b, 0, y - 1, 'l', 0, y);\n        add_block(b, 1, y, 'd', 0, y);\n        c.blocks = b;\n        c.final_block_index = (int)b.size() - 1;\n        candidates.push_back(c);\n    };\n    auto add_bottom = [&](int y) {\n        Candidate c;\n        c.home = {H - 1, y};\n        vector<BlockCell> b;\n        add_block(b, H - 3, y, 'u', H - 2, y);\n        add_block(b, H - 2, y + 1, 'u', H - 1, y + 1);\n        add_block(b, H - 1, y + 1, 'r', H - 1, y);\n        add_block(b, H - 2, y - 1, 'u', H - 1, y - 1);\n        add_block(b, H - 1, y - 1, 'l', H - 1, y);\n        add_block(b, H - 2, y, 'u', H - 1, y);\n        c.blocks = b;\n        c.final_block_index = (int)b.size() - 1;\n        candidates.push_back(c);\n    };\n    auto add_left = [&](int x) {\n        Candidate c;\n        c.home = {x, 0};\n        vector<BlockCell> b;\n        add_block(b, x, 2, 'r', x, 1);\n        add_block(b, x + 1, 1, 'r', x + 1, 0);\n        add_block(b, x + 1, 0, 'd', x, 0);\n        add_block(b, x - 1, 1, 'r', x - 1, 0);\n        add_block(b, x - 1, 0, 'u', x, 0);\n        add_block(b, x, 1, 'r', x, 0);\n        c.blocks = b;\n        c.final_block_index = (int)b.size() - 1;\n        candidates.push_back(c);\n    };\n    auto add_right = [&](int x) {\n        Candidate c;\n        c.home = {x, W - 1};\n        vector<BlockCell> b;\n        add_block(b, x, W - 3, 'l', x, W - 2);\n        add_block(b, x + 1, W - 2, 'l', x + 1, W - 1);\n        add_block(b, x + 1, W - 1, 'd', x, W - 1);\n        add_block(b, x - 1, W - 2, 'l', x - 1, W - 1);\n        add_block(b, x - 1, W - 1, 'u', x, W - 1);\n        add_block(b, x, W - 2, 'l', x, W - 1);\n        c.blocks = b;\n        c.final_block_index = (int)b.size() - 1;\n        candidates.push_back(c);\n    };\n    for (int y : edge) add_top(y);\n    for (int y : edge) add_bottom(y);\n    for (int x : edge) add_left(x);\n    for (int x : edge) add_right(x);\n\n    int C = (int)candidates.size();\n    vector<int> candidate_penalty(C, 0);\n    array<int, 6> type_weight = {0, 1, 1, 1, 3, 2};\n\n    auto update_penalty = [&]() {\n        fill(candidate_penalty.begin(), candidate_penalty.end(), 0);\n        for (int j = 0; j < C; ++j) {\n            int pen = 0;\n            for (int i = 0; i < N; ++i) {\n                int dist = abs(pets[i].x - candidates[j].home.x) + abs(pets[i].y - candidates[j].home.y);\n                if (dist < PET_RADIUS)\n                    pen += (PET_RADIUS - dist) * PET_WEIGHT * type_weight[pet_type[i]];\n            }\n            candidate_penalty[j] = pen;\n        }\n    };\n    update_penalty();\n\n    vector<vector<int>> cost(M, vector<int>(C));\n    for (int i = 0; i < M; ++i)\n        for (int j = 0; j < C; ++j) {\n            int dist = abs(humans[i].x - candidates[j].home.x) + abs(humans[i].y - candidates[j].home.y);\n            cost[i][j] = dist * DIST_WEIGHT + candidate_penalty[j];\n        }\n    vector<int> assign = hungarian(cost);\n\n    vector<int> candidate_owner(C, -1);\n    vector<int> candidate_block_until(C, -1000);\n\n    vector<int> human_target_idx(M, -1);\n    vector<Point> targets(M);\n    vector<vector<BlockCell>> human_block_cells(M);\n    vector<vector<int>> human_block_done(M);\n    vector<int> final_block_index(M, -1);\n    vector<int> stage(M, 0);\n    vector<int> idle_block_turns(M, 0);\n    vector<int> stuck_move_turns(M, 0);\n    vector<int> pet_on_me_turns(M, 0);\n    vector<int> block_reason(M, 0);\n    vector<int> reassign_count(M, 0);\n\n    auto is_complete = [&](int idx) -> bool {\n        for (int v : human_block_done[idx]) if (!v) return false;\n        return true;\n    };\n\n    auto set_candidate = [&](int idx, int cand) {\n        human_target_idx[idx] = cand;\n        targets[idx] = candidates[cand].home;\n        human_block_cells[idx] = candidates[cand].blocks;\n        human_block_done[idx].assign(human_block_cells[idx].size(), 0);\n        for (int k = 0; k < (int)human_block_cells[idx].size(); ++k) {\n            const auto &bc = human_block_cells[idx][k];\n            if (blocked[bc.x][bc.y]) human_block_done[idx][k] = 1;\n        }\n        final_block_index[idx] = candidates[cand].final_block_index;\n        idle_block_turns[idx] = 0;\n        stuck_move_turns[idx] = 0;\n        pet_on_me_turns[idx] = 0;\n        block_reason[idx] = 0;\n        if (humans[idx].x == targets[idx].x && humans[idx].y == targets[idx].y) {\n            stage[idx] = is_complete(idx) ? 2 : 1;\n        } else {\n            stage[idx] = 0;\n        }\n    };\n\n    for (int i = 0; i < M; ++i) {\n        candidate_owner[assign[i]] = i;\n        set_candidate(i, assign[i]);\n    }\n\n    auto try_reassign = [&](int idx, int remaining, int turn) -> bool {\n        if (reassign_count[idx] >= MAX_REASSIGN) return false;\n        int old = human_target_idx[idx];\n        if (old < 0) return false;\n        candidate_owner[old] = -1;\n        candidate_block_until[old] = turn + CAND_COOLDOWN;\n        const int INF = 1e9;\n        int best = -1, best_cost = INF;\n        for (int j = 0; j < C; ++j) {\n            if (candidate_owner[j] != -1) continue;\n            if (candidate_block_until[j] > turn) continue;\n            if (blocked[candidates[j].home.x][candidates[j].home.y]) continue;\n            int dist = abs(humans[idx].x - candidates[j].home.x) + abs(humans[idx].y - candidates[j].home.y);\n            if (dist + REASSIGN_BUFFER > remaining) continue;\n            int cur = dist * DIST_WEIGHT + candidate_penalty[j];\n            if (cur < best_cost) best_cost = cur, best = j;\n        }\n        if (best == -1) {\n            candidate_owner[old] = idx;\n            return false;\n        }\n        candidate_owner[best] = idx;\n        set_candidate(idx, best);\n        reassign_count[idx]++;\n        return true;\n    };\n\n    for (int turn = 0; turn < 300; ++turn) {\n        for (int i = 0; i < M; ++i) {\n            for (int k = 0; k < (int)human_block_cells[i].size(); ++k) {\n                if (!human_block_done[i][k]) {\n                    const auto &bc = human_block_cells[i][k];\n                    if (blocked[bc.x][bc.y]) human_block_done[i][k] = 1;\n                }\n            }\n            if (stage[i] == 1 && is_complete(i)) stage[i] = 2;\n        }\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 0 && humans[i].x == targets[i].x && humans[i].y == targets[i].y) {\n                stage[i] = is_complete(i) ? 2 : 1;\n            }\n        }\n\n        vector<vector<int>> humans_here(H, vector<int>(W, 0));\n        for (auto &h : humans) humans_here[h.x][h.y]++;\n\n        Point invalid{-1, -1};\n        vector<Point> move_target(M, invalid);\n        vector<int> block_exec(M, -1);\n        vector<int> block_reason_tmp(M, 0);\n        vector<int> current_block_idx(M, -1);\n        string actions(M, '.');\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 0) {\n                move_target[i] = targets[i];\n                continue;\n            }\n            if (stage[i] != 1) {\n                block_reason_tmp[i] = 0;\n                continue;\n            }\n            while (true) {\n                int blk = -1;\n                for (int k = 0; k < (int)human_block_cells[i].size(); ++k)\n                    if (!human_block_done[i][k]) { blk = k; break; }\n                if (blk == -1) { stage[i] = 2; block_reason_tmp[i] = 0; break; }\n                current_block_idx[i] = blk;\n                const auto &bc = human_block_cells[i][blk];\n                if (blocked[bc.x][bc.y]) {\n                    human_block_done[i][blk] = 1;\n                    continue;\n                }\n                if (humans[i].x != bc.rx || humans[i].y != bc.ry) {\n                    move_target[i] = {bc.rx, bc.ry};\n                    block_reason_tmp[i] = 0;\n                } else {\n                    if (pet_count[bc.x][bc.y] > 0) {\n                        block_reason_tmp[i] = 1;\n                    } else {\n                        bool adj_pet = false;\n                        for (int d = 0; d < 4; ++d) {\n                            int ax = bc.x + DX[d], ay = bc.y + DY[d];\n                            if (inside(ax, ay) && pet_count[ax][ay] > 0) { adj_pet = true; break; }\n                        }\n                        if (adj_pet) {\n                            block_reason_tmp[i] = 2;\n                        } else if (humans_here[bc.x][bc.y] > 0) {\n                            block_reason_tmp[i] = 3;\n                        } else {\n                            actions[i] = bc.action;\n                            block_exec[i] = blk;\n                            block_reason_tmp[i] = 0;\n                        }\n                    }\n                }\n                break;\n            }\n        }\n\n        vector<vector<int>> temp_blocked = blocked;\n        for (int i = 0; i < M; ++i) {\n            if (block_exec[i] != -1) {\n                const auto &bc = human_block_cells[i][block_exec[i]];\n                temp_blocked[bc.x][bc.y] = 1;\n            }\n        }\n\n        vector<int> move_dir(M, -2);\n        for (int i = 0; i < M; ++i) {\n            if (actions[i] != '.') continue;\n            if (move_target[i].x == -1) continue;\n            if (humans[i].x == move_target[i].x && humans[i].y == move_target[i].y) continue;\n            int dir = bfs_next_dir(temp_blocked, humans[i], move_target[i]);\n            move_dir[i] = dir;\n            if (dir != -1) actions[i] = MOVE_CH[dir];\n        }\n\n        cout << actions << endl;\n\n        vector<Point> start_pos = humans;\n        for (int i = 0; i < M; ++i) {\n            char act = actions[i];\n            int dir = dir_from_char(act);\n            if (act == '.' || dir == -1) continue;\n            if ('A' <= act && act <= 'Z') {\n                humans[i].x += DX[dir];\n                humans[i].y += DY[dir];\n            } else {\n                const auto &bc = human_block_cells[i][block_exec[i]];\n                blocked[bc.x][bc.y] = 1;\n                human_block_done[i][block_exec[i]] = 1;\n            }\n        }\n\n        for (int i = 0; i < M; ++i) {\n            if (stage[i] == 1) {\n                if (block_exec[i] != -1) {\n                    idle_block_turns[i] = 0;\n                } else if (move_target[i].x != -1 &&\n                           !(humans[i].x == move_target[i].x && humans[i].y == move_target[i].y)) {\n                    idle_block_turns[i] = 0;\n                } else if (block_reason_tmp[i] == 1 || block_reason_tmp[i] == 2) {\n                    idle_block_turns[i]++;\n                } else {\n                    idle_block_turns[i] = 0;\n                }\n            } else {\n                idle_block_turns[i] = 0;\n            }\n            if (move_target[i].x != -1 &&\n                !(humans[i].x == move_target[i].x && humans[i].y == move_target[i].y) &&\n                move_dir[i] == -1) {\n                stuck_move_turns[i]++;\n            } else if (move_target[i].x != -1 &&\n                       !(humans[i].x == move_target[i].x && humans[i].y == move_target[i].y) &&\n                       move_dir[i] != -2) {\n                stuck_move_turns[i] = 0;\n            } else if (move_target[i].x == -1) {\n                stuck_move_turns[i] = 0;\n            }\n            block_reason[i] = block_reason_tmp[i];\n        }\n\n        vector<string> pet_moves(N);\n        for (int i = 0; i < N; ++i) cin >> pet_moves[i];\n        for (int i = 0; i < N; ++i) {\n            for (char c : pet_moves[i]) {\n                int dir = dir_from_char(c);\n                if (dir == -1) continue;\n                pets[i].x += DX[dir];\n                pets[i].y += DY[dir];\n            }\n        }\n        for (int x = 0; x < H; ++x) fill(pet_count[x].begin(), pet_count[x].end(), 0);\n        for (auto &p : pets)\n            if (inside(p.x, p.y)) pet_count[p.x][p.y]++;\n        update_penalty();\n\n        for (int i = 0; i < M; ++i) {\n            if (pet_count[humans[i].x][humans[i].y] > 0) pet_on_me_turns[i]++;\n            else pet_on_me_turns[i] = 0;\n        }\n\n        int remaining = 300 - (turn + 1);\n        if (remaining >= MIN_REMAINING_FOR_REASSIGN) {\n            for (int i = 0; i < M; ++i) {\n                if (stage[i] == 2) continue;\n                bool need = false;\n                if (stage[i] == 1 && !is_complete(i)) {\n                    if ((block_reason[i] == 1 || block_reason[i] == 2) && idle_block_turns[i] >= REASSIGN_WAIT)\n                        need = true;\n                    if (pet_on_me_turns[i] >= PET_ON_ME_WAIT) need = true;\n                }\n                if (!need && stuck_move_turns[i] >= MOVE_STUCK_WAIT) need = true;\n                if (need) try_reassign(i, remaining, turn);\n            }\n        }\n    }\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int H = 20;\nconstexpr int W = 20;\nconstexpr int N = H * W;\nconstexpr int MAX_L = 200;\nconstexpr int MAX_SEG_LEN = 80;\nconst char DIR_CHARS[4] = {'U', 'D', 'L', 'R'};\nconstexpr double TIME_LIMIT = 1.95;\nconstexpr double IMPROVE_EPS = 1e-9;\n\nstruct StepResult {\n    double score;\n    double reachProb;\n};\n\ninline StepResult apply_transition_raw(const double* from, double* to, int dir, int step,\n                                       double forgetProb, double moveProb,\n                                       const array<array<int, N>, 4>& neighbor,\n                                       int targetIdx) {\n    StepResult res{0.0, 0.0};\n    fill(to, to + N, 0.0);\n    const double rewardFactor = 401.0 - (step + 1);\n    for (int idx = 0; idx < N; ++idx) {\n        double prob = from[idx];\n        if (prob <= 1e-15) continue;\n        double stayProb = prob * forgetProb;\n        int nxt = neighbor[dir][idx];\n        double move = prob * moveProb;\n        if (nxt == idx) {\n            stayProb += move;\n        } else if (nxt == targetIdx) {\n            res.score += rewardFactor * move;\n            res.reachProb += move;\n        } else {\n            to[nxt] += move;\n        }\n        to[idx] += stayProb;\n    }\n    return res;\n}\n\ninline double dot_product_raw(const double* a, const double* b) {\n    double sum = 0.0;\n    for (int i = 0; i < N; ++i) sum += a[i] * b[i];\n    return sum;\n}\n\ninline double expected_distance_raw(const double* dist, const double* distTarget) {\n    double sum = 0.0;\n    for (int idx = 0; idx < N; ++idx) sum += dist[idx] * distTarget[idx];\n    return sum;\n}\n\nvector<int> compute_distances(const array<array<int, N>, 4>& neighbor, int targetIdx) {\n    const int INF = 1e9;\n    vector<int> dist(N, INF);\n    queue<int> q;\n    dist[targetIdx] = 0;\n    q.push(targetIdx);\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        for (int dir = 0; dir < 4; ++dir) {\n            int v = neighbor[dir][u];\n            if (v == u) continue;\n            if (dist[v] > dist[u] + 1) {\n                dist[v] = dist[u] + 1;\n                q.push(v);\n            }\n        }\n    }\n    return dist;\n}\n\nvector<int> compute_bfs_path(const array<array<int, N>, 4>& neighbor,\n                             int startIdx, int targetIdx) {\n    vector<int> parent(N, -1);\n    vector<int> parentDir(N, -1);\n    queue<int> q;\n    q.push(startIdx);\n    parent[startIdx] = startIdx;\n    while (!q.empty()) {\n        int u = q.front(); q.pop();\n        if (u == targetIdx) break;\n        for (int dir = 0; dir < 4; ++dir) {\n            int v = neighbor[dir][u];\n            if (v == u) continue;\n            if (parent[v] != -1) continue;\n            parent[v] = u;\n            parentDir[v] = dir;\n            q.push(v);\n        }\n    }\n    vector<int> path;\n    if (parent[targetIdx] != -1) {\n        int cur = targetIdx;\n        vector<int> rev;\n        while (cur != startIdx) {\n            rev.push_back(parentDir[cur]);\n            cur = parent[cur];\n        }\n        path.assign(rev.rbegin(), rev.rend());\n    }\n    return path;\n}\n\nvector<int> build_sequence_from_path(const vector<int>& path, int repeatEach, bool loopMode) {\n    vector<int> seq(MAX_L);\n    int pos = 0;\n    auto append_once = [&]() {\n        for (int dir : path) {\n            for (int r = 0; r < repeatEach; ++r) {\n                if (pos >= MAX_L) return;\n                seq[pos++] = dir;\n            }\n        }\n    };\n    if (!path.empty() && loopMode) {\n        while (pos < MAX_L) append_once();\n    } else {\n        append_once();\n    }\n    while (pos < MAX_L) seq[pos++] = (pos % 4 == 3) ? 3 : 1;\n    return seq;\n}\n\nvector<int> build_default_sequence() {\n    vector<int> seq(MAX_L);\n    for (int i = 0; i < MAX_L; ++i) seq[i] = (i % 4 == 3) ? 3 : 1;\n    return seq;\n}\n\nstruct BeamParam {\n    double weight;\n    double noise;\n    int width;\n};\n\nstruct BeamResult {\n    vector<int> seq;\n    double score;\n};\n\nBeamResult run_beam(const BeamParam& param,\n                    const array<array<int, N>, 4>& neighbor,\n                    const vector<double>& distTarget,\n                    int startIdx, int targetIdx,\n                    double forgetProb,\n                    mt19937& rng) {\n    const double moveProb = 1.0 - forgetProb;\n    struct Candidate {\n        array<double, N> dist;\n        double score;\n        double heuristic;\n        array<uint8_t, MAX_L> path;\n        int len;\n    };\n    vector<Candidate> beam, next;\n    beam.reserve(param.width);\n    next.reserve(param.width * 4);\n\n    Candidate init;\n    init.dist.fill(0.0);\n    init.dist[startIdx] = 1.0;\n    init.score = 0.0;\n    init.len = 0;\n    init.path.fill(0);\n    init.heuristic = 0.0;\n    beam.push_back(init);\n\n    uniform_real_distribution<double> noiseDist(-param.noise, param.noise);\n    auto cmp = [](const Candidate& a, const Candidate& b) {\n        return a.heuristic > b.heuristic;\n    };\n\n    for (int step = 0; step < MAX_L; ++step) {\n        next.clear();\n        for (const Candidate& cand : beam) {\n            for (int dir = 0; dir < 4; ++dir) {\n                Candidate child;\n                child.path = cand.path;\n                child.path[cand.len] = static_cast<uint8_t>(dir);\n                child.len = cand.len + 1;\n                StepResult sr = apply_transition_raw(cand.dist.data(), child.dist.data(),\n                                                     dir, step, forgetProb, moveProb,\n                                                     neighbor, targetIdx);\n                child.score = cand.score + sr.score;\n                double expDist = expected_distance_raw(child.dist.data(), distTarget.data());\n                double noise = (param.noise > 0) ? noiseDist(rng) : 0.0;\n                child.heuristic = child.score - param.weight * expDist + noise;\n                next.push_back(std::move(child));\n            }\n        }\n        if (next.empty()) break;\n        int width = min(param.width, static_cast<int>(next.size()));\n        partial_sort(next.begin(), next.begin() + width, next.end(), cmp);\n        next.resize(width);\n        beam.swap(next);\n    }\n\n    Candidate best = beam[0];\n    for (const Candidate& cand : beam) if (cand.score > best.score) best = cand;\n    vector<int> seq(MAX_L);\n    for (int i = 0; i < MAX_L; ++i) seq[i] = best.path[i];\n    return {seq, best.score};\n}\n\nstruct Evaluator {\n    const array<array<int, N>, 4>& neighbor;\n    int startIdx;\n    int targetIdx;\n    double forgetProb;\n    double moveProb;\n    vector<double> cur, nxt;\n    Evaluator(const array<array<int, N>, 4>& neighbor_, int s, int t, double p)\n        : neighbor(neighbor_), startIdx(s), targetIdx(t), forgetProb(p), moveProb(1.0 - p),\n          cur(N, 0.0), nxt(N, 0.0) {}\n\n    double evaluate(const vector<int>& seq) {\n        fill(cur.begin(), cur.end(), 0.0);\n        cur[startIdx] = 1.0;\n        double total = 0.0;\n        for (int step = 0; step < (int)seq.size(); ++step) {\n            StepResult sr = apply_transition_raw(cur.data(), nxt.data(), seq[step], step,\n                                                 forgetProb, moveProb, neighbor, targetIdx);\n            total += sr.score;\n            cur.swap(nxt);\n            bool empty = true;\n            for (double v : cur) if (v > 1e-15) { empty = false; break; }\n            if (empty) break;\n        }\n        return total;\n    }\n};\n\nvoid recompute_forward_from(int startStep,\n                            const vector<int>& seq,\n                            vector<array<double, N>>& forward,\n                            vector<double>& prefixScore,\n                            vector<double>& aliveProb,\n                            double forgetProb, double moveProb,\n                            const array<array<int, N>, 4>& neighbor,\n                            int targetIdx, int startIdx) {\n    if (startStep <= 0) {\n        startStep = 0;\n        forward[0].fill(0.0);\n        forward[0][startIdx] = 1.0;\n        prefixScore[0] = 0.0;\n        aliveProb[0] = 1.0;\n    }\n    for (int step = startStep; step < MAX_L; ++step) {\n        StepResult sr = apply_transition_raw(forward[step].data(), forward[step + 1].data(),\n                                             seq[step], step, forgetProb, moveProb,\n                                             neighbor, targetIdx);\n        prefixScore[step + 1] = prefixScore[step] + sr.score;\n        double alive = aliveProb[step] - sr.reachProb;\n        if (alive < 0.0) alive = 0.0;\n        aliveProb[step + 1] = alive;\n    }\n}\n\nvoid recompute_backward_up_to(int uptoStep,\n                              const vector<int>& seq,\n                              vector<array<double, N>>& value,\n                              double forgetProb, double moveProb,\n                              const array<array<int, N>, 4>& neighbor,\n                              int targetIdx) {\n    if (uptoStep >= MAX_L - 1) uptoStep = MAX_L - 1;\n    for (int step = uptoStep; step >= 0; --step) {\n        auto& cur = value[step];\n        auto& nxt = value[step + 1];\n        int dir = seq[step];\n        double rewardFactor = 401.0 - (step + 1);\n        for (int idx = 0; idx < N; ++idx) {\n            double val = forgetProb * nxt[idx];\n            int nextIdx = neighbor[dir][idx];\n            if (nextIdx == idx) {\n                val += moveProb * nxt[idx];\n            } else if (nextIdx == targetIdx) {\n                val += moveProb * rewardFactor;\n            } else {\n                val += moveProb * nxt[nextIdx];\n            }\n            cur[idx] = val;\n        }\n        cur[targetIdx] = 0.0;\n    }\n}\n\nstruct SegmentParam {\n    double weight;\n    double noise;\n    int width;\n    double futureCoeff;\n};\n\nstruct SegmentResult {\n    bool success;\n    vector<int> path;\n    double totalContribution;\n};\n\nSegmentResult run_segment_beam(const array<double, N>& distPre,\n                               const array<double, N>& suffixValue,\n                               int len, int stepOffset,\n                               const array<array<int, N>, 4>& neighbor,\n                               double forgetProb, double moveProb,\n                               const vector<double>& distTarget,\n                               const SegmentParam& param,\n                               mt19937& rng,\n                               int targetIdx) {\n    SegmentResult result{false, {}, -1e300};\n    if (len <= 0 || len > MAX_SEG_LEN) return result;\n    struct Node {\n        array<double, N> dist;\n        double score;\n        double heuristic;\n        array<uint8_t, MAX_SEG_LEN> path;\n        int len;\n    };\n    vector<Node> beam;\n    vector<Node> next;\n    beam.reserve(param.width);\n    next.reserve(param.width * 4);\n\n    Node init;\n    init.dist = distPre;\n    init.score = 0.0;\n    init.len = 0;\n    init.heuristic = dot_product_raw(distPre.data(), suffixValue.data());\n    init.path.fill(0);\n    beam.push_back(init);\n\n    uniform_real_distribution<double> noiseDist(-param.noise, param.noise);\n    auto cmp = [](const Node& a, const Node& b) {\n        return a.heuristic > b.heuristic;\n    };\n\n    for (int step = 0; step < len; ++step) {\n        next.clear();\n        for (const Node& cand : beam) {\n            for (int dir = 0; dir < 4; ++dir) {\n                Node child;\n                child.path = cand.path;\n                child.path[cand.len] = static_cast<uint8_t>(dir);\n                child.len = cand.len + 1;\n                StepResult sr = apply_transition_raw(cand.dist.data(), child.dist.data(),\n                                                     dir, stepOffset + step,\n                                                     forgetProb, moveProb,\n                                                     neighbor, targetIdx);\n                child.score = cand.score + sr.score;\n                double expDist = expected_distance_raw(child.dist.data(), distTarget.data());\n                double futureEst = dot_product_raw(child.dist.data(), suffixValue.data());\n                double noise = (param.noise > 0) ? noiseDist(rng) : 0.0;\n                child.heuristic = child.score + param.futureCoeff * futureEst\n                                - param.weight * expDist + noise;\n                next.push_back(std::move(child));\n            }\n        }\n        if (next.empty()) return result;\n        int width = min(param.width, static_cast<int>(next.size()));\n        partial_sort(next.begin(), next.begin() + width, next.end(), cmp);\n        next.resize(width);\n        beam.swap(next);\n    }\n\n    double bestTotal = -1e300;\n    int bestIdx = 0;\n    for (int i = 0; i < (int)beam.size(); ++i) {\n        double total = beam[i].score + dot_product_raw(beam[i].dist.data(), suffixValue.data());\n        if (total > bestTotal) {\n            bestTotal = total;\n            bestIdx = i;\n        }\n    }\n    result.success = true;\n    result.totalContribution = bestTotal;\n    result.path.resize(len);\n    for (int i = 0; i < len; ++i) result.path[i] = beam[bestIdx].path[i];\n    return result;\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    cin >> si >> sj >> ti >> tj >> p;\n    vector<string> h(H), v(H - 1);\n    for (int i = 0; i < H; ++i) cin >> h[i];\n    for (int i = 0; i < H - 1; ++i) cin >> v[i];\n\n    array<array<int, N>, 4> neighbor;\n    auto idx = [&](int r, int c) { return r * W + c; };\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int id = idx(i, j);\n            neighbor[0][id] = (i > 0 && v[i - 1][j] == '0') ? idx(i - 1, j) : id;\n            neighbor[1][id] = (i < H - 1 && v[i][j] == '0') ? idx(i + 1, j) : id;\n            neighbor[2][id] = (j > 0 && h[i][j - 1] == '0') ? idx(i, j - 1) : id;\n            neighbor[3][id] = (j < W - 1 && h[i][j] == '0') ? idx(i, j + 1) : id;\n        }\n    }\n\n    int startIdx = idx(si, sj);\n    int targetIdx = idx(ti, tj);\n\n    vector<int> distInt = compute_distances(neighbor, targetIdx);\n    vector<double> distTarget(N);\n    for (int i = 0; i < N; ++i) distTarget[i] = (distInt[i] >= 1e8) ? 100.0 : (double)distInt[i];\n\n    auto bfsPath = compute_bfs_path(neighbor, startIdx, targetIdx);\n\n    mt19937 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n\n    vector<vector<int>> candidates;\n    candidates.push_back(build_sequence_from_path(bfsPath, 1, false));\n    candidates.push_back(build_sequence_from_path(bfsPath, 2, false));\n    candidates.push_back(build_sequence_from_path(bfsPath, 3, false));\n    candidates.push_back(build_sequence_from_path(bfsPath, 1, true));\n    candidates.push_back(build_sequence_from_path(bfsPath, 2, true));\n    candidates.push_back(build_default_sequence());\n\n    vector<BeamParam> beamParams;\n    double factor = 0.6 + 0.8 * p;\n    beamParams.push_back({0.8 * factor, 3e-4, 10});\n    beamParams.push_back({1.1 * factor, 2e-4, 12});\n    beamParams.push_back({1.5 * factor, 1e-4, 14});\n    beamParams.push_back({2.1 * factor, 5e-5, 16});\n    beamParams.push_back({2.9 * factor, 2e-5, 18});\n    beamParams.push_back({3.6 * factor, 1e-5, 20});\n    beamParams.push_back({4.4 * factor, 5e-6, 22});\n\n    double beamTimeLimit = min(0.55, TIME_LIMIT * 0.4);\n    size_t paramIdx = 0;\n    while (elapsed() < beamTimeLimit && paramIdx < beamParams.size()) {\n        BeamResult res = run_beam(beamParams[paramIdx], neighbor, distTarget,\n                                  startIdx, targetIdx, p, rng);\n        candidates.push_back(std::move(res.seq));\n        ++paramIdx;\n    }\n\n    Evaluator evaluator(neighbor, startIdx, targetIdx, p);\n    double bestEval = -1.0;\n    vector<int> bestSeq;\n    for (const auto& seq : candidates) {\n        double sc = evaluator.evaluate(seq);\n        if (sc > bestEval + IMPROVE_EPS) {\n            bestEval = sc;\n            bestSeq = seq;\n        }\n    }\n    if (bestSeq.empty()) bestSeq = build_default_sequence();\n\n    vector<array<double, N>> forward(MAX_L + 1), value(MAX_L + 1);\n    for (auto& arr : forward) arr.fill(0.0);\n    for (auto& arr : value) arr.fill(0.0);\n    vector<double> prefixScore(MAX_L + 1, 0.0);\n    vector<double> aliveProb(MAX_L + 1, 0.0);\n\n    forward[0][startIdx] = 1.0;\n    aliveProb[0] = 1.0;\n    recompute_forward_from(0, bestSeq, forward, prefixScore, aliveProb,\n                           p, 1.0 - p, neighbor, targetIdx, startIdx);\n    value[MAX_L].fill(0.0);\n    recompute_backward_up_to(MAX_L - 1, bestSeq, value,\n                             p, 1.0 - p, neighbor, targetIdx);\n    double bestScore = prefixScore[MAX_L];\n\n    array<double, N> tempDist;\n\n    auto buildSegmentParam = [&](int len, int step) -> SegmentParam {\n        SegmentParam param;\n        double lenRatio = (double)len / 32.0;\n        double early = max(0.0, 1.0 - step / 160.0);\n        param.weight = (0.85 + 0.9 * p) * (1.0 + 0.1 * min(2.0, lenRatio)) * (1.0 + 0.15 * early);\n        param.futureCoeff = 0.55 + 0.2 * min(1.5, (double)len / 40.0) + 0.15 * early;\n        param.noise = 7e-5 / (1.0 + 0.25 * lenRatio);\n        int baseWidth;\n        if (len <= 12) baseWidth = 32;\n        else if (len <= 20) baseWidth = 28;\n        else if (len <= 28) baseWidth = 24;\n        else if (len <= 36) baseWidth = 22;\n        else if (len <= 48) baseWidth = 20;\n        else if (len <= 56) baseWidth = 18;\n        else if (len <= 64) baseWidth = 16;\n        else if (len <= 72) baseWidth = 15;\n        else baseWidth = 14;\n        if (step < 50) baseWidth += 4;\n        else if (step < 100) baseWidth += 2;\n        if (step > 140) baseWidth -= 3;\n        else if (step > 110) baseWidth -= 1;\n        baseWidth -= (int)round(p * 2.0);\n        param.width = max(baseWidth, 10);\n        return param;\n    };\n\n    auto try_segment = [&](int start, int len) -> bool {\n        if (len <= 0) return false;\n        if (start < 0) {\n            len += start;\n            start = 0;\n        }\n        if (start >= MAX_L || len < 4) return false;\n        if (start + len > MAX_L) len = MAX_L - start;\n        if (len <= 0 || len > MAX_SEG_LEN) return false;\n        if (aliveProb[start] < 1e-9) return false;\n        SegmentParam param = buildSegmentParam(len, start);\n        SegmentResult segRes = run_segment_beam(forward[start], value[start + len],\n                                                len, start, neighbor, p, 1.0 - p,\n                                                distTarget, param, rng, targetIdx);\n        if (!segRes.success) return false;\n        double candidateScore = prefixScore[start] + segRes.totalContribution;\n        if (candidateScore > bestScore + IMPROVE_EPS) {\n            for (int i = 0; i < len; ++i) bestSeq[start + i] = segRes.path[i];\n            recompute_forward_from(start, bestSeq, forward, prefixScore, aliveProb,\n                                   p, 1.0 - p, neighbor, targetIdx, startIdx);\n            recompute_backward_up_to(start + len - 1, bestSeq, value,\n                                     p, 1.0 - p, neighbor, targetIdx);\n            bestScore = prefixScore[MAX_L];\n            return true;\n        }\n        return false;\n    };\n\n    auto run_coordinate = [&](double limitTime, int maxPass, vector<double>* marginOut) {\n        if (elapsed() >= limitTime) return;\n        if (marginOut) fill(marginOut->begin(), marginOut->end(), 0.0);\n        bool improved = true;\n        int passes = 0;\n        while (improved && elapsed() < limitTime && passes < maxPass) {\n            improved = false;\n            ++passes;\n            for (int step = 0; step < MAX_L && elapsed() < limitTime; ++step) {\n                if (aliveProb[step] < 1e-9) break;\n                auto& distIn = forward[step];\n                auto& suffix = value[step + 1];\n                double currentVal = -1e300;\n                double bestVal = -1e300;\n                int bestDir = bestSeq[step];\n                for (int dir = 0; dir < 4; ++dir) {\n                    StepResult sr = apply_transition_raw(distIn.data(), tempDist.data(),\n                                                         dir, step, p, 1.0 - p,\n                                                         neighbor, targetIdx);\n                    double val = sr.score + dot_product_raw(tempDist.data(), suffix.data());\n                    if (dir == bestSeq[step]) currentVal = val;\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestDir = dir;\n                    }\n                }\n                if (marginOut) (*marginOut)[step] = max(0.0, bestVal - currentVal);\n                if (bestVal > currentVal + IMPROVE_EPS && bestDir != bestSeq[step]) {\n                    bestSeq[step] = bestDir;\n                    recompute_forward_from(step, bestSeq, forward, prefixScore, aliveProb,\n                                           p, 1.0 - p, neighbor, targetIdx, startIdx);\n                    recompute_backward_up_to(step, bestSeq, value,\n                                             p, 1.0 - p, neighbor, targetIdx);\n                    bestScore = prefixScore[MAX_L];\n                    improved = true;\n                }\n            }\n        }\n    };\n\n    auto apply_margin_segments = [&](const vector<double>& margin,\n                                     double timeLimit, int topK) {\n        vector<pair<double, int>> items;\n        items.reserve(MAX_L);\n        for (int step = 0; step < MAX_L; ++step) {\n            if (aliveProb[step] < 1e-9) continue;\n            if (margin[step] <= 1e-8) continue;\n            items.emplace_back(margin[step], step);\n        }\n        sort(items.begin(), items.end(), greater<>());\n        vector<int> lengths = {6, 10, 14, 20, 28, 36};\n        int processed = 0;\n        for (const auto& [m, step] : items) {\n            if (processed >= topK) break;\n            if (elapsed() > timeLimit) break;\n            ++processed;\n            for (int len : lengths) {\n                if (elapsed() > timeLimit) break;\n                int start = step - len / 2;\n                if (try_segment(start, len)) break;\n            }\n        }\n    };\n\n    auto apply_drop_segments = [&](double timeLimit, int topK) {\n        vector<pair<double, int>> drops;\n        drops.reserve(MAX_L);\n        for (int step = 0; step < MAX_L; ++step) {\n            double drop = aliveProb[step] - aliveProb[step + 1];\n            if (drop > 1e-8) drops.emplace_back(drop, step);\n        }\n        sort(drops.begin(), drops.end(), greater<>());\n        vector<int> lengths = {8, 12, 16, 24, 32, 40};\n        int processed = 0;\n        for (const auto& [drop, step] : drops) {\n            if (processed >= topK) break;\n            if (elapsed() > timeLimit) break;\n            ++processed;\n            for (int len : lengths) {\n                if (elapsed() > timeLimit) break;\n                int start = step - len / 2;\n                if (try_segment(start, len)) break;\n            }\n        }\n    };\n\n    vector<double> marginBuf(MAX_L, 0.0);\n    double coordLimit1 = min(1.0, TIME_LIMIT * 0.65);\n    run_coordinate(coordLimit1, 3, &marginBuf);\n\n    double marginLimit = TIME_LIMIT * 0.75;\n    apply_margin_segments(marginBuf, marginLimit, 14);\n\n    run_coordinate(min(TIME_LIMIT * 0.8, coordLimit1 + 0.2), 1, nullptr);\n\n    double dropLimit = TIME_LIMIT * 0.86;\n    apply_drop_segments(dropLimit, 12);\n\n    run_coordinate(min(TIME_LIMIT * 0.9, dropLimit + 0.12), 1, nullptr);\n\n    vector<pair<int, int>> prioritySegments;\n    auto addSeg = [&](int s, int len) {\n        if (len <= 0) return;\n        if (s < 0) {\n            len += s;\n            s = 0;\n        }\n        if (s >= MAX_L) return;\n        if (s + len > MAX_L) len = MAX_L - s;\n        if (len >= 4) prioritySegments.emplace_back(s, len);\n    };\n    addSeg(0, 64);\n    addSeg(0, 48);\n    addSeg(16, 48);\n    addSeg(32, 48);\n    addSeg(48, 48);\n    addSeg(MAX_L - 96, 48);\n    addSeg(MAX_L - 64, 64);\n    addSeg(MAX_L - 48, 48);\n\n    double priorityLimit = TIME_LIMIT * 0.92;\n    for (auto [st, len] : prioritySegments) {\n        if (elapsed() > priorityLimit) break;\n        try_segment(st, len);\n    }\n\n    run_coordinate(min(TIME_LIMIT * 0.95, priorityLimit + 0.1), 1, nullptr);\n\n    vector<int> segLens = {4, 6, 8, 10, 12, 16, 20, 24, 28, 32,\n                           36, 40, 48, 56, 64, 72, 80};\n    vector<double> lenWeights;\n    for (int len : segLens) lenWeights.push_back(1.0 / len);\n    discrete_distribution<int> lenDist(lenWeights.begin(), lenWeights.end());\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    auto sample_weighted_start = [&](mt19937& rng) -> int {\n        array<double, MAX_L> weights;\n        double total = 0.0;\n        for (int i = 0; i < MAX_L; ++i) {\n            double w = aliveProb[i] * (401.0 - (i + 1));\n            weights[i] = max(0.0, w);\n            total += weights[i];\n        }\n        if (total < 1e-9) {\n            uniform_int_distribution<int> dist(0, MAX_L - 1);\n            return dist(rng);\n        }\n        uniform_real_distribution<double> dist(0.0, total);\n        double r = dist(rng);\n        double acc = 0.0;\n        for (int i = 0; i < MAX_L; ++i) {\n            acc += weights[i];\n            if (r <= acc) return i;\n        }\n        return MAX_L - 1;\n    };\n\n    double lnsLimit = TIME_LIMIT * 0.985;\n    while (elapsed() < lnsLimit) {\n        int len = segLens[lenDist(rng)];\n        int start = sample_weighted_start(rng);\n        if (start + len > MAX_L) start = MAX_L - len;\n        if (start < 0) start = 0;\n        if (aliveProb[start] < 1e-9) continue;\n        try_segment(start, len);\n    }\n\n    apply_drop_segments(TIME_LIMIT * 0.99, 6);\n    run_coordinate(TIME_LIMIT * 0.998, 1, nullptr);\n\n    string answer(MAX_L, 'U');\n    for (int i = 0; i < MAX_L; ++i) answer[i] = DIR_CHARS[bestSeq[i]];\n    cout << answer << '\\n';\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int H = 30;\nconstexpr int W = 30;\nconstexpr int N = H * W;\nconstexpr int DIR = 4;\nconstexpr int STATE = N * DIR;\n\nconstexpr int di[4] = {0, -1, 0, 1};\nconstexpr int dj[4] = {-1, 0, 1, 0};\n\nconstexpr int TO_TABLE[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\nconstexpr int ROT_NEXT[8] = {1, 2, 3, 0, 5, 4, 7, 6};\narray<array<int, 4>, N> g_neighbors;\nint ROT_TABLE[8][4];\n\nstruct EvalResult {\n    long long score;\n    int l1;\n    int l2;\n    int loopCnt;\n};\n\nstruct Evaluator {\n    array<int, STATE> visitedStamp{};\n    array<int, STATE> pathStamp{};\n    array<int, STATE> pathPos{};\n    int visitedToken = 0;\n    int pathToken = 0;\n    vector<int> pathList;\n\n    Evaluator() { pathList.reserve(STATE); }\n\n    EvalResult operator()(const vector<int>& finalType) {\n        ++visitedToken;\n        int token = visitedToken;\n        for (int cell = 0; cell < N; ++cell) {\n            int type = finalType[cell];\n            for (int d = 0; d < DIR; ++d) {\n                if (TO_TABLE[type][d] == -1) {\n                    visitedStamp[(cell << 2) | d] = token;\n                }\n            }\n        }\n\n        long long best1 = 0, best2 = 0;\n        int loops = 0;\n\n        for (int cell = 0; cell < N; ++cell) {\n            for (int d = 0; d < DIR; ++d) {\n                int idx = (cell << 2) | d;\n                if (visitedStamp[idx] == token) continue;\n\n                ++pathToken;\n                int pathTok = pathToken;\n                pathList.clear();\n\n                int curCell = cell;\n                int curDir = d;\n                int i = curCell / W;\n                int j = curCell % W;\n                int length = 0;\n\n                while (true) {\n                    int stateIdx = (curCell << 2) | curDir;\n                    if (visitedStamp[stateIdx] == token) break;\n\n                    if (pathStamp[stateIdx] == pathTok) {\n                        int loopLen = length - pathPos[stateIdx];\n                        if (loopLen > 0) {\n                            ++loops;\n                            if (loopLen >= best1) {\n                                best2 = best1;\n                                best1 = loopLen;\n                            } else if (loopLen > best2) {\n                                best2 = loopLen;\n                            }\n                        }\n                        break;\n                    }\n\n                    pathStamp[stateIdx] = pathTok;\n                    pathPos[stateIdx] = length;\n                    pathList.push_back(stateIdx);\n\n                    int type = finalType[curCell];\n                    int nextDir = TO_TABLE[type][curDir];\n                    if (nextDir == -1) break;\n\n                    int ni = i + di[nextDir];\n                    int nj = j + dj[nextDir];\n                    if (ni < 0 || ni >= H || nj < 0 || nj >= W) break;\n\n                    i = ni;\n                    j = nj;\n                    curCell = ni * W + nj;\n                    curDir = (nextDir + 2) & 3;\n                    ++length;\n                }\n\n                for (int s : pathList) {\n                    visitedStamp[s] = token;\n                }\n            }\n        }\n\n        long long score = (loops >= 2) ? best1 * best2 : 0LL;\n        return {score, (int)best1, (int)best2, loops};\n    }\n};\n\nstruct Solution {\n    long long score = -1;\n    vector<int> rot;\n    vector<int> type;\n};\n\nSolution solve_single(const vector<int>& base, double TIME_LIMIT, uint64_t seed,\n                      const vector<int>* initialRot = nullptr) {\n    auto start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    mt19937 rng(seed);\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    vector<int> rot(N, 0);\n    vector<int> finalType(N, 0);\n\n    const int MATCH_BONUS = 7;\n    const int OPEN_PENALTY = -3;\n    const int BORDER_PENALTY = -6;\n\n    if (initialRot) {\n        rot = *initialRot;\n        for (int cell = 0; cell < N; ++cell) {\n            rot[cell] &= 3;\n            finalType[cell] = ROT_TABLE[base[cell]][rot[cell]];\n        }\n    } else {\n        for (int cell = 0; cell < N; ++cell) {\n            int baseType = base[cell];\n            int bestR = 0;\n            int bestVal = -1e9;\n            array<char, 8> used{};\n            for (int r = 0; r < 4; ++r) {\n                int type = ROT_TABLE[baseType][r];\n                if (used[type]) continue;\n                used[type] = 1;\n                int val = 0;\n                for (int d = 0; d < DIR; ++d) {\n                    if (TO_TABLE[type][d] == -1) continue;\n                    int nb = g_neighbors[cell][d];\n                    if (nb == -1) val += BORDER_PENALTY;\n                    else val += MATCH_BONUS / 2;\n                }\n                if (val > bestVal || (val == bestVal && (rng() & 1))) {\n                    bestVal = val;\n                    bestR = r;\n                }\n            }\n            rot[cell] = bestR;\n            finalType[cell] = ROT_TABLE[baseType][bestR];\n        }\n    }\n\n    vector<int> openEnds(N, 0);\n    vector<int> badPos(N, -1);\n    vector<int> badCells;\n    badCells.reserve(N);\n\n    auto setBadState = [&](int cell, bool bad) {\n        if (bad) {\n            if (badPos[cell] == -1) {\n                badPos[cell] = (int)badCells.size();\n                badCells.push_back(cell);\n            }\n        } else if (badPos[cell] != -1) {\n            int idx = badPos[cell];\n            int last = badCells.back();\n            badCells[idx] = last;\n            badPos[last] = idx;\n            badCells.pop_back();\n            badPos[cell] = -1;\n        }\n    };\n\n    struct LocalResult { int score; int open; };\n\n    auto localEval = [&](int cell, int type) -> LocalResult {\n        LocalResult res{0, 0};\n        for (int d = 0; d < DIR; ++d) {\n            if (TO_TABLE[type][d] == -1) continue;\n            int nb = g_neighbors[cell][d];\n            if (nb == -1) {\n                res.score += BORDER_PENALTY;\n                res.open += 1;\n            } else {\n                int nbType = finalType[nb];\n                if (TO_TABLE[nbType][(d + 2) & 3] != -1) {\n                    res.score += MATCH_BONUS;\n                } else {\n                    res.score += OPEN_PENALTY;\n                    res.open += 1;\n                }\n            }\n        }\n        return res;\n    };\n\n    auto updateOne = [&](int cell) {\n        if (cell < 0) return;\n        LocalResult res = localEval(cell, finalType[cell]);\n        openEnds[cell] = res.open;\n        setBadState(cell, res.open > 0);\n    };\n\n    auto updateAround = [&](int cell) {\n        updateOne(cell);\n        for (int d = 0; d < DIR; ++d) {\n            int nb = g_neighbors[cell][d];\n            if (nb != -1) updateOne(nb);\n        }\n    };\n\n    auto recomputeAll = [&]() {\n        badCells.clear();\n        fill(badPos.begin(), badPos.end(), -1);\n        for (int cell = 0; cell < N; ++cell) updateOne(cell);\n    };\n\n    recomputeAll();\n\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    double greedyLimit = initialRot ? 0.0 : min(0.45, TIME_LIMIT * 0.35);\n\n    while (elapsed() < greedyLimit) {\n        bool improved = false;\n        shuffle(order.begin(), order.end(), rng);\n        for (int cell : order) {\n            if (elapsed() > greedyLimit) break;\n            int baseType = base[cell];\n            int curType = finalType[cell];\n            LocalResult curRes = localEval(cell, curType);\n            pair<int, int> bestMetric = {curRes.score, -curRes.open};\n            int bestType = curType;\n            int bestRot = rot[cell];\n            array<char, 8> used{};\n            for (int r = 0; r < 4; ++r) {\n                int candType = ROT_TABLE[baseType][r];\n                if (used[candType]) continue;\n                used[candType] = 1;\n                LocalResult candRes = localEval(cell, candType);\n                pair<int, int> metric = {candRes.score, -candRes.open};\n                if (metric > bestMetric || (metric == bestMetric && (rng() & 1))) {\n                    bestMetric = metric;\n                    bestType = candType;\n                    bestRot = r;\n                }\n            }\n            if (bestType != curType) {\n                finalType[cell] = bestType;\n                rot[cell] = bestRot;\n                improved = true;\n                updateAround(cell);\n            }\n        }\n        if (!improved) break;\n    }\n\n    recomputeAll();\n\n    Evaluator evaluator;\n    EvalResult curEval = evaluator(finalType);\n    long long currentScore = curEval.score;\n    long long bestScore = currentScore;\n    vector<int> bestRot = rot;\n    vector<int> bestType = finalType;\n\n    double saStart = elapsed();\n    double saEnd = min(TIME_LIMIT - 0.02, TIME_LIMIT * 0.98);\n    if (saEnd <= saStart + 1e-4) saEnd = TIME_LIMIT - 0.02;\n\n    if (saEnd > saStart + 1e-4) {\n        double span = max(1e-6, saEnd - saStart);\n        const double T0 = 4.0;\n        const double T1 = 0.05;\n\n        while (elapsed() < saEnd) {\n            double progress = (elapsed() - saStart) / span;\n            progress = min(1.0, max(0.0, progress));\n            double temp = T0 + (T1 - T0) * progress;\n\n            int cell;\n            if (!badCells.empty() && dist01(rng) < 0.85) {\n                cell = badCells[rng() % badCells.size()];\n            } else {\n                cell = rng() % N;\n            }\n\n            int baseType = base[cell];\n            int oldRot = rot[cell];\n            int oldType = finalType[cell];\n\n            int newRot = oldRot;\n            int newType = oldType;\n            bool changed = false;\n            for (int tries = 0; tries < 4; ++tries) {\n                int diff = rng() % 3 + 1;\n                int candRot = (oldRot + diff) & 3;\n                int candType = ROT_TABLE[baseType][candRot];\n                if (candType != oldType) {\n                    newRot = candRot;\n                    newType = candType;\n                    changed = true;\n                    break;\n                }\n            }\n            if (!changed) {\n                for (int r = 0; r < 4; ++r) {\n                    int candType = ROT_TABLE[baseType][r];\n                    if (candType != oldType) {\n                        newRot = r;\n                        newType = candType;\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n            if (!changed) continue;\n\n            rot[cell] = newRot;\n            finalType[cell] = newType;\n\n            EvalResult nextEval = evaluator(finalType);\n            long long delta = nextEval.score - currentScore;\n            bool accept = (delta >= 0) || (exp(delta / temp) > dist01(rng));\n\n            if (accept) {\n                currentScore = nextEval.score;\n                updateAround(cell);\n                if (nextEval.score > bestScore) {\n                    bestScore = nextEval.score;\n                    bestRot = rot;\n                    bestType = finalType;\n                }\n            } else {\n                rot[cell] = oldRot;\n                finalType[cell] = oldType;\n            }\n        }\n    }\n\n    Solution sol;\n    sol.score = bestScore;\n    sol.rot = move(bestRot);\n    sol.type = move(bestType);\n    return sol;\n}\n\nvoid hill_climb_improve(Solution& sol, const vector<int>& base, double timeBudget, uint64_t seed) {\n    if (timeBudget <= 1e-4 || sol.score < 0) return;\n    auto start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    mt19937 rng(seed);\n    Evaluator evaluator;\n\n    while (elapsed() < timeBudget) {\n        int cell = rng() % N;\n        int baseType = base[cell];\n        int oldRot = sol.rot[cell];\n        int oldType = sol.type[cell];\n\n        long long bestScore = sol.score;\n        int bestRot = oldRot;\n        int bestType = oldType;\n\n        for (int diff = 1; diff <= 3; ++diff) {\n            int newRot = (oldRot + diff) & 3;\n            int newType = ROT_TABLE[baseType][newRot];\n            if (newType == bestType) continue;\n            sol.rot[cell] = newRot;\n            sol.type[cell] = newType;\n            EvalResult res = evaluator(sol.type);\n            if (res.score > bestScore) {\n                bestScore = res.score;\n                bestRot = newRot;\n                bestType = newType;\n            }\n        }\n\n        sol.rot[cell] = bestRot;\n        sol.type[cell] = bestType;\n        sol.score = bestScore;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> base(N);\n    for (int i = 0; i < H; ++i) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < W; ++j) {\n            base[i * W + j] = s[j] - '0';\n        }\n    }\n\n    for (int cell = 0; cell < N; ++cell) {\n        int i = cell / W;\n        int j = cell % W;\n        for (int d = 0; d < DIR; ++d) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            g_neighbors[cell][d] = (0 <= ni && ni < H && 0 <= nj && nj < W) ? ni * W + nj : -1;\n        }\n    }\n\n    for (int t = 0; t < 8; ++t) {\n        ROT_TABLE[t][0] = t;\n        for (int r = 1; r < 4; ++r) {\n            ROT_TABLE[t][r] = ROT_NEXT[ROT_TABLE[t][r - 1]];\n        }\n    }\n\n    const double TOTAL_LIMIT = 1.9;\n    const double FINAL_MARGIN = 0.02;\n    const double HILL_BUDGET = 0.18;\n\n    vector<double> baseRuns = {0.9, 0.65};\n\n    auto globalStart = chrono::steady_clock::now();\n    auto totalElapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - globalStart).count();\n    };\n\n    uint64_t seedBase = chrono::high_resolution_clock::now().time_since_epoch().count();\n    Solution bestOverall;\n    bestOverall.score = -1;\n\n    for (size_t attempt = 0; attempt < baseRuns.size(); ++attempt) {\n        double remain = TOTAL_LIMIT - totalElapsed();\n        if (remain <= FINAL_MARGIN + HILL_BUDGET + 0.25) break;\n        double limit = min(baseRuns[attempt], remain - (FINAL_MARGIN + HILL_BUDGET));\n        if (limit < 0.25) break;\n        Solution sol = solve_single(base, limit, seedBase + attempt * 9973 + 1);\n        if (sol.score > bestOverall.score) bestOverall = sol;\n    }\n\n    if (bestOverall.score < 0) {\n        double remain = TOTAL_LIMIT - totalElapsed();\n        double limit = max(0.4, remain - (HILL_BUDGET + FINAL_MARGIN));\n        Solution sol = solve_single(base, limit, seedBase ^ 0x9e3779b97f4a7c15ULL);\n        if (sol.score > bestOverall.score) bestOverall = sol;\n    }\n\n    double remainForReanneal = TOTAL_LIMIT - totalElapsed() - (HILL_BUDGET + FINAL_MARGIN);\n    if (bestOverall.score >= 0 && remainForReanneal > 0.25) {\n        double limit = min(0.6, remainForReanneal);\n        Solution reSol = solve_single(base, limit, seedBase + 0x12345, &bestOverall.rot);\n        if (reSol.score > bestOverall.score) bestOverall = reSol;\n    }\n\n    double hillBudget = TOTAL_LIMIT - totalElapsed() - FINAL_MARGIN;\n    if (hillBudget > 0) {\n        hill_climb_improve(bestOverall, base, min(hillBudget, HILL_BUDGET), seedBase + 0xabcdef);\n    }\n\n    Evaluator finalEval;\n    bestOverall.score = finalEval(bestOverall.type).score;\n\n    string output;\n    output.reserve(N);\n    for (int idx = 0; idx < N; ++idx) {\n        output.push_back(char('0' + bestOverall.rot[idx]));\n    }\n    cout << output << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAX_N = 10;\nconst int MAX_CELLS = MAX_N * MAX_N;\n\nint N, T;\nint total_cells, total_tiles;\n\nuint64_t zobrist[MAX_CELLS][16];\nuint8_t visited_buf[MAX_CELLS];\nint queue_buf[MAX_CELLS];\n\nconst int CONN_DX[4] = {0, -1, 0, 1};\nconst int CONN_DY[4] = {-1, 0, 1, 0};\nconst int CONN_BIT[4] = {1, 2, 4, 8};\nconst int CONN_OPP[4] = {2, 3, 0, 1};\n\nconst int BLANK_DX[4] = {-1, 1, 0, 0};\nconst int BLANK_DY[4] = {0, 0, -1, 1};\nconst char MOVE_CHAR[4] = {'U', 'D', 'L', 'R'};\nconst int MOVE_OPP[4] = {1, 0, 3, 2};\n\nstruct EvalResult {\n    int matched_edges;\n    int largest_tree;\n    int best_component_nodes;\n    int best_component_cycles;\n};\n\ninline bool evalBetter(const EvalResult& a, const EvalResult& b) {\n    if (a.largest_tree != b.largest_tree) return a.largest_tree > b.largest_tree;\n    if (a.best_component_nodes != b.best_component_nodes) return a.best_component_nodes > b.best_component_nodes;\n    if (a.best_component_cycles != b.best_component_cycles) return a.best_component_cycles < b.best_component_cycles;\n    if (a.matched_edges != b.matched_edges) return a.matched_edges > b.matched_edges;\n    return false;\n}\n\ninline bool evalEqual(const EvalResult& a, const EvalResult& b) {\n    return a.largest_tree == b.largest_tree &&\n           a.best_component_nodes == b.best_component_nodes &&\n           a.best_component_cycles == b.best_component_cycles &&\n           a.matched_edges == b.matched_edges;\n}\n\nEvalResult evaluateBoard(const uint8_t* board) {\n    EvalResult res;\n    res.matched_edges = 0;\n    res.largest_tree = 0;\n    res.best_component_nodes = 0;\n    res.best_component_cycles = INT_MAX;\n\n    for (int i = 0; i < N; ++i) {\n        int base = i * N;\n        for (int j = 0; j < N; ++j) {\n            int idx = base + j;\n            uint8_t val = board[idx];\n            if (!val) continue;\n            if (j + 1 < N) {\n                uint8_t nb = board[idx + 1];\n                if (nb && (val & 4) && (nb & 1)) res.matched_edges++;\n            }\n            if (i + 1 < N) {\n                uint8_t nb = board[idx + N];\n                if (nb && (val & 8) && (nb & 2)) res.matched_edges++;\n            }\n        }\n    }\n\n    fill(visited_buf, visited_buf + total_cells, 0);\n    for (int idx = 0; idx < total_cells; ++idx) {\n        uint8_t val = board[idx];\n        if (!val || visited_buf[idx]) continue;\n        int head = 0, tail = 0;\n        queue_buf[tail++] = idx;\n        visited_buf[idx] = 1;\n        int nodes = 0;\n        int edges = 0;\n        while (head < tail) {\n            int cur = queue_buf[head++];\n            nodes++;\n            int cx = cur / N;\n            int cy = cur % N;\n            uint8_t curv = board[cur];\n            for (int d = 0; d < 4; ++d) {\n                if (!(curv & CONN_BIT[d])) continue;\n                int nx = cx + CONN_DX[d];\n                int ny = cy + CONN_DY[d];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                int nidx = nx * N + ny;\n                uint8_t nval = board[nidx];\n                if (!nval) continue;\n                if (!(nval & CONN_BIT[CONN_OPP[d]])) continue;\n                if (cur < nidx) edges++;\n                if (!visited_buf[nidx]) {\n                    visited_buf[nidx] = 1;\n                    queue_buf[tail++] = nidx;\n                }\n            }\n        }\n        int cycles = max(0, edges - (nodes - 1));\n        if (cycles == 0) res.largest_tree = max(res.largest_tree, nodes);\n        if (nodes > res.best_component_nodes ||\n            (nodes == res.best_component_nodes && cycles < res.best_component_cycles)) {\n            res.best_component_nodes = nodes;\n            res.best_component_cycles = cycles;\n        }\n    }\n    if (res.best_component_nodes == 0) res.best_component_cycles = 0;\n    return res;\n}\n\nuint64_t computeHash(const array<uint8_t, MAX_CELLS>& board) {\n    uint64_t h = 0;\n    for (int i = 0; i < total_cells; ++i) h ^= zobrist[i][board[i]];\n    return h;\n}\n\ninline void applyMoveArray(array<uint8_t, MAX_CELLS>& board, int& blank, int dir) {\n    int x = blank / N;\n    int y = blank % N;\n    int nx = x + BLANK_DX[dir];\n    int ny = y + BLANK_DY[dir];\n    int nidx = nx * N + ny;\n    swap(board[blank], board[nidx]);\n    blank = nidx;\n}\n\nstruct NodeInfo { int parent; char move; };\n\nstruct SearchState {\n    array<uint8_t, MAX_CELLS> tiles;\n    uint16_t blank = 0;\n    uint64_t hash = 0;\n    EvalResult eval{};\n    uint16_t depth = 0;\n    int node_id = 0;\n    uint32_t rand_key = 0;\n};\n\nstruct AttemptResult {\n    EvalResult eval;\n    int depth;\n    string sequence;\n    array<uint8_t, MAX_CELLS> board;\n    int blank;\n};\n\nAttemptResult runAttempt(const array<uint8_t, MAX_CELLS>& start_tiles,\n                         int blank_pos,\n                         int beam_width,\n                         int depth_limit,\n                         double time_limit,\n                         const chrono::steady_clock::time_point& start_time,\n                         mt19937& rng) {\n    AttemptResult result;\n    result.board = start_tiles;\n    result.blank = blank_pos;\n    result.eval = evaluateBoard(start_tiles.data());\n    result.depth = 0;\n    result.sequence.clear();\n    if (depth_limit <= 0 || result.eval.largest_tree == total_tiles) {\n        return result;\n    }\n\n    vector<NodeInfo> nodes;\n    nodes.reserve(1 + beam_width * 64);\n    nodes.push_back({-1, '?'});\n\n    size_t reserve_est = (size_t)beam_width * min(depth_limit, 64);\n    unordered_map<uint64_t, uint16_t> visited;\n    visited.reserve(reserve_est + 16);\n\n    vector<SearchState> beam;\n    vector<SearchState> candidates;\n    beam.reserve(beam_width);\n    candidates.reserve(beam_width * 4 + 8);\n\n    SearchState init;\n    init.tiles = start_tiles;\n    init.blank = blank_pos;\n    init.hash = computeHash(start_tiles);\n    init.eval = result.eval;\n    init.depth = 0;\n    init.node_id = 0;\n    init.rand_key = rng();\n    beam.push_back(init);\n    visited.emplace(init.hash, 0);\n\n    EvalResult best_eval = init.eval;\n    int best_depth = 0;\n    int best_node = 0;\n    array<uint8_t, MAX_CELLS> best_tiles = start_tiles;\n    int best_blank = blank_pos;\n\n    auto stateComparator = [](const SearchState& a, const SearchState& b) {\n        if (evalBetter(a.eval, b.eval)) return true;\n        if (evalBetter(b.eval, a.eval)) return false;\n        if (a.depth != b.depth) return a.depth < b.depth;\n        return a.rand_key < b.rand_key;\n    };\n\n    int current_depth = 0;\n    bool terminate = false;\n\n    while (!beam.empty() && current_depth < depth_limit && !terminate) {\n        if ((current_depth & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n            if (elapsed > time_limit) break;\n        }\n        candidates.clear();\n        for (size_t si = 0; si < beam.size() && !terminate; ++si) {\n            if ((si & 3) == 0) {\n                double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n                if (elapsed > time_limit) { terminate = true; break; }\n            }\n            const SearchState& state = beam[si];\n            int blank = state.blank;\n            int bx = blank / N;\n            int by = blank % N;\n            int dir_order[4] = {0, 1, 2, 3};\n            for (int i = 3; i > 0; --i) {\n                int j = rng() % (i + 1);\n                swap(dir_order[i], dir_order[j]);\n            }\n            for (int k = 0; k < 4; ++k) {\n                int dir = dir_order[k];\n                int nx = bx + BLANK_DX[dir];\n                int ny = by + BLANK_DY[dir];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                int nidx = nx * N + ny;\n                if (state.tiles[nidx] == 0) continue;\n                SearchState child = state;\n                uint8_t tile_to_move = state.tiles[nidx];\n                child.tiles[blank] = tile_to_move;\n                child.tiles[nidx] = 0;\n                child.blank = nidx;\n                child.depth = state.depth + 1;\n                if (child.depth > depth_limit) continue;\n                child.hash ^= zobrist[blank][0];\n                child.hash ^= zobrist[nidx][tile_to_move];\n                child.hash ^= zobrist[blank][tile_to_move];\n                child.hash ^= zobrist[nidx][0];\n                auto it = visited.find(child.hash);\n                if (it != visited.end()) {\n                    if (child.depth >= it->second) continue;\n                    it->second = child.depth;\n                } else {\n                    visited.emplace(child.hash, child.depth);\n                }\n                child.node_id = static_cast<int>(nodes.size());\n                nodes.push_back({state.node_id, MOVE_CHAR[dir]});\n                child.eval = evaluateBoard(child.tiles.data());\n                child.rand_key = rng();\n                if (evalBetter(child.eval, best_eval) ||\n                    (evalEqual(child.eval, best_eval) && child.depth < best_depth)) {\n                    best_eval = child.eval;\n                    best_depth = child.depth;\n                    best_node = child.node_id;\n                    best_tiles = child.tiles;\n                    best_blank = child.blank;\n                    if (best_eval.largest_tree == total_tiles) {\n                        terminate = true;\n                        candidates.emplace_back(std::move(child));\n                        break;\n                    }\n                }\n                candidates.emplace_back(std::move(child));\n            }\n        }\n        if (terminate || candidates.empty()) break;\n        sort(candidates.begin(), candidates.end(), stateComparator);\n        if ((int)candidates.size() > beam_width) candidates.resize(beam_width);\n        beam.swap(candidates);\n        current_depth++;\n    }\n\n    string seq;\n    seq.reserve(best_depth);\n    int node = best_node;\n    while (node != 0) {\n        seq.push_back(nodes[node].move);\n        node = nodes[node].parent;\n    }\n    reverse(seq.begin(), seq.end());\n\n    result.sequence = seq;\n    result.eval = best_eval;\n    result.depth = best_depth;\n    result.board = best_tiles;\n    result.blank = best_blank;\n    return result;\n}\n\nvoid guidedRandomSearch(string& best_sequence,\n                        int& best_length,\n                        array<uint8_t, MAX_CELLS>& best_board,\n                        int& best_blank,\n                        EvalResult& best_eval,\n                        const chrono::steady_clock::time_point& start_time,\n                        double time_limit,\n                        mt19937& rng) {\n    if (best_length >= T) return;\n    string current_sequence = best_sequence;\n    array<uint8_t, MAX_CELLS> current_board = best_board;\n    int current_blank = best_blank;\n    EvalResult current_eval = best_eval;\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n    int prev_dir = -1;\n    int stagnation = 0;\n    const int reset_interval = max(80, 40 + 6 * N);\n\n    while ((int)current_sequence.size() < T) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n        if (elapsed > time_limit) break;\n\n        if (stagnation > reset_interval) {\n            current_sequence = best_sequence;\n            current_board = best_board;\n            current_blank = best_blank;\n            current_eval = best_eval;\n            prev_dir = -1;\n            stagnation = 0;\n        }\n\n        struct CandidateMove {\n            int dir;\n            EvalResult eval;\n            bool is_reverse;\n        };\n        CandidateMove candidates[4];\n        int candCount = 0;\n\n        int x = current_blank / N;\n        int y = current_blank % N;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = x + BLANK_DX[dir];\n            int ny = y + BLANK_DY[dir];\n            if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n            int nidx = nx * N + ny;\n            if (current_board[nidx] == 0) continue;\n            int temp_blank = current_blank;\n            applyMoveArray(current_board, temp_blank, dir);\n            EvalResult eval = evaluateBoard(current_board.data());\n            applyMoveArray(current_board, temp_blank, MOVE_OPP[dir]);\n            candidates[candCount++] = {dir, eval, (dir == MOVE_OPP[prev_dir])};\n        }\n\n        if (candCount == 0) break;\n\n        double progress = (double)best_eval.largest_tree / max(1, total_tiles);\n        double explore_prob = 0.08 + 0.25 * (1.0 - progress);\n        if (stagnation > reset_interval / 2) explore_prob += 0.05;\n        explore_prob = min(0.4, max(0.05, explore_prob));\n        bool explore = dist01(rng) < explore_prob;\n\n        int chosen_idx = 0;\n        if (!explore) {\n            for (int i = 1; i < candCount; ++i) {\n                if (evalBetter(candidates[i].eval, candidates[chosen_idx].eval)) {\n                    chosen_idx = i;\n                } else if (!evalBetter(candidates[chosen_idx].eval, candidates[i].eval)) {\n                    bool a_rev = candidates[chosen_idx].is_reverse;\n                    bool b_rev = candidates[i].is_reverse;\n                    if (a_rev != b_rev) {\n                        if (!b_rev) chosen_idx = i;\n                    } else if (rng() & 1) {\n                        chosen_idx = i;\n                    }\n                }\n            }\n        } else {\n            int nonRev[4];\n            int nonCnt = 0;\n            for (int i = 0; i < candCount; ++i) if (!candidates[i].is_reverse) nonRev[nonCnt++] = i;\n            if (nonCnt > 0) chosen_idx = nonRev[rng() % nonCnt];\n            else chosen_idx = rng() % candCount;\n        }\n\n        int dir = candidates[chosen_idx].dir;\n        applyMoveArray(current_board, current_blank, dir);\n        current_sequence.push_back(MOVE_CHAR[dir]);\n        prev_dir = dir;\n        current_eval = candidates[chosen_idx].eval;\n        stagnation++;\n\n        if (evalBetter(current_eval, best_eval)) {\n            best_eval = current_eval;\n            best_sequence = current_sequence;\n            best_board = current_board;\n            best_blank = current_blank;\n            best_length = (int)best_sequence.size();\n            stagnation = 0;\n            if (best_eval.largest_tree == total_tiles) break;\n        }\n\n        if ((int)current_sequence.size() >= T) break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T;\n    total_cells = N * N;\n    total_tiles = total_cells - 1;\n\n    array<uint8_t, MAX_CELLS> initial_tiles{};\n    int blank_pos = -1;\n    for (int i = 0; i < N; ++i) {\n        string row;\n        cin >> row;\n        for (int j = 0; j < N; ++j) {\n            char c = row[j];\n            int val = (c <= '9') ? c - '0' : 10 + (c - 'a');\n            int idx = i * N + j;\n            initial_tiles[idx] = static_cast<uint8_t>(val);\n            if (val == 0) blank_pos = idx;\n        }\n    }\n\n    mt19937_64 rng64(chrono::steady_clock::now().time_since_epoch().count());\n    for (int i = 0; i < MAX_CELLS; ++i)\n        for (int v = 0; v < 16; ++v) {\n            uint64_t x = rng64();\n            if (x == 0) x = 1;\n            zobrist[i][v] = x;\n        }\n    mt19937 rng(static_cast<uint32_t>(rng64()));\n\n    EvalResult best_eval = evaluateBoard(initial_tiles.data());\n    string best_sequence;\n    best_sequence.reserve(T);\n    array<uint8_t, MAX_CELLS> best_board = initial_tiles;\n    int best_blank = blank_pos;\n    int best_length = 0;\n\n    const double TIME_LIMIT = 2.80;\n    const double FIRST_RATIO = 0.55;\n    const double SECOND_RATIO = 0.92;\n\n    int base_width = 80 - 4 * N;\n    base_width = max(12, min(base_width, 90));\n    int local_base_width = max(8, base_width - 8);\n\n    int global_depth_cap = min(T, max(200, 10 * N * N));\n    int local_depth_cap = min(T, max(80, 4 * N * N));\n\n    auto start_time = chrono::steady_clock::now();\n\n    auto attemptBetter = [&](const AttemptResult& a, const AttemptResult& b) {\n        if (evalBetter(a.eval, b.eval)) return true;\n        if (evalBetter(b.eval, a.eval)) return false;\n        return a.depth < b.depth;\n    };\n\n    vector<AttemptResult> candidateStates;\n    const int MAX_CANDIDATES = 5;\n    AttemptResult initial_state;\n    initial_state.eval = best_eval;\n    initial_state.sequence = \"\";\n    initial_state.depth = 0;\n    initial_state.board = initial_tiles;\n    initial_state.blank = blank_pos;\n    candidateStates.push_back(initial_state);\n\n    auto addCandidate = [&](const AttemptResult& res) {\n        candidateStates.push_back(res);\n        sort(candidateStates.begin(), candidateStates.end(),\n             [&](const AttemptResult& x, const AttemptResult& y) {\n                 if (attemptBetter(x, y)) return true;\n                 if (attemptBetter(y, x)) return false;\n                 return x.sequence.size() < y.sequence.size();\n             });\n        vector<AttemptResult> filtered;\n        filtered.reserve(MAX_CANDIDATES);\n        for (const auto& cand : candidateStates) {\n            bool dup = false;\n            for (const auto& f : filtered) {\n                if (evalEqual(cand.eval, f.eval) && cand.depth == f.depth) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) {\n                filtered.push_back(cand);\n                if ((int)filtered.size() == MAX_CANDIDATES) break;\n            }\n        }\n        candidateStates.swap(filtered);\n    };\n\n    int attempt = 0;\n    while (true) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n        if (elapsed > TIME_LIMIT * FIRST_RATIO) break;\n        int width = base_width;\n        int mod = attempt % 4;\n        if (mod == 1) width += 8;\n        else if (mod == 2) width -= 6;\n        else if (mod == 3) width += 2;\n        width = max(10, min(width, 96));\n\n        AttemptResult res = runAttempt(initial_tiles, blank_pos, width, global_depth_cap,\n                                       TIME_LIMIT, start_time, rng);\n        attempt++;\n        addCandidate(res);\n        if (evalBetter(res.eval, best_eval) ||\n            (evalEqual(res.eval, best_eval) && (best_length == 0 || res.depth < best_length))) {\n            best_eval = res.eval;\n            best_sequence = res.sequence;\n            best_board = res.board;\n            best_blank = res.blank;\n            best_length = res.depth;\n            if (best_eval.largest_tree == total_tiles) break;\n        }\n    }\n\n    if (best_eval.largest_tree < total_tiles && best_length < T) {\n        vector<AttemptResult> snapshot = candidateStates;\n        for (size_t idx = 0; idx < snapshot.size(); ++idx) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n            if (elapsed > TIME_LIMIT * SECOND_RATIO) break;\n            AttemptResult base_state = snapshot[idx];\n            for (int iter = 0; iter < 2; ++iter) {\n                double elapsed2 = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n                if (elapsed2 > TIME_LIMIT * SECOND_RATIO) break;\n                int remaining = T - base_state.depth;\n                if (remaining <= 0) break;\n                int depth_cap = min(remaining, local_depth_cap);\n                int width = local_base_width;\n                int mod = (idx + iter) % 3;\n                if (mod == 1) width += 4;\n                else if (mod == 2) width -= 4;\n                width = max(8, min(width, 90));\n\n                AttemptResult res = runAttempt(base_state.board, base_state.blank, width, depth_cap,\n                                               TIME_LIMIT, start_time, rng);\n                if (res.depth == 0) continue;\n\n                AttemptResult combined;\n                combined.eval = res.eval;\n                combined.depth = base_state.depth + res.depth;\n                combined.sequence = base_state.sequence + res.sequence;\n                combined.board = res.board;\n                combined.blank = res.blank;\n\n                addCandidate(combined);\n\n                if (evalBetter(combined.eval, best_eval)) {\n                    best_eval = combined.eval;\n                    best_sequence = combined.sequence;\n                    best_board = combined.board;\n                    best_blank = combined.blank;\n                    best_length = combined.depth;\n                    if (best_eval.largest_tree == total_tiles || best_length >= T) break;\n                }\n                base_state = combined;\n            }\n            if (best_eval.largest_tree == total_tiles || best_length >= T) break;\n        }\n    }\n\n    best_length = (int)best_sequence.size();\n\n    if (best_eval.largest_tree < total_tiles && best_length < T) {\n        guidedRandomSearch(best_sequence, best_length, best_board, best_blank,\n                           best_eval, start_time, TIME_LIMIT, rng);\n    }\n\n    cout << best_sequence << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\nstruct Line { long long A, B, C; };\nstruct Key { unsigned long long lo, hi; };\nstruct PieceSegment { int start, len; };\nusing CountArr = array<int, 11>;\n\nconst long long COORD_LIMIT = 1'000'000'000LL;\nconst double TIME_LIMIT = 2.8;\nconst int DIR_LIMIT = 1000;\nconst int GENERATE_LINE_ATTEMPTS = 100;\n\nint N, K;\narray<int, 11> demand{};\nvector<Point> points;\n\nvector<unsigned long long> pattern_lo, pattern_hi;\nvector<Key> tmp_keys;\nvector<long long> proj_values;\nvector<long long> proj_sorted_buffer;\nvector<long long> piece_proj_buffer;\nvector<long long> unique_values_buffer;\nvector<int> targeted_gap_indices;\nvector<int> state_order;\nvector<int> eval_order;\nvector<int> piece_id;\nvector<PieceSegment> piece_segments;\nvector<int> gap_indices;\nvector<Line> lines_current;\n\nCountArr current_counts_state{};\nint bits_used = 0;\nbool piece_info_valid = false;\n\nmt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\nchrono::steady_clock::time_point start_time;\nbool time_up = false;\n\ninline long long absll(long long x) { return x >= 0 ? x : -x; }\n\nlong long floor_div(long long a, long long b) {\n    assert(b != 0);\n    if (b < 0) { a = -a; b = -b; }\n    if (a >= 0) return a / b;\n    return -(( -a + b - 1 ) / b);\n}\nlong long ceil_div(long long a, long long b) {\n    assert(b != 0);\n    if (b < 0) { a = -a; b = -b; }\n    if (a >= 0) return (a + b - 1) / b;\n    return -((-a) / b);\n}\n\nlong long ext_gcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) {\n        x = (a >= 0) ? 1 : -1;\n        y = 0;\n        return absll(a);\n    }\n    long long x1, y1;\n    long long g = ext_gcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\ninline bool check_time() {\n    if (time_up) return true;\n    double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    if (elapsed > TIME_LIMIT) time_up = true;\n    return time_up;\n}\n\nvoid reset_state() {\n    fill(pattern_lo.begin(), pattern_lo.end(), 0ULL);\n    fill(pattern_hi.begin(), pattern_hi.end(), 0ULL);\n    lines_current.clear();\n    lines_current.reserve(K);\n    bits_used = 0;\n    piece_info_valid = false;\n}\n\nint score_from_counts(const CountArr &cnt) {\n    int sc = 0;\n    for (int d = 1; d <= 10; ++d) sc += min(demand[d], cnt[d]);\n    return sc;\n}\n\nint recompute_state(CountArr &out_cnt, bool store_info) {\n    out_cnt.fill(0);\n    for (int i = 0; i < N; ++i) {\n        tmp_keys[i] = {pattern_lo[i], pattern_hi[i]};\n        state_order[i] = i;\n    }\n    auto cmp = [&](int lhs, int rhs) {\n        const Key &a = tmp_keys[lhs];\n        const Key &b = tmp_keys[rhs];\n        if (a.hi != b.hi) return a.hi < b.hi;\n        return a.lo < b.lo;\n    };\n    sort(state_order.begin(), state_order.end(), cmp);\n\n    if (store_info) {\n        piece_segments.clear();\n        piece_segments.reserve(N);\n        piece_info_valid = true;\n        current_counts_state = out_cnt; // temporary zero, will overwrite later\n    } else {\n        piece_info_valid = false;\n    }\n\n    int idx = 0;\n    while (idx < N) {\n        int j = idx + 1;\n        while (j < N) {\n            const Key &ka = tmp_keys[state_order[idx]];\n            const Key &kb = tmp_keys[state_order[j]];\n            if (ka.lo != kb.lo || ka.hi != kb.hi) break;\n            ++j;\n        }\n        int len = j - idx;\n        if (len <= 10) out_cnt[len]++;\n        if (store_info) {\n            piece_segments.push_back({idx, len});\n            int pid = (int)piece_segments.size() - 1;\n            for (int t = idx; t < j; ++t) piece_id[state_order[t]] = pid;\n        }\n        idx = j;\n    }\n    if (store_info) current_counts_state = out_cnt;\n    return score_from_counts(out_cnt);\n}\n\nint evaluate_candidate(const Line &line) {\n    if (bits_used >= 128) return -1;\n    for (int i = 0; i < N; ++i) {\n        long long val = line.A * points[i].x + line.B * points[i].y - line.C;\n        if (val == 0) return -1;\n        unsigned long long bit = (val > 0) ? 1ULL : 0ULL;\n        unsigned long long lo = pattern_lo[i];\n        unsigned long long hi = pattern_hi[i];\n        if (bits_used < 64) lo |= bit << bits_used;\n        else hi |= bit << (bits_used - 64);\n        tmp_keys[i] = {lo, hi};\n        eval_order[i] = i;\n    }\n    auto cmp = [&](int lhs, int rhs) {\n        const Key &a = tmp_keys[lhs];\n        const Key &b = tmp_keys[rhs];\n        if (a.hi != b.hi) return a.hi < b.hi;\n        return a.lo < b.lo;\n    };\n    sort(eval_order.begin(), eval_order.end(), cmp);\n    CountArr cnt;\n    cnt.fill(0);\n    int idx = 0;\n    while (idx < N) {\n        int j = idx + 1;\n        while (j < N) {\n            const Key &ka = tmp_keys[eval_order[idx]];\n            const Key &kb = tmp_keys[eval_order[j]];\n            if (ka.lo != kb.lo || ka.hi != kb.hi) break;\n            ++j;\n        }\n        int len = j - idx;\n        if (len <= 10) cnt[len]++;\n        idx = j;\n    }\n    return score_from_counts(cnt);\n}\n\ninline long long rand_ll(long long l, long long r) {\n    unsigned long long range = (unsigned long long)(r - l + 1);\n    return l + (long long)(rng() % range);\n}\n\nbool sample_pair_line_indices(int i, int j, Line &line) {\n    if (i == j) return false;\n    long long a = points[j].x - points[i].x;\n    long long b = points[j].y - points[i].y;\n    long long g = std::gcd(absll(a), absll(b));\n    if (g == 0) return false;\n    a /= g; b /= g;\n    if (a < 0 || (a == 0 && b < 0)) { a = -a; b = -b; }\n    long long vi = a * points[i].x + b * points[i].y;\n    long long vj = a * points[j].x + b * points[j].y;\n    if (vi == vj) return false;\n    long long lo = min(vi, vj);\n    long long hi = max(vi, vj);\n    if (hi - lo < 2) return false;\n    long long c = rand_ll(lo + 1, hi - 1);\n    line = {a, b, c};\n    return true;\n}\n\nbool sample_direction_line(Line &line) {\n    static const pair<int,int> preset[4] = {{1,0},{0,1},{1,1},{1,-1}};\n    for (int iter = 0; iter < 12; ++iter) {\n        long long a = 0, b = 0;\n        int mode = rng() % 6;\n        if (mode < 4) {\n            a = preset[mode].first;\n            b = preset[mode].second;\n        } else {\n            do {\n                a = rand_ll(-DIR_LIMIT, DIR_LIMIT);\n                b = rand_ll(-DIR_LIMIT, DIR_LIMIT);\n            } while (a == 0 && b == 0);\n        }\n        long long g = std::gcd(absll(a), absll(b));\n        if (g == 0) continue;\n        a /= g; b /= g;\n        if (a < 0 || (a == 0 && b < 0)) { a = -a; b = -b; }\n        for (int i = 0; i < N; ++i) proj_values[i] = a * points[i].x + b * points[i].y;\n        vector<long long> sorted_vals = proj_values;\n        sort(sorted_vals.begin(), sorted_vals.end());\n        gap_indices.clear();\n        for (int i = 1; i < N; ++i) {\n            if (sorted_vals[i] - sorted_vals[i - 1] >= 2) gap_indices.push_back(i);\n        }\n        if (gap_indices.empty()) continue;\n        int pos = gap_indices[rng() % gap_indices.size()];\n        long long left = sorted_vals[pos - 1];\n        long long right = sorted_vals[pos];\n        long long c = rand_ll(left + 1, right - 1);\n        line = {a, b, c};\n        return true;\n    }\n    return false;\n}\n\nbool sample_pair_line(Line &line) {\n    if (N < 2) return false;\n    for (int tries = 0; tries < 40; ++tries) {\n        int i = rng() % N;\n        int j = rng() % N;\n        if (i == j) continue;\n        if (sample_pair_line_indices(i, j, line)) return true;\n    }\n    return false;\n}\n\nbool piece_direction_split(const PieceSegment &seg, Line &line) {\n    if (seg.len < 2) return false;\n    for (int dir_try = 0; dir_try < 6; ++dir_try) {\n        int idx1 = state_order[seg.start + rng() % seg.len];\n        int idx2 = state_order[seg.start + rng() % seg.len];\n        if (idx1 == idx2) continue;\n        long long a = points[idx2].x - points[idx1].x;\n        long long b = points[idx2].y - points[idx1].y;\n        long long g = std::gcd(absll(a), absll(b));\n        if (g == 0) continue;\n        a /= g; b /= g;\n        if (a < 0 || (a == 0 && b < 0)) { a = -a; b = -b; }\n        for (int i = 0; i < N; ++i) proj_values[i] = a * points[i].x + b * points[i].y;\n        piece_proj_buffer.clear();\n        piece_proj_buffer.reserve(seg.len);\n        for (int t = 0; t < seg.len; ++t) {\n            piece_proj_buffer.push_back(proj_values[state_order[seg.start + t]]);\n        }\n        sort(piece_proj_buffer.begin(), piece_proj_buffer.end());\n        proj_sorted_buffer.assign(proj_values.begin(), proj_values.end());\n        sort(proj_sorted_buffer.begin(), proj_sorted_buffer.end());\n        unique_values_buffer.clear();\n        unique_values_buffer.reserve(proj_sorted_buffer.size());\n        for (long long val : proj_sorted_buffer) {\n            if (unique_values_buffer.empty() || unique_values_buffer.back() != val)\n                unique_values_buffer.push_back(val);\n        }\n        targeted_gap_indices.clear();\n        for (int k = 0; k + 1 < (int)unique_values_buffer.size(); ++k) {\n            long long left = unique_values_buffer[k];\n            long long right = unique_values_buffer[k + 1];\n            if (right - left < 2) continue;\n            auto itRight = lower_bound(piece_proj_buffer.begin(), piece_proj_buffer.end(), right);\n            if (itRight == piece_proj_buffer.end()) continue;\n            auto itLeft = upper_bound(piece_proj_buffer.begin(), piece_proj_buffer.end(), left);\n            if (itLeft == piece_proj_buffer.begin()) continue;\n            targeted_gap_indices.push_back(k);\n        }\n        if (targeted_gap_indices.empty()) continue;\n        int chosen_idx = targeted_gap_indices[rng() % targeted_gap_indices.size()];\n        long long left = unique_values_buffer[chosen_idx];\n        long long right = unique_values_buffer[chosen_idx + 1];\n        long long c = rand_ll(left + 1, right - 1);\n        line = {a, b, c};\n        return true;\n    }\n    return false;\n}\n\nbool sample_piece_line(Line &line) {\n    if (!piece_info_valid || piece_segments.empty()) return false;\n    int desired_size = 10;\n    for (int d = 1; d <= 10; ++d) {\n        if (current_counts_state[d] < demand[d]) {\n            desired_size = d;\n            break;\n        }\n    }\n    for (int tries = 0; tries < 80; ++tries) {\n        int idx = rng() % N;\n        int pid = piece_id[idx];\n        const auto &seg = piece_segments[pid];\n        if (seg.len < 2) continue;\n        if (seg.len <= desired_size && (rng() % 4 != 0)) continue;\n        bool try_direction = (seg.len >= 4) && (rng() % 2 == 0);\n        if (try_direction) {\n            if (piece_direction_split(seg, line)) return true;\n        }\n        int other = state_order[seg.start + rng() % seg.len];\n        if (other == idx) continue;\n        if (sample_pair_line_indices(idx, other, line)) return true;\n    }\n    return false;\n}\n\nbool generate_candidate_line(Line &line) {\n    for (int attempt = 0; attempt < GENERATE_LINE_ATTEMPTS; ++attempt) {\n        if (check_time()) break;\n        int choice = rng() % 100;\n        bool ok = false;\n        if (piece_info_valid && choice < 55) ok = sample_piece_line(line);\n        if (!ok && choice < 80) ok = sample_pair_line(line);\n        if (!ok) ok = sample_direction_line(line);\n        if (ok) return true;\n    }\n    return false;\n}\n\nvoid apply_line(const Line &line) {\n    for (int i = 0; i < N; ++i) {\n        long long val = line.A * points[i].x + line.B * points[i].y - line.C;\n        if (val == 0) val = 1;\n        unsigned long long bit = (val > 0) ? 1ULL : 0ULL;\n        if (bits_used < 64) pattern_lo[i] |= bit << bits_used;\n        else pattern_hi[i] |= bit << (bits_used - 64);\n    }\n    lines_current.push_back(line);\n    ++bits_used;\n}\n\nint candidate_trials(int iter) {\n    if (iter < 10) return 45;\n    if (iter < 25) return 35;\n    if (iter < 50) return 28;\n    if (iter < 80) return 22;\n    return 18;\n}\n\nstruct AttemptResult {\n    int score;\n    vector<Line> lines;\n};\n\nAttemptResult run_attempt(const vector<Line> &base_lines) {\n    reset_state();\n    for (const auto &ln : base_lines) {\n        if ((int)lines_current.size() >= K) break;\n        apply_line(ln);\n    }\n    CountArr current_counts;\n    int current_score = recompute_state(current_counts, true);\n    int best_score_local = current_score;\n    vector<Line> best_lines_local = lines_current;\n\n    while ((int)lines_current.size() < K && !check_time()) {\n        int trials = candidate_trials((int)lines_current.size());\n        Line chosen{};\n        int chosen_score = INT_MIN;\n        bool found = false;\n        for (int t = 0; t < trials && !check_time(); ++t) {\n            Line cand;\n            if (!generate_candidate_line(cand)) continue;\n            int sc = evaluate_candidate(cand);\n            if (sc < 0) continue;\n            if (!found || sc > chosen_score) {\n                found = true;\n                chosen_score = sc;\n                chosen = cand;\n            }\n        }\n        if (!found) break;\n        apply_line(chosen);\n        current_score = recompute_state(current_counts, true);\n        if (current_score > best_score_local) {\n            best_score_local = current_score;\n            best_lines_local = lines_current;\n        }\n    }\n    return {best_score_local, best_lines_local};\n}\n\nbool line_to_points(const Line &line, array<long long,4> &out) {\n    long long A = line.A, B = line.B, C = line.C;\n    if (A == 0 && B == 0) return false;\n    if (B == 0) {\n        long long x = C / A;\n        long long y1 = -COORD_LIMIT + 1;\n        long long y2 = y1 + 1;\n        out = {{x, y1, x, y2}};\n        return true;\n    }\n    if (A == 0) {\n        long long y = C / B;\n        long long x1 = -COORD_LIMIT + 1;\n        long long x2 = x1 + 1;\n        out = {{x1, y, x2, y}};\n        return true;\n    }\n    long long x0, y0;\n    long long g = ext_gcd(A, B, x0, y0);\n    if (g == 0 || C % g != 0) return false;\n    long long mult = C / g;\n    x0 *= mult;\n    y0 *= mult;\n    auto range_for = [&](long long base, long long coeff) -> pair<long long,long long> {\n        const long long INF = (1LL << 60);\n        if (coeff == 0) {\n            if (absll(base) > COORD_LIMIT) return {1, 0};\n            return {-INF, INF};\n        }\n        long long low = -INF, high = INF;\n        if (coeff > 0) {\n            low = max(low, ceil_div(-COORD_LIMIT - base, coeff));\n            high = min(high, floor_div(COORD_LIMIT - base, coeff));\n        } else {\n            high = min(high, floor_div(-COORD_LIMIT - base, coeff));\n            low = max(low, ceil_div(COORD_LIMIT - base, coeff));\n        }\n        return {low, high};\n    };\n    auto rx = range_for(x0, B);\n    auto ry = range_for(y0, -A);\n    long long low = max(rx.first, ry.first);\n    long long high = min(rx.second, ry.second);\n    if (low > high) return false;\n    auto point_from = [&](long long k) -> pair<long long,long long> {\n        return {x0 + B * k, y0 - A * k};\n    };\n    long long k0 = min(max(0LL, low), high);\n    auto P = point_from(k0);\n    if (absll(P.first) > COORD_LIMIT || absll(P.second) > COORD_LIMIT) {\n        P = point_from(low);\n        k0 = low;\n    }\n    long long qk = (k0 < high) ? k0 + 1 : k0 - 1;\n    auto Q = point_from(qk);\n    if (absll(Q.first) > COORD_LIMIT || absll(Q.second) > COORD_LIMIT || (Q.first == P.first && Q.second == P.second)) {\n        bool found = false;\n        for (long long delta = 1; delta <= 200000 && !found; ++delta) {\n            if (k0 + delta <= high) {\n                auto cand = point_from(k0 + delta);\n                if (absll(cand.first) <= COORD_LIMIT && absll(cand.second) <= COORD_LIMIT && (cand.first != P.first || cand.second != P.second)) {\n                    Q = cand;\n                    found = true;\n                    break;\n                }\n            }\n            if (k0 - delta >= low) {\n                auto cand = point_from(k0 - delta);\n                if (absll(cand.first) <= COORD_LIMIT && absll(cand.second) <= COORD_LIMIT && (cand.first != P.first || cand.second != P.second)) {\n                    Q = cand;\n                    found = true;\n                    break;\n                }\n            }\n        }\n        if (!found) return false;\n    }\n    out = {{P.first, P.second, Q.first, Q.second}};\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K;\n    for (int d = 1; d <= 10; ++d) cin >> demand[d];\n    points.resize(N);\n    for (int i = 0; i < N; ++i) cin >> points[i].x >> points[i].y;\n\n    pattern_lo.assign(N, 0ULL);\n    pattern_hi.assign(N, 0ULL);\n    tmp_keys.resize(N);\n    proj_values.resize(N);\n    proj_sorted_buffer.reserve(N);\n    piece_proj_buffer.reserve(N);\n    unique_values_buffer.reserve(N);\n    targeted_gap_indices.reserve(N);\n    state_order.resize(N);\n    eval_order.resize(N);\n    piece_id.resize(N);\n    lines_current.reserve(K);\n    gap_indices.reserve(N);\n\n    current_counts_state.fill(0);\n    start_time = chrono::steady_clock::now();\n\n    int global_best_score = -1;\n    vector<Line> global_best_lines;\n    vector<Line> base_prefix;\n    base_prefix.reserve(K);\n\n    while (!check_time()) {\n        base_prefix.clear();\n        if (!global_best_lines.empty()) {\n            int mode = rng() % 5;\n            if (mode <= 2) {\n                int drop = rng() % (global_best_lines.size() + 1);\n                int keep = (int)global_best_lines.size() - drop;\n                keep = min(keep, K);\n                base_prefix.insert(base_prefix.end(), global_best_lines.begin(), global_best_lines.begin() + keep);\n            } else {\n                int keep_percent = 55 + (rng() % 36);\n                for (const auto &ln : global_best_lines) {\n                    if ((int)base_prefix.size() >= K) break;\n                    if ((int)(rng() % 100) < keep_percent) base_prefix.push_back(ln);\n                }\n            }\n            if ((int)base_prefix.size() >= K) base_prefix.resize(max(0, K - 1));\n        }\n\n        AttemptResult res = run_attempt(base_prefix);\n        if (res.score > global_best_score) {\n            global_best_score = res.score;\n            global_best_lines = res.lines;\n        }\n        if (check_time()) break;\n    }\n\n    vector<array<long long,4>> output;\n    output.reserve(global_best_lines.size());\n    for (const auto &ln : global_best_lines) {\n        array<long long,4> pts;\n        if (!line_to_points(ln, pts)) {\n            pts = {{-COORD_LIMIT + 1, -COORD_LIMIT + 1, -COORD_LIMIT + 2, -COORD_LIMIT + 1}};\n        }\n        output.push_back(pts);\n    }\n\n    cout << output.size() << '\\n';\n    for (auto &v : output) {\n        cout << v[0] << ' ' << v[1] << ' ' << v[2] << ' ' << v[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    enum Direction : int {\n        DIR_UP = 0, DIR_DOWN = 1, DIR_RIGHT = 2, DIR_LEFT = 3,\n        DIR_NE = 4, DIR_SW = 5, DIR_NW = 6, DIR_SE = 7\n    };\n    static int dirBit(int dir) { return 1 << dir; }\n\n    struct Candidate {\n        array<int, 8> pts{};\n    };\n    struct CandidateScore {\n        Candidate cand;\n        double score = 0.0;\n        double perim = 0.0;\n        int len = 0;\n    };\n    struct NeighborInfo {\n        bool exists = false;\n        bool edgeFree = false;\n        int x = 0;\n        int y = 0;\n    };\n    struct PotentialCounts {\n        double axis = 0.0;\n        double diag = 0.0;\n    };\n    struct DirNeighbor {\n        int x = 0;\n        int y = 0;\n        int dir = -1;\n    };\n    struct RunResult {\n        long long totalWeight = 0;\n        vector<array<int, 8>> ops;\n    };\n    struct Param {\n        double lambdaStart;\n        double lambdaEnd;\n        double progressPower;\n        double noiseAmp;\n        double timeBudget;\n        double alphaAxis;\n        double alphaDiag;\n        int keepLimit;\n        double pickDecay;\n        double frontierCoeff;\n        double frontierDecay;\n    };\n\n    static bool betterCand(const CandidateScore &a, const CandidateScore &b) {\n        if (a.score != b.score) return a.score > b.score;\n        if (a.perim != b.perim) return a.perim < b.perim;\n        if (a.len != b.len) return a.len < b.len;\n        return a.cand.pts < b.cand.pts;\n    }\n    static bool worseCand(const CandidateScore &a, const CandidateScore &b) {\n        return betterCand(b, a);\n    }\n\n    static constexpr double ABS_TIME_LIMIT = 4.95;\n    static constexpr double SAFETY_MARGIN = 0.05;\n\n    int N = 0, M = 0;\n    vector<pair<int, int>> initialDots;\n\n    vector<vector<int>> rowDots, colDots;\n    vector<vector<int>> diagPosDots, diagNegDots;\n    vector<vector<char>> hasDot;\n    vector<vector<char>> usedH, usedV, usedDiagPos, usedDiagNeg;\n    vector<vector<int>> weight;\n    vector<array<int, 8>> currentOperations;\n\n    int center = 0;\n    int diagOffset = 0;\n    int totalCells = 0;\n\n    int dotCount = 0;\n    long long totalWeight = 0;\n    int baseInitialCount = 0;\n    int extraCapacity = 1;\n\n    int bMinX = 0, bMaxX = 0, bMinY = 0, bMaxY = 0;\n\n    chrono::steady_clock::time_point startTime;\n    double currentTimeLimit = ABS_TIME_LIMIT;\n\n    uint64_t baseSeed = 0;\n    mt19937 rng;\n\n    double elapsed() const {\n        using namespace chrono;\n        return duration<double>(steady_clock::now() - startTime).count();\n    }\n\n    pair<int, int> uvToXY(int u, int v) const {\n        int x = (u + v) / 2;\n        int y = (u - v) / 2;\n        return {x, y};\n    }\n\n    void insertSorted(vector<int> &vec, int val) {\n        vec.insert(lower_bound(vec.begin(), vec.end(), val), val);\n    }\n\n    bool addDot(int x, int y) {\n        if (hasDot[x][y]) return false;\n        hasDot[x][y] = 1;\n        insertSorted(rowDots[y], x);\n        insertSorted(colDots[x], y);\n        insertSorted(diagPosDots[x - y + diagOffset], x + y);\n        insertSorted(diagNegDots[x + y], x - y);\n        if (bMinX > bMaxX) {\n            bMinX = bMaxX = x;\n            bMinY = bMaxY = y;\n        } else {\n            bMinX = min(bMinX, x);\n            bMaxX = max(bMaxX, x);\n            bMinY = min(bMinY, y);\n            bMaxY = max(bMaxY, y);\n        }\n        return true;\n    }\n\n    void resetState() {\n        for (auto &row : rowDots) row.clear();\n        for (auto &col : colDots) col.clear();\n        for (auto &diag : diagPosDots) diag.clear();\n        for (auto &diag : diagNegDots) diag.clear();\n        for (auto &row : hasDot) fill(row.begin(), row.end(), 0);\n        for (auto &row : usedH) fill(row.begin(), row.end(), 0);\n        for (auto &row : usedV) fill(row.begin(), row.end(), 0);\n        for (auto &row : usedDiagPos) fill(row.begin(), row.end(), 0);\n        for (auto &row : usedDiagNeg) fill(row.begin(), row.end(), 0);\n        currentOperations.clear();\n        currentOperations.reserve(totalCells);\n\n        dotCount = 0;\n        totalWeight = 0;\n        bMinX = bMinY = N;\n        bMaxX = bMaxY = -1;\n\n        for (auto [x, y] : initialDots) {\n            if (addDot(x, y)) {\n                ++dotCount;\n                totalWeight += weight[x][y];\n            }\n        }\n        if (bMinX > bMaxX) {\n            bMinX = bMinY = 0;\n            bMaxX = bMaxY = N - 1;\n        }\n        baseInitialCount = dotCount;\n        extraCapacity = max(1, totalCells - baseInitialCount);\n    }\n\n    bool horizontalSegmentUnused(int y, int x1, int x2) const {\n        if (x1 == x2) return false;\n        int l = min(x1, x2);\n        int r = max(x1, x2);\n        for (int x = l; x < r; ++x) {\n            if (usedH[y][x]) return false;\n        }\n        return true;\n    }\n\n    bool verticalSegmentUnused(int x, int y1, int y2) const {\n        if (y1 == y2) return false;\n        int l = min(y1, y2);\n        int r = max(y1, y2);\n        for (int y = l; y < r; ++y) {\n            if (usedV[x][y]) return false;\n        }\n        return true;\n    }\n\n    bool diagPosSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return false;\n        if (x2 < x1) return diagPosSegmentsUnused(x2, y2, x1, y1);\n        if ((x2 - x1) != (y2 - y1)) return false;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            if (usedDiagPos[x1 + i][y1 + i]) return false;\n        }\n        return true;\n    }\n\n    bool diagNegSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return false;\n        if (x2 < x1) return diagNegSegmentsUnused(x2, y2, x1, y1);\n        if ((x2 - x1) != -(y2 - y1)) return false;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            int y = y1 - i;\n            if (y <= 0 || y > N - 1) return false;\n            if (usedDiagNeg[x1 + i][y - 1]) return false;\n        }\n        return true;\n    }\n\n    void markHorizontal(int y, int x1, int x2) {\n        if (x1 == x2) return;\n        int l = min(x1, x2);\n        int r = max(x1, x2);\n        for (int x = l; x < r; ++x) usedH[y][x] = 1;\n    }\n\n    void markVertical(int x, int y1, int y2) {\n        if (y1 == y2) return;\n        int l = min(y1, y2);\n        int r = max(y1, y2);\n        for (int y = l; y < r; ++y) usedV[x][y] = 1;\n    }\n\n    void markDiagPos(int x1, int y1, int x2, int y2) {\n        if (x2 < x1) {\n            markDiagPos(x2, y2, x1, y1);\n            return;\n        }\n        if ((x2 - x1) != (y2 - y1)) return;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) usedDiagPos[x1 + i][y1 + i] = 1;\n    }\n\n    void markDiagNeg(int x1, int y1, int x2, int y2) {\n        if (x2 < x1) {\n            markDiagNeg(x2, y2, x1, y1);\n            return;\n               }\n        if ((x2 - x1) != -(y2 - y1)) return;\n        int len = x2 - x1;\n        for (int i = 0; i < len; ++i) {\n            int y = y1 - i;\n            if (y > 0) usedDiagNeg[x1 + i][y - 1] = 1;\n        }\n    }\n\n    bool edgeSegmentsUnused(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return verticalSegmentUnused(x1, y1, y2);\n        if (y1 == y2) return horizontalSegmentUnused(y1, x1, x2);\n        if (x2 - x1 == y2 - y1) return diagPosSegmentsUnused(x1, y1, x2, y2);\n        if (x2 - x1 == -(y2 - y1)) return diagNegSegmentsUnused(x1, y1, x2, y2);\n        return false;\n    }\n\n    void markEdge(int x1, int y1, int x2, int y2) {\n        if (x1 == x2) markVertical(x1, y1, y2);\n        else if (y1 == y2) markHorizontal(y1, x1, x2);\n        else if (x2 - x1 == y2 - y1) markDiagPos(x1, y1, x2, y2);\n        else if (x2 - x1 == -(y2 - y1)) markDiagNeg(x1, y1, x2, y2);\n    }\n\n    bool edgeInteriorClear(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2 && y1 == y2) return false;\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n        int steps = max(abs(dx), abs(dy));\n        if (steps <= 1) return true;\n        int sx = (dx > 0) - (dx < 0);\n        int sy = (dy > 0) - (dy < 0);\n        int cx = x1 + sx;\n        int cy = y1 + sy;\n        for (int i = 1; i < steps; ++i) {\n            if (cx < 0 || cx >= N || cy < 0 || cy >= N) return false;\n            if (hasDot[cx][cy]) return false;\n            cx += sx;\n            cy += sy;\n        }\n        return true;\n    }\n\n    int directionFromTo(int x1, int y1, int x2, int y2) const {\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n        if (dx == 0 && dy == 0) return -1;\n        if (dx == 0) return dy > 0 ? DIR_UP : DIR_DOWN;\n        if (dy == 0) return dx > 0 ? DIR_RIGHT : DIR_LEFT;\n        if (dx == dy) return dx > 0 ? DIR_NE : DIR_SW;\n        if (dx == -dy) return dx > 0 ? DIR_SE : DIR_NW;\n        return -1;\n    }\n\n    PotentialCounts evaluatePotential(int dx, int dy, int blockedMask) const {\n        PotentialCounts result;\n        array<DirNeighbor, 2> verticals{};\n        array<DirNeighbor, 2> horizontals{};\n        array<DirNeighbor, 2> diagPlus{};\n        array<DirNeighbor, 2> diagMinus{};\n        int vCnt = 0, hCnt = 0, dpCnt = 0, dnCnt = 0;\n\n        auto tryAddVertical = [&](int ny, int dir) {\n            if (ny < 0 || ny >= N) return;\n            if (dir < 0) return;\n            if (blockedMask & dirBit(dir)) return;\n            if (!edgeSegmentsUnused(dx, dy, dx, ny)) return;\n            if (!edgeInteriorClear(dx, dy, dx, ny)) return;\n            if (vCnt < 2) verticals[vCnt++] = {dx, ny, dir};\n        };\n        auto tryAddHorizontal = [&](int nx, int dir) {\n            if (nx < 0 || nx >= N) return;\n            if (dir < 0) return;\n            if (blockedMask & dirBit(dir)) return;\n            if (!edgeSegmentsUnused(dx, dy, nx, dy)) return;\n            if (!edgeInteriorClear(dx, dy, nx, dy)) return;\n            if (hCnt < 2) horizontals[hCnt++] = {nx, dy, dir};\n        };\n        auto tryAddDiagPlus = [&](int nx, int ny, int dir) {\n            if (nx < 0 || nx >= N || ny < 0 || ny >= N) return;\n            if (dir < 0) return;\n            if (blockedMask & dirBit(dir)) return;\n            if (!edgeSegmentsUnused(dx, dy, nx, ny)) return;\n            if (!edgeInteriorClear(dx, dy, nx, ny)) return;\n            if (dpCnt < 2) diagPlus[dpCnt++] = {nx, ny, dir};\n        };\n        auto tryAddDiagMinus = [&](int nx, int ny, int dir) {\n            if (nx < 0 || nx >= N || ny < 0 || ny >= N) return;\n            if (dir < 0) return;\n            if (blockedMask & dirBit(dir)) return;\n            if (!edgeSegmentsUnused(dx, dy, nx, ny)) return;\n            if (!edgeInteriorClear(dx, dy, nx, ny)) return;\n            if (dnCnt < 2) diagMinus[dnCnt++] = {nx, ny, dir};\n        };\n\n        const auto &col = colDots[dx];\n        auto itUp = upper_bound(col.begin(), col.end(), dy);\n        if (itUp != col.end()) tryAddVertical(*itUp, DIR_UP);\n        auto itMid = lower_bound(col.begin(), col.end(), dy);\n        if (itMid != col.begin()) {\n            --itMid;\n            tryAddVertical(*itMid, DIR_DOWN);\n        }\n\n        const auto &row = rowDots[dy];\n        auto itRight = upper_bound(row.begin(), row.end(), dx);\n        if (itRight != row.end()) tryAddHorizontal(*itRight, DIR_RIGHT);\n        auto itRowMid = lower_bound(row.begin(), row.end(), dx);\n        if (itRowMid != row.begin()) {\n            --itRowMid;\n            tryAddHorizontal(*itRowMid, DIR_LEFT);\n        }\n\n        const auto &diagP = diagPosDots[dx - dy + diagOffset];\n        auto itDiagPHigh = upper_bound(diagP.begin(), diagP.end(), dx + dy);\n        if (itDiagPHigh != diagP.end()) {\n            auto [nx, ny] = uvToXY(*itDiagPHigh, dx - dy);\n            tryAddDiagPlus(nx, ny, DIR_NE);\n        }\n        auto itDiagPLow = lower_bound(diagP.begin(), diagP.end(), dx + dy);\n        if (itDiagPLow != diagP.begin()) {\n            --itDiagPLow;\n            auto [nx, ny] = uvToXY(*itDiagPLow, dx - dy);\n            tryAddDiagPlus(nx, ny, DIR_SW);\n        }\n\n        const auto &diagN = diagNegDots[dx + dy];\n        auto itDiagNHigh = upper_bound(diagN.begin(), diagN.end(), dx - dy);\n        if (itDiagNHigh != diagN.end()) {\n            auto [nx, ny] = uvToXY(dx + dy, *itDiagNHigh);\n            tryAddDiagMinus(nx, ny, DIR_SE);\n        }\n        auto itDiagNLow = lower_bound(diagN.begin(), diagN.end(), dx - dy);\n        if (itDiagNLow != diagN.begin()) {\n            --itDiagNLow;\n            auto [nx, ny] = uvToXY(dx + dy, *itDiagNLow);\n            tryAddDiagMinus(nx, ny, DIR_NW);\n        }\n\n        for (int i = 0; i < vCnt; ++i) {\n            for (int j = 0; j < hCnt; ++j) {\n                int nx = horizontals[j].x;\n                int ny = verticals[i].y;\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                if (hasDot[nx][ny]) continue;\n                if (!edgeInteriorClear(verticals[i].x, verticals[i].y, nx, ny)) continue;\n                if (!edgeInteriorClear(horizontals[j].x, horizontals[j].y, nx, ny)) continue;\n                if (!edgeSegmentsUnused(verticals[i].x, verticals[i].y, nx, ny)) continue;\n                if (!edgeSegmentsUnused(horizontals[j].x, horizontals[j].y, nx, ny)) continue;\n                result.axis += 1.0;\n            }\n        }\n\n        for (int i = 0; i < dpCnt; ++i) {\n            for (int j = 0; j < dnCnt; ++j) {\n                int nx = diagPlus[i].x + (diagMinus[j].x - dx);\n                int ny = diagPlus[i].y + (diagMinus[j].y - dy);\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                if (hasDot[nx][ny]) continue;\n                if (!edgeInteriorClear(diagPlus[i].x, diagPlus[i].y, nx, ny)) continue;\n                if (!edgeInteriorClear(diagMinus[j].x, diagMinus[j].y, nx, ny)) continue;\n                if (!edgeSegmentsUnused(diagPlus[i].x, diagPlus[i].y, nx, ny)) continue;\n                if (!edgeSegmentsUnused(diagMinus[j].x, diagMinus[j].y, nx, ny)) continue;\n                result.diag += 1.0;\n            }\n        }\n\n        return result;\n    }\n\n    double frontierGain(int x, int y) const {\n        if (bMinX > bMaxX) return 0.0;\n        double gain = 0.0;\n        if (x < bMinX) gain += double(bMinX - x);\n        else if (x > bMaxX) gain += double(x - bMaxX);\n        if (y < bMinY) gain += double(bMinY - y);\n        else if (y > bMaxY) gain += double(y - bMaxY);\n        return gain;\n    }\n\n    bool findCandidate(double lambda, double noiseAmp,\n                       double alphaAxis, double alphaDiag,\n                       double frontierCoef,\n                       int keepLimit, double pickDecay,\n                       Candidate &chosen, bool &timeoutFlag) {\n        keepLimit = max(1, keepLimit);\n        vector<CandidateScore> pool;\n        pool.reserve(keepLimit + 4);\n\n        timeoutFlag = false;\n        bool stop = false;\n        int processed = 0;\n\n        uniform_real_distribution<double> noiseDist(-noiseAmp, noiseAmp);\n        auto noise = [&]() -> double {\n            return (noiseAmp > 0.0) ? noiseDist(rng) : 0.0;\n        };\n\n        auto pushCandidate = [&](const CandidateScore &cs) {\n            if ((int)pool.size() < keepLimit) {\n                pool.push_back(cs);\n            } else {\n                int worst = 0;\n                for (int i = 1; i < (int)pool.size(); ++i) {\n                    if (worseCand(pool[i], pool[worst])) worst = i;\n                }\n                if (!worseCand(cs, pool[worst])) {\n                    pool[worst] = cs;\n                }\n            }\n        };\n\n        for (int y = 0; y < N && !stop; ++y) {\n            const auto &row = rowDots[y];\n            int rowSize = (int)row.size();\n            if (rowSize == 0) continue;\n            for (int idx = 0; idx < rowSize && !stop; ++idx) {\n                if ((processed & 63) == 0 && elapsed() > currentTimeLimit) {\n                    timeoutFlag = true;\n                    stop = true;\n                    break;\n                }\n                ++processed;\n                int ax = row[idx];\n                int ay = y;\n\n                NeighborInfo left, right, up, down, ne, sw, nw, se;\n\n                if (idx > 0) {\n                    left.exists = true;\n                    left.x = row[idx - 1];\n                    left.y = ay;\n                    left.edgeFree = edgeSegmentsUnused(ax, ay, left.x, left.y);\n                }\n                if (idx + 1 < rowSize) {\n                    right.exists = true;\n                    right.x = row[idx + 1];\n                    right.y = ay;\n                    right.edgeFree = edgeSegmentsUnused(ax, ay, right.x, right.y);\n                }\n\n                const auto &col = colDots[ax];\n                auto itCol = lower_bound(col.begin(), col.end(), ay);\n                if (itCol == col.end() || *itCol != ay) continue;\n                int posCol = int(itCol - col.begin());\n                if (posCol > 0) {\n                    down.exists = true;\n                    down.x = ax;\n                    down.y = col[posCol - 1];\n                    down.edgeFree = edgeSegmentsUnused(ax, ay, down.x, down.y);\n                }\n                if (posCol + 1 < (int)col.size()) {\n                    up.exists = true;\n                    up.x = ax;\n                    up.y = col[posCol + 1];\n                    up.edgeFree = edgeSegmentsUnused(ax, ay, up.x, up.y);\n                }\n\n                int uVal = ax + ay;\n                int vVal = ax - ay;\n\n                auto &diagV = diagPosDots[vVal + diagOffset];\n                auto itV = lower_bound(diagV.begin(), diagV.end(), uVal);\n                if (itV != diagV.end() && *itV == uVal) {\n                    int posV = int(itV - diagV.begin());\n                    if (posV > 0) {\n                        int uPrev = diagV[posV - 1];\n                        auto [nx, ny] = uvToXY(uPrev, vVal);\n                        sw.exists = true;\n                        sw.x = nx;\n                        sw.y = ny;\n                        sw.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                    if (posV + 1 < (int)diagV.size()) {\n                        int uNext = diagV[posV + 1];\n                        auto [nx, ny] = uvToXY(uNext, vVal);\n                        ne.exists = true;\n                        ne.x = nx;\n                        ne.y = ny;\n                        ne.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                }\n\n                auto &diagU = diagNegDots[uVal];\n                auto itU = lower_bound(diagU.begin(), diagU.end(), vVal);\n                if (itU != diagU.end() && *itU == vVal) {\n                    int posU = int(itU - diagU.begin());\n                    if (posU > 0) {\n                        int vPrev = diagU[posU - 1];\n                        auto [nx, ny] = uvToXY(uVal, vPrev);\n                        nw.exists = true;\n                        nw.x = nx;\n                        nw.y = ny;\n                        nw.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                    if (posU + 1 < (int)diagU.size()) {\n                        int vNext = diagU[posU + 1];\n                        auto [nx, ny] = uvToXY(uVal, vNext);\n                        se.exists = true;\n                        se.x = nx;\n                        se.y = ny;\n                        se.edgeFree = edgeSegmentsUnused(ax, ay, nx, ny);\n                    }\n                }\n\n                auto considerAxis = [&](const NeighborInfo &vert, const NeighborInfo &horiz) {\n                    if (!vert.exists || !horiz.exists) return;\n                    if (!vert.edgeFree || !horiz.edgeFree) return;\n                    int dx = horiz.x;\n                    int dy = vert.y;\n                    if (dx < 0 || dx >= N || dy < 0 || dy >= N) return;\n                    if (hasDot[dx][dy]) return;\n                    if (!edgeInteriorClear(vert.x, vert.y, dx, dy)) return;\n                    if (!edgeInteriorClear(horiz.x, horiz.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(vert.x, vert.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(horiz.x, horiz.y, dx, dy)) return;\n                    int width = abs(dx - ax);\n                    int height = abs(dy - ay);\n                    if (width <= 0 || height <= 0) return;\n                    double perim = 2.0 * (width + height);\n                    int len = width + height;\n                    int blockedMask = 0;\n                    int dir1 = directionFromTo(dx, dy, vert.x, vert.y);\n                    int dir2 = directionFromTo(dx, dy, horiz.x, horiz.y);\n                    if (dir1 >= 0) blockedMask |= dirBit(dir1);\n                    if (dir2 >= 0) blockedMask |= dirBit(dir2);\n                    PotentialCounts pot = evaluatePotential(dx, dy, blockedMask);\n                    double frontier = frontierCoef > 0.0 ? frontierCoef * frontierGain(dx, dy) : 0.0;\n                    double score = (double)weight[dx][dy]\n                                   + alphaAxis * pot.axis\n                                   + alphaDiag * pot.diag\n                                   + frontier\n                                   - lambda * perim + noise();\n                    Candidate cand{{dx, dy,\n                                    vert.x, vert.y,\n                                    ax, ay,\n                                    horiz.x, horiz.y}};\n                    pushCandidate({cand, score, perim, len});\n                };\n\n                auto considerDiag = [&](const NeighborInfo &diagP, const NeighborInfo &diagN) {\n                    if (!diagP.exists || !diagN.exists) return;\n                    if (!diagP.edgeFree || !diagN.edgeFree) return;\n                    int dx = diagP.x + (diagN.x - ax);\n                    int dy = diagP.y + (diagN.y - ay);\n                    if (dx < 0 || dx >= N || dy < 0 || dy >= N) return;\n                    if (hasDot[dx][dy]) return;\n                    if (!edgeInteriorClear(diagP.x, diagP.y, dx, dy)) return;\n                    if (!edgeInteriorClear(diagN.x, diagN.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(diagP.x, diagP.y, dx, dy)) return;\n                    if (!edgeSegmentsUnused(diagN.x, diagN.y, dx, dy)) return;\n                    int len1 = abs(diagP.x - ax);\n                    int len2 = abs(diagN.x - ax);\n                    if (len1 <= 0 || len2 <= 0) return;\n                    double perim = 2.0 * (len1 + len2);\n                    int len = len1 + len2;\n                    int blockedMask = 0;\n                    int dir1 = directionFromTo(dx, dy, diagP.x, diagP.y);\n                    int dir2 = directionFromTo(dx, dy, diagN.x, diagN.y);\n                    if (dir1 >= 0) blockedMask |= dirBit(dir1);\n                    if (dir2 >= 0) blockedMask |= dirBit(dir2);\n                    PotentialCounts pot = evaluatePotential(dx, dy, blockedMask);\n                    double frontier = frontierCoef > 0.0 ? frontierCoef * frontierGain(dx, dy) : 0.0;\n                    double score = (double)weight[dx][dy]\n                                   + alphaAxis * pot.axis\n                                   + alphaDiag * pot.diag\n                                   + frontier\n                                   - lambda * perim + noise();\n                    Candidate cand{{dx, dy,\n                                    diagP.x, diagP.y,\n                                    ax, ay,\n                                    diagN.x, diagN.y}};\n                    pushCandidate({cand, score, perim, len});\n                };\n\n                considerAxis(up, right);\n                considerAxis(up, left);\n                considerAxis(down, right);\n                considerAxis(down, left);\n\n                considerDiag(ne, nw);\n                considerDiag(ne, se);\n                considerDiag(sw, nw);\n                considerDiag(sw, se);\n            }\n        }\n\n        if (pool.empty()) return false;\n        sort(pool.begin(), pool.end(), betterCand);\n\n        double decay = max(0.0, min(1.0, pickDecay));\n        int size = (int)pool.size();\n        int chosenIdx = 0;\n        if (size > 1) {\n            if (decay <= 1e-6) {\n                chosenIdx = 0;\n            } else if (decay >= 0.999999) {\n                chosenIdx = rng() % size;\n            } else {\n                vector<double> prefix(size);\n                double weightAccum = 0.0;\n                double w = 1.0;\n                for (int i = 0; i < size; ++i) {\n                    if (i == 0) w = 1.0;\n                    else w *= decay;\n                    weightAccum += w;\n                    prefix[i] = weightAccum;\n                    if (w < 1e-18) {\n                        for (int j = i + 1; j < size; ++j) prefix[j] = weightAccum;\n                        break;\n                    }\n                }\n                uniform_real_distribution<double> dist(0.0, weightAccum);\n                double r = dist(rng);\n                chosenIdx = lower_bound(prefix.begin(), prefix.end(), r) - prefix.begin();\n                if (chosenIdx >= size) chosenIdx = size - 1;\n            }\n        }\n        chosen = pool[chosenIdx].cand;\n        return true;\n    }\n\n    void applyCandidate(const Candidate &cand) {\n        const auto &pts = cand.pts;\n        for (int i = 0; i < 4; ++i) {\n            int j = (i + 1) & 3;\n            markEdge(pts[2 * i], pts[2 * i + 1], pts[2 * j], pts[2 * j + 1]);\n        }\n        int dx = pts[0], dy = pts[1];\n        if (addDot(dx, dy)) {\n            ++dotCount;\n            totalWeight += weight[dx][dy];\n        }\n        currentOperations.push_back(pts);\n    }\n\n    RunResult runOne(const Param &param, double budget, uint64_t seedShift) {\n        resetState();\n        rng.seed(baseSeed + seedShift * 0x9e3779b97f4a7c15ULL + 0x7f4a7c15ULL);\n\n        double now = elapsed();\n        currentTimeLimit = min(ABS_TIME_LIMIT, now + max(0.0, budget));\n\n        while (true) {\n            double cur = elapsed();\n            if (cur > currentTimeLimit) break;\n            int gained = dotCount - baseInitialCount;\n            if (gained < 0) gained = 0;\n            double progress = (double)gained / (double)extraCapacity;\n            progress = min(1.0, max(0.0, progress));\n            double factor = (param.progressPower == 1.0)\n                                ? progress\n                                : pow(progress, param.progressPower);\n            double lambda = param.lambdaStart +\n                            (param.lambdaEnd - param.lambdaStart) * factor;\n            double noiseScale = max(0.0, 1.0 - 0.75 * progress);\n            double noiseAmp = param.noiseAmp * noiseScale;\n            double axisCoef = param.alphaAxis * (1.0 - 0.35 * progress);\n            double diagCoef = param.alphaDiag * (1.0 - 0.25 * progress);\n            axisCoef = max(axisCoef, param.alphaAxis * 0.3);\n            diagCoef = max(diagCoef, param.alphaDiag * 0.3);\n            double frontierCoef = param.frontierCoeff * max(0.0, 1.0 - param.frontierDecay * progress);\n            frontierCoef = max(frontierCoef, param.frontierCoeff * 0.2);\n\n            Candidate cand;\n            bool timeout = false;\n            if (!findCandidate(lambda, noiseAmp, axisCoef, diagCoef, frontierCoef,\n                               param.keepLimit, param.pickDecay,\n                               cand, timeout)) break;\n            applyCandidate(cand);\n            if (timeout) break;\n        }\n\n        RunResult res;\n        res.totalWeight = totalWeight;\n        res.ops = currentOperations;\n        return res;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M)) return;\n        initialDots.resize(M);\n        for (int i = 0; i < M; ++i) cin >> initialDots[i].first >> initialDots[i].second;\n\n        center = (N - 1) / 2;\n        diagOffset = N - 1;\n        totalCells = N * N;\n\n        weight.assign(N, vector<int>(N, 0));\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                int dx = x - center;\n                int dy = y - center;\n                weight[x][y] = dx * dx + dy * dy + 1;\n            }\n        }\n\n        rowDots.assign(N, {});\n        colDots.assign(N, {});\n        diagPosDots.assign(2 * N, {});\n        diagNegDots.assign(2 * N, {});\n        hasDot.assign(N, vector<char>(N, 0));\n        int seg = max(1, N - 1);\n        usedH.assign(N, vector<char>(seg, 0));\n        usedV.assign(N, vector<char>(seg, 0));\n        usedDiagPos.assign(seg, vector<char>(seg, 0));\n        usedDiagNeg.assign(seg, vector<char>(seg, 0));\n        currentOperations.reserve(totalCells);\n\n        baseSeed = 1469598103934665603ULL;\n        baseSeed ^= (uint64_t)(N + 0x9e3779b97f4a7c15ULL + (baseSeed << 6) + (baseSeed >> 2));\n        baseSeed ^= (uint64_t)(M + 0x9e3779b97f4a7c15ULL + (baseSeed << 6) + (baseSeed >> 2));\n        for (auto [x, y] : initialDots) {\n            uint64_t v = (uint64_t)(x + 1) * 1000003ULL + (uint64_t)(y + 1) * 998244353ULL;\n            baseSeed ^= v + 0x9e3779b97f4a7c15ULL + (baseSeed << 6) + (baseSeed >> 2);\n        }\n\n        startTime = chrono::steady_clock::now();\n\n        vector<Param> params = {\n            {52.0,  -8.0, 0.60, 0.90, 0.90,  80.0, 65.0, 52, 0.45, 48.0, 0.80},\n            {34.0, -36.0, 1.08, 1.70, 0.85,  62.0, 78.0, 60, 0.58, 55.0, 1.10},\n            {82.0,  12.0, 0.42, 0.45, 1.00, 110.0, 90.0, 42, 0.32, 38.0, 0.60},\n            {70.0, -22.0, 0.95, 0.38, 0.80,  68.0, 52.0, 64, 0.28, 60.0, 0.90},\n            {46.0, -24.0, 1.25, 2.10, 0.70,  58.0, 58.0, 38, 0.78, 45.0, 1.25},\n        };\n\n        vector<array<int, 8>> bestOps;\n        long long bestWeight = -1;\n        bool ran = false;\n\n        for (int idx = 0; idx < (int)params.size(); ++idx) {\n            double now = elapsed();\n            double timeLeft = ABS_TIME_LIMIT - now;\n            if (timeLeft <= SAFETY_MARGIN) break;\n            double available = max(0.0, timeLeft - SAFETY_MARGIN);\n            double budget = min(params[idx].timeBudget, available);\n            if (budget <= 0.02) break;\n            RunResult res = runOne(params[idx], budget, idx + 1);\n            ran = true;\n            if (res.totalWeight > bestWeight) {\n                bestWeight = res.totalWeight;\n                bestOps = move(res.ops);\n            }\n        }\n\n        if (!ran) {\n            double now = elapsed();\n            double left = max(0.02, ABS_TIME_LIMIT - now - 0.01);\n            RunResult res = runOne(params.front(), left, params.size() + 5);\n            bestOps = move(res.ops);\n        }\n\n        cout << bestOps.size() << '\\n';\n        for (auto &op : bestOps) {\n            for (int i = 0; i < 8; ++i) {\n                if (i) cout << ' ';\n                cout << op[i];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct MinCostFlow {\n    struct Edge { int to, rev, cap, cost; };\n    int N;\n    vector<vector<Edge>> graph;\n    MinCostFlow(int n = 0) : N(n), graph(n) {}\n    void add_edge(int fr, int to, int cap, int cost) {\n        Edge f{to, (int)graph[to].size(), cap, cost};\n        Edge b{fr, (int)graph[fr].size(), 0, -cost};\n        graph[fr].push_back(f);\n        graph[to].push_back(b);\n    }\n    pair<int,long long> min_cost_flow(int s, int t, int maxf) {\n        const long long INF = (1LL<<60);\n        vector<long long> potential(N,0), dist(N);\n        vector<int> prevv(N), preve(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            priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n            pq.emplace(0LL,s);\n            while(!pq.empty()){\n                auto [d,v]=pq.top(); pq.pop();\n                if(dist[v]<d) continue;\n                for(int i=0;i<(int)graph[v].size();++i){\n                    const Edge &e=graph[v][i];\n                    if(e.cap<=0) continue;\n                    long long nd=dist[v]+e.cost+potential[v]-potential[e.to];\n                    if(nd<dist[e.to]){\n                        dist[e.to]=nd;\n                        prevv[e.to]=v;\n                        preve[e.to]=i;\n                        pq.emplace(nd,e.to);\n                    }\n                }\n            }\n            if(dist[t]==INF) break;\n            for(int v=0;v<N;++v) if(dist[v]<INF) potential[v]+=dist[v];\n            int d=maxf-flow;\n            for(int v=t;v!=s;v=prevv[v]) d=min(d,graph[prevv[v]][preve[v]].cap);\n            flow+=d;\n            cost+=1LL*d*potential[t];\n            for(int v=t;v!=s;v=prevv[v]){\n                Edge &e=graph[prevv[v]][preve[v]];\n                e.cap-=d;\n                graph[v][e.rev].cap+=d;\n            }\n        }\n        return {flow,cost};\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 10;\n    using Grid = array<array<uint8_t,N>,N>;\n    using ZoneGrid = array<array<int8_t,N>,N>;\n    static constexpr char DIRS[4] = {'F','B','L','R'};\n    static constexpr double ZONE_ALPHA = 0.35;\n    static constexpr double W_COMPONENT = 1.0;\n    static constexpr double W_ADJ_SAME = 18.0;\n    static constexpr double W_ADJ_DIFF = 13.0;\n    static constexpr double W_ZONE = 60.0;\n    static constexpr double W_LARGEST = 12.0;\n    static constexpr double W_COMP_COUNT = 20.0;\n    static constexpr double W_ZONE_HIT = 6.0;\n    static constexpr double W_ZONE_DIST = 1.0;\n    static constexpr double W_ZONE_EMPTY = 3.0;\n    static constexpr double LOOKAHEAD_WEIGHT = 0.35;\n    static constexpr double REVERSE_PENALTY = 0.35;\n    static constexpr int FULL_LOOKAHEAD_THRESHOLD1 = 36;\n    static constexpr int FULL_LOOKAHEAD_THRESHOLD2 = 18;\n    static constexpr int OCC_PENALTY = 6;\n\n    vector<int> flavors = vector<int>(100);\n    array<int,3> totalCounts{};\n    Grid board{};\n    int placed = 0;\n    mt19937 rng;\n    ZoneGrid targetZone{};\n    array<array<array<uint8_t,N>,N>,3> zoneDistance{};\n    array<int,3> zoneCellCount{};\n    array<pair<int,int>,N*N> cellOrder{};\n    array<pair<int,int>,3> baseAnchors{};\n    bool hasLastMove=false;\n    char lastMove='F';\n    int rezoneCount=0;\n    int lastRezoneTurn=-1000;\n\n    Solver(){\n        for(int idx=0;idx<N*N;++idx) cellOrder[idx]={idx/N,idx%N};\n    }\n\n    bool readInput(){\n        totalCounts.fill(0);\n        for(int i=0;i<100;++i){\n            if(!(cin>>flavors[i])) return false;\n            if(1<=flavors[i] && flavors[i]<=3) totalCounts[flavors[i]-1]++;\n        }\n        uint32_t seed=712387u;\n        for(int i=0;i<100;++i){\n            seed=seed*1000003u + (uint32_t)flavors[i]*239017u + i;\n        }\n        rng.seed(seed);\n        computeZones();\n        return true;\n    }\n\n    void solve(){\n        for(auto &row:board) row.fill(0);\n        placed=0;\n        hasLastMove=false;\n        rezoneCount=0;\n        lastRezoneTurn=-1000;\n        for(int t=0;t<100;++t){\n            int p;\n            if(!(cin>>p)) return;\n            placeCandy(p,flavors[t]);\n            ++placed;\n            maybeRezone();\n            auto dec = chooseMove(placed);\n            board = dec.board;\n            lastMove = dec.dir;\n            hasLastMove = true;\n            cout << dec.dir << '\\n' << flush;\n        }\n    }\n\n    void placeCandy(int idx,int flavor){\n        int target=idx;\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c)\n                if(board[r][c]==0 && --target==0){\n                    board[r][c]=uint8_t(flavor);\n                    return;\n                }\n    }\n\n    void applyTilt(Grid &g,char dir) const{\n        if(dir=='F'){\n            for(int c=0;c<N;++c){\n                array<uint8_t,N> tmp{};\n                int k=0;\n                for(int r=0;r<N;++r) if(g[r][c]) tmp[k++]=g[r][c];\n                for(int r=0;r<N;++r) g[r][c]=(r<k?tmp[r]:0);\n            }\n        }else if(dir=='B'){\n            for(int c=0;c<N;++c){\n                array<uint8_t,N> tmp{};\n                int k=0;\n                for(int r=0;r<N;++r) if(g[r][c]) tmp[k++]=g[r][c];\n                int idx=k-1;\n                for(int r=N-1;r>=0;--r) g[r][c]=(idx>=0?tmp[idx--]:0);\n            }\n        }else if(dir=='L'){\n            for(int r=0;r<N;++r){\n                array<uint8_t,N> tmp{};\n                int k=0;\n                for(int c=0;c<N;++c) if(g[r][c]) tmp[k++]=g[r][c];\n                for(int c=0;c<N;++c) g[r][c]=(c<k?tmp[c]:0);\n            }\n        }else{\n            for(int r=0;r<N;++r){\n                array<uint8_t,N> tmp{};\n                int k=0;\n                for(int c=0;c<N;++c) if(g[r][c]) tmp[k++]=g[r][c];\n                int idx=k-1;\n                for(int c=N-1;c>=0;--c) g[r][c]=(idx>=0?tmp[idx--]:0);\n            }\n        }\n    }\n\n    struct Decision { char dir='F'; Grid board{}; };\n\n    Decision chooseMove(int filled){\n        Decision best;\n        double bestScore=-1e100;\n        bool first=true;\n        int depth = (filled >= 70 ? 2 : 1);\n        for(char dir:DIRS){\n            Grid cand=board;\n            applyTilt(cand,dir);\n            double score=evaluateWithDepth(cand,filled,depth);\n            if(hasLastMove && isOpposite(dir,lastMove)) score -= REVERSE_PENALTY;\n            score += randomNoise();\n            if(first || score>bestScore){\n                first=false;\n                bestScore=score;\n                best.dir=dir;\n                best.board=cand;\n            }\n        }\n        return best;\n    }\n\n    bool isOpposite(char a,char b) const{\n        return (a=='F'&&b=='B')||(a=='B'&&b=='F')||(a=='L'&&b=='R')||(a=='R'&&b=='L');\n    }\n\n    int getEnumerationThreshold(int depth) const {\n        return (depth <= 1 ? FULL_LOOKAHEAD_THRESHOLD1 : FULL_LOOKAHEAD_THRESHOLD2);\n    }\n\n    int getSampleLimit(int depth, int filled) const {\n        if (depth <= 1) {\n            if (filled < 25) return 30;\n            if (filled < 50) return 20;\n            if (filled < 75) return 14;\n            if (filled < 90) return 10;\n            return 8;\n        } else {\n            return 6;\n        }\n    }\n\n    double evaluateWithDepth(const Grid &state,int filled,int depth){\n        double base=evaluate(state,filled);\n        if(depth<=0 || filled>=100) return base;\n        int nextIdx=filled;\n        if(nextIdx >= (int)flavors.size()) return base;\n\n        vector<int> empties;\n        empties.reserve(N*N);\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c)\n                if(!state[r][c]) empties.push_back(r*N+c);\n        if(empties.empty()) return base;\n\n        int emptiesSz=(int)empties.size();\n        int threshold = getEnumerationThreshold(depth);\n        bool useAll = (emptiesSz <= threshold);\n        int sampleCount;\n        if(useAll){\n            sampleCount = emptiesSz;\n        }else{\n            int limit = getSampleLimit(depth, filled);\n            sampleCount = min(limit, emptiesSz);\n            for(int i=0;i<sampleCount;++i){\n                int span = emptiesSz - i;\n                int j = i + (int)(rng()%span);\n                swap(empties[i], empties[j]);\n            }\n        }\n\n        int nextFlavor = flavors[nextIdx];\n        double accum=0.0;\n        for(int i=0;i<sampleCount;++i){\n            int idx = empties[i];\n            int r = idx / N, c = idx % N;\n            Grid tmp = state;\n            tmp[r][c] = (uint8_t)nextFlavor;\n            double bestNext=-1e100;\n            for(char dir:DIRS){\n                Grid fut = tmp;\n                applyTilt(fut, dir);\n                bestNext = max(bestNext, evaluateWithDepth(fut, filled+1, depth-1));\n            }\n            accum += bestNext;\n        }\n        double avg = accum / sampleCount;\n\n        double fillRatio = (double)filled / 100.0;\n        double adapt = 0.35 + 0.65*(1.0 - fillRatio);\n        double coverage = useAll ? 1.0 : (double)sampleCount / emptiesSz;\n        double coverageFactor = sqrt(max(1e-9, coverage));\n        double depthDecay = (depth <= 1 ? 1.0 : 0.75);\n        double lookFactor = LOOKAHEAD_WEIGHT * adapt * coverageFactor * depthDecay;\n        lookFactor = min(0.45, lookFactor);\n\n        return base*(1.0 - lookFactor) + avg*lookFactor;\n    }\n\n    double evaluate(const Grid &g,int filled) const{\n        array<int,3> cnt{};\n        array<double,3> sumR{}, sumC{};\n        array<int,3> zoneHits{};\n        array<double,3> zoneDist{};\n        array<int,3> zoneEmpty{};\n        double sameAdj=0, diffAdj=0;\n\n        for(int r=0;r<N;++r){\n            for(int c=0;c<N;++c){\n                int val=g[r][c];\n                if(val){\n                    int idx=val-1;\n                    cnt[idx]++;\n                    sumR[idx]+=r;\n                    sumC[idx]+=c;\n                    if(targetZone[r][c]==idx) zoneHits[idx]++;\n                    zoneDist[idx]+=zoneDistance[idx][r][c];\n                    if(r+1<N && g[r+1][c]){\n                        if(g[r+1][c]==val) sameAdj+=1.0;\n                        else diffAdj+=1.0;\n                    }\n                    if(c+1<N && g[r][c+1]){\n                        if(g[r][c+1]==val) sameAdj+=1.0;\n                        else diffAdj+=1.0;\n                    }\n                }else{\n                    int tz = targetZone[r][c];\n                    zoneEmpty[tz]++;\n                }\n            }\n        }\n\n        array<double,3> meanR{}, meanC{};\n        for(int i=0;i<3;++i)\n            if(cnt[i]){\n                meanR[i]=sumR[i]/cnt[i];\n                meanC[i]=sumC[i]/cnt[i];\n            }\n\n        double centroidScore=0.0;\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c){\n                int val=g[r][c];\n                if(!val) continue;\n                int idx=val-1;\n                double dr=r-meanR[idx], dc=c-meanC[idx];\n                centroidScore += 1.0 / (1.0 + ZONE_ALPHA*(dr*dr+dc*dc));\n            }\n\n        array<array<uint8_t,N>,N> vis{};\n        array<int,3> compCounts{};\n        array<int,3> largest{};\n        double compScore=0.0;\n        const int dr4[4]={-1,1,0,0};\n        const int dc4[4]={0,0,-1,1};\n        for(int r=0;r<N;++r){\n            for(int c=0;c<N;++c){\n                if(!g[r][c] || vis[r][c]) continue;\n                int color=g[r][c];\n                queue<pair<int,int>> q;\n                q.emplace(r,c);\n                vis[r][c]=1;\n                int sz=0;\n                while(!q.empty()){\n                    auto [cr,cc]=q.front(); q.pop();\n                    ++sz;\n                    for(int d=0;d<4;++d){\n                        int nr=cr+dr4[d], nc=cc+dc4[d];\n                        if(nr<0||nr>=N||nc<0||nc>=N) continue;\n                        if(vis[nr][nc] || g[nr][nc]!=color) continue;\n                        vis[nr][nc]=1;\n                        q.emplace(nr,nc);\n                    }\n                }\n                compScore += 1.0 * sz * sz;\n                int idx=color-1;\n                compCounts[idx]++;\n                largest[idx]=max(largest[idx],sz);\n            }\n        }\n\n        int compCountSum=compCounts[0]+compCounts[1]+compCounts[2];\n        int largestSum=largest[0]+largest[1]+largest[2];\n        double fillRatio=(double)filled/100.0;\n\n        double zoneWeight=W_ZONE*(0.4+0.6*(1.0-fillRatio));\n        double adjFactor=0.4+0.6*fillRatio;\n        double adjSameWeight=W_ADJ_SAME*adjFactor;\n        double adjDiffWeight=W_ADJ_DIFF*adjFactor;\n        double compCountWeight=W_COMP_COUNT*fillRatio*fillRatio;\n        double zoneHitBase=W_ZONE_HIT*(0.55+0.45*(1.0-fillRatio));\n        double zoneDistBase=W_ZONE_DIST*(0.5+0.5*fillRatio);\n        double zoneEmptyWeight=W_ZONE_EMPTY*(0.7+0.3*(1.0-fillRatio));\n\n        double zoneHitVal=0.0, zoneDistVal=0.0, zoneEmptyVal=0.0;\n        for(int i=0;i<3;++i){\n            int total = cnt[i] + zoneEmpty[i];\n            if(total==0) continue;\n            double insideRatio = (total? (double)zoneHits[i]/max(1,cnt[i]) : 0.0);\n            double shortage = (cnt[i]? 1.0 - (double)zoneHits[i]/cnt[i] : 1.0);\n            shortage = clamp(shortage, 0.0, 1.0);\n            double factor = 0.4+0.6*shortage;\n            zoneHitVal += factor * zoneHits[i];\n            zoneDistVal += factor * zoneDist[i];\n            zoneEmptyVal += (0.3 + 0.7 * shortage) * zoneEmpty[i];\n        }\n\n        double score = W_COMPONENT*compScore\n                     + adjSameWeight*sameAdj\n                     - adjDiffWeight*diffAdj\n                     + zoneWeight*centroidScore\n                     + W_LARGEST*largestSum\n                     - compCountWeight*compCountSum\n                     + zoneHitBase*zoneHitVal\n                     - zoneDistBase*zoneDistVal\n                     + zoneEmptyWeight*zoneEmptyVal;\n        return score;\n    }\n\n    double randomNoise(){\n        return (double(rng() & 0xffffu)/65535.0 - 0.5) * 1e-3;\n    }\n\n    void computeZones(){\n        ZoneGrid zone{};\n        array<pair<int,int>,3> anchors{};\n        if(!buildBestZone(zone,anchors)) fallbackZone(zone,anchors);\n        baseAnchors = anchors;\n        targetZone = zone;\n        zoneCellCount.fill(0);\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c)\n                zoneCellCount[targetZone[r][c]]++;\n        computeZoneDistances();\n    }\n\n    bool buildBestZone(ZoneGrid &outZone, array<pair<int,int>,3> &anchorsOut){\n        vector<array<pair<int,int>,3>> anchorSets;\n        auto addSet=[&](initializer_list<pair<int,int>> pts){\n            if(pts.size()!=3) return;\n            array<pair<int,int>,3> arr{};\n            int idx=0;\n            for(auto pt:pts) arr[idx++]=pt;\n            anchorSets.push_back(arr);\n        };\n        addSet({{1,1},{1,8},{7,4}});\n        addSet({{1,1},{8,1},{4,8}});\n        addSet({{1,8},{8,8},{4,1}});\n        addSet({{8,1},{8,8},{1,4}});\n        addSet({{0,0},{9,0},{4,9}});\n        addSet({{0,0},{0,9},{9,4}});\n        addSet({{0,4},{9,4},{4,9}});\n        addSet({{4,0},{4,9},{8,5}});\n        addSet({{2,2},{2,7},{7,5}});\n        addSet({{2,2},{7,2},{5,7}});\n        addSet({{1,1},{8,8},{5,5}});\n        addSet({{8,1},{1,8},{5,5}});\n        addSet({{0,0},{9,9},{4,5}});\n        addSet({{0,9},{9,0},{5,4}});\n        addSet({{2,2},{7,7},{4,4}});\n        for(int i=0;i<80;++i){\n            array<pair<int,int>,3> arr{};\n            for(int k=0;k<3;++k) arr[k]={int(rng()%N),int(rng()%N)};\n            anchorSets.push_back(arr);\n        }\n\n        bool success=false;\n        long long bestCost=(1LL<<60);\n        ZoneGrid bestZone{};\n        array<pair<int,int>,3> bestAnchors{};\n\n        for(const auto &set:anchorSets){\n            array<int,3> perm={0,1,2};\n            do{\n                array<pair<int,int>,3> anchors{};\n                for(int i=0;i<3;++i) anchors[perm[i]] = set[i];\n                ZoneGrid cand{};\n                long long cost;\n                if(!buildZoneForAnchors(anchors,cand,cost,nullptr)) continue;\n                if(!success || cost<bestCost){\n                    success=true;\n                    bestCost=cost;\n                    bestZone=cand;\n                    bestAnchors=anchors;\n                }\n            }while(next_permutation(perm.begin(),perm.end()));\n        }\n        if(success){\n            outZone=bestZone;\n            anchorsOut=bestAnchors;\n        }\n        return success;\n    }\n\n    bool buildZoneForAnchors(const array<pair<int,int>,3> &anchors,\n                             ZoneGrid &outZone,long long &outCost,\n                             const Grid *boardState){\n        const int totalCells=N*N;\n        const int SRC=0;\n        const int COLOR_BASE=1;\n        const int CELL_BASE=COLOR_BASE+3;\n        const int SINK=CELL_BASE+totalCells;\n        MinCostFlow mcf(SINK+1);\n        vector<vector<int>> edgeIndex(3, vector<int>(totalCells,-1));\n\n        int totalCandy=totalCounts[0]+totalCounts[1]+totalCounts[2];\n        if(totalCandy==0) return false;\n\n        for(int color=0;color<3;++color){\n            mcf.add_edge(SRC,COLOR_BASE+color,totalCounts[color],0);\n        }\n        for(int color=0;color<3;++color){\n            if(totalCounts[color]==0) continue;\n            auto [ar,ac]=anchors[color];\n            ar=clamp(ar,0,N-1);\n            ac=clamp(ac,0,N-1);\n            int node=COLOR_BASE+color;\n            for(int idx=0;idx<totalCells;++idx){\n                auto [r,c]=cellOrder[idx];\n                int cost=abs(r-ar)+abs(c-ac);\n                if(boardState){\n                    int occ=(*boardState)[r][c];\n                    if(occ && occ-1!=color) cost += OCC_PENALTY;\n                }\n                int pos=(int)mcf.graph[node].size();\n                mcf.add_edge(node,CELL_BASE+idx,1,cost);\n                edgeIndex[color][idx]=pos;\n            }\n        }\n        for(int idx=0;idx<totalCells;++idx)\n            mcf.add_edge(CELL_BASE+idx,SINK,1,0);\n\n        auto res=mcf.min_cost_flow(SRC,SINK,totalCandy);\n        if(res.first!=totalCandy) return false;\n        outCost=res.second;\n\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c)\n                outZone[r][c]=0;\n\n        for(int idx=0;idx<totalCells;++idx){\n            int assigned=-1;\n            for(int color=0;color<3;++color){\n                int pos=edgeIndex[color][idx];\n                if(pos==-1) continue;\n                if(mcf.graph[COLOR_BASE+color][pos].cap==0){\n                    assigned=color;\n                    break;\n                }\n            }\n            if(assigned==-1) assigned=0;\n            auto [r,c]=cellOrder[idx];\n            outZone[r][c]=(int8_t)assigned;\n        }\n        return true;\n    }\n\n    void fallbackZone(ZoneGrid &zone, array<pair<int,int>,3> &anchors){\n        anchors = {{{2,2},{2,7},{7,5}}};\n        array<int,3> remaining=totalCounts;\n        int color=0;\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c){\n                while(color<3 && remaining[color]==0) ++color;\n                if(color>=3) color=2;\n                zone[r][c]=(int8_t)color;\n                if(remaining[color]>0) --remaining[color];\n            }\n    }\n\n    void computeZoneDistances(){\n        const int INF=1e9;\n        for(int color=0;color<3;++color){\n            if(zoneCellCount[color]==0){\n                for(int r=0;r<N;++r)\n                    for(int c=0;c<N;++c)\n                        zoneDistance[color][r][c]=0;\n                continue;\n            }\n            array<array<int,N>,N> dist;\n            for(int r=0;r<N;++r)\n                for(int c=0;c<N;++c)\n                    dist[r][c]=INF;\n            queue<pair<int,int>> q;\n            for(int r=0;r<N;++r)\n                for(int c=0;c<N;++c)\n                    if(targetZone[r][c]==color){\n                        dist[r][c]=0;\n                        q.emplace(r,c);\n                    }\n            const int dr4[4]={-1,1,0,0};\n            const int dc4[4]={0,0,-1,1};\n            while(!q.empty()){\n                auto [r,c]=q.front(); q.pop();\n                for(int d=0;d<4;++d){\n                    int nr=r+dr4[d], nc=c+dc4[d];\n                    if(nr<0||nr>=N||nc<0||nc>=N) continue;\n                    if(dist[nr][nc]>dist[r][c]+1){\n                        dist[nr][nc]=dist[r][c]+1;\n                        q.emplace(nr,nc);\n                    }\n                }\n            }\n            for(int r=0;r<N;++r)\n                for(int c=0;c<N;++c){\n                    int d=dist[r][c];\n                    if(d==INF) d=250;\n                    if(d>250) d=250;\n                    zoneDistance[color][r][c]=(uint8_t)d;\n                }\n        }\n    }\n\n    struct ZoneStats {\n        array<int,3> cnt{};\n        array<int,3> hits{};\n        array<double,3> sumR{}, sumC{};\n    };\n\n    ZoneStats collectStats() const{\n        ZoneStats zs;\n        for(int r=0;r<N;++r)\n            for(int c=0;c<N;++c){\n                int val=board[r][c];\n                if(!val) continue;\n                int idx=val-1;\n                zs.cnt[idx]++;\n                zs.sumR[idx]+=r;\n                zs.sumC[idx]+=c;\n                if(targetZone[r][c]==idx) zs.hits[idx]++;\n            }\n        return zs;\n    }\n\n    void maybeRezone(){\n        const int GAP = 12;\n        if (rezoneCount >= 2) return;\n        ZoneStats st = collectStats();\n        double worstShortage = 0.0;\n        for(int i=0;i<3;++i){\n            if(st.cnt[i]==0) continue;\n            double insideRatio=(double)st.hits[i]/st.cnt[i];\n            worstShortage = max(worstShortage, 1.0 - insideRatio);\n        }\n\n        bool trigger = false;\n        if (rezoneCount == 0 && placed >= 55 && worstShortage > 0.55 && placed - lastRezoneTurn >= GAP) {\n            trigger = true;\n        } else if (rezoneCount == 1 && placed >= 80 && worstShortage > 0.65 && placed - lastRezoneTurn >= GAP) {\n            trigger = true;\n        }\n        if (!trigger) return;\n\n        array<pair<int,int>,3> anchors = baseAnchors;\n        for(int i=0;i<3;++i){\n            if(st.cnt[i]==0) continue;\n            double cr = st.sumR[i]/st.cnt[i];\n            double cc = st.sumC[i]/st.cnt[i];\n            double ir = 0.65*cr + 0.35*baseAnchors[i].first;\n            double ic = 0.65*cc + 0.35*baseAnchors[i].second;\n            anchors[i] = {clamp((int)round(ir),0,N-1), clamp((int)round(ic),0,N-1)};\n        }\n\n        ZoneGrid zone;\n        long long cost;\n        if(buildZoneForAnchors(anchors, zone, cost, &board)){\n            targetZone = zone;\n            zoneCellCount.fill(0);\n            for(int r=0;r<N;++r)\n                for(int c=0;c<N;++c)\n                    zoneCellCount[targetZone[r][c]]++;\n            computeZoneDistances();\n        }\n        lastRezoneTurn = placed;\n        ++rezoneCount;\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver solver;\n    if(!solver.readInput()) return 0;\n    solver.solve();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\n// ------------------------- Hungarian -------------------------\nstruct Hungarian {\n    int n;\n    vector<vector<int>> cost;\n    vector<int> assignment;\n    Hungarian(int n=0){ init(n); }\n    void init(int m){\n        n=m;\n        cost.assign(n, vector<int>(n,0));\n        assignment.assign(n,-1);\n    }\n    void solve(){\n        const int INF=1e9;\n        vector<int> u(n+1,0), v(n+1,0), p(n+1,0), way(n+1,0);\n        for(int i=1;i<=n;i++){\n            p[0]=i;\n            vector<int> minv(n+1, INF);\n            vector<char> used(n+1,false);\n            int j0=0;\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> ans(n,-1);\n        for(int j=1;j<=n;j++) if(p[j]>0) ans[p[j]-1]=j-1;\n        assignment=ans;\n    }\n};\n\n// ------------------------- Designer -------------------------\nstruct Designer {\n    static constexpr int N=60;\n    static constexpr int A=32;\n    static constexpr int P=N-A;\n\n    int M;\n    double eps;\n\n    int payloadEdges = P*(P-1)/2;\n    int payloadWords = (payloadEdges+63)/64;\n\n    vector<vector<int>> anchorAdj;\n    vector<uint64_t> anchorAdjMask;\n    vector<uint64_t> payloadAnchorMask;\n    vector<int> degAA_can, degAP_can;\n    vector<vector<uint64_t>> graphCodes;\n\n    vector<vector<int>> payloadIdx;\n    mt19937_64 rng;\n    uint64_t seedBase;\n\n    Designer() {\n        payloadIdx.assign(P, vector<int>(P,-1));\n        int idx=0;\n        for(int i=0;i<P;i++)\n            for(int j=i+1;j<P;j++)\n                payloadIdx[i][j]=idx++;\n    }\n\n    vector<uint64_t> randomPayloadBits(){\n        vector<uint64_t> bits(payloadWords);\n        for(auto &w: bits) w=rng();\n        if(payloadEdges%64)\n            bits.back() &= (1ULL<<(payloadEdges%64))-1ULL;\n        return bits;\n    }\n\n    void generateAnchorAdj(double prob=0.82){\n        anchorAdj.assign(A, vector<int>(A,0));\n        anchorAdjMask.assign(A,0);\n        uniform_real_distribution<double> dist(0.0,1.0);\n        for(int i=0;i<A;i++)\n            for(int j=i+1;j<A;j++){\n                bool e = dist(rng)<prob;\n                anchorAdj[i][j]=anchorAdj[j][i]=e;\n            }\n        degAA_can.assign(A,0);\n        for(int i=0;i<A;i++){\n            uint64_t mask=0;\n            int cnt=0;\n            for(int j=0;j<A;j++)\n                if(anchorAdj[i][j]){\n                    mask |= (1ULL<<j);\n                    cnt++;\n                }\n            anchorAdjMask[i]=mask;\n            degAA_can[i]=cnt;\n        }\n    }\n\n    void generatePayloadRows(int minWeight=10,int maxWeight=22,int minDist=8){\n        payloadAnchorMask.clear();\n        int attempts=0;\n        const int LIMIT=30000;\n        while((int)payloadAnchorMask.size()<P){\n            uint64_t mask=rng() & ((1ULL<<A)-1ULL);\n            int w=__builtin_popcountll(mask);\n            if(w<minWeight || w>maxWeight){ attempts++; continue; }\n            bool ok=true;\n            for(auto prev: payloadAnchorMask)\n                if(__builtin_popcountll(mask ^ prev) < minDist){ ok=false; break; }\n            if(ok) payloadAnchorMask.push_back(mask);\n            else attempts++;\n            if(attempts>LIMIT){\n                if(minDist>5) minDist--;\n                else if(minWeight>6) minWeight--;\n                attempts=0;\n            }\n        }\n        degAP_can.assign(A,0);\n        for(int i=0;i<A;i++){\n            int cnt=0;\n            for(auto mask: payloadAnchorMask)\n                if((mask>>i)&1ULL) cnt++;\n            degAP_can[i]=cnt;\n        }\n    }\n\n    int hamming(const vector<uint64_t>&a,const vector<uint64_t>&b) const{\n        int s=0;\n        for(size_t i=0;i<a.size();i++) s+=__builtin_popcountll(a[i]^b[i]);\n        return s;\n    }\n\n    void generateGraphCodes(int M,int baseDist){\n        graphCodes.clear();\n        int curDist=min(baseDist,payloadEdges);\n        int minDist=min(max(70, baseDist-25), payloadEdges);\n        int attempts=0;\n        const int LIMIT=50000;\n        while((int)graphCodes.size()<M){\n            auto cand = randomPayloadBits();\n            bool ok=true;\n            for(auto &ex: graphCodes){\n                if(hamming(cand,ex)<curDist){ ok=false; break; }\n            }\n            if(ok){\n                graphCodes.push_back(move(cand));\n            }else{\n                attempts++;\n                if(attempts>LIMIT && curDist>minDist){\n                    curDist--;\n                    attempts=0;\n                }\n            }\n        }\n    }\n\n    void build(int M_, double eps_){\n        M=M_;\n        eps=eps_;\n        int epsInt=(int)round(eps*100+1e-9);\n        seedBase = 1234567ULL + 10007ULL*M + 7919ULL*epsInt;\n        rng.seed(seedBase);\n        generateAnchorAdj();\n        generatePayloadRows();\n        int baseDist = 110 + epsInt/4;\n        generateGraphCodes(M, baseDist);\n    }\n\n    string graphString(int idx){\n        string s;\n        s.reserve(N*(N-1)/2);\n        auto &code = graphCodes[idx];\n        for(int i=0;i<N;i++)\n            for(int j=i+1;j<N;j++){\n                bool val=false;\n                if(i<A && j<A) val=anchorAdj[i][j];\n                else if(i<A && j>=A){\n                    int p=j-A;\n                    val = ((payloadAnchorMask[p]>>i)&1ULL);\n                }else{\n                    int u=i-A, v=j-A;\n                    int bitIdx=payloadIdx[u][v];\n                    val = (code[bitIdx>>6]>>(bitIdx&63))&1ULL;\n                }\n                s.push_back(val?'1':'0');\n            }\n        return s;\n    }\n};\n\n// ------------------------- Decoder -------------------------\nstruct Decoder {\n    Designer *des;\n    mt19937 rng;\n    Decoder(Designer* d): des(d){\n        rng.seed(des->seedBase ^ 0x9e3779b97f4a7c15ULL);\n    }\n\n    vector<uint64_t> parse(const string& s){\n        vector<uint64_t> adj(Designer::N,0);\n        int pos=0;\n        for(int i=0;i<Designer::N;i++)\n            for(int j=i+1;j<Designer::N;j++)\n                if(s[pos++]=='1'){\n                    adj[i]|=(1ULL<<j);\n                    adj[j]|=(1ULL<<i);\n                }\n        return adj;\n    }\n\n    vector<int> improveAnchors(vector<int> set, const vector<uint64_t>&adj){\n        int N=Designer::N,A=Designer::A;\n        if((int)set.size()!=A){\n            set.resize(A);\n            iota(set.begin(), set.end(), 0);\n        }\n        auto recompute=[&](const vector<int>& curr){\n            vector<int> deg(N,0);\n            for(int v=0; v<N; ++v){\n                int cnt=0;\n                for(int u: curr)\n                    if(u!=v && ((adj[v]>>u)&1ULL)) cnt++;\n                deg[v]=cnt;\n            }\n            return deg;\n        };\n        vector<int> degIn = recompute(set);\n        vector<char> in(N,false);\n        for(int v:set) in[v]=true;\n\n        for(int iter=0; iter<6; ++iter){\n            int bestDelta = 0, bestU=-1, bestV=-1;\n            for(int u: set){\n                for(int v=0; v<N; ++v){\n                    if(in[v]) continue;\n                    bool edge = (adj[u]>>v)&1ULL;\n                    int delta = (degIn[v] - (edge?1:0)) - degIn[u];\n                    if(delta>bestDelta){\n                        bestDelta=delta; bestU=u; bestV=v;\n                    }\n                }\n            }\n            if(bestDelta<=0) break;\n            in[bestU]=false; in[bestV]=true;\n            for(int &x: set) if(x==bestU){ x=bestV; break; }\n            degIn = recompute(set);\n        }\n\n        sort(set.begin(), set.end());\n        return set;\n    }\n\n    vector<vector<int>> generateAnchorCandidates(const vector<uint64_t>&adj){\n        int N=Designer::N,A=Designer::A;\n        vector<int> deg(N);\n        for(int i=0;i<N;i++) deg[i]=__builtin_popcountll(adj[i]);\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a,int b){\n            if(deg[a]!=deg[b]) return deg[a]>deg[b];\n            return a<b;\n        });\n        const int MAX_CAND=40;\n        vector<vector<int>> candidates;\n\n        auto makeCand=[&](int shift=0){\n            vector<int> cand;\n            cand.reserve(A);\n            for(int i=0;i<A;i++) cand.push_back(order[(i+shift)%N]);\n            return cand;\n        };\n\n        auto addCandidate=[&](vector<int> cand){\n            if((int)candidates.size()>=MAX_CAND) return;\n            cand = improveAnchors(cand,adj);\n            candidates.push_back(move(cand));\n        };\n\n        addCandidate(makeCand(0));\n        int shifts = min(5, N-A);\n        for(int s=1;s<=shifts;s++){\n            if((int)candidates.size()>=MAX_CAND) break;\n            vector<int> cand(order.begin()+s, order.begin()+s+A);\n            addCandidate(cand);\n        }\n        for(int t=0;t<5 && (int)candidates.size()<MAX_CAND;t++){\n            shuffle(order.begin(), order.end(), rng);\n            vector<int> cand(order.begin(), order.begin()+A);\n            addCandidate(cand);\n        }\n        if(candidates.empty()) addCandidate(makeCand(0));\n        return candidates;\n    }\n\n    struct AnchorMapResult {\n        vector<int> anchorMap;\n        vector<int> payloads;\n        int anchorCost;\n    };\n\n    AnchorMapResult mapAnchors(const vector<uint64_t>&adj, const vector<int>&cand){\n        int N=Designer::N,A=Designer::A;\n        vector<char> isAnchor(N,false);\n        for(int v:cand) isAnchor[v]=true;\n        vector<int> payloads;\n        for(int i=0;i<N;i++) if(!isAnchor[i]) payloads.push_back(i);\n        uint64_t payloadMask=0;\n        for(int v: payloads) payloadMask|=(1ULL<<v);\n\n        vector<vector<int>> obsAA(A, vector<int>(A,0));\n        vector<int> degAA_obs(A,0), degAP_obs(A,0);\n        for(int i=0;i<A;i++){\n            int vi=cand[i];\n            for(int j=0;j<A;j++){\n                if(i==j) continue;\n                if((adj[vi]>>cand[j])&1ULL){\n                    obsAA[i][j]=1;\n                    degAA_obs[i]++;\n                }\n            }\n            degAP_obs[i]=__builtin_popcountll(adj[vi] & payloadMask);\n        }\n\n        Hungarian hung(A);\n        for(int i=0;i<A;i++)\n            for(int j=0;j<A;j++)\n                hung.cost[i][j]=5*abs(des->degAA_can[i]-degAA_obs[j]) +\n                                abs(des->degAP_can[i]-degAP_obs[j]);\n        hung.solve();\n\n        vector<int> perm = hung.assignment;\n        auto calcCost=[&](const vector<int>&p){\n            int total=0;\n            for(int i=0;i<A;i++)\n                for(int j=i+1;j<A;j++)\n                    total += des->anchorAdj[i][j] ^ obsAA[p[i]][p[j]];\n            return total;\n        };\n\n        vector<int> best=perm;\n        int bestCost=calcCost(best);\n        vector<int> cur=perm;\n        int curCost=bestCost;\n\n        uniform_int_distribution<int> distIdx(0,A-1);\n        uniform_real_distribution<double> distReal(0.0,1.0);\n        double temp=4.0;\n        for(int iter=0; iter<2000; ++iter){\n            int i=distIdx(rng), j=distIdx(rng);\n            if(i==j) continue;\n            if(i>j) swap(i,j);\n            int oi=cur[i], oj=cur[j];\n            int delta=0;\n            for(int k=0;k<A;k++){\n                if(k==i || k==j) continue;\n                int ok=cur[k];\n                delta += (des->anchorAdj[i][k] ^ obsAA[oj][ok]) - (des->anchorAdj[i][k] ^ obsAA[oi][ok]);\n                delta += (des->anchorAdj[j][k] ^ obsAA[oi][ok]) - (des->anchorAdj[j][k] ^ obsAA[oj][ok]);\n            }\n            delta += (des->anchorAdj[i][j] ^ obsAA[oj][oi]) - (des->anchorAdj[i][j] ^ obsAA[oi][oj]);\n            if(delta < 0 || (temp>1e-6 && distReal(rng) < exp(-delta/temp))){\n                swap(cur[i], cur[j]);\n                curCost += delta;\n                if(curCost < bestCost){\n                    bestCost = curCost;\n                    best = cur;\n                }\n            }\n            temp *= 0.995;\n            if(temp < 0.15) temp = 0.15;\n        }\n\n        vector<int> anchorMap(A);\n        for(int i=0;i<A;i++) anchorMap[i]=cand[best[i]];\n        sort(payloads.begin(), payloads.end());\n        return { anchorMap, payloads, bestCost };\n    }\n\n    vector<uint64_t> observedPayloadBits(const vector<uint64_t>&adj, const vector<int>&order){\n        vector<uint64_t> bits(des->payloadWords,0);\n        int idx=0;\n        for(int i=0;i<Designer::P;i++)\n            for(int j=i+1;j<Designer::P;j++){\n                bool bit = (adj[order[i]]>>order[j])&1ULL;\n                if(bit) bits[idx>>6] |= (1ULL<<(idx&63));\n                idx++;\n            }\n        return bits;\n    }\n\n    vector<int> refinePayloadOrder(const vector<int>&initial,\n                                   const vector<vector<int>>&anchorMismatch,\n                                   const vector<vector<int>>&realEdge,\n                                   int codeIdx){\n        if(codeIdx<0) return initial;\n        int P=Designer::P;\n        vector<int> assign=initial;\n\n        vector<vector<int>> codeEdge(P, vector<int>(P,0));\n        const auto &code = des->graphCodes[codeIdx];\n        for(int i=0;i<P;i++)\n            for(int j=i+1;j<P;j++){\n                int pos=des->payloadIdx[i][j];\n                int bit = (code[pos>>6]>>(pos&63))&1ULL;\n                codeEdge[i][j]=codeEdge[j][i]=bit;\n            }\n\n        const int wA=2, wE=3;\n        int anchorCost=0;\n        for(int i=0;i<P;i++) anchorCost += anchorMismatch[i][assign[i]];\n        int edgeCost=0;\n        for(int i=0;i<P;i++)\n            for(int j=i+1;j<P;j++)\n                edgeCost += (realEdge[assign[i]][assign[j]] ^ codeEdge[i][j]);\n        int totalCost = wA*anchorCost + wE*edgeCost;\n\n        vector<int> best=assign;\n        int bestCost=totalCost;\n\n        uniform_int_distribution<int> distIdx(0,P-1);\n        uniform_real_distribution<double> distReal(0.0,1.0);\n        double temp=3.0;\n        for(int iter=0; iter<3500; ++iter){\n            int a=distIdx(rng), b=distIdx(rng);\n            if(a==b) continue;\n            if(a>b) swap(a,b);\n            int ra=assign[a], rb=assign[b];\n            if(ra==rb) continue;\n            int deltaA = anchorMismatch[a][rb] + anchorMismatch[b][ra]\n                        - anchorMismatch[a][ra] - anchorMismatch[b][rb];\n            int deltaE=0;\n            for(int t=0;t<P;t++){\n                if(t==a || t==b) continue;\n                int rt=assign[t];\n                int oldA = realEdge[ra][rt] ^ codeEdge[a][t];\n                int newA = realEdge[rb][rt] ^ codeEdge[a][t];\n                deltaE += newA - oldA;\n                int oldB = realEdge[rb][rt] ^ codeEdge[b][t];\n                int newB = realEdge[ra][rt] ^ codeEdge[b][t];\n                deltaE += newB - oldB;\n            }\n            int delta = wA*deltaA + wE*deltaE;\n            if(delta<0 || (temp>1e-6 && distReal(rng)<exp(-delta/temp))){\n                assign[a]=rb;\n                assign[b]=ra;\n                totalCost += delta;\n                if(totalCost<bestCost){\n                    bestCost=totalCost;\n                    best=assign;\n                }\n            }\n            temp*=0.995;\n            if(temp<0.2) temp=0.2;\n        }\n        return best;\n    }\n\n    struct DecodeResult { int graphIdx; int dist; int anchorCost; };\n\n    DecodeResult decodeWithAnchors(const vector<uint64_t>&adj, const vector<int>&cand){\n        if((int)cand.size()!=Designer::A) return {-1, INT_MAX, INT_MAX};\n        auto mapRes = mapAnchors(adj, cand);\n        if((int)mapRes.payloads.size()!=Designer::P) return {-1, INT_MAX, INT_MAX};\n        const auto &payloads = mapRes.payloads;\n\n        vector<uint64_t> obsMask(Designer::P,0);\n        for(int i=0;i<Designer::P;i++){\n            uint64_t mask=0;\n            int v=payloads[i];\n            for(int a=0;a<Designer::A;a++)\n                if((adj[v]>>mapRes.anchorMap[a])&1ULL) mask|=(1ULL<<a);\n            obsMask[i]=mask;\n        }\n\n        vector<vector<int>> anchorMismatch(Designer::P, vector<int>(Designer::P,0));\n        for(int i=0;i<Designer::P;i++)\n            for(int j=0;j<Designer::P;j++)\n                anchorMismatch[i][j]=__builtin_popcountll(obsMask[j] ^ des->payloadAnchorMask[i]);\n\n        vector<vector<int>> realEdge(Designer::P, vector<int>(Designer::P,0));\n        for(int i=0;i<Designer::P;i++)\n            for(int j=i+1;j<Designer::P;j++){\n                bool bit=(adj[payloads[i]]>>payloads[j])&1ULL;\n                realEdge[i][j]=realEdge[j][i]=bit;\n            }\n\n        Hungarian hung(Designer::P);\n        for(int r=0;r<Designer::P;r++)\n            for(int c=0;c<Designer::P;c++)\n                hung.cost[r][c]=anchorMismatch[c][r];\n        hung.solve();\n\n        vector<int> assign(des->P,-1);\n        vector<char> used(des->P,false);\n        for(int r=0;r<Designer::P;r++){\n            int c = hung.assignment[r];\n            if(c>=0 && c<Designer::P && assign[c]==-1){\n                assign[c]=r;\n                used[r]=true;\n            }\n        }\n        int ptr=0;\n        for(int c=0;c<Designer::P;c++){\n            if(assign[c]==-1){\n                while(ptr<Designer::P && used[ptr]) ptr++;\n                assign[c]=(ptr<Designer::P)?ptr:0;\n                if(ptr<Designer::P) used[ptr]=true;\n            }\n        }\n\n        auto orderFromAssign=[&](const vector<int>&as){\n            vector<int> order(Designer::P);\n            for(int i=0;i<Designer::P;i++) order[i]=payloads[as[i]];\n            return order;\n        };\n        auto bitsFromAssign=[&](const vector<int>&as){\n            auto order = orderFromAssign(as);\n            return observedPayloadBits(adj, order);\n        };\n\n        auto baseBits = bitsFromAssign(assign);\n        vector<pair<int,int>> codeDist;\n        codeDist.reserve(des->graphCodes.size());\n        for(int k=0;k<(int)des->graphCodes.size();k++){\n            int dist = des->hamming(baseBits, des->graphCodes[k]);\n            codeDist.emplace_back(dist, k);\n        }\n        sort(codeDist.begin(), codeDist.end());\n\n        DecodeResult bestRes{codeDist[0].second, codeDist[0].first, mapRes.anchorCost};\n        const int topK = min(6, (int)codeDist.size());\n        for(int idx=0; idx<topK; ++idx){\n            int codeIdx = codeDist[idx].second;\n            auto refinedAssign = refinePayloadOrder(assign, anchorMismatch, realEdge, codeIdx);\n            auto refinedBits = bitsFromAssign(refinedAssign);\n            int bestCodeHere=-1, bestDistHere=INT_MAX;\n            for(int k=0;k<(int)des->graphCodes.size();k++){\n                int dist = des->hamming(refinedBits, des->graphCodes[k]);\n                if(dist < bestDistHere){\n                    bestDistHere = dist;\n                    bestCodeHere = k;\n                }\n            }\n            pair<int,int> keyRef = {bestDistHere, mapRes.anchorCost};\n            pair<int,int> keyBest = {bestRes.dist, bestRes.anchorCost};\n            if(keyRef < keyBest){\n                bestRes = {bestCodeHere, bestDistHere, mapRes.anchorCost};\n            }\n        }\n        return bestRes;\n    }\n\n    int decode(const string& s){\n        auto adj = parse(s);\n        auto candidates = generateAnchorCandidates(adj);\n        int best=-1;\n        pair<int,int> bestKey={INT_MAX, INT_MAX};\n        for(auto &cand : candidates){\n            auto res = decodeWithAnchors(adj, cand);\n            if(res.graphIdx==-1) continue;\n            pair<int,int> key={res.dist, res.anchorCost};\n            if(key<bestKey){\n                bestKey=key;\n                best=res.graphIdx;\n            }\n        }\n        if(best==-1){\n            uniform_int_distribution<int> dist(0,(int)des->graphCodes.size()-1);\n            best=dist(rng);\n        }\n        return best;\n    }\n};\n\n// ------------------------- main -------------------------\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int M;\n    double eps;\n    if(!(cin>>M>>eps)) return 0;\n    Designer designer;\n    designer.build(M, eps);\n    cout<<Designer::N<<\"\\n\";\n    for(int k=0;k<M;k++){\n        cout<<designer.graphString(k)<<\"\\n\";\n    }\n    cout.flush();\n    Decoder decoder(&designer);\n    for(int q=0;q<100;q++){\n        string H;\n        if(!(cin>>H)) break;\n        int ans = decoder.decode(H);\n        cout<<ans<<\"\\n\";\n        cout.flush();\n    }\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n};\n\nstruct DSU {\n    int n;\n    vector<int> parent, sz;\n    int components;\n    DSU(int n=0){ if(n) init(n); }\n    void init(int n_){\n        n = n_;\n        parent.resize(n);\n        sz.resize(n);\n        reset();\n    }\n    void reset(){\n        iota(parent.begin(), parent.end(), 0);\n        fill(sz.begin(), sz.end(), 1);\n        components = n;\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    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        parent[b]=a;\n        sz[a]+=sz[b];\n        --components;\n        return true;\n    }\n};\n\nconst double TOTAL_TIME_LIMIT = 5.8;\nconst double CENTRALITY_LIMIT = 2.9;\nconst double LOCAL_SEARCH_LIMIT = 5.0;\nconst double MOVE_EPS = 1e-9;\nconst double VERTEX_COEFF = 0.18;\nconst double DAYCOUNT_COEFF = 0.035;\nconst double LENGTH_COEFF_RATIO = 0.05;\nconst double MIN_REMAIN_FOR_NEW_RUN = 0.9;\nconst int MAX_RUNS = 3;\nconst int MAX_SAMPLE = 8;\nconst ll INFLL = (1LL<<60);\n\nint N,M,D,K;\nvector<int> U,V,W;\nvector<vector<pair<int,int>>> graphAdj;\n\nvector<double> edgeScore;\nvector<int> assignment;\nvector<vector<int>> dayEdges;\nvector<int> edgePos;\nvector<double> dayScore;\nvector<int> dayCount;\nvector<int> vertexDayCount;\nvector<vector<char>> dayBlocked;\n\nvector<int> sampleSources;\nvector<vector<ll>> baseDist;\n\nvector<vector<vector<ll>>> daySampleDist;\nvector<vector<double>> daySampleSum;\nvector<double> dayEval;\n\nmt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());\n\ndouble alphaCoeff, betaCoeff;\n\nvoid dijkstra_with_block(int src, const vector<char>* blocked, vector<ll>& dist){\n    priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n    fill(dist.begin(), dist.end(), INFLL);\n    dist[src] = 0;\n    pq.emplace(0LL, src);\n    while(!pq.empty()){\n        auto [d,v] = pq.top();\n        pq.pop();\n        if(d != dist[v]) continue;\n        for(auto [to,eid] : graphAdj[v]){\n            if(blocked && (*blocked)[eid]) continue;\n            ll nd = d + W[eid];\n            if(nd < dist[to]){\n                dist[to] = nd;\n                pq.emplace(nd, to);\n            }\n        }\n    }\n}\n\nvoid select_samples_and_base(){\n    int sampleCnt = min(MAX_SAMPLE, N);\n    vector<int> deg(N,0);\n    for(int i=0;i<M;++i){\n        deg[U[i]]++;\n        deg[V[i]]++;\n    }\n    int first = 0;\n    for(int i=1;i<N;++i){\n        if(deg[i] > deg[first]) first = i;\n    }\n    sampleSources.clear();\n    baseDist.clear();\n    vector<ll> cover(N, INFLL);\n    vector<ll> dist(N);\n    int current = first;\n    for(int s=0; s<sampleCnt; ++s){\n        if(s==0) current = first;\n        else{\n            ll best = -1;\n            int bestNode = 0;\n            for(int v=0; v<N; ++v){\n                if(cover[v] > best){\n                    best = cover[v];\n                    bestNode = v;\n                }\n            }\n            current = bestNode;\n        }\n        sampleSources.push_back(current);\n        dijkstra_with_block(current, nullptr, dist);\n        baseDist.push_back(dist);\n        for(int v=0; v<N; ++v){\n            cover[v] = min(cover[v], dist[v]);\n        }\n        cover[current] = 0;\n    }\n}\n\nvector<double> compute_edge_scores(Timer &timer){\n    vector<double> score(M, 0.0);\n    vector<ll> dist(N);\n    vector<double> sigma(N), delta(N);\n    vector<vector<int>> preds(N);\n    for(int i=0;i<N;++i) preds[i].reserve(graphAdj[i].size());\n    vector<int> order;\n    order.reserve(N);\n    vector<int> nodes(N);\n    iota(nodes.begin(), nodes.end(), 0);\n    shuffle(nodes.begin(), nodes.end(), rng);\n    int processed = 0;\n    for(int idx=0; idx<N; ++idx){\n        if(timer.elapsed() > CENTRALITY_LIMIT) break;\n        int s = nodes[idx];\n        fill(dist.begin(), dist.end(), INFLL);\n        fill(sigma.begin(), sigma.end(), 0.0);\n        fill(delta.begin(), delta.end(), 0.0);\n        for(int i=0;i<N;++i) preds[i].clear();\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[s] = 0;\n        sigma[s] = 1.0;\n        pq.emplace(0LL, s);\n        order.clear();\n        while(!pq.empty()){\n            auto [d,v] = pq.top();\n            pq.pop();\n            if(d != dist[v]) continue;\n            order.push_back(v);\n            for(auto [to,eid] : graphAdj[v]){\n                ll nd = d + W[eid];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    pq.emplace(nd, to);\n                    sigma[to] = sigma[v];\n                    preds[to].clear();\n                    preds[to].push_back(eid);\n                }else if(nd == dist[to]){\n                    sigma[to] += sigma[v];\n                    preds[to].push_back(eid);\n                }\n            }\n        }\n        while(!order.empty()){\n            int w = order.back();\n            order.pop_back();\n            if(sigma[w] <= 0.0) continue;\n            double coeff = (1.0 + delta[w]) / sigma[w];\n            for(int eid : preds[w]){\n                int v = (U[eid]==w) ? V[eid] : U[eid];\n                double contrib = sigma[v] * coeff;\n                delta[v] += contrib;\n                score[eid] += contrib;\n            }\n        }\n        ++processed;\n    }\n    if(processed == 0) processed = 1;\n    if(processed < N){\n        double scale = (double)N / processed;\n        for(double &x : score) x *= scale;\n    }\n    double totalScore = 0.0;\n    for(double s : score) totalScore += s;\n    if(totalScore <= 0) totalScore = 1.0;\n    long double baseScale = (long double)totalScore * totalScore;\n    baseScale /= max(1, M);\n    baseScale /= max(1, D);\n    alphaCoeff = (double)(baseScale * VERTEX_COEFF);\n    betaCoeff  = (double)(baseScale * DAYCOUNT_COEFF);\n    if(!isfinite(alphaCoeff) || alphaCoeff < 1e-9) alphaCoeff = 1e-9;\n    if(!isfinite(betaCoeff)  || betaCoeff  < 1e-9) betaCoeff  = 1e-9;\n    alphaCoeff = min(alphaCoeff, 1e18);\n    betaCoeff  = min(betaCoeff , 1e18);\n\n    ll sumW = 0;\n    for(int w : W) sumW += w;\n    double avgScore = totalScore / M;\n    double avgW = (double)sumW / M;\n    double lengthCoeff = (avgW > 0) ? LENGTH_COEFF_RATIO * avgScore / avgW : 0.0;\n    for(int i=0;i<M;++i){\n        score[i] += lengthCoeff * W[i];\n        if(score[i] <= 0) score[i] = 1e-9;\n    }\n    return score;\n}\n\nvoid initialize_state(){\n    assignment.assign(M, -1);\n    dayEdges.assign(D, {});\n    edgePos.assign(M, -1);\n    dayScore.assign(D, 0.0);\n    dayCount.assign(D, 0);\n    vertexDayCount.assign(N*D, 0);\n    dayBlocked.assign(D, vector<char>(M, 0));\n}\n\nvoid move_edge(int eid, int newDay){\n    int oldDay = assignment[eid];\n    if(oldDay == newDay) return;\n    double s = edgeScore[eid];\n    if(oldDay != -1){\n        auto &vec = dayEdges[oldDay];\n        int pos = edgePos[eid];\n        int last = vec.back();\n        if(pos != (int)vec.size()-1){\n            vec[pos] = last;\n            edgePos[last] = pos;\n        }\n        vec.pop_back();\n        dayScore[oldDay] -= s;\n        dayCount[oldDay]--;\n        vertexDayCount[U[eid]*D + oldDay]--;\n        vertexDayCount[V[eid]*D + oldDay]--;\n        dayBlocked[oldDay][eid] = 0;\n    }\n    assignment[eid] = newDay;\n    if(newDay != -1){\n        auto &vec = dayEdges[newDay];\n        edgePos[eid] = vec.size();\n        vec.push_back(eid);\n        dayScore[newDay] += s;\n        dayCount[newDay]++;\n        vertexDayCount[U[eid]*D + newDay]++;\n        vertexDayCount[V[eid]*D + newDay]++;\n        dayBlocked[newDay][eid] = 1;\n    }else edgePos[eid] = -1;\n}\n\ndouble move_delta(int eid, int fromDay, int toDay){\n    double s = edgeScore[eid];\n    double delta = s * (dayScore[toDay] - dayScore[fromDay]);\n    int u = U[eid], v = V[eid];\n    delta += alphaCoeff * ((vertexDayCount[u*D + toDay] + vertexDayCount[v*D + toDay])\n                         - (vertexDayCount[u*D + fromDay] + vertexDayCount[v*D + fromDay]));\n    delta += betaCoeff * (dayCount[toDay] - dayCount[fromDay]);\n    return delta;\n}\n\nbool is_day_connected_plain(int day){\n    DSU dsu(N);\n    for(int eid=0; eid<M; ++eid){\n        if(assignment[eid] == day) continue;\n        dsu.unite(U[eid], V[eid]);\n    }\n    return dsu.components == 1;\n}\n\nint build_components_without_day(int day, vector<int> &comp){\n    DSU dsu(N);\n    for(int eid=0; eid<M; ++eid){\n        if(assignment[eid] == day) continue;\n        dsu.unite(U[eid], V[eid]);\n    }\n    if((int)comp.size()!=N) comp.assign(N, 0);\n    vector<int> rootId(N, -1);\n    int comps = 0;\n    for(int i=0;i<N;++i){\n        int r = dsu.find(i);\n        if(rootId[r]==-1) rootId[r]=comps++;\n        comp[i]=rootId[r];\n    }\n    return comps;\n}\n\nint pick_low_score_edge(int day){\n    if(dayEdges[day].empty()) return -1;\n    int best = dayEdges[day][0];\n    double bestScore = edgeScore[best];\n    for(int eid : dayEdges[day]){\n        if(edgeScore[eid] < bestScore){\n            bestScore = edgeScore[eid];\n            best = eid;\n        }\n    }\n    return best;\n}\n\nbool attempt_swap_move_basic(int eid, int targetDay){\n    int fromDay = assignment[eid];\n    int swapEdge = pick_low_score_edge(targetDay);\n    if(swapEdge == -1) return false;\n    move_edge(eid, -1);\n    move_edge(swapEdge, fromDay);\n    move_edge(eid, targetDay);\n    if(!is_day_connected_plain(targetDay) || !is_day_connected_plain(fromDay)){\n        move_edge(swapEdge, targetDay);\n        move_edge(eid, fromDay);\n        return false;\n    }\n    return true;\n}\n\nbool try_move_edge_from_day(int eid, int day){\n    vector<pair<double,int>> withSlot;\n    vector<pair<double,int>> noSlot;\n    for(int d=0; d<D; ++d){\n        if(d==day) continue;\n        double delta = move_delta(eid, day, d);\n        if(dayCount[d] < K) withSlot.emplace_back(delta, d);\n        else noSlot.emplace_back(delta, d);\n    }\n    sort(withSlot.begin(), withSlot.end());\n    for(auto [delta, d] : withSlot){\n        move_edge(eid, d);\n        if(is_day_connected_plain(day) && is_day_connected_plain(d)) return true;\n        move_edge(eid, day);\n    }\n    for(auto [delta, d] : withSlot){\n        move_edge(eid, d);\n        return true;\n    }\n    sort(noSlot.begin(), noSlot.end());\n    for(auto [delta, d] : noSlot){\n        if(attempt_swap_move_basic(eid, d)) return true;\n    }\n    return false;\n}\n\nvoid enforce_connectivity(Timer &timer){\n    vector<int> comp(N);\n    int outerGuard = 0;\n    while(timer.elapsed() < TOTAL_TIME_LIMIT - 0.4 && outerGuard < 4*D){\n        bool changed = false;\n        for(int day=0; day<D; ++day){\n            if(timer.elapsed() > TOTAL_TIME_LIMIT - 0.45) return;\n            int guard = 0;\n            while(guard < M){\n                int comps = build_components_without_day(day, comp);\n                if(comps <= 1) break;\n                vector<int> critical;\n                for(int eid : dayEdges[day]){\n                    if(comp[U[eid]] != comp[V[eid]]) critical.push_back(eid);\n                }\n                if(critical.empty()) break;\n                sort(critical.begin(), critical.end(), [&](int a,int b){\n                    if(edgeScore[a]!=edgeScore[b]) return edgeScore[a] > edgeScore[b];\n                    return a<b;\n                });\n                bool moved = false;\n                for(int eid : critical){\n                    if(try_move_edge_from_day(eid, day)){\n                        changed = true;\n                        moved = true;\n                        break;\n                    }\n                }\n                if(!moved) break;\n                ++guard;\n            }\n        }\n        if(!changed) break;\n        ++outerGuard;\n    }\n}\n\nvoid greedy_initial_assignment(const vector<int> &order){\n    for(int eid : order){\n        double bestVal = numeric_limits<double>::infinity();\n        int bestDay = -1;\n        double s = edgeScore[eid];\n        int u = U[eid], v = V[eid];\n        int baseU = u*D, baseV = v*D;\n        for(int day=0; day<D; ++day){\n            if(dayCount[day] >= K) continue;\n            double val = dayScore[day] * s\n                       + alphaCoeff * (vertexDayCount[baseU + day] + vertexDayCount[baseV + day])\n                       + betaCoeff  * dayCount[day];\n            if(val < bestVal - 1e-12){\n                bestVal = val;\n                bestDay = day;\n            }\n        }\n        if(bestDay == -1){\n            bestDay = min_element(dayCount.begin(), dayCount.end()) - dayCount.begin();\n        }\n        move_edge(eid, bestDay);\n    }\n}\n\nvoid local_search(Timer &timer){\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    bool improved = true;\n    while(improved && timer.elapsed() < LOCAL_SEARCH_LIMIT){\n        improved = false;\n        shuffle(idx.begin(), idx.end(), rng);\n        for(int eid : idx){\n            if(timer.elapsed() > LOCAL_SEARCH_LIMIT) return;\n            int oldDay = assignment[eid];\n            vector<pair<double,int>> cand;\n            cand.reserve(D-1);\n            for(int day=0; day<D; ++day){\n                if(day == oldDay) continue;\n                if(dayCount[day] >= K) continue;\n                double delta = move_delta(eid, oldDay, day);\n                cand.emplace_back(delta, day);\n            }\n            sort(cand.begin(), cand.end());\n            for(auto [delta, day] : cand){\n                if(delta >= -MOVE_EPS) break;\n                move_edge(eid, day);\n                if(is_day_connected_plain(oldDay) && is_day_connected_plain(day)){\n                    improved = true;\n                    break;\n                }else{\n                    move_edge(eid, oldDay);\n                }\n            }\n        }\n    }\n}\n\ndouble compute_full_eval(){\n    if(sampleSources.empty()) return 0.0;\n    int S = sampleSources.size();\n    daySampleDist.assign(D, vector<vector<ll>>(S, vector<ll>(N)));\n    daySampleSum.assign(D, vector<double>(S, 0.0));\n    dayEval.assign(D, 0.0);\n    vector<ll> dist(N);\n    double total = 0.0;\n    for(int day=0; day<D; ++day){\n        double sumSamples = 0.0;\n        for(int s=0; s<S; ++s){\n            dijkstra_with_block(sampleSources[s], &dayBlocked[day], dist);\n            daySampleDist[day][s] = dist;\n            long double diffSum = 0.0;\n            const auto &base = baseDist[s];\n            for(int v=0; v<N; ++v){\n                ll ref = base[v];\n                if(ref >= INFLL/4) ref = 1000000000LL;\n                ll cur = dist[v];\n                ll diff;\n                if(cur >= INFLL/4) diff = 1000000000LL - ref;\n                else diff = cur - ref;\n                if(diff < 0) diff = 0;\n                diffSum += diff;\n            }\n            double norm = diffSum / (double)max(1, N-1);\n            daySampleSum[day][s] = norm;\n            sumSamples += norm;\n        }\n        dayEval[day] = sumSamples / S;\n        total += dayEval[day];\n    }\n    return total / D;\n}\n\nvoid compute_day_temp(int day, vector<vector<ll>> &bufDist, vector<double> &bufSum, vector<ll> &scratch){\n    int S = sampleSources.size();\n    for(int s=0; s<S; ++s){\n        dijkstra_with_block(sampleSources[s], &dayBlocked[day], scratch);\n        bufDist[s] = scratch;\n        long double diffSum = 0.0;\n        const auto &base = baseDist[s];\n        for(int v=0; v<N; ++v){\n            ll ref = base[v];\n            if(ref >= INFLL/4) ref = 1000000000LL;\n            ll cur = scratch[v];\n            ll diff;\n            if(cur >= INFLL/4) diff = 1000000000LL - ref;\n            else diff = cur - ref;\n            if(diff < 0) diff = 0;\n            diffSum += diff;\n        }\n        bufSum[s] = diffSum / (double)max(1, N-1);\n    }\n}\n\nbool try_move_eval(int eid, int newDay, double &currentScore,\n                   vector<vector<ll>> &tempOld,\n                   vector<vector<ll>> &tempNew,\n                   vector<double> &tempSumOld,\n                   vector<double> &tempSumNew,\n                   vector<ll> &scratch){\n    int oldDay = assignment[eid];\n    if(oldDay == newDay) return false;\n    if(dayCount[newDay] >= K) return false;\n    move_edge(eid, newDay);\n    if(!is_day_connected_plain(oldDay) || !is_day_connected_plain(newDay)){\n        move_edge(eid, oldDay);\n        return false;\n    }\n    compute_day_temp(oldDay, tempOld, tempSumOld, scratch);\n    compute_day_temp(newDay, tempNew, tempSumNew, scratch);\n    double evalOld = accumulate(tempSumOld.begin(), tempSumOld.end(), 0.0) / sampleSources.size();\n    double evalNew = accumulate(tempSumNew.begin(), tempSumNew.end(), 0.0) / sampleSources.size();\n    double newTotal = currentScore - dayEval[oldDay] - dayEval[newDay] + evalOld + evalNew;\n    if(newTotal < currentScore - 1e-6){\n        for(size_t s=0; s<sampleSources.size(); ++s){\n            daySampleDist[oldDay][s] = tempOld[s];\n            daySampleDist[newDay][s] = tempNew[s];\n            daySampleSum[oldDay][s] = tempSumOld[s];\n            daySampleSum[newDay][s] = tempSumNew[s];\n        }\n        dayEval[oldDay] = evalOld;\n        dayEval[newDay] = evalNew;\n        currentScore = newTotal;\n        return true;\n    }else{\n        move_edge(eid, oldDay);\n        return false;\n    }\n}\n\nbool try_swap_eval(int eid, int targetDay, int swapEdge, double &currentScore,\n                   vector<vector<ll>> &tempOld,\n                   vector<vector<ll>> &tempNew,\n                   vector<double> &tempSumOld,\n                   vector<double> &tempSumNew,\n                   vector<ll> &scratch){\n    int oldDay = assignment[eid];\n    if(oldDay == targetDay) return false;\n    if(assignment[swapEdge] != targetDay) return false;\n    move_edge(eid, -1);\n    move_edge(swapEdge, oldDay);\n    move_edge(eid, targetDay);\n    if(!is_day_connected_plain(oldDay) || !is_day_connected_plain(targetDay)){\n        move_edge(swapEdge, targetDay);\n        move_edge(eid, oldDay);\n        return false;\n    }\n    compute_day_temp(oldDay, tempOld, tempSumOld, scratch);\n    compute_day_temp(targetDay, tempNew, tempSumNew, scratch);\n    double evalOld = accumulate(tempSumOld.begin(), tempSumOld.end(), 0.0) / sampleSources.size();\n    double evalNew = accumulate(tempSumNew.begin(), tempSumNew.end(), 0.0) / sampleSources.size();\n    double newTotal = currentScore - dayEval[oldDay] - dayEval[targetDay] + evalOld + evalNew;\n    if(newTotal < currentScore - 1e-6){\n        for(size_t s=0; s<sampleSources.size(); ++s){\n            daySampleDist[oldDay][s] = tempOld[s];\n            daySampleDist[targetDay][s] = tempNew[s];\n            daySampleSum[oldDay][s] = tempSumOld[s];\n            daySampleSum[targetDay][s] = tempSumNew[s];\n        }\n        dayEval[oldDay] = evalOld;\n        dayEval[targetDay] = evalNew;\n        currentScore = newTotal;\n        return true;\n    }else{\n        move_edge(swapEdge, targetDay);\n        move_edge(eid, oldDay);\n        return false;\n    }\n}\n\nvector<int> get_low_edges(int day, int limit){\n    vector<pair<double,int>> arr;\n    arr.reserve(dayEdges[day].size());\n    for(int eid : dayEdges[day]) arr.push_back({edgeScore[eid], eid});\n    if(arr.empty()) return {};\n    if((int)arr.size() > limit){\n        nth_element(arr.begin(), arr.begin()+limit, arr.end(),\n                    [](const auto &a, const auto &b){ return a.first < b.first; });\n        arr.resize(limit);\n    }\n    sort(arr.begin(), arr.end(),\n         [](const auto &a, const auto &b){ return a.first < b.first; });\n    vector<int> res;\n    res.reserve(arr.size());\n    for(auto &p : arr) res.push_back(p.second);\n    return res;\n}\n\nvoid sample_based_improve(double &currentScore, Timer &timer){\n    if(sampleSources.empty()) return;\n    const double TIME_MARGIN = 0.2;\n    int S = sampleSources.size();\n    vector<vector<ll>> tempDistA(S, vector<ll>(N));\n    vector<vector<ll>> tempDistB(S, vector<ll>(N));\n    vector<double> tempSumA(S), tempSumB(S);\n    vector<ll> scratch(N);\n    while(timer.elapsed() < TOTAL_TIME_LIMIT - TIME_MARGIN){\n        vector<int> dayOrder(D);\n        iota(dayOrder.begin(), dayOrder.end(), 0);\n        sort(dayOrder.begin(), dayOrder.end(), [&](int a,int b){\n            return dayEval[a] > dayEval[b];\n        });\n        bool improved = false;\n        int considerDays = min(D, 3);\n        for(int idx=0; idx<considerDays && !improved; ++idx){\n            int srcDay = dayOrder[idx];\n            auto edges = dayEdges[srcDay];\n            if(edges.empty()) continue;\n            sort(edges.begin(), edges.end(), [&](int a,int b){\n                return edgeScore[a] > edgeScore[b];\n            });\n            if((int)edges.size() > 15) edges.resize(15);\n            for(int eid : edges){\n                if(timer.elapsed() > TOTAL_TIME_LIMIT - TIME_MARGIN) break;\n                int oldDay = assignment[eid];\n                vector<pair<double,int>> candMove;\n                vector<pair<double,int>> candSwap;\n                for(int day=0; day<D; ++day){\n                    if(day==oldDay) continue;\n                    double approx = move_delta(eid, oldDay, day);\n                    if(dayCount[day] < K) candMove.emplace_back(approx, day);\n                    else candSwap.emplace_back(approx, day);\n                }\n                sort(candMove.begin(), candMove.end());\n                sort(candSwap.begin(), candSwap.end());\n                int moveLimit = min((int)candMove.size(), 6);\n                for(int i=0;i<moveLimit && timer.elapsed() < TOTAL_TIME_LIMIT - TIME_MARGIN; ++i){\n                    int day = candMove[i].second;\n                    if(try_move_eval(eid, day, currentScore,\n                                     tempDistA, tempDistB,\n                                     tempSumA, tempSumB, scratch)){\n                        improved = true;\n                        break;\n                    }\n                }\n                if(improved) break;\n                int swapDayLimit = min((int)candSwap.size(), 4);\n                for(int i=0;i<swapDayLimit && !improved && timer.elapsed() < TOTAL_TIME_LIMIT - TIME_MARGIN; ++i){\n                    int day = candSwap[i].second;\n                    auto lowEdges = get_low_edges(day, 4);\n                    for(int swapEdge : lowEdges){\n                        if(try_swap_eval(eid, day, swapEdge, currentScore,\n                                         tempDistA, tempDistB,\n                                         tempSumA, tempSumB, scratch)){\n                            improved = true;\n                            break;\n                        }\n                    }\n                }\n                if(improved) break;\n            }\n        }\n        if(!improved) break;\n    }\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Timer timer;\n    if(!(cin >> N >> M >> D >> K)) return 0;\n    U.resize(M); V.resize(M); W.resize(M);\n    graphAdj.assign(N, {});\n    for(int i=0;i<M;++i){\n        int u,v,w;\n        cin >> u >> v >> w;\n        --u; --v;\n        U[i]=u; V[i]=v; W[i]=w;\n        graphAdj[u].push_back({v,i});\n        graphAdj[v].push_back({u,i});\n    }\n    for(int i=0;i<N;++i){\n        int x,y;\n        cin >> x >> y;\n        (void)x; (void)y;\n    }\n\n    select_samples_and_base();\n    edgeScore = compute_edge_scores(timer);\n\n    vector<int> bestAssignment;\n    double bestApprox = 1e300;\n    uniform_real_distribution<double> noiseDist(-1.0, 1.0);\n\n    int run = 0;\n    while(run < MAX_RUNS){\n        if(run>0 && TOTAL_TIME_LIMIT - timer.elapsed() < MIN_REMAIN_FOR_NEW_RUN) break;\n\n        initialize_state();\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        vector<double> key(M);\n        double noiseLevel = (run==0 ? 0.0 : 0.2);\n        for(int i=0;i<M;++i){\n            double noise = noiseLevel * noiseDist(rng);\n            key[i] = edgeScore[i] * (1.0 + noise);\n        }\n        sort(order.begin(), order.end(), [&](int a,int b){\n            if(key[a]!=key[b]) return key[a] > key[b];\n            return a<b;\n        });\n\n        greedy_initial_assignment(order);\n        enforce_connectivity(timer);\n        local_search(timer);\n        enforce_connectivity(timer);\n\n        double approxScore = compute_full_eval();\n        sample_based_improve(approxScore, timer);\n\n        if(approxScore < bestApprox){\n            bestApprox = approxScore;\n            bestAssignment = assignment;\n        }\n        ++run;\n    }\n\n    if(bestAssignment.empty()) bestAssignment = assignment;\n\n    for(int i=0;i<M;++i){\n        if(i) cout << ' ';\n        cout << bestAssignment[i] + 1;\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Segment {\n    int x, y;\n    int z0;\n    int len;\n};\n\nstruct Builder {\n    bool active = false;\n    int start = 0;\n    int len = 0;\n};\n\nstruct LayerAssign {\n    vector<pair<int,int>> pairs;\n    vector<int> assigned_y_for_x;\n    vector<int> assigned_x_for_y;\n};\n\nint rand_pick(const vector<int>& cand, mt19937* rng) {\n    if (cand.empty()) return -1;\n    if (!rng) return cand.front();\n    uniform_int_distribution<int> dist(0, (int)cand.size() - 1);\n    return cand[dist(*rng)];\n}\n\nLayerAssign assign_x_major(\n        int D,\n        const vector<int>& X,\n        const vector<int>& Y,\n        const vector<int>& prev_y_for_x,\n        const vector<int>& prev_x_for_y,\n        mt19937* rng) {\n\n    LayerAssign res;\n    res.assigned_y_for_x.assign(D, -1);\n    res.assigned_x_for_y.assign(D, -1);\n    if (Y.empty()) return res;\n\n    vector<char> y_present(D, 0);\n    for (int y : Y) y_present[y] = 1;\n    vector<char> x_used(D, 0);\n\n    auto choose_with_prev = [&](int target_y) -> int {\n        vector<int> cand;\n        for (int x : X) if (!x_used[x] && prev_y_for_x[x] == target_y) cand.push_back(x);\n        return rand_pick(cand, rng);\n    };\n    auto choose_any = [&]() -> int {\n        vector<int> cand;\n        for (int x : X) if (!x_used[x]) cand.push_back(x);\n        return rand_pick(cand, rng);\n    };\n\n    for (int y : Y) {\n        int x = choose_with_prev(y);\n        if (x == -1) x = choose_any();\n        if (x == -1) x = X.front();\n        x_used[x] = 1;\n        res.assigned_y_for_x[x] = y;\n        res.assigned_x_for_y[y] = x;\n        res.pairs.emplace_back(x, y);\n    }\n\n    if (!Y.empty()) {\n        size_t ptr = 0;\n        for (int x : X) {\n            if (x_used[x]) continue;\n            int y = -1;\n            if (prev_y_for_x[x] != -1 && y_present[prev_y_for_x[x]]) y = prev_y_for_x[x];\n            else {\n                y = Y[ptr];\n                ptr = (ptr + 1) % Y.size();\n            }\n            x_used[x] = 1;\n            res.assigned_y_for_x[x] = y;\n            res.assigned_x_for_y[y] = x;\n            res.pairs.emplace_back(x, y);\n        }\n    }\n    return res;\n}\n\nLayerAssign assign_y_major(\n        int D,\n        const vector<int>& X,\n        const vector<int>& Y,\n        const vector<int>& prev_y_for_x,\n        const vector<int>& prev_x_for_y,\n        mt19937* rng) {\n\n    LayerAssign res;\n    res.assigned_y_for_x.assign(D, -1);\n    res.assigned_x_for_y.assign(D, -1);\n    if (X.empty()) return res;\n\n    vector<char> x_present(D, 0);\n    for (int x : X) x_present[x] = 1;\n    vector<char> y_used(D, 0);\n\n    auto choose_with_prev = [&](int target_x) -> int {\n        vector<int> cand;\n        for (int y : Y) if (!y_used[y] && prev_x_for_y[y] == target_x) cand.push_back(y);\n        return rand_pick(cand, rng);\n    };\n    auto choose_any = [&]() -> int {\n        vector<int> cand;\n        for (int y : Y) if (!y_used[y]) cand.push_back(y);\n        return rand_pick(cand, rng);\n    };\n\n    for (int x : X) {\n        int y = choose_with_prev(x);\n        if (y == -1) y = choose_any();\n        if (y == -1) y = Y.front();\n        y_used[y] = 1;\n        res.assigned_y_for_x[x] = y;\n        res.assigned_x_for_y[y] = x;\n        res.pairs.emplace_back(x, y);\n    }\n\n    if (!X.empty()) {\n        size_t ptr = 0;\n        for (int y : Y) {\n            if (y_used[y]) continue;\n            int x = -1;\n            if (prev_x_for_y[y] != -1 && x_present[prev_x_for_y[y]]) x = prev_x_for_y[y];\n            else {\n                x = X[ptr];\n                ptr = (ptr + 1) % X.size();\n            }\n            y_used[y] = 1;\n            res.assigned_x_for_y[y] = x;\n            res.assigned_y_for_x[x] = y;\n            res.pairs.emplace_back(x, y);\n        }\n    }\n    return res;\n}\n\nvector<Segment> build_segments(int D, const vector<string>& front, const vector<string>& right, mt19937* rng) {\n    vector<Segment> segments;\n    vector<vector<Builder>> builder(D, vector<Builder>(D));\n    vector<vector<char>> stay(D, vector<char>(D, 0));\n    vector<int> prev_y_for_x(D, -1), prev_x_for_y(D, -1);\n    uniform_real_distribution<double> dist(0.0, 1.0);\n\n    for (int z = 0; z < D; ++z) {\n        vector<int> X, Y;\n        for (int x = 0; x < D; ++x) if (front[z][x] == '1') X.push_back(x);\n        for (int y = 0; y < D; ++y) if (right[z][y] == '1') Y.push_back(y);\n        if (rng) {\n            shuffle(X.begin(), X.end(), *rng);\n            shuffle(Y.begin(), Y.end(), *rng);\n        }\n\n        bool use_x_major;\n        if (X.size() == Y.size()) use_x_major = true;\n        else use_x_major = X.size() >= Y.size();\n        if (rng && dist(*rng) < 0.25) use_x_major = !use_x_major;\n\n        LayerAssign assign = use_x_major\n            ? assign_x_major(D, X, Y, prev_y_for_x, prev_x_for_y, rng)\n            : assign_y_major(D, X, Y, prev_y_for_x, prev_x_for_y, rng);\n\n        for (int x = 0; x < D; ++x)\n            fill(stay[x].begin(), stay[x].end(), 0);\n\n        for (auto [x, y] : assign.pairs) {\n            if (!builder[x][y].active) {\n                builder[x][y].active = true;\n                builder[x][y].start = z;\n                builder[x][y].len = 0;\n            }\n            builder[x][y].len++;\n            stay[x][y] = 1;\n        }\n\n        for (int x = 0; x < D; ++x)\n            for (int y = 0; y < D; ++y)\n                if (builder[x][y].active && !stay[x][y]) {\n                    segments.push_back({x, y, builder[x][y].start, builder[x][y].len});\n                    builder[x][y].active = false;\n                }\n\n        prev_y_for_x = assign.assigned_y_for_x;\n        prev_x_for_y = assign.assigned_x_for_y;\n    }\n\n    for (int x = 0; x < D; ++x)\n        for (int y = 0; y < D; ++y)\n            if (builder[x][y].active) {\n                segments.push_back({x, y, builder[x][y].start, builder[x][y].len});\n                builder[x][y].active = false;\n            }\n    return segments;\n}\n\nstruct PQNode {\n    int len, idx;\n};\nstruct PQCmp {\n    bool operator()(const PQNode& a, const PQNode& b) const { return a.len < b.len; }\n};\n\nPQNode pop_valid(priority_queue<PQNode, vector<PQNode>, PQCmp>& pq,\n                 const vector<Segment>& segs,\n                 const vector<int>& partner) {\n    while (!pq.empty()) {\n        auto node = pq.top(); pq.pop();\n        if (node.idx >= (int)segs.size()) continue;\n        if (partner[node.idx] != -1) continue;\n        if (segs[node.idx].len != node.len) {\n            pq.push({segs[node.idx].len, node.idx});\n            continue;\n        }\n        return node;\n    }\n    return {-1,-1};\n}\n\nint split_segment(vector<Segment>& segs, vector<int>& partner, int idx, int take_len) {\n    Segment seg = segs[idx];\n    Segment newSeg{seg.x, seg.y, seg.z0, take_len};\n    segs[idx].z0 += take_len;\n    segs[idx].len -= take_len;\n    int newIdx = segs.size();\n    segs.push_back(newSeg);\n    partner.push_back(-1);\n    return newIdx;\n}\n\nvoid align_segments(vector<Segment>& seg0, vector<Segment>& seg1,\n                    vector<int>& partner0, vector<int>& partner1) {\n    partner0.assign(seg0.size(), -1);\n    partner1.assign(seg1.size(), -1);\n    priority_queue<PQNode, vector<PQNode>, PQCmp> pq0, pq1;\n    for (int i = 0; i < (int)seg0.size(); ++i) pq0.push({seg0[i].len, i});\n    for (int i = 0; i < (int)seg1.size(); ++i) pq1.push({seg1[i].len, i});\n\n    while (true) {\n        auto node0 = pop_valid(pq0, seg0, partner0);\n        if (node0.idx == -1) break;\n        auto node1 = pop_valid(pq1, seg1, partner1);\n        if (node1.idx == -1) break;\n\n        int idx0 = node0.idx, idx1 = node1.idx;\n        if (node0.len == node1.len) {\n            partner0[idx0] = idx1;\n            partner1[idx1] = idx0;\n        } else if (node0.len > node1.len) {\n            int newIdx = split_segment(seg0, partner0, idx0, node1.len);\n            partner0[newIdx] = idx1;\n            partner1[idx1] = newIdx;\n            pq0.push({seg0[idx0].len, idx0});\n        } else {\n            int newIdx = split_segment(seg1, partner1, idx1, node0.len);\n            partner0[idx0] = newIdx;\n            partner1[newIdx] = idx0;\n            pq1.push({seg1[idx1].len, idx1});\n        }\n    }\n}\n\nvector<int> hungarian(const vector<vector<long long>>& cost) {\n    int n = cost.size();\n    vector<long long> u(n + 1, 0), v(n + 1, 0);\n    vector<int> p(n + 1, 0), way(n + 1, 0);\n\n    for (int i = 1; i <= n; ++i) {\n        p[0] = i;\n        int j0 = 0;\n        vector<long long> minv(n + 1, (long long)4e18);\n        vector<char> used(n + 1, false);\n        do {\n            used[j0] = true;\n            int i0 = p[j0], j1 = 0;\n            long long delta = (long long)4e18;\n            for (int j = 1; j <= n; ++j) if (!used[j]) {\n                long long cur = cost[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= n; ++j) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    v[j] -= delta;\n                } else {\n                    minv[j] -= delta;\n                }\n            }\n            j0 = j1;\n        } while (p[j0] != 0);\n        do {\n            int j1 = way[j0];\n            p[j0] = p[j1];\n            j0 = j1;\n        } while (j0);\n    }\n    vector<int> match(n, -1);\n    for (int j = 1; j <= n; ++j)\n        if (p[j]) match[p[j] - 1] = j - 1;\n    return match;\n}\n\nvoid optimize_pairing(const vector<Segment>& seg0, const vector<Segment>& seg1,\n                      vector<int>& partner0, vector<int>& partner1) {\n    unordered_map<int, vector<int>> len_rows;\n    len_rows.reserve(seg0.size() * 2);\n    for (int i = 0; i < (int)seg0.size(); ++i) {\n        if (partner0[i] == -1) continue;\n        len_rows[seg0[i].len].push_back(i);\n    }\n    for (auto& kv : len_rows) {\n        vector<int>& rows = kv.second;\n        int m = rows.size();\n        if (m <= 1) continue;\n        vector<int> cols;\n        cols.reserve(m);\n        for (int idx : rows) cols.push_back(partner0[idx]);\n\n        vector<vector<long long>> cost(m, vector<long long>(m, 0));\n        for (int i = 0; i < m; ++i) {\n            auto& s0 = seg0[rows[i]];\n            for (int j = 0; j < m; ++j) {\n                auto& s1 = seg1[cols[j]];\n                long long dx = abs(s0.x - s1.x);\n                long long dy = abs(s0.y - s1.y);\n                long long dz = abs(s0.z0 - s1.z0);\n                cost[i][j] = dx * 100 + dy * 100 + dz;\n            }\n        }\n        vector<int> match = hungarian(cost);\n        vector<int> inv(m);\n        for (int i = 0; i < m; ++i) inv[match[i]] = i;\n        for (int i = 0; i < m; ++i) {\n            int s0 = rows[i];\n            int s1 = cols[match[i]];\n            partner0[s0] = s1;\n        }\n        for (int j = 0; j < m; ++j) {\n            int s1 = cols[j];\n            int s0 = rows[inv[j]];\n            partner1[s1] = s0;\n        }\n    }\n}\n\nvoid extend_shared_segments(\n        int D,\n        vector<Segment>& seg0,\n        vector<Segment>& seg1,\n        const vector<int>& partner0,\n        const vector<string>& f0,\n        const vector<string>& r0,\n        const vector<string>& f1,\n        const vector<string>& r1) {\n\n    vector<vector<vector<char>>> occ0(D, vector<vector<char>>(D, vector<char>(D, 0)));\n    vector<vector<vector<char>>> occ1(D, vector<vector<char>>(D, vector<char>(D, 0)));\n\n    for (auto& s : seg0)\n        for (int dz = 0; dz < s.len; ++dz)\n            occ0[s.x][s.y][s.z0 + dz] = 1;\n\n    for (auto& s : seg1)\n        for (int dz = 0; dz < s.len; ++dz)\n            occ1[s.x][s.y][s.z0 + dz] = 1;\n\n    for (int i = 0; i < (int)seg0.size(); ++i) {\n        int j = partner0[i];\n        if (j == -1) continue;\n        auto& s0 = seg0[i];\n        auto& s1 = seg1[j];\n        while (true) {\n            bool changed = false;\n            int nz0 = s0.z0 - 1;\n            int nz1 = s1.z0 - 1;\n            if (nz0 >= 0 && nz1 >= 0 &&\n                f0[nz0][s0.x] == '1' && r0[nz0][s0.y] == '1' &&\n                f1[nz1][s1.x] == '1' && r1[nz1][s1.y] == '1' &&\n                !occ0[s0.x][s0.y][nz0] &&\n                !occ1[s1.x][s1.y][nz1]) {\n\n                s0.z0--; s0.len++;\n                s1.z0--; s1.len++;\n                occ0[s0.x][s0.y][nz0] = 1;\n                occ1[s1.x][s1.y][nz1] = 1;\n                changed = true;\n            }\n            nz0 = s0.z0 + s0.len;\n            nz1 = s1.z0 + s1.len;\n            if (nz0 < D && nz1 < D &&\n                f0[nz0][s0.x] == '1' && r0[nz0][s0.y] == '1' &&\n                f1[nz1][s1.x] == '1' && r1[nz1][s1.y] == '1' &&\n                !occ0[s0.x][s0.y][nz0] &&\n                !occ1[s1.x][s1.y][nz1]) {\n\n                s0.len++;\n                s1.len++;\n                occ0[s0.x][s0.y][nz0] = 1;\n                occ1[s1.x][s1.y][nz1] = 1;\n                changed = true;\n            }\n            if (!changed) break;\n        }\n    }\n}\n\nstruct BlockSpec {\n    int seg0 = -1;\n    int seg1 = -1;\n};\n\nstruct BlockUsage {\n    bool used = false;\n    int x = 0, y = 0;\n    int z0 = 0;\n    int len = 0;\n};\n\nbool overlap_span(const BlockUsage& a, const BlockUsage& b) {\n    int l = max(a.z0, b.z0);\n    int r = min(a.z0 + a.len, b.z0 + b.len);\n    return l < r;\n}\n\npair<int,int> rotate_vec(pair<int,int> d, int rot) {\n    int dx = d.first, dy = d.second;\n    if (rot == 0) return {dx, dy};\n    if (rot == 1) return {-dy, dx};\n    if (rot == 2) return {-dx, -dy};\n    return {dy, -dx};\n}\n\nint rotation_needed(pair<int,int> d0, pair<int,int> d1) {\n    for (int rot = 0; rot < 4; ++rot) {\n        auto t = rotate_vec(d0, rot);\n        if (t == d1) return rot;\n    }\n    return -1;\n}\n\nvoid merge_shared_blocks(\n        int& n,\n        vector<int>& grid0,\n        vector<int>& grid1,\n        const vector<Segment>& seg0,\n        const vector<Segment>& seg1,\n        const vector<int>& block_seg0,\n        const vector<int>& block_seg1) {\n\n    vector<array<BlockUsage,2>> info(n + 1);\n    for (int id = 0; id < n; ++id) {\n        if (block_seg0[id] != -1) {\n            auto& s = seg0[block_seg0[id]];\n            info[id + 1][0] = {true, s.x, s.y, s.z0, s.len};\n        }\n        if (block_seg1[id] != -1) {\n            auto& s = seg1[block_seg1[id]];\n            info[id + 1][1] = {true, s.x, s.y, s.z0, s.len};\n        }\n    }\n\n    vector<tuple<int,int,int,int>> edges;\n    edges.reserve(n * 4);\n    for (int a = 1; a <= n; ++a) {\n        auto& a0 = info[a][0];\n        auto& a1 = info[a][1];\n        if (!(a0.used && a1.used)) continue;\n        for (int b = a + 1; b <= n; ++b) {\n            auto& b0 = info[b][0];\n            auto& b1 = info[b][1];\n            if (!(b0.used && b1.used)) continue;\n            if (!overlap_span(a0, b0)) continue;\n            if (!overlap_span(a1, b1)) continue;\n            if (abs(a0.x - b0.x) + abs(a0.y - b0.y) != 1) continue;\n            if (abs(a1.x - b1.x) + abs(a1.y - b1.y) != 1) continue;\n            if ((b0.z0 - a0.z0) != (b1.z0 - a1.z0)) continue;\n\n            pair<int,int> d0 = {b0.x - a0.x, b0.y - a0.y};\n            pair<int,int> d1 = {b1.x - a1.x, b1.y - a1.y};\n            int rot = rotation_needed(d0, d1);\n            if (rot == -1) continue;\n\n            int score = a0.len + b0.len;\n            edges.emplace_back(-score, a, b, rot);\n        }\n    }\n    if (edges.empty()) return;\n\n    sort(edges.begin(), edges.end());\n\n    vector<int> parent(n + 1);\n    vector<int> compRot(n + 1, -1);\n    iota(parent.begin(), parent.end(), 0);\n\n    function<int(int)> findp = [&](int x) {\n        if (parent[x] == x) return x;\n        return parent[x] = findp(parent[x]);\n    };\n\n    for (auto [neg_score, a, b, rotReq] : edges) {\n        int ra = findp(a);\n        int rb = findp(b);\n        if (ra == rb) continue;\n        int rota = compRot[ra];\n        int rotb = compRot[rb];\n        if (rota != -1 && rota != rotReq) continue;\n        if (rotb != -1 && rotb != rotReq) continue;\n        parent[rb] = ra;\n        if (rota == -1) {\n            compRot[ra] = (rotb == -1 ? rotReq : rotb);\n        } else {\n            compRot[ra] = rota;\n        }\n    }\n\n    vector<int> newId(n + 1, -1);\n    int cnt = 0;\n    for (int i = 1; i <= n; ++i)\n        if (findp(i) == i) newId[i] = ++cnt;\n    for (int i = 1; i <= n; ++i)\n        newId[i] = newId[findp(i)];\n\n    for (int& v : grid0) if (v > 0) v = newId[v];\n    for (int& v : grid1) if (v > 0) v = newId[v];\n    n = cnt;\n}\n\nbool verify(int D, const vector<int>& grid,\n            const vector<string>& front, const vector<string>& right) {\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n    for (int z = 0; z < D; ++z) {\n        for (int x = 0; x < D; ++x) {\n            bool occ = false;\n            for (int y = 0; y < D; ++y)\n                if (grid[idx(x, y, z)]) { occ = true; break; }\n            if (occ != (front[z][x] == '1')) return false;\n        }\n        for (int y = 0; y < D; ++y) {\n            bool occ = false;\n            for (int x = 0; x < D; ++x)\n                if (grid[idx(x, y, z)]) { occ = true; break; }\n            if (occ != (right[z][y] == '1')) return false;\n        }\n    }\n    return true;\n}\n\nstruct Cell { int x, y, z; };\n\nvector<Cell> build_min_cells(int D, const vector<string>& front, const vector<string>& right) {\n    vector<Cell> cells;\n    for (int z = 0; z < D; ++z) {\n        vector<int> xs, ys;\n        for (int x = 0; x < D; ++x) if (front[z][x] == '1') xs.push_back(x);\n        for (int y = 0; y < D; ++y) if (right[z][y] == '1') ys.push_back(y);\n        if (xs.empty()) xs.push_back(0);\n        if (ys.empty()) ys.push_back(0);\n        if (xs.size() >= ys.size()) {\n            for (size_t i = 0; i < xs.size(); ++i)\n                cells.push_back({xs[i], ys[i % ys.size()], z});\n        } else {\n            for (size_t i = 0; i < ys.size(); ++i)\n                cells.push_back({xs[i % xs.size()], ys[i], z});\n        }\n    }\n    return cells;\n}\n\ntuple<int, vector<int>, vector<int>> baseline_solution(\n        int D,\n        const vector<string>& f0, const vector<string>& r0,\n        const vector<string>& f1, const vector<string>& r1) {\n\n    vector<Cell> c0 = build_min_cells(D, f0, r0);\n    vector<Cell> c1 = build_min_cells(D, f1, r1);\n    int n = max(c0.size(), c1.size());\n    vector<int> grid0(D*D*D, 0), grid1(D*D*D, 0);\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n    for (size_t i = 0; i < c0.size(); ++i) grid0[idx(c0[i].x, c0[i].y, c0[i].z)] = i + 1;\n    for (size_t i = 0; i < c1.size(); ++i) grid1[idx(c1[i].x, c1[i].y, c1[i].z)] = i + 1;\n    return {n, grid0, grid1};\n}\n\ndouble evaluate_solution(int n, const vector<int>& grid0, const vector<int>& grid1) {\n    vector<int> cnt0(n + 1, 0), cnt1(n + 1, 0);\n    for (int v : grid0) if (v > 0) cnt0[v]++;\n    for (int v : grid1) if (v > 0) cnt1[v]++;\n\n    vector<int> volume(n + 1, 0);\n    int total = 0;\n    for (int i = 1; i <= n; ++i) {\n        int v = max(cnt0[i], cnt1[i]);\n        volume[i] = v;\n        total += v;\n    }\n\n    int used0 = 0, used1 = 0;\n    double shared = 0.0;\n    for (int i = 1; i <= n; ++i) {\n        int v = volume[i];\n        if (v == 0) continue;\n        if (cnt0[i]) used0 += v;\n        if (cnt1[i]) used1 += v;\n        if (cnt0[i] && cnt1[i]) shared += 1.0 / v;\n    }\n    double r0 = total - used0;\n    double r1 = total - used1;\n    return r0 + r1 + shared;\n}\n\nbool build_advanced(\n        int D,\n        const vector<string>& f0, const vector<string>& r0,\n        const vector<string>& f1, const vector<string>& r1,\n        int& n,\n        vector<int>& grid0,\n        vector<int>& grid1,\n        mt19937* rng) {\n\n    vector<Segment> seg0 = build_segments(D, f0, r0, rng);\n    vector<Segment> seg1 = build_segments(D, f1, r1, rng);\n    vector<int> partner0, partner1;\n    align_segments(seg0, seg1, partner0, partner1);\n    optimize_pairing(seg0, seg1, partner0, partner1);\n    extend_shared_segments(D, seg0, seg1, partner0, f0, r0, f1, r1);\n\n    vector<BlockSpec> blocks;\n    vector<char> used0(seg0.size(), 0), used1(seg1.size(), 0);\n    vector<int> block_seg0, block_seg1;\n\n    for (int i = 0; i < (int)seg0.size(); ++i) {\n        if (used0[i]) continue;\n        if (partner0[i] != -1) {\n            int s1 = partner0[i];\n            if (used1[s1]) continue;\n            used0[i] = used1[s1] = 1;\n            blocks.push_back({i, s1});\n            block_seg0.push_back(i);\n            block_seg1.push_back(s1);\n        } else {\n            used0[i] = 1;\n            blocks.push_back({i, -1});\n            block_seg0.push_back(i);\n            block_seg1.push_back(-1);\n        }\n    }\n    for (int j = 0; j < (int)seg1.size(); ++j) {\n        if (used1[j]) continue;\n        if (partner1[j] != -1) continue;\n        used1[j] = 1;\n        blocks.push_back({-1, j});\n        block_seg0.push_back(-1);\n        block_seg1.push_back(j);\n    }\n\n    n = blocks.size();\n    grid0.assign(D*D*D, 0);\n    grid1.assign(D*D*D, 0);\n    auto idx = [&](int x, int y, int z) { return x * D * D + y * D + z; };\n    for (int id = 0; id < n; ++id) {\n        if (blocks[id].seg0 != -1) {\n            auto& s = seg0[blocks[id].seg0];\n            for (int dz = 0; dz < s.len; ++dz) {\n                int z = s.z0 + dz;\n                grid0[idx(s.x, s.y, z)] = id + 1;\n            }\n        }\n        if (blocks[id].seg1 != -1) {\n            auto& s = seg1[blocks[id].seg1];\n            for (int dz = 0; dz < s.len; ++dz) {\n                int z = s.z0 + dz;\n                grid1[idx(s.x, s.y, z)] = id + 1;\n            }\n        }\n    }\n\n    if (!verify(D, grid0, f0, r0)) return false;\n    if (!verify(D, grid1, f1, r1)) return false;\n\n    merge_shared_blocks(n, grid0, grid1, seg0, seg1, block_seg0, block_seg1);\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int D;\n    if (!(cin >> D)) return 0;\n    vector<vector<string>> front(2, vector<string>(D));\n    vector<vector<string>> right(2, vector<string>(D));\n    for (int i = 0; i < 2; ++i) {\n        for (int z = 0; z < D; ++z) cin >> front[i][z];\n        for (int z = 0; z < D; ++z) cin >> right[i][z];\n    }\n\n    mt19937 rng(uint64_t(chrono::high_resolution_clock::now().time_since_epoch().count()));\n    auto time_start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - time_start).count();\n    };\n\n    int bestN = -1;\n    vector<int> bestG0, bestG1;\n    double bestScore = 1e100;\n    auto consider = [&](int n, const vector<int>& g0, const vector<int>& g1) {\n        double sc = evaluate_solution(n, g0, g1);\n        if (bestN == -1 || sc < bestScore - 1e-9) {\n            bestN = n;\n            bestG0 = g0;\n            bestG1 = g1;\n            bestScore = sc;\n        }\n    };\n\n    {\n        int n; vector<int> g0, g1;\n        if (build_advanced(D, front[0], right[0], front[1], right[1], n, g0, g1, nullptr)) {\n            consider(n, g0, g1);\n        }\n    }\n\n    const int MAX_ATTEMPTS = 400;\n    const double TIME_LIMIT = 2.8;\n    int attempts = 0;\n    while (attempts < MAX_ATTEMPTS && elapsed() < TIME_LIMIT) {\n        int n; vector<int> g0, g1;\n        if (build_advanced(D, front[0], right[0], front[1], right[1], n, g0, g1, &rng)) {\n            consider(n, g0, g1);\n        }\n        ++attempts;\n    }\n\n    if (bestN == -1) {\n        auto [n, g0, g1] = baseline_solution(D, front[0], right[0], front[1], right[1]);\n        bestN = n; bestG0 = g0; bestG1 = g1;\n    }\n\n    cout << bestN << '\\n';\n    for (int i = 0; i < D*D*D; ++i) {\n        if (i) cout << ' ';\n        cout << bestG0[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < D*D*D; ++i) {\n        if (i) cout << ' ';\n        cout << bestG1[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge { int u, v; long long w; };\nstruct AdjEdge { int to; long long w; int id; };\nstruct Candidate { long long dist; int to; };\nstruct MoveCandidate {\n    long long approxDelta;\n    int resident;\n    int station;\n    long long dist;\n    int oldStation;\n};\n\nstruct Solver {\n    static constexpr long long INF64 = (1LL << 60);\n    static constexpr long long MAX_RAD_SQ = 5000LL * 5000LL;\n\n    const double TIME_LIMIT = 1.93;\n    const double RESTART_LIMIT = 1.70;\n\n    int N, M, K;\n    vector<long long> xs, ys;\n    vector<long long> ax, ay;\n    vector<Edge> edges;\n    vector<vector<AdjEdge>> graph;\n\n    vector<vector<long long>> distMat;\n    vector<vector<int>> parentEdge;\n    vector<vector<int>> parentVertex;\n\n    vector<vector<Candidate>> resCandidates;\n\n    vector<int> assignStation;\n    vector<long long> distAssigned;\n\n    vector<vector<int>> residentsOfStation;\n    vector<long long> maxDist;\n    vector<long long> secondMaxDist;\n    vector<int> maxCount;\n    vector<int> P;\n    vector<char> broadcast;\n\n    long long currentPcost = 0;\n    long long currentTreeCost = 0;\n\n    chrono::steady_clock::time_point startTime;\n    mt19937_64 rng;\n\n    inline double elapsedSeconds() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n    inline bool timeLimitExceeded() const {\n        return elapsedSeconds() > TIME_LIMIT;\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M >> K)) return;\n        startTime = chrono::steady_clock::now();\n        rng.seed(startTime.time_since_epoch().count());\n\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; ++i) cin >> xs[i] >> ys[i];\n\n        edges.resize(M);\n        graph.assign(N, {});\n        for (int j = 0; j < M; ++j) {\n            int u, v;\n            long long w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[j] = {u, v, w};\n            graph[u].push_back({v, w, j});\n            graph[v].push_back({u, w, j});\n        }\n\n        ax.resize(K);\n        ay.resize(K);\n        for (int i = 0; i < K; ++i) cin >> ax[i] >> ay[i];\n\n        computeAllPairs();\n        buildResidentCandidates();\n        initialAssignment();\n\n        residentsOfStation.assign(N, {});\n        maxDist.assign(N, 0);\n        secondMaxDist.assign(N, 0);\n        maxCount.assign(N, 0);\n        P.assign(N, 0);\n        broadcast.assign(N, 0);\n\n        rebuildAll();\n        localImprove();\n\n        vector<int> bestAssign = assignStation;\n        vector<long long> bestDist = distAssigned;\n        long long bestTotal = totalCost();\n\n        while (elapsedSeconds() < RESTART_LIMIT && !timeLimitExceeded()) {\n            assignStation = bestAssign;\n            distAssigned = bestDist;\n            rebuildAll();\n\n            bool strong = (rng() & 1);\n            int baseMoves = max(25, K / 45);\n            int moves = strong ? baseMoves * 2 : baseMoves;\n            perturbAssignments(moves, strong);\n            rebuildAll();\n            localImprove();\n\n            long long cur = totalCost();\n            if (cur < bestTotal) {\n                bestTotal = cur;\n                bestAssign = assignStation;\n                bestDist = distAssigned;\n            }\n            if (timeLimitExceeded()) break;\n        }\n\n        assignStation = bestAssign;\n        distAssigned = bestDist;\n        rebuildAll();\n\n        vector<int> edgeOn(M, 0);\n        buildFinalEdges(edgeOn);\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << P[i];\n        }\n        cout << '\\n';\n        for (int j = 0; j < M; ++j) {\n            if (j) cout << ' ';\n            cout << edgeOn[j];\n        }\n        cout << '\\n';\n    }\n\n    void computeAllPairs() {\n        distMat.assign(N, vector<long long>(N, INF64));\n        parentEdge.assign(N, vector<int>(N, -1));\n        parentVertex.assign(N, vector<int>(N, -1));\n        for (int s = 0; s < N; ++s) {\n            vector<long long> dist(N, INF64);\n            vector<int> prevE(N, -1), prevV(N, -1);\n            dist[s] = 0;\n            using Node = pair<long long, int>;\n            priority_queue<Node, vector<Node>, greater<Node>> pq;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [d, v] = pq.top();\n                pq.pop();\n                if (d != dist[v]) continue;\n                for (const auto &ed : graph[v]) {\n                    int to = ed.to;\n                    long long nd = d + ed.w;\n                    if (nd < dist[to]) {\n                        dist[to] = nd;\n                        prevE[to] = ed.id;\n                        prevV[to] = v;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n            distMat[s] = dist;\n            parentEdge[s] = prevE;\n            parentVertex[s] = prevV;\n        }\n    }\n\n    void buildResidentCandidates() {\n        resCandidates.assign(K, {});\n        vector<pair<long long, int>> tmp;\n        tmp.reserve(N);\n        for (int k = 0; k < K; ++k) {\n            tmp.clear();\n            for (int i = 0; i < N; ++i) {\n                long long dx = xs[i] - ax[k];\n                long long dy = ys[i] - ay[k];\n                long long d = dx * dx + dy * dy;\n                tmp.emplace_back(d, i);\n            }\n            sort(tmp.begin(), tmp.end());\n            vector<Candidate> cand;\n            cand.reserve(N);\n            bool hasWithin = false;\n            for (auto &p : tmp) {\n                if (p.first <= MAX_RAD_SQ) {\n                    cand.push_back({p.first, p.second});\n                    hasWithin = true;\n                } else if (hasWithin) break;\n            }\n            if (cand.empty()) cand.push_back({tmp[0].first, tmp[0].second});\n            resCandidates[k] = move(cand);\n        }\n    }\n\n    void initialAssignment() {\n        assignStation.resize(K);\n        distAssigned.resize(K);\n        for (int k = 0; k < K; ++k) {\n            const auto &cand = resCandidates[k];\n            assignStation[k] = cand[0].to;\n            long long d = cand[0].dist;\n            if (d > MAX_RAD_SQ) d = MAX_RAD_SQ;\n            distAssigned[k] = d;\n        }\n    }\n\n    int ceil_sqrt_ll(long long v) const {\n        if (v <= 0) return 0;\n        long double r = sqrt((long double)v);\n        long long x = (long long)r;\n        while (x * x < v) ++x;\n        while (x > 0 && (x - 1) * (x - 1) >= v) --x;\n        if (x > 5000) x = 5000;\n        return (int)x;\n    }\n\n    void rebuildAll() {\n        for (int i = 0; i < N; ++i) {\n            residentsOfStation[i].clear();\n            maxDist[i] = 0;\n            secondMaxDist[i] = 0;\n            maxCount[i] = 0;\n        }\n        for (int k = 0; k < K; ++k) {\n            int st = assignStation[k];\n            residentsOfStation[st].push_back(k);\n            long long d = distAssigned[k];\n            if (d > maxDist[st]) {\n                secondMaxDist[st] = maxDist[st];\n                maxDist[st] = d;\n                maxCount[st] = 1;\n            } else if (d == maxDist[st]) {\n                maxCount[st]++;\n            } else if (d > secondMaxDist[st]) {\n                secondMaxDist[st] = d;\n            }\n        }\n        currentPcost = 0;\n        for (int i = 0; i < N; ++i) {\n            if (!residentsOfStation[i].empty()) {\n                broadcast[i] = 1;\n                P[i] = ceil_sqrt_ll(maxDist[i]);\n            } else {\n                broadcast[i] = 0;\n                P[i] = 0;\n                maxDist[i] = secondMaxDist[i] = 0;\n                maxCount[i] = 0;\n            }\n            currentPcost += 1LL * P[i] * P[i];\n        }\n        currentTreeCost = computeCurrentMST();\n    }\n\n    long long computeMSTNodes(const vector<int> &nodes) {\n        if (nodes.size() <= 1) return 0;\n        vector<long long> key(nodes.size(), INF64);\n        vector<char> used(nodes.size(), false);\n        key[0] = 0;\n        long long total = 0;\n        for (size_t it = 0; it < nodes.size(); ++it) {\n            int u = -1;\n            long long best = INF64;\n            for (size_t i = 0; i < nodes.size(); ++i)\n                if (!used[i] && key[i] < best)\n                    best = key[i], u = (int)i;\n            if (u == -1) break;\n            used[u] = true;\n            total += key[u];\n            for (size_t v = 0; v < nodes.size(); ++v) {\n                if (used[v]) continue;\n                long long d = distMat[nodes[u]][nodes[v]];\n                if (d < key[v]) key[v] = d;\n            }\n        }\n        return total;\n    }\n\n    long long computeCurrentMST() {\n        vector<int> nodes;\n        nodes.reserve(N);\n        nodes.push_back(0);\n        for (int i = 1; i < N; ++i) if (broadcast[i]) nodes.push_back(i);\n        return computeMSTNodes(nodes);\n    }\n\n    long long maxAfterRemovingDist(int station, long long distVal) const {\n        if (!broadcast[station]) return 0;\n        if (distVal < maxDist[station]) return maxDist[station];\n        if (distVal == maxDist[station]) {\n            if (maxCount[station] >= 2) return maxDist[station];\n            return secondMaxDist[station];\n        }\n        return maxDist[station];\n    }\n\n    bool tryRemove(int s) {\n        if (!broadcast[s]) return false;\n        auto resList = residentsOfStation[s];\n        if (resList.empty()) return false;\n\n        vector<long long> tempMax = maxDist;\n        vector<int> tempP = P;\n        vector<int> chosenStation(resList.size(), -1);\n        vector<long long> chosenDist(resList.size(), 0);\n\n        vector<int> order(resList.size());\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            long long da = distAssigned[resList[a]];\n            long long db = distAssigned[resList[b]];\n            if (da != db) return da > db;\n            return resList[a] < resList[b];\n        });\n\n        for (int ordIdx : order) {\n            int rid = resList[ordIdx];\n            long long bestDelta = INF64;\n            int bestTarget = -1;\n            long long bestDist = 0;\n            long long bestNewMax = 0;\n            int bestNewP = 0;\n            for (const auto &cand : resCandidates[rid]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                int t = cand.to;\n                if (t == s) continue;\n                if (!broadcast[t]) continue;\n                long long curMax = tempMax[t];\n                int curP = tempP[t];\n                long long newMax = curMax;\n                int newP = curP;\n                if (cand.dist > newMax) {\n                    newMax = cand.dist;\n                    newP = ceil_sqrt_ll(newMax);\n                }\n                long long delta = 1LL * newP * newP - 1LL * curP * curP;\n                if (bestTarget == -1 || delta < bestDelta ||\n                    (delta == bestDelta && newMax < bestNewMax)) {\n                    bestDelta = delta;\n                    bestTarget = t;\n                    bestDist = cand.dist;\n                    bestNewMax = newMax;\n                    bestNewP = newP;\n                }\n            }\n            if (bestTarget == -1) return false;\n            chosenStation[ordIdx] = bestTarget;\n            chosenDist[ordIdx] = bestDist;\n            tempMax[bestTarget] = bestNewMax;\n            tempP[bestTarget] = bestNewP;\n        }\n\n        tempMax[s] = 0;\n        tempP[s] = 0;\n\n        vector<int> nodesAfter;\n        nodesAfter.reserve(N);\n        nodesAfter.push_back(0);\n        long long newPcost = 0;\n        for (int i = 0; i < N; ++i) {\n            newPcost += 1LL * tempP[i] * tempP[i];\n            if (i > 0 && tempP[i] > 0) nodesAfter.push_back(i);\n        }\n        long long newTree = computeMSTNodes(nodesAfter);\n        if (newPcost + newTree >= totalCost()) return false;\n\n        for (size_t idx = 0; idx < resList.size(); ++idx) {\n            assignStation[resList[idx]] = chosenStation[idx];\n            distAssigned[resList[idx]] = chosenDist[idx];\n        }\n        rebuildAll();\n        return true;\n    }\n\n    bool tryReassignAll() {\n        vector<int> newAssign(K);\n        vector<long long> newDist(K);\n        bool changed = false;\n        for (int r = 0; r < K; ++r) {\n            int bestStation = -1;\n            long long bestDist = 0;\n            for (const auto &cand : resCandidates[r]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                if (!broadcast[cand.to]) continue;\n                bestStation = cand.to;\n                bestDist = cand.dist;\n                break;\n            }\n            if (bestStation == -1) return false;\n            newAssign[r] = bestStation;\n            newDist[r] = bestDist;\n            if (bestStation != assignStation[r]) changed = true;\n        }\n        if (!changed) return false;\n\n        vector<long long> newMax(N, 0);\n        vector<int> counts(N, 0);\n        for (int r = 0; r < K; ++r) {\n            int st = newAssign[r];\n            ++counts[st];\n            if (newDist[r] > newMax[st]) newMax[st] = newDist[r];\n        }\n        vector<int> newP(N, 0);\n        vector<char> newBroadcast(N, 0);\n        long long newPcost = 0;\n        for (int i = 0; i < N; ++i) {\n            if (counts[i] > 0) {\n                newBroadcast[i] = 1;\n                newP[i] = ceil_sqrt_ll(newMax[i]);\n            } else {\n                newBroadcast[i] = 0;\n                newP[i] = 0;\n            }\n            newPcost += 1LL * newP[i] * newP[i];\n        }\n        vector<int> nodes;\n        nodes.reserve(N);\n        nodes.push_back(0);\n        for (int i = 1; i < N; ++i) if (newBroadcast[i]) nodes.push_back(i);\n        long long newTree = computeMSTNodes(nodes);\n        if (newPcost + newTree >= totalCost()) return false;\n\n        assignStation.swap(newAssign);\n        distAssigned.swap(newDist);\n        rebuildAll();\n        return true;\n    }\n\n    bool improveSingleFarMove() {\n        vector<int> order;\n        order.reserve(N);\n        for (int i = 0; i < N; ++i) if (broadcast[i]) order.push_back(i);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (P[a] != P[b]) return P[a] > P[b];\n            return residentsOfStation[a].size() > residentsOfStation[b].size();\n        });\n        for (int s : order) {\n            if ((int)residentsOfStation[s].size() <= 1) continue;\n            int farRes = -1;\n            long long farDist = -1;\n            for (int r : residentsOfStation[s]) {\n                if (distAssigned[r] > farDist) {\n                    farDist = distAssigned[r];\n                    farRes = r;\n                }\n            }\n            if (farRes == -1) continue;\n            long long newMaxS = maxAfterRemovingDist(s, distAssigned[farRes]);\n            int newPs = ceil_sqrt_ll(newMaxS);\n            long long bestDelta = 0;\n            int bestTarget = -1;\n            long long bestDist = 0;\n            for (const auto &cand : resCandidates[farRes]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                int t = cand.to;\n                if (t == s) continue;\n                if (!broadcast[t]) continue;\n                long long newMaxT = max(maxDist[t], cand.dist);\n                int newPt = ceil_sqrt_ll(newMaxT);\n                long long delta = 1LL * newPs * newPs + 1LL * newPt * newPt\n                                  - (1LL * P[s] * P[s] + 1LL * P[t] * P[t]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestTarget = t;\n                    bestDist = cand.dist;\n                }\n            }\n            if (bestTarget != -1) {\n                if (applyMoveSingle(farRes, bestTarget, bestDist)) return true;\n            }\n            if (timeLimitExceeded()) break;\n        }\n        return false;\n    }\n\n    bool tryResidentReassignActive() {\n        if (timeLimitExceeded()) return false;\n        vector<int> order(K);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n        const int MAX_ATTEMPTS = 400;\n        int attempts = 0;\n        for (int idx = 0; idx < K && attempts < MAX_ATTEMPTS; ++idx) {\n            if (timeLimitExceeded()) break;\n            int r = order[idx];\n            int s = assignStation[r];\n            long long distR = distAssigned[r];\n            for (const auto &cand : resCandidates[r]) {\n                if (cand.dist > MAX_RAD_SQ) break;\n                int t = cand.to;\n                if (t == s) continue;\n                if (!broadcast[t]) continue;\n                long long newMaxS = maxAfterRemovingDist(s, distR);\n                int newPs = ceil_sqrt_ll(newMaxS);\n                long long dAdd = min(cand.dist, MAX_RAD_SQ);\n                long long newMaxT = max(maxDist[t], dAdd);\n                int newPt = ceil_sqrt_ll(newMaxT);\n                long long delta = 1LL * newPs * newPs + 1LL * newPt * newPt\n                                  - (1LL * P[s] * P[s] + 1LL * P[t] * P[t]);\n                if (delta < 0) {\n                    if (applyMoveSingle(r, t, dAdd)) {\n                        ++attempts;\n                        break;\n                    }\n                }\n                if (timeLimitExceeded()) break;\n            }\n        }\n        return attempts > 0;\n    }\n\n    bool optimizeExisting() {\n        bool overall = false;\n        while (!timeLimitExceeded()) {\n            bool changed = false;\n            while (!timeLimitExceeded()) {\n                vector<int> order;\n                order.reserve(N);\n                for (int i = 0; i < N; ++i) if (broadcast[i]) order.push_back(i);\n                sort(order.begin(), order.end(), [&](int a, int b) {\n                    if (residentsOfStation[a].size() != residentsOfStation[b].size())\n                        return residentsOfStation[a].size() < residentsOfStation[b].size();\n                    if (P[a] != P[b]) return P[a] < P[b];\n                    return a < b;\n                });\n                bool removed = false;\n                for (int s : order) {\n                    if (tryRemove(s)) {\n                        changed = true;\n                        removed = true;\n                        break;\n                    }\n                    if (timeLimitExceeded()) break;\n                }\n                if (!removed) break;\n            }\n            if (timeLimitExceeded()) break;\n            if (tryReassignAll()) changed = true;\n            if (timeLimitExceeded()) break;\n            if (improveSingleFarMove()) changed = true;\n            if (timeLimitExceeded()) break;\n            if (tryResidentReassignActive()) changed = true;\n            if (!changed) break;\n            overall = true;\n        }\n        return overall;\n    }\n\n    long long totalCost() const {\n        return currentPcost + currentTreeCost;\n    }\n\n    bool applyMoveSingle(int resident, int targetStation, long long distSq) {\n        int prevStation = assignStation[resident];\n        long long prevDist = distAssigned[resident];\n        if (prevStation == targetStation) return false;\n        long long oldCost = totalCost();\n        if (distSq > MAX_RAD_SQ) distSq = MAX_RAD_SQ;\n        assignStation[resident] = targetStation;\n        distAssigned[resident] = distSq;\n        rebuildAll();\n        if (totalCost() < oldCost) {\n            return true;\n        } else {\n            assignStation[resident] = prevStation;\n            distAssigned[resident] = prevDist;\n            rebuildAll();\n            return false;\n        }\n    }\n\n    void computeActiveDistances(vector<long long> &minToActive, vector<long long> &minExcl) {\n        vector<int> activeNodes;\n        activeNodes.reserve(N);\n        activeNodes.push_back(0);\n        for (int i = 1; i < N; ++i) if (broadcast[i]) activeNodes.push_back(i);\n\n        minToActive.assign(N, INF64);\n        for (int i = 0; i < N; ++i) {\n            long long best = INF64;\n            for (int v : activeNodes) {\n                long long d = distMat[i][v];\n                if (d < best) best = d;\n            }\n            minToActive[i] = best;\n        }\n\n        minExcl.assign(N, INF64);\n        for (int node : activeNodes) {\n            long long best = INF64;\n            for (int v : activeNodes) {\n                if (v == node) continue;\n                long long d = distMat[node][v];\n                if (d < best) best = d;\n            }\n            if (node == 0 && best == INF64) best = 0;\n            minExcl[node] = best;\n        }\n        for (int i = 0; i < N; ++i)\n            if (minExcl[i] == INF64) minExcl[i] = minToActive[i];\n    }\n\n    bool tryActivateStations() {\n        bool overall = false;\n        const int MAX_CAND_PER_RES = 6;\n        const int MAX_ATTEMPTS = 80;\n        while (!timeLimitExceeded()) {\n            vector<long long> minDistToActive, minDistExcl;\n            computeActiveDistances(minDistToActive, minDistExcl);\n\n            vector<MoveCandidate> candidates;\n            candidates.reserve(K * MAX_CAND_PER_RES);\n            for (int r = 0; r < K; ++r) {\n                int oldS = assignStation[r];\n                long long newMaxWithout = maxAfterRemovingDist(oldS, distAssigned[r]);\n                int newPOld = ceil_sqrt_ll(newMaxWithout);\n                long long newPOldSq = 1LL * newPOld * newPOld;\n                long long oldPOldSq = 1LL * P[oldS] * P[oldS];\n                long long removalGain = 0;\n                if (oldS != 0 && (int)residentsOfStation[oldS].size() == 1) {\n                    removalGain = minDistExcl[oldS];\n                }\n                int used = 0;\n                for (const auto &cand : resCandidates[r]) {\n                    if (cand.dist > MAX_RAD_SQ) break;\n                    int s = cand.to;\n                    if (broadcast[s]) continue;\n                    long long hook = minDistToActive[s];\n                    if (hook >= INF64 / 4) continue;\n                    int newPs = ceil_sqrt_ll(cand.dist);\n                    long long newPsSq = 1LL * newPs * newPs;\n                    long long approx = hook - removalGain + (newPsSq + newPOldSq - oldPOldSq);\n                    candidates.push_back({approx, r, s, cand.dist, oldS});\n                    if (++used >= MAX_CAND_PER_RES) break;\n                }\n            }\n            if (candidates.empty()) break;\n            sort(candidates.begin(), candidates.end(), [](const MoveCandidate &a, const MoveCandidate &b) {\n                if (a.approxDelta != b.approxDelta) return a.approxDelta < b.approxDelta;\n                if (a.resident != b.resident) return a.resident < b.resident;\n                return a.station < b.station;\n            });\n            bool applied = false;\n            int attempts = 0;\n            for (const auto &cand : candidates) {\n                if (cand.approxDelta >= 0) break;\n                if (assignStation[cand.resident] != cand.oldStation) continue;\n                if (broadcast[cand.station]) continue;\n                if (cand.dist > MAX_RAD_SQ) continue;\n                ++attempts;\n                if (attempts > MAX_ATTEMPTS) break;\n                if (applyMoveSingle(cand.resident, cand.station, cand.dist)) {\n                    overall = true;\n                    applied = true;\n                    break;\n                }\n                if (timeLimitExceeded()) break;\n            }\n            if (!applied || timeLimitExceeded()) break;\n        }\n        return overall;\n    }\n\n    bool tryActivateBatch(int s) {\n        const int NEIGH_LIMIT = 8;\n        vector<pair<long long,int>> cand;\n        cand.reserve(64);\n        for (int r = 0; r < K; ++r) {\n            int cnt = 0;\n            for (const auto &c : resCandidates[r]) {\n                if (c.dist > MAX_RAD_SQ) break;\n                ++cnt;\n                if (c.to == s) {\n                    cand.emplace_back(c.dist, r);\n                    break;\n                }\n                if (cnt >= NEIGH_LIMIT) break;\n            }\n        }\n        if ((int)cand.size() < 2) return false;\n        sort(cand.begin(), cand.end());\n        if ((int)cand.size() > 40) cand.resize(40);\n\n        static const int subsetSizes[] = {2,3,4,5,6,8,10,12};\n        long long baseCost = totalCost();\n\n        for (int sz : subsetSizes) {\n            if (timeLimitExceeded()) break;\n            if ((int)cand.size() < sz) break;\n\n            vector<int> changed;\n            vector<int> oldStation;\n            vector<long long> oldDist;\n            changed.reserve(sz);\n            oldStation.reserve(sz);\n            oldDist.reserve(sz);\n\n            for (int i = 0; i < sz; ++i) {\n                int r = cand[i].second;\n                changed.push_back(r);\n                oldStation.push_back(assignStation[r]);\n                oldDist.push_back(distAssigned[r]);\n                assignStation[r] = s;\n                distAssigned[r] = min(cand[i].first, MAX_RAD_SQ);\n            }\n\n            rebuildAll();\n            long long newCost = totalCost();\n            if (newCost < baseCost) {\n                return true;\n            } else {\n                for (size_t j = 0; j < changed.size(); ++j) {\n                    int r = changed[j];\n                    assignStation[r] = oldStation[j];\n                    distAssigned[r] = oldDist[j];\n                }\n                rebuildAll();\n            }\n        }\n        return false;\n    }\n\n    bool tryActivateBatchStations() {\n        vector<int> inactive;\n        for (int i = 1; i < N; ++i) if (!broadcast[i]) inactive.push_back(i);\n        if (inactive.empty()) return false;\n        shuffle(inactive.begin(), inactive.end(), rng);\n        int limit = min((int)inactive.size(), 10);\n        for (int i = 0; i < limit && !timeLimitExceeded(); ++i) {\n            if (tryActivateBatch(inactive[i])) return true;\n        }\n        return false;\n    }\n\n    void localImprove() {\n        while (!timeLimitExceeded()) {\n            bool changed = false;\n            if (optimizeExisting()) changed = true;\n            if (timeLimitExceeded()) break;\n            if (tryActivateStations()) changed = true;\n            if (timeLimitExceeded()) break;\n            if (tryActivateBatchStations()) changed = true;\n            if (!changed) break;\n        }\n    }\n\n    void perturbAssignments(int moves, bool strong) {\n        uniform_int_distribution<int> resDist(0, K - 1);\n        for (int it = 0; it < moves; ++it) {\n            int r = resDist(rng);\n            auto &cand = resCandidates[r];\n            if (cand.empty()) continue;\n            int limit = strong ? min<int>(cand.size(), 12) : min<int>(cand.size(), 6);\n            if (limit == 0) continue;\n            uniform_int_distribution<int> idxDist(0, limit - 1);\n            int idx = idxDist(rng);\n            assignStation[r] = cand[idx].to;\n            distAssigned[r] = min(cand[idx].dist, MAX_RAD_SQ);\n        }\n        if (strong) {\n            vector<int> act;\n            for (int i = 0; i < N; ++i)\n                if (broadcast[i] && residentsOfStation[i].size() >= 2) act.push_back(i);\n            if (!act.empty()) {\n                uniform_int_distribution<int> stDist(0, (int)act.size() - 1);\n                int pick = act[stDist(rng)];\n                for (int rid : residentsOfStation[pick]) {\n                    auto &cand = resCandidates[rid];\n                    if (cand.size() <= 1) continue;\n                    vector<int> opts;\n                    for (size_t idx = 1; idx < cand.size() && idx < 10; ++idx)\n                        if (cand[idx].to != assignStation[rid]) opts.push_back(idx);\n                    if (opts.empty()) continue;\n                    uniform_int_distribution<int> optDist(0, (int)opts.size() - 1);\n                    int idx = opts[optDist(rng)];\n                    assignStation[rid] = cand[idx].to;\n                    distAssigned[rid] = min(cand[idx].dist, MAX_RAD_SQ);\n                }\n            }\n        }\n    }\n\n    void recomputeSP(int s) {\n        vector<long long> dist(N, INF64);\n        vector<int> prevE(N, -1), prevV(N, -1);\n        dist[s] = 0;\n        using Node = pair<long long, int>;\n        priority_queue<Node, vector<Node>, greater<Node>> pq;\n        pq.push({0, s});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            for (const auto &ed : graph[v]) {\n                int to = ed.to;\n                long long nd = d + ed.w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    prevE[to] = ed.id;\n                    prevV[to] = v;\n                    pq.push({nd, to});\n                }\n            }\n        }\n        distMat[s] = dist;\n        parentEdge[s] = prevE;\n        parentVertex[s] = prevV;\n    }\n\n    bool followPath(int source, int target, vector<int> &edgeOn) {\n        int cur = target;\n        while (cur != source) {\n            int e = parentEdge[source][cur];\n            int pv = parentVertex[source][cur];\n            if (e == -1 || pv == -1) return false;\n            edgeOn[e] = 1;\n            cur = pv;\n        }\n        return true;\n    }\n\n    void addPath(int source, int target, vector<int> &edgeOn) {\n        if (source == target) return;\n        if (!followPath(source, target, edgeOn)) {\n            recomputeSP(source);\n            followPath(source, target, edgeOn);\n        }\n    }\n\n    vector<char> computeReachable(const vector<int> &edgeOn) {\n        vector<char> vis(N, 0);\n        queue<int> q;\n        vis[0] = 1;\n        q.push(0);\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            for (const auto &ed : graph[v]) {\n                if (!edgeOn[ed.id]) continue;\n                if (!vis[ed.to]) {\n                    vis[ed.to] = 1;\n                    q.push(ed.to);\n                }\n            }\n        }\n        return vis;\n    }\n\n    void buildFinalEdges(vector<int> &edgeOn) {\n        fill(edgeOn.begin(), edgeOn.end(), 0);\n        vector<int> nodes;\n        nodes.reserve(N);\n        nodes.push_back(0);\n        for (int i = 1; i < N; ++i) if (broadcast[i]) nodes.push_back(i);\n        if (nodes.size() <= 1) return;\n\n        int T = nodes.size();\n        vector<long long> key(T, INF64);\n        vector<int> parent(T, -1);\n        vector<char> used(T, false);\n        key[0] = 0;\n        for (int iter = 0; iter < T; ++iter) {\n            int u = -1;\n            long long best = INF64;\n            for (int i = 0; i < T; ++i) {\n                if (!used[i] && key[i] < best) {\n                    best = key[i];\n                    u = i;\n                }\n            }\n            if (u == -1) break;\n            used[u] = true;\n            if (parent[u] != -1) {\n                addPath(nodes[u], nodes[parent[u]], edgeOn);\n            }\n            for (int v = 0; v < T; ++v) {\n                if (used[v]) continue;\n                long long d = distMat[nodes[u]][nodes[v]];\n                if (d < key[v]) {\n                    key[v] = d;\n                    parent[v] = u;\n                }\n            }\n        }\n\n        auto vis = computeReachable(edgeOn);\n        for (int node : nodes) {\n            if (!vis[node]) {\n                addPath(0, node, edgeOn);\n                vis = computeReachable(edgeOn);\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 30;\nconstexpr int TOTAL = N * (N + 1) / 2;\nconstexpr int LIMIT = 10000;\nusing Tri = vector<vector<int>>;\n\nstruct Result {\n    vector<array<int, 4>> ops;\n    Tri board;\n};\n\ninline bool inRange(int x, int y) { return 0 <= x && x < N && 0 <= y && y <= x; }\n\nbool adjacent(int x1, int y1, int x2, int y2) {\n    if (!inRange(x1, y1) || !inRange(x2, y2)) return false;\n    if (x1 == x2) return abs(y1 - y2) == 1;\n    if (x1 + 1 == x2) return (y1 == y2) || (y1 == y2 - 1);\n    if (x2 + 1 == x1) return (y2 == y1) || (y2 == y1 - 1);\n    return false;\n}\n\nint countViolations(const Tri& a) {\n    int cnt = 0;\n    for (int x = 0; x < N - 1; ++x)\n        for (int y = 0; y <= x; ++y) {\n            if (a[x][y] > a[x + 1][y]) ++cnt;\n            if (a[x][y] > a[x + 1][y + 1]) ++cnt;\n        }\n    return cnt;\n}\n\nbool applyOps(const Tri& initial, const vector<array<int, 4>>& ops, Tri& board) {\n    if ((int)ops.size() > LIMIT) return false;\n    board = initial;\n    for (const auto& op : ops) {\n        int x1 = op[0], y1 = op[1], x2 = op[2], y2 = op[3];\n        if (!adjacent(x1, y1, x2, y2)) return false;\n        swap(board[x1][y1], board[x2][y2]);\n    }\n    return true;\n}\n\nbool ensureValid(Result& res, const Tri& initial) {\n    Tri board;\n    if (!applyOps(initial, res.ops, board)) return false;\n    if (countViolations(board) != 0) return false;\n    res.board = move(board);\n    return true;\n}\n\nResult runBaseline(const Tri& initial) {\n    Result res;\n    res.board = initial;\n    res.ops.reserve(5000);\n    auto swapBall = [&](int x1, int y1, int x2, int y2) {\n        res.ops.push_back({x1, y1, x2, y2});\n        swap(res.board[x1][y1], res.board[x2][y2]);\n    };\n    for (int x = N - 2; x >= 0; --x)\n        for (int y = 0; y <= x; ++y) {\n            int cx = x, cy = y;\n            while (cx < N - 1) {\n                int left = res.board[cx + 1][cy];\n                int right = res.board[cx + 1][cy + 1];\n                int mn = min(left, right);\n                if (res.board[cx][cy] <= mn) break;\n                int ny = (left < right ? cy : cy + 1);\n                swapBall(cx, cy, cx + 1, ny);\n                ++cx;\n                cy = ny;\n            }\n        }\n    return res;\n}\n\nstruct XorShift {\n    uint64_t state;\n    explicit XorShift(uint64_t seed) : state(seed ? seed : 1) {}\n    uint32_t next() {\n        uint64_t x = state;\n        x ^= x << 7;\n        x ^= x >> 9;\n        return state = x;\n    }\n};\n\nbool runPriorityFix(const Tri& startBoard, int upperBound, Result& out, XorShift& rng, int mode) {\n    if (upperBound <= 0) return false;\n    upperBound = min(upperBound, LIMIT);\n    Tri board = startBoard;\n    vector<array<int, 4>> ops;\n    ops.reserve(upperBound);\n\n    auto calcPriority = [&](int x, int diff) -> int {\n        int depth = N - 1 - x;\n        switch (mode % 8) {\n            case 0: return diff;\n            case 1: return diff * (depth + 1);\n            case 2: return diff * (depth + 1) + depth;\n            case 3: return diff * (depth + 1) * (depth + 1);\n            case 4: return diff * 2 + depth;\n            case 5: return diff * (depth + 2);\n            case 6: return diff * (depth + 1) + diff;\n            case 7: return diff + depth;\n            default: return diff;\n        }\n    };\n\n    struct Node {\n        int pri, x, y;\n        uint32_t rd;\n        bool operator<(const Node& other) const {\n            if (pri != other.pri) return pri < other.pri;\n            return rd < other.rd;\n        }\n    };\n    priority_queue<Node> pq;\n\n    auto pushNode = [&](int x, int y) {\n        if (x < 0 || x >= N - 1 || y < 0 || y > x) return;\n        int left = board[x + 1][y];\n        int right = board[x + 1][y + 1];\n        int diff = board[x][y] - min(left, right);\n        if (diff > 0) {\n            int pri = calcPriority(x, diff);\n            pq.push(Node{pri, x, y, rng.next()});\n        }\n    };\n\n    for (int x = 0; x < N - 1; ++x)\n        for (int y = 0; y <= x; ++y)\n            pushNode(x, y);\n\n    while (!pq.empty()) {\n        if ((int)ops.size() >= upperBound) return false;\n        Node cur = pq.top();\n        pq.pop();\n        int x = cur.x, y = cur.y;\n        if (x >= N - 1) continue;\n        int left = board[x + 1][y];\n        int right = board[x + 1][y + 1];\n        int mn = min(left, right);\n        if (board[x][y] <= mn) continue;\n        int childY = (left == right) ? ((rng.next() & 1) ? y : y + 1)\n                                     : (left < right ? y : y + 1);\n        int cx = x + 1, cy = childY;\n        ops.push_back({x, y, cx, cy});\n        swap(board[x][y], board[cx][cy]);\n        pushNode(x, y);\n        pushNode(cx, cy);\n        pushNode(x - 1, y - 1);\n        pushNode(x - 1, y);\n        if (childY == y)\n            pushNode(x, y - 1);\n        else\n            pushNode(x, y + 1);\n    }\n\n    if ((int)ops.size() >= upperBound) return false;\n    if (countViolations(board) != 0) return false;\n    out.board = move(board);\n    out.ops = move(ops);\n    return true;\n}\n\noptional<Result> preArrangeSimple(const Tri& start, int depth, int limit,\n                                  const vector<vector<int>>& adj,\n                                  const vector<pair<int, int>>& idx2coord,\n                                  const vector<vector<int>>& idxOf) {\n    if (limit <= 0) return nullopt;\n    depth = min(depth, N - 1);\n    vector<int> targets;\n    for (int x = 0; x <= depth && x < N; ++x)\n        for (int y = 0; y <= x; ++y)\n            targets.push_back(idxOf[x][y]);\n\n    Tri board = start;\n    vector<array<int, 4>> ops;\n    vector<char> blocked(TOTAL, false);\n    vector<int> parent(TOTAL, -1);\n    vector<char> visited(TOTAL, 0);\n\n    for (int target : targets) {\n        if ((int)ops.size() >= limit) return nullopt;\n        int bestIdx = -1, bestVal = INT_MAX;\n        for (int idx = 0; idx < TOTAL; ++idx) {\n            if (blocked[idx]) continue;\n            auto [x, y] = idx2coord[idx];\n            int val = board[x][y];\n            if (val < bestVal) {\n                bestVal = val;\n                bestIdx = idx;\n            }\n        }\n        if (bestIdx == -1) break;\n        if (bestIdx != target) {\n            fill(parent.begin(), parent.end(), -1);\n            fill(visited.begin(), visited.end(), 0);\n            queue<int> q;\n            visited[bestIdx] = 1;\n            parent[bestIdx] = -2;\n            q.push(bestIdx);\n            bool found = false;\n            while (!q.empty()) {\n                int v = q.front();\n                q.pop();\n                if (v == target) {\n                    found = true;\n                    break;\n                }\n                for (int nv : adj[v]) {\n                    if (visited[nv]) continue;\n                    if (blocked[nv] && nv != target) continue;\n                    visited[nv] = 1;\n                    parent[nv] = v;\n                    q.push(nv);\n                }\n            }\n            if (!found) return nullopt;\n            vector<int> path;\n            int cur = target;\n            path.push_back(cur);\n            while (cur != bestIdx) {\n                cur = parent[cur];\n                if (cur < 0) return nullopt;\n                path.push_back(cur);\n            }\n            reverse(path.begin(), path.end());\n            if ((int)ops.size() + (int)path.size() - 1 > limit) return nullopt;\n            for (size_t i = 0; i + 1 < path.size(); ++i) {\n                auto [x1, y1] = idx2coord[path[i]];\n                auto [x2, y2] = idx2coord[path[i + 1]];\n                ops.push_back({x1, y1, x2, y2});\n                swap(board[x1][y1], board[x2][y2]);\n            }\n        }\n        blocked[target] = true;\n    }\n\n    Result res;\n    res.board = move(board);\n    res.ops = move(ops);\n    return res;\n}\n\noptional<Result> preArrangeSmart(const Tri& start, int depth, int limit,\n                                 int candLimit, int baseRankWeight,\n                                 const vector<vector<int>>& adj,\n                                 const vector<pair<int, int>>& idx2coord,\n                                 const vector<vector<int>>& idxOf) {\n    if (limit <= 0 || candLimit <= 0) return nullopt;\n    depth = min(depth, N - 1);\n    vector<int> targets;\n    for (int x = 0; x <= depth && x < N; ++x)\n        for (int y = 0; y <= x; ++y)\n            targets.push_back(idxOf[x][y]);\n\n    Tri board = start;\n    vector<array<int, 4>> ops;\n    vector<char> blocked(TOTAL, false);\n    vector<int> dist(TOTAL), parent(TOTAL), order(TOTAL);\n    iota(order.begin(), order.end(), 0);\n    const int INF = 1e9;\n\n    for (int targetIdx : targets) {\n        if ((int)ops.size() >= limit) return nullopt;\n\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            auto [xa, ya] = idx2coord[a];\n            auto [xb, yb] = idx2coord[b];\n            return board[xa][ya] < board[xb][yb];\n        });\n\n        fill(dist.begin(), dist.end(), INF);\n        fill(parent.begin(), parent.end(), -1);\n        queue<int> q;\n        dist[targetIdx] = 0;\n        parent[targetIdx] = -2;\n        q.push(targetIdx);\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (blocked[v] && v != targetIdx) continue;\n                if (dist[v] != INF) continue;\n                dist[v] = dist[u] + 1;\n                parent[v] = u;\n                q.push(v);\n            }\n        }\n\n        vector<pair<int, int>> options;\n        int rank = 0;\n        for (int idx : order) {\n            if (blocked[idx]) continue;\n            if (dist[idx] != INF) {\n                options.push_back({idx, rank});\n                if ((int)options.size() >= candLimit) break;\n            }\n            ++rank;\n        }\n        if (options.empty()) return nullopt;\n\n        auto [tx, ty] = idx2coord[targetIdx];\n        int rankWeight = max(1, baseRankWeight * (depth - tx + 1));\n        int selected = -1;\n        long long bestScore = (1LL << 60);\n        for (auto [candIdx, candRank] : options) {\n            long long score = 1LL * dist[candIdx] + 1LL * rankWeight * candRank;\n            if (score < bestScore) {\n                bestScore = score;\n                selected = candIdx;\n            }\n        }\n        if (selected == -1) return nullopt;\n\n        vector<int> path;\n        int cur = selected;\n        path.push_back(cur);\n        while (cur != targetIdx) {\n            cur = parent[cur];\n            if (cur < 0) return nullopt;\n            path.push_back(cur);\n        }\n\n        for (size_t i = 0; i + 1 < path.size(); ++i) {\n            auto [x1, y1] = idx2coord[path[i]];\n            auto [x2, y2] = idx2coord[path[i + 1]];\n            if ((int)ops.size() >= limit) return nullopt;\n            ops.push_back({x1, y1, x2, y2});\n            swap(board[x1][y1], board[x2][y2]);\n        }\n        blocked[targetIdx] = true;\n    }\n\n    Result res;\n    res.board = move(board);\n    res.ops = move(ops);\n    return res;\n}\n\nstruct StagePlan {\n    int depth, stageLimit, candLimit, baseRank;\n};\n\noptional<Result> preArrangeStaged(const Tri& start, int totalLimit,\n                                  const vector<StagePlan>& stages,\n                                  const vector<vector<int>>& adj,\n                                  const vector<pair<int, int>>& idx2coord,\n                                  const vector<vector<int>>& idxOf) {\n    if (totalLimit <= 0) return nullopt;\n    Tri board = start;\n    vector<array<int, 4>> ops;\n    for (const auto& st : stages) {\n        if ((int)ops.size() >= totalLimit) return nullopt;\n        int stageCap = min(st.stageLimit, totalLimit - (int)ops.size());\n        if (stageCap <= 0) return nullopt;\n        auto sub = preArrangeSmart(board, st.depth, stageCap, st.candLimit, st.baseRank,\n                                   adj, idx2coord, idxOf);\n        if (!sub) return nullopt;\n        if ((int)ops.size() + (int)sub->ops.size() > totalLimit) return nullopt;\n        ops.insert(ops.end(), sub->ops.begin(), sub->ops.end());\n        board = sub->board;\n    }\n    Result res;\n    res.board = move(board);\n    res.ops = move(ops);\n    return res;\n}\n\noptional<Result> preArrangeBottomSmart(const Tri& start, int depth, int limit,\n                                       int candLimit, int baseRankWeight,\n                                       const vector<vector<int>>& adj,\n                                       const vector<pair<int, int>>& idx2coord,\n                                       const vector<vector<int>>& idxOf) {\n    if (limit <= 0 || candLimit <= 0) return nullopt;\n    depth = max(1, min(depth, N));\n    int startX = max(0, N - depth);\n    vector<int> targets;\n    for (int x = N - 1; x >= startX; --x)\n        for (int y = 0; y <= x; ++y)\n            targets.push_back(idxOf[x][y]);\n\n    Tri board = start;\n    vector<array<int, 4>> ops;\n    vector<char> blocked(TOTAL, false);\n    vector<int> dist(TOTAL), parent(TOTAL), order(TOTAL);\n    iota(order.begin(), order.end(), 0);\n    const int INF = 1e9;\n\n    for (int targetIdx : targets) {\n        if ((int)ops.size() >= limit) return nullopt;\n\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            auto [xa, ya] = idx2coord[a];\n            auto [xb, yb] = idx2coord[b];\n            return board[xa][ya] > board[xb][yb];\n        });\n\n        fill(dist.begin(), dist.end(), INF);\n        fill(parent.begin(), parent.end(), -1);\n        queue<int> q;\n        dist[targetIdx] = 0;\n        parent[targetIdx] = -2;\n        q.push(targetIdx);\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (blocked[v] && v != targetIdx) continue;\n                if (dist[v] != INF) continue;\n                dist[v] = dist[u] + 1;\n                parent[v] = u;\n                q.push(v);\n            }\n        }\n\n        vector<pair<int, int>> options;\n        int rank = 0;\n        for (int idx : order) {\n            if (blocked[idx]) continue;\n            if (dist[idx] != INF) {\n                options.emplace_back(idx, rank);\n                if ((int)options.size() >= candLimit) break;\n            }\n            ++rank;\n        }\n        if (options.empty()) return nullopt;\n\n        auto [tx, ty] = idx2coord[targetIdx];\n        int depthWeight = (tx - startX + 1);\n        int rankWeight = max(1, baseRankWeight * depthWeight);\n        int selected = -1;\n        long long bestScore = (1LL << 60);\n        for (auto [candIdx, candRank] : options) {\n            long long score = 1LL * dist[candIdx] + 1LL * rankWeight * candRank;\n            if (score < bestScore) {\n                bestScore = score;\n                selected = candIdx;\n            }\n        }\n        if (selected == -1) return nullopt;\n\n        vector<int> path;\n        int cur = selected;\n        path.push_back(cur);\n        while (cur != targetIdx) {\n            cur = parent[cur];\n            if (cur < 0) return nullopt;\n            path.push_back(cur);\n        }\n\n        for (size_t i = 0; i + 1 < path.size(); ++i) {\n            auto [x1, y1] = idx2coord[path[i]];\n            auto [x2, y2] = idx2coord[path[i + 1]];\n            if ((int)ops.size() >= limit) return nullopt;\n            ops.push_back({x1, y1, x2, y2});\n            swap(board[x1][y1], board[x2][y2]);\n        }\n        blocked[targetIdx] = true;\n    }\n\n    Result res;\n    res.board = move(board);\n    res.ops = move(ops);\n    return res;\n}\n\noptional<Result> preArrangeBandSmart(const Tri& start, int lo, int hi, int limit,\n                                     bool ascending, int candLimit, int baseRankWeight,\n                                     const vector<vector<int>>& adj,\n                                     const vector<pair<int, int>>& idx2coord,\n                                     const vector<vector<int>>& idxOf) {\n    if (limit <= 0 || candLimit <= 0) return nullopt;\n    lo = max(0, lo);\n    hi = min(N - 1, hi);\n    if (lo > hi) return nullopt;\n    vector<int> targets;\n    for (int x = lo; x <= hi; ++x)\n        for (int y = 0; y <= x; ++y)\n            targets.push_back(idxOf[x][y]);\n    if (targets.empty()) return nullopt;\n\n    Tri board = start;\n    vector<array<int, 4>> ops;\n    vector<char> blocked(TOTAL, false);\n    vector<int> dist(TOTAL), parent(TOTAL), order(TOTAL);\n    iota(order.begin(), order.end(), 0);\n    const int INF = 1e9;\n\n    for (int targetIdx : targets) {\n        if ((int)ops.size() >= limit) return nullopt;\n\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            auto [xa, ya] = idx2coord[a];\n            auto [xb, yb] = idx2coord[b];\n            return ascending ? board[xa][ya] < board[xb][yb]\n                             : board[xa][ya] > board[xb][yb];\n        });\n\n        fill(dist.begin(), dist.end(), INF);\n        fill(parent.begin(), parent.end(), -1);\n        queue<int> q;\n        dist[targetIdx] = 0;\n        parent[targetIdx] = -2;\n        q.push(targetIdx);\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (blocked[v] && v != targetIdx) continue;\n                if (dist[v] != INF)\n                    continue;\n                dist[v] = dist[u] + 1;\n                parent[v] = u;\n                q.push(v);\n            }\n        }\n\n        vector<pair<int, int>> options;\n        int rank = 0;\n        for (int idx : order) {\n            if (blocked[idx]) continue;\n            if (dist[idx] != INF) {\n                options.emplace_back(idx, rank);\n                if ((int)options.size() >= candLimit) break;\n            }\n            ++rank;\n        }\n        if (options.empty()) return nullopt;\n\n        auto [tx, ty] = idx2coord[targetIdx];\n        int depthWeight = ascending ? (hi - tx + 1) : (tx - lo + 1);\n        int rankWeight = max(1, baseRankWeight * depthWeight);\n        int selected = -1;\n        long long bestScore = (1LL << 60);\n        for (auto [candIdx, candRank] : options) {\n            long long score = 1LL * dist[candIdx] + 1LL * rankWeight * candRank;\n            if (score < bestScore) {\n                bestScore = score;\n                selected = candIdx;\n            }\n        }\n        if (selected == -1) return nullopt;\n\n        vector<int> path;\n        int cur = selected;\n        path.push_back(cur);\n        while (cur != targetIdx) {\n            cur = parent[cur];\n            if (cur < 0) return nullopt;\n            path.push_back(cur);\n        }\n\n        for (size_t i = 0; i + 1 < path.size(); ++i) {\n            auto [x1, y1] = idx2coord[path[i]];\n            auto [x2, y2] = idx2coord[path[i + 1]];\n            if ((int)ops.size() >= limit) return nullopt;\n            ops.push_back({x1, y1, x2, y2});\n            swap(board[x1][y1], board[x2][y2]);\n        }\n        blocked[targetIdx] = true;\n    }\n\n    Result res;\n    res.board = move(board);\n    res.ops = move(ops);\n    return res;\n}\n\noptional<Result> pipelineTopBottomTop(const Tri& start, int totalLimit,\n                                      const vector<StagePlan>& topStage1,\n                                      int bottomDepth, int bottomCand, int bottomRank,\n                                      const vector<StagePlan>& topStage2,\n                                      const vector<vector<int>>& adj,\n                                      const vector<pair<int, int>>& idx2coord,\n                                      const vector<vector<int>>& idxOf) {\n    if (totalLimit <= 0) return nullopt;\n    Tri board = start;\n    vector<array<int, 4>> ops;\n\n    auto applyStage = [&](const vector<StagePlan>& plan) -> bool {\n        if (plan.empty()) return true;\n        if ((int)ops.size() >= totalLimit) return false;\n        int cap = totalLimit - (int)ops.size();\n        auto res = preArrangeStaged(board, cap, plan, adj, idx2coord, idxOf);\n        if (!res) return false;\n        if ((int)ops.size() + (int)res->ops.size() > totalLimit) return false;\n        ops.insert(ops.end(), res->ops.begin(), res->ops.end());\n        board = res->board;\n        return true;\n    };\n\n    if (!applyStage(topStage1)) return nullopt;\n    if ((int)ops.size() >= totalLimit) return nullopt;\n    {\n        int cap = totalLimit - (int)ops.size();\n        auto bottom = preArrangeBottomSmart(board, bottomDepth, cap,\n                                            bottomCand, bottomRank,\n                                            adj, idx2coord, idxOf);\n        if (!bottom) return nullopt;\n        if ((int)ops.size() + (int)bottom->ops.size() > totalLimit) return nullopt;\n        ops.insert(ops.end(), bottom->ops.begin(), bottom->ops.end());\n        board = bottom->board;\n    }\n    if (!applyStage(topStage2)) return nullopt;\n\n    Result res;\n    res.board = move(board);\n    res.ops = move(ops);\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Tri initial(N);\n    for (int x = 0; x < N; ++x) {\n        initial[x].resize(x + 1);\n        for (int y = 0; y <= x; ++y)\n            cin >> initial[x][y];\n    }\n\n    vector<vector<int>> idxOf(N);\n    vector<pair<int, int>> idx2coord(TOTAL);\n    int cur = 0;\n    for (int x = 0; x < N; ++x) {\n        idxOf[x].resize(x + 1);\n        for (int y = 0; y <= x; ++y) {\n            idxOf[x][y] = cur;\n            idx2coord[cur] = {x, y};\n            ++cur;\n        }\n    }\n\n    vector<vector<int>> adj(TOTAL);\n    for (int x = 0; x < N; ++x)\n        for (int y = 0; y <= x; ++y) {\n            int idx = idxOf[x][y];\n            auto add = [&](int nx, int ny) {\n                if (inRange(nx, ny))\n                    adj[idx].push_back(idxOf[nx][ny]);\n            };\n            add(x - 1, y - 1);\n            add(x - 1, y);\n            add(x, y - 1);\n            add(x, y + 1);\n            add(x + 1, y);\n            add(x + 1, y + 1);\n        }\n\n    Result baseline = runBaseline(initial);\n    ensureValid(baseline, initial);\n    Result best = baseline;\n    int bestK = best.ops.size();\n\n    uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n    seed ^= (uint64_t)initial[0][0] << 21;\n    XorShift rng(seed);\n\n    const double TIME_LIMIT = 1.98;\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n\n    vector<int> modes = {0, 1, 2, 3, 4, 5, 6, 7};\n\n    auto tryPriority = [&](const Tri& startBoard, const vector<array<int, 4>>& prefixOps, int maxAttempts) {\n        for (int t = 0; t < maxAttempts; ++t) {\n            if (elapsed() > TIME_LIMIT) break;\n            int remaining = bestK - (int)prefixOps.size();\n            if (remaining <= 1) break;\n            int bound = remaining - 1;\n            Result suffix;\n            int mode = modes[(rng.next() + t) % modes.size()];\n            if (runPriorityFix(startBoard, bound, suffix, rng, mode)) {\n                int total = prefixOps.size() + suffix.ops.size();\n                if (total >= bestK) continue;\n                Result cand;\n                cand.board = suffix.board;\n                cand.ops.reserve(total);\n                cand.ops.insert(cand.ops.end(), prefixOps.begin(), prefixOps.end());\n                cand.ops.insert(cand.ops.end(), suffix.ops.begin(), suffix.ops.end());\n                if (ensureValid(cand, initial)) {\n                    best = move(cand);\n                    bestK = best.ops.size();\n                }\n            }\n        }\n    };\n\n    tryPriority(initial, {}, 650);\n\n    auto processPre = [&](const Tri& board, vector<array<int, 4>> prefix, int attemptsPriority) {\n        if ((int)prefix.size() >= bestK) return;\n        Result pre;\n        pre.board = board;\n        pre.ops = move(prefix);\n\n        if (countViolations(pre.board) == 0) {\n            Result cand = pre;\n            if ((int)cand.ops.size() < bestK && ensureValid(cand, initial)) {\n                best = move(cand);\n                bestK = best.ops.size();\n            }\n        }\n        if (elapsed() > TIME_LIMIT) return;\n\n        Result baseAfterPre = runBaseline(pre.board);\n        int totalOps = pre.ops.size() + baseAfterPre.ops.size();\n        if (totalOps < bestK && totalOps <= LIMIT) {\n            Result cand;\n            cand.board = baseAfterPre.board;\n            cand.ops.reserve(totalOps);\n            cand.ops.insert(cand.ops.end(), pre.ops.begin(), pre.ops.end());\n            cand.ops.insert(cand.ops.end(), baseAfterPre.ops.begin(), baseAfterPre.ops.end());\n            if (ensureValid(cand, initial)) {\n                best = move(cand);\n                bestK = best.ops.size();\n            }\n        }\n        tryPriority(pre.board, pre.ops, attemptsPriority);\n    };\n\n    auto tryPre = [&](auto generator, int attemptsPriority) {\n        if (elapsed() > TIME_LIMIT) return;\n        int limitForPre = bestK - 1;\n        if (limitForPre <= 0) return;\n        auto preOpt = generator(limitForPre);\n        if (!preOpt) return;\n        processPre(preOpt->board, preOpt->ops, attemptsPriority);\n    };\n\n    vector<int> simpleDepths = {4, 6, 8, 9};\n    for (int depth : simpleDepths) {\n        tryPre([&](int limit) {\n            return preArrangeSimple(initial, depth, limit, adj, idx2coord, idxOf);\n        }, 90);\n    }\n\n    vector<int> smartDepths = {5, 6, 7, 8, 9, 10};\n    vector<pair<int, int>> smartParams = {{24, 3}, {28, 4}, {32, 4}, {36, 5}};\n    for (int depth : smartDepths)\n        for (auto [candLim, baseRank] : smartParams)\n            tryPre([&](int limit) {\n                return preArrangeSmart(initial, depth, limit,\n                                       candLim, baseRank, adj, idx2coord, idxOf);\n            }, 130);\n\n    vector<vector<StagePlan>> stagePlans = {\n        {{4, 220, 18, 3}, {7, 360, 24, 4}},\n        {{5, 240, 18, 3}, {8, 360, 26, 4}},\n        {{4, 180, 16, 3}, {6, 220, 20, 3}, {9, 360, 28, 4}},\n        {{5, 200, 18, 3}, {7, 260, 22, 4}, {10, 360, 30, 5}},\n        {{4, 150, 16, 3}, {7, 300, 22, 4}, {9, 320, 26, 4}},\n        {{6, 200, 20, 4}, {8, 260, 24, 4}, {10, 320, 28, 5}},\n        {{5, 180, 18, 3}, {6, 200, 20, 4}, {8, 240, 24, 4}, {10, 300, 30, 5}}\n    };\n    for (const auto& plan : stagePlans)\n        tryPre([&](int limit) {\n            return preArrangeStaged(initial, limit, plan, adj, idx2coord, idxOf);\n        }, 180);\n\n    vector<int> bottomDepths = {3, 4, 5, 6, 7};\n    vector<pair<int, int>> bottomParams = {{24, 3}, {28, 4}, {32, 4}, {36, 5}};\n    for (int depth : bottomDepths)\n        for (auto [candLim, baseRank] : bottomParams)\n            tryPre([&](int limit) {\n                return preArrangeBottomSmart(initial, depth, limit,\n                                              candLim, baseRank, adj, idx2coord, idxOf);\n            }, 130);\n\n    vector<tuple<int,int,bool,int,int>> bandConfigs = {\n        {4, 10, true, 30, 3},\n        {6, 12, true, 30, 3},\n        {9, 15, false, 28, 3},\n        {11, 17, false, 30, 4}\n    };\n    for (auto [lo, hi, asc, cand, baseRank] : bandConfigs) {\n        tryPre([&](int limit) {\n            return preArrangeBandSmart(initial, lo, hi, limit, asc, cand, baseRank,\n                                       adj, idx2coord, idxOf);\n        }, 140);\n    }\n\n    vector<vector<StagePlan>> hybridTopStages = {\n        {{4, 180, 16, 3}},\n        {{5, 200, 18, 3}},\n        {{6, 200, 20, 4}},\n        {{6, 220, 20, 4}, {7, 260, 22, 4}}\n    };\n    vector<vector<StagePlan>> hybridPolishStages = {\n        {{6, 200, 18, 3}},\n        {{7, 220, 20, 4}},\n        {{8, 240, 22, 4}},\n        {{5, 180, 18, 3}, {7, 240, 22, 4}}\n    };\n    vector<tuple<int,int,int>> hybridBottom = {\n        {4, 28, 4}, {5, 30, 4}, {6, 32, 4}\n    };\n\n    for (const auto& topStage : hybridTopStages) {\n        for (const auto& bottomCfg : hybridBottom) {\n            int bDepth, bCand, bRank;\n            tie(bDepth, bCand, bRank) = bottomCfg;\n            for (const auto& polishStage : hybridPolishStages)\n                tryPre([&](int limit) -> optional<Result> {\n                    return pipelineTopBottomTop(\n                        initial, limit,\n                        topStage, bDepth, bCand, bRank,\n                        polishStage, adj, idx2coord, idxOf\n                    );\n                }, 160);\n        }\n    }\n\n    if (!ensureValid(best, initial)) {\n        best = baseline;\n        ensureValid(best, initial);\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (const auto& op : best.ops)\n        cout << op[0] << ' ' << op[1] << ' ' << op[2] << ' ' << op[3] << '\\n';\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int DX[4] = {1, -1, 0, 0};\nconst int DY[4] = {0, 0, 1, -1};\n\nconst int EMPTY     = -1;\nconst int ENTRANCE  = -2;\nconst int OBSTACLE  = -3;\nconst int TEMPBLOCK = -4;\n\nint D;\nint entrance_i, entrance_j;\nvector<vector<int>> grid;\nvector<vector<int>> dist_from_entrance;\nvector<pair<int,int>> target_order;\nvector<vector<int>> target_rank;\nvector<int> remaining_small;   // unseen IDs prefix counts\nvector<int> empty_prefix;      // empty ranks prefix counts\nint total_cells = 0;\nint empty_cells_remaining = 0;\nlong long tie_counter = 0;\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < D && 0 <= y && y < D;\n}\n\nvector<vector<int>> compute_dist(const vector<vector<int>>& base_grid) {\n    const int INF = 1e9;\n    vector<vector<int>> dist(D, vector<int>(D, INF));\n    queue<pair<int,int>> q;\n    q.push({entrance_i, entrance_j});\n    dist[entrance_i][entrance_j] = 0;\n    while (!q.empty()) {\n        auto [x, y] = q.front(); q.pop();\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = x + DX[dir];\n            int ny = y + DY[dir];\n            if (!inside(nx, ny)) continue;\n            if (base_grid[nx][ny] == OBSTACLE) continue;\n            if (dist[nx][ny] != INF) continue;\n            dist[nx][ny] = dist[x][y] + 1;\n            q.push({nx, ny});\n        }\n    }\n    return dist;\n}\n\nbool is_safe_offline(vector<vector<int>>& state, int x, int y, int remain) {\n    if (state[x][y] != 0) return false;\n    state[x][y] = -1;\n    queue<int> q;\n    vector<char> visited(D * D, 0);\n    int start = entrance_i * D + entrance_j;\n    q.push(start);\n    visited[start] = 1;\n    int reachable = 0;\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int cx = v / D;\n        int cy = v % D;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = cx + DX[dir];\n            int ny = cy + DY[dir];\n            if (!inside(nx, ny)) continue;\n            int nid = nx * D + ny;\n            if (visited[nid]) continue;\n            if (state[nx][ny] == -1) continue;\n            visited[nid] = 1;\n            q.push(nid);\n            if (state[nx][ny] == 0) ++reachable;\n        }\n    }\n    state[x][y] = 0;\n    return reachable == remain - 1;\n}\n\nvector<pair<int,int>> compute_target_order(const vector<vector<int>>& base_grid) {\n    vector<vector<int>> state(D, vector<int>(D, -1));\n    int remain = 0;\n    for (int i = 0; i < D; ++i) {\n        for (int j = 0; j < D; ++j) {\n            if (base_grid[i][j] == OBSTACLE) continue;\n            if (i == entrance_i && j == entrance_j) {\n                state[i][j] = -2;\n            } else {\n                state[i][j] = 0;\n                ++remain;\n            }\n        }\n    }\n\n    vector<pair<int,int>> elimination;\n    elimination.reserve(remain);\n\n    while (remain > 0) {\n        pair<int,int> best = {-1, -1};\n        int bestScore = INT_MIN;\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (state[i][j] != 0) continue;\n                if (!is_safe_offline(state, i, j, remain)) continue;\n                int score = dist_from_entrance[i][j] * 1000 - (abs(i - entrance_i) + abs(j - entrance_j));\n                if (score > bestScore) {\n                    bestScore = score;\n                    best = {i, j};\n                }\n            }\n        }\n        if (best.first == -1) {\n            for (int i = 0; i < D && best.first == -1; ++i) {\n                for (int j = 0; j < D; ++j) {\n                    if (state[i][j] == 0) {\n                        best = {i, j};\n                        break;\n                    }\n                }\n            }\n        }\n        elimination.push_back(best);\n        state[best.first][best.second] = -1;\n        --remain;\n    }\n\n    vector<pair<int,int>> retrieval = elimination;\n    reverse(retrieval.begin(), retrieval.end());\n    return retrieval;\n}\n\nbool is_safe_cell(int x, int y) {\n    grid[x][y] = TEMPBLOCK;\n    queue<int> q;\n    vector<char> visited(D * D, 0);\n    int start = entrance_i * D + entrance_j;\n    q.push(start);\n    visited[start] = 1;\n    int reachable = 0;\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int cx = v / D;\n        int cy = v % D;\n        for (int dir = 0; dir < 4; ++dir) {\n            int nx = cx + DX[dir];\n            int ny = cy + DY[dir];\n            if (!inside(nx, ny)) continue;\n            int nid = nx * D + ny;\n            if (visited[nid]) continue;\n            int val = grid[nx][ny];\n            if (val == OBSTACLE || val == TEMPBLOCK) continue;\n            if (val >= 0) continue;\n            visited[nid] = 1;\n            q.push(nid);\n            if (val == EMPTY) ++reachable;\n        }\n    }\n    grid[x][y] = EMPTY;\n    return reachable == empty_cells_remaining - 1;\n}\n\npair<int,int> choose_cell(int number) {\n    const long long DIFF_WEIGHT  = 4000;\n    const long long NEG_EXTRA    = 25000;\n    const long long DIST_WEIGHT  = 200;\n    const long long DEGREE_WEIGHT = 80;\n\n    int bestDef = INT_MAX;\n    long long bestCost = (1LL << 60);\n    pair<int,int> best = {-1, -1};\n\n    for (int i = 0; i < D; ++i) {\n        for (int j = 0; j < D; ++j) {\n            if (grid[i][j] != EMPTY) continue;\n            if (!is_safe_cell(i, j)) continue;\n            int r = target_rank[i][j];\n            if (r < 0) continue;\n\n            int deficit = 0;\n            if (bestDef != 0) {\n                for (int q = r; q < total_cells; ++q) {\n                    int need = remaining_small[q];\n                    if (need == 0) continue;\n                    int avail = empty_prefix[q] - 1;\n                    if (avail < need) {\n                        deficit += need - avail;\n                        if (bestDef != INT_MAX && deficit > bestDef) break;\n                    }\n                }\n                if (bestDef != INT_MAX && deficit > bestDef) continue;\n            } else {\n                bool ok = true;\n                for (int q = r; q < total_cells; ++q) {\n                    int need = remaining_small[q];\n                    if (need == 0) continue;\n                    int avail = empty_prefix[q] - 1;\n                    if (avail < need) { ok = false; break; }\n                }\n                if (!ok) continue;\n                deficit = 0;\n            }\n\n            long long diff = (long long)r - number;\n            long long absdiff = llabs(diff);\n            long long cost = absdiff * absdiff * DIFF_WEIGHT;\n            if (diff < 0) cost += (-diff) * NEG_EXTRA;\n            cost += (long long)dist_from_entrance[i][j] * DIST_WEIGHT;\n\n            int degree = 0;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + DX[dir];\n                int nj = j + DY[dir];\n                if (!inside(ni, nj)) continue;\n                if (grid[ni][nj] == EMPTY) ++degree;\n            }\n            int leafScore = max(0, 3 - degree);\n            cost += (long long)leafScore * DEGREE_WEIGHT;\n\n            cost = (cost << 4) + (tie_counter++ & 15);\n\n            if (deficit < bestDef || (deficit == bestDef && cost < bestCost)) {\n                bestDef = deficit;\n                bestCost = cost;\n                best = {i, j};\n            }\n        }\n    }\n\n    if (best.first == -1) {\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (grid[i][j] == EMPTY && is_safe_cell(i, j)) {\n                    best = {i, j};\n                    break;\n                }\n            }\n            if (best.first != -1) break;\n        }\n    }\n\n    return best;\n}\n\nvector<pair<int,int>> build_retrieval_order() {\n    vector<pair<int,int>> order;\n    order.reserve(total_cells);\n    vector<vector<char>> cleared(D, vector<char>(D, 0));\n    vector<vector<char>> in_queue(D, vector<char>(D, 0));\n    cleared[entrance_i][entrance_j] = 1;\n\n    struct Node {\n        int value;\n        int rank;\n        long long tie;\n        int x, y;\n    };\n    struct Cmp {\n        bool operator()(const Node& a, const Node& b) const {\n            if (a.value != b.value) return a.value > b.value;\n            if (a.rank  != b.rank)  return a.rank > b.rank;\n            return a.tie > b.tie;\n        }\n    };\n\n    priority_queue<Node, vector<Node>, Cmp> pq;\n\n    auto push_node = [&](int x, int y) {\n        if (!inside(x, y)) return;\n        if (cleared[x][y]) return;\n        if (grid[x][y] < 0) return;\n        if (in_queue[x][y]) return;\n        pq.push(Node{grid[x][y], target_rank[x][y], tie_counter++, x, y});\n        in_queue[x][y] = 1;\n    };\n\n    for (int dir = 0; dir < 4; ++dir)\n        push_node(entrance_i + DX[dir], entrance_j + DY[dir]);\n\n    auto refill = [&]() {\n        if (!pq.empty()) return;\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                if (grid[i][j] < 0 || cleared[i][j] || in_queue[i][j]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + DX[dir];\n                    int nj = j + DY[dir];\n                    if (!inside(ni, nj)) continue;\n                    if (cleared[ni][nj]) {\n                        push_node(i, j);\n                        break;\n                    }\n                }\n            }\n        }\n    };\n\n    while ((int)order.size() < total_cells) {\n        refill();\n        if (pq.empty()) break;\n        Node cur = pq.top(); pq.pop();\n        if (cleared[cur.x][cur.y]) continue;\n        order.push_back({cur.x, cur.y});\n        cleared[cur.x][cur.y] = 1;\n        grid[cur.x][cur.y] = EMPTY;\n        for (int dir = 0; dir < 4; ++dir)\n            push_node(cur.x + DX[dir], cur.y + DY[dir]);\n    }\n    return order;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    if (!(cin >> D >> N)) return 0;\n    entrance_i = 0;\n    entrance_j = (D - 1) / 2;\n\n    grid.assign(D, vector<int>(D, EMPTY));\n    for (int k = 0; k < N; ++k) {\n        int r, c; cin >> r >> c;\n        grid[r][c] = OBSTACLE;\n    }\n    grid[entrance_i][entrance_j] = ENTRANCE;\n\n    vector<vector<int>> base_grid = grid;\n\n    dist_from_entrance = compute_dist(base_grid);\n    target_order = compute_target_order(base_grid);\n    total_cells = (int)target_order.size();\n\n    target_rank.assign(D, vector<int>(D, -1));\n    for (int idx = 0; idx < total_cells; ++idx) {\n        auto [x, y] = target_order[idx];\n        target_rank[x][y] = idx;\n    }\n\n    remaining_small.assign(total_cells, 0);\n    empty_prefix.assign(total_cells, 0);\n    for (int q = 0; q < total_cells; ++q) {\n        remaining_small[q] = q + 1;\n        empty_prefix[q] = q + 1;\n    }\n\n    empty_cells_remaining = total_cells;\n    int total_containers = total_cells;\n\n    for (int step = 0; step < total_containers; ++step) {\n        int t; cin >> t;\n        for (int q = t; q < total_cells; ++q)\n            --remaining_small[q];\n\n        auto cell = choose_cell(t);\n        grid[cell.first][cell.second] = t;\n        --empty_cells_remaining;\n\n        int r = target_rank[cell.first][cell.second];\n        for (int q = r; q < total_cells; ++q)\n            --empty_prefix[q];\n\n        cout << cell.first << ' ' << cell.second << '\\n' << flush;\n    }\n\n    auto retrieval = build_retrieval_order();\n    for (auto [x, y] : retrieval)\n        cout << x << ' ' << y << '\\n';\n    cout.flush();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr double TIME_LIMIT = 1.90;  // seconds\n    static constexpr double ZERO_WEIGHT = 4.0;  // weight of zero adjacency in priority score\n    static constexpr double ANCHOR_JITTER = 6.0;\n\n    int n, m, m1, N;\n    vector<int> initialBoard;\n    vector<int> initialColorCount;\n    vector<vector<int>> colorCells;\n    vector<double> centroidRow, centroidCol;\n    vector<int> baseAdjCount;\n    vector<char> canTouchZero;\n    vector<int> bestBoard;\n    int bestZero = 0;\n\n    chrono::steady_clock::time_point startTime;\n    mt19937_64 rng;\n\n    const array<int, 4> di{-1, 1, 0, 0};\n    const array<int, 4> dj{0, 0, -1, 1};\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    inline int adjIndex(int a, int b) const { return a * m1 + b; }\n\n    inline void changeAdj(vector<int>& adj, int a, int b, int delta) const {\n        if (a == b || delta == 0) return;\n        int idx1 = adjIndex(a, b);\n        int idx2 = adjIndex(b, a);\n        adj[idx1] += delta;\n        adj[idx2] += delta;\n    }\n\n    inline int getAdj(const vector<int>& adj, int a, int b) const {\n        return adj[adjIndex(a, b)];\n    }\n\n    bool checkConnectivity(int removeIdx, int color, const vector<int>& board,\n                           const vector<int>& colorCount, vector<int>& visitStamp,\n                           int& visitToken) const {\n        int remaining = colorCount[color] - 1;\n        if (remaining <= 0) return false;\n\n        int start = -1;\n        int ri = removeIdx / n;\n        int rj = removeIdx % n;\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = ri + di[dir];\n            int nj = rj + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n            int nidx = ni * n + nj;\n            if (board[nidx] == color) {\n                start = nidx;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        visitToken++;\n        if (visitToken == INT_MAX) {\n            fill(visitStamp.begin(), visitStamp.end(), 0);\n            visitToken = 1;\n        }\n        visitStamp[start] = visitToken;\n        queue<int> q;\n        q.push(start);\n        int reached = 0;\n        while (!q.empty()) {\n            int cur = q.front();\n            q.pop();\n            reached++;\n            if (reached == remaining) return true;\n            int ci = cur / n;\n            int cj = cur % n;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = ci + di[dir];\n                int nj = cj + dj[dir];\n                if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n                int nidx = ni * n + nj;\n                if (nidx == removeIdx) continue;\n                if (board[nidx] == color && visitStamp[nidx] != visitToken) {\n                    visitStamp[nidx] = visitToken;\n                    q.push(nidx);\n                }\n            }\n        }\n        return reached == remaining;\n    }\n\n    bool tryRemove(int idx, vector<int>& board, vector<int>& colorCount,\n                   vector<int>& adjCount, vector<int>& visitStamp, int& visitToken) const {\n        int c = board[idx];\n        if (c == 0 || !canTouchZero[c] || colorCount[c] <= 1) return false;\n\n        int i = idx / n;\n        int j = idx % n;\n\n        int zeroEdges = 0;\n        int sameNeighbors = 0;\n        int neighborColors[4];\n        int neighborEdges[4];\n        int neighborKinds = 0;\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                zeroEdges++;\n                continue;\n            }\n            int nidx = ni * n + nj;\n            int d = board[nidx];\n            if (d == 0) {\n                zeroEdges++;\n            } else if (d == c) {\n                sameNeighbors++;\n            } else {\n                if (!canTouchZero[d]) return false;\n                bool found = false;\n                for (int t = 0; t < neighborKinds; ++t) {\n                    if (neighborColors[t] == d) {\n                        neighborEdges[t]++;\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) {\n                    neighborColors[neighborKinds] = d;\n                    neighborEdges[neighborKinds] = 1;\n                    neighborKinds++;\n                }\n            }\n        }\n\n        if (zeroEdges == 0) return false;\n        if (getAdj(adjCount, c, 0) <= zeroEdges) return false;\n        for (int t = 0; t < neighborKinds; ++t) {\n            int d = neighborColors[t];\n            if (getAdj(adjCount, c, d) <= neighborEdges[t]) return false;\n        }\n\n        if (sameNeighbors >= 2) {\n            if (!checkConnectivity(idx, c, board, colorCount, visitStamp, visitToken)) {\n                return false;\n            }\n        }\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                changeAdj(adjCount, c, 0, -1);\n            } else {\n                int nidx = ni * n + nj;\n                int d = board[nidx];\n                if (d == c) continue;\n                changeAdj(adjCount, c, d, -1);\n            }\n        }\n\n        board[idx] = 0;\n        colorCount[c]--;\n        colorCount[0]++;\n\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = i + di[dir];\n            int nj = j + dj[dir];\n            if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n            int nidx = ni * n + nj;\n            int d = board[nidx];\n            if (d == 0) continue;\n            changeAdj(adjCount, 0, d, +1);\n        }\n\n        return true;\n    }\n\n    struct IterationResult {\n        vector<int> board;\n        int zeroCount;\n    };\n\n    IterationResult runIteration(bool usePriority, const vector<pair<double, double>>& anchors) {\n        vector<int> board = initialBoard;\n        vector<int> colorCount = initialColorCount;\n        vector<int> adjCount = baseAdjCount;\n        vector<int> visitStamp(N, 0);\n        int visitToken = 1;\n\n        auto zeroAdjCount = [&](int idx) -> int {\n            int i = idx / n;\n            int j = idx % n;\n            int cnt = 0;\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + di[dir];\n                int nj = j + dj[dir];\n                if (ni < 0 || ni >= n || nj < 0 || nj >= n) {\n                    cnt++;\n                } else if (board[ni * n + nj] == 0) {\n                    cnt++;\n                }\n            }\n            return cnt;\n        };\n\n        if (usePriority) {\n            struct Entry {\n                double score;\n                int idx;\n                int version;\n                bool operator<(const Entry& other) const { return score < other.score; }\n            };\n            priority_queue<Entry> pq;\n            vector<int> version(N, 0);\n            uniform_real_distribution<double> noiseDist(0.0, 1.0);\n\n            auto pushCandidate = [&](int idx) {\n                if (idx < 0 || idx >= N) return;\n                if (board[idx] == 0) return;\n                int c = board[idx];\n                if (!canTouchZero[c]) return;\n                int zeroAdj = zeroAdjCount(idx);\n                if (zeroAdj == 0) return;\n                int i = idx / n;\n                int j = idx % n;\n                double dist = fabs(i - anchors[c].first) + fabs(j - anchors[c].second);\n                double score = dist + ZERO_WEIGHT * zeroAdj + noiseDist(rng);\n                int ver = ++version[idx];\n                pq.push({score, idx, ver});\n            };\n\n            for (int i = 0; i < n; ++i) {\n                pushCandidate(i * n);\n                pushCandidate(i * n + (n - 1));\n            }\n            for (int j = 0; j < n; ++j) {\n                pushCandidate(j);\n                pushCandidate((n - 1) * n + j);\n            }\n\n            while (!pq.empty()) {\n                if (elapsed() > TIME_LIMIT) break;\n                auto cur = pq.top();\n                pq.pop();\n                if (cur.version != version[cur.idx]) continue;\n                int idx = cur.idx;\n                if (board[idx] == 0) continue;\n                int c = board[idx];\n                if (!canTouchZero[c]) continue;\n                if (zeroAdjCount(idx) == 0) continue;\n                if (!tryRemove(idx, board, colorCount, adjCount, visitStamp, visitToken)) continue;\n                int ci = idx / n;\n                int cj = idx % n;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = ci + di[dir];\n                    int nj = cj + dj[dir];\n                    if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n                    pushCandidate(ni * n + nj);\n                }\n            }\n        } else {\n            vector<int> frontier;\n            frontier.reserve(N);\n            vector<char> inFrontier(N, 0);\n\n            auto pushCandidate = [&](int idx) {\n                if (idx < 0 || idx >= N) return;\n                if (board[idx] == 0) return;\n                if (inFrontier[idx]) return;\n                int c = board[idx];\n                if (!canTouchZero[c]) return;\n                if (zeroAdjCount(idx) == 0) return;\n                inFrontier[idx] = 1;\n                frontier.push_back(idx);\n            };\n\n            for (int i = 0; i < n; ++i) {\n                pushCandidate(i * n);\n                pushCandidate(i * n + (n - 1));\n            }\n            for (int j = 0; j < n; ++j) {\n                pushCandidate(j);\n                pushCandidate((n - 1) * n + j);\n            }\n\n            while (!frontier.empty()) {\n                if (elapsed() > TIME_LIMIT) break;\n                int pos = rng() % frontier.size();\n                int idx = frontier[pos];\n                frontier[pos] = frontier.back();\n                frontier.pop_back();\n                inFrontier[idx] = 0;\n                if (board[idx] == 0) continue;\n                int c = board[idx];\n                if (!canTouchZero[c]) continue;\n                if (zeroAdjCount(idx) == 0) continue;\n                if (!tryRemove(idx, board, colorCount, adjCount, visitStamp, visitToken)) continue;\n                int ci = idx / n;\n                int cj = idx % n;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = ci + di[dir];\n                    int nj = cj + dj[dir];\n                    if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue;\n                    pushCandidate(ni * n + nj);\n                }\n            }\n        }\n\n        return {std::move(board), colorCount[0]};\n    }\n\n    void readInput() {\n        cin >> n >> m;\n        m1 = m + 1;\n        N = n * n;\n        initialBoard.assign(N, 0);\n        colorCells.assign(m1, {});\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int c;\n                cin >> c;\n                initialBoard[i * n + j] = c;\n                colorCells[c].push_back(i * n + j);\n            }\n        }\n    }\n\n    void precompute() {\n        initialColorCount.assign(m1, 0);\n        centroidRow.assign(m1, 0.0);\n        centroidCol.assign(m1, 0.0);\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int idx = i * n + j;\n                int c = initialBoard[idx];\n                initialColorCount[c]++;\n                centroidRow[c] += i;\n                centroidCol[c] += j;\n            }\n        }\n        for (int c = 0; c <= m; ++c) {\n            if (initialColorCount[c] > 0) {\n                centroidRow[c] /= initialColorCount[c];\n                centroidCol[c] /= initialColorCount[c];\n            }\n        }\n\n        baseAdjCount.assign(m1 * m1, 0);\n        auto addEdge = [&](int a, int b) {\n            if (a == b) return;\n            int idx1 = adjIndex(a, b);\n            int idx2 = adjIndex(b, a);\n            baseAdjCount[idx1] += 1;\n            baseAdjCount[idx2] += 1;\n        };\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                int idx = i * n + j;\n                int c = initialBoard[idx];\n                if (i + 1 < n) addEdge(c, initialBoard[(i + 1) * n + j]);\n                if (j + 1 < n) addEdge(c, initialBoard[i * n + (j + 1)]);\n                if (i == 0) addEdge(c, 0);\n                if (i == n - 1) addEdge(c, 0);\n                if (j == 0) addEdge(c, 0);\n                if (j == n - 1) addEdge(c, 0);\n            }\n        }\n\n        canTouchZero.assign(m1, 0);\n        canTouchZero[0] = 1;\n        for (int c = 1; c <= m; ++c) {\n            if (baseAdjCount[adjIndex(c, 0)] > 0) {\n                canTouchZero[c] = 1;\n            }\n        }\n\n        bestBoard = initialBoard;\n        bestZero = initialColorCount[0];\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        readInput();\n        precompute();\n\n        startTime = chrono::steady_clock::now();\n        rng.seed(startTime.time_since_epoch().count());\n\n        vector<pair<double, double>> anchors(m1, {0.0, 0.0});\n        vector<pair<double, double>> dummyAnchors(m1, {0.0, 0.0});\n        uniform_real_distribution<double> jitterDist(-ANCHOR_JITTER, ANCHOR_JITTER);\n\n        int iteration = 0;\n        while (elapsed() < TIME_LIMIT) {\n            bool usePriority = (iteration % 3 != 2);\n            if (usePriority) {\n                bool useRandomCellAnchor = (iteration % 6 == 0);\n                for (int c = 1; c <= m; ++c) {\n                    if (useRandomCellAnchor && !colorCells[c].empty()) {\n                        int pick = colorCells[c][rng() % colorCells[c].size()];\n                        anchors[c].first = pick / n;\n                        anchors[c].second = pick % n;\n                    } else {\n                        double baseR = centroidRow[c];\n                        double baseC = centroidCol[c];\n                        anchors[c].first = clamp(baseR + jitterDist(rng), 0.0, double(n - 1));\n                        anchors[c].second = clamp(baseC + jitterDist(rng), 0.0, double(n - 1));\n                    }\n                }\n            }\n            const auto& anchorRef = usePriority ? anchors : dummyAnchors;\n            IterationResult res = runIteration(usePriority, anchorRef);\n            if (res.zeroCount > bestZero) {\n                bestZero = res.zeroCount;\n                bestBoard = std::move(res.board);\n            }\n            iteration++;\n            if (elapsed() > TIME_LIMIT) break;\n        }\n\n        for (int i = 0; i < n; ++i) {\n            for (int j = 0; j < n; ++j) {\n                if (j) cout << ' ';\n                cout << bestBoard[i * n + j];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Query {\n    vector<int> idx;\n    vector<int8_t> coeff;\n    double scale = 1.0;\n    double invScale = 1.0;\n    double invScaleSq = 1.0;\n    int result = 0;\n};\n\nvector<double> estimate_weights(const vector<Query>& queries, int N, mt19937& rng) {\n    vector<double> w(N, 1.0);\n    if (queries.empty()) return w;\n    const double minW = 1e-6;\n    const double lr_main = 0.05;\n    const double lr_eq = 0.04;\n    const double reg = 1e-4;\n    uniform_int_distribution<int> qdist(0, (int)queries.size() - 1);\n    int iterations = min(200000, max(20000, 30 * (int)queries.size()));\n\n    for (int iter = 0; iter < iterations; ++iter) {\n        const Query& qu = queries[qdist(rng)];\n        if (qu.idx.empty()) continue;\n        double diff = 0.0;\n        for (size_t k = 0; k < qu.idx.size(); ++k) diff += w[qu.idx[k]] * qu.coeff[k];\n\n        if (qu.result == 0) {\n            double grad_base = diff * qu.invScaleSq;\n            for (size_t k = 0; k < qu.idx.size(); ++k) {\n                int idx = qu.idx[k];\n                double grad = grad_base * qu.coeff[k] + reg * w[idx];\n                w[idx] -= lr_eq * grad;\n                if (w[idx] < minW) w[idx] = minW;\n            }\n        } else {\n            int y = qu.result;\n            double score = diff * qu.invScale;\n            double s = y * score;\n            double sigma;\n            if (s >= 0) {\n                double e = exp(-s);\n                sigma = e / (1.0 + e);\n            } else {\n                double e = exp(s);\n                sigma = 1.0 / (1.0 + e);\n            }\n            double grad_base = -y * sigma * qu.invScale;\n            for (size_t k = 0; k < qu.idx.size(); ++k) {\n                int idx = qu.idx[k];\n                double grad = grad_base * qu.coeff[k] + reg * w[idx];\n                w[idx] -= lr_main * grad;\n                if (w[idx] < minW) w[idx] = minW;\n            }\n        }\n\n        if ((iter & 255) == 0) {\n            double mean = accumulate(w.begin(), w.end(), 0.0) / N;\n            if (mean > 0) for (double &val : w) val /= mean;\n        }\n    }\n\n    double perceptron_lr = 0.02;\n    for (int pass = 0; pass < 2; ++pass) {\n        for (const Query& qu : queries) {\n            if (qu.idx.empty()) continue;\n            double diff = 0.0;\n            for (size_t k = 0; k < qu.idx.size(); ++k) diff += w[qu.idx[k]] * qu.coeff[k];\n            double margin = 0.05 * qu.scale;\n            bool violation = false;\n            if (qu.result == 1) violation = diff < margin;\n            else if (qu.result == -1) violation = diff > -margin;\n            else violation = fabs(diff) > margin;\n            if (!violation) continue;\n\n            if (qu.result == 0) {\n                double grad_base = diff * qu.invScaleSq;\n                for (size_t k = 0; k < qu.idx.size(); ++k) {\n                    int idx = qu.idx[k];\n                    w[idx] -= perceptron_lr * grad_base * qu.coeff[k];\n                    if (w[idx] < minW) w[idx] = minW;\n                }\n            } else {\n                for (size_t k = 0; k < qu.idx.size(); ++k) {\n                    int idx = qu.idx[k];\n                    w[idx] += perceptron_lr * qu.result * qu.coeff[k];\n                    if (w[idx] < minW) w[idx] = minW;\n                }\n            }\n        }\n        double mean = accumulate(w.begin(), w.end(), 0.0) / N;\n        if (mean > 0) for (double &val : w) val /= mean;\n    }\n\n    double sum = accumulate(w.begin(), w.end(), 0.0);\n    if (sum > 0) {\n        double factor = (double)N / sum;\n        for (double &val : w) val *= factor;\n    }\n    return w;\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    vector<Query> queries;\n    queries.reserve(Q);\n    vector<double> biasScore(N, 0.0);\n\n    mt19937 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> uniform01(0.0, 1.0);\n\n    auto ask = [&](const vector<int>& L, const vector<int>& R) -> int {\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string resp;\n        if (!(cin >> resp)) exit(0);\n        int res = 0;\n        if (!resp.empty()) {\n            if (resp[0] == '>') res = 1;\n            else if (resp[0] == '<') res = -1;\n        }\n\n        Query q;\n        q.result = res;\n        q.idx.reserve(L.size() + R.size());\n        q.coeff.reserve(L.size() + R.size());\n        for (int x : L) { q.idx.push_back(x); q.coeff.push_back(1); }\n        for (int x : R) { q.idx.push_back(x); q.coeff.push_back(-1); }\n        int len = (int)q.idx.size();\n        if (len == 0) len = 1;\n        q.scale = sqrt((double)len);\n        q.invScale = 1.0 / q.scale;\n        q.invScaleSq = q.invScale * q.invScale;\n        queries.push_back(std::move(q));\n\n        if (res == 1) {\n            for (int x : L) biasScore[x] += 1.0;\n            for (int x : R) biasScore[x] -= 1.0;\n        } else if (res == -1) {\n            for (int x : L) biasScore[x] -= 1.0;\n            for (int x : R) biasScore[x] += 1.0;\n        }\n        return res;\n    };\n\n    int champion = 0;\n    for (int i = 1; i < N && (int)queries.size() < Q; ++i) {\n        vector<int> L = {champion};\n        vector<int> R = {i};\n        int res = ask(L, R);\n        if (res == -1) champion = i;\n    }\n\n    while ((int)queries.size() < Q) {\n        vector<int> L, R;\n        int type = rng() % 3;\n        if (type == 0) {\n            int a = rng() % N;\n            int b = rng() % N;\n            while (b == a) b = rng() % N;\n            L = {a};\n            R = {b};\n        } else if (type == 1) {\n            vector<int> picks;\n            picks.reserve(4);\n            while ((int)picks.size() < 4) {\n                int x = rng() % N;\n                bool ok = true;\n                for (int y : picks) if (y == x) { ok = false; break; }\n                if (ok) picks.push_back(x);\n            }\n            L = {picks[0], picks[1]};\n            R = {picks[2], picks[3]};\n        } else {\n            double density = 0.18 + 0.22 * (double)N / 100.0;\n            density = min(0.35, max(0.18, density));\n            for (int i = 0; i < N; ++i) {\n                double v = uniform01(rng);\n                if (v < density) L.push_back(i);\n                else if (v < 2.0 * density) R.push_back(i);\n            }\n            if (L.empty() && !R.empty()) {\n                L.push_back(R.back());\n                R.pop_back();\n            }\n            if (R.empty() && !L.empty()) {\n                R.push_back(L.back());\n                L.pop_back();\n            }\n            if (L.empty() || R.empty()) {\n                int a = rng() % N;\n                int b = rng() % N;\n                while (b == a) b = rng() % N;\n                L = {a};\n                R = {b};\n            }\n        }\n        ask(L, R);\n    }\n\n    vector<double> weights = estimate_weights(queries, N, rng);\n\n    double maxAbs = 0.0;\n    for (double s : biasScore) maxAbs = max(maxAbs, fabs(s));\n    if (maxAbs < 1e-9) maxAbs = 1.0;\n\n    const double alpha = 0.4;\n    for (int i = 0; i < N; ++i) {\n        double factor = 1.0 + alpha * (biasScore[i] / maxAbs);\n        weights[i] *= factor;\n        if (weights[i] < 1e-6) weights[i] = 1e-6;\n    }\n\n    double sumW = accumulate(weights.begin(), weights.end(), 0.0);\n    if (sumW > 0) {\n        double factor = (double)N / sumW;\n        for (double &w : weights) w *= factor;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        double noise = 0.98 + 0.04 * uniform01(rng);\n        weights[i] *= noise;\n    }\n    sumW = accumulate(weights.begin(), weights.end(), 0.0);\n    if (sumW > 0) {\n        double factor = (double)N / sumW;\n        for (double &w : weights) w *= factor;\n    }\n\n    double mean = accumulate(weights.begin(), weights.end(), 0.0) / N;\n    double var = 0.0;\n    for (double w : weights) {\n        double diff = w - mean;\n        var += diff * diff;\n    }\n    var /= N;\n    if (var < 1e-4) {\n        for (int i = 0; i < N; ++i) {\n            double factor = 1.0 + 0.5 * (biasScore[i] / maxAbs);\n            weights[i] = max(1e-6, factor);\n        }\n        double sum = accumulate(weights.begin(), weights.end(), 0.0);\n        if (sum > 0) {\n            double coeff = (double)N / sum;\n            for (double &w : weights) w *= coeff;\n        }\n    }\n\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (weights[a] != weights[b]) return weights[a] > weights[b];\n        return a < b;\n    });\n\n    vector<vector<int>> orders;\n    orders.push_back(order);\n    {\n        vector<int> rev = order;\n        reverse(rev.begin(), rev.end());\n        orders.push_back(rev);\n    }\n    {\n        vector<int> snake;\n        int l = 0, r = N - 1;\n        while (l <= r) {\n            snake.push_back(order[l++]);\n            if (l <= r) snake.push_back(order[r--]);\n        }\n        orders.push_back(snake);\n    }\n    {\n        vector<int> rnd = order;\n        shuffle(rnd.begin(), rnd.end(), rng);\n        orders.push_back(rnd);\n    }\n\n    double total = accumulate(weights.begin(), weights.end(), 0.0);\n    double target = (D == 0) ? 0.0 : total / D;\n\n    struct PartitionState {\n        vector<int> assign;\n        vector<double> sums;\n        vector<int> sizes;\n    };\n\n    auto build_state = [&](const vector<int>& seq) -> PartitionState {\n        PartitionState st;\n        st.assign.assign(N, 0);\n        st.sums.assign(D, 0.0);\n        st.sizes.assign(D, 0);\n        for (int idx : seq) {\n            int best = 0;\n            for (int d = 1; d < D; ++d) {\n                if (st.sums[d] + 1e-9 < st.sums[best]) best = d;\n                else if (fabs(st.sums[d] - st.sums[best]) <= 1e-9 &&\n                         st.sizes[d] < st.sizes[best]) best = d;\n            }\n            st.assign[idx] = best;\n            st.sums[best] += weights[idx];\n            st.sizes[best]++;\n        }\n        return st;\n    };\n\n    auto random_local = [&](PartitionState& st) {\n        if (D <= 1) return;\n        int LS_ITERS = 10000 + 200 * N;\n        uniform_int_distribution<int> distItem(0, N - 1);\n        uniform_int_distribution<int> distBucket(0, D - 1);\n        for (int iter = 0; iter < LS_ITERS; ++iter) {\n            if (rng() & 1) {\n                int i = distItem(rng);\n                int from = st.assign[i];\n                int to = distBucket(rng);\n                if (from == to) continue;\n                double wi = weights[i];\n                double sa = st.sums[from];\n                double sb = st.sums[to];\n                double oldScore = (sa - target) * (sa - target) + (sb - target) * (sb - target);\n                double na = sa - wi;\n                double nb = sb + wi;\n                double newScore = (na - target) * (na - target) + (nb - target) * (nb - target);\n                if (newScore + 1e-9 < oldScore) {\n                    st.assign[i] = to;\n                    st.sums[from] = na;\n                    st.sums[to] = nb;\n                    st.sizes[from]--;\n                    st.sizes[to]++;\n                }\n            } else {\n                int i = distItem(rng);\n                int j = distItem(rng);\n                if (st.assign[i] == st.assign[j]) continue;\n                int a = st.assign[i];\n                int b = st.assign[j];\n                double wi = weights[i];\n                double wj = weights[j];\n                double sa = st.sums[a];\n                double sb = st.sums[b];\n                double oldScore = (sa - target) * (sa - target) + (sb - target) * (sb - target);\n                double na = sa - wi + wj;\n                double nb = sb - wj + wi;\n                double newScore = (na - target) * (na - target) + (nb - target) * (nb - target);\n                if (newScore + 1e-9 < oldScore) {\n                    st.assign[i] = b;\n                    st.assign[j] = a;\n                    st.sums[a] = na;\n                    st.sums[b] = nb;\n                }\n            }\n        }\n    };\n\n    auto best_move = [&](PartitionState& st) -> bool {\n        const double EPS = 1e-7;\n        double bestDelta = -EPS;\n        int bestItem = -1, bestTo = -1;\n        for (int i = 0; i < N; ++i) {\n            int from = st.assign[i];\n            double wi = weights[i];\n            double sa = st.sums[from];\n            double baseA = (sa - target) * (sa - target);\n            for (int to = 0; to < D; ++to) {\n                if (to == from) continue;\n                double sb = st.sums[to];\n                double baseB = (sb - target) * (sb - target);\n                double na = sa - wi;\n                double nb = sb + wi;\n                double newScore = (na - target) * (na - target) + (nb - target) * (nb - target);\n                double delta = newScore - (baseA + baseB);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestItem = i;\n                    bestTo = to;\n                }\n            }\n        }\n        if (bestItem == -1) return false;\n        int from = st.assign[bestItem];\n        double wi = weights[bestItem];\n        st.assign[bestItem] = bestTo;\n        st.sums[from] -= wi;\n        st.sums[bestTo] += wi;\n        st.sizes[from]--;\n        st.sizes[bestTo]++;\n        return true;\n    };\n\n    auto best_swap = [&](PartitionState& st) -> bool {\n        const double EPS = 1e-7;\n        double bestDelta = -EPS;\n        int bestI = -1, bestJ = -1;\n        for (int i = 0; i < N; ++i) {\n            int a = st.assign[i];\n            double wi = weights[i];\n            double sa = st.sums[a];\n            double baseA = (sa - target) * (sa - target);\n            for (int j = i + 1; j < N; ++j) {\n                int b = st.assign[j];\n                if (a == b) continue;\n                double wj = weights[j];\n                double sb = st.sums[b];\n                double baseB = (sb - target) * (sb - target);\n                double na = sa - wi + wj;\n                double nb = sb - wj + wi;\n                double newScore = (na - target) * (na - target) + (nb - target) * (nb - target);\n                double delta = newScore - (baseA + baseB);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                }\n            }\n        }\n        if (bestI == -1) return false;\n        int a = st.assign[bestI];\n        int b = st.assign[bestJ];\n        double wi = weights[bestI];\n        double wj = weights[bestJ];\n        st.assign[bestI] = b;\n        st.assign[bestJ] = a;\n        st.sums[a] += -wi + wj;\n        st.sums[b] += -wj + wi;\n        return true;\n    };\n\n    auto improve_state = [&](PartitionState& st) {\n        const int MOVE_LIMIT1 = 250;\n        const int SWAP_LIMIT = 120;\n        const int MOVE_LIMIT2 = 120;\n        for (int i = 0; i < MOVE_LIMIT1; ++i) if (!best_move(st)) break;\n        for (int i = 0; i < SWAP_LIMIT; ++i) if (!best_swap(st)) break;\n        for (int i = 0; i < MOVE_LIMIT2; ++i) if (!best_move(st)) break;\n    };\n\n    auto compute_penalty = [&](const vector<double>& sums) -> double {\n        double pen = 0.0;\n        for (double s : sums) {\n            double diff = s - target;\n            pen += diff * diff;\n        }\n        return pen;\n    };\n\n    vector<int> bestAssign(N, 0);\n    double bestPenalty = numeric_limits<double>::infinity();\n    bool found = false;\n\n    for (size_t idx = 0; idx < orders.size(); ++idx) {\n        PartitionState st = build_state(orders[idx]);\n        if (idx == 0) random_local(st);\n        improve_state(st);\n        double pen = compute_penalty(st.sums);\n        if (!found || pen + 1e-6 < bestPenalty) {\n            found = true;\n            bestPenalty = pen;\n            bestAssign = st.assign;\n        }\n    }\n\n    if (!found) {\n        iota(bestAssign.begin(), bestAssign.end(), 0);\n        for (int i = 0; i < N; ++i) bestAssign[i] %= D;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << bestAssign[i];\n    }\n    cout << '\\n' << flush;\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int n, m, bucketSize;\n    vector<vector<int>> stacks;\n    struct Pos {\n        int stack = -1;\n        int idx = -1;\n    };\n    vector<Pos> pos;\n    vector<int> targetStack;\n    vector<pair<int,int>> operations;\n    long long energy = 0;\n\n    int stack_min(int idx) const {\n        if (stacks[idx].empty()) return 1e9;\n        int mn = stacks[idx][0];\n        for (int v : stacks[idx]) mn = min(mn, v);\n        return mn;\n    }\n\n    int choose_destination(int source, const vector<int>& chunk, int chunk_min) {\n        const int INF = 1e9;\n        struct Cand {\n            int idx;\n            bool safe;\n            int stackMin;\n            int match;\n            int height;\n            int top;\n        };\n        Cand bestSafe{ -1, false, -1, -1, -1, -1 };\n        Cand bestUnsafe{ -1, false, -1, -1, -1, -1 };\n        for (int i = 0; i < m; ++i) {\n            if (i == source) continue;\n            bool empty = stacks[i].empty();\n            int topVal = empty ? INF : stacks[i].back();\n            bool safe = empty || topVal >= chunk_min;\n            int smin = empty ? INF : stack_min(i);\n            int match = 0;\n            for (int v : chunk) if (targetStack[v] == i) ++match;\n            int height = (int)stacks[i].size();\n            Cand cand{i, safe, smin, match, height, empty ? INF : topVal};\n\n            if (safe) {\n                if (bestSafe.idx == -1) bestSafe = cand;\n                else {\n                    auto &b = bestSafe;\n                    if (cand.stackMin != b.stackMin) { if (cand.stackMin > b.stackMin) bestSafe = cand; continue; }\n                    if (cand.match != b.match) { if (cand.match > b.match) bestSafe = cand; continue; }\n                    if (cand.height != b.height) { if (cand.height < b.height) bestSafe = cand; continue; }\n                    if (cand.top != b.top) { if (cand.top > b.top) bestSafe = cand; continue; }\n                    if (cand.idx < b.idx) bestSafe = cand;\n                }\n            } else {\n                if (bestUnsafe.idx == -1) bestUnsafe = cand;\n                else {\n                    auto &b = bestUnsafe;\n                    if (cand.top != b.top) { if (cand.top > b.top) bestUnsafe = cand; continue; }\n                    if (cand.stackMin != b.stackMin) { if (cand.stackMin > b.stackMin) bestUnsafe = cand; continue; }\n                    if (cand.height != b.height) { if (cand.height < b.height) bestUnsafe = cand; continue; }\n                    if (cand.match != b.match) { if (cand.match > b.match) bestUnsafe = cand; continue; }\n                    if (cand.idx < b.idx) bestUnsafe = cand;\n                }\n            }\n        }\n        if (bestSafe.idx != -1) return bestSafe.idx;\n        if (bestUnsafe.idx != -1) return bestUnsafe.idx;\n        for (int i = 0; i < m; ++i) if (i != source) return i;\n        return source; // should never happen\n    }\n\n    void move_segment(int box, int dest) {\n        auto p = pos[box];\n        int s = p.stack;\n        int idx = p.idx;\n        if (s == -1 || dest == -1 || s == dest) return;\n        vector<int> segment;\n        segment.reserve(stacks[s].size() - idx);\n        for (int i = idx; i < (int)stacks[s].size(); ++i) segment.push_back(stacks[s][i]);\n        stacks[s].resize(idx);\n        int destStart = stacks[dest].size();\n        stacks[dest].insert(stacks[dest].end(), segment.begin(), segment.end());\n        for (int t = 0; t < (int)segment.size(); ++t) {\n            pos[segment[t]].stack = dest;\n            pos[segment[t]].idx = destStart + t;\n        }\n        operations.emplace_back(box, dest + 1);\n        energy += (long long)segment.size() + 1;\n    }\n\n    void remove_box(int box) {\n        auto p = pos[box];\n        int s = p.stack;\n        if (s == -1) return;\n        stacks[s].pop_back();\n        pos[box].stack = -1;\n        pos[box].idx = -1;\n        operations.emplace_back(box, 0);\n    }\n\n    void solve() {\n        cin >> n >> m;\n        bucketSize = n / m;\n        stacks.assign(m, {});\n        pos.assign(n + 1, {});\n        targetStack.assign(n + 1, 0);\n        for (int v = 1; v <= n; ++v) {\n            targetStack[v] = min(m - 1, (v - 1) / bucketSize);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            stacks[i].resize(bucketSize);\n            for (int j = 0; j < bucketSize; ++j) {\n                int v; cin >> v;\n                stacks[i][j] = v;\n                pos[v].stack = i;\n                pos[v].idx = j;\n            }\n        }\n\n        for (int v = 1; v <= n; ++v) {\n            while (true) {\n                auto p = pos[v];\n                int s = p.stack;\n                if (s == -1) break;\n                int idx = p.idx;\n                if (idx == (int)stacks[s].size() - 1) {\n                    remove_box(v);\n                    break;\n                } else {\n                    vector<int> chunk;\n                    chunk.reserve(stacks[s].size() - idx - 1);\n                    int chunk_min = INT_MAX;\n                    for (int t = idx + 1; t < (int)stacks[s].size(); ++t) {\n                        int val = stacks[s][t];\n                        chunk.push_back(val);\n                        chunk_min = min(chunk_min, val);\n                    }\n                    int dest = choose_destination(s, chunk, chunk_min);\n                    if (dest == s) {\n                        for (int i = 0; i < m; ++i) if (i != s) { dest = i; break; }\n                    }\n                    int box_to_move = stacks[s][idx + 1];\n                    move_segment(box_to_move, dest);\n                }\n            }\n        }\n\n        for (auto [v, i] : operations) {\n            cout << v << ' ' << i << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MOVE_LIMIT = 100000;\n    static constexpr double TIME_LIMIT = 1.95;\n    static constexpr double FINAL_MARGIN = 0.15;\n    static constexpr array<char, 4> DIR_CHARS = {'U', 'D', 'L', 'R'};\n    static constexpr double LOCAL_TWO = 0.03;\n    static constexpr double LOCAL_OR = 0.03;\n    static constexpr double LOCAL_RAND = 0.015;\n    static constexpr int POOL_LIMIT = 6;\n\n    struct Tour {\n        long long cost;\n        vector<int> perm;\n    };\n\n    int N;\n    int totalNodes;\n    vector<string> h, v;\n    vector<vector<int>> d;\n    vector<int> d_flat;\n    vector<vector<int>> adj;\n    vector<array<int, 4>> dirNeighbor;\n    vector<int> node_r, node_c;\n    vector<uint16_t> dist_all;\n    vector<uint16_t> next_all;\n    vector<vector<int>> visitTimes;\n    vector<vector<int>> candidates;\n\n    mt19937 rng;\n    chrono::steady_clock::time_point start_time;\n\n    Solver()\n        : rng(static_cast<uint32_t>(chrono::steady_clock::now().time_since_epoch().count())) {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n        read_input();\n    }\n\n    void read_input() {\n        cin >> N;\n        h.resize(max(0, N - 1));\n        for (int i = 0; i < N - 1; ++i) cin >> h[i];\n        v.resize(N);\n        for (int i = 0; i < N; ++i) cin >> v[i];\n        d.assign(N, vector<int>(N));\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                cin >> d[i][j];\n\n        totalNodes = N * N;\n        node_r.resize(totalNodes);\n        node_c.resize(totalNodes);\n        d_flat.resize(totalNodes);\n        int idx = 0;\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j, ++idx) {\n                node_r[idx] = i;\n                node_c[idx] = j;\n                d_flat[idx] = d[i][j];\n            }\n\n        adj.assign(totalNodes, {});\n        dirNeighbor.assign(totalNodes, array<int, 4>{-1, -1, -1, -1});\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int u = i * N + j;\n                if (i + 1 < N && h[i][j] == '0') {\n                    int w = (i + 1) * N + j;\n                    adj[u].push_back(w);\n                    adj[w].push_back(u);\n                    dirNeighbor[u][1] = w;\n                    dirNeighbor[w][0] = u;\n                }\n                if (j + 1 < N && v[i][j] == '0') {\n                    int w = i * N + (j + 1);\n                    adj[u].push_back(w);\n                    adj[w].push_back(u);\n                    dirNeighbor[u][3] = w;\n                    dirNeighbor[w][2] = u;\n                }\n            }\n        }\n        visitTimes.assign(totalNodes, {});\n    }\n\n    void solve() {\n        start_time = chrono::steady_clock::now();\n\n        string bestRoute = build_dfs_route();\n        long double bestScore = evaluate(bestRoute);\n\n        precompute_all_pairs();\n        build_candidates(min(35, max(1, totalNodes - 1)));\n\n        vector<vector<int>> perms;\n        perms.reserve(16);\n        auto add_perm = [&](vector<int> perm) {\n            if ((int)perm.size() != totalNodes) return;\n            normalize_order(perm);\n            perms.push_back(move(perm));\n        };\n\n        add_perm(order_snake_rows());\n        add_perm(order_snake_cols());\n        add_perm(order_morton());\n        add_perm(order_bfs(false));\n        add_perm(order_bfs(true));\n        add_perm(order_dfs(false));\n        add_perm(order_dfs(true));\n        add_perm(order_nearest());\n        add_perm(order_sorted_d());\n        add_perm(order_cheapest_insertion(false));\n        add_perm(order_cheapest_insertion(true));\n        add_perm(order_random());\n        add_perm(order_random());\n\n        if (perms.empty()) {\n            cout << bestRoute << '\\n';\n            return;\n        }\n\n        vector<pair<long long, int>> orderCost;\n        orderCost.reserve(perms.size());\n        for (int i = 0; i < (int)perms.size(); ++i) {\n            long long cost = tour_cost(perms[i]);\n            orderCost.emplace_back(cost, i);\n        }\n        sort(orderCost.begin(), orderCost.end());\n\n        vector<pair<long long, vector<int>>> candidatePerms;\n        candidatePerms.reserve(40);\n        vector<Tour> pool;\n\n        auto add_pool = [&](const vector<int>& perm, long long cost) {\n            for (auto& t : pool) {\n                if (t.cost == cost && t.perm == perm) return;\n            }\n            pool.push_back({cost, perm});\n            sort(pool.begin(), pool.end(),\n                 [](const Tour& a, const Tour& b) { return a.cost < b.cost; });\n            if ((int)pool.size() > POOL_LIMIT) pool.pop_back();\n        };\n\n        auto push_candidate = [&](vector<int> perm, long long cost) {\n            normalize_order(perm);\n            candidatePerms.emplace_back(cost, perm);\n            add_pool(perm, cost);\n        };\n\n        push_candidate(perms[orderCost[0].second], orderCost[0].first);\n        if (orderCost.size() >= 2) {\n            push_candidate(perms[orderCost[1].second], orderCost[1].first);\n        }\n\n        vector<int> bestPerm = perms[orderCost[0].second];\n        normalize_order(bestPerm);\n        long long bestPermCost = orderCost[0].first;\n\n        int localCount = min(6, (int)orderCost.size());\n        for (int t = 0; t < localCount; ++t) {\n            if (elapsed() > TIME_LIMIT - FINAL_MARGIN - 0.05) break;\n            int idx = orderCost[t].second;\n            vector<int> perm = perms[idx];\n            long long cost = orderCost[t].first;\n            improve_perm(perm, cost, LOCAL_TWO, LOCAL_OR, LOCAL_RAND);\n            push_candidate(perm, cost);\n            if (cost < bestPermCost) {\n                bestPermCost = cost;\n                bestPerm = perm;\n            }\n        }\n\n        if (!bestPerm.empty() && elapsed() < TIME_LIMIT - FINAL_MARGIN - 0.02) {\n            double now = elapsed();\n            double randStop = min(TIME_LIMIT - FINAL_MARGIN, now + 0.18);\n            random_two_opt(bestPerm, bestPermCost, randStop, 25000);\n            normalize_order(bestPerm);\n            now = elapsed();\n            double orStop = min(TIME_LIMIT - FINAL_MARGIN, now + 0.08);\n            or_opt_local(bestPerm, bestPermCost, orStop);\n            normalize_order(bestPerm);\n            now = elapsed();\n            double detStop = min(TIME_LIMIT - FINAL_MARGIN, now + 0.05);\n            two_opt_candidates(bestPerm, bestPermCost, detStop);\n            normalize_order(bestPerm);\n            push_candidate(bestPerm, bestPermCost);\n        }\n\n        if (!bestPerm.empty()) {\n            pool_iterated_search(pool, bestPerm, bestPermCost, candidatePerms);\n        }\n        push_candidate(bestPerm, bestPermCost);\n\n        sort(candidatePerms.begin(), candidatePerms.end(),\n             [](const auto& a, const auto& b) {\n                 if (a.first != b.first) return a.first < b.first;\n                 return a.second < b.second;\n             });\n\n        vector<pair<long long, vector<int>>> selected;\n        selected.reserve(8);\n        for (auto& cand : candidatePerms) {\n            bool duplicate = false;\n            for (auto& sel : selected) {\n                if (sel.first == cand.first && sel.second == cand.second) {\n                    duplicate = true;\n                    break;\n                }\n            }\n            if (!duplicate) selected.push_back(cand);\n            if ((int)selected.size() >= 6) break;\n        }\n\n        for (auto& cand : selected) {\n            if (cand.first > MOVE_LIMIT) continue;\n            if (elapsed() > TIME_LIMIT - 0.02) break;\n            vector<int> perm = cand.second;\n            normalize_order(perm);\n            string route;\n            if (!build_route_from_perm(perm, route)) continue;\n            long double score = evaluate(route);\n            if (score < bestScore) {\n                bestScore = score;\n                bestRoute = route;\n            }\n        }\n\n        if (bestRoute.empty()) bestRoute = build_dfs_route();\n        cout << bestRoute << '\\n';\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void normalize_order(vector<int>& perm) const {\n        if (perm.empty()) return;\n        auto it = find(perm.begin(), perm.end(), 0);\n        if (it != perm.end() && it != perm.begin()) {\n            rotate(perm.begin(), it, perm.end());\n        }\n    }\n\n    string build_dfs_route() const {\n        string route;\n        route.reserve(totalNodes * 2);\n        vector<char> visited(totalNodes, 0);\n        auto dfs = [&](auto&& self, int u) -> void {\n            visited[u] = 1;\n            for (int dir = 0; dir < 4; ++dir) {\n                int nxt = dirNeighbor[u][dir];\n                if (nxt == -1 || visited[nxt]) continue;\n                route.push_back(DIR_CHARS[dir]);\n                self(self, nxt);\n                route.push_back(DIR_CHARS[dir ^ 1]);\n            }\n        };\n        dfs(dfs, 0);\n        return route;\n    }\n\n    void precompute_all_pairs() {\n        int n = totalNodes;\n        dist_all.assign((size_t)n * n, 0);\n        next_all.assign((size_t)n * n, 0);\n        vector<int> dist(n);\n        vector<int> parent(n);\n        vector<int> order(n);\n        vector<int> queue_buf(n);\n        vector<int> rootChild(n);\n\n        for (int s = 0; s < n; ++s) {\n            fill(dist.begin(), dist.end(), -1);\n            int head = 0, tail = 0;\n            queue_buf[tail++] = s;\n            dist[s] = 0;\n            parent[s] = -1;\n            int qsize = 0;\n            while (head < tail) {\n                int u = queue_buf[head++];\n                order[qsize++] = u;\n                for (int vtx : adj[u]) {\n                    if (dist[vtx] != -1) continue;\n                    dist[vtx] = dist[u] + 1;\n                    parent[vtx] = u;\n                    queue_buf[tail++] = vtx;\n                }\n            }\n            rootChild[s] = s;\n            for (int k = 1; k < qsize; ++k) {\n                int u = order[k];\n                int p = parent[u];\n                rootChild[u] = (p == s) ? u : rootChild[p];\n            }\n            size_t base = (size_t)s * n;\n            for (int t = 0; t < n; ++t) {\n                dist_all[base + t] = static_cast<uint16_t>(dist[t]);\n                next_all[base + t] = static_cast<uint16_t>(rootChild[t]);\n            }\n        }\n    }\n\n    void build_candidates(int K) {\n        if (totalNodes <= 1 || K <= 0) {\n            candidates.assign(totalNodes, {});\n            return;\n        }\n        candidates.assign(totalNodes, {});\n        vector<int> indices(totalNodes - 1);\n        for (int u = 0; u < totalNodes; ++u) {\n            int m = 0;\n            for (int v = 0; v < totalNodes; ++v) {\n                if (v == u) continue;\n                indices[m++] = v;\n            }\n            int need = min(K, m);\n            auto comp = [&](int a, int b) {\n                return dist_idx(u, a) < dist_idx(u, b);\n            };\n            if (need < m) {\n                nth_element(indices.begin(), indices.begin() + need, indices.begin() + m, comp);\n            }\n            sort(indices.begin(), indices.begin() + need, comp);\n            candidates[u].assign(indices.begin(), indices.begin() + need);\n        }\n    }\n\n    inline int dist_idx(int a, int b) const {\n        return dist_all[(size_t)a * totalNodes + b];\n    }\n\n    inline int next_idx(int a, int b) const {\n        return next_all[(size_t)a * totalNodes + b];\n    }\n\n    vector<int> order_snake_rows() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        for (int i = 0; i < N; ++i) {\n            if (i % 2 == 0) {\n                for (int j = 0; j < N; ++j) perm.push_back(i * N + j);\n            } else {\n                for (int j = N - 1; j >= 0; --j) perm.push_back(i * N + j);\n            }\n        }\n        return perm;\n    }\n\n    vector<int> order_snake_cols() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        for (int j = 0; j < N; ++j) {\n            if (j % 2 == 0) {\n                for (int i = 0; i < N; ++i) perm.push_back(i * N + j);\n            } else {\n                for (int i = N - 1; i >= 0; --i) perm.push_back(i * N + j);\n            }\n        }\n        return perm;\n    }\n\n    vector<int> order_morton() const {\n        vector<pair<uint32_t, int>> nodes;\n        nodes.reserve(totalNodes - 1);\n        for (int idx = 1; idx < totalNodes; ++idx) {\n            nodes.emplace_back(morton_code(node_r[idx], node_c[idx]), idx);\n        }\n        sort(nodes.begin(), nodes.end());\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        for (auto& p : nodes) perm.push_back(p.second);\n        return perm;\n    }\n\n    uint32_t morton_code(int r, int c) const {\n        uint32_t code = 0;\n        for (int i = 0; i < 6; ++i) {\n            code |= ((uint32_t)((r >> i) & 1)) << (2 * i + 1);\n            code |= ((uint32_t)((c >> i) & 1)) << (2 * i);\n        }\n        return code;\n    }\n\n    vector<int> order_bfs(bool randomize) {\n        vector<int> order;\n        order.reserve(totalNodes);\n        vector<char> visited(totalNodes, 0);\n        queue<int> q;\n        q.push(0);\n        visited[0] = 1;\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            order.push_back(u);\n            vector<int> neighbors = adj[u];\n            if (randomize) shuffle(neighbors.begin(), neighbors.end(), rng);\n            for (int vtx : neighbors) {\n                if (visited[vtx]) continue;\n                visited[vtx] = 1;\n                q.push(vtx);\n            }\n        }\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (!visited[vtx]) order.push_back(vtx);\n        }\n        return order;\n    }\n\n    vector<int> order_dfs(bool randomize) {\n        vector<int> order;\n        order.reserve(totalNodes);\n        vector<char> visited(totalNodes, 0);\n        vector<int> stack = {0};\n        while (!stack.empty()) {\n            int u = stack.back();\n            stack.pop_back();\n            if (visited[u]) continue;\n            visited[u] = 1;\n            order.push_back(u);\n            vector<int> neighbors = adj[u];\n            if (randomize) shuffle(neighbors.begin(), neighbors.end(), rng);\n            for (int vtx : neighbors) {\n                if (!visited[vtx]) stack.push_back(vtx);\n            }\n        }\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (!visited[vtx]) order.push_back(vtx);\n        }\n        return order;\n    }\n\n    vector<int> order_nearest() {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        vector<char> used(totalNodes, 0);\n        int cur = 0;\n        perm.push_back(cur);\n        used[cur] = 1;\n        for (int step = 1; step < totalNodes; ++step) {\n            int best = -1;\n            int bestDist = INT_MAX;\n            for (int vtx = 0; vtx < totalNodes; ++vtx) {\n                if (used[vtx]) continue;\n                int dd = dist_idx(cur, vtx);\n                if (best == -1 || dd < bestDist ||\n                    (dd == bestDist && (d_flat[vtx] > d_flat[best] ||\n                                        ((rng() & 1) && d_flat[vtx] == d_flat[best])))) {\n                    best = vtx;\n                    bestDist = dd;\n                }\n            }\n            if (best == -1) break;\n            perm.push_back(best);\n            used[best] = 1;\n            cur = best;\n        }\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (!used[vtx]) perm.push_back(vtx);\n        }\n        return perm;\n    }\n\n    vector<int> order_sorted_d() const {\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        vector<pair<int, int>> nodes;\n        nodes.reserve(totalNodes - 1);\n        for (int idx = 1; idx < totalNodes; ++idx) {\n            nodes.emplace_back(-d_flat[idx], idx);\n        }\n        sort(nodes.begin(), nodes.end());\n        for (auto& p : nodes) perm.push_back(p.second);\n        return perm;\n    }\n\n    vector<int> order_random() {\n        vector<int> perm(totalNodes);\n        iota(perm.begin(), perm.end(), 0);\n        if (totalNodes > 1) shuffle(perm.begin() + 1, perm.end(), rng);\n        return perm;\n    }\n\n    vector<int> order_cheapest_insertion(bool useFarthest) {\n        if (totalNodes == 1) return vector<int>{0};\n        vector<char> used(totalNodes, 0);\n        vector<int> perm;\n        perm.reserve(totalNodes);\n        perm.push_back(0);\n        used[0] = 1;\n\n        int second = -1;\n        int bestVal = useFarthest ? -1 : INT_MAX;\n        for (int vtx = 1; vtx < totalNodes; ++vtx) {\n            int val = dist_idx(0, vtx);\n            if (second == -1 ||\n                (!useFarthest && val < bestVal) ||\n                (useFarthest && val > bestVal)) {\n                second = vtx;\n                bestVal = val;\n            }\n        }\n        if (second == -1) second = 1;\n        perm.push_back(second);\n        used[second] = 1;\n\n        vector<int> unvisited;\n        unvisited.reserve(totalNodes - 2);\n        vector<int> bestDist(totalNodes, INT_MAX);\n        for (int vtx = 0; vtx < totalNodes; ++vtx) {\n            if (used[vtx]) continue;\n            unvisited.push_back(vtx);\n            bestDist[vtx] = min(dist_idx(vtx, 0), dist_idx(vtx, second));\n        }\n\n        while (!unvisited.empty()) {\n            int bestNode = -1;\n            int bestMetric = useFarthest ? -1 : INT_MAX;\n            size_t bestIdx = 0;\n            for (size_t idx = 0; idx < unvisited.size(); ++idx) {\n                int node = unvisited[idx];\n                int val = bestDist[node];\n                if (bestNode == -1 ||\n                    (!useFarthest && (val < bestMetric ||\n                                      (val == bestMetric &&\n                                       (d_flat[node] > d_flat[bestNode] ||\n                                        ((rng() & 1) && d_flat[node] == d_flat[bestNode]))))) ||\n                    (useFarthest && (val > bestMetric ||\n                                     (val == bestMetric &&\n                                      (d_flat[node] > d_flat[bestNode] ||\n                                       ((rng() & 1) && d_flat[node] == d_flat[bestNode])))))) {\n                    bestNode = node;\n                    bestMetric = val;\n                    bestIdx = idx;\n                }\n            }\n            int node = bestNode;\n            unvisited[bestIdx] = unvisited.back();\n            unvisited.pop_back();\n\n            int m = perm.size();\n            int bestPos = 0;\n            int bestDelta = INT_MAX;\n            for (int i = 0; i < m; ++i) {\n                int a = perm[i];\n                int b = perm[(i + 1) % m];\n                int delta = dist_idx(a, node) + dist_idx(node, b) - dist_idx(a, b);\n                if (delta < bestDelta || (delta == bestDelta && (rng() & 1))) {\n                    bestDelta = delta;\n                    bestPos = i;\n                }\n            }\n            perm.insert(perm.begin() + bestPos + 1, node);\n            used[node] = 1;\n            for (int rest : unvisited) {\n                bestDist[rest] = min(bestDist[rest], dist_idx(rest, node));\n            }\n        }\n        return perm;\n    }\n\n    long long tour_cost(const vector<int>& perm) const {\n        if (perm.empty()) return (long long)4e18;\n        long long cost = 0;\n        for (int i = 0; i + 1 < (int)perm.size(); ++i) {\n            cost += dist_idx(perm[i], perm[i + 1]);\n        }\n        cost += dist_idx(perm.back(), perm.front());\n        return cost;\n    }\n\n    void improve_perm(vector<int>& perm, long long& cost,\n                      double twoBudget, double orBudget, double randBudget) {\n        if (perm.empty()) return;\n        if (elapsed() >= TIME_LIMIT - FINAL_MARGIN) {\n            normalize_order(perm);\n            return;\n        }\n        double now = elapsed();\n        double detStop = min(TIME_LIMIT - FINAL_MARGIN, now + twoBudget);\n        if (detStop > now) two_opt_candidates(perm, cost, detStop);\n        if (elapsed() >= TIME_LIMIT - FINAL_MARGIN) {\n            normalize_order(perm);\n            return;\n        }\n        now = elapsed();\n        double orStop = min(TIME_LIMIT - FINAL_MARGIN, now + orBudget);\n        if (orStop > now) or_opt_local(perm, cost, orStop);\n        if (elapsed() >= TIME_LIMIT - FINAL_MARGIN) {\n            normalize_order(perm);\n            return;\n        }\n        now = elapsed();\n        double randStop = min(TIME_LIMIT - FINAL_MARGIN, now + randBudget);\n        if (randStop > now) random_two_opt(perm, cost, randStop, 12000);\n        normalize_order(perm);\n    }\n\n    long long two_opt_delta(const vector<int>& perm, int ii, int jj) const {\n        int n = perm.size();\n        int prev_i = (ii == 0) ? n - 1 : ii - 1;\n        int next_j = (jj + 1 == n) ? 0 : jj + 1;\n        int a = perm[prev_i];\n        int b = perm[ii];\n        int c = perm[jj];\n        int d = perm[next_j];\n        return (long long)dist_idx(a, c) + dist_idx(b, d)\n             - dist_idx(a, b) - dist_idx(c, d);\n    }\n\n    void two_opt_candidates(vector<int>& perm, long long& cost, double stopTime) {\n        int n = perm.size();\n        if (n <= 3) return;\n        if (elapsed() >= stopTime) return;\n        vector<int> pos(n);\n        for (int i = 0; i < n; ++i) pos[perm[i]] = i;\n        while (elapsed() < stopTime) {\n            bool improved = false;\n            for (int i = 0; i < n; ++i) {\n                int a = perm[i];\n                for (int b : candidates[a]) {\n                    int j = pos[b];\n                    if (i == j) continue;\n                    int ii = i, jj = j;\n                    if (ii > jj) swap(ii, jj);\n                    if (jj == ii || jj == ii + 1) continue;\n                    if (ii == 0 && jj == n - 1) continue;\n                    long long delta = two_opt_delta(perm, ii, jj);\n                    if (delta < 0) {\n                        reverse(perm.begin() + ii, perm.begin() + jj + 1);\n                        for (int k = ii; k <= jj; ++k) pos[perm[k]] = k;\n                        cost += delta;\n                        improved = true;\n                        break;\n                    }\n                }\n                if (improved) break;\n                if ((i & 31) == 0 && elapsed() >= stopTime) return;\n            }\n            if (!improved) break;\n        }\n    }\n\n    void or_opt_local(vector<int>& perm, long long& cost, double stopTime) {\n        int n = perm.size();\n        if (n <= 4 || elapsed() >= stopTime) return;\n        vector<int> pos(n);\n        auto rebuild_pos = [&]() {\n            for (int i = 0; i < n; ++i) pos[perm[i]] = i;\n        };\n        rebuild_pos();\n        while (elapsed() < stopTime) {\n            bool moved = false;\n            for (int len = 1; len <= 3; ++len) {\n                for (int st = 1; st + len <= n; ++st) {\n                    if (elapsed() >= stopTime) return;\n                    int en = st + len - 1;\n                    bool hasZero = false;\n                    for (int k = st; k <= en; ++k) {\n                        if (perm[k] == 0) {\n                            hasZero = true;\n                            break;\n                        }\n                    }\n                    if (hasZero) continue;\n                    int a = perm[st - 1];\n                    int b = perm[st];\n                    int c = perm[en];\n                    int d = (en + 1 < n) ? perm[en + 1] : perm[0];\n                    long long removeDelta =\n                        (long long)dist_idx(a, d) - dist_idx(a, b) - dist_idx(c, d);\n\n                    vector<int> posList;\n                    posList.reserve(24);\n                    auto try_add = [&](int insertAfter) {\n                        if (insertAfter < 0 || insertAfter >= n) return;\n                        if (insertAfter == n - 1) return;\n                        if (insertAfter >= st - 1 && insertAfter <= en) return;\n                        if (insertAfter == st - 2 && st - 2 >= 0) return;\n                        for (int val : posList)\n                            if (val == insertAfter) return;\n                        posList.push_back(insertAfter);\n                    };\n                    for (int cand : candidates[b]) {\n                        try_add(pos[cand]);\n                        if ((int)posList.size() >= 18) break;\n                    }\n                    for (int cand : candidates[c]) {\n                        try_add(pos[cand]);\n                        if ((int)posList.size() >= 24) break;\n                    }\n                    try_add(st - 2);\n                    try_add(en + 1);\n                    for (int t = 0; t < 3; ++t) try_add(rng() % (n - 1));\n\n                    for (int insertAfter : posList) {\n                        if (insertAfter < 0 || insertAfter >= n) continue;\n                        if (insertAfter == n - 1) continue;\n                        int x = perm[insertAfter];\n                        int y = (insertAfter + 1 < n) ? perm[insertAfter + 1] : perm[0];\n                        long long insertDelta =\n                            (long long)dist_idx(x, b) + dist_idx(c, y) - dist_idx(x, y);\n                        long long delta = removeDelta + insertDelta;\n                        if (delta < 0) {\n                            vector<int> segment(perm.begin() + st, perm.begin() + en + 1);\n                            perm.erase(perm.begin() + st, perm.begin() + en + 1);\n                            int insertIndex =\n                                (insertAfter < st) ? insertAfter + 1 : insertAfter - len + 1;\n                            perm.insert(perm.begin() + insertIndex, segment.begin(),\n                                        segment.end());\n                            cost += delta;\n                            n = perm.size();\n                            rebuild_pos();\n                            moved = true;\n                            goto NEXT_OUTER;\n                        }\n                    }\n                }\n            }\n        NEXT_OUTER:\n            if (!moved || elapsed() >= stopTime) break;\n        }\n    }\n\n    void random_two_opt(vector<int>& perm, long long& cost, double stopTime, int idleLimit) {\n        int n = perm.size();\n        if (n <= 3) return;\n        if (elapsed() >= stopTime) return;\n        vector<int> pos(n);\n        for (int i = 0; i < n; ++i) pos[perm[i]] = i;\n        int idle = 0;\n        while (elapsed() < stopTime && idle < idleLimit) {\n            int i = rng() % n;\n            int j = rng() % n;\n            if (i == j) continue;\n            int ii = i, jj = j;\n            if (ii > jj) swap(ii, jj);\n            if (jj == ii || jj == ii + 1) continue;\n            if (ii == 0 && jj == n - 1) continue;\n            long long delta = two_opt_delta(perm, ii, jj);\n            if (delta < 0) {\n                reverse(perm.begin() + ii, perm.begin() + jj + 1);\n                for (int k = ii; k <= jj; ++k) pos[perm[k]] = k;\n                cost += delta;\n                idle = 0;\n            } else {\n                ++idle;\n            }\n        }\n    }\n\n    void double_bridge(vector<int>& perm) {\n        int n = perm.size();\n        if (n < 8) return;\n        array<int, 4> cuts;\n        for (int t = 0; t < 4; ++t) {\n            int x;\n            do {\n                x = 1 + rng() % (n - 1);\n                bool ok = true;\n                for (int k = 0; k < t; ++k)\n                    if (cuts[k] == x) ok = false;\n                if (ok) break;\n            } while (true);\n            cuts[t] = x;\n        }\n        sort(cuts.begin(), cuts.end());\n        int a = cuts[0], b = cuts[1], c = cuts[2], d = cuts[3];\n        vector<int> newPerm;\n        newPerm.reserve(n);\n        newPerm.insert(newPerm.end(), perm.begin(), perm.begin() + a);\n        newPerm.insert(newPerm.end(), perm.begin() + c, perm.begin() + d);\n        newPerm.insert(newPerm.end(), perm.begin() + b, perm.begin() + c);\n        newPerm.insert(newPerm.end(), perm.begin() + a, perm.begin() + b);\n        newPerm.insert(newPerm.end(), perm.begin() + d, perm.end());\n        perm.swap(newPerm);\n    }\n\n    void pool_iterated_search(vector<Tour>& pool,\n                              vector<int>& bestPerm, long long& bestCost,\n                              vector<pair<long long, vector<int>>>& cand) {\n        if (pool.empty()) return;\n        double limit = TIME_LIMIT - FINAL_MARGIN - 0.02;\n        while (elapsed() < limit) {\n            int choices = max(1, min((int)pool.size(), 4));\n            int pick = rng() % choices;\n            vector<int> perm = pool[pick].perm;\n            long long cost = pool[pick].cost;\n            double_bridge(perm);\n            if ((rng() & 3) == 0) double_bridge(perm);\n            normalize_order(perm);\n            cost = tour_cost(perm);\n            double remain = limit - elapsed();\n            if (remain <= 0) break;\n            double twoB = min(remain * 0.45, 0.02);\n            double orB = min(remain * 0.35, 0.02);\n            double randB = min(remain * 0.25, 0.012);\n            improve_perm(perm, cost, twoB, orB, randB);\n            normalize_order(perm);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestPerm = perm;\n            }\n            cand.emplace_back(cost, perm);\n            pool.push_back({cost, perm});\n            sort(pool.begin(), pool.end(),\n                 [](const Tour& a, const Tour& b) { return a.cost < b.cost; });\n            if ((int)pool.size() > POOL_LIMIT) pool.pop_back();\n            if ((int)cand.size() > 40) break;\n        }\n    }\n\n    bool build_route_from_perm(const vector<int>& perm, string& route) const {\n        if (perm.empty() || perm[0] != 0) return false;\n        route.clear();\n        route.reserve(min(MOVE_LIMIT, totalNodes * 4));\n        int cur = perm[0];\n        for (int idx = 1; idx < (int)perm.size(); ++idx) {\n            if (!append_path(cur, perm[idx], route)) return false;\n            cur = perm[idx];\n        }\n        if (!append_path(cur, perm[0], route)) return false;\n        return (int)route.size() <= MOVE_LIMIT;\n    }\n\n    bool append_path(int from, int to, string& route) const {\n        if (from == to) return true;\n        int safety = totalNodes * 4 + 10;\n        int cur = from;\n        while (cur != to && safety-- > 0) {\n            int nxt = next_idx(cur, to);\n            if (nxt == cur) return false;\n            char mv = move_char(cur, nxt);\n            if (mv == '?') return false;\n            route.push_back(mv);\n            cur = nxt;\n            if ((int)route.size() > MOVE_LIMIT) return false;\n        }\n        return cur == to;\n    }\n\n    char move_char(int from, int to) const {\n        int r1 = node_r[from], c1 = node_c[from];\n        int r2 = node_r[to], c2 = node_c[to];\n        if (r2 == r1 - 1 && c2 == c1) return 'U';\n        if (r2 == r1 + 1 && c2 == c1) return 'D';\n        if (r2 == r1 && c2 == c1 - 1) return 'L';\n        if (r2 == r1 && c2 == c1 + 1) return 'R';\n        return '?';\n    }\n\n    int char_dir(char c) const {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        if (c == 'R') return 3;\n        return -1;\n    }\n\n    long double evaluate(const string& route) {\n        if (route.empty() || (int)route.size() > MOVE_LIMIT) return 1e100L;\n        for (auto& vec : visitTimes) vec.clear();\n        int pos = 0;\n        for (int t = 0; t < (int)route.size(); ++t) {\n            int dir = char_dir(route[t]);\n            if (dir == -1) return 1e100L;\n            int nxt = dirNeighbor[pos][dir];\n            if (nxt == -1) return 1e100L;\n            pos = nxt;\n            visitTimes[pos].push_back(t + 1);\n       }\n        if (pos != 0) return 1e100L;\n\n        long double total = 0.0L;\n        long double L = (long double)route.size();\n        for (int idx = 0; idx < totalNodes; ++idx) {\n            auto& times = visitTimes[idx];\n            if (times.empty()) return 1e100L;\n            size_t m = times.size();\n            for (size_t j = 0; j < m; ++j) {\n                long long cur = times[j];\n                long long nxt = (j + 1 < m) ? times[j + 1] : (long long)times[0] + (long long)L;\n                long long delta = nxt - cur;\n                total += (long double)d_flat[idx] *\n                         (long double)delta * (long double)(delta - 1) / 2.0L;\n            }\n        }\n        return total / L;\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point start;\n    Timer() : start(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n};\n\nstruct XorShift64 {\n    unsigned long long x;\n    explicit XorShift64(unsigned long long seed = 88172645463393265ull) : x(seed) {}\n    unsigned long long next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return int(next() % n); }\n    double nextDouble() { return (next() >> 11) * (1.0 / (1ull << 53)); }\n};\n\nconstexpr int CODE_POWER = 26 * 26 * 26 * 26;\nconstexpr int GREEDY_K = 6;\n\nint encodeWord(const string &w) {\n    int code = 0;\n    for (char c : w) code = code * 26 + (c - 'A');\n    return code;\n}\n\nint calcOverlap(const string &a, const string &b) {\n    for (int len = 4; len >= 0; --len) {\n        bool ok = true;\n        for (int k = 0; k < len; ++k) {\n            if (a[5 - len + k] != b[k]) { ok = false; break; }\n        }\n        if (ok) return len;\n    }\n    return 0;\n}\n\nint computeOrderCost(const vector<int>& order, const vector<vector<int>>& cost) {\n    if (order.empty()) return 0;\n    int total = 5;\n    for (int i = 0; i + 1 < (int)order.size(); ++i) total += cost[order[i]][order[i + 1]];\n    return total;\n}\n\nvector<int> greedyOrderFromStart(int start, bool randomized,\n                                 const vector<vector<int>>& cost,\n                                 const vector<int>& sumOut,\n                                 XorShift64& rng) {\n    int n = cost.size();\n    vector<int> order;\n    vector<char> used(n, 0);\n    order.reserve(n);\n    int cur = start;\n    used[cur] = 1;\n    order.push_back(cur);\n    for (int step = 1; step < n; ++step) {\n        array<int, GREEDY_K> candNode;\n        array<int, GREEDY_K> candCost;\n        candNode.fill(-1);\n        candCost.fill(INT_MAX / 4);\n        for (int nxt = 0; nxt < n; ++nxt) {\n            if (used[nxt]) continue;\n            int c = cost[cur][nxt];\n            for (int pos = 0; pos < GREEDY_K; ++pos) {\n                if (candNode[pos] == -1 ||\n                    c < candCost[pos] ||\n                    (c == candCost[pos] &&\n                     (sumOut[nxt] < sumOut[candNode[pos]] ||\n                      (sumOut[nxt] == sumOut[candNode[pos]] && nxt < candNode[pos])))) {\n                    for (int q = GREEDY_K - 1; q > pos; --q) {\n                        candNode[q] = candNode[q - 1];\n                        candCost[q] = candCost[q - 1];\n                    }\n                    candNode[pos] = nxt;\n                    candCost[pos] = c;\n                    break;\n                }\n            }\n        }\n        int candCnt = 0;\n        while (candCnt < GREEDY_K && candNode[candCnt] != -1) ++candCnt;\n        int pick = 0;\n        if (randomized && candCnt > 1) {\n            double r = rng.nextDouble();\n            if (candCnt >= 3) {\n                if (r < 0.6) pick = 0;\n                else if (r < 0.85) pick = 1;\n                else if (r < 0.95) pick = 2;\n                else pick = rng.nextInt(candCnt);\n            } else {\n                pick = (r < 0.8) ? 0 : 1;\n            }\n        }\n        int nextNode = candNode[pick];\n        if (nextNode == -1) {\n            for (int nxt = 0; nxt < n; ++nxt) if (!used[nxt]) { nextNode = nxt; break; }\n        }\n        used[nextNode] = 1;\n        order.push_back(nextNode);\n        cur = nextNode;\n    }\n    return order;\n}\n\nvector<int> cheapestInsertionOrder(bool deterministicStart,\n                                   bool randomized,\n                                   const vector<vector<int>>& cost,\n                                   const vector<int>& sumOut,\n                                   XorShift64& rng) {\n    int n = cost.size();\n    vector<int> order;\n    vector<char> used(n, 0);\n    int a = 0, b = 1;\n    if (deterministicStart) {\n        int best = INT_MAX;\n        for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) if (i != j) {\n            int c = cost[i][j];\n            if (c < best || (c == best && sumOut[i] + sumOut[j] < sumOut[a] + sumOut[b])) {\n                best = c;\n                a = i;\n                b = j;\n            }\n        }\n    } else {\n        a = rng.nextInt(n);\n        b = rng.nextInt(n - 1);\n        if (b >= a) ++b;\n    }\n    order.push_back(a);\n    order.push_back(b);\n    used[a] = used[b] = 1;\n    while ((int)order.size() < n) {\n        int bestNode = -1, bestPos = 0;\n        int bestDelta = INT_MAX / 4;\n        for (int node = 0; node < n; ++node) if (!used[node]) {\n            for (int pos = 0; pos <= (int)order.size(); ++pos) {\n                int prev = (pos == 0) ? -1 : order[pos - 1];\n                int next = (pos == (int)order.size()) ? -1 : order[pos];\n                int delta;\n                if (prev == -1 && next == -1) delta = 0;\n                else if (prev == -1) delta = cost[node][next];\n                else if (next == -1) delta = cost[prev][node];\n                else delta = cost[prev][node] + cost[node][next] - cost[prev][next];\n                bool take = false;\n                if (delta < bestDelta) take = true;\n                else if (delta == bestDelta) {\n                    if (randomized) take = rng.nextDouble() < 0.5;\n                    else if (bestNode == -1 || sumOut[node] < sumOut[bestNode] ||\n                             (sumOut[node] == sumOut[bestNode] && node < bestNode)) take = true;\n                }\n                if (take) {\n                    bestDelta = delta;\n                    bestNode = node;\n                    bestPos = pos;\n                }\n            }\n        }\n        if (bestNode == -1) {\n            for (int node = 0; node < n; ++node) if (!used[node]) { bestNode = node; bestPos = order.size(); break; }\n        }\n        order.insert(order.begin() + bestPos, bestNode);\n        used[bestNode] = 1;\n    }\n    return order;\n}\n\nint swapDelta(const vector<int>& order, int i, int j, const vector<vector<int>>& cost) {\n    if (i == j) return 0;\n    if (i > j) swap(i, j);\n    int n = order.size();\n    auto edge = [&](int u, int v)->int { return (u < 0 || v < 0) ? 0 : cost[u][v]; };\n    int a = order[i];\n    int b = order[j];\n    if (j == i + 1) {\n        int li = (i > 0) ? order[i - 1] : -1;\n        int rj = (j + 1 < n) ? order[j + 1] : -1;\n        int before = 0, after = 0;\n        if (li != -1) before += edge(li, a);\n        before += edge(a, b);\n        if (rj != -1) before += edge(b, rj);\n        if (li != -1) after += edge(li, b);\n        after += edge(b, a);\n        if (rj != -1) after += edge(a, rj);\n        return after - before;\n    } else {\n        int li = (i > 0) ? order[i - 1] : -1;\n        int ri = (i + 1 < n) ? order[i + 1] : -1;\n        int lj = (j > 0) ? order[j - 1] : -1;\n        int rj = (j + 1 < n) ? order[j + 1] : -1;\n        int before = 0, after = 0;\n        if (li != -1) before += edge(li, a);\n        if (ri != -1) before += edge(a, ri);\n        if (lj != -1) before += edge(lj, b);\n        if (rj != -1) before += edge(b, rj);\n        if (li != -1) after += edge(li, b);\n        if (ri != -1) after += edge(b, ri);\n        if (lj != -1) after += edge(lj, a);\n        if (rj != -1) after += edge(a, rj);\n        return after - before;\n    }\n}\n\nint segmentMoveDelta(const vector<int>& order, int L, int len, int insertPos, const vector<vector<int>>& cost) {\n    int n = order.size();\n    int R = L + len - 1;\n    if (insertPos >= L && insertPos <= R + 1) return 0;\n    auto edge = [&](int u, int v)->int { return (u < 0 || v < 0) ? 0 : cost[u][v]; };\n    int segFront = order[L];\n    int segBack = order[R];\n    int left = (L > 0) ? order[L - 1] : -1;\n    int right = (R + 1 < n) ? order[R + 1] : -1;\n    int delta = 0;\n    if (left != -1) delta -= edge(left, segFront);\n    if (right != -1) delta -= edge(segBack, right);\n    if (left != -1 && right != -1) delta += edge(left, right);\n    int reducedTarget;\n    if (insertPos <= L) reducedTarget = insertPos;\n    else if (insertPos > R + 1) reducedTarget = insertPos - len;\n    else return 0;\n    int newSize = n - len;\n    auto getValue = [&](int idx)->int {\n        if (idx < 0) return -1;\n        if (idx >= newSize) return -1;\n        if (idx < L) return order[idx];\n        return order[idx + len];\n    };\n    int before = getValue(reducedTarget - 1);\n    int after = getValue(reducedTarget);\n    if (before != -1) delta += edge(before, segFront);\n    if (after != -1) delta += edge(segBack, after);\n    if (before != -1 && after != -1) delta -= edge(before, after);\n    return delta;\n}\n\nvoid applySegmentMove(vector<int>& order, int L, int len, int insertPos) {\n    vector<int> segment(order.begin() + L, order.begin() + L + len);\n    order.erase(order.begin() + L, order.begin() + L + len);\n    int pos = insertPos;\n    if (pos > L) pos -= len;\n    pos = max(0, min(pos, (int)order.size()));\n    order.insert(order.begin() + pos, segment.begin(), segment.end());\n}\n\nint twoOptDelta(const vector<int>& order, int l, int r, const vector<vector<int>>& cost) {\n    if (l >= r) return 0;\n    int n = order.size();\n    auto edge = [&](int u, int v)->int { return (u < 0 || v < 0) ? 0 : cost[u][v]; };\n    int delta = 0;\n    int left = (l > 0) ? order[l - 1] : -1;\n    int right = (r + 1 < n) ? order[r + 1] : -1;\n    if (left != -1) delta += edge(left, order[r]) - edge(left, order[l]);\n    if (right != -1) delta += edge(order[l], right) - edge(order[r], right);\n    for (int i = l; i < r; ++i) {\n        int u = order[i];\n        int v = order[i + 1];\n        delta += edge(v, u) - edge(u, v);\n    }\n    return delta;\n}\n\nbool improveSwap(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                 Timer& timer, double deadline) {\n    int n = order.size();\n    int bestI = -1, bestJ = -1;\n    int bestDelta = 0;\n    for (int i = 0; i < n; ++i) {\n        if (timer.elapsed() >= deadline) break;\n        for (int j = i + 1; j < n; ++j) {\n            int delta = swapDelta(order, i, j, cost);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestI = i;\n                bestJ = j;\n            }\n        }\n    }\n    if (bestDelta < 0) {\n        swap(order[bestI], order[bestJ]);\n        costVal += bestDelta;\n        return true;\n    }\n    return false;\n}\n\nbool improveSegmentMoveLen(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                           int len, Timer& timer, double deadline) {\n    int n = order.size();\n    if (n <= len) return false;\n    int bestL = -1, bestPos = -1;\n    int bestDelta = 0;\n    for (int L = 0; L + len <= n; ++L) {\n        if (timer.elapsed() >= deadline) break;\n        for (int pos = 0; pos <= n; ++pos) {\n            if (pos >= L && pos <= L + len) continue;\n            int delta = segmentMoveDelta(order, L, len, pos, cost);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestL = L;\n                bestPos = pos;\n            }\n        }\n    }\n    if (bestDelta < 0) {\n        applySegmentMove(order, bestL, len, bestPos);\n        costVal += bestDelta;\n        return true;\n    }\n    return false;\n}\n\nbool improveTwoOpt(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                   Timer& timer, double deadline) {\n    int n = order.size();\n    for (int l = 0; l < n; ++l) {\n        if (timer.elapsed() >= deadline) break;\n        for (int r = l + 1; r < n; ++r) {\n            int delta = twoOptDelta(order, l, r, cost);\n            if (delta < 0) {\n                reverse(order.begin() + l, order.begin() + r + 1);\n                costVal += delta;\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nvoid deterministicLocalSearch(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                              Timer& timer, double deadline) {\n    while (timer.elapsed() < deadline) {\n        if (improveSwap(order, costVal, cost, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveSegmentMoveLen(order, costVal, cost, 1, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveSegmentMoveLen(order, costVal, cost, 2, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveSegmentMoveLen(order, costVal, cost, 3, timer, deadline)) continue;\n        if (timer.elapsed() >= deadline) break;\n        if (improveTwoOpt(order, costVal, cost, timer, deadline)) continue;\n        break;\n    }\n}\n\nvoid simulatedAnnealing(vector<int>& order, int &costVal, const vector<vector<int>>& cost,\n                        XorShift64& rng, Timer& timer, double deadline) {\n    double startTime = timer.elapsed();\n    double totalTime = deadline - startTime;\n    if (totalTime <= 1e-4) return;\n    vector<int> bestOrder = order;\n    int bestCost = costVal;\n    int n = order.size();\n    const double START_TEMP = 4.0;\n    const double END_TEMP = 0.1;\n    while (true) {\n        double now = timer.elapsed();\n        if (now >= deadline) break;\n        double progress = (now - startTime) / totalTime;\n        progress = min(max(progress, 0.0), 1.0);\n        double temp = START_TEMP + (END_TEMP - START_TEMP) * progress;\n        temp = max(temp, 1e-4);\n        int op = rng.nextInt(4);\n        if (op == 0) {\n            if (n <= 1) continue;\n            int i = rng.nextInt(n);\n            int j = rng.nextInt(n - 1);\n            if (j >= i) ++j;\n            int delta = swapDelta(order, i, j, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                swap(order[i], order[j]);\n                costVal += delta;\n                if (costVal < bestCost) { bestCost = costVal; bestOrder = order; }\n            }\n        } else if (op == 1) {\n            int len = (n >= 4 && rng.nextDouble() < 0.5) ? 2 : 1;\n            if (n <= len) continue;\n            int L = rng.nextInt(n - len + 1);\n            int pos = rng.nextInt(n + 1);\n            if (pos >= L && pos <= L + len) continue;\n            int delta = segmentMoveDelta(order, L, len, pos, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                applySegmentMove(order, L, len, pos);\n                costVal += delta;\n                if (costVal < bestCost) { bestCost = costVal; bestOrder = order; }\n            }\n        } else if (op == 2) {\n            if (n < 3) continue;\n            int l = rng.nextInt(n - 1);\n            int r = rng.nextInt(n - l - 1) + l + 1;\n            int delta = twoOptDelta(order, l, r, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                reverse(order.begin() + l, order.begin() + r + 1);\n                costVal += delta;\n                if (costVal < bestCost) { bestCost = costVal; bestOrder = order; }\n            }\n        } else {\n            if (n < 5) continue;\n            int len = 3;\n            int L = rng.nextInt(n - len + 1);\n            int pos = rng.nextInt(n + 1);\n            if (pos >= L && pos <= L + len) continue;\n            int delta = segmentMoveDelta(order, L, len, pos, cost);\n            if (delta <= 0 || rng.nextDouble() < exp(-delta / temp)) {\n                applySegmentMove(order, L, len, pos);\n                costVal += delta;\n                if (costVal < bestCost) { bestCost = costVal; bestOrder = order; }\n            }\n        }\n    }\n    if (bestCost < costVal) {\n        order = bestOrder;\n        costVal = bestCost;\n    }\n}\n\nbool applyDoubleBridge(vector<int>& order, XorShift64& rng) {\n    int n = order.size();\n    if (n < 8) return false;\n    for (int attempt = 0; attempt < 20; ++attempt) {\n        array<int,4> cuts;\n        for (int i = 0; i < 4; ++i) cuts[i] = rng.nextInt(n - 1) + 1;\n        sort(cuts.begin(), cuts.end());\n        bool ok = true;\n        for (int i = 1; i < 4; ++i) if (cuts[i] == cuts[i - 1]) { ok = false; break; }\n        if (!ok) continue;\n        if (cuts[0] == 0 || cuts[3] >= n) continue;\n        vector<int> newOrder;\n        newOrder.reserve(n);\n        newOrder.insert(newOrder.end(), order.begin(), order.begin() + cuts[0]);\n        newOrder.insert(newOrder.end(), order.begin() + cuts[2], order.begin() + cuts[3]);\n        newOrder.insert(newOrder.end(), order.begin() + cuts[1], order.begin() + cuts[2]);\n        newOrder.insert(newOrder.end(), order.begin() + cuts[0], order.begin() + cuts[1]);\n        newOrder.insert(newOrder.end(), order.begin() + cuts[3], order.end());\n        order.swap(newOrder);\n        return true;\n    }\n    return false;\n}\n\nbool randomSegmentMoveRaw(vector<int>& order, int len, XorShift64& rng) {\n    int n = order.size();\n    if (n <= len) {\n        len = max(1, n - 1);\n        if (len <= 0) return false;\n    }\n    int L = rng.nextInt(n - len + 1);\n    int pos = rng.nextInt(n + 1);\n    if (pos >= L && pos <= L + len) {\n        pos = (rng.nextDouble() < 0.5) ? 0 : n;\n        if (pos >= L && pos <= L + len) return false;\n    }\n    applySegmentMove(order, L, len, pos);\n    return true;\n}\n\nvoid randomPerturb(vector<int>& order, XorShift64& rng) {\n    int n = order.size();\n    if (n < 4) return;\n    bool dbApplied = false;\n    int ops = 6;\n    for (int k = 0; k < ops; ++k) {\n        double r = rng.nextDouble();\n        if (r < 0.35 && n >= 8) {\n            dbApplied |= applyDoubleBridge(order, rng);\n        } else {\n            int lenChoice = (rng.nextDouble() < 0.6) ? 1 : ((rng.nextDouble() < 0.5) ? 2 : 3);\n            randomSegmentMoveRaw(order, min(lenChoice, max(1, n - 1)), rng);\n        }\n    }\n    if (!dbApplied && n >= 8) applyDoubleBridge(order, rng);\n}\n\nstring buildLuckyString(const vector<int>& order,\n                        const vector<string>& words,\n                        const vector<vector<int>>& overlap) {\n    if (order.empty()) return \"\";\n    string result = words[order[0]];\n    for (int idx = 1; idx < (int)order.size(); ++idx) {\n        int u = order[idx - 1];\n        int v = order[idx];\n        int ov = overlap[u][v];\n        result.append(words[v].substr(ov));\n    }\n    return result;\n}\n\nvoid ensureCoverage(string &S, const vector<string>& words,\n                    const unordered_map<int,int>& codeToIdx) {\n    int M = words.size();\n    vector<char> seen(M, 0);\n    int covered = 0;\n    int windowLen = 0;\n    int code = 0;\n    for (char c : S) {\n        int val = c - 'A';\n        if (windowLen < 5) {\n            code = code * 26 + val;\n            ++windowLen;\n        } else {\n            code %= CODE_POWER;\n            code = code * 26 + val;\n        }\n        if (windowLen >= 5) {\n            auto it = codeToIdx.find(code);\n            if (it != codeToIdx.end() && !seen[it->second]) {\n                seen[it->second] = 1;\n                ++covered;\n                if (covered == M) return;\n            }\n        }\n    }\n    if (covered == M) return;\n    auto appendWord = [&](const string& w) {\n        int overlapLen = 0;\n        int limit = min(4, (int)S.size());\n        for (int len = limit; len >= 0; --len) {\n            bool ok = true;\n            for (int k = 0; k < len; ++k) {\n                if (S[S.size() - len + k] != w[k]) { ok = false; break; }\n            }\n            if (ok) { overlapLen = len; break; }\n        }\n        for (int k = overlapLen; k < 5; ++k) {\n            char c = w[k];\n            S.push_back(c);\n            int val = c - 'A';\n            if (windowLen < 5) {\n                code = code * 26 + val;\n                ++windowLen;\n            } else {\n                code %= CODE_POWER;\n                code = code * 26 + val;\n            }\n            if (windowLen >= 5) {\n                auto it = codeToIdx.find(code);\n                if (it != codeToIdx.end() && !seen[it->second]) {\n                    seen[it->second] = 1;\n                    ++covered;\n                }\n            }\n        }\n    };\n    for (int idx = 0; idx < M; ++idx) {\n        if (!seen[idx]) {\n            appendWord(words[idx]);\n            if (covered == M) break;\n        }\n    }\n}\n\nstruct TypingResult {\n    vector<int> path;\n    int cost;\n};\n\nTypingResult buildTypingPlan(const string& S, int si, int sj,\n                             const vector<vector<int>>& cellsByChar,\n                             const vector<int>& rowOfCell,\n                             const vector<int>& colOfCell) {\n    const int INF = 1e9;\n    if (S.empty()) return {{}, INF};\n    int L = S.size();\n    vector<vector<int>> dp(L);\n    vector<vector<int>> parent(L);\n    for (int pos = 0; pos < L; ++pos) {\n        int c = S[pos] - 'A';\n        const auto &cells = cellsByChar[c];\n        int m = cells.size();\n        dp[pos].assign(m, INF);\n        parent[pos].assign(m, -1);\n        if (pos == 0) {\n            for (int idx = 0; idx < m; ++idx) {\n                int cell = cells[idx];\n                dp[pos][idx] = abs(rowOfCell[cell] - si) + abs(colOfCell[cell] - sj) + 1;\n            }\n        } else {\n            int prevC = S[pos - 1] - 'A';\n            const auto &prevCells = cellsByChar[prevC];\n            for (int idx = 0; idx < m; ++idx) {\n                int cell = cells[idx];\n                int bestVal = INF;\n                int bestPrev = -1;\n                for (int p = 0; p < (int)prevCells.size(); ++p) {\n                    int prevCell = prevCells[p];\n                    int prevCost = dp[pos - 1][p];\n                    if (prevCost >= INF) continue;\n                    int dist = abs(rowOfCell[cell] - rowOfCell[prevCell]) +\n                               abs(colOfCell[cell] - colOfCell[prevCell]);\n                    int cand = prevCost + dist + 1;\n                    if (cand < bestVal) {\n                        bestVal = cand;\n                        bestPrev = p;\n                    }\n                }\n                dp[pos][idx] = bestVal;\n                parent[pos][idx] = bestPrev;\n            }\n        }\n    }\n    int lastPos = L - 1;\n    const auto &lastCells = cellsByChar[S[lastPos] - 'A'];\n    int bestIdx = -1;\n    int bestVal = INF;\n    for (int idx = 0; idx < (int)lastCells.size(); ++idx) {\n        if (dp[lastPos][idx] < bestVal) {\n            bestVal = dp[lastPos][idx];\n            bestIdx = idx;\n        }\n    }\n    if (bestIdx == -1) return {{}, INF};\n    vector<int> path(L);\n    int curIdx = bestIdx;\n    for (int pos = L - 1; pos >= 0; --pos) {\n        path[pos] = cellsByChar[S[pos] - 'A'][curIdx];\n        if (pos == 0) break;\n        curIdx = parent[pos][curIdx];\n        if (curIdx < 0) curIdx = 0;\n    }\n    return {path, bestVal};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TOTAL_LIMIT = 1.95;\n    const double RESERVED_TIME = 0.20;\n    double heurDeadline = min(1.70, TOTAL_LIMIT - RESERVED_TIME);\n\n    int N, M;\n    if (!(cin >> N >> M)) return 0;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> grid(N);\n    for (int i = 0; i < N; ++i) cin >> grid[i];\n    vector<string> words(M);\n    for (int i = 0; i < M; ++i) cin >> words[i];\n\n    vector<int> rowOfCell(N * N), colOfCell(N * N);\n    vector<vector<int>> cellsByChar(26);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int idx = i * N + j;\n            rowOfCell[idx] = i;\n            colOfCell[idx] = j;\n            cellsByChar[grid[i][j] - 'A'].push_back(idx);\n        }\n    }\n\n    unordered_map<int,int> codeToIdx;\n    codeToIdx.reserve(M * 2);\n    for (int i = 0; i < M; ++i) codeToIdx[encodeWord(words[i])] = i;\n\n    vector<vector<int>> overlap(M, vector<int>(M, 0));\n    vector<vector<int>> baseEdge(M, vector<int>(M, 5));\n    for (int i = 0; i < M; ++i) for (int j = 0; j < M; ++j) if (i != j) {\n        int ov = calcOverlap(words[i], words[j]);\n        overlap[i][j] = ov;\n        baseEdge[i][j] = 5 - ov;\n    }\n\n    vector<vector<int>> approxDist(26, vector<int>(26, INT_MAX));\n    for (int a = 0; a < 26; ++a) {\n        for (int b = 0; b < 26; ++b) {\n            int best = INT_MAX;\n            for (int cellA : cellsByChar[a]) {\n                for (int cellB : cellsByChar[b]) {\n                    int dist = abs(rowOfCell[cellA] - rowOfCell[cellB]) +\n                               abs(colOfCell[cellA] - colOfCell[cellB]) + 1;\n                    if (dist < best) best = dist;\n                }\n            }\n            approxDist[a][b] = best;\n        }\n    }\n\n    vector<vector<int>> approxEdge(M, vector<int>(M, 0));\n    double sumBase = 0.0, sumApprox = 0.0;\n    long long pairCnt = 0;\n    for (int u = 0; u < M; ++u) {\n        for (int v = 0; v < M; ++v) if (u != v) {\n            int ov = overlap[u][v];\n            if (ov >= 5) { approxEdge[u][v] = 0; }\n            else {\n                int prevChar = words[u].back() - 'A';\n                int first = words[v][ov] - 'A';\n                int cost = approxDist[prevChar][first];\n                for (int k = ov + 1; k < 5; ++k) {\n                    int a = words[v][k - 1] - 'A';\n                    int b = words[v][k] - 'A';\n                    cost += approxDist[a][b];\n                }\n                approxEdge[u][v] = cost;\n            }\n            sumBase += baseEdge[u][v];\n            sumApprox += approxEdge[u][v];\n            ++pairCnt;\n        }\n    }\n    double avgBase = sumBase / max(1ll, pairCnt);\n    double avgApprox = sumApprox / max(1ll, pairCnt);\n    double ratio = (avgApprox > 1e-9) ? avgBase / avgApprox : 0.2;\n    ratio = max(0.05, min(1.0, ratio * 1.1)); // slightly emphasise keyboard\n    vector<vector<int>> heurCost(M, vector<int>(M, 0));\n    for (int i = 0; i < M; ++i) {\n        for (int j = 0; j < M; ++j) if (i != j) {\n            double val = baseEdge[i][j] + ratio * approxEdge[i][j];\n            heurCost[i][j] = (int)llround(val * 100.0);\n        }\n    }\n\n    vector<int> sumOut(M, 0);\n    for (int i = 0; i < M; ++i) {\n        long long s = 0;\n        for (int j = 0; j < M; ++j) if (i != j) s += heurCost[i][j];\n        sumOut[i] = (int)s;\n    }\n\n    uint64_t seed = 1469598103934665603ull;\n    seed = seed * 1000003 + si * 911 + sj * 1013;\n    for (const auto &row : grid) for (char c : row) seed = seed * 1000003 + (unsigned char)c;\n    for (const auto &w : words) for (char c : w) seed = seed * 1000003 + (unsigned char)c;\n    XorShift64 rng(seed);\n\n    vector<uint64_t> randWord(M);\n    for (int i = 0; i < M; ++i) randWord[i] = rng.next();\n\n    auto computeHash = [&](const vector<int>& ord) -> uint64_t {\n        uint64_t h = 1469598103934665603ull;\n        for (int v : ord) {\n            h ^= randWord[v];\n            h *= 1099511628211ull;\n        }\n        return h;\n    };\n\n    struct EvalCandidate {\n        vector<int> order;\n        int heurCost;\n        uint64_t hash;\n    };\n    vector<EvalCandidate> evalCands;\n    unordered_set<uint64_t> evalHashes;\n    const int MAX_EVAL = 24;\n\n    auto addEvalCandidate = [&](const vector<int>& ord, int costVal) {\n        uint64_t h = computeHash(ord);\n        if (!evalHashes.insert(h).second) return;\n        evalCands.push_back({ord, costVal, h});\n        if ((int)evalCands.size() > MAX_EVAL) {\n            int worst = 0;\n            for (int i = 1; i < (int)evalCands.size(); ++i) {\n                if (evalCands[i].heurCost > evalCands[worst].heurCost) worst = i;\n            }\n            evalHashes.erase(evalCands[worst].hash);\n            evalCands.erase(evalCands.begin() + worst);\n        }\n    };\n\n    vector<vector<int>> candidateOrders;\n    vector<int> candidateCosts;\n    const int MAX_CAND = 12;\n    auto addCandidateOrder = [&](const vector<int>& ord, int costVal) {\n        if ((int)candidateOrders.size() < MAX_CAND) {\n            candidateOrders.push_back(ord);\n            candidateCosts.push_back(costVal);\n        } else {\n            int worstIdx = max_element(candidateCosts.begin(), candidateCosts.end()) - candidateCosts.begin();\n            if (costVal < candidateCosts[worstIdx]) {\n                candidateOrders[worstIdx] = ord;\n                candidateCosts[worstIdx] = costVal;\n            }\n        }\n    };\n\n    vector<int> bestOrder;\n    int bestCost = INT_MAX;\n\n    for (int start = 0; start < M; ++start) {\n        if (timer.elapsed() > heurDeadline && !candidateOrders.empty()) break;\n        auto ord = greedyOrderFromStart(start, false, heurCost, sumOut, rng);\n        int c = computeOrderCost(ord, heurCost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidateOrder(ord, c);\n    }\n\n    int randomGreedyRuns = 100;\n    for (int iter = 0; iter < randomGreedyRuns; ++iter) {\n        if (timer.elapsed() > heurDeadline) break;\n        int start = rng.nextInt(M);\n        auto ord = greedyOrderFromStart(start, true, heurCost, sumOut, rng);\n        int c = computeOrderCost(ord, heurCost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidateOrder(ord, c);\n    }\n\n    if (timer.elapsed() < heurDeadline) {\n        auto ord = cheapestInsertionOrder(true, false, heurCost, sumOut, rng);\n        int c = computeOrderCost(ord, heurCost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidateOrder(ord, c);\n    }\n\n    int insertionRuns = 12;\n    for (int iter = 0; iter < insertionRuns; ++iter) {\n        if (timer.elapsed() > heurDeadline) break;\n        auto ord = cheapestInsertionOrder(false, true, heurCost, sumOut, rng);\n        int c = computeOrderCost(ord, heurCost);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n        addCandidateOrder(ord, c);\n    }\n\n    if (bestOrder.empty()) {\n        bestOrder.resize(M);\n        iota(bestOrder.begin(), bestOrder.end(), 0);\n        bestCost = computeOrderCost(bestOrder, heurCost);\n        addCandidateOrder(bestOrder, bestCost);\n    }\n\n    vector<int> currentOrder = bestOrder;\n    int currentCost = bestCost;\n    deterministicLocalSearch(currentOrder, currentCost, heurCost, timer, heurDeadline);\n    addEvalCandidate(currentOrder, currentCost);\n    if (currentCost < bestCost) { bestCost = currentCost; bestOrder = currentOrder; }\n\n    vector<int> idx(candidateOrders.size());\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int a, int b) { return candidateCosts[a] < candidateCosts[b]; });\n\n    for (int id : idx) {\n        if (timer.elapsed() > heurDeadline) break;\n        vector<int> ord = candidateOrders[id];\n        int c = candidateCosts[id];\n        deterministicLocalSearch(ord, c, heurCost, timer, heurDeadline);\n        addEvalCandidate(ord, c);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n    }\n\n    if (timer.elapsed() < heurDeadline - 0.05) {\n        vector<int> ord = bestOrder;\n        int c = bestCost;\n        double saDeadline = heurDeadline - 0.03;\n        simulatedAnnealing(ord, c, heurCost, rng, timer, saDeadline);\n        deterministicLocalSearch(ord, c, heurCost, timer, heurDeadline);\n        addEvalCandidate(ord, c);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n    }\n\n    while (timer.elapsed() < heurDeadline - 0.05) {\n        vector<int> ord = bestOrder;\n        randomPerturb(ord, rng);\n        int c = computeOrderCost(ord, heurCost);\n        double localDeadline = min(heurDeadline, timer.elapsed() + 0.12);\n        deterministicLocalSearch(ord, c, heurCost, timer, localDeadline);\n        addEvalCandidate(ord, c);\n        if (c < bestCost) { bestCost = c; bestOrder = ord; }\n    }\n\n    addEvalCandidate(bestOrder, bestCost);\n    if (evalCands.empty()) addEvalCandidate(bestOrder, bestCost);\n\n    sort(evalCands.begin(), evalCands.end(),\n         [](const EvalCandidate& a, const EvalCandidate& b) { return a.heurCost < b.heurCost; });\n\n    vector<int> bestPath;\n    int bestTypingCost = INT_MAX;\n\n    for (const auto& cand : evalCands) {\n        string S = buildLuckyString(cand.order, words, overlap);\n        ensureCoverage(S, words, codeToIdx);\n        if ((int)S.size() > 5000) continue;\n        TypingResult res = buildTypingPlan(S, si, sj, cellsByChar, rowOfCell, colOfCell);\n        if (res.cost >= INT_MAX / 2) continue;\n        if (res.cost < bestTypingCost) {\n            bestTypingCost = res.cost;\n            bestPath = move(res.path);\n        }\n    }\n\n    if (bestPath.empty()) {\n        string S = buildLuckyString(bestOrder, words, overlap);\n        ensureCoverage(S, words, codeToIdx);\n        if ((int)S.size() > 5000) S.resize(5000);\n        TypingResult res = buildTypingPlan(S, si, sj, cellsByChar, rowOfCell, colOfCell);\n        bestPath = move(res.path);\n    }\n\n    for (int cell : bestPath) {\n        cout << rowOfCell[cell] << ' ' << colOfCell[cell] << '\\n';\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAX_N = 20;\nconstexpr int MAX_CELLS = MAX_N * MAX_N;\nconstexpr double LOG_SEARCH_LIMIT = 13.0;\nconstexpr long long SEARCH_NODE_LIMIT = 1'000'000;\nconstexpr long long SEARCH_SOLUTION_LIMIT = 120'000;\nconstexpr int INF_DIST = 1e9;\n\nstruct Candidate {\n    vector<int> cells;\n    bitset<MAX_CELLS> mask;\n};\n\nstruct FieldState {\n    vector<Candidate> candidates;\n    vector<char> alive;\n    int rem = 0;\n    vector<int> cellCoverCount;\n    vector<unsigned char> possibleFlag;\n    vector<unsigned char> guaranteedFlag;\n    bool fixed = false;\n    int fixedCandidate = -1;\n    vector<vector<int>> cellToCand;\n};\n\nint N, M;\ndouble eps;\nint nCells;\nvector<FieldState> fields;\nvector<int> assigned_total;\nvector<int> observed;\nvector<char> drilled;\nvector<int> observed_cells;\nvector<int> possible_sum;\nvector<int> guaranteed_sum;\nvector<int> cellStatus;\nvector<char> zeroProcessed;\nvector<int> zero_queue;\nvector<double> cellProb;\nvector<int> distObserved;\nbool dist_dirty = true;\n\nbool contradiction = false;\nmt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\ninline int cell_id(int i, int j) { return i * N + j; }\n\ninline bool set_status(int idx, int val) {\n    if (cellStatus[idx] == val) return false;\n    cellStatus[idx] = val;\n    if (val == 0) zero_queue.push_back(idx);\n    return true;\n}\n\nvoid recompute_distances() {\n    distObserved.assign(nCells, INF_DIST);\n    queue<int> q;\n    for (int idx = 0; idx < nCells; ++idx) if (drilled[idx]) {\n        distObserved[idx] = 0;\n        q.push(idx);\n    }\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    while (!q.empty()) {\n        int cur = q.front(); q.pop();\n        int ci = cur / N;\n        int cj = cur % N;\n        for (int dir = 0; dir < 4; ++dir) {\n            int ni = ci + di[dir];\n            int nj = cj + dj[dir];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n            int nxt = cell_id(ni, nj);\n            if (distObserved[nxt] > distObserved[cur] + 1) {\n                distObserved[nxt] = distObserved[cur] + 1;\n                q.push(nxt);\n            }\n        }\n    }\n    dist_dirty = false;\n}\ninline int get_dist(int idx) {\n    if (dist_dirty) recompute_distances();\n    return distObserved[idx];\n}\n\nbool update_trivial_positions();\nbool process_zero_queue();\nbool apply_propagation();\nvoid fix_field(int k);\nvoid eliminate_candidate(int k, int t);\n\nstruct AttemptResult { bool progress = false, needPropagation = false; };\nAttemptResult attempt_search();\nAttemptResult enumerate_component(const vector<int>& compFields, const vector<int>& compObs);\n\nvoid recompute_field_flags(int k) {\n    FieldState &F = fields[k];\n    if (F.fixed) return;\n    for (int idx = 0; idx < nCells; ++idx) {\n        unsigned char newPossible = (F.cellCoverCount[idx] > 0) ? 1 : 0;\n        unsigned char newGuaranteed = (F.rem > 0 && F.cellCoverCount[idx] == F.rem) ? 1 : 0;\n        if (newPossible != F.possibleFlag[idx]) {\n            possible_sum[idx] += int(newPossible) - int(F.possibleFlag[idx]);\n            F.possibleFlag[idx] = newPossible;\n        }\n        if (newGuaranteed != F.guaranteedFlag[idx]) {\n            guaranteed_sum[idx] += int(newGuaranteed) - int(F.guaranteedFlag[idx]);\n            F.guaranteedFlag[idx] = newGuaranteed;\n        }\n    }\n}\n\nvoid fix_field(int k) {\n    FieldState &F = fields[k];\n    if (F.fixed) return;\n    int t = -1;\n    for (int i = 0; i < (int)F.candidates.size(); ++i) if (F.alive[i]) { t = i; break; }\n    if (t == -1) { contradiction = true; return; }\n    F.fixed = true;\n    F.fixedCandidate = t;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (F.possibleFlag[idx]) { possible_sum[idx] -= 1; F.possibleFlag[idx] = 0; }\n        if (F.guaranteedFlag[idx]) { guaranteed_sum[idx] -= 1; F.guaranteedFlag[idx] = 0; }\n    }\n    F.alive.assign(F.candidates.size(), 0);\n    F.alive[t] = 1;\n    F.rem = 0;\n    for (int idx : F.candidates[t].cells) {\n        assigned_total[idx]++;\n        set_status(idx, 1);\n    }\n}\n\nvoid eliminate_candidate(int k, int t) {\n    FieldState &F = fields[k];\n    if (F.fixed || !F.alive[t]) return;\n    F.alive[t] = false;\n    F.rem--;\n    for (int idx : F.candidates[t].cells) F.cellCoverCount[idx]--;\n    recompute_field_flags(k);\n    if (F.rem < 0) contradiction = true;\n    else if (F.rem == 0) contradiction = true;\n    else if (F.rem == 1) fix_field(k);\n}\n\nbool check_candidate(int k, int t) {\n    FieldState &F = fields[k];\n    const Candidate &cand = F.candidates[t];\n    for (int idx : observed_cells) {\n        if (!F.possibleFlag[idx]) continue;\n        int cover = cand.mask.test(idx) ? 1 : 0;\n        int need = observed[idx] - (assigned_total[idx] + cover);\n        int min_other = guaranteed_sum[idx];\n        int max_other = possible_sum[idx];\n        if (F.guaranteedFlag[idx]) min_other -= 1;\n        if (F.possibleFlag[idx]) max_other -= 1;\n        if (need < min_other || need > max_other) return false;\n    }\n    return true;\n}\n\nbool validate_bounds() {\n    for (int idx : observed_cells) {\n        int min_total = assigned_total[idx] + guaranteed_sum[idx];\n        int max_total = assigned_total[idx] + possible_sum[idx];\n        if (observed[idx] < min_total || observed[idx] > max_total) return false;\n    }\n    return true;\n}\n\nbool run_propagation() {\n    bool changed = true;\n    while (!contradiction && changed) {\n        changed = false;\n        for (int k = 0; k < M; ++k) {\n            FieldState &F = fields[k];\n            if (F.fixed) continue;\n            for (int t = 0; t < (int)F.candidates.size(); ++t) {\n                if (!F.alive[t]) continue;\n                if (!check_candidate(k, t)) {\n                    eliminate_candidate(k, t);\n                    changed = true;\n                    if (contradiction) return false;\n                }\n            }\n        }\n        if (!validate_bounds()) return false;\n    }\n    return true;\n}\n\nbool update_trivial_positions() {\n    bool changed = false;\n    for (int idx = 0; idx < nCells; ++idx) {\n        int oldStatus = cellStatus[idx];\n        int newStatus = oldStatus;\n        if (drilled[idx] && observed[idx] >= 0) newStatus = (observed[idx] > 0) ? 1 : 0;\n        else {\n            if (assigned_total[idx] > 0 || guaranteed_sum[idx] > 0) newStatus = 1;\n            else if (possible_sum[idx] == 0) newStatus = 0;\n        }\n        if (newStatus != oldStatus) {\n            cellStatus[idx] = newStatus;\n            changed = true;\n            if (newStatus == 0) zero_queue.push_back(idx);\n        }\n    }\n    return changed;\n}\n\nbool process_zero_queue() {\n    bool changed = false;\n    while (!zero_queue.empty()) {\n        int idx = zero_queue.back();\n        zero_queue.pop_back();\n        if (cellStatus[idx] != 0 || zeroProcessed[idx]) continue;\n        zeroProcessed[idx] = 1;\n        for (int k = 0; k < M; ++k) {\n            FieldState &F = fields[k];\n            if (F.fixed) continue;\n            for (int t : F.cellToCand[idx]) {\n                if (!F.alive[t]) continue;\n                eliminate_candidate(k, t);\n                changed = true;\n                if (contradiction) return true;\n            }\n        }\n    }\n    return changed;\n}\n\nbool apply_propagation() {\n    while (true) {\n        if (!run_propagation()) return false;\n        bool statusChanged = update_trivial_positions();\n        bool zeroEffect = process_zero_queue();\n        if (contradiction) return false;\n        if (!statusChanged && !zeroEffect) break;\n    }\n    return true;\n}\n\nint drill_cell(int idx) {\n    if (drilled[idx]) return observed[idx];\n    int i = idx / N, j = idx % N;\n    cout << \"q 1 \" << i << ' ' << j << '\\n' << flush;\n    int val;\n    if (!(cin >> val)) exit(0);\n    drilled[idx] = 1;\n    observed[idx] = val;\n    dist_dirty = true;\n    set_status(idx, (val > 0) ? 1 : 0);\n    observed_cells.push_back(idx);\n    return val;\n}\n\nbool all_cells_determined() {\n    for (int idx = 0; idx < nCells; ++idx) if (cellStatus[idx] == -1) return false;\n    return true;\n}\n\nint select_any_undetermined_cell() {\n    for (int idx = 0; idx < nCells; ++idx) if (cellStatus[idx] == -1) return idx;\n    return -1;\n}\n\nvoid fill_heuristic_probabilities() {\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (cellStatus[idx] == 1) { cellProb[idx] = 1.0; continue; }\n        if (cellStatus[idx] == 0) { cellProb[idx] = 0.0; continue; }\n        if (cellProb[idx] >= -0.5) continue;\n        if (assigned_total[idx] > 0) { cellProb[idx] = 1.0; continue; }\n        double logZero = 0.0;\n        bool touched = false;\n        for (int k = 0; k < M; ++k) {\n            FieldState &F = fields[k];\n            if (F.fixed || F.rem <= 0) continue;\n            int cnt = F.cellCoverCount[idx];\n            if (cnt == 0) continue;\n            touched = true;\n            double freq = double(cnt) / double(F.rem);\n            freq = min(1.0, max(0.0, freq));\n            double complement = max(1.0 - freq, 1e-12);\n            logZero += log(complement);\n        }\n        if (!touched) cellProb[idx] = 0.0;\n        else {\n            double zeroProb = exp(logZero);\n            zeroProb = min(1.0, max(0.0, zeroProb));\n            cellProb[idx] = 1.0 - zeroProb;\n        }\n    }\n}\n\nint select_next_cell() {\n    fill_heuristic_probabilities();\n\n    double bestProbScore = -1.0;\n    int bestProbIdx = -1;\n    int bestProbDist = INF_DIST;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (drilled[idx] || cellStatus[idx] != -1) continue;\n        double p = cellProb[idx];\n        if (p < -0.5) continue;\n        double score = min(p, 1.0 - p);\n        int dist = get_dist(idx);\n        if (score > bestProbScore + 1e-9 ||\n           (abs(score - bestProbScore) <= 1e-9 && dist < bestProbDist)) {\n            bestProbScore = score;\n            bestProbIdx = idx;\n            bestProbDist = dist;\n        }\n    }\n    if (bestProbIdx != -1 && bestProbScore > 1e-3) return bestProbIdx;\n\n    long long bestScore = -1;\n    int bestIdx = -1;\n    int bestDist = INF_DIST;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (drilled[idx] || cellStatus[idx] != -1) continue;\n        long long score = 0;\n        for (int k = 0; k < M; ++k) {\n            FieldState &F = fields[k];\n            if (F.fixed || F.rem <= 1) continue;\n            int cnt = F.cellCoverCount[idx];\n            if (cnt == 0 || cnt == F.rem) continue;\n            score += min(cnt, F.rem - cnt);\n        }\n        int dist = get_dist(idx);\n        if (score > bestScore ||\n           (score == bestScore && dist < bestDist) ||\n           (score == bestScore && dist == bestDist && (rng() & 1))) {\n            bestScore = score;\n            bestIdx = idx;\n            bestDist = dist;\n        }\n    }\n    if (bestIdx != -1 && bestScore > 0) return bestIdx;\n\n    long long fallbackScore = -1;\n    int fallbackIdx = -1;\n    int fallbackDist = INF_DIST;\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (drilled[idx] || cellStatus[idx] != -1) continue;\n        long long s = possible_sum[idx] - guaranteed_sum[idx];\n        if (s < 0) s = 0;\n        int dist = get_dist(idx);\n        if (s > fallbackScore ||\n           (s == fallbackScore && dist < fallbackDist)) {\n            fallbackScore = s;\n            fallbackIdx = idx;\n            fallbackDist = dist;\n        }\n    }\n    return fallbackIdx;\n}\n\nAttemptResult attempt_search() {\n    AttemptResult total;\n    fill(cellProb.begin(), cellProb.end(), -1.0);\n    if (contradiction || observed_cells.empty()) return total;\n\n    vector<char> active(M, 0);\n    bool anyActive = false;\n    for (int k = 0; k < M; ++k) if (!fields[k].fixed && fields[k].rem > 0) { active[k] = 1; anyActive = true; }\n    if (!anyActive) return total;\n\n    vector<uint32_t> adjMask(M, 0);\n    vector<int> fieldList;\n    fieldList.reserve(M);\n    for (int idx = 0; idx < nCells; ++idx) {\n        fieldList.clear();\n        for (int k = 0; k < M; ++k) {\n            if (!active[k]) continue;\n            if (fields[k].possibleFlag[idx]) fieldList.push_back(k);\n        }\n        for (int a = 0; a < (int)fieldList.size(); ++a) {\n            for (int b = a + 1; b < (int)fieldList.size(); ++b) {\n                int u = fieldList[a], v = fieldList[b];\n                adjMask[u] |= (1u << v);\n                adjMask[v] |= (1u << u);\n            }\n        }\n    }\n\n    vector<char> visited(M, 0);\n    bool anyEnum = false;\n    for (int start = 0; start < M; ++start) {\n        if (!active[start] || visited[start]) continue;\n        vector<int> comp;\n        queue<int> q;\n        q.push(start);\n        visited[start] = 1;\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            comp.push_back(u);\n            uint32_t mask = adjMask[u];\n            for (int v = 0; v < M; ++v) {\n                if (!active[v] || visited[v]) continue;\n                if (mask >> v & 1u) {\n                    visited[v] = 1;\n                    q.push(v);\n                }\n            }\n        }\n        vector<int> compObs;\n        compObs.reserve(observed_cells.size());\n        for (int idx : observed_cells) {\n            for (int fk : comp) if (fields[fk].possibleFlag[idx]) { compObs.push_back(idx); break; }\n        }\n        if (compObs.empty()) continue;\n        double logSum = 0.0;\n        for (int fk : comp) logSum += log((double)fields[fk].rem);\n        if (logSum > LOG_SEARCH_LIMIT) continue;\n        sort(compObs.begin(), compObs.end());\n        compObs.erase(unique(compObs.begin(), compObs.end()), compObs.end());\n\n        AttemptResult r = enumerate_component(comp, compObs);\n        anyEnum = true;\n        total.progress |= r.progress;\n        total.needPropagation |= r.needPropagation;\n        if (contradiction) return total;\n        if (total.needPropagation) return total;\n    }\n    if (!anyEnum) fill_heuristic_probabilities();\n    return total;\n}\n\nAttemptResult enumerate_component(const vector<int>& compFields, const vector<int>& compObs) {\n    AttemptResult result;\n    if (compObs.empty()) return result;\n    int K = compFields.size();\n    vector<int> order = compFields;\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        return fields[a].rem < fields[b].rem;\n    });\n    int obsCount = compObs.size();\n    vector<int> obsIndex(nCells, -1);\n    for (int i = 0; i < obsCount; ++i) obsIndex[compObs[i]] = i;\n    vector<int> residual(obsCount);\n    for (int i = 0; i < obsCount; ++i) {\n        residual[i] = observed[compObs[i]] - assigned_total[compObs[i]];\n        if (residual[i] < 0) { contradiction = true; return result; }\n    }\n    vector<vector<int>> suffixPossible(K + 1, vector<int>(obsCount, 0));\n    for (int pos = K - 1; pos >= 0; --pos) {\n        suffixPossible[pos] = suffixPossible[pos + 1];\n        FieldState &F = fields[order[pos]];\n        for (int i = 0; i < obsCount; ++i) if (F.possibleFlag[compObs[i]]) suffixPossible[pos][i]++;\n    }\n    for (int i = 0; i < obsCount; ++i) if (residual[i] > suffixPossible[0][i]) { contradiction = true; return result; }\n\n    vector<vector<int>> candList(K);\n    vector<vector<vector<int>>> candObs(K);\n    for (int pos = 0; pos < K; ++pos) {\n        FieldState &F = fields[order[pos]];\n        for (int t = 0; t < (int)F.candidates.size(); ++t) if (F.alive[t]) {\n            candList[pos].push_back(t);\n            vector<int> obsVec;\n            for (int cell : F.candidates[t].cells) {\n                int map = obsIndex[cell];\n                if (map != -1) obsVec.push_back(map);\n            }\n            candObs[pos].push_back(move(obsVec));\n        }\n        if (candList[pos].empty()) { contradiction = true; return result; }\n    }\n\n    vector<int> touchedCells;\n    vector<char> touched(nCells, 0);\n    for (int fk : order) {\n        FieldState &F = fields[fk];\n        for (int idx = 0; idx < nCells; ++idx) {\n            if (F.possibleFlag[idx] && !touched[idx]) {\n                touched[idx] = 1;\n                touchedCells.push_back(idx);\n            }\n        }\n    }\n\n    vector<int> enumPossible(nCells, 0);\n    for (int fk : order) {\n        FieldState &F = fields[fk];\n        for (int idx : touchedCells) if (F.possibleFlag[idx]) enumPossible[idx]++;\n    }\n\n    vector<vector<char>> used(K);\n    for (int pos = 0; pos < K; ++pos) used[pos].assign(candList[pos].size(), 0);\n    vector<uint16_t> curTotal(nCells);\n    for (int idx = 0; idx < nCells; ++idx) curTotal[idx] = assigned_total[idx];\n    vector<char> alwaysPos(nCells, 0), everPos(nCells, 0);\n    vector<int> positiveCount(nCells, 0);\n    for (int idx : touchedCells) {\n        alwaysPos[idx] = 1;\n        everPos[idx] = 0;\n        positiveCount[idx] = 0;\n    }\n\n    vector<int> chosenLocal(K, -1);\n    long long nodeCount = 0, solutionCount = 0;\n    bool aborted = false;\n\n    auto dfs = [&](auto&& self, int pos) -> void {\n        if (aborted) return;\n        if (++nodeCount > SEARCH_NODE_LIMIT) { aborted = true; return; }\n        for (int i = 0; i < obsCount; ++i) if (residual[i] > suffixPossible[pos][i]) return;\n        if (pos == K) {\n            for (int i = 0; i < obsCount; ++i) if (residual[i] != 0) return;\n            solutionCount++;\n            if (solutionCount > SEARCH_SOLUTION_LIMIT) { aborted = true; return; }\n            for (int idx : touchedCells) {\n                bool positive = curTotal[idx] > 0;\n                if (!positive) alwaysPos[idx] = 0;\n                else {\n                    everPos[idx] = 1;\n                    positiveCount[idx]++;\n                }\n            }\n            for (int p = 0; p < K; ++p) {\n                int loc = chosenLocal[p];\n                if (loc >= 0) used[p][loc] = 1;\n            }\n            return;\n        }\n        FieldState &F = fields[order[pos]];\n        auto &candIdxs = candList[pos];\n        auto &candObsList = candObs[pos];\n        for (int ci = 0; ci < (int)candIdxs.size(); ++ci) {\n            auto &obsVec = candObsList[ci];\n            bool ok = true;\n            for (int obsId : obsVec) if (residual[obsId] == 0) { ok = false; break; }\n            if (!ok) continue;\n            for (int obsId : obsVec) residual[obsId]--;\n            for (int cell : fields[order[pos]].candidates[candIdxs[ci]].cells) curTotal[cell]++;\n            chosenLocal[pos] = ci;\n            self(self, pos + 1);\n            chosenLocal[pos] = -1;\n            for (int cell : fields[order[pos]].candidates[candIdxs[ci]].cells) curTotal[cell]--;\n            for (int obsId : obsVec) residual[obsId]++;\n            if (aborted) return;\n        }\n    };\n\n    dfs(dfs, 0);\n    if (aborted) return result;\n    if (solutionCount == 0) { contradiction = true; return result; }\n\n    for (int idx : touchedCells) {\n        if (enumPossible[idx] > 0) cellProb[idx] = (double)positiveCount[idx] / solutionCount;\n    }\n\n    bool statusChange = false;\n    for (int idx : touchedCells) {\n        if (enumPossible[idx] == 0) continue;\n        if (alwaysPos[idx]) {\n            if (set_status(idx, 1)) statusChange = true;\n        } else if (!everPos[idx] && enumPossible[idx] == possible_sum[idx]) {\n            if (set_status(idx, 0)) statusChange = true;\n        }\n    }\n\n    bool fieldsChanged = false;\n    for (int pos = 0; pos < K; ++pos) {\n        int fk = order[pos];\n        for (int ci = 0; ci < (int)candList[pos].size(); ++ci) {\n            if (!used[pos][ci]) {\n                int candIdx = candList[pos][ci];\n                if (fields[fk].alive[candIdx]) {\n                    eliminate_candidate(fk, candIdx);\n                    fieldsChanged = true;\n                    if (contradiction) return result;\n                }\n            }\n        }\n    }\n\n    result.progress = statusChange || fieldsChanged;\n    result.needPropagation = result.progress;\n    return result;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> M >> eps)) return 0;\n    nCells = N * N;\n    fields.resize(M);\n    assigned_total.assign(nCells, 0);\n    observed.assign(nCells, -1);\n    drilled.assign(nCells, 0);\n    possible_sum.assign(nCells, 0);\n    guaranteed_sum.assign(nCells, 0);\n    cellStatus.assign(nCells, -1);\n    zeroProcessed.assign(nCells, 0);\n    cellProb.assign(nCells, -1.0);\n    distObserved.assign(nCells, INF_DIST);\n    observed_cells.reserve(nCells);\n\n    for (int k = 0; k < M; ++k) {\n        int d;\n        cin >> d;\n        vector<pair<int,int>> shape(d);\n        int max_i = 0, max_j = 0;\n        for (int t = 0; t < d; ++t) {\n            int a, b;\n            cin >> a >> b;\n            shape[t] = {a, b};\n            max_i = max(max_i, a);\n            max_j = max(max_j, b);\n        }\n        FieldState &F = fields[k];\n        for (int di = 0; di + max_i < N; ++di) {\n            for (int dj = 0; dj + max_j < N; ++dj) {\n                Candidate cand;\n                cand.cells.reserve(d);\n                cand.mask.reset();\n                bool ok = true;\n                for (auto [a,b] : shape) {\n                    int ii = di + a;\n                    int jj = dj + b;\n                    if (ii < 0 || ii >= N || jj < 0 || jj >= N) { ok = false; break; }\n                    int idx = cell_id(ii, jj);\n                    cand.cells.push_back(idx);\n                    cand.mask.set(idx);\n                }\n                if (ok) F.candidates.push_back(move(cand));\n            }\n        }\n        F.rem = (int)F.candidates.size();\n        if (F.rem == 0) contradiction = true;\n        F.alive.assign(F.rem, 1);\n        F.cellCoverCount.assign(nCells, 0);\n        for (int t = 0; t < F.rem; ++t)\n            for (int idx : F.candidates[t].cells)\n                F.cellCoverCount[idx]++;\n        F.cellToCand.assign(nCells, {});\n        for (int t = 0; t < F.rem; ++t)\n            for (int idx : F.candidates[t].cells)\n                F.cellToCand[idx].push_back(t);\n        F.possibleFlag.assign(nCells, 0);\n        F.guaranteedFlag.assign(nCells, 0);\n        for (int idx = 0; idx < nCells; ++idx) {\n            if (F.cellCoverCount[idx] > 0) { F.possibleFlag[idx] = 1; possible_sum[idx] += 1; }\n            if (F.rem > 0 && F.cellCoverCount[idx] == F.rem) { F.guaranteedFlag[idx] = 1; guaranteed_sum[idx] += 1; }\n        }\n    }\n\n    for (int k = 0; k < M; ++k)\n        if (!fields[k].fixed && fields[k].rem == 1)\n            fix_field(k);\n\n    update_trivial_positions();\n    process_zero_queue();\n\n    while (!contradiction && !all_cells_determined()) {\n        AttemptResult sr = attempt_search();\n        if (contradiction) break;\n        if (sr.needPropagation) {\n            if (!apply_propagation()) break;\n            continue;\n        }\n        if (sr.progress) continue;\n        int next = select_next_cell();\n        if (next == -1) next = select_any_undetermined_cell();\n        if (next == -1) break;\n        drill_cell(next);\n        if (!apply_propagation()) break;\n    }\n\n    if (contradiction || !all_cells_determined()) {\n        for (int idx = 0; idx < nCells; ++idx)\n            if (!drilled[idx]) drill_cell(idx);\n        apply_propagation();\n    }\n\n    for (int idx = 0; idx < nCells; ++idx) {\n        if (cellStatus[idx] == -1) {\n            if (observed[idx] >= 0) set_status(idx, (observed[idx] > 0) ? 1 : 0);\n            else if (assigned_total[idx] > 0 || guaranteed_sum[idx] > 0) set_status(idx, 1);\n            else set_status(idx, 0);\n        }\n    }\n\n    vector<pair<int,int>> answer;\n    for (int idx = 0; idx < nCells; ++idx)\n        if (cellStatus[idx] == 1)\n            answer.emplace_back(idx / N, idx % N);\n\n    cout << \"a \" << answer.size();\n    for (auto [i,j] : answer) cout << ' ' << i << ' ' << j;\n    cout << '\\n' << flush;\n\n    int verdict;\n    if (!(cin >> verdict)) return 0;\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RectInfo {\n    int i0 = 0, j0 = 0, i1 = 1, j1 = 1;\n};\n\nstruct TreeNode {\n    int left = -1;\n    int right = -1;\n    int leaf = -1;\n    bool isLeaf = false;\n    bool splitHorizontal = false;\n};\n\nint W, D, N;\nlong long TOT;\n\nvector<vector<int>> demands;\nvector<long long> baseArea;\nvector<int> orderIdx;\n\nvector<TreeNode> nodes;\nint rootNode = -1;\n\nvector<RectInfo> currentRects;\nvector<long long> leafActualArea;\nvector<long double> subtreeWeight;\n\nvector<long long> compute_base_area() {\n    const long long baseMin = 1;\n    vector<long long> area(N, baseMin);\n    vector<vector<int>> stats(N, vector<int>(D));\n    for (int d = 0; d < D; ++d)\n        for (int k = 0; k < N; ++k)\n            stats[k][d] = demands[d][N - 1 - k];\n    for (int k = 0; k < N; ++k) sort(stats[k].begin(), stats[k].end());\n\n    struct NodeWF { int benefit; long long len; int idx; };\n    struct CmpWF {\n        bool operator()(const NodeWF& a, const NodeWF& b) const {\n            if (a.benefit != b.benefit) return a.benefit < b.benefit;\n            if (a.len != b.len) return a.len < b.len;\n            return a.idx > b.idx;\n        }\n    };\n    vector<int> ptr(N, 0);\n    priority_queue<NodeWF, vector<NodeWF>, CmpWF> pq;\n    auto push = [&](int j) {\n        while (ptr[j] < D && (long long)stats[j][ptr[j]] <= area[j]) ptr[j]++;\n        if (ptr[j] >= D) return;\n        long long len = (long long)stats[j][ptr[j]] - area[j];\n        if (len <= 0) return;\n        int benefit = D - ptr[j];\n        if (benefit <= 0) return;\n        pq.push(NodeWF{benefit, len, j});\n    };\n    for (int j = 0; j < N; ++j) push(j);\n\n    long long used = baseMin * N;\n    long long remaining = TOT - used;\n    while (remaining > 0 && !pq.empty()) {\n        NodeWF cur = pq.top(); pq.pop();\n        long long take = min(cur.len, remaining);\n        area[cur.idx] += take;\n        remaining -= take;\n        cur.len -= take;\n        if (cur.len > 0) pq.push(cur);\n        else push(cur.idx);\n    }\n    long long sum = accumulate(area.begin(), area.end(), 0LL);\n    if (sum < TOT) {\n        long long leftover = TOT - sum;\n        long long addEach = leftover / N;\n        if (addEach > 0) {\n            for (int i = 0; i < N; ++i) area[i] += addEach;\n            leftover -= addEach * N;\n        }\n        for (int i = 0; i < N && leftover > 0; ++i) {\n            area[i] += 1;\n            leftover -= 1;\n        }\n    }\n    return area;\n}\n\nint build_tree(const vector<int>& ids, int x0, int y0, int x1, int y1) {\n    int nodeId = (int)nodes.size();\n    nodes.push_back(TreeNode());\n    TreeNode &node = nodes.back();\n    if ((int)ids.size() == 1) {\n        node.isLeaf = true;\n        node.leaf = ids[0];\n        return nodeId;\n    }\n    int h = x1 - x0;\n    int w = y1 - y0;\n\n    vector<long long> prefix(ids.size() + 1, 0);\n    for (int i = 0; i < (int)ids.size(); ++i)\n        prefix[i + 1] = prefix[i] + baseArea[ids[i]];\n    long long total = prefix.back();\n    int bestMid = 1;\n    long long bestDiff = (1LL << 62);\n    for (int mid = 1; mid < (int)ids.size(); ++mid) {\n        long long diff = llabs(prefix[mid] * 2 - total);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestMid = mid;\n        }\n    }\n    vector<int> leftIds(ids.begin(), ids.begin() + bestMid);\n    vector<int> rightIds(ids.begin() + bestMid, ids.end());\n    long long sumLeft = prefix[bestMid];\n\n    bool preferHoriz = (h >= w);\n    int splitLen = -1;\n    bool ok = false;\n\n    auto try_split_horizontal = [&](long long needLeft) -> bool {\n        if (h < 2) return false;\n        long double ratio = total > 0 ? (long double)needLeft / (long double)total : 0.5L;\n        int split = (int)llround((long double)h * ratio);\n        split = max(1, min(h - 1, split));\n        splitLen = split;\n        return true;\n    };\n    auto try_split_vertical = [&](long long needLeft) -> bool {\n        if (w < 2) return false;\n        long double ratio = total > 0 ? (long double)needLeft / (long double)total : 0.5L;\n        int split = (int)llround((long double)w * ratio);\n        split = max(1, min(w - 1, split));\n        splitLen = split;\n        return true;\n    };\n\n    if (preferHoriz) {\n        ok = try_split_horizontal(sumLeft);\n        if (ok) node.splitHorizontal = true;\n    }\n    if (!ok) {\n        ok = try_split_vertical(sumLeft);\n        if (ok) node.splitHorizontal = false;\n    }\n    if (!ok) {\n        if (h >= 2) {\n            node.splitHorizontal = true;\n            splitLen = max(1, min(h - 1, h / 2));\n        } else {\n            node.splitHorizontal = false;\n            splitLen = max(1, min(w - 1, w / 2));\n        }\n    }\n\n    if (node.splitHorizontal) {\n        node.left = build_tree(leftIds, x0, y0, x0 + splitLen, y1);\n        node.right = build_tree(rightIds, x0 + splitLen, y0, x1, y1);\n    } else {\n        node.left = build_tree(leftIds, x0, y0, x1, y0 + splitLen);\n        node.right = build_tree(rightIds, x0, y0 + splitLen, x1, y1);\n    }\n    return nodeId;\n}\n\nlong double build_weights(int node, const vector<long double>& weights) {\n    TreeNode &nd = nodes[node];\n    if (nd.isLeaf) {\n        long double val = max<long double>(weights[nd.leaf], 1e-9L);\n        subtreeWeight[node] = val;\n        return val;\n    }\n    long double left = build_weights(nd.left, weights);\n    long double right = build_weights(nd.right, weights);\n    subtreeWeight[node] = left + right;\n    return subtreeWeight[node];\n}\n\nint calc_split_len(int len, long double leftWeight, long double totalWeight) {\n    if (len <= 1) return 1;\n    if (totalWeight <= 0) totalWeight = 1.0L;\n    long double ratio = leftWeight / totalWeight;\n    ratio = max((long double)0.0L, min((long double)1.0L, ratio));\n    int split = (int)llround((long double)len * ratio);\n    split = max(1, min(len - 1, split));\n    return split;\n}\n\nvoid assign_geometry(int node, int x0, int y0, int x1, int y1) {\n    TreeNode &nd = nodes[node];\n    if (nd.isLeaf) {\n        currentRects[nd.leaf].i0 = x0;\n        currentRects[nd.leaf].j0 = y0;\n        currentRects[nd.leaf].i1 = x1;\n        currentRects[nd.leaf].j1 = y1;\n        long long area = 1LL * (x1 - x0) * (y1 - y0);\n        if (area <= 0) area = 1;\n        leafActualArea[nd.leaf] = area;\n        return;\n    }\n    int h = x1 - x0;\n    int w = y1 - y0;\n    bool canHoriz = (h >= 2);\n    bool canVert = (w >= 2);\n    bool useHoriz = nd.splitHorizontal;\n    if (useHoriz && !canHoriz) useHoriz = false;\n    if (!useHoriz && !canVert) useHoriz = true;\n\n    long double leftW = subtreeWeight[nd.left];\n    long double rightW = subtreeWeight[nd.right];\n    long double total = leftW + rightW;\n    if (total <= 0) { leftW = rightW = 1.0L; total = 2.0L; }\n\n    if (useHoriz) {\n        int split = calc_split_len(h, leftW, total);\n        assign_geometry(nd.left, x0, y0, x0 + split, y1);\n        assign_geometry(nd.right, x0 + split, y0, x1, y1);\n    } else {\n        int split = calc_split_len(w, leftW, total);\n        assign_geometry(nd.left, x0, y0, x1, y0 + split);\n        assign_geometry(nd.right, x0, y0 + split, x1, y1);\n    }\n}\n\nvoid apply_layout(const vector<long long>& leafWeights, vector<long long>& actualAreas) {\n    vector<long double> weightLD(N);\n    for (int i = 0; i < N; ++i)\n        weightLD[i] = max<long double>((long double)leafWeights[i], 1.0L);\n    subtreeWeight.assign(nodes.size(), 0.0L);\n    build_weights(rootNode, weightLD);\n    assign_geometry(rootNode, 0, 0, W, W);\n    actualAreas = leafActualArea;\n}\n\nvoid adjust_working(const vector<long long>& base,\n                    const vector<long long>& target,\n                    vector<long long>& working) {\n    working = base;\n    vector<long long> curTarget = target;\n    int n = base.size();\n    long long need = 0;\n    vector<pair<long long,int>> donors;\n    donors.reserve(n);\n    for (int i = 0; i < n; ++i) {\n        if (working[i] < curTarget[i]) {\n            need += curTarget[i] - working[i];\n            working[i] = curTarget[i];\n        }\n    }\n    for (int i = 0; i < n; ++i) {\n        long long slack = working[i] - curTarget[i];\n        if (slack > 0) donors.emplace_back(slack, i);\n    }\n    sort(donors.begin(), donors.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 : donors) {\n        if (need == 0) break;\n        int idx = p.second;\n        long long avail = working[idx] - curTarget[idx];\n        if (avail <= 0) continue;\n        long long take = min(avail, need);\n        working[idx] -= take;\n        need -= take;\n    }\n    if (need > 0) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b){\n            if (working[a] != working[b]) return working[a] > working[b];\n            return a < b;\n        });\n        for (int idx : ord) {\n            if (need == 0) break;\n            long long can = working[idx] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, need);\n            working[idx] -= take;\n            need -= take;\n        }\n    }\n    if (need > 0) {\n        for (int idx : orderIdx) {\n            if (need == 0) break;\n            long long can = working[idx] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, need);\n            working[idx] -= take;\n            need -= take;\n        }\n    }\n    if (need > 0) {\n        for (int i = 0; i < n && need > 0; ++i) {\n            long long can = working[i] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, need);\n            working[i] -= take;\n            need -= take;\n        }\n    }\n    for (int i = 0; i < n; ++i) working[i] = max(1LL, working[i]);\n\n    long long sum = accumulate(working.begin(), working.end(), 0LL);\n    if (sum > TOT) {\n        long long excess = sum - TOT;\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b){\n            if (working[a] != working[b]) return working[a] > working[b];\n            return a < b;\n        });\n        for (int idx : ord) {\n            if (excess == 0) break;\n            long long can = working[idx] - 1;\n            if (can <= 0) continue;\n            long long take = min(can, excess);\n            working[idx] -= take;\n            excess -= take;\n        }\n        if (excess > 0) {\n            for (int i = 0; i < n && excess > 0; ++i) {\n                long long can = working[i] - 1;\n                if (can <= 0) continue;\n                long long take = min(can, excess);\n                working[i] -= take;\n                excess -= take;\n            }\n        }\n    } else if (sum < TOT) {\n        long long deficit = TOT - sum;\n        while (deficit > 0) {\n            for (int idx : orderIdx) {\n                if (deficit == 0) break;\n                long long add = min(deficit, 1LL);\n                working[idx] += add;\n                deficit -= add;\n            }\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    if (!(cin >> W >> D >> N)) return 0;\n    TOT = 1LL * W * W;\n    demands.assign(D, vector<int>(N));\n    for (int d = 0; d < D; ++d)\n        for (int k = 0; k < N; ++k)\n            cin >> demands[d][k];\n\n    baseArea = compute_base_area();\n\n    orderIdx.resize(N);\n    iota(orderIdx.begin(), orderIdx.end(), 0);\n    sort(orderIdx.begin(), orderIdx.end(), [&](int a, int b) {\n        if (baseArea[a] != baseArea[b]) return baseArea[a] > baseArea[b];\n        return a < b;\n    });\n\n    nodes.reserve(2 * N + 5);\n    rootNode = build_tree(orderIdx, 0, 0, W, W);\n\n    currentRects.assign(N, RectInfo());\n    leafActualArea.assign(N, 1);\n\n    apply_layout(baseArea, leafActualArea);\n    vector<long long> lastAreas = leafActualArea;\n\n    vector<long long> desiredLeaf(N, 1);\n    vector<long long> effectiveTarget(N, 1);\n    vector<long long> baseVec(N), working(N), actual(N);\n    vector<pair<int,int>> req(N);\n    vector<int> reqToLeaf(N);\n    const int MAX_ITER = 6;\n\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) req[k] = {demands[d][k], k};\n        sort(req.begin(), req.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 pos = 0; pos < N; ++pos) {\n            int leaf = orderIdx[pos];\n            desiredLeaf[leaf] = req[pos].first;\n            reqToLeaf[req[pos].second] = leaf;\n        }\n\n        effectiveTarget = desiredLeaf;\n        baseVec = lastAreas;\n        for (int iter = 0; iter < MAX_ITER; ++iter) {\n            adjust_working(baseVec, effectiveTarget, working);\n            apply_layout(working, actual);\n            bool ok = true;\n            for (int i = 0; i < N; ++i) {\n                long long deficit = desiredLeaf[i] - actual[i];\n                if (deficit > 0) {\n                    effectiveTarget[i] += deficit + 1;\n                    ok = false;\n                }\n            }\n            baseVec = actual;\n            if (ok) break;\n        }\n        lastAreas = actual;\n\n        for (int k = 0; k < N; ++k) {\n            const RectInfo &r = currentRects[reqToLeaf[k]];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Operation {\n    int stamp;\n    int p, q;\n    array<int, 9> cells;\n    array<int, 9> adds;\n};\n\nstruct Solver {\n    static constexpr int MOD = 998244353;\n    int N, M, K;\n    vector<int> board_mod;\n    vector<Operation> ops;\n    vector<char> used;\n    vector<int> used_ops;\n    vector<int> pos_in_used;\n    long long current_score = 0;\n    long long best_score = 0;\n    vector<int> best_ops;\n\n    mt19937 rng;\n    uniform_real_distribution<double> dist01;\n\n    Solver() : rng(random_device{}()), dist01(0.0, 1.0) {}\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        auto global_start = chrono::steady_clock::now();\n\n        cin >> N >> M >> K;\n        vector<int> initial(N * N);\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                cin >> initial[i * N + j];\n            }\n        }\n        vector<array<array<int, 3>, 3>> stamps(M);\n        for (int m = 0; m < M; ++m) {\n            for (int i = 0; i < 3; ++i) {\n                for (int j = 0; j < 3; ++j) {\n                    cin >> stamps[m][i][j];\n                }\n            }\n        }\n\n        build_operations(stamps);\n\n        board_mod = initial;\n        used.assign(ops.size(), 0);\n        pos_in_used.assign(ops.size(), -1);\n        used_ops.clear();\n        used_ops.reserve(K);\n\n        current_score = 0;\n        for (int v : board_mod) current_score += v;\n        best_score = current_score;\n        best_ops = used_ops;\n\n        greedy_init();\n\n        constexpr double TOTAL_TIME_LIMIT = 1.90; // seconds\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n        double remaining = TOTAL_TIME_LIMIT - elapsed;\n        if (remaining > 0.05 && !ops.empty()) {\n            simulated_annealing(max(0.01, remaining - 0.01));\n        }\n\n        output_best();\n    }\n\n    void build_operations(const vector<array<array<int, 3>, 3>>& stamps) {\n        ops.clear();\n        int placements = (N - 2) * (N - 2);\n        ops.reserve(M * placements);\n        for (int m = 0; m < M; ++m) {\n            for (int p = 0; p <= N - 3; ++p) {\n                for (int q = 0; q <= N - 3; ++q) {\n                    Operation op;\n                    op.stamp = m;\n                    op.p = p;\n                    op.q = q;\n                    int idx = 0;\n                    for (int i = 0; i < 3; ++i) {\n                        for (int j = 0; j < 3; ++j) {\n                            op.cells[idx] = (p + i) * N + (q + j);\n                            op.adds[idx] = stamps[m][i][j];\n                            ++idx;\n                        }\n                    }\n                    ops.push_back(op);\n                }\n            }\n        }\n    }\n\n    long long apply_operation(int op_idx) {\n        const Operation& op = ops[op_idx];\n        long long delta = 0;\n        for (int t = 0; t < 9; ++t) {\n            int add = op.adds[t];\n            if (add == 0) continue;\n            int idx = op.cells[t];\n            int before = board_mod[idx];\n            int after = before + add;\n            if (after >= MOD) after -= MOD;\n            board_mod[idx] = after;\n            delta += after - before;\n        }\n        return delta;\n    }\n\n    long long remove_operation(int op_idx) {\n        const Operation& op = ops[op_idx];\n        long long delta = 0;\n        for (int t = 0; t < 9; ++t) {\n            int add = op.adds[t];\n            if (add == 0) continue;\n            int idx = op.cells[t];\n            int before = board_mod[idx];\n            int after = before - add;\n            if (after < 0) after += MOD;\n            board_mod[idx] = after;\n            delta += after - before;\n        }\n        return delta;\n    }\n\n    void greedy_init() {\n        for (int iter = 0; iter < K; ++iter) {\n            long long best_delta = 0;\n            int best_idx = -1;\n            for (int op_idx = 0; op_idx < (int)ops.size(); ++op_idx) {\n                if (used[op_idx]) continue;\n                const Operation& op = ops[op_idx];\n                long long delta = 0;\n                for (int t = 0; t < 9; ++t) {\n                    int add = op.adds[t];\n                    if (add == 0) continue;\n                    int idx = op.cells[t];\n                    int before = board_mod[idx];\n                    int after = before + add;\n                    if (after >= MOD) after -= MOD;\n                    delta += after - before;\n                }\n                if (delta > best_delta) {\n                    best_delta = delta;\n                    best_idx = op_idx;\n                }\n            }\n            if (best_idx == -1 || best_delta <= 0) break;\n            long long delta = apply_operation(best_idx);\n            current_score += delta;\n            used[best_idx] = 1;\n            pos_in_used[best_idx] = used_ops.size();\n            used_ops.push_back(best_idx);\n            if (current_score > best_score) {\n                best_score = current_score;\n                best_ops = used_ops;\n            }\n        }\n    }\n\n    int pick_random_unused() {\n        if ((int)used_ops.size() >= (int)ops.size()) return -1;\n        for (int attempt = 0; attempt < 32; ++attempt) {\n            int idx = rng() % ops.size();\n            if (!used[idx]) return idx;\n        }\n        for (int idx = 0; idx < (int)ops.size(); ++idx) {\n            if (!used[idx]) return idx;\n        }\n        return -1;\n    }\n\n    bool accept_move(long long delta, double temp) {\n        if (delta >= 0) return true;\n        if (temp <= 1e-9) return false;\n        double ratio = delta / temp;\n        if (ratio < -50.0) return false;\n        double prob = exp(ratio);\n        return dist01(rng) < prob;\n    }\n\n    void simulated_annealing(double time_limit) {\n        auto start = chrono::steady_clock::now();\n        auto end_time = start + chrono::duration<double>(time_limit);\n        const double START_TEMP = 5e8;\n        const double END_TEMP = 5e2;\n        double temp = START_TEMP;\n        long long iter = 0;\n\n        while (true) {\n            if ((iter & 63) == 0) {\n                auto now = chrono::steady_clock::now();\n                if (now >= end_time) break;\n                double elapsed = chrono::duration<double>(now - start).count();\n                double progress = min(1.0, max(0.0, elapsed / time_limit));\n                temp = START_TEMP + (END_TEMP - START_TEMP) * progress;\n                if (temp < 1.0) temp = 1.0;\n            }\n            ++iter;\n\n            int used_cnt = (int)used_ops.size();\n            int move_type;\n            if (used_cnt == 0) {\n                move_type = 0;\n            } else if (used_cnt >= K) {\n                move_type = (rng() & 1) ? 1 : 2;\n            } else {\n                move_type = rng() % 3;\n            }\n\n            if (move_type == 0) { // add\n                int op_idx = pick_random_unused();\n                if (op_idx == -1) continue;\n                long long delta = apply_operation(op_idx);\n                current_score += delta;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    used[op_idx] = 1;\n                    pos_in_used[op_idx] = used_ops.size();\n                    used_ops.push_back(op_idx);\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev = remove_operation(op_idx);\n                    current_score += rev;\n                }\n            } else if (move_type == 1) { // remove\n                if (used_cnt == 0) continue;\n                int pos = rng() % used_cnt;\n                int op_idx = used_ops[pos];\n                long long delta = remove_operation(op_idx);\n                current_score += delta;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    int last_op = used_ops.back();\n                    used_ops[pos] = last_op;\n                    pos_in_used[last_op] = pos;\n                    used_ops.pop_back();\n                    used[op_idx] = 0;\n                    pos_in_used[op_idx] = -1;\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev = apply_operation(op_idx);\n                    current_score += rev;\n                }\n            } else { // swap\n                if (used_cnt == 0) continue;\n                int op_add = pick_random_unused();\n                if (op_add == -1) continue;\n                int pos = rng() % used_cnt;\n                int op_remove = used_ops[pos];\n\n                long long delta_remove = remove_operation(op_remove);\n                current_score += delta_remove;\n\n                long long delta_add = apply_operation(op_add);\n                current_score += delta_add;\n\n                long long delta = delta_remove + delta_add;\n                bool accept = accept_move(delta, temp);\n                if (accept) {\n                    int last_op = used_ops.back();\n                    used_ops[pos] = last_op;\n                    pos_in_used[last_op] = pos;\n                    used_ops.pop_back();\n                    used[op_remove] = 0;\n                    pos_in_used[op_remove] = -1;\n\n                    used[op_add] = 1;\n                    pos_in_used[op_add] = used_ops.size();\n                    used_ops.push_back(op_add);\n\n                    if (current_score > best_score) {\n                        best_score = current_score;\n                        best_ops = used_ops;\n                    }\n                } else {\n                    long long rev_add = remove_operation(op_add);\n                    current_score += rev_add;\n                    long long rev_remove = apply_operation(op_remove);\n                    current_score += rev_remove;\n                }\n            }\n        }\n    }\n\n    void output_best() const {\n        cout << best_ops.size() << '\\n';\n        for (int idx : best_ops) {\n            const Operation& op = ops[idx];\n            cout << op.stamp << ' ' << op.p << ' ' << op.q << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int LIMIT = 10000;\n\nstruct Params {\n    int rowWeight;\n    int colWeight;\n    int gateColBias;\n    int diffWeight;\n    int backlogWeight;\n    int distWeight;\n    int forcedGapWeight;\n    int sameRowBonus;\n    int focusBonus;\n    int noiseRange;\n};\n\nstruct ImprovedSolver {\n    int N;\n    const vector<vector<int>> &A;\n    const Params &params;\n    mt19937_64 rng;\n\n    string mainOps;\n    int cr = 0, cc = 0;\n    int holding = -1;\n    bool ok = true;\n\n    vector<int> gate_idx;\n    vector<int> next_needed;\n    vector<bool> id_done;\n    vector<pair<int,int>> stored_loc;\n    vector<vector<int>> stored_ids;\n    vector<int> stored_pos;\n    vector<vector<int>> grid;\n    vector<pair<int,int>> storage_cells;\n    vector<vector<pair<int,int>>> rowPrefCells;\n\n    int empty_slots = 0;\n    int stored_total = 0;\n    int total_dispatched = 0;\n    int focus_row = 0;\n\n    ImprovedSolver(int N_, const vector<vector<int>> &A_, const Params &p, uint64_t seed)\n        : N(N_), A(A_), params(p), rng(seed) {\n        init();\n    }\n\n    void init() {\n        mainOps.clear();\n        cr = 0; cc = 0; holding = -1; ok = true;\n        focus_row = 0;\n        int total = N * N;\n        gate_idx.assign(N, 0);\n        next_needed.resize(N);\n        for (int r = 0; r < N; ++r) next_needed[r] = r * N;\n        id_done.assign(total, false);\n        stored_loc.assign(total, {-1, -1});\n        stored_ids.assign(N, {});\n        stored_pos.assign(total, -1);\n        grid.assign(N, vector<int>(N, -99));\n        storage_cells.clear();\n        rowPrefCells.assign(N, {});\n        empty_slots = 0;\n        stored_total = 0;\n        total_dispatched = 0;\n\n        for (int r = 0; r < N; ++r) {\n            grid[r][0] = -10;\n            for (int c = 1; c <= N - 2; ++c) {\n                grid[r][c] = -1;\n                storage_cells.push_back({r, c});\n                rowPrefCells[r].push_back({r, c});\n                ++empty_slots;\n            }\n            grid[r][N - 1] = -11;\n        }\n    }\n\n    inline int dist(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    inline int randNoise() {\n        if (params.noiseRange <= 0) return 0;\n        uint64_t val = rng();\n        int span = params.noiseRange * 2 + 1;\n        return int(val % span) - params.noiseRange;\n    }\n\n    bool apply_action(char c) {\n        if (!ok) return false;\n        mainOps.push_back(c);\n        if ((int)mainOps.size() > LIMIT) {\n            ok = false;\n            return false;\n        }\n        return true;\n    }\n\n    bool move_char(char c) {\n        if (!apply_action(c)) return false;\n        if (c == 'U') --cr;\n        else if (c == 'D') ++cr;\n        else if (c == 'L') --cc;\n        else if (c == 'R') ++cc;\n        else { ok = false; return false; }\n        if (cr < 0 || cr >= N || cc < 0 || cc >= N) { ok = false; return false; }\n        return true;\n    }\n\n    bool move_to(int tr, int tc) {\n        while (cr < tr) if (!move_char('D')) return false;\n        while (cr > tr) if (!move_char('U')) return false;\n        while (cc < tc) if (!move_char('R')) return false;\n        while (cc > tc) if (!move_char('L')) return false;\n        return true;\n    }\n\n    bool pick_action(int id) {\n        if (holding != -1) { ok = false; return false; }\n        if (!apply_action('P')) return false;\n        holding = id;\n        return true;\n    }\n\n    bool drop_action() {\n        if (holding == -1) { ok = false; return false; }\n        if (!apply_action('Q')) return false;\n        holding = -1;\n        return true;\n    }\n\n    void advance_next(int row) {\n        int row_end = (row + 1) * N;\n        while (next_needed[row] < row_end && id_done[next_needed[row]]) {\n            ++next_needed[row];\n        }\n    }\n\n    void add_storage_cell(int r, int c) {\n        if (grid[r][c] == -10) {\n            grid[r][c] = -1;\n            storage_cells.push_back({r, c});\n            rowPrefCells[r].push_back({r, c});\n            ++empty_slots;\n        }\n    }\n\n    pair<int,int> choose_storage_cell(int target_row) {\n        for (auto [r, c] : rowPrefCells[target_row]) {\n            if (grid[r][c] == -1) return {r, c};\n        }\n        int best_cost = INT_MAX;\n        pair<int,int> best = {-1, -1};\n        for (auto [r, c] : storage_cells) {\n            if (grid[r][c] == -1) {\n                int cost = params.rowWeight * abs(r - target_row)\n                         + params.colWeight * (N - 1 - c);\n                if (c == 0) cost += params.gateColBias;\n                if (cost < best_cost) {\n                    best_cost = cost;\n                    best = {r, c};\n                }\n            }\n        }\n        return best;\n    }\n\n    bool store_current(int id) {\n        int row = id / N;\n        auto cell = choose_storage_cell(row);\n        if (cell.first == -1) { ok = false; return false; }\n        if (!move_to(cell.first, cell.second)) return false;\n        if (grid[cell.first][cell.second] != -1) { ok = false; return false; }\n        if (!drop_action()) return false;\n        grid[cell.first][cell.second] = id;\n        stored_loc[id] = cell;\n        stored_pos[id] = (int)stored_ids[row].size();\n        stored_ids[row].push_back(id);\n        --empty_slots;\n        ++stored_total;\n        return true;\n    }\n\n    bool pickup_from_storage(int id) {\n        auto [r, c] = stored_loc[id];\n        if (r == -1) { ok = false; return false; }\n        if (!move_to(r, c)) return false;\n        if (grid[r][c] != id) { ok = false; return false; }\n        if (!pick_action(id)) return false;\n        grid[r][c] = -1;\n        stored_loc[id] = {-1, -1};\n        ++empty_slots;\n        --stored_total;\n        int row = id / N;\n        int idx = stored_pos[id];\n        if (idx < 0) { ok = false; return false; }\n        int last = stored_ids[row].back();\n        stored_ids[row][idx] = last;\n        stored_pos[last] = idx;\n        stored_ids[row].pop_back();\n        stored_pos[id] = -1;\n        return true;\n    }\n\n    bool deliver_after_pick(int id) {\n        int row = id / N;\n        if (!move_to(row, N - 1)) return false;\n        if (!drop_action()) return false;\n        id_done[id] = true;\n        ++total_dispatched;\n        advance_next(row);\n        focus_row = row;\n        return true;\n    }\n\n    bool deliver_from_storage(int id) {\n        if (!pickup_from_storage(id)) return false;\n        return deliver_after_pick(id);\n    }\n\n    long long row_bonus(int row) const {\n        int dr = abs(row - cr);\n        if (dr == 0) return params.sameRowBonus;\n        if (dr == 1) return params.sameRowBonus / 2;\n        return 0;\n    }\n\n    long long focus_bonus(int row) const {\n        int dr = abs(row - focus_row);\n        if (dr == 0) return params.focusBonus;\n        if (dr == 1) return params.focusBonus / 2;\n        return 0;\n    }\n\n    bool fetch_gate(int gate) {\n        if (gate_idx[gate] >= N) { ok = false; return false; }\n        int id = A[gate][gate_idx[gate]];\n        int row = id / N;\n        if (!move_to(gate, 0)) return false;\n        if (!pick_action(id)) return false;\n        ++gate_idx[gate];\n        if (gate_idx[gate] == N) add_storage_cell(gate, 0);\n\n        int row_end = (row + 1) * N;\n        bool immediate = (next_needed[row] < row_end && id == next_needed[row]);\n        if (immediate) return deliver_after_pick(id);\n        if (empty_slots <= 0) { ok = false; return false; }\n        return store_current(id);\n    }\n\n    bool deliver_ready_from_storage() {\n        long long best_score = (1LL << 60);\n        int best_id = -1;\n        for (int r = 0; r < N; ++r) {\n            int need = next_needed[r];\n            int row_end = (r + 1) * N;\n            if (need >= row_end) continue;\n            if (stored_pos[need] == -1) continue;\n            auto [sr, sc] = stored_loc[need];\n            int cost = dist(cr, cc, sr, sc) + dist(sr, sc, r, N - 1);\n            long long score = cost - row_bonus(r) - focus_bonus(r) - randNoise();\n            if (score < best_score || (score == best_score && need < best_id)) {\n                best_score = score;\n                best_id = need;\n            }\n        }\n        if (best_id != -1) {\n            return deliver_from_storage(best_id);\n        }\n        return false;\n    }\n\n    bool fetch_gate_immediate() {\n        int best_gate = -1;\n        int best_id = -1;\n        long long best_score = (1LL << 60);\n        for (int g = 0; g < N; ++g) {\n            if (gate_idx[g] >= N) continue;\n            int id = A[g][gate_idx[g]];\n            int row = id / N;\n            int row_end = (row + 1) * N;\n            if (!(next_needed[row] < row_end && id == next_needed[row])) continue;\n            int cost = dist(cr, cc, g, 0) + dist(g, 0, row, N - 1);\n            long long score = cost - row_bonus(row) - focus_bonus(row) - randNoise();\n            if (score < best_score || (score == best_score && id < best_id)) {\n                best_score = score;\n                best_gate = g;\n                best_id = id;\n            }\n        }\n        if (best_gate != -1) {\n            return fetch_gate(best_gate);\n        }\n        return false;\n    }\n\n    int select_forced_id_cost() {\n        int best_id = -1;\n        long long best_score = (1LL << 60);\n        for (int r = 0; r < N; ++r) {\n            if (stored_ids[r].empty()) continue;\n            int need = next_needed[r];\n            for (int id : stored_ids[r]) {\n                auto [sr, sc] = stored_loc[id];\n                if (sr == -1) continue;\n                int gap = max(id - need, 0);\n                int cost = dist(cr, cc, sr, sc) + dist(sr, sc, r, N - 1);\n                long long score = 1LL * params.forcedGapWeight * gap\n                                + cost - row_bonus(r) - focus_bonus(r) - randNoise();\n                if (score < best_score || (score == best_score && id < best_id)) {\n                    best_score = score;\n                    best_id = id;\n                }\n            }\n        }\n        return best_id;\n    }\n\n    bool fetch_general_gate() {\n        long long best_score = (1LL << 60);\n        int best_gate = -1;\n        int best_diff = INT_MAX;\n        int best_distgate = INT_MAX;\n        int best_id = INT_MAX;\n        for (int g = 0; g < N; ++g) {\n            if (gate_idx[g] >= N) continue;\n            int id = A[g][gate_idx[g]];\n            int row = id / N;\n            int need = next_needed[row];\n            int row_end = (row + 1) * N;\n            int diff = (need < row_end) ? max(id - need, 0) : max(id - row_end, 0) + 5;\n            int backlog = (int)stored_ids[row].size();\n            int distGate = dist(cr, cc, g, 0);\n            long long score = 1LL * params.diffWeight * diff\n                            + 1LL * params.backlogWeight * backlog\n                            + 1LL * params.distWeight * distGate\n                            - row_bonus(row) - focus_bonus(row) - randNoise();\n            if (score < best_score ||\n                (score == best_score &&\n                 (diff < best_diff ||\n                  (diff == best_diff &&\n                   (distGate < best_distgate ||\n                    (distGate == best_distgate && id < best_id))))))\n            {\n                best_score = score;\n                best_gate = g;\n                best_diff = diff;\n                best_distgate = distGate;\n                best_id = id;\n            }\n        }\n        if (best_gate != -1) {\n            return fetch_gate(best_gate);\n        }\n        return false;\n    }\n\n    bool step() {\n        if (!ok) return false;\n        if (deliver_ready_from_storage()) return true;\n        if (fetch_gate_immediate()) return true;\n        if (empty_slots == 0) {\n            int forced_id = select_forced_id_cost();\n            if (forced_id == -1) { ok = false; return false; }\n            return deliver_from_storage(forced_id);\n        }\n        if (fetch_general_gate()) return true;\n        if (stored_total > 0) {\n            int forced_id = select_forced_id_cost();\n            if (forced_id == -1) { ok = false; return false; }\n            return deliver_from_storage(forced_id);\n        }\n        ok = false;\n        return false;\n    }\n\n    vector<string> run() {\n        int guard = 0;\n        while (ok && total_dispatched < N * N && guard < 200000) {\n            if (!step()) break;\n            ++guard;\n        }\n        if (!ok || total_dispatched != N * N || holding != -1) return {};\n        string big = mainOps;\n        if (big.empty()) big.push_back('.');\n        int L = big.size();\n        vector<string> ops(N);\n        ops[0] = big;\n        for (int i = 1; i < N; ++i) {\n            string s(L, '.');\n            if (!s.empty()) s[0] = 'B';\n            ops[i] = move(s);\n        }\n        return ops;\n    }\n};\n\nvector<string> solve_baseline(int N, const vector<vector<int>> &A) {\n    string mainOps;\n    int cr = 0, cc = 0;\n    auto move_char = [&](char c) {\n        mainOps.push_back(c);\n        if (c == 'U') --cr;\n        else if (c == 'D') ++cr;\n        else if (c == 'L') --cc;\n        else if (c == 'R') ++cc;\n    };\n    auto move_to = [&](int tr, int tc) {\n        while (cr < tr) move_char('D');\n        while (cr > tr) move_char('U');\n        while (cc < tc) move_char('R');\n        while (cc > tc) move_char('L');\n    };\n    for (int src = 0; src < N; ++src) {\n        for (int idx = 0; idx < N; ++idx) {\n            move_to(src, 0);\n            mainOps.push_back('P');\n            int id = A[src][idx];\n            int row = id / N;\n            move_to(row, N - 1);\n            mainOps.push_back('Q');\n        }\n    }\n    if (mainOps.empty()) mainOps.push_back('.');\n    vector<string> ops(N);\n    int L = mainOps.size();\n    ops[0] = mainOps;\n    for (int i = 1; i < N; ++i) {\n        string s(L, '.');\n        if (!s.empty()) s[0] = 'B';\n        ops[i] = move(s);\n    }\n    return ops;\n}\n\ntemplate<class T>\nT clampT(T x, T l, T r) { return min(max(x, l), r); }\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>> A(N, vector<int>(N));\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            cin >> A[i][j];\n\n    vector<Params> baseParams = {\n        {40, 6, 80, 70, 10, 2,  90, 18, 18, 2},\n        {50, 7, 70, 80, 12, 1, 100, 20, 22, 3},\n        {35, 5, 90, 60,  8, 3,  80, 16, 16, 1},\n        {45, 8, 60, 55,  6, 4,  70, 14, 14, 2},\n        {30, 9, 85, 75,  9, 2, 110, 22, 24, 1},\n        {60, 5, 95, 65, 11, 1, 120, 25, 28, 4},\n        {38, 7, 75, 68,  9, 3,  95, 17, 18, 2},\n        {55, 6, 85, 72, 10, 2, 105, 21, 21, 3},\n        {42, 7, 78, 66,  9, 2,  88, 19, 20, 2},\n        {48, 8, 82, 69, 11, 3,  92, 23, 26, 3},\n        {33, 6, 87, 62,  7, 2,  85, 17, 17, 1},\n        {52, 5, 90, 74, 10, 3, 115, 24, 24, 2}\n    };\n\n    uint64_t baseSeed = 0;\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            baseSeed = baseSeed * 1000003ULL + (uint64_t)(A[i][j] + 1);\n\n    mt19937_64 rng(baseSeed ^ 0xdecafbadULL);\n    auto randInt = [&](int l, int r) {\n        return l + int(rng() % (uint64_t)(r - l + 1));\n    };\n\n    const auto start = chrono::steady_clock::now();\n    const double timeLimit = 2.95; // seconds\n    const int MAX_RANDOM_TRIES = 1000;\n    const int excellentThreshold = 320;\n\n    vector<string> best_ops;\n    size_t best_len = numeric_limits<size_t>::max();\n\n    struct Candidate {\n        size_t len;\n        Params p;\n    };\n    vector<Candidate> topParams;\n\n    auto addCandidate = [&](size_t len, const Params &p) {\n        topParams.push_back({len, p});\n        sort(topParams.begin(), topParams.end(),\n             [](const Candidate &a, const Candidate &b) { return a.len < b.len; });\n        if (topParams.size() > 3) topParams.resize(3);\n    };\n\n    auto try_params = [&](const Params &p, size_t idx) {\n        uint64_t runSeed = baseSeed ^ (0x9e3779b97f4a7c15ULL + 0x94d049bb133111ebULL * idx);\n        ImprovedSolver solver(N, A, p, runSeed);\n        auto ops = solver.run();\n        if (ops.empty()) return;\n        size_t len = ops[0].size();\n        if (len > (size_t)LIMIT) return;\n        addCandidate(len, p);\n        if (len < best_len) {\n            best_len = len;\n            best_ops = ops;\n        }\n    };\n\n    size_t idx = 0;\n    for (const auto &p : baseParams) {\n        try_params(p, idx++);\n    }\n\n    auto gen_random_params = [&]() -> Params {\n        Params p;\n        p.rowWeight       = randInt(25, 75);\n        p.colWeight       = randInt(3, 12);\n        p.gateColBias     = randInt(50, 130);\n        p.diffWeight      = randInt(35, 100);\n        p.backlogWeight   = randInt(4, 20);\n        p.distWeight      = randInt(1, 6);\n        p.forcedGapWeight = randInt(60, 150);\n        p.sameRowBonus    = randInt(8, 35);\n        p.focusBonus      = randInt(10, 40);\n        p.noiseRange      = randInt(0, 6);\n        return p;\n    };\n\n    auto gen_local_params = [&](const Params &baseP) -> Params {\n        Params p = baseP;\n        auto jitter = [&](int val, int delta, int lo, int hi) {\n            return clampT(val + randInt(-delta, delta), lo, hi);\n        };\n        p.rowWeight       = jitter(p.rowWeight,       8, 25, 75);\n        p.colWeight       = jitter(p.colWeight,       3,  3, 12);\n        p.gateColBias     = jitter(p.gateColBias,    15, 50,130);\n        p.diffWeight      = jitter(p.diffWeight,     10, 35,100);\n        p.backlogWeight   = jitter(p.backlogWeight,   4,  4, 20);\n        p.distWeight      = jitter(p.distWeight,      2,  1, 6);\n        p.forcedGapWeight = jitter(p.forcedGapWeight,15, 60,150);\n        p.sameRowBonus    = jitter(p.sameRowBonus,    5,  8, 35);\n        p.focusBonus      = jitter(p.focusBonus,      6, 10, 40);\n        p.noiseRange      = jitter(p.noiseRange,      2,  0, 6);\n        return p;\n    };\n\n    for (int t = 0; t < MAX_RANDOM_TRIES; ++t) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        if (elapsed > timeLimit || best_len <= (size_t)excellentThreshold) break;\n\n        Params p;\n        bool doLocal = (!topParams.empty() && randInt(0, 2) > 0); // 2/3 chance local if available\n        if (doLocal) {\n            const Candidate &cand = topParams[randInt(0, (int)topParams.size() - 1)];\n            p = gen_local_params(cand.p);\n        } else {\n            p = gen_random_params();\n        }\n        try_params(p, idx++);\n    }\n\n    if (best_ops.empty()) {\n        best_ops = solve_baseline(N, A);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << best_ops[i] << '\\n';\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Cell {\n    int r, c, val;\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    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j) cin >> h[i][j];\n\n    vector<string> ops;\n    ops.reserve(120000);\n\n    int cur_r = 0, cur_c = 0;\n    long long load = 0;\n\n    auto moveTo = [&](int tr, int tc) {\n        while (cur_r < tr) { ops.emplace_back(\"D\"); ++cur_r; }\n        while (cur_r > tr) { ops.emplace_back(\"U\"); --cur_r; }\n        while (cur_c < tc) { ops.emplace_back(\"R\"); ++cur_c; }\n        while (cur_c > tc) { ops.emplace_back(\"L\"); --cur_c; }\n    };\n\n    vector<Cell> positives, negatives;\n    positives.reserve(N * N);\n    negatives.reserve(N * N);\n\n    auto collectCells = [&]() {\n        positives.clear();\n        negatives.clear();\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int val = h[i][j];\n                if (val > 0) positives.push_back({i, j, val});\n                else if (val < 0) negatives.push_back({i, j, val});\n            }\n        }\n    };\n\n    auto selectPositive = [&]() -> pair<int,int> {\n        long long bestScore = (1LL << 60);\n        int bestVal = -1;\n        pair<int,int> best{-1,-1};\n        for (const auto& p : positives) {\n            long long distTruck = abs(cur_r - p.r) + abs(cur_c - p.c);\n            long long nearestNeg = 0;\n            if (!negatives.empty()) {\n                int dmin = INT_MAX;\n                for (const auto& n : negatives) {\n                    int d = abs(p.r - n.r) + abs(p.c - n.c);\n                    if (d < dmin) dmin = d;\n                }\n                nearestNeg = dmin;\n            }\n            long long score = distTruck * 1000 + nearestNeg * 350 - 20LL * p.val;\n            if (score < bestScore || (score == bestScore && p.val > bestVal)) {\n                bestScore = score;\n                bestVal = p.val;\n                best = {p.r, p.c};\n            }\n        }\n        return best;\n    };\n\n    auto selectNegative = [&]() -> pair<int,int> {\n        long long bestScore = (1LL << 60);\n        long long bestDeliver = -1;\n        pair<int,int> best{-1,-1};\n        for (const auto& n : negatives) {\n            long long dist = abs(cur_r - n.r) + abs(cur_c - n.c);\n            long long need = -n.val;\n            long long deliver = min<long long>(load, need);\n            if (deliver <= 0) continue;\n            long long score = dist * 1000 - deliver * 25;\n            if (score < bestScore || (score == bestScore && deliver > bestDeliver)) {\n                bestScore = score;\n                bestDeliver = deliver;\n                best = {n.r, n.c};\n            }\n        }\n        return best;\n    };\n\n    const int MAX_OPS = 100000;\n    const int CLEANUP_RESERVE = 36000; // leave room for final gather/distribute\n    const int MAX_ITER = 200000;\n    int iter = 0;\n\n    while ((int)ops.size() < MAX_OPS - CLEANUP_RESERVE && iter < MAX_ITER) {\n        collectCells();\n        if (positives.empty() && negatives.empty() && load == 0) break;\n\n        if (load == 0) {\n            if (positives.empty()) break;\n            auto tgt = selectPositive();\n            if (tgt.first == -1) break;\n            moveTo(tgt.first, tgt.second);\n            int amount = h[tgt.first][tgt.second];\n            if (amount <= 0) { ++iter; continue; }\n            ops.emplace_back(\"+\" + to_string(amount));\n            load += amount;\n            h[tgt.first][tgt.second] = 0;\n        } else {\n            if (negatives.empty()) break;\n            auto tgt = selectNegative();\n            if (tgt.first == -1) break;\n            moveTo(tgt.first, tgt.second);\n            int need = -h[tgt.first][tgt.second];\n            if (need <= 0) { ++iter; continue; }\n            int amount = (int)min<long long>(load, need);\n            if (amount <= 0) { ++iter; continue; }\n            ops.emplace_back(\"-\" + to_string(amount));\n            load -= amount;\n            h[tgt.first][tgt.second] += amount;\n        }\n        ++iter;\n    }\n\n    if (load > 0) {\n        moveTo(0, 0);\n        ops.emplace_back(\"-\" + to_string(load));\n        h[0][0] += (int)load;\n        load = 0;\n    }\n\n    auto gatherPositivesToOrigin = [&]() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (i == 0 && j == 0) continue;\n                int val = h[i][j];\n                if (val <= 0) continue;\n                moveTo(i, j);\n                ops.emplace_back(\"+\" + to_string(val));\n                load += val;\n                h[i][j] = 0;\n                moveTo(0, 0);\n                ops.emplace_back(\"-\" + to_string(val));\n                load -= val;\n                h[0][0] += val;\n            }\n        }\n    };\n\n    auto distributeFromOrigin = [&]() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (h[i][j] >= 0) continue;\n                int need = -h[i][j];\n                if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n                ops.emplace_back(\"+\" + to_string(need));\n                load += need;\n                h[0][0] -= need;\n                moveTo(i, j);\n                ops.emplace_back(\"-\" + to_string(need));\n                load -= need;\n                h[i][j] = 0;\n            }\n        }\n    };\n\n    gatherPositivesToOrigin();\n    distributeFromOrigin();\n\n    if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n\n    if (h[0][0] > 0) {\n        int val = h[0][0];\n        ops.emplace_back(\"+\" + to_string(val));\n        load += val;\n        h[0][0] = 0;\n        ops.emplace_back(\"-\" + to_string(val));\n        load -= val;\n    } else if (h[0][0] < 0) {\n        int val = -h[0][0];\n        ops.emplace_back(\"-\" + to_string(val));\n        load -= val;\n        h[0][0] = 0;\n        ops.emplace_back(\"+\" + to_string(val));\n        load += val;\n    }\n\n    if (load > 0) {\n        if (cur_r != 0 || cur_c != 0) moveTo(0, 0);\n        ops.emplace_back(\"-\" + to_string(load));\n        h[0][0] += (int)load;\n        load = 0;\n    }\n\n    for (const string& op : ops) cout << op << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAX_M = 15;\nconstexpr int MAX_TOTAL = 2000;\nconstexpr int MAX_TARGETS = 5;\n\nstruct Seed {\n    array<int, MAX_M> attr;\n    int value;\n    Seed() {\n        attr.fill(0);\n        value = 0;\n    }\n};\n\ndouble computePairScore(const Seed& A, const Seed& B,\n                        const vector<int>& targets,\n                        const vector<double>& weights,\n                        const vector<double>& probWeights,\n                        int M,\n                        int bestValue,\n                        double potentialWeight,\n                        const vector<int>& attrTargets,\n                        const vector<double>& attrWeights,\n                        double attrComponentScale) {\n    static array<double, MAX_TOTAL> dp{};\n    static array<double, MAX_TOTAL> ndp{};\n\n    double attrScore = 0.0;\n    if (!attrWeights.empty()) {\n        for (int l = 0; l < M; ++l) {\n            double w = attrWeights[l];\n            if (w <= 1e-9) continue;\n            int target = attrTargets[l];\n            bool aGood = A.attr[l] >= target;\n            bool bGood = B.attr[l] >= target;\n            if (!aGood && !bGood) continue;\n            attrScore += (aGood && bGood) ? w : (w * 0.5);\n        }\n    }\n    double total = attrScore * attrComponentScale;\n\n    int maxSum = 0;\n    for (int l = 0; l < M; ++l) {\n        maxSum += max(A.attr[l], B.attr[l]);\n    }\n    if (maxSum + 1 > MAX_TOTAL) maxSum = MAX_TOTAL - 1;\n\n    fill(dp.begin(), dp.begin() + (maxSum + 1), 0.0);\n    dp[0] = 1.0;\n    int currentMax = 0;\n    for (int l = 0; l < M; ++l) {\n        int aVal = A.attr[l];\n        int bVal = B.attr[l];\n        int add = max(aVal, bVal);\n        int nextMax = currentMax + add;\n        if (nextMax > MAX_TOTAL - 1) nextMax = MAX_TOTAL - 1;\n        fill(ndp.begin(), ndp.begin() + (nextMax + 1), 0.0);\n        for (int s = 0; s <= currentMax; ++s) {\n            double prob = dp[s];\n            if (prob == 0.0) continue;\n            if (s + aVal <= nextMax) ndp[s + aVal] += prob * 0.5;\n            if (s + bVal <= nextMax) ndp[s + bVal] += prob * 0.5;\n        }\n        currentMax = nextMax;\n        dp.swap(ndp);\n    }\n\n    int K = targets.size();\n    if (K == 0) {\n        double potential = currentMax - bestValue;\n        if (potential > 0) total += potentialWeight * potential;\n        return total;\n    }\n\n    array<double, MAX_TARGETS> tailProb{};\n    array<double, MAX_TARGETS> tailSum{};\n    int minTarget = targets.front();\n    if (minTarget < 0) minTarget = 0;\n    if (currentMax > minTarget) {\n        for (int s = currentMax; s > minTarget; --s) {\n            double prob = dp[s];\n            if (prob == 0.0) continue;\n            for (int idx = 0; idx < K; ++idx) {\n                if (s > targets[idx]) {\n                    tailProb[idx] += prob;\n                    tailSum[idx] += prob * s;\n                } else {\n                    break;\n                }\n            }\n        }\n    }\n\n    for (int idx = 0; idx < K; ++idx) {\n        double sc = tailSum[idx] - static_cast<double>(targets[idx]) * tailProb[idx];\n        if (sc < 0) sc = 0;\n        total += weights[idx] * sc + probWeights[idx] * tailProb[idx];\n    }\n\n    double potential = currentMax - bestValue;\n    if (potential > 0) total += potentialWeight * potential;\n    return total;\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    int seedCount = 2 * N * (N - 1);\n    int selectCount = N * N;\n    vector<Seed> seeds(seedCount);\n    for (int i = 0; i < seedCount; ++i) {\n        int sum = 0;\n        for (int j = 0; j < M; ++j) {\n            int val;\n            cin >> val;\n            seeds[i].attr[j] = val;\n            sum += val;\n        }\n        for (int j = M; j < MAX_M; ++j) seeds[i].attr[j] = 0;\n        seeds[i].value = sum;\n    }\n\n    const int cellCount = selectCount;\n    vector<vector<int>> neighbors(cellCount);\n    vector<pair<int, int>> edges;\n    edges.reserve(2 * N * (N - 1));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int pos = i * N + j;\n            if (j + 1 < N) {\n                int q = pos + 1;\n                neighbors[pos].push_back(q);\n                neighbors[q].push_back(pos);\n                edges.emplace_back(pos, q);\n            }\n            if (i + 1 < N) {\n                int q = pos + N;\n                neighbors[pos].push_back(q);\n                neighbors[q].push_back(pos);\n                edges.emplace_back(pos, q);\n            }\n        }\n    }\n    vector<int> cellDegree(cellCount, 0);\n    for (int pos = 0; pos < cellCount; ++pos) {\n        sort(neighbors[pos].begin(), neighbors[pos].end());\n        neighbors[pos].erase(unique(neighbors[pos].begin(), neighbors[pos].end()), neighbors[pos].end());\n        cellDegree[pos] = (int)neighbors[pos].size();\n    }\n\n    vector<int> positionOrder(cellCount);\n    iota(positionOrder.begin(), positionOrder.end(), 0);\n    double center = (N - 1) / 2.0;\n    vector<double> cellDist(cellCount, 0.0);\n    for (int pos = 0; pos < cellCount; ++pos) {\n        int r = pos / N;\n        int c = pos % N;\n        cellDist[pos] = fabs(r - center) + fabs(c - center);\n    }\n    sort(positionOrder.begin(), positionOrder.end(), [&](int a, int b) {\n        if (fabs(cellDist[a] - cellDist[b]) > 1e-9) return cellDist[a] < cellDist[b];\n        if (cellDegree[a] != cellDegree[b]) return cellDegree[a] > cellDegree[b];\n        return a < b;\n    });\n    vector<int> positionOrderReverse = positionOrder;\n    reverse(positionOrderReverse.begin(), positionOrderReverse.end());\n    vector<int> positionOrderRow(cellCount);\n    iota(positionOrderRow.begin(), positionOrderRow.end(), 0);\n\n    mt19937 rng(712367);\n    uniform_real_distribution<double> realDist(0.0, 1.0);\n    uniform_int_distribution<int> posDist(0, cellCount - 1);\n\n    vector<int> orderIndices(seedCount);\n\n    for (int turn = 0; turn < T; ++turn) {\n        vector<int> bestAttrValue(M, -1);\n        vector<int> secondAttrValue(M, -1);\n        vector<int> bestAttrIndex(M, -1);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            for (int l = 0; l < M; ++l) {\n                int val = seeds[idx].attr[l];\n                if (val > bestAttrValue[l]) {\n                    secondAttrValue[l] = bestAttrValue[l];\n                    bestAttrValue[l] = val;\n                    bestAttrIndex[l] = idx;\n                } else if (val == bestAttrValue[l]) {\n                    if (bestAttrIndex[l] == -1 || seeds[idx].value > seeds[bestAttrIndex[l]].value) {\n                        secondAttrValue[l] = bestAttrValue[l];\n                        bestAttrValue[l] = val;\n                        bestAttrIndex[l] = idx;\n                    } else if (val > secondAttrValue[l]) {\n                        secondAttrValue[l] = val;\n                    }\n                } else if (val > secondAttrValue[l]) {\n                    secondAttrValue[l] = val;\n                }\n            }\n        }\n\n        vector<int> seedChampionCount(seedCount, 0);\n        vector<int> attrTopCount(M, 0);\n        for (int l = 0; l < M; ++l) {\n            if (bestAttrValue[l] < 0) continue;\n            for (int idx = 0; idx < seedCount; ++idx) {\n                if (seeds[idx].attr[l] == bestAttrValue[l]) {\n                    ++attrTopCount[l];\n                    ++seedChampionCount[idx];\n                }\n            }\n        }\n\n        vector<vector<int>> attrOrder(M, vector<int>(seedCount));\n        for (int l = 0; l < M; ++l) {\n            auto& arr = attrOrder[l];\n            iota(arr.begin(), arr.end(), 0);\n            int attrIdx = l;\n            sort(arr.begin(), arr.end(), [&](int a, int b) {\n                if (seeds[a].attr[attrIdx] != seeds[b].attr[attrIdx]) return seeds[a].attr[attrIdx] > seeds[b].attr[attrIdx];\n                if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n                return a < b;\n            });\n        }\n\n        int bestValue = 0;\n        for (const auto& s : seeds) bestValue = max(bestValue, s.value);\n\n        int targetMax = 0;\n        for (int l = 0; l < M; ++l) targetMax += max(0, bestAttrValue[l]);\n\n        const int maintainMargin = 8;\n        int maintainTarget = max(0, bestValue - maintainMargin);\n        int gap = max(0, targetMax - bestValue);\n        double phase = (T <= 1) ? 1.0 : (double)turn / (T - 1);\n        double gapFactor = min(1.0, (gap + 5.0) / 60.0);\n        int improveMargin1 = max(3, (int)round(min(gap * 0.35, 40.0)));\n        int improveMargin2 = max(improveMargin1 + 3, (int)round(min(gap * 0.65, 80.0)));\n        int targetImprove1 = min(bestValue + improveMargin1, targetMax);\n        int targetImprove2 = min(bestValue + improveMargin2, targetMax);\n\n        double improvementScale = (0.5 + 0.5 * (1.0 - phase)) * (0.4 + 0.6 * gapFactor);\n        improvementScale = clamp(improvementScale, 0.25, 1.2);\n        double maintainWeight = 0.8 + 0.5 * phase;\n        double maintainProbWeight = 0.05;\n        double improve1Weight = 4.0 * improvementScale;\n        double improve2Weight = 8.0 * improvementScale;\n        double improve1ProbWeight = 0.8 * improvementScale;\n        double improve2ProbWeight = 1.6 * improvementScale;\n        double potentialWeight = 0.02 + 0.04 * improvementScale;\n\n        vector<int> targets;\n        vector<double> weights, probWeights;\n        targets.reserve(MAX_TARGETS);\n        weights.reserve(MAX_TARGETS);\n        probWeights.reserve(MAX_TARGETS);\n        auto addTarget = [&](int target, double w, double pw) {\n            target = clamp(target, 0, targetMax);\n            if (!targets.empty() && target <= targets.back()) return;\n            if ((int)targets.size() >= MAX_TARGETS) return;\n            targets.push_back(target);\n            weights.push_back(w);\n            probWeights.push_back(pw);\n        };\n        addTarget(maintainTarget, maintainWeight, maintainProbWeight);\n        if (targetImprove1 > maintainTarget) addTarget(targetImprove1, improve1Weight, improve1ProbWeight);\n        if (targetImprove2 > targetImprove1) addTarget(targetImprove2, improve2Weight, improve2ProbWeight);\n\n        vector<int> attrTargets(M, 0);\n        vector<double> attrWeights(M, 0.0);\n        for (int l = 0; l < M; ++l) {\n            int bestVal = bestAttrValue[l];\n            if (bestVal <= 0) {\n                attrTargets[l] = 0;\n                attrWeights[l] = 0.0;\n                continue;\n            }\n            if (bestVal <= 8) {\n                attrTargets[l] = bestVal;\n                attrWeights[l] = 0.0;\n                continue;\n            }\n            int secondVal = max(0, secondAttrValue[l]);\n            int gapAttr = max(0, bestVal - secondVal);\n            int approx = (bestVal * 92 + 50) / 100;\n            int margin = max(1, gapAttr / 2);\n            int target = bestVal - margin;\n            target = max(target, approx);\n            target = max(target, bestVal - 6);\n            target = min(target, bestVal);\n            attrTargets[l] = max(0, target);\n            int bestCount = max(1, attrTopCount[l]);\n            double rarity = 1.0;\n            if (bestVal >= 90) rarity += 0.3;\n            else if (bestVal >= 80) rarity += 0.2;\n            if (gapAttr >= 5) rarity += 0.25;\n            if (gapAttr >= 10) rarity += 0.25;\n            if (bestCount <= 3) rarity += 0.25;\n            if (bestCount == 1) rarity += 0.35;\n            attrWeights[l] = rarity;\n        }\n        double attrComponentScale = (4.0 + 3.0 * (1.0 - phase)) * (0.85 + 0.25 * gapFactor);\n\n        vector<char> attrConsider(M, false);\n        vector<int> coverageThreshold(M, 0);\n        for (int l = 0; l < M; ++l) {\n            int bestVal = bestAttrValue[l];\n            if (bestVal >= 4) attrConsider[l] = true;\n            if (bestVal <= 1) {\n                coverageThreshold[l] = max(0, bestVal);\n            } else {\n                int base = max(attrTargets[l], bestVal - 4);\n                base = min(base, bestVal - 1);\n                coverageThreshold[l] = max(0, base);\n            }\n        }\n\n        vector<int> attrCoverage(seedCount, 0);\n        vector<int> nearBestCount(seedCount, 0);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            int sum = 0;\n            int near = 0;\n            for (int l = 0; l < M; ++l) {\n                if (!attrConsider[l]) continue;\n                int thr = coverageThreshold[l];\n                int diff = seeds[idx].attr[l] - thr;\n                if (diff >= 0) ++near;\n                if (diff > 0) sum += diff;\n            }\n            attrCoverage[idx] = sum;\n            nearBestCount[idx] = near;\n        }\n\n        double wValue = 1.0;\n        double wAttr = 4.5 + 6.0 * gapFactor;\n        double wNear = 8.0 + 6.0 * gapFactor;\n        double wChampion = 150.0 + 40.0 * gapFactor;\n\n        vector<double> combinedScore(seedCount, 0.0);\n        for (int idx = 0; idx < seedCount; ++idx) {\n            combinedScore[idx] = wValue * seeds[idx].value +\n                                 wAttr * attrCoverage[idx] +\n                                 wChampion * seedChampionCount[idx] +\n                                 wNear * nearBestCount[idx];\n        }\n\n        vector<int> attrImportance(M);\n        iota(attrImportance.begin(), attrImportance.end(), 0);\n        sort(attrImportance.begin(), attrImportance.end(), [&](int a, int b) {\n            if (attrWeights[a] > attrWeights[b] + 1e-9) return true;\n            if (attrWeights[b] > attrWeights[a] + 1e-9) return false;\n            if (bestAttrValue[a] != bestAttrValue[b]) return bestAttrValue[a] > bestAttrValue[b];\n            return a < b;\n        });\n\n        vector<int> selectedIndices;\n        selectedIndices.reserve(selectCount);\n        vector<char> used(seedCount, false);\n\n        for (int l = 0; l < M; ++l) {\n            int idx = bestAttrIndex[l];\n            if (idx >= 0 && !used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n\n        int extraPerAttr = (gapFactor >= 0.65 ? 3 : 2);\n        for (int attrIdx : attrImportance) {\n            if ((int)selectedIndices.size() >= selectCount) break;\n            if (!attrConsider[attrIdx] && attrWeights[attrIdx] < 0.05) continue;\n            int added = 0;\n            for (int seedIdx : attrOrder[attrIdx]) {\n                if ((int)selectedIndices.size() >= selectCount) break;\n                if (used[seedIdx]) continue;\n                if (attrConsider[attrIdx]) {\n                    int thr = coverageThreshold[attrIdx];\n                    if (seeds[seedIdx].attr[attrIdx] + 2 < thr) break;\n                }\n                used[seedIdx] = true;\n                selectedIndices.push_back(seedIdx);\n                ++added;\n                if (added >= extraPerAttr) break;\n            }\n        }\n\n        iota(orderIndices.begin(), orderIndices.end(), 0);\n        sort(orderIndices.begin(), orderIndices.end(), [&](int a, int b) {\n            if (combinedScore[a] > combinedScore[b] + 1e-9) return true;\n            if (combinedScore[b] > combinedScore[a] + 1e-9) return false;\n            if (seedChampionCount[a] != seedChampionCount[b]) return seedChampionCount[a] > seedChampionCount[b];\n            if (attrCoverage[a] != attrCoverage[b]) return attrCoverage[a] > attrCoverage[b];\n            if (nearBestCount[a] != nearBestCount[b]) return nearBestCount[a] > nearBestCount[b];\n            if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n            return a < b;\n        });\n        for (int idx : orderIndices) {\n            if ((int)selectedIndices.size() >= selectCount) break;\n            if (!used[idx]) {\n                used[idx] = true;\n                selectedIndices.push_back(idx);\n            }\n        }\n        if ((int)selectedIndices.size() < selectCount) {\n            for (int idx = 0; idx < seedCount && (int)selectedIndices.size() < selectCount; ++idx) {\n                if (!used[idx]) {\n                    used[idx] = true;\n                    selectedIndices.push_back(idx);\n                }\n            }\n        }\n\n        vector<int> selectedValues(selectCount);\n        vector<int> selectedAttrCount(selectCount);\n        vector<int> selectedCoverage(selectCount);\n        vector<int> selectedNearCount(selectCount);\n        for (int i = 0; i < selectCount; ++i) {\n            int idx = selectedIndices[i];\n            selectedValues[i] = seeds[idx].value;\n            selectedAttrCount[i] = seedChampionCount[idx];\n            selectedCoverage[i] = attrCoverage[idx];\n            selectedNearCount[i] = nearBestCount[idx];\n        }\n\n        vector<int> targetsLocal = targets;\n        vector<double> weightsLocal = weights;\n        vector<double> probWeightsLocal = probWeights;\n\n        vector<int> attrTargetsLocal = attrTargets;\n        vector<double> attrWeightsLocal = attrWeights;\n\n        double attrComponentScaleLocal = attrComponentScale;\n\n        int S = selectCount;\n        vector<double> pairScore((size_t)S * S, 0.0);\n        for (int i = 0; i < S; ++i) {\n            pairScore[i * S + i] = 0.0;\n            for (int j = i + 1; j < S; ++j) {\n                double val = computePairScore(seeds[selectedIndices[i]],\n                                              seeds[selectedIndices[j]],\n                                              targetsLocal, weightsLocal, probWeightsLocal,\n                                              M, bestValue, potentialWeight,\n                                              attrTargetsLocal, attrWeightsLocal, attrComponentScaleLocal);\n                pairScore[i * S + j] = val;\n                pairScore[j * S + i] = val;\n            }\n        }\n\n        auto makeOrder = [&](auto comparator) {\n            vector<int> ord(S);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), comparator);\n            return ord;\n        };\n\n        auto cmpChampion = [&](int a, int b) {\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            if (selectedNearCount[a] != selectedNearCount[b]) return selectedNearCount[a] > selectedNearCount[b];\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n        auto cmpCoverage = [&](int a, int b) {\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedNearCount[a] != selectedNearCount[b]) return selectedNearCount[a] > selectedNearCount[b];\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n        auto cmpValue = [&](int a, int b) {\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            if (selectedAttrCount[a] != selectedAttrCount[b]) return selectedAttrCount[a] > selectedAttrCount[b];\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            if (selectedNearCount[a] != selectedNearCount[b]) return selectedNearCount[a] > selectedNearCount[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n        vector<double> hybridScore(selectCount);\n        for (int i = 0; i < selectCount; ++i) {\n            hybridScore[i] = selectedValues[i] * 1.0 +\n                             selectedCoverage[i] * 6.5 +\n                             selectedAttrCount[i] * 220.0 +\n                             selectedNearCount[i] * 18.0;\n        }\n        auto cmpHybrid = [&](int a, int b) {\n            if (hybridScore[a] > hybridScore[b] + 1e-9) return true;\n            if (hybridScore[b] > hybridScore[a] + 1e-9) return false;\n            if (selectedValues[a] != selectedValues[b]) return selectedValues[a] > selectedValues[b];\n            if (selectedCoverage[a] != selectedCoverage[b]) return selectedCoverage[a] > selectedCoverage[b];\n            return selectedIndices[a] < selectedIndices[b];\n        };\n\n        vector<int> orderChampion = makeOrder(cmpChampion);\n        vector<int> orderHybrid = makeOrder(cmpHybrid);\n        vector<int> orderCoverage = makeOrder(cmpCoverage);\n        vector<int> orderValue = makeOrder(cmpValue);\n        vector<int> orderRandom(selectCount);\n        iota(orderRandom.begin(), orderRandom.end(), 0);\n        shuffle(orderRandom.begin(), orderRandom.end(), rng);\n        vector<int> orderRandom2 = orderRandom;\n        shuffle(orderRandom2.begin(), orderRandom2.end(), rng);\n\n        vector<vector<int>> seedOrders;\n        seedOrders.reserve(6);\n        seedOrders.push_back(orderChampion);\n        seedOrders.push_back(orderHybrid);\n        seedOrders.push_back(orderCoverage);\n        seedOrders.push_back(orderValue);\n        seedOrders.push_back(orderRandom);\n        seedOrders.push_back(orderRandom2);\n\n        vector<vector<int>> cellOrders = {positionOrder, positionOrderReverse, positionOrderRow};\n\n        const int MAX_INITIAL = 8;\n        vector<pair<int, int>> comboPriority = {\n            {0, 0}, {1, 0}, {2, 0}, {3, 0},\n            {0, 1}, {1, 2}, {2, 1}, {3, 2},\n            {4, 0}, {5, 0}, {4, 1}, {5, 1}\n        };\n\n        vector<vector<int>> initialAssignments;\n        for (auto [si, ci] : comboPriority) {\n            if ((int)initialAssignments.size() >= MAX_INITIAL) break;\n            if (si >= (int)seedOrders.size() || ci >= (int)cellOrders.size()) continue;\n            vector<int> assign(cellCount, -1);\n            const auto& order = seedOrders[si];\n            const auto& placement = cellOrders[ci];\n            for (int idx = 0; idx < cellCount; ++idx) {\n                assign[placement[idx]] = order[idx];\n            }\n            initialAssignments.push_back(assign);\n        }\n        if (initialAssignments.empty()) {\n            vector<int> assign(cellCount, -1);\n            for (int idx = 0; idx < cellCount; ++idx) {\n                assign[positionOrder[idx]] = orderChampion[idx];\n            }\n            initialAssignments.push_back(assign);\n        }\n\n        double degWeight = 0.02 * (0.9 - 0.4 * phase);\n        int initialCount = initialAssignments.size();\n        int totalBudget = (int)(15000 + 6000 * (1.0 - phase));\n        int iterPerInit = max(2000, totalBudget / max(1, initialCount));\n\n        vector<int> bestAssignGlobal;\n        double bestScoreGlobal = -1e100;\n\n        auto runSA = [&](const vector<int>& initialAssign) {\n            vector<int> assign = initialAssign;\n            double edgeScore = 0.0;\n            for (auto [u, v] : edges) {\n                edgeScore += pairScore[assign[u] * S + assign[v]];\n            }\n            double degTerm = 0.0;\n            for (int pos = 0; pos < cellCount; ++pos) {\n                degTerm += cellDegree[pos] * selectedValues[assign[pos]];\n            }\n            double currentScore = edgeScore + degWeight * degTerm;\n            double bestScore = currentScore;\n            vector<int> bestAssign = assign;\n\n            double Tstart = 1.2 * improvementScale + 0.3;\n            double Tend = 0.01;\n            array<pair<int, int>, 32> impacted{};\n\n            for (int iter = 0; iter < iterPerInit; ++iter) {\n                int pos1 = posDist(rng);\n                int pos2 = posDist(rng);\n                if (pos1 == pos2) continue;\n                int seed1 = assign[pos1];\n                int seed2 = assign[pos2];\n                if (seed1 == seed2) continue;\n\n                int cnt = 0;\n                auto addEdgeLocal = [&](int a, int b) {\n                    if (a > b) swap(a, b);\n                    for (int k = 0; k < cnt; ++k) {\n                        if (impacted[k].first == a && impacted[k].second == b) return;\n                    }\n                    impacted[cnt++] = {a, b};\n                };\n                for (int nb : neighbors[pos1]) addEdgeLocal(pos1, nb);\n                for (int nb : neighbors[pos2]) addEdgeLocal(pos2, nb);\n\n                double beforeEdge = 0.0;\n                for (int k = 0; k < cnt; ++k) {\n                    int a = impacted[k].first;\n                    int b = impacted[k].second;\n                    beforeEdge += pairScore[assign[a] * S + assign[b]];\n                }\n\n                double deltaPos = degWeight * (double)(selectedValues[seed2] - selectedValues[seed1]) *\n                                  (cellDegree[pos1] - cellDegree[pos2]);\n\n                swap(assign[pos1], assign[pos2]);\n\n                double afterEdge = 0.0;\n                for (int k = 0; k < cnt; ++k) {\n                    int a = impacted[k].first;\n                    int b = impacted[k].second;\n                    afterEdge += pairScore[assign[a] * S + assign[b]];\n                }\n\n                double delta = (afterEdge - beforeEdge) + deltaPos;\n                double progress = (double)iter / iterPerInit;\n                double temperature = Tstart + (Tend - Tstart) * progress;\n                bool accept = false;\n                if (delta >= 0) {\n                    accept = true;\n                } else if (temperature > 0) {\n                    double prob = exp(delta / temperature);\n                    if (realDist(rng) < prob) accept = true;\n                }\n                if (accept) {\n                    currentScore += delta;\n                    if (currentScore > bestScore) {\n                        bestScore = currentScore;\n                        bestAssign = assign;\n                    }\n                } else {\n                    swap(assign[pos1], assign[pos2]);\n                }\n            }\n\n            if (bestScore > bestScoreGlobal) {\n                bestScoreGlobal = bestScore;\n                bestAssignGlobal = bestAssign;\n            }\n        };\n\n        for (const auto& initAssign : initialAssignments) {\n            runSA(initAssign);\n        }\n\n        if (bestAssignGlobal.empty()) bestAssignGlobal = initialAssignments[0];\n\n        vector<vector<int>> grid(N, vector<int>(N, 0));\n        for (int pos = 0; pos < cellCount; ++pos) {\n            int r = pos / N;\n            int c = pos % N;\n            grid[r][c] = selectedIndices[bestAssignGlobal[pos]];\n        }\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (j) cout << ' ';\n                cout << grid[i][j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        if (turn + 1 == T) break;\n        for (int i = 0; i < seedCount; ++i) {\n            int sum = 0;\n            for (int j = 0; j < M; ++j) {\n                int val;\n                cin >> val;\n                seeds[i].attr[j] = val;\n                sum += val;\n            }\n            seeds[i].value = sum;\n        }\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Cell {\n    int x, y;\n};\n\n// Hungarian algorithm for assignment (minimization)\nvector<int> hungarian(const vector<vector<int>>& a) {\n    int n = (int)a.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        vector<int> minv(n + 1, INF);\n        vector<char> used(n + 1, false);\n        int j0 = 0;\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 = a[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= n; ++j) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    v[j] -= delta;\n                } else {\n                    minv[j] -= delta;\n                }\n            }\n            j0 = j1;\n        } while (p[j0] != 0);\n        do {\n            int j1 = way[j0];\n            p[j0] = p[j1];\n            j0 = j1;\n        } while (j0);\n    }\n    vector<int> match(n, -1);\n    for (int j = 1; j <= n; ++j)\n        if (p[j] != 0) match[p[j] - 1] = j - 1;\n    return match;\n}\n\n// Hilbert order helper\nuint64_t hilbertOrder(int x, int y, int pow2) {\n    uint64_t d = 0;\n    for (int s = pow2 / 2; s > 0; s >>= 1) {\n        int rx = (x & s) ? 1 : 0;\n        int ry = (y & s) ? 1 : 0;\n        d += (uint64_t)s * s * ((3 * rx) ^ ry);\n        if (ry == 0) {\n            if (rx == 1) {\n                x = pow2 - 1 - x;\n                y = pow2 - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n    return d;\n}\n\nll bridging_cost(const vector<int>& ord, const vector<vector<int>>& C) {\n    ll res = 0;\n    for (int i = 1; i < (int)ord.size(); ++i)\n        res += C[ord[i - 1]][ord[i]];\n    return res;\n}\n\n// relocate single vertex anywhere\nvector<int> relocate_full(vector<int> ord, const vector<vector<int>>& C) {\n    int n = ord.size();\n    if (n <= 2) return ord;\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        n = ord.size();\n        for (int i = 0; i < n; ++i) {\n            int node = ord[i];\n            int left = (i > 0) ? ord[i - 1] : -1;\n            int right = (i + 1 < n) ? ord[i + 1] : -1;\n            ll removal = 0;\n            if (left != -1) removal -= C[left][node];\n            if (right != -1) removal -= C[node][right];\n            if (left != -1 && right != -1) removal += C[left][right];\n            int newSize = n - 1;\n            int bestPos = -1;\n            ll bestDelta = 0;\n            for (int pos = 0; pos <= newSize; ++pos) {\n                if (pos == i) continue;\n                int prev = -1;\n                if (pos > 0) {\n                    int idx = pos - 1;\n                    prev = (idx < i) ? ord[idx] : ord[idx + 1];\n                }\n                int next = -1;\n                if (pos < newSize) {\n                    int idx = pos;\n                    next = (idx < i) ? ord[idx] : ord[idx + 1];\n                }\n                ll delta = removal;\n                if (prev != -1) delta += C[prev][node];\n                if (next != -1) delta += C[node][next];\n                if (prev != -1 && next != -1) delta -= C[prev][next];\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPos = pos;\n                }\n            }\n            if (bestPos != -1) {\n                int val = ord[i];\n                ord.erase(ord.begin() + i);\n                ord.insert(ord.begin() + bestPos, val);\n                improved = true;\n                break;\n            }\n        }\n    }\n    return ord;\n}\n\n// or-opt of segment length len\nvector<int> or_opt_segment(vector<int> ord, const vector<vector<int>>& C, int len) {\n    int n = ord.size();\n    if (n <= len) return ord;\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int i = 0; i + len <= n; ++i) {\n            int first = ord[i], last = ord[i + len - 1];\n            int left = (i > 0) ? ord[i - 1] : -1;\n            int right = (i + len < n) ? ord[i + len] : -1;\n            ll removal = 0;\n            if (left != -1) removal -= C[left][first];\n            if (right != -1) removal -= C[last][right];\n            if (left != -1 && right != -1) removal += C[left][right];\n            vector<int> rest;\n            rest.reserve(n - len);\n            for (int k = 0; k < i; ++k) rest.push_back(ord[k]);\n            for (int k = i + len; k < n; ++k) rest.push_back(ord[k]);\n            int m = rest.size();\n            int bestPos = -1;\n            ll bestDelta = 0;\n            for (int pos = 0; pos <= m; ++pos) {\n                int prev = (pos == 0) ? -1 : rest[pos - 1];\n                int next = (pos == m) ? -1 : rest[pos];\n                ll delta = removal;\n                if (prev != -1) delta += C[prev][first];\n                if (next != -1) delta += C[last][next];\n                if (prev != -1 && next != -1) delta -= C[prev][next];\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPos = pos;\n                }\n            }\n            if (bestPos != -1) {\n                vector<int> newOrd = rest;\n                newOrd.insert(newOrd.begin() + bestPos, ord.begin() + i, ord.begin() + i + len);\n                ord.swap(newOrd);\n                improved = true;\n                break;\n            }\n        }\n    }\n    return ord;\n}\n\n// 2-opt reversal\nvector<int> two_opt_full(vector<int> ord, const vector<vector<int>>& C) {\n    int n = ord.size();\n    if (n <= 2) return ord;\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int l = 0; l < n - 1; ++l) {\n            for (int r = l + 1; r < n; ++r) {\n                ll before = 0;\n                if (l > 0) before += C[ord[l - 1]][ord[l]];\n                for (int k = l + 1; k <= r; ++k)\n                    before += C[ord[k - 1]][ord[k]];\n                if (r + 1 < n) before += C[ord[r]][ord[r + 1]];\n                ll after = 0;\n                if (l > 0) after += C[ord[l - 1]][ord[r]];\n                for (int k = r; k > l; --k)\n                    after += C[ord[k]][ord[k - 1]];\n                if (r + 1 < n) after += C[ord[l]][ord[r + 1]];\n                if (after < before) {\n                    reverse(ord.begin() + l, ord.begin() + r + 1);\n                    improved = true;\n                    break;\n                }\n            }\n            if (improved) break;\n        }\n    }\n    return ord;\n}\n\n// pairwise swap local search\nvector<int> swap_full(vector<int> ord, const vector<vector<int>>& C) {\n    int n = ord.size();\n    if (n <= 2) return ord;\n    auto edgeCost = [&](const vector<int>& arr, int pos) -> ll {\n        if (pos <= 0 || pos >= (int)arr.size()) return 0;\n        return C[arr[pos - 1]][arr[pos]];\n    };\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int i = 0; i < n - 1 && !improved; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                vector<int> idxs = {i, i + 1, j, j + 1};\n                sort(idxs.begin(), idxs.end());\n                idxs.erase(unique(idxs.begin(), idxs.end()), idxs.end());\n                ll before = 0, after = 0;\n                for (int pos : idxs) before += edgeCost(ord, pos);\n                swap(ord[i], ord[j]);\n                for (int pos : idxs) after += edgeCost(ord, pos);\n                if (after < before) {\n                    improved = true;\n                    break;\n                } else swap(ord[i], ord[j]);\n            }\n        }\n    }\n    return ord;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    int N, M, V;\n    if (!(cin >> N >> M >> V)) return 0;\n    vector<string> s(N), t(N);\n    for (int i = 0; i < N; ++i) cin >> s[i];\n    for (int i = 0; i < N; ++i) cin >> t[i];\n\n    vector<vector<int>> occ(N, vector<int>(N));\n    vector<Cell> surplus, deficit;\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j) {\n            occ[i][j] = s[i][j] - '0';\n            int ti = t[i][j] - '0';\n            if (occ[i][j] == 1 && ti == 0) surplus.push_back({i, j});\n            else if (occ[i][j] == 0 && ti == 1) deficit.push_back({i, j});\n        }\n\n    int K = surplus.size();\n    vector<int> match;\n    if (K > 0) {\n        vector<vector<int>> cost(K, vector<int>(K));\n        for (int i = 0; i < K; ++i)\n            for (int j = 0; j < K; ++j)\n                cost[i][j] = abs(surplus[i].x - deficit[j].x) +\n                             abs(surplus[i].y - deficit[j].y);\n        match = hungarian(cost);\n    }\n\n    vector<int> pickX(K), pickY(K), dropX(K), dropY(K);\n    for (int i = 0; i < K; ++i) {\n        pickX[i] = surplus[i].x;\n        pickY[i] = surplus[i].y;\n        dropX[i] = deficit[match[i]].x;\n        dropY[i] = deficit[match[i]].y;\n    }\n\n    vector<vector<int>> C(K, vector<int>(K));\n    for (int i = 0; i < K; ++i)\n        for (int j = 0; j < K; ++j)\n            C[i][j] = abs(dropX[i] - pickX[j]) + abs(dropY[i] - pickY[j]);\n\n    vector<vector<int>> candidates;\n    if (K > 0) {\n        vector<int> idx(K);\n        iota(idx.begin(), idx.end(), 0);\n\n        // greedy nearest-neighbor\n        vector<int> greedy;\n        vector<char> used(K, false);\n        pair<int,int> cur = {N / 2, N / 2};\n        for (int iter = 0; iter < K; ++iter) {\n            int best = -1, bestDist = INT_MAX, bestPair = INT_MAX;\n            for (int i = 0; i < K; ++i) if (!used[i]) {\n                int dist = abs(cur.first - pickX[i]) + abs(cur.second - pickY[i]);\n                int pairDist = abs(pickX[i] - dropX[i]) + abs(pickY[i] - dropY[i]);\n                if (dist < bestDist || (dist == bestDist && pairDist < bestPair)) {\n                    best = i;\n                    bestDist = dist;\n                    bestPair = pairDist;\n                }\n            }\n            used[best] = true;\n            greedy.push_back(best);\n            cur = {dropX[best], dropY[best]};\n        }\n        candidates.push_back(greedy);\n\n        int pow2 = 1;\n        while (pow2 < max(N, 1)) pow2 <<= 1;\n\n        vector<uint64_t> hilb(K);\n        for (int i = 0; i < K; ++i) hilb[i] = hilbertOrder(pickX[i], pickY[i], pow2);\n        vector<int> hilbertPick = idx;\n        sort(hilbertPick.begin(), hilbertPick.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            if (pickX[a] != pickX[b]) return pickX[a] < pickX[b];\n            return pickY[a] < pickY[b];\n        });\n        candidates.push_back(hilbertPick);\n\n        vector<uint64_t> hilbDrop(K);\n        for (int i = 0; i < K; ++i) hilbDrop[i] = hilbertOrder(dropX[i], dropY[i], pow2);\n        vector<int> hilbertDrop = idx;\n        sort(hilbertDrop.begin(), hilbertDrop.end(), [&](int a, int b) {\n            if (hilbDrop[a] != hilbDrop[b]) return hilbDrop[a] < hilbDrop[b];\n            if (dropX[a] != dropX[b]) return dropX[a] < dropX[b];\n            return dropY[a] < dropY[b];\n        });\n        candidates.push_back(hilbertDrop);\n\n        vector<int> rowIdx = idx;\n        sort(rowIdx.begin(), rowIdx.end(), [&](int a, int b) {\n            if (pickX[a] != pickX[b]) return pickX[a] < pickX[b];\n            return pickY[a] < pickY[b];\n        });\n        candidates.push_back(rowIdx);\n\n        vector<int> rndIdx = idx;\n        mt19937 rng(1234567);\n        shuffle(rndIdx.begin(), rndIdx.end(), rng);\n        candidates.push_back(rndIdx);\n    }\n\n    vector<int> bestOrder;\n    ll bestScore = (1LL << 60);\n    if (K > 0) {\n        for (auto cand : candidates) {\n            cand = relocate_full(cand, C);\n            cand = or_opt_segment(cand, C, 2);\n            cand = or_opt_segment(cand, C, 3);\n            cand = or_opt_segment(cand, C, 4);\n            cand = two_opt_full(cand, C);\n            cand = swap_full(cand, C);\n            ll cost = bridging_cost(cand, C);\n            if (bestOrder.empty() || cost < bestScore) {\n                bestScore = cost;\n                bestOrder = cand;\n            }\n        }\n        if (bestOrder.empty()) {\n            bestOrder.resize(K);\n            iota(bestOrder.begin(), bestOrder.end(), 0);\n        }\n    }\n\n    int root_x = (K > 0) ? pickX[bestOrder[0]] : 0;\n    int root_y = (K > 0) ? pickY[bestOrder[0]] : 0;\n\n    cout << 1 << '\\n';\n    cout << root_x << ' ' << root_y << '\\n';\n    if (K == 0) return 0;\n\n    const int LIMIT = 100000;\n    vector<string> ops;\n    ops.reserve(2 * K);\n    bool limitReached = false;\n    int rx = root_x, ry = root_y;\n    bool holding = false;\n\n    auto emit = [&](char moveChar, char actionChar) -> bool {\n        if ((int)ops.size() >= LIMIT) {\n            limitReached = true;\n            return false;\n        }\n        string op(2, '.');\n        op[0] = moveChar;\n        op[1] = actionChar;\n        ops.push_back(op);\n        if (moveChar == 'U') --rx;\n        else if (moveChar == 'D') ++rx;\n        else if (moveChar == 'L') --ry;\n        else if (moveChar == 'R') ++ry;\n        return true;\n    };\n\n    auto move_with_action = [&](int tx, int ty, bool doAction, bool isPick) {\n        if (limitReached) return;\n        vector<char> path;\n        int cx = rx, cy = ry;\n        while (cx < tx) { path.push_back('D'); ++cx; }\n        while (cx > tx) { path.push_back('U'); --cx; }\n        while (cy < ty) { path.push_back('R'); ++cy; }\n        while (cy > ty) { path.push_back('L'); --cy; }\n        if (path.empty()) {\n            if (doAction) emit('.', 'P');\n        } else {\n            for (size_t i = 0; i < path.size(); ++i) {\n                char act = (doAction && i + 1 == path.size()) ? 'P' : '.';\n                if (!emit(path[i], act)) return;\n            }\n        }\n        if (doAction && !limitReached) {\n            if (isPick) {\n                if (!holding && occ[tx][ty] == 1) {\n                    occ[tx][ty] = 0;\n                    holding = true;\n                }\n            } else {\n                if (holding && occ[tx][ty] == 0) {\n                    occ[tx][ty] = 1;\n                    holding = false;\n                }\n            }\n        }\n    };\n\n    for (int idx : bestOrder) {\n        move_with_action(pickX[idx], pickY[idx], true, true);\n        if (limitReached) break;\n        move_with_action(dropX[idx], dropY[idx], true, false);\n        if (limitReached) break;\n    }\n\n    for (const string& line : ops) cout << line << '\\n';\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAX_COORD = 100000;\nconst int NEG_INF = -1000000000;\nconstexpr double TIME_LIMIT = 1.92;\nconst long long MAX_PERIM = 400000;\n\nstruct Score {\n    int diff;\n    int m;\n    int s;\n};\n\nstruct RectAns {\n    int x1 = 0, x2 = 0, y1 = 0, y2 = 0;\n    Score sc{NEG_INF, 0, 0};\n};\n\nstruct ShapeAns {\n    vector<pair<int,int>> poly;\n    Score sc{NEG_INF, 0, 0};\n    long long area2 = 0;\n    long long perim = 0;\n};\n\nstruct BIT2D {\n    int n = 0;\n    vector<int> xs_sorted;\n    vector<vector<int>> ys;\n    vector<vector<int>> bitM, bitS;\n\n    void build(const vector<int>& px, const vector<int>& py, const vector<int>& type) {\n        xs_sorted = px;\n        sort(xs_sorted.begin(), xs_sorted.end());\n        xs_sorted.erase(unique(xs_sorted.begin(), xs_sorted.end()), xs_sorted.end());\n        n = xs_sorted.size();\n        ys.assign(n + 1, {});\n        for (size_t idx = 0; idx < px.size(); ++idx) {\n            int xi = lower_bound(xs_sorted.begin(), xs_sorted.end(), px[idx]) - xs_sorted.begin() + 1;\n            for (int i = xi; i <= n; i += i & -i) ys[i].push_back(py[idx]);\n        }\n        bitM.assign(n + 1, {});\n        bitS.assign(n + 1, {});\n        for (int i = 1; i <= n; ++i) {\n            auto &vec = ys[i];\n            sort(vec.begin(), vec.end());\n            vec.erase(unique(vec.begin(), vec.end()), vec.end());\n            bitM[i].assign(vec.size() + 1, 0);\n            bitS[i].assign(vec.size() + 1, 0);\n        }\n        for (size_t idx = 0; idx < px.size(); ++idx) {\n            int xi = lower_bound(xs_sorted.begin(), xs_sorted.end(), px[idx]) - xs_sorted.begin() + 1;\n            int y = py[idx];\n            int addM = type[idx] == 1 ? 1 : 0;\n            int addS = type[idx] == -1 ? 1 : 0;\n            for (int i = xi; i <= n; i += i & -i) {\n                if (ys[i].empty()) continue;\n                int yi = lower_bound(ys[i].begin(), ys[i].end(), y) - ys[i].begin() + 1;\n                if (addM) {\n                    for (int j = yi; j < (int)bitM[i].size(); j += j & -j) bitM[i][j] += addM;\n                }\n                if (addS) {\n                    for (int j = yi; j < (int)bitS[i].size(); j += j & -j) bitS[i][j] += addS;\n                }\n            }\n        }\n    }\n\n    pair<int,int> prefix(int xVal, int yVal) const {\n        if (n == 0) return {0,0};\n        int xi = upper_bound(xs_sorted.begin(), xs_sorted.end(), xVal) - xs_sorted.begin();\n        int sumM = 0, sumS = 0;\n        for (int i = xi; i > 0; i -= i & -i) {\n            const auto &vec = ys[i];\n            if (vec.empty()) continue;\n            int yi = upper_bound(vec.begin(), vec.end(), yVal) - vec.begin();\n            for (int j = yi; j > 0; j -= j & -j) {\n                sumM += bitM[i][j];\n                sumS += bitS[i][j];\n            }\n        }\n        return {sumM, sumS};\n    }\n};\n\nBIT2D bit2d;\nint N;\nvector<int> xs, ys, types;\nvector<pair<int,int>> m_coords;\nvector<int> unique_x_vals, unique_y_vals;\nRectAns best_rect;\nvector<RectAns> top_rects;\nconst int TOP_LIMIT = 24;\nShapeAns best_shape;\n\nmt19937 rng(chrono::steady_clock::now().time_since_epoch().count());\nchrono::steady_clock::time_point start_time;\n\ninline double elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n}\n\ninline bool normalize_rect(int &x1, int &x2, int &y1, int &y2) {\n    if (x1 > x2) swap(x1, x2);\n    if (y1 > y2) swap(y1, y2);\n    x1 = clamp(x1, 0, MAX_COORD);\n    x2 = clamp(x2, 0, MAX_COORD);\n    y1 = clamp(y1, 0, MAX_COORD);\n    y2 = clamp(y2, 0, MAX_COORD);\n    if (x1 == x2) {\n        if (x2 < MAX_COORD) ++x2;\n        else if (x1 > 0) --x1;\n    }\n    if (y1 == y2) {\n        if (y2 < MAX_COORD) ++y2;\n        else if (y1 > 0) --y1;\n    }\n    return x1 != x2 && y1 != y2;\n}\n\ninline long long rect_area(int x1, int x2, int y1, int y2) {\n    return 1LL * (x2 - x1) * (y2 - y1);\n}\n\nbool better_rect(const RectAns &a, const RectAns &b) {\n    if (b.sc.diff == NEG_INF) return true;\n    if (a.sc.diff != b.sc.diff) return a.sc.diff > b.sc.diff;\n    if (a.sc.m != b.sc.m) return a.sc.m > b.sc.m;\n    if (a.sc.s != b.sc.s) return a.sc.s < b.sc.s;\n    return rect_area(a.x1,a.x2,a.y1,a.y2) < rect_area(b.x1,b.x2,b.y1,b.y2);\n}\n\nScore compute_score(int x1, int x2, int y1, int y2) {\n    auto A = bit2d.prefix(x2, y2);\n    auto B = bit2d.prefix(x1 - 1, y2);\n    auto C = bit2d.prefix(x2, y1 - 1);\n    auto D = bit2d.prefix(x1 - 1, y1 - 1);\n    int m = A.first - B.first - C.first + D.first;\n    int s = A.second - B.second - C.second + D.second;\n    return {m - s, m, s};\n}\n\nvoid push_candidate(const RectAns &cand) {\n    if (better_rect(cand, best_rect)) best_rect = cand;\n    for (auto &r : top_rects) {\n        if (r.x1 == cand.x1 && r.x2 == cand.x2 && r.y1 == cand.y1 && r.y2 == cand.y2) {\n            if (better_rect(cand, r)) r = cand;\n            return;\n        }\n    }\n    auto it = top_rects.begin();\n    while (it != top_rects.end() && !better_rect(cand, *it)) ++it;\n    top_rects.insert(it, cand);\n    if ((int)top_rects.size() > TOP_LIMIT) top_rects.pop_back();\n}\n\nvoid consider_rect(int x1, int x2, int y1, int y2) {\n    if (!normalize_rect(x1,x2,y1,y2)) return;\n    Score sc = compute_score(x1,x2,y1,y2);\n    RectAns cand{x1,x2,y1,y2,sc};\n    push_candidate(cand);\n}\n\nlong long polygon_area2(const vector<pair<int,int>>& poly) {\n    long long area2 = 0;\n    int m = poly.size();\n    for (int i = 0; i < m; ++i) {\n        const auto &a = poly[i];\n        const auto &b = poly[(i + 1) % m];\n        area2 += 1LL * a.first * b.second - 1LL * a.second * b.first;\n    }\n    return llabs(area2);\n}\n\nlong long polygon_perimeter(const vector<pair<int,int>>& poly) {\n    long long perim = 0;\n    int m = poly.size();\n    for (int i = 0; i < m; ++i) {\n        const auto &a = poly[i];\n        const auto &b = poly[(i + 1) % m];\n        perim += llabs(a.first - b.first) + llabs(a.second - b.second);\n    }\n    return perim;\n}\n\nbool point_on_segment(int x1,int y1,int x2,int y2,int px,int py){\n    if (x1==x2 && px==x1) {\n        return min(y1,y2)<=py && py<=max(y1,y2);\n    }\n    if (y1==y2 && py==y1) {\n        return min(x1,x2)<=px && px<=max(x1,x2);\n    }\n    return false;\n}\n\nbool point_in_poly_axis(const vector<pair<int,int>>& poly, int x, int y) {\n    bool inside = false;\n    int m = poly.size();\n    for (int i = 0; i < m; ++i) {\n        const auto &a = poly[i];\n        const auto &b = poly[(i + 1) % m];\n        if (point_on_segment(a.first,a.second,b.first,b.second,x,y)) return true;\n        bool cond = ((a.second > y) != (b.second > y));\n        if (cond) {\n            long double atX = (long double)(b.first - a.first) * (y - a.second) / (b.second - a.second) + a.first;\n            if ((long double)x < atX) inside = !inside;\n        }\n    }\n    return inside;\n}\n\nScore evaluate_polygon_points(const vector<pair<int,int>>& poly) {\n    if (poly.size() < 3) return {NEG_INF,0,0};\n    Score sc{0,0,0};\n    for (size_t i = 0; i < xs.size(); ++i) {\n        int px = xs[i], py = ys[i];\n        if (point_in_poly_axis(poly, px, py)) {\n            sc.diff += types[i];\n            if (types[i] == 1) ++sc.m;\n            else ++sc.s;\n        }\n    }\n    return sc;\n}\n\nbool better_shape(const ShapeAns &a, const ShapeAns &b) {\n    if (b.sc.diff == NEG_INF) return true;\n    if (a.sc.diff!=b.sc.diff) return a.sc.diff>b.sc.diff;\n    if (a.sc.m!=b.sc.m) return a.sc.m>b.sc.m;\n    if (a.sc.s!=b.sc.s) return a.sc.s<b.sc.s;\n    if (a.perim!=b.perim) return a.perim<b.perim;\n    return a.area2<b.area2;\n}\n\nvoid consider_shape(const vector<pair<int,int>>& poly, const Score &sc) {\n    if (sc.diff == NEG_INF || poly.size() < 3) return;\n    long long area2 = polygon_area2(poly);\n    if (area2 <= 0) return;\n    long long perim = polygon_perimeter(poly);\n    if (perim > MAX_PERIM) return;\n    ShapeAns cand{poly, sc, area2, perim};\n    if (better_shape(cand, best_shape)) best_shape = cand;\n}\n\nvoid ensure_shape_from_rect(const RectAns &rect) {\n    if (rect.sc.diff == NEG_INF) return;\n    vector<pair<int,int>> poly;\n    poly.reserve(4);\n    poly.emplace_back(rect.x1, rect.y1);\n    poly.emplace_back(rect.x2, rect.y1);\n    poly.emplace_back(rect.x2, rect.y2);\n    poly.emplace_back(rect.x1, rect.y2);\n    consider_shape(poly, rect.sc);\n}\n\n// Helper candidate generation\nvector<int> gather_candidates(const vector<int>& coords, int low, int high, int current) {\n    vector<int> cand;\n    if (low > high) return cand;\n    auto clampv = [&](int v) { return clamp(v, low, high); };\n    static const int OFFSETS[] = {-20000,-10000,-5000,-2500,-1200,-600,-300,-150,-70,-30,-12,-5,0,\n                                  5,12,30,70,150,300,600,1200,2500,5000,10000,20000};\n    cand.reserve(150);\n    cand.push_back(clampv(current));\n    for (int off : OFFSETS) cand.push_back(clampv(current + off));\n    cand.push_back(low);\n    cand.push_back(high);\n    if (!coords.empty()) {\n        auto itL = lower_bound(coords.begin(), coords.end(), low);\n        auto itR = upper_bound(coords.begin(), coords.end(), high);\n        int len = itR - itL;\n        if (len > 0) {\n            int step = max(1, len / 18);\n            for (int idx = 0; idx < len && (int)cand.size() < 160; idx += step)\n                cand.push_back(*(itL + idx));\n            int random_samples = min(15, len);\n            for (int i = 0; i < random_samples; ++i)\n                cand.push_back(*(itL + (rng() % len)));\n        }\n    }\n    if (high - low >= 1) {\n        for (int i = 0; i < 10; ++i)\n            cand.push_back(low + (int)(rng() % (high - low + 1)));\n    }\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n    const int LIMIT = 80;\n    if ((int)cand.size() > LIMIT) {\n        vector<int> reduced;\n        reduced.reserve(LIMIT);\n        reduced.push_back(cand.front());\n        reduced.push_back(cand.back());\n        int cur = clampv(current);\n        auto it = lower_bound(cand.begin(), cand.end(), cur);\n        int pos = it - cand.begin();\n        for (int k = -4; k <= 4; ++k) {\n            int idx = pos + k;\n            if (idx >= 0 && idx < (int)cand.size())\n                reduced.push_back(cand[idx]);\n        }\n        while ((int)reduced.size() < LIMIT)\n            reduced.push_back(cand[rng() % cand.size()]);\n        sort(reduced.begin(), reduced.end());\n        reduced.erase(unique(reduced.begin(), reduced.end()), reduced.end());\n        if ((int)reduced.size() > LIMIT) reduced.resize(LIMIT);\n        cand.swap(reduced);\n    }\n    return cand;\n}\n\nvector<int> limit_values(vector<int> cand, int limit) {\n    if ((int)cand.size() <= limit) return cand;\n    vector<int> res;\n    int step = max(1, (int)cand.size() / limit);\n    for (int i = 0; i < (int)cand.size() && (int)res.size() < limit; i += step)\n        res.push_back(cand[i]);\n    while ((int)res.size() < limit)\n        res.push_back(cand[rng() % cand.size()]);\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    if ((int)res.size() > limit) {\n        shuffle(res.begin(), res.end(), rng);\n        res.resize(limit);\n        sort(res.begin(), res.end());\n    }\n    return res;\n}\n\nvector<pair<int,int>> build_interval_candidates(const vector<int>& vals, int limit) {\n    vector<pair<int,int>> res;\n    int sz = vals.size();\n    if (sz < 2 || limit <= 0) return res;\n    vector<int> idxs;\n    idxs.push_back(0);\n    if (sz > 1) idxs.push_back(sz - 1);\n    int step = max(1, sz / 6);\n    for (int i = step; i < sz - 1 && (int)idxs.size() < 16; i += step)\n        idxs.push_back(i);\n    sort(idxs.begin(), idxs.end());\n    idxs.erase(unique(idxs.begin(), idxs.end()), idxs.end());\n    auto add_pair = [&](int a, int b) {\n        if (a >= b) return;\n        res.emplace_back(a, b);\n    };\n    for (size_t i = 0; i < idxs.size(); ++i)\n        for (size_t j = i + 1; j < idxs.size(); ++j)\n            add_pair(vals[idxs[i]], vals[idxs[j]]);\n    int tries = 0;\n    while ((int)res.size() < limit && tries < limit * 8) {\n        ++tries;\n        int i = rng() % sz;\n        int j = rng() % sz;\n        if (i == j) continue;\n        if (i > j) swap(i, j);\n        add_pair(vals[i], vals[j]);\n    }\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    if ((int)res.size() > limit) {\n        shuffle(res.begin(), res.end(), rng);\n        res.resize(limit);\n        sort(res.begin(), res.end());\n    }\n    return res;\n}\n\n// Boundary adjustments\nbool adjust_left(RectAns &rect) {\n    int low = 0;\n    int high = rect.x2 - 1;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(unique_x_vals, low, high, rect.x1);\n    RectAns best = rect;\n    bool improved = false;\n    for (int x1 : cand) {\n        if (x1 >= rect.x2) continue;\n        Score sc = compute_score(x1, rect.x2, rect.y1, rect.y2);\n        RectAns candRect{x1, rect.x2, rect.y1, rect.y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect);\n    }\n    return improved;\n}\n\nbool adjust_right(RectAns &rect) {\n    int low = rect.x1 + 1;\n    int high = MAX_COORD;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(unique_x_vals, low, high, rect.x2);\n    RectAns best = rect;\n    bool improved = false;\n    for (int x2 : cand) {\n        if (x2 <= rect.x1) continue;\n        Score sc = compute_score(rect.x1, x2, rect.y1, rect.y2);\n        RectAns candRect{rect.x1, x2, rect.y1, rect.y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect);\n    }\n    return improved;\n}\n\nbool adjust_bottom(RectAns &rect) {\n    int low = 0;\n    int high = rect.y2 - 1;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(unique_y_vals, low, high, rect.y1);\n    RectAns best = rect;\n    bool improved = false;\n    for (int y1 : cand) {\n        if (y1 >= rect.y2) continue;\n        Score sc = compute_score(rect.x1, rect.x2, y1, rect.y2);\n        RectAns candRect{rect.x1, rect.x2, y1, rect.y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect);\n    }\n    return improved;\n}\n\nbool adjust_top(RectAns &rect) {\n    int low = rect.y1 + 1;\n    int high = MAX_COORD;\n    if (low > high) return false;\n    vector<int> cand = gather_candidates(unique_y_vals, low, high, rect.y2);\n    RectAns best = rect;\n    bool improved = false;\n    for (int y2 : cand) {\n        if (y2 <= rect.y1) continue;\n        Score sc = compute_score(rect.x1, rect.x2, rect.y1, y2);\n        RectAns candRect{rect.x1, rect.x2, rect.y1, y2, sc};\n        if (better_rect(candRect, best)) {\n            best = candRect;\n            improved = true;\n        }\n    }\n    if (improved) {\n        rect = best;\n        push_candidate(rect);\n    }\n    return improved;\n}\n\nvoid refine_rectangle(RectAns rect, int cycles) {\n    if (rect.sc.diff == NEG_INF) rect.sc = compute_score(rect.x1, rect.x2, rect.y1, rect.y2);\n    RectAns current = rect;\n    for (int iter = 0; iter < cycles && elapsed() < TIME_LIMIT; ++iter) {\n        bool changed = false;\n        changed |= adjust_left(current);\n        if (elapsed() > TIME_LIMIT) break;\n        changed |= adjust_right(current);\n        if (elapsed() > TIME_LIMIT) break;\n        changed |= adjust_bottom(current);\n        if (elapsed() > TIME_LIMIT) break;\n        changed |= adjust_top(current);\n        if (!changed) break;\n    }\n}\n\nvoid refine_top_rects(int count, int cycles) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min(count, (int)seeds.size());\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        refine_rectangle(seeds[i], cycles);\n    }\n}\n\n// Heuristic rectangle search\nvector<int> build_lines(const vector<int>& coords, int segments) {\n    vector<int> lines;\n    int extras = segments / 3 + 2;\n    lines.reserve(segments + extras + 4);\n    lines.push_back(0);\n    if (!coords.empty()) {\n        int size = coords.size();\n        for (int i = 1; i < segments; ++i) {\n            long long idx = 1LL * size * i / segments;\n            idx = min<long long>(idx, size - 1);\n            lines.push_back(coords[idx]);\n        }\n        uniform_int_distribution<int> dist(0, size - 1);\n        int extra = min(extras, size);\n        for (int i = 0; i < extra; ++i) lines.push_back(coords[dist(rng)]);\n    }\n    lines.push_back(MAX_COORD + 1);\n    sort(lines.begin(), lines.end());\n    lines.erase(unique(lines.begin(), lines.end()), lines.end());\n    if (lines.front() != 0) lines.insert(lines.begin(), 0);\n    if (lines.back() != MAX_COORD + 1) lines.push_back(MAX_COORD + 1);\n    return lines;\n}\n\nvoid grid_search(int segments, const vector<int>& sorted_x, const vector<int>& sorted_y) {\n    if (elapsed() > TIME_LIMIT) return;\n    auto lines_x = build_lines(sorted_x, segments);\n    auto lines_y = build_lines(sorted_y, segments);\n    int W = (int)lines_x.size() - 1;\n    int H = (int)lines_y.size() - 1;\n    if (W <= 0 || H <= 0) return;\n\n    vector<int> grid(W * H, 0);\n    for (size_t i = 0; i < xs.size(); ++i) {\n        int cx = upper_bound(lines_x.begin(), lines_x.end(), xs[i]) - lines_x.begin() - 1;\n        int cy = upper_bound(lines_y.begin(), lines_y.end(), ys[i]) - lines_y.begin() - 1;\n        cx = clamp(cx, 0, W - 1);\n        cy = clamp(cy, 0, H - 1);\n        grid[cy * W + cx] += types[i];\n    }\n\n    vector<int> arr(W, 0);\n    int best_sum = NEG_INF;\n    int best_top = 0, best_bottom = 0, best_left = 0, best_right = 0;\n    for (int top = 0; top < H; ++top) {\n        fill(arr.begin(), arr.end(), 0);\n        for (int bottom = top; bottom < H; ++bottom) {\n            int row_offset = bottom * W;\n            for (int col = 0; col < W; ++col) arr[col] += grid[row_offset + col];\n            int cur = 0, start = 0;\n            for (int col = 0; col < W; ++col) {\n                if (cur <= 0) {\n                    cur = arr[col];\n                    start = col;\n                } else cur += arr[col];\n                if (cur > best_sum) {\n                    best_sum = cur;\n                    best_top = top;\n                    best_bottom = bottom;\n                    best_left = start;\n                    best_right = col;\n                }\n            }\n        }\n    }\n\n    auto convert = [&](int left, int right, int top, int bottom) {\n        int x1 = lines_x[left];\n        int x2 = lines_x[right + 1] - 1;\n        int y1 = lines_y[top];\n        int y2 = lines_y[bottom + 1] - 1;\n        consider_rect(x1, x2, y1, y2);\n    };\n\n    convert(best_left, best_right, best_top, best_bottom);\n\n    array<pair<int,int>,3> top_cells;\n    int filled = 0;\n    for (int idx = 0; idx < H * W; ++idx) {\n        int val = grid[idx];\n        if (filled < 3) top_cells[filled++] = {val, idx};\n        else {\n            int pos = 0;\n            for (int j = 1; j < 3; ++j)\n                if (top_cells[j].first < top_cells[pos].first) pos = j;\n            if (val > top_cells[pos].first) top_cells[pos] = {val, idx};\n        }\n    }\n    for (int i = 0; i < filled; ++i) {\n        int idx = top_cells[i].second;\n        int cy = idx / W;\n        int cx = idx % W;\n        for (int rad = 0; rad <= 1; ++rad) {\n            int left = max(0, cx - rad);\n            int right = min(W - 1, cx + rad);\n            int top = max(0, cy - rad);\n            int bottom = min(H - 1, cy + rad);\n            convert(left, right, top, bottom);\n        }\n    }\n}\n\n// Randomized rectangle sampling\nint sample_half_span() {\n    static const int options[] = {0, 20, 40, 80, 150, 250, 400, 600, 900, 1300, 1800,\n                                  2500, 3400, 4500, 6000, 8000, 10500, 13500, 17000,\n                                  21000, 26000, 32000, 39000, 47000};\n    static const int SZ = sizeof(options)/sizeof(int);\n    int base = options[rng() % SZ];\n    int extra_range = base / 3 + 1;\n    if (base == 0) extra_range = 60;\n    int extra = rng() % extra_range;\n    return base + extra;\n}\n\nint sample_span() {\n    static const pair<int,int> ranges[] = {\n        {1, 400}, {200, 1200}, {800, 3200}, {2000, 7000}, {5000, 15000},\n        {12000, 30000}, {25000, 50000}, {40000, 80000}, {70000, 100000}\n    };\n    static const int SZ = sizeof(ranges)/sizeof(ranges[0]);\n    auto [lo, hi] = ranges[rng() % SZ];\n    hi = min(hi, MAX_COORD);\n    lo = min(lo, hi);\n    int width = lo;\n    if (hi > lo) width += rng() % (hi - lo + 1);\n    return max(1, width);\n}\n\nvoid random_centered(int iterations) {\n    if (m_coords.empty()) return;\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        const auto &p = m_coords[dist(rng)];\n        int dx = sample_half_span();\n        int dy = sample_half_span();\n        consider_rect(p.first - dx, p.first + dx, p.second - dy, p.second + dy);\n    }\n}\n\nvoid random_global(int iterations) {\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int width = sample_span();\n        int height = sample_span();\n        int x1_max = max(0, MAX_COORD - width);\n        int y1_max = max(0, MAX_COORD - height);\n        int x1 = x1_max ? (int)(rng() % (x1_max + 1)) : 0;\n        int y1 = y1_max ? (int)(rng() % (y1_max + 1)) : 0;\n        consider_rect(x1, x1 + width, y1, y1 + height);\n    }\n}\n\nvoid random_pair_rects(int iterations) {\n    if (m_coords.empty()) return;\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        const auto &a = m_coords[dist(rng)];\n        const auto &b = m_coords[dist(rng)];\n        int x1 = min(a.first, b.first) - sample_half_span();\n        int x2 = max(a.first, b.first) + sample_half_span();\n        const auto &c = m_coords[dist(rng)];\n        const auto &d = m_coords[dist(rng)];\n        int y1 = min(c.second, d.second) - sample_half_span();\n        int y2 = max(c.second, d.second) + sample_half_span();\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_cluster_rects(int iterations) {\n    if (m_coords.empty()) return;\n    vector<int> cluster_sizes = {2,3,4,5,7,9,12,16};\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int k = cluster_sizes[rng() % cluster_sizes.size()];\n        k = min(k, (int)m_coords.size());\n        if (k == 0) break;\n        int minx = INT_MAX, miny = INT_MAX;\n        int maxx = INT_MIN, maxy = INT_MIN;\n        for (int j = 0; j < k; ++j) {\n            const auto &p = m_coords[rng() % m_coords.size()];\n            minx = min(minx, p.first);\n            maxx = max(maxx, p.first);\n            miny = min(miny, p.second);\n            maxy = max(maxy, p.second);\n        }\n        int marginx = sample_half_span();\n        int marginy = sample_half_span();\n        consider_rect(minx - marginx, maxx + marginx, miny - marginy, maxy + marginy);\n    }\n}\n\nvoid quantile_rects(int iterations, const vector<int>& sorted_x, const vector<int>& sorted_y) {\n    if (sorted_x.empty() || sorted_y.empty()) return;\n    uniform_int_distribution<int> dist_x(0, (int)sorted_x.size() - 1);\n    uniform_int_distribution<int> dist_y(0, (int)sorted_y.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int li = dist_x(rng);\n        int ri = dist_x(rng);\n        if (li > ri) swap(li, ri);\n        int marginx = sample_half_span() / 2 + rng() % 200;\n        int x1 = sorted_x[li] - marginx;\n        int x2 = sorted_x[ri] + marginx;\n        int lj = dist_y(rng);\n        int rj = dist_y(rng);\n        if (lj > rj) swap(lj, rj);\n        int marginy = sample_half_span() / 2 + rng() % 200;\n        int y1 = sorted_y[lj] - marginy;\n        int y2 = sorted_y[rj] + marginy;\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid slender_rects(int iterations) {\n    if (m_coords.empty()) return;\n    static const int widths[] = {150, 300, 600, 1000, 1600, 2500, 4000, 6000, 9000};\n    static const int SZ = sizeof(widths)/sizeof(widths[0]);\n    uniform_int_distribution<int> dist(0, (int)m_coords.size() - 1);\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        bool vertical = (rng() & 1);\n        const auto &center = m_coords[dist(rng)];\n        int span = widths[rng() % SZ];\n        int half = span / 2;\n        if (vertical) {\n            int x1 = center.first - half;\n            int x2 = center.first + half;\n            int height = sample_span();\n            int y_mid = rng() % (MAX_COORD + 1);\n            int y1 = y_mid - height / 2;\n            int y2 = y1 + height;\n            consider_rect(x1, x2, y1, y2);\n        } else {\n            int y1 = center.second - half;\n            int y2 = center.second + half;\n            int width = sample_span();\n            int x_mid = rng() % (MAX_COORD + 1);\n            int x1 = x_mid - width / 2;\n            int x2 = x1 + width;\n            consider_rect(x1, x2, y1, y2);\n        }\n    }\n}\n\nconst int BIG_PERTURB[] = {5, 15, 30, 60, 120, 250, 400, 700, 1100, 1700,\n                           2500, 3600, 5000, 7500, 10000, 13500, 17000};\nconst int SMALL_PERTURB[] = {2,4,8,16,32,64,128,256,512,1024,2048,3072,4096};\nconst int BIG_PSZ = sizeof(BIG_PERTURB)/sizeof(int);\nconst int SMALL_PSZ = sizeof(SMALL_PERTURB)/sizeof(int);\nconst int LOCAL_STEPS[] = {1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946};\nconst int LOCAL_SZ = sizeof(LOCAL_STEPS)/sizeof(int);\n\nvoid random_perturb_rect(const RectAns &base, int iterations, const int *options, int opt_sz) {\n    if (base.sc.diff == NEG_INF) return;\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int delta = options[rng() % opt_sz];\n        int x1 = base.x1 - (int)(rng() % (delta + 1));\n        int x2 = base.x2 + (int)(rng() % (delta + 1));\n        int y1 = base.y1 - (int)(rng() % (delta + 1));\n        int y2 = base.y2 + (int)(rng() % (delta + 1));\n        int shiftx = delta ? (int)(rng() % (2 * delta + 1)) - delta : 0;\n        int shifty = delta ? (int)(rng() % (2 * delta + 1)) - delta : 0;\n        x1 += shiftx; x2 += shiftx;\n        y1 += shifty; y2 += shifty;\n        if (rng() & 1) x1 += rng() % (delta + 1);\n        if (rng() & 1) x2 -= rng() % (delta + 1);\n        if (rng() & 1) y1 += rng() % (delta + 1);\n        if (rng() & 1) y2 -= rng() % (delta + 1);\n        consider_rect(x1, x2, y1, y2);\n    }\n}\n\nvoid random_perturb_best(int iterations) {\n    random_perturb_rect(best_rect, iterations, BIG_PERTURB, BIG_PSZ);\n}\n\nvoid random_around_top_rects(int iterations_each) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min<int>(seeds.size(), 6);\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        random_perturb_rect(seeds[i], iterations_each, SMALL_PERTURB, SMALL_PSZ);\n    }\n}\n\nvoid local_search_from(const RectAns &seed, int iterations) {\n    if (seed.sc.diff == NEG_INF) return;\n    RectAns current = seed;\n    for (int it = 0; it < iterations && elapsed() < TIME_LIMIT; ++it) {\n        int step = LOCAL_STEPS[rng() % LOCAL_SZ];\n        int op = rng() % 12;\n        int x1 = current.x1;\n        int x2 = current.x2;\n        int y1 = current.y1;\n        int y2 = current.y2;\n        switch (op) {\n            case 0: x1 -= step; break;\n            case 1: x1 += step; break;\n            case 2: x2 += step; break;\n            case 3: x2 -= step; break;\n            case 4: y1 -= step; break;\n            case 5: y1 += step; break;\n            case 6: y2 += step; break;\n            case 7: y2 -= step; break;\n            case 8: { int shift = (int)(rng() % (2 * step + 1)) - step; x1 += shift; x2 += shift; break; }\n            case 9: { int shift = (int)(rng() % (2 * step + 1)) - step; y1 += shift; y2 += shift; break; }\n            case 10: x1 -= step; x2 += step; break;\n            case 11: y1 -= step; y2 += step; break;\n        }\n        if (!normalize_rect(x1,x2,y1,y2)) continue;\n        Score sc = compute_score(x1,x2,y1,y2);\n        RectAns cand{x1,x2,y1,y2,sc};\n        push_candidate(cand);\n        if (better_rect(cand, current)) current = cand;\n        if ((it & 63) == 63 && better_rect(best_rect, current)) current = best_rect;\n    }\n}\n\nvoid run_local_search_pool(int iterations_per_seed) {\n    if (top_rects.empty()) return;\n    vector<RectAns> seeds = top_rects;\n    int limit = min<int>(seeds.size(), 4);\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        local_search_from(seeds[i], iterations_per_seed);\n    }\n}\n\n// Notch generation\nstruct NotchCandidate {\n    int type; // 0 top, 1 bottom, 2 left, 3 right\n    int p1, p2, cut;\n    Score approx;\n};\n\nbool better_score(const Score &a, const Score &b) {\n    if (b.diff == NEG_INF) return true;\n    if (a.diff != b.diff) return a.diff > b.diff;\n    if (a.m != b.m) return a.m > b.m;\n    if (a.s != b.s) return a.s < b.s;\n    return false;\n}\n\nvoid push_notch_candidate(vector<NotchCandidate>& vec, const NotchCandidate& cand, int keep_limit) {\n    auto it = vec.begin();\n    while (it != vec.end() && !better_score(cand.approx, it->approx)) ++it;\n    vec.insert(it, cand);\n    if ((int)vec.size() > keep_limit) vec.pop_back();\n}\n\nvoid collect_top_notches(const RectAns& base, vector<NotchCandidate>& out, int keep_limit, int eval_limit) {\n    if (base.y2 - base.y1 < 2) return;\n    auto candX = limit_values(gather_candidates(unique_x_vals, base.x1 + 1, base.x2 - 1, (base.x1 + base.x2) / 2), 32);\n    auto candY = limit_values(gather_candidates(unique_y_vals, base.y1 + 1, base.y2 - 1, base.y2 - (base.y2 - base.y1) / 4), 20);\n    auto intervals = build_interval_candidates(candX, 40);\n    if (candY.empty() || intervals.empty()) return;\n    vector<NotchCandidate> local;\n    int evals=0;\n    for (auto [lx, rx] : intervals) {\n        if (!(base.x1 < lx && lx < rx && rx < base.x2)) continue;\n        for (int ycut : candY) {\n            if (ycut <= base.y1 || ycut >= base.y2) continue;\n            Score notch = compute_score(lx, rx, ycut, base.y2);\n            Score approx = base.sc;\n            approx.diff -= notch.diff;\n            approx.m -= notch.m;\n            approx.s -= notch.s;\n            NotchCandidate cand{0, lx, rx, ycut, approx};\n            push_notch_candidate(local, cand, keep_limit);\n            if (++evals >= eval_limit) break;\n        }\n        if (evals >= eval_limit) break;\n    }\n    out.insert(out.end(), local.begin(), local.end());\n}\n\nvoid collect_bottom_notches(const RectAns& base, vector<NotchCandidate>& out, int keep_limit, int eval_limit) {\n    if (base.y2 - base.y1 < 2) return;\n    auto candX = limit_values(gather_candidates(unique_x_vals, base.x1 + 1, base.x2 - 1, (base.x1 + base.x2) / 2), 32);\n    auto candY = limit_values(gather_candidates(unique_y_vals, base.y1 + 1, base.y2 - 1, base.y1 + (base.y2 - base.y1) / 4), 20);\n    auto intervals = build_interval_candidates(candX, 40);\n    if (candY.empty() || intervals.empty()) return;\n    vector<NotchCandidate> local;\n    int evals=0;\n    for (auto [lx, rx] : intervals) {\n        if (!(base.x1 < lx && lx < rx && rx < base.x2)) continue;\n        for (int ycut : candY) {\n            if (ycut <= base.y1 || ycut >= base.y2) continue;\n            Score notch = compute_score(lx, rx, base.y1, ycut);\n            Score approx = base.sc;\n            approx.diff -= notch.diff;\n            approx.m -= notch.m;\n            approx.s -= notch.s;\n            NotchCandidate cand{1, lx, rx, ycut, approx};\n            push_notch_candidate(local, cand, keep_limit);\n            if (++evals >= eval_limit) break;\n        }\n        if (evals >= eval_limit) break;\n    }\n    out.insert(out.end(), local.begin(), local.end());\n}\n\nvoid collect_left_notches(const RectAns& base, vector<NotchCandidate>& out, int keep_limit, int eval_limit) {\n    if (base.x2 - base.x1 < 2) return;\n    auto candCut = limit_values(gather_candidates(unique_x_vals, base.x1 + 1, base.x2 - 1, base.x1 + (base.x2 - base.x1) / 4), 32);\n    auto candY = limit_values(gather_candidates(unique_y_vals, base.y1 + 1, base.y2 - 1, (base.y1 + base.y2) / 2), 32);\n    auto intervals = build_interval_candidates(candY, 40);\n    if (candCut.empty() || intervals.empty()) return;\n    vector<NotchCandidate> local;\n    int evals=0;\n    for (int xcut : candCut) {\n        if (xcut <= base.x1 || xcut >= base.x2) continue;\n        for (auto [ly, ry] : intervals) {\n            if (!(base.y1 < ly && ly < ry && ry < base.y2)) continue;\n            Score notch = compute_score(base.x1, xcut, ly, ry);\n            Score approx = base.sc;\n            approx.diff -= notch.diff;\n            approx.m -= notch.m;\n            approx.s -= notch.s;\n            NotchCandidate cand{2, ly, ry, xcut, approx};\n            push_notch_candidate(local, cand, keep_limit);\n            if (++evals >= eval_limit) break;\n        }\n        if (evals >= eval_limit) break;\n    }\n    out.insert(out.end(), local.begin(), local.end());\n}\n\nvoid collect_right_notches(const RectAns& base, vector<NotchCandidate>& out, int keep_limit, int eval_limit) {\n    if (base.x2 - base.x1 < 2) return;\n    auto candCut = limit_values(gather_candidates(unique_x_vals, base.x1 + 1, base.x2 - 1, base.x2 - (base.x2 - base.x1) / 4), 32);\n    auto candY = limit_values(gather_candidates(unique_y_vals, base.y1 + 1, base.y2 - 1, (base.y1 + base.y2) / 2), 32);\n    auto intervals = build_interval_candidates(candY, 40);\n    if (candCut.empty() || intervals.empty()) return;\n    vector<NotchCandidate> local;\n    int evals=0;\n    for (int xcut : candCut) {\n        if (xcut <= base.x1 || xcut >= base.x2) continue;\n        for (auto [ly, ry] : intervals) {\n            if (!(base.y1 < ly && ly < ry && ry < base.y2)) continue;\n            Score notch = compute_score(xcut, base.x2, ly, ry);\n            Score approx = base.sc;\n            approx.diff -= notch.diff;\n            approx.m -= notch.m;\n            approx.s -= notch.s;\n            NotchCandidate cand{3, ly, ry, xcut, approx};\n            push_notch_candidate(local, cand, keep_limit);\n            if (++evals >= eval_limit) break;\n        }\n        if (evals >= eval_limit) break;\n    }\n    out.insert(out.end(), local.begin(), local.end());\n}\n\nvector<pair<int,int>> build_notch_polygon(const RectAns& base, const NotchCandidate& cand) {\n    vector<pair<int,int>> poly;\n    switch (cand.type) {\n        case 0:\n            poly = {\n                {base.x1, base.y1},\n                {base.x2, base.y1},\n                {base.x2, base.y2},\n                {cand.p2, base.y2},\n                {cand.p2, cand.cut},\n                {cand.p1, cand.cut},\n                {cand.p1, base.y2},\n                {base.x1, base.y2}\n            };\n            break;\n        case 1:\n            poly = {\n                {base.x1, base.y1},\n                {cand.p1, base.y1},\n                {cand.p1, cand.cut},\n                {cand.p2, cand.cut},\n                {cand.p2, base.y1},\n                {base.x2, base.y1},\n                {base.x2, base.y2},\n                {base.x1, base.y2}\n            };\n            break;\n        case 2:\n            poly = {\n                {base.x1, base.y1},\n                {base.x2, base.y1},\n                {base.x2, base.y2},\n                {base.x1, base.y2},\n                {base.x1, cand.p2},\n                {cand.cut, cand.p2},\n                {cand.cut, cand.p1},\n                {base.x1, cand.p1}\n            };\n            break;\n        case 3:\n            poly = {\n                {base.x1, base.y1},\n                {base.x2, base.y1},\n                {base.x2, cand.p1},\n                {cand.cut, cand.p1},\n                {cand.cut, cand.p2},\n                {base.x2, cand.p2},\n                {base.x2, base.y2},\n                {base.x1, base.y2}\n            };\n            break;\n    }\n    if (!poly.empty() && poly.front() == poly.back()) poly.pop_back();\n    return poly;\n}\n\nvoid notch_on_rect(const RectAns& base) {\n    if (base.sc.diff == NEG_INF || elapsed() > TIME_LIMIT) return;\n    vector<NotchCandidate> candidates;\n    const int KEEP = 6;\n    const int EVAL_LIMIT = 300;\n    collect_top_notches(base, candidates, KEEP, EVAL_LIMIT);\n    collect_bottom_notches(base, candidates, KEEP, EVAL_LIMIT);\n    collect_left_notches(base, candidates, KEEP, EVAL_LIMIT);\n    collect_right_notches(base, candidates, KEEP, EVAL_LIMIT);\n    for (const auto &cand : candidates) {\n        if (elapsed() > TIME_LIMIT) break;\n        auto poly = build_notch_polygon(base, cand);\n        if (poly.size() < 4) continue;\n        Score sc = evaluate_polygon_points(poly);\n        consider_shape(poly, sc);\n    }\n}\n\nvoid try_notch_improvements() {\n    if (elapsed() > TIME_LIMIT) return;\n    vector<RectAns> seeds = top_rects;\n    if (seeds.empty() && best_rect.sc.diff != NEG_INF) seeds.push_back(best_rect);\n    int limit = min<int>(6, seeds.size());\n    for (int i = 0; i < limit && elapsed() < TIME_LIMIT; ++i) {\n        notch_on_rect(seeds[i]);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    start_time = chrono::steady_clock::now();\n\n    cin >> N;\n    xs.reserve(2 * N);\n    ys.reserve(2 * N);\n    types.reserve(2 * N);\n    m_coords.reserve(N);\n\n    for (int i = 0; i < N; ++i) {\n        int x,y; cin >> x >> y;\n        xs.push_back(x); ys.push_back(y); types.push_back(1);\n        m_coords.emplace_back(x,y);\n    }\n    for (int i = 0; i < N; ++i) {\n        int x,y; cin >> x >> y;\n        xs.push_back(x); ys.push_back(y); types.push_back(-1);\n    }\n\n    vector<int> sorted_x = xs;\n    vector<int> sorted_y = ys;\n    sort(sorted_x.begin(), sorted_x.end());\n    sort(sorted_y.begin(), sorted_y.end());\n    unique_x_vals = sorted_x;\n    unique_y_vals = sorted_y;\n    unique_x_vals.erase(unique(unique_x_vals.begin(), unique_x_vals.end()), unique_x_vals.end());\n    unique_y_vals.erase(unique(unique_y_vals.begin(), unique_y_vals.end()), unique_y_vals.end());\n\n    bit2d.build(xs, ys, types);\n    best_rect.sc.diff = NEG_INF;\n    best_shape.sc.diff = NEG_INF;\n    top_rects.clear();\n\n    consider_rect(0, MAX_COORD, 0, MAX_COORD);\n    int half = MAX_COORD / 2;\n    consider_rect(0, half, 0, half);\n    consider_rect(half, MAX_COORD, 0, half);\n    consider_rect(0, half, half, MAX_COORD);\n    consider_rect(half, MAX_COORD, half, MAX_COORD);\n    consider_rect(MAX_COORD/4, 3*MAX_COORD/4, MAX_COORD/4, 3*MAX_COORD/4);\n\n    vector<int> segments = {12, 18, 26, 35, 48, 64, 85, 110, 140};\n    for (int seg : segments) {\n        if (elapsed() > TIME_LIMIT) break;\n        grid_search(seg, sorted_x, sorted_y);\n    }\n\n    random_centered(2200);\n    random_pair_rects(1800);\n    random_cluster_rects(1200);\n    random_global(1500);\n    quantile_rects(1400, sorted_x, sorted_y);\n    slender_rects(1000);\n    random_centered(600);\n    random_perturb_best(2000);\n    random_around_top_rects(400);\n    run_local_search_pool(360);\n    refine_top_rects(6, 11);\n    random_around_top_rects(250);\n    random_perturb_best(800);\n    run_local_search_pool(240);\n    refine_top_rects(4, 9);\n\n    if (best_rect.sc.diff == NEG_INF) {\n        consider_rect(0, MAX_COORD, 0, MAX_COORD);\n    }\n\n    ensure_shape_from_rect(best_rect);\n    try_notch_improvements();\n    if (best_shape.sc.diff == NEG_INF) ensure_shape_from_rect(best_rect);\n    if (best_shape.sc.diff == NEG_INF) {\n        vector<pair<int,int>> fallback = {{0,0}, {MAX_COORD,0}, {MAX_COORD,MAX_COORD}, {0,MAX_COORD}};\n        Score sc = evaluate_polygon_points(fallback);\n        consider_shape(fallback, sc);\n    }\n\n    cout << best_shape.poly.size() << '\\n';\n    for (const auto &p : best_shape.poly) {\n        cout << p.first << ' ' << p.second << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst long long INFLL = (long long)4e18;\n\nstruct Profile {\n    vector<long long> widths;\n    vector<long long> heights;  // monotone non-increasing\n};\n\nstruct Solution {\n    vector<int> orientation;\n    vector<int> column_id;\n    vector<long long> column_widths;\n    vector<long long> column_heights;\n    vector<int> anchor;\n    vector<int> idx_max_width;\n    vector<pair<int,int>> ranges;\n    long long total_width = 0;\n    long long total_height = 0;\n    long long score = INFLL;\n};\n\nstruct DPState {\n    long long width_sum;\n    long long max_height;\n    int prev_idx;\n    int prev_state;\n    int block_end;\n    int choice_idx;\n    uint32_t tiebreak;\n};\n\nuint64_t hash_solution(const Solution &sol) {\n    uint64_t h = 1469598103934665603ULL;\n    const uint64_t prime = 1099511628211ULL;\n    for (size_t i = 0; i < sol.orientation.size(); ++i) {\n        uint64_t val = (uint64_t)(sol.orientation[i] & 1);\n        val |= (uint64_t)(sol.column_id[i] & 0xFFFF) << 1;\n        h ^= val;\n        h *= prime;\n    }\n    return h;\n}\n\nstruct ColumnPackingSolver {\n    int N = 0;\n    vector<long long> w, h;\n    vector<array<long long,2>> widthOpt, heightOpt;\n    vector<long long> minHeight, maxHeight;\n    long long H_lower = 0;\n    long long H_upper = 0;\n    long long total_min_height = 0;\n    vector<vector<Profile>> profiles;\n\n    void init(const vector<long long>& W, const vector<long long>& H) {\n        w = W; h = H;\n        N = (int)w.size();\n        widthOpt.assign(N, {0,0});\n        heightOpt.assign(N, {0,0});\n        minHeight.resize(N);\n        maxHeight.resize(N);\n        total_min_height = 0;\n        H_lower = 0;\n        H_upper = 0;\n        for (int i = 0; i < N; ++i) {\n            widthOpt[i][0] = w[i];\n            heightOpt[i][0] = h[i];\n            widthOpt[i][1] = h[i];\n            heightOpt[i][1] = w[i];\n            minHeight[i] = min(heightOpt[i][0], heightOpt[i][1]);\n            maxHeight[i] = max(heightOpt[i][0], heightOpt[i][1]);\n            total_min_height += minHeight[i];\n            H_lower = max(H_lower, minHeight[i]);\n            H_upper += maxHeight[i];\n        }\n        if (H_upper < H_lower) H_upper = H_lower;\n        build_profiles();\n    }\n\n    long long lower() const { return H_lower; }\n    long long upper() const { return H_upper; }\n    long long minHeightSum() const { return total_min_height; }\n\n    void build_profiles() {\n        const int PROFILE_LIMIT = 80;\n        profiles.assign(N + 1, vector<Profile>(N + 1));\n        for (int l = 0; l < N; ++l) {\n            for (int r = l + 1; r <= N; ++r) {\n                vector<long long> widths;\n                widths.reserve(2 * (r - l));\n                for (int k = l; k < r; ++k) {\n                    widths.push_back(widthOpt[k][0]);\n                    widths.push_back(widthOpt[k][1]);\n                }\n                sort(widths.begin(), widths.end());\n                widths.erase(unique(widths.begin(), widths.end()), widths.end());\n                vector<long long> heights(widths.size(), INFLL);\n                for (size_t idx = 0; idx < widths.size(); ++idx) {\n                    long long limit = widths[idx];\n                    long long sumH = 0;\n                    bool ok = true;\n                    for (int k = l; k < r; ++k) {\n                        long long best = INFLL;\n                        if (widthOpt[k][0] <= limit) best = min(best, heightOpt[k][0]);\n                        if (widthOpt[k][1] <= limit) best = min(best, heightOpt[k][1]);\n                        if (best >= INFLL/2) { ok = false; break; }\n                        sumH += best;\n                    }\n                    if (ok) heights[idx] = sumH;\n                }\n                long long last = INFLL;\n                for (size_t idx = 0; idx < heights.size(); ++idx) {\n                    if (heights[idx] < last) last = heights[idx];\n                    else heights[idx] = last;\n                }\n                if ((int)widths.size() > PROFILE_LIMIT) {\n                    vector<long long> newW, newH;\n                    newW.reserve(PROFILE_LIMIT);\n                    newH.reserve(PROFILE_LIMIT);\n                    for (int i = 0; i < PROFILE_LIMIT; ++i) {\n                        int idx = (int)llround((long double)i * (widths.size() - 1) / (PROFILE_LIMIT - 1));\n                        newW.push_back(widths[idx]);\n                        newH.push_back(heights[idx]);\n                    }\n                    for (int i = 1; i < (int)newH.size(); ++i)\n                        newH[i] = min(newH[i], newH[i-1]);\n                    widths.swap(newW);\n                    heights.swap(newH);\n                }\n                profiles[l][r] = Profile{move(widths), move(heights)};\n            }\n        }\n    }\n\n    long long min_width_for_height(int l, int r, long long Hmax) const {\n        const Profile &prof = profiles[l][r];\n        if (prof.heights.empty()) return INFLL;\n        const auto &hv = prof.heights;\n        int lo = 0, hi = (int)hv.size();\n        while (lo < hi) {\n            int mid = (lo + hi) / 2;\n            if (hv[mid] <= Hmax) hi = mid;\n            else lo = mid + 1;\n        }\n        if (lo >= (int)hv.size()) return INFLL;\n        return prof.widths[lo];\n    }\n\n    int choose_orientation(int idx, long long width_limit) const {\n        int best = -1;\n        long long best_h = INFLL;\n        long long best_w = INFLL;\n        for (int o = 0; o < 2; ++o) {\n            if (widthOpt[idx][o] <= width_limit) {\n                long long hval = heightOpt[idx][o];\n                long long wval = widthOpt[idx][o];\n                if (best == -1 || hval < best_h || (hval == best_h && wval < best_w)) {\n                    best = o;\n                    best_h = hval;\n                    best_w = wval;\n                }\n            }\n        }\n        if (best == -1) best = (heightOpt[idx][0] <= heightOpt[idx][1]) ? 0 : 1;\n        return best;\n    }\n\n    vector<long long> generate_candidate_heights(mt19937 &rng, int limit) const {\n        limit = max(limit, 2);\n        vector<long long> cand;\n        auto clampH = [&](long long v) {\n            if (v < H_lower) v = H_lower;\n            if (v > H_upper) v = H_upper;\n            return v;\n        };\n        auto add = [&](long long v) {\n            cand.push_back(clampH(v));\n        };\n\n        add(H_lower);\n        add(H_upper);\n        add(total_min_height);\n        add((H_lower + H_upper) / 2);\n\n        vector<double> fudge = {0.65, 0.75, 0.85, 0.95, 1.0, 1.05, 1.15, 1.3, 1.5};\n        int maxCols = min(N, 60);\n        for (int c = 1; c <= maxCols; ++c) {\n            double base = (double)total_min_height / max(1, c);\n            for (double f : fudge) add((long long)llround(base * f));\n        }\n\n        long double val = (long double)H_lower;\n        for (int i = 0; i < 100 && val <= (long double)H_upper; ++i) {\n            add((long long)llround(val));\n            val *= 1.05L;\n            if (val > (long double)H_upper * 1.01L) break;\n        }\n\n        if (H_upper > H_lower) {\n            int linearCnt = min(limit, 200);\n            for (int i = 0; i < linearCnt; ++i) {\n                long double ratio = (long double)i / max(1, linearCnt - 1);\n                add((long long)llround(H_lower + ratio * (H_upper - H_lower)));\n            }\n            uniform_int_distribution<long long> dist(H_lower, H_upper);\n            int randomSamples = min(limit, 200);\n            for (int i = 0; i < randomSamples; ++i) add(dist(rng));\n        }\n\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n        if ((int)cand.size() > limit) {\n            vector<long long> reduced;\n            reduced.reserve(limit);\n            for (int i = 0; i < limit; ++i) {\n                size_t idx = (size_t)llround((long double)i * (cand.size() - 1) / max(1, limit - 1));\n                reduced.push_back(cand[idx]);\n            }\n            sort(reduced.begin(), reduced.end());\n            reduced.erase(unique(reduced.begin(), reduced.end()), reduced.end());\n            cand.swap(reduced);\n        }\n        if (cand.empty()) cand.push_back(H_lower);\n        return cand;\n    }\n\n    bool build_height_solution(long long Hmax, Solution &sol, mt19937 &rng) const {\n        vector<long long> dp(N + 1, INFLL);\n        vector<int> prv(N + 1, -1);\n        vector<long long> width_choice(N + 1, -1);\n        vector<uint32_t> jitter(N + 1);\n        vector<uint32_t> best_jitter(N + 1, UINT_MAX);\n        for (int i = 0; i <= N; ++i) jitter[i] = rng();\n        dp[0] = 0;\n        best_jitter[0] = jitter[0];\n\n        for (int i = 1; i <= N; ++i) {\n            for (int j = 0; j < i; ++j) {\n                if (dp[j] >= INFLL/2) continue;\n                long long width = min_width_for_height(j, i, Hmax);\n                if (width >= INFLL/2) continue;\n                long long cand = dp[j] + width;\n                if (cand < dp[i] || (cand == dp[i] && jitter[j] < best_jitter[i])) {\n                    dp[i] = cand;\n                    prv[i] = j;\n                    width_choice[i] = width;\n                    best_jitter[i] = jitter[j];\n                }\n            }\n        }\n        if (dp[N] >= INFLL/2) return false;\n\n        vector<int> cuts;\n        int cur = N;\n        while (cur > 0) {\n            cuts.push_back(cur);\n            cur = prv[cur];\n            if (cur < 0) return false;\n        }\n        cuts.push_back(0);\n        reverse(cuts.begin(), cuts.end());\n        int cols = (int)cuts.size() - 1;\n\n        sol.orientation.assign(N, 0);\n        sol.column_id.assign(N, 0);\n        sol.column_widths.assign(cols, 0);\n        sol.column_heights.assign(cols, 0);\n        sol.anchor.assign(cols, -1);\n        sol.idx_max_width.assign(cols, -1);\n        sol.ranges.resize(cols);\n\n        for (int c = 0; c < cols; ++c) {\n            int l = cuts[c];\n            int r = cuts[c + 1];\n            long long width_limit = width_choice[r];\n            long long sumH = 0;\n            long long maxW = 0;\n            int idxMax = l;\n            for (int k = l; k < r; ++k) {\n                int orient = choose_orientation(k, width_limit);\n                sol.orientation[k] = orient;\n                sol.column_id[k] = c;\n                long long wval = widthOpt[k][orient];\n                long long hval = heightOpt[k][orient];\n                sumH += hval;\n                if (wval > maxW || (wval == maxW && k < idxMax)) {\n                    maxW = wval;\n                    idxMax = k;\n                }\n            }\n            if (maxW < width_limit) maxW = width_limit;\n            sol.column_widths[c] = maxW;\n            sol.column_heights[c] = sumH;\n            sol.idx_max_width[c] = idxMax;\n            sol.ranges[c] = {l, r};\n            sol.anchor[c] = (c == 0) ? -1 : sol.idx_max_width[c - 1];\n        }\n\n        long long total_w = 0;\n        long long total_h = 0;\n        for (auto wcol : sol.column_widths) total_w += wcol;\n        for (auto hcol : sol.column_heights) total_h = max(total_h, hcol);\n        sol.total_width = total_w;\n        sol.total_height = total_h;\n        sol.score = total_w + total_h;\n        return true;\n    }\n};\n\nbool build_greedy_solution(const ColumnPackingSolver &solver,\n                           long long targetH, double slack,\n                           Solution &sol, mt19937 &rng) {\n    int N = solver.N;\n    if (N == 0) return false;\n    sol.orientation.assign(N, 0);\n    vector<int> column_id(N, 0);\n\n    vector<int> colStart, colEnd, idxMax;\n    vector<long long> colWidth, colHeight;\n\n    int curStart = 0;\n    long long curWidth = 0;\n    long long curHeight = 0;\n    int curIdxMax = 0;\n    int currentColIndex = 0;\n    bool columnInitialized = false;\n\n    auto finalize_col = [&](int endIdx) {\n        if (!columnInitialized || curStart >= endIdx) return;\n        colStart.push_back(curStart);\n        colEnd.push_back(endIdx);\n        colWidth.push_back(curWidth);\n        colHeight.push_back(curHeight);\n        idxMax.push_back(curIdxMax);\n        currentColIndex = colStart.size();\n        columnInitialized = false;\n    };\n\n    uniform_real_distribution<double> noise_dist(0.0, 1.0);\n\n    for (int i = 0; i < N; ++i) {\n        while (true) {\n            long double limit = (targetH <= 0 ? 1e30L : (long double)targetH * slack);\n            struct Choice {\n                int o;\n                long long newWidth;\n                long long newHeight;\n                bool fits;\n                double cost;\n            };\n            vector<Choice> choices;\n            for (int o = 0; o < 2; ++o) {\n                long long w = solver.widthOpt[i][o];\n                long long h = solver.heightOpt[i][o];\n                long long newWidth = columnInitialized ? max(curWidth, w) : w;\n                long long newHeight = (columnInitialized ? curHeight : 0) + h;\n                bool fits = ((long double)newHeight <= limit + 1e-6L);\n                double widthWeight = 1.0;\n                double heightWeight = 0.12 + 0.06 * noise_dist(rng);\n                long double overflow = (long double)newHeight - limit;\n                double penalty = (!fits && overflow > 0) ? (double)overflow * 0.8 : 0.0;\n                double cost = newWidth * widthWeight + newHeight * heightWeight +\n                              penalty + noise_dist(rng) * 1e-3;\n                choices.push_back({o, newWidth, newHeight, fits, cost});\n            }\n            bool anyFit = false;\n            for (auto &c : choices) if (c.fits) anyFit = true;\n            int bestIdx = -1;\n            double bestCost = 1e300;\n            for (int idx = 0; idx < 2; ++idx) {\n                const auto &c = choices[idx];\n                if (!anyFit || c.fits) {\n                    if (c.cost < bestCost) {\n                        bestCost = c.cost;\n                        bestIdx = idx;\n                    }\n                }\n            }\n            if (bestIdx == -1) bestIdx = 0;\n            if (!anyFit && columnInitialized && curHeight > 0) {\n                finalize_col(i);\n                curStart = i;\n                curWidth = 0;\n                curHeight = 0;\n                curIdxMax = i;\n                columnInitialized = false;\n                continue;\n            }\n            const auto &best = choices[bestIdx];\n            sol.orientation[i] = best.o;\n            if (!columnInitialized) {\n                curStart = i;\n                curWidth = 0;\n                curHeight = 0;\n                curIdxMax = i;\n                columnInitialized = true;\n                currentColIndex = colStart.size();\n            }\n            long long rectWidth = solver.widthOpt[i][best.o];\n            long long rectHeight = solver.heightOpt[i][best.o];\n            if (rectWidth > curWidth || (rectWidth == curWidth && i < curIdxMax)) {\n                curIdxMax = i;\n            }\n            curWidth = max(curWidth, rectWidth);\n            curHeight += rectHeight;\n            column_id[i] = currentColIndex;\n            break;\n        }\n    }\n    finalize_col(N);\n    if (colStart.empty()) return false;\n\n    int cols = colStart.size();\n    sol.column_id = move(column_id);\n    sol.column_widths = colWidth;\n    sol.column_heights = colHeight;\n    sol.idx_max_width = idxMax;\n    sol.ranges.resize(cols);\n    sol.anchor.assign(cols, -1);\n    for (int c = 0; c < cols; ++c) {\n        sol.ranges[c] = {colStart[c], colEnd[c]};\n        sol.anchor[c] = (c == 0) ? -1 : idxMax[c - 1];\n    }\n    sol.total_width = 0;\n    sol.total_height = 0;\n    for (int c = 0; c < cols; ++c) {\n        sol.total_width += sol.column_widths[c];\n        sol.total_height = max(sol.total_height, sol.column_heights[c]);\n    }\n    sol.score = sol.total_width + sol.total_height;\n    return true;\n}\n\nvoid prune_states(vector<DPState> &states, int limit) {\n    if (states.empty()) return;\n    sort(states.begin(), states.end(), [](const DPState &a, const DPState &b){\n        if (a.width_sum != b.width_sum) return a.width_sum < b.width_sum;\n        if (a.max_height != b.max_height) return a.max_height < b.max_height;\n        return a.tiebreak < b.tiebreak;\n    });\n    vector<DPState> pareto;\n    pareto.reserve(states.size());\n    long long best_height = INFLL;\n    for (const auto &st : states) {\n        if (st.max_height < best_height) {\n            pareto.push_back(st);\n            best_height = st.max_height;\n        }\n    }\n    if ((int)pareto.size() > limit) {\n        sort(pareto.begin(), pareto.end(), [](const DPState &a, const DPState &b){\n            long long sa = a.width_sum + a.max_height;\n            long long sb = b.width_sum + b.max_height;\n            if (sa != sb) return sa < sb;\n            if (a.width_sum != b.width_sum) return a.width_sum < b.width_sum;\n            if (a.max_height != b.max_height) return a.max_height < b.max_height;\n            return a.tiebreak < b.tiebreak;\n        });\n        pareto.resize(limit);\n        sort(pareto.begin(), pareto.end(), [](const DPState &a, const DPState &b){\n            if (a.width_sum != b.width_sum) return a.width_sum < b.width_sum;\n            if (a.max_height != b.max_height) return a.max_height < b.max_height;\n            return a.tiebreak < b.tiebreak;\n        });\n    }\n    states.swap(pareto);\n}\n\nSolution reconstruct_solution(const vector<vector<DPState>> &dp, int final_idx, const ColumnPackingSolver &solver) {\n    int N = solver.N;\n    vector<int> starts, ends, choices;\n    int cur_idx = final_idx;\n    int cur_pos = N;\n    while (cur_pos > 0) {\n        const DPState &st = dp[cur_pos][cur_idx];\n        starts.push_back(st.prev_idx);\n        ends.push_back(cur_pos);\n        choices.push_back(st.choice_idx);\n        cur_idx = st.prev_state;\n        cur_pos = st.prev_idx;\n        if (cur_pos < 0) break;\n    }\n    reverse(starts.begin(), starts.end());\n    reverse(ends.begin(), ends.end());\n    reverse(choices.begin(), choices.end());\n    int cols = starts.size();\n    Solution sol;\n    sol.orientation.assign(N, 0);\n    sol.column_id.assign(N, 0);\n    sol.column_widths.assign(cols, 0);\n    sol.column_heights.assign(cols, 0);\n    sol.anchor.assign(cols, -1);\n    sol.idx_max_width.assign(cols, -1);\n    sol.ranges.resize(cols);\n\n    for (int c = 0; c < cols; ++c) {\n        int l = starts[c];\n        int r = ends[c];\n        int choice = choices[c];\n        const Profile &prof = solver.profiles[l][r];\n        long long width_limit = prof.widths[choice];\n        long long sumH = 0;\n        long long maxW = 0;\n        int idxMax = l;\n        for (int k = l; k < r; ++k) {\n            int orient = solver.choose_orientation(k, width_limit);\n            sol.orientation[k] = orient;\n            sol.column_id[k] = c;\n            long long wval = solver.widthOpt[k][orient];\n            long long hval = solver.heightOpt[k][orient];\n            sumH += hval;\n            if (wval > maxW || (wval == maxW && k < idxMax)) {\n                maxW = wval;\n                idxMax = k;\n            }\n        }\n        sol.column_widths[c] = maxW;\n        sol.column_heights[c] = sumH;\n        sol.idx_max_width[c] = idxMax;\n        sol.ranges[c] = {l, r};\n        sol.anchor[c] = (c == 0) ? -1 : sol.idx_max_width[c - 1];\n    }\n\n    long long total_w = 0;\n    long long total_h = 0;\n    for (auto wcol : sol.column_widths) total_w += wcol;\n    for (auto hcol : sol.column_heights) total_h = max(total_h, hcol);\n    sol.total_width = total_w;\n    sol.total_height = total_h;\n    sol.score = total_w + total_h;\n    return sol;\n}\n\nSolution build_row_solution(const ColumnPackingSolver &solver) {\n    int N = solver.N;\n    Solution sol;\n    sol.orientation.assign(N, 0);\n    sol.column_id.assign(N, 0);\n    sol.column_widths.assign(N, 0);\n    sol.column_heights.assign(N, 0);\n    sol.anchor.assign(N, -1);\n    sol.idx_max_width.resize(N);\n    sol.ranges.resize(N);\n    for (int i = 0; i < N; ++i) {\n        int best = 0;\n        if (solver.widthOpt[i][1] < solver.widthOpt[i][0]) best = 1;\n        else if (solver.widthOpt[i][1] == solver.widthOpt[i][0] && solver.heightOpt[i][1] < solver.heightOpt[i][0]) best = 1;\n        sol.orientation[i] = best;\n        sol.column_id[i] = i;\n        sol.column_widths[i] = solver.widthOpt[i][best];\n        sol.column_heights[i] = solver.heightOpt[i][best];\n        sol.idx_max_width[i] = i;\n        sol.anchor[i] = (i == 0) ? -1 : i - 1;\n        sol.ranges[i] = {i, i + 1};\n    }\n    long long total_w = accumulate(sol.column_widths.begin(), sol.column_widths.end(), 0LL);\n    long long total_h = 0;\n    for (auto hv : sol.column_heights) total_h = max(total_h, hv);\n    sol.total_width = total_w;\n    sol.total_height = total_h;\n    sol.score = total_w + total_h;\n    return sol;\n}\n\ntemplate <class AddFunc>\nvoid run_trial(const ColumnPackingSolver &solver, mt19937 &rng, int state_limit,\n               int take_top, int take_rand, AddFunc add_solution) {\n    int N = solver.N;\n    vector<vector<DPState>> dp(N + 1);\n    DPState init;\n    init.width_sum = 0;\n    init.max_height = 0;\n    init.prev_idx = -1;\n    init.prev_state = -1;\n    init.block_end = 0;\n    init.choice_idx = -1;\n    init.tiebreak = rng();\n    dp[0].push_back(init);\n\n    for (int i = 1; i <= N; ++i) {\n        vector<DPState> cand;\n        for (int j = 0; j < i; ++j) {\n            if (dp[j].empty()) continue;\n            const Profile &prof = solver.profiles[j][i];\n            if (prof.widths.empty()) continue;\n            for (int sid = 0; sid < (int)dp[j].size(); ++sid) {\n                const DPState &st = dp[j][sid];\n                for (int k = 0; k < (int)prof.widths.size(); ++k) {\n                    long long height = prof.heights[k];\n                    if (height >= INFLL/2) continue;\n                    DPState ns;\n                    ns.width_sum = st.width_sum + prof.widths[k];\n                    ns.max_height = max(st.max_height, height);\n                    ns.prev_idx = j;\n                    ns.prev_state = sid;\n                    ns.block_end = i;\n                    ns.choice_idx = k;\n                    ns.tiebreak = rng();\n                    cand.push_back(ns);\n                }\n            }\n        }\n        prune_states(cand, state_limit);\n        dp[i] = move(cand);\n        if (dp[i].empty()) return;\n    }\n    const auto &final_states = dp[N];\n    if (final_states.empty()) return;\n    vector<int> order(final_states.size());\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b){\n        long long sa = final_states[a].width_sum + final_states[a].max_height;\n        long long sb = final_states[b].width_sum + final_states[b].max_height;\n        if (sa != sb) return sa < sb;\n        if (final_states[a].width_sum != final_states[b].width_sum)\n            return final_states[a].width_sum < final_states[b].width_sum;\n        if (final_states[a].max_height != final_states[b].max_height)\n            return final_states[a].max_height < final_states[b].max_height;\n        return final_states[a].tiebreak < final_states[b].tiebreak;\n    });\n    auto add_state = [&](int idx) {\n        Solution sol = reconstruct_solution(dp, idx, solver);\n        add_solution(move(sol));\n    };\n    int take_top_eff = min(take_top, (int)order.size());\n    for (int i = 0; i < take_top_eff; ++i) add_state(order[i]);\n    if (take_rand > 0 && (int)order.size() > take_top_eff) {\n        vector<int> rest(order.begin() + take_top_eff, order.end());\n        shuffle(rest.begin(), rest.end(), rng);\n        int take_rand_eff = min(take_rand, (int)rest.size());\n        for (int i = 0; i < take_rand_eff; ++i) add_state(rest[i]);\n    }\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_obs(N), h_obs(N);\n    for (int i = 0; i < N; ++i) cin >> w_obs[i] >> h_obs[i];\n\n    uint64_t seed = 1469598103934665603ULL;\n    auto mix = [&](uint64_t x) {\n        seed ^= x + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(N); mix(T); mix((uint64_t)sigma);\n    for (int i = 0; i < N; ++i) { mix((uint64_t)w_obs[i]); mix((uint64_t)h_obs[i]); }\n    mt19937 rng(seed);\n\n    ColumnPackingSolver solver;\n    solver.init(w_obs, h_obs);\n\n    vector<Solution> pool;\n    pool.reserve(T * 3 + 50);\n    unordered_set<uint64_t> seen;\n    seen.reserve(T * 6 + 60);\n\n    auto add_solution = [&](Solution sol) {\n        uint64_t h = hash_solution(sol);\n        if (seen.insert(h).second) pool.push_back(move(sol));\n    };\n\n    int height_limit = min(500, max(200, T * 3));\n    vector<long long> candidate_heights = solver.generate_candidate_heights(rng, height_limit);\n    for (long long H : candidate_heights) {\n        Solution sol;\n        if (solver.build_height_solution(H, sol, rng)) add_solution(move(sol));\n    }\n\n    const int STATE_LIMIT = 55;\n    int runs = min(8, max(3, T / 20 + 1));\n    runs = min(runs, T);\n    if (runs < 1) runs = 1;\n    int base_take = max(5, T / max(1, runs));\n    base_take = min(base_take, STATE_LIMIT);\n    for (int iter = 0; iter < runs; ++iter) {\n        int take_top = base_take;\n        int take_rand = max(2, take_top / 2);\n        run_trial(solver, rng, STATE_LIMIT, take_top, take_rand, add_solution);\n    }\n\n    int greedy_trials = min(300, max(80, T * 2));\n    uniform_real_distribution<double> slack_dist(0.0, 0.7);\n    uniform_int_distribution<int> idx_dist(0, max(0, (int)candidate_heights.size() - 1));\n    for (int g = 0; g < greedy_trials; ++g) {\n        long long target = 0;\n        if (!candidate_heights.empty()) {\n            if (g % 6 == 0) target = 0;\n            else target = candidate_heights[idx_dist(rng)];\n        }\n        double slack = 1.02 + slack_dist(rng);\n        Solution sol;\n        if (build_greedy_solution(solver, target, slack, sol, rng)) add_solution(move(sol));\n    }\n\n    add_solution(build_row_solution(solver));\n    if (pool.empty()) pool.push_back(build_row_solution(solver));\n\n    sort(pool.begin(), pool.end(), [](const Solution &a, const Solution &b){\n        if (a.score != b.score) return a.score < b.score;\n        if (a.total_width != b.total_width) return a.total_width < b.total_width;\n        if (a.total_height != b.total_height) return a.total_height < b.total_height;\n        return a.column_widths.size() < b.column_widths.size();\n    });\n\n    vector<const Solution*> plan(T);\n    int use = min((int)pool.size(), T);\n    for (int i = 0; i < use; ++i) plan[i] = &pool[i];\n    for (int i = use; i < T; ++i) plan[i] = &pool[i % use];\n\n    for (int t = 0; t < T; ++t) {\n        const Solution &sol = *plan[t];\n        cout << N << '\\n';\n        for (int i = 0; i < N; ++i) {\n            int col = sol.column_id[i];\n            int b = sol.anchor[col];\n            cout << i << ' ' << sol.orientation[i] << ' ' << 'U' << ' ' << b << '\\n';\n        }\n        cout.flush();\n        long long Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n    }\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct BuildParams {\n    double rootBeautyWeight;\n    double rootCenterWeight;\n    double rootRandomWeight;\n    int candidateMode;\n    int shallowThreshold;\n    long long depthWeight;\n    long long shallowBonus;\n    long long deepBonus;\n    long long beautyWeight;\n    int candidateRandomRange;\n};\n\nstruct Solution {\n    vector<int> parent;\n    vector<int> depth;\n    long long score;\n    Solution() : score(-(1LL << 60)) {}\n};\n\nlong long compute_score(const vector<int>& depth, const vector<int>& A) {\n    long long sum = 0;\n    for (size_t i = 0; i < depth.size(); ++i) {\n        sum += 1LL * (depth[i] + 1) * A[i];\n    }\n    return sum;\n}\n\ndouble randDouble(mt19937& rng, double low, double high) {\n    uniform_real_distribution<double> dist(low, high);\n    return dist(rng);\n}\n\nint randInt(mt19937& rng, int low, int high) {\n    uniform_int_distribution<int> dist(low, high);\n    return dist(rng);\n}\n\nBuildParams random_params(mt19937& rng, int H) {\n    BuildParams p;\n    p.rootBeautyWeight = randDouble(rng, 0.25, 1.35);\n    p.rootCenterWeight = randDouble(rng, -0.05, 0.12);\n    p.rootRandomWeight = randDouble(rng, 0.0, 4.0);\n    p.candidateMode = rng() % 2;\n\n    if (p.candidateMode == 0) {\n        int lowThr = max(1, H / 4);\n        int highThr = max(lowThr, H - 2);\n        p.shallowThreshold = randInt(rng, lowThr, highThr);\n        p.depthWeight = randInt(rng, 9000, 17000);\n        p.shallowBonus = randInt(rng, 2500, 6000);\n        p.deepBonus = randInt(rng, 100, 700);\n        p.beautyWeight = 0;\n    } else {\n        p.shallowThreshold = 0;\n        p.depthWeight = randInt(rng, 5000, 11000);\n        p.shallowBonus = 0;\n        p.deepBonus = 0;\n        p.beautyWeight = randInt(rng, 300, 450);\n    }\n    p.candidateRandomRange = randInt(rng, 30, 200);\n    return p;\n}\n\nvector<int> select_roots(const vector<vector<int>>& adj,\n                         const vector<int>& A,\n                         const vector<double>& distCenter,\n                         int H,\n                         const BuildParams& params,\n                         mt19937& rng) {\n    const int N = adj.size();\n    const int INF = 1e9;\n    vector<int> minDist(N, INF);\n    vector<double> tieValue(N, 0.0);\n    uniform_real_distribution<double> rand01(0.0, 1.0);\n\n    for (int v = 0; v < N; ++v) {\n        double rnd = (params.rootRandomWeight > 0.0) ? rand01(rng) : 0.0;\n        tieValue[v] = params.rootBeautyWeight * A[v]\n                    + params.rootCenterWeight * distCenter[v]\n                    + params.rootRandomWeight * rnd;\n    }\n\n    vector<int> dist_local(N, INF);\n    vector<int> touched;\n    touched.reserve(N);\n    vector<int> roots;\n\n    auto add_root = [&](int start) {\n        queue<int> q;\n        touched.clear();\n        dist_local[start] = 0;\n        touched.push_back(start);\n        q.push(start);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int d = dist_local[v];\n            if (d < minDist[v]) minDist[v] = d;\n            if (d == H) continue;\n            for (int nb : adj[v]) {\n                if (dist_local[nb] != INF) continue;\n                int nd = d + 1;\n                if (nd > H) continue;\n                dist_local[nb] = nd;\n                touched.push_back(nb);\n                q.push(nb);\n            }\n        }\n        for (int v : touched) dist_local[v] = INF;\n    };\n\n    while (true) {\n        int best = -1;\n        for (int v = 0; v < N; ++v) {\n            if (minDist[v] > H) {\n                if (best == -1 || minDist[v] > minDist[best] ||\n                    (minDist[v] == minDist[best] && tieValue[v] < tieValue[best])) {\n                    best = v;\n                }\n            }\n        }\n        if (best == -1) break;\n        add_root(best);\n        roots.push_back(best);\n    }\n    if (roots.empty()) {\n        int best = min_element(A.begin(), A.end()) - A.begin();\n        add_root(best);\n        roots.push_back(best);\n    }\n    return roots;\n}\n\nSolution build_solution(const vector<vector<int>>& adj,\n                        const vector<int>& A,\n                        const vector<double>& distCenter,\n                        int H,\n                        const BuildParams& params,\n                        mt19937& rng) {\n    const int N = adj.size();\n    Solution sol;\n    sol.parent.assign(N, -1);\n    sol.depth.assign(N, -1);\n\n    vector<int> roots = select_roots(adj, A, distCenter, H, params, rng);\n\n    vector<char> assigned(N, 0);\n    vector<int> bestDepth(N, -1);\n    vector<int> bestParent(N, -1);\n    vector<long long> bestKey(N, numeric_limits<long long>::min());\n\n    struct Candidate {\n        long long key;\n        int depth;\n        int node;\n        bool operator<(const Candidate& other) const {\n            if (key != other.key) return key < other.key;\n            if (depth != other.depth) return depth < other.depth;\n            return node > other.node;\n        }\n    };\n    priority_queue<Candidate> pq;\n\n    auto randContribution = [&](int range) -> long long {\n        if (range <= 0) return 0LL;\n        return static_cast<long long>(rng() % range);\n    };\n\n    int threshold = params.shallowThreshold;\n    threshold = max(0, min(threshold, H));\n\n    auto computeKey = [&](int v, int depth) -> long long {\n        long long key = 1LL * depth * params.depthWeight;\n        if (params.candidateMode == 0) {\n            if (depth <= threshold) key += params.shallowBonus - A[v];\n            else key += params.deepBonus + A[v];\n        } else {\n            key += 1LL * A[v] * params.beautyWeight;\n        }\n        key += randContribution(params.candidateRandomRange);\n        return key;\n    };\n\n    auto pushCandidate = [&](int child, int par) {\n        if (assigned[child]) return;\n        int parentDepth = sol.depth[par];\n        if (parentDepth < 0) return;\n        int newDepth = parentDepth + 1;\n        if (newDepth > H) return;\n        long long key = computeKey(child, newDepth);\n        if (newDepth > bestDepth[child] || (newDepth == bestDepth[child] && key > bestKey[child])) {\n            bestDepth[child] = newDepth;\n            bestParent[child] = par;\n            bestKey[child] = key;\n            pq.push({key, newDepth, child});\n        }\n    };\n\n    int assignedCount = 0;\n    for (int r : roots) {\n        if (!assigned[r]) {\n            assigned[r] = 1;\n            sol.depth[r] = 0;\n            sol.parent[r] = -1;\n            assignedCount++;\n        }\n    }\n    if (assignedCount == 0) {\n        int best = min_element(A.begin(), A.end()) - A.begin();\n        assigned[best] = 1;\n        sol.depth[best] = 0;\n        sol.parent[best] = -1;\n        assignedCount = 1;\n        roots.push_back(best);\n    }\n    for (int r : roots) {\n        for (int nb : adj[r]) if (!assigned[nb]) pushCandidate(nb, r);\n    }\n\n    while (assignedCount < N) {\n        if (pq.empty()) {\n            int choice = -1;\n            int bestBeauty = INT_MAX;\n            for (int v = 0; v < N; ++v) {\n                if (!assigned[v] && A[v] < bestBeauty) {\n                    bestBeauty = A[v];\n                    choice = v;\n                }\n            }\n            if (choice == -1) break;\n            assigned[choice] = 1;\n            sol.depth[choice] = 0;\n            sol.parent[choice] = -1;\n            assignedCount++;\n            for (int nb : adj[choice]) if (!assigned[nb]) pushCandidate(nb, choice);\n            continue;\n        }\n        Candidate cur = pq.top(); pq.pop();\n        int v = cur.node;\n        if (assigned[v]) continue;\n        if (cur.depth != bestDepth[v]) continue;\n        if (cur.key != bestKey[v]) continue;\n        int par = bestParent[v];\n        if (par == -1) {\n            assigned[v] = 1;\n            sol.depth[v] = 0;\n            sol.parent[v] = -1;\n        } else {\n            assigned[v] = 1;\n            sol.depth[v] = cur.depth;\n            sol.parent[v] = par;\n        }\n        assignedCount++;\n        for (int nb : adj[v]) if (!assigned[nb]) pushCandidate(nb, v);\n    }\n\n    for (int v = 0; v < N; ++v) {\n        if (sol.depth[v] < 0) {\n            sol.depth[v] = 0;\n            sol.parent[v] = -1;\n        }\n    }\n    sol.score = compute_score(sol.depth, A);\n    return sol;\n}\n\nvoid improve_leaves(const vector<vector<int>>& adj,\n                    const vector<int>& A,\n                    int H,\n                    const vector<int>& beautyOrder,\n                    Solution& sol,\n                    int maxIterations = 8) {\n    const int N = adj.size();\n    vector<int> childCnt(N, 0);\n    for (int v = 0; v < N; ++v) {\n        int p = sol.parent[v];\n        if (p >= 0) childCnt[p]++;\n    }\n\n    for (int iter = 0; iter < maxIterations; ++iter) {\n        bool changed = false;\n        for (int v : beautyOrder) {\n            if (childCnt[v] != 0) continue;\n            int curDepth = sol.depth[v];\n            int bestParent = -1;\n            int bestDepth = curDepth;\n            for (int nb : adj[v]) {\n                int parentDepth = sol.depth[nb];\n                if (parentDepth < 0) continue;\n                int newDepth = parentDepth + 1;\n                if (newDepth > H) continue;\n                if (newDepth > bestDepth) {\n                    bestDepth = newDepth;\n                    bestParent = nb;\n                } else if (newDepth == bestDepth && bestParent >= 0 && A[nb] > A[bestParent]) {\n                    bestParent = nb;\n                }\n            }\n            if (bestParent >= 0 && bestDepth > curDepth) {\n                int oldParent = sol.parent[v];\n                if (oldParent >= 0) childCnt[oldParent]--;\n                sol.parent[v] = bestParent;\n                sol.depth[v] = bestDepth;\n                childCnt[bestParent]++;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n    sol.score = compute_score(sol.depth, A);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    cin >> N >> M >> H;\n    vector<int> A(N);\n    for (int i = 0; i < N; ++i) cin >> A[i];\n\n    vector<vector<int>> adj(N);\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; ++i) cin >> xs[i] >> ys[i];\n\n    double cx = 0.0, cy = 0.0;\n    for (int i = 0; i < N; ++i) {\n        cx += xs[i];\n        cy += ys[i];\n    }\n    cx /= N;\n    cy /= N;\n\n    vector<double> distCenter(N, 0.0);\n    for (int i = 0; i < N; ++i) {\n        double dx = xs[i] - cx;\n        double dy = ys[i] - cy;\n        distCenter[i] = sqrt(dx * dx + dy * dy);\n    }\n\n    vector<int> beautyOrder(N);\n    iota(beautyOrder.begin(), beautyOrder.end(), 0);\n    sort(beautyOrder.begin(), beautyOrder.end(), [&](int lhs, int rhs) {\n        if (A[lhs] != A[rhs]) return A[lhs] > A[rhs];\n        return lhs < rhs;\n    });\n\n    vector<BuildParams> baseParams = {\n        {1.00,  0.02, 0.80, 0, 4, 15000, 4500, 350,   0,  80},\n        {0.80,  0.08, 2.50, 0, 5, 12000, 4200, 600,   0, 110},\n        {1.20, -0.02, 0.40, 0, 3, 17000, 5200, 250,   0,  70},\n        {0.60,  0.10, 3.00, 1, 0,  7000,    0,   0, 360, 120},\n        {0.45, -0.03, 4.40, 1, 0,  6200,    0,   0, 420, 150},\n        {0.95,  0.05, 1.50, 0, 2, 14000, 3600, 500,   0,  60}\n    };\n\n    mt19937 rng(123456789);\n    auto start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.80;\n\n    Solution best;\n    bool hasBest = false;\n\n    auto runAttempt = [&](const BuildParams& params) {\n        Solution sol = build_solution(adj, A, distCenter, H, params, rng);\n        improve_leaves(adj, A, H, beautyOrder, sol);\n        if (!hasBest || sol.score > best.score) {\n            best = sol;\n            hasBest = true;\n        }\n    };\n\n    for (const auto& params : baseParams) {\n        runAttempt(params);\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        if (elapsed > TIME_LIMIT) break;\n    }\n\n    while (chrono::duration<double>(chrono::steady_clock::now() - start).count() < TIME_LIMIT) {\n        BuildParams params = random_params(rng, H);\n        runAttempt(params);\n    }\n\n    if (!hasBest) {\n        BuildParams fallback = baseParams.front();\n        Solution sol = build_solution(adj, A, distCenter, H, fallback, rng);\n        improve_leaves(adj, A, H, beautyOrder, sol);\n        best = sol;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << best.parent[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Candidate {\n    char dir;\n    int idx;\n    int shifts;\n    int removal;\n};\n\nstruct PlanResult {\n    vector<Candidate> seq;\n    int cost = 0;\n    bool success = false;\n};\n\nstruct GreedyConfig {\n    double tolerance;\n    double valuePower;\n    double costPower;\n    double valueBias;\n    double hardBias;\n    double focusHardProb;\n    double noiseAmp;\n};\n\nstruct CandidateData {\n    char dir;\n    int idx;\n    int shifts;\n    int removal;\n    int hardCount;\n    double value;\n    int cost;\n    double ratio;\n};\n\nstruct SetOperation {\n    char dir;\n    int idx;\n    int shifts;\n    int cost;\n    uint64_t mask;\n    vector<int> oniList;\n};\n\nstruct PlanOps {\n    vector<int> opIndices;\n    int cost = 0;\n    bool success = false;\n};\n\nint N;\nint LIMIT_OPS;\nvector<vector<double>> cellWeight;\nvector<vector<int>> cellHard;\nvector<int> rowFirstF, rowLastF, colFirstF, colLastF;\n\nint countOni(const vector<string>& board) {\n    int cnt = 0;\n    for (const auto& row : board)\n        for (char c : row)\n            if (c == 'x') ++cnt;\n    return cnt;\n}\n\nchar oppositeDir(char dir) {\n    if (dir == 'U') return 'D';\n    if (dir == 'D') return 'U';\n    if (dir == 'L') return 'R';\n    return 'L';\n}\n\nint removeCells(vector<string>& board, const Candidate& cand) {\n    int removed = 0;\n    if (cand.dir == 'U') {\n        for (int r = 0; r < cand.shifts; ++r) {\n            char& cell = board[r][cand.idx];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'D') {\n        for (int r = N - cand.shifts; r < N; ++r) {\n            char& cell = board[r][cand.idx];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else if (cand.dir == 'L') {\n        for (int c = 0; c < cand.shifts; ++c) {\n            char& cell = board[cand.idx][c];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    } else {\n        for (int c = N - cand.shifts; c < N; ++c) {\n            char& cell = board[cand.idx][c];\n            if (cell == 'o') return -1;\n            if (cell == 'x') { cell = '.'; ++removed; }\n        }\n    }\n    return removed;\n}\n\nGreedyConfig sampleConfig(mt19937& rng, double tolerance) {\n    uniform_real_distribution<double> dist(0.0, 1.0);\n    GreedyConfig cfg;\n    cfg.tolerance = tolerance;\n    cfg.valuePower = 1.0 + 1.4 * dist(rng);\n    cfg.costPower = 0.2 + 0.8 * dist(rng);\n    cfg.valueBias = 0.05 + 0.45 * dist(rng);\n    cfg.hardBias = 0.3 + 1.0 * dist(rng);\n    cfg.focusHardProb = 0.05 + 0.35 * pow(dist(rng), 1.5);\n    cfg.noiseAmp = 0.005 + 0.02 * dist(rng);\n    return cfg;\n}\n\nGreedyConfig deterministicConfig() {\n    GreedyConfig cfg;\n    cfg.tolerance = 0.0;\n    cfg.valuePower = 1.0;\n    cfg.costPower = 1.0;\n    cfg.valueBias = 0.0;\n    cfg.hardBias = 0.0;\n    cfg.focusHardProb = 0.0;\n    cfg.noiseAmp = 0.0;\n    return cfg;\n}\n\nPlanResult greedyPlan(const vector<string>& initial,\n                      const GreedyConfig& cfg,\n                      mt19937& rng,\n                      int costLimit,\n                      bool deterministic = false) {\n    PlanResult result;\n    vector<string> board = initial;\n    int remaining = countOni(board);\n    if (remaining == 0) {\n        result.success = true;\n        return result;\n    }\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    while (remaining > 0) {\n        vector<CandidateData> candidates;\n        int remainingBudget = costLimit - result.cost;\n        if (remainingBudget <= 0) return PlanResult();\n\n        auto addCandidate = [&](char dir, int idx, int shifts,\n                                int removal, double baseValue, int hardCount) {\n            if (removal <= 0 || shifts <= 0) return;\n            int opCost = shifts * 2;\n            if (opCost > remainingBudget) return;\n            double value = baseValue + cfg.valueBias * removal + cfg.hardBias * hardCount;\n            if (value <= 1e-9) value = removal;\n            double ratio = opCost / value;\n            if (!deterministic && cfg.noiseAmp > 0.0) {\n                double noise = (dist01(rng) * 2.0 - 1.0) * cfg.noiseAmp;\n                ratio *= max(0.05, 1.0 + noise);\n            }\n            candidates.push_back({dir, idx, shifts, removal, hardCount, value, opCost, ratio});\n        };\n\n        for (int j = 0; j < N; ++j) {\n            int limit = min(colFirstF[j], N);\n            int removal = 0, hard = 0, deepest = -1;\n            double val = 0.0;\n            for (int r = 0; r < limit; ++r) {\n                if (board[r][j] == 'x') {\n                    ++removal;\n                    deepest = r;\n                    val += cellWeight[r][j];\n                    hard += cellHard[r][j];\n                }\n            }\n            if (removal > 0) addCandidate('U', j, deepest + 1, removal, val, hard);\n\n            int start = colLastF[j];\n            int removal2 = 0, hard2 = 0, top = N;\n            double val2 = 0.0;\n            for (int r = N - 1; r > start; --r) {\n                if (board[r][j] == 'x') {\n                    ++removal2;\n                    top = min(top, r);\n                    val2 += cellWeight[r][j];\n                    hard2 += cellHard[r][j];\n                }\n            }\n            if (removal2 > 0) addCandidate('D', j, N - top, removal2, val2, hard2);\n        }\n\n        for (int i = 0; i < N; ++i) {\n            int limit = min(rowFirstF[i], N);\n            int removal = 0, hard = 0, farthest = -1;\n            double val = 0.0;\n            for (int c = 0; c < limit; ++c) {\n                if (board[i][c] == 'x') {\n                    ++removal;\n                    farthest = c;\n                    val += cellWeight[i][c];\n                    hard += cellHard[i][c];\n                }\n            }\n            if (removal > 0) addCandidate('L', i, farthest + 1, removal, val, hard);\n\n            int start = rowLastF[i];\n            int removal2 = 0, hard2 = 0, leftmost = N;\n            double val2 = 0.0;\n            for (int c = N - 1; c > start; --c) {\n                if (board[i][c] == 'x') {\n                    ++removal2;\n                    leftmost = min(leftmost, c);\n                    val2 += cellWeight[i][c];\n                    hard2 += cellHard[i][c];\n                }\n            }\n            if (removal2 > 0) addCandidate('R', i, N - leftmost, removal2, val2, hard2);\n        }\n\n        if (candidates.empty()) return PlanResult();\n\n        double minRatio = candidates.front().ratio;\n        for (const auto& cand : candidates) minRatio = min(minRatio, cand.ratio);\n        double threshold = minRatio * (1.0 + cfg.tolerance);\n\n        vector<int> eligible, hardEligible;\n        for (int idx = 0; idx < (int)candidates.size(); ++idx) {\n            if (candidates[idx].ratio <= threshold + 1e-9) {\n                eligible.push_back(idx);\n                if (candidates[idx].hardCount > 0) hardEligible.push_back(idx);\n            }\n        }\n        if (eligible.empty()) {\n            int bestIdx = 0;\n            for (int idx = 1; idx < (int)candidates.size(); ++idx)\n                if (candidates[idx].ratio + 1e-9 < candidates[bestIdx].ratio)\n                    bestIdx = idx;\n            eligible.push_back(bestIdx);\n        }\n\n        int chosenIdx = eligible.front();\n        if (deterministic) {\n            for (int idx : eligible) {\n                const auto& cur = candidates[idx];\n                const auto& best = candidates[chosenIdx];\n                if (cur.ratio + 1e-9 < best.ratio) chosenIdx = idx;\n                else if (fabs(cur.ratio - best.ratio) <= 1e-9) {\n                    if (cur.cost < best.cost) chosenIdx = idx;\n                    else if (cur.cost == best.cost && cur.removal > best.removal) chosenIdx = idx;\n                    else if (cur.cost == best.cost && cur.removal == best.removal &&\n                             cur.value > best.value + 1e-9) chosenIdx = idx;\n                }\n            }\n        } else {\n            vector<int>* pool = &eligible;\n            if (!hardEligible.empty() && dist01(rng) < cfg.focusHardProb) pool = &hardEligible;\n            vector<double> weights;\n            weights.reserve(pool->size());\n            double totalW = 0.0;\n            for (int idx : *pool) {\n                double w = pow(max(candidates[idx].value, 1e-6), cfg.valuePower);\n                if (cfg.costPower > 1e-9)\n                    w /= pow((double)candidates[idx].cost, cfg.costPower);\n                w = max(w, 1e-12);\n                weights.push_back(w);\n                totalW += w;\n            }\n            if (totalW <= 0.0) {\n                for (int idx : *pool)\n                    if (candidates[idx].ratio + 1e-9 < candidates[chosenIdx].ratio)\n                        chosenIdx = idx;\n            } else {\n                double pick = dist01(rng) * totalW;\n                for (int k = 0; k < (int)pool->size(); ++k) {\n                    pick -= weights[k];\n                    if (pick <= 1e-12) {\n                        chosenIdx = (*pool)[k];\n                        break;\n                    }\n                }\n            }\n        }\n\n        const auto& chosen = candidates[chosenIdx];\n        Candidate op{chosen.dir, chosen.idx, chosen.shifts, chosen.removal};\n        int removed = removeCells(board, op);\n        if (removed <= 0) return PlanResult();\n        op.removal = removed;\n        result.seq.push_back(op);\n        result.cost += chosen.cost;\n        remaining -= removed;\n        if (result.cost > costLimit) return PlanResult();\n    }\n    result.success = true;\n    return result;\n}\n\nPlanResult sequentialPlan(const vector<string>& initial) {\n    vector<string> board = initial;\n    PlanResult res;\n    int remaining = countOni(board);\n    while (remaining > 0) {\n        Candidate best{};\n        bool found = false;\n        int bestShift = INT_MAX;\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                if (board[i][j] != 'x') continue;\n                auto consider = [&](char dir, int shifts, int idx) {\n                    if (shifts <= 0) return;\n                    if (shifts < bestShift) {\n                        bestShift = shifts;\n                        best = Candidate{dir, idx, shifts, 0};\n                        found = true;\n                    }\n                };\n                bool ok = true;\n                for (int r = 0; r < i; ++r) if (board[r][j] == 'o') { ok = false; break; }\n                if (ok) consider('U', i + 1, j);\n                ok = true;\n                for (int r = i + 1; r < N; ++r) if (board[r][j] == 'o') { ok = false; break; }\n                if (ok) consider('D', N - i, j);\n                ok = true;\n                for (int c = 0; c < j; ++c) if (board[i][c] == 'o') { ok = false; break; }\n                if (ok) consider('L', j + 1, i);\n                ok = true;\n                for (int c = j + 1; c < N; ++c) if (board[i][c] == 'o') { ok = false; break; }\n                if (ok) consider('R', N - j, i);\n            }\n        }\n        if (!found) break;\n        int removed = removeCells(board, best);\n        if (removed <= 0) break;\n        best.removal = removed;\n        res.seq.push_back(best);\n        res.cost += 2 * best.shifts;\n        remaining -= removed;\n        if (res.cost > LIMIT_OPS) break;\n    }\n    if (remaining == 0 && res.cost <= LIMIT_OPS) res.success = true;\n    return res;\n}\n\nbool applyPrefix(const vector<string>& initial, const vector<Candidate>& seq,\n                 int keep, vector<string>& boardOut, int& costOut) {\n    boardOut = initial;\n    costOut = 0;\n    keep = min(keep, (int)seq.size());\n    for (int i = 0; i < keep; ++i) {\n        costOut += 2 * seq[i].shifts;\n        if (costOut > LIMIT_OPS) return false;\n        int removed = removeCells(boardOut, seq[i]);\n        if (removed <= 0) return false;\n    }\n    return true;\n}\n\nvoid localSearch(const vector<string>& initial, PlanResult& best,\n                 mt19937& rng, int iterations, double maxTol) {\n    if (!best.success || best.seq.empty()) return;\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n    vector<string> board;\n    int prefixCost = 0;\n    for (int iter = 0; iter < iterations; ++iter) {\n        if (best.seq.empty()) break;\n        double r = dist01(rng);\n        int keep;\n        if (r < 0.2) keep = 0;\n        else if (r < 0.5) keep = rng() % min<int>(best.seq.size(), 5);\n        else if (r < 0.85) keep = rng() % max<int>(1, (int)best.seq.size() / 2);\n        else keep = rng() % best.seq.size();\n        if (!applyPrefix(initial, best.seq, keep, board, prefixCost)) continue;\n        int budget = LIMIT_OPS - prefixCost;\n        if (budget <= 0) continue;\n        double tol = pow(dist01(rng), 1.3) * maxTol;\n        GreedyConfig cfg = sampleConfig(rng, tol);\n        PlanResult tail = greedyPlan(board, cfg, rng, budget, false);\n        if (!tail.success) continue;\n        PlanResult candidate;\n        candidate.success = true;\n        candidate.cost = prefixCost + tail.cost;\n        candidate.seq.reserve(keep + tail.seq.size());\n        candidate.seq.insert(candidate.seq.end(), best.seq.begin(), best.seq.begin() + keep);\n        candidate.seq.insert(candidate.seq.end(), tail.seq.begin(), tail.seq.end());\n        if (!best.success || candidate.cost < best.cost ||\n            (candidate.cost == best.cost && candidate.seq.size() < best.seq.size())) {\n            best = move(candidate);\n        }\n    }\n}\n\nbool simulatePlan(const vector<string>& initial, const PlanResult& plan,\n                  vector<pair<char,int>>& output) {\n    if (!plan.success) return false;\n    if (plan.cost > LIMIT_OPS) return false;\n    vector<string> board = initial;\n    int remaining = countOni(board);\n    output.clear();\n    output.reserve(plan.cost + 5);\n\n    auto doShift = [&](char dir, int idx) -> bool {\n        if ((int)output.size() >= LIMIT_OPS) return false;\n        output.emplace_back(dir, idx);\n        if (dir == 'U') {\n            char removed = board[0][idx];\n            for (int r = 0; r < N - 1; ++r) board[r][idx] = board[r + 1][idx];\n            board[N - 1][idx] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else if (dir == 'D') {\n            char removed = board[N - 1][idx];\n            for (int r = N - 1; r >= 1; --r) board[r][idx] = board[r - 1][idx];\n            board[0][idx] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else if (dir == 'L') {\n            char removed = board[idx][0];\n            for (int c = 0; c < N - 1; ++c) board[idx][c] = board[idx][c + 1];\n            board[idx][N - 1] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        } else {\n            char removed = board[idx][N - 1];\n            for (int c = N - 1; c >= 1; --c) board[idx][c] = board[idx][c - 1];\n            board[idx][0] = '.';\n            if (removed == 'x') --remaining;\n            else if (removed == 'o') return false;\n        }\n        return true;\n    };\n\n    for (const auto& cand : plan.seq) {\n        for (int s = 0; s < cand.shifts; ++s)\n            if (!doShift(cand.dir, cand.idx)) { output.clear(); return false; }\n        char opp = oppositeDir(cand.dir);\n        for (int s = 0; s < cand.shifts; ++s)\n            if (!doShift(opp, cand.idx)) { output.clear(); return false; }\n    }\n    if (remaining != 0) { output.clear(); return false; }\n    if ((int)output.size() > LIMIT_OPS) { output.clear(); return false; }\n    return true;\n}\n\nvoid buildPrecomputations(const vector<string>& board) {\n    rowFirstF.assign(N, N);\n    rowLastF.assign(N, -1);\n    colFirstF.assign(N, N);\n    colLastF.assign(N, -1);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (board[i][j] == 'o') {\n                rowFirstF[i] = min(rowFirstF[i], j);\n                rowLastF[i] = max(rowLastF[i], j);\n                colFirstF[j] = min(colFirstF[j], i);\n                colLastF[j] = max(colLastF[j], i);\n            }\n        }\n    }\n\n    cellWeight.assign(N, vector<double>(N, 0.0));\n    cellHard.assign(N, vector<int>(N, 0));\n    vector<vector<int>> colPrev(N, vector<int>(N));\n    vector<vector<int>> colNext(N, vector<int>(N));\n    vector<vector<int>> rowPrev(N, vector<int>(N));\n    vector<vector<int>> rowNext(N, vector<int>(N));\n    for (int j = 0; j < N; ++j) {\n        int prev = -1;\n        for (int i = 0; i < N; ++i) {\n            colPrev[j][i] = prev;\n            if (board[i][j] == 'o') prev = i;\n        }\n        int next = N;\n        for (int i = N - 1; i >= 0; --i) {\n            colNext[j][i] = next;\n            if (board[i][j] == 'o') next = i;\n        }\n    }\n    for (int i = 0; i < N; ++i) {\n        int prev = -1;\n        for (int j = 0; j < N; ++j) {\n            rowPrev[i][j] = prev;\n            if (board[i][j] == 'o') prev = j;\n        }\n        int next = N;\n        for (int j = N - 1; j >= 0; --j) {\n            rowNext[i][j] = next;\n            if (board[i][j] == 'o') next = j;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (board[i][j] != 'x') continue;\n            bool safeUp = (colPrev[j][i] == -1);\n            bool safeDown = (colNext[j][i] == N);\n            bool safeLeft = (rowPrev[i][j] == -1);\n            bool safeRight = (rowNext[i][j] == N);\n            int deg = safeUp + safeDown + safeLeft + safeRight;\n            int minShift = INT_MAX;\n            if (safeUp) minShift = min(minShift, i + 1);\n            if (safeDown) minShift = min(minShift, N - i);\n            if (safeLeft) minShift = min(minShift, j + 1);\n            if (safeRight) minShift = min(minShift, N - j);\n            if (deg == 0) minShift = min({i + 1, N - i, j + 1, N - j});\n            double degBonus = 0.0;\n            if (deg <= 1) degBonus = 1.2;\n            else if (deg == 2) degBonus = 0.6;\n            else if (deg == 3) degBonus = 0.25;\n            else degBonus = 0.1;\n            double distBonus = 0.03 * minShift;\n            int edgeDist = min({i, j, N - 1 - i, N - 1 - j});\n            double edgeBonus = (edgeDist <= 1 ? 0.2 : 0.0);\n            double weight = 1.0 + degBonus + distBonus + edgeBonus;\n            cellWeight[i][j] = weight;\n            cellHard[i][j] = (deg <= 2) ? 1 : 0;\n        }\n    }\n}\n\nvoid buildPieceData(const vector<string>& board,\n                    vector<pair<int,int>>& oniPos,\n                    vector<vector<int>>& oniId,\n                    vector<vector<pair<int,int>>>& rowOni,\n                    vector<vector<pair<int,int>>>& colOni,\n                    vector<double>& oniWeight) {\n    oniPos.clear();\n    oniWeight.clear();\n    oniId.assign(N, vector<int>(N, -1));\n    rowOni.assign(N, {});\n    colOni.assign(N, {});\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (board[i][j] != 'x') continue;\n            int id = oniPos.size();\n            oniPos.emplace_back(i, j);\n            oniId[i][j] = id;\n            oniWeight.push_back(cellWeight[i][j]);\n            rowOni[i].push_back({j, id});\n            colOni[j].push_back({i, id});\n        }\n    }\n    for (int i = 0; i < N; ++i) sort(rowOni[i].begin(), rowOni[i].end());\n    for (int j = 0; j < N; ++j) sort(colOni[j].begin(), colOni[j].end());\n}\n\ninline long long encodeKey(char dir, int idx, int shifts) {\n    int dirId = (dir == 'U' ? 0 : dir == 'D' ? 1 : dir == 'L' ? 2 : 3);\n    return ( (long long)dirId << 32 ) ^ ( (long long)idx << 16 ) ^ (long long)shifts;\n}\n\nvector<SetOperation> buildSetOperations(\n        const vector<pair<int,int>>& oniPos,\n        const vector<vector<pair<int,int>>>& rowOni,\n        const vector<vector<pair<int,int>>>& colOni,\n        const vector<double>& oniWeight,\n        unordered_map<long long,int>& keyMap) {\n    vector<SetOperation> ops;\n    keyMap.clear();\n    auto addOp = [&](char dir, int idx, int shifts, const vector<int>& cover) {\n        if (cover.empty() || shifts <= 0) return;\n        long long key = encodeKey(dir, idx, shifts);\n        if (keyMap.count(key)) return;\n        SetOperation op;\n        op.dir = dir;\n        op.idx = idx;\n        op.shifts = shifts;\n        op.cost = shifts * 2;\n        op.mask = 0;\n        op.oniList = cover;\n        for (int id : cover) op.mask |= (1ULL << id);\n        if (op.mask == 0) return;\n        ops.push_back(move(op));\n        keyMap[key] = (int)ops.size() - 1;\n    };\n\n    int K = oniPos.size();\n    for (int id = 0; id < K; ++id) {\n        auto [i, j] = oniPos[id];\n        if (colFirstF[j] >= i) {\n            vector<int> cover;\n            for (auto [row, oid] : colOni[j]) {\n                if (row > i) break;\n                cover.push_back(oid);\n            }\n            addOp('U', j, i + 1, cover);\n        }\n        if (colLastF[j] <= i) {\n            vector<int> cover;\n            for (auto [row, oid] : colOni[j])\n                if (row >= i) cover.push_back(oid);\n            addOp('D', j, N - i, cover);\n        }\n        if (rowFirstF[i] >= j) {\n            vector<int> cover;\n            for (auto [col, oid] : rowOni[i]) {\n                if (col > j) break;\n                cover.push_back(oid);\n            }\n            addOp('L', i, j + 1, cover);\n        }\n        if (rowLastF[i] <= j) {\n            vector<int> cover;\n            for (auto [col, oid] : rowOni[i])\n                if (col >= j) cover.push_back(oid);\n            addOp('R', i, N - j, cover);\n        }\n    }\n    return ops;\n}\n\nPlanOps convertPlanToOps(const PlanResult& plan,\n                         const unordered_map<long long,int>& keyMap,\n                         const vector<SetOperation>& ops) {\n    PlanOps res;\n    if (!plan.success) return res;\n    for (const auto& cand : plan.seq) {\n        long long key = encodeKey(cand.dir, cand.idx, cand.shifts);\n        auto it = keyMap.find(key);\n        if (it == keyMap.end()) {\n            res.success = false;\n            res.opIndices.clear();\n            res.cost = 0;\n            return res;\n        }\n        res.opIndices.push_back(it->second);\n        res.cost += ops[it->second].cost;\n    }\n    if (res.cost != plan.cost) {\n        res.success = false;\n        res.opIndices.clear();\n        res.cost = 0;\n        return res;\n    }\n    res.success = true;\n    return res;\n}\n\nPlanResult convertSetPlanToPlanResult(const PlanOps& planOps,\n                                      const vector<SetOperation>& ops) {\n    PlanResult res;\n    if (!planOps.success) return res;\n    res.success = true;\n    res.cost = 0;\n    res.seq.reserve(planOps.opIndices.size());\n    for (int idx : planOps.opIndices) {\n        const auto& op = ops[idx];\n        res.seq.push_back({op.dir, op.idx, op.shifts, 0});\n        res.cost += op.cost;\n    }\n    return res;\n}\n\nstruct SetCoverSolver {\n    const vector<SetOperation>& ops;\n    const vector<vector<int>>& oniToOps;\n    const vector<double>& weights;\n    uint64_t fullMask;\n    int limit;\n    vector<int> bestPlan;\n    int bestCost;\n    vector<int> curPlan;\n    unordered_map<uint64_t,int> memo;\n    chrono::steady_clock::time_point start;\n    double timeLimit;\n    bool timeExceeded = false;\n\n    SetCoverSolver(const vector<SetOperation>& ops_,\n                   const vector<vector<int>>& oniToOps_,\n                   const vector<double>& weights_,\n                   uint64_t fullMask_,\n                   int limit_,\n                   const PlanOps& initial,\n                   double timeLimitSec)\n        : ops(ops_), oniToOps(oniToOps_), weights(weights_),\n          fullMask(fullMask_), limit(limit_),\n          bestPlan(initial.opIndices), bestCost(initial.cost),\n          timeLimit(timeLimitSec) {\n        start = chrono::steady_clock::now();\n    }\n\n    double sumWeight(uint64_t mask) const {\n        double sum = 0.0;\n        while (mask) {\n            int id = __builtin_ctzll(mask);\n            sum += weights[id];\n            mask &= mask - 1;\n        }\n        return sum;\n    }\n\n    double computeMinRatio(uint64_t mask) const {\n        double best = numeric_limits<double>::infinity();\n        for (size_t i = 0; i < ops.size(); ++i) {\n            uint64_t cover = ops[i].mask & mask;\n            if (!cover) continue;\n            double w = sumWeight(cover);\n            if (w <= 1e-9) continue;\n            double ratio = ops[i].cost / w;\n            if (ratio < best) best = ratio;\n        }\n        return best;\n    }\n\n    int selectPivot(uint64_t mask) const {\n        int bestOni = -1;\n        int bestCnt = INT_MAX;\n        uint64_t temp = mask;\n        while (temp) {\n            int id = __builtin_ctzll(temp);\n            temp &= temp - 1;\n            int cnt = oniToOps[id].size();\n            if (cnt == 0) return -1;\n            if (cnt < bestCnt) {\n                bestCnt = cnt;\n                bestOni = id;\n                if (cnt == 1) break;\n            }\n        }\n        return bestOni;\n    }\n\n    void dfs(uint64_t mask, int cost) {\n        if (timeExceeded) return;\n        if (cost >= bestCost) return;\n        if (mask == 0) {\n            bestCost = cost;\n            bestPlan = curPlan;\n            return;\n        }\n        if (cost >= limit) return;\n        if (chrono::duration<double>(chrono::steady_clock::now() - start).count() > timeLimit) {\n            timeExceeded = true;\n            return;\n        }\n        auto it = memo.find(mask);\n        if (it != memo.end() && it->second <= cost) return;\n        memo[mask] = cost;\n        double remWeight = sumWeight(mask);\n        double minRatio = computeMinRatio(mask);\n        if (!isfinite(minRatio)) return;\n        if (cost + remWeight * minRatio >= bestCost - 1e-9) return;\n\n        int pivot = selectPivot(mask);\n        if (pivot == -1) return;\n        vector<pair<double,int>> options;\n        options.reserve(oniToOps[pivot].size());\n        for (int opIdx : oniToOps[pivot]) {\n            uint64_t cover = ops[opIdx].mask & mask;\n            if (!(cover & (1ULL << pivot))) continue;\n            double w = sumWeight(cover);\n            if (w <= 1e-9) continue;\n            double ratio = ops[opIdx].cost / w;\n            options.emplace_back(ratio, opIdx);\n        }\n        sort(options.begin(), options.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 [ratio, opIdx] : options) {\n            curPlan.push_back(opIdx);\n            dfs(mask & ~ops[opIdx].mask, cost + ops[opIdx].cost);\n            curPlan.pop_back();\n            if (timeExceeded) return;\n        }\n    }\n\n    PlanOps solve() {\n        memo.reserve(4096);\n        dfs(fullMask, 0);\n        PlanOps res;\n        res.success = true;\n        res.cost = bestCost;\n        res.opIndices = bestPlan;\n        return res;\n    }\n};\n\nPlanResult improveWithSetCover(const PlanResult& basePlan,\n                               const vector<SetOperation>& ops,\n                               const unordered_map<long long,int>& keyMap,\n                               const vector<vector<int>>& oniToOps,\n                               const vector<double>& oniWeight,\n                               uint64_t fullMask) {\n    PlanResult res;\n    if (!basePlan.success) return res;\n    if (fullMask == 0 || ops.empty()) return res;\n    PlanOps baseOps = convertPlanToOps(basePlan, keyMap, ops);\n    if (!baseOps.success) return res;\n    uint64_t coverage = 0;\n    for (int idx : baseOps.opIndices) coverage |= ops[idx].mask;\n    if (coverage != fullMask) return res;\n    double timeLimit = (ops.size() <= 90 ? 0.08 : 0.05);\n    SetCoverSolver solver(ops, oniToOps, oniWeight, fullMask, LIMIT_OPS, baseOps, timeLimit);\n    PlanOps solved = solver.solve();\n    if (!solved.success) return res;\n    if (solved.cost >= basePlan.cost) return res;\n    return convertSetPlanToPlanResult(solved, ops);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N)) return 0;\n    vector<string> board(N);\n    for (int i = 0; i < N; ++i) cin >> board[i];\n    LIMIT_OPS = 4 * N * N;\n\n    buildPrecomputations(board);\n\n    vector<pair<int,int>> oniPos;\n    vector<vector<int>> oniId;\n    vector<vector<pair<int,int>>> rowOni, colOni;\n    vector<double> oniWeight;\n    buildPieceData(board, oniPos, oniId, rowOni, colOni, oniWeight);\n\n    unordered_map<long long,int> opKeyMap;\n    vector<SetOperation> setOps = buildSetOperations(oniPos, rowOni, colOni, oniWeight, opKeyMap);\n    vector<vector<int>> oniToOps(oniPos.size());\n    for (int idx = 0; idx < (int)setOps.size(); ++idx)\n        for (int id : setOps[idx].oniList)\n            oniToOps[id].push_back(idx);\n    uint64_t fullMask = oniPos.empty() ? 0ULL : ((1ULL << oniPos.size()) - 1);\n\n    uint64_t seed = 1469598103934665603ULL;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < N; ++i)\n        for (char c : board[i]) {\n            seed ^= (uint64_t)(unsigned char)c + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    mt19937 rng(seed);\n    uniform_real_distribution<double> dist01(0.0, 1.0);\n\n    const int MAX_TRIALS = 180;\n    const double MAX_TOL = 0.38;\n    PlanResult best;\n    best.cost = numeric_limits<int>::max();\n\n    for (int t = 0; t < MAX_TRIALS; ++t) {\n        double tol = (t == 0) ? 0.0 : pow(dist01(rng), 1.4) * MAX_TOL;\n        GreedyConfig cfg = sampleConfig(rng, tol);\n        PlanResult plan = greedyPlan(board, cfg, rng, LIMIT_OPS, false);\n        if (!plan.success) continue;\n        if (!best.success || plan.cost < best.cost ||\n            (plan.cost == best.cost && plan.seq.size() < best.seq.size())) {\n            best = plan;\n        }\n    }\n\n    if (!best.success) {\n        GreedyConfig detCfg = deterministicConfig();\n        PlanResult detPlan = greedyPlan(board, detCfg, rng, LIMIT_OPS, true);\n        if (detPlan.success) best = detPlan;\n    }\n\n    if (best.success) {\n        localSearch(board, best, rng, 100, 0.3);\n    } else {\n        PlanResult seqPlan = sequentialPlan(board);\n        if (seqPlan.success) best = seqPlan;\n    }\n\n    if (best.success && !oniPos.empty() && !setOps.empty() && setOps.size() <= 160) {\n        PlanResult bnbPlan = improveWithSetCover(best, setOps, opKeyMap, oniToOps, oniWeight, fullMask);\n        if (bnbPlan.success && (bnbPlan.cost < best.cost ||\n            (bnbPlan.cost == best.cost && bnbPlan.seq.size() < best.seq.size()))) {\n            best = bnbPlan;\n        }\n    }\n\n    vector<pair<char,int>> opsOutput;\n    if (!simulatePlan(board, best, opsOutput)) {\n        GreedyConfig detCfg = deterministicConfig();\n        PlanResult detPlan = greedyPlan(board, detCfg, rng, LIMIT_OPS, true);\n        if (!detPlan.success || !simulatePlan(board, detPlan, opsOutput)) {\n            PlanResult seqPlan = sequentialPlan(board);\n            simulatePlan(board, seqPlan, opsOutput);\n        }\n    }\n\n    for (auto& op : opsOutput) {\n        cout << op.first << ' ' << op.second << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\ndouble elapsedSec(const chrono::steady_clock::time_point &start) {\n    return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n}\n\nstruct AssignState {\n    int N = 0;\n    int totalItems = 0;\n    vector<int> src, weights, dest, itemPos;\n    vector<vector<int>> binItems;\n    vector<long long> cap, sum, rem;\n    vector<char> locked;\n    long long penalty = 0;\n\n    void setup(int n, const vector<int> &supply, const vector<int> &demand) {\n        N = n;\n        totalItems = 2 * N;\n        src.resize(totalItems);\n        weights.resize(totalItems);\n        dest.assign(totalItems, -1);\n        itemPos.assign(totalItems, -1);\n        binItems.assign(N, {});\n        cap.resize(N);\n        sum.assign(N, 0);\n        rem.assign(N, 0);\n        locked.assign(totalItems, 0);\n        penalty = 0;\n        for (int i = 0; i < N; ++i) {\n            long long w = i < (int)supply.size() ? supply[i] : 0;\n            if (w < 0) w = 0;\n            src[2 * i] = src[2 * i + 1] = i;\n            weights[2 * i] = weights[2 * i + 1] = (int)w;\n            long long tgt = i < (int)demand.size() ? demand[i] : 0;\n            if (tgt < 0) tgt = 0;\n            cap[i] = 2LL * tgt;\n            rem[i] = cap[i];\n        }\n    }\n};\n\nvoid initialAssign(AssignState &st, mt19937 &rng) {\n    for (int j = 0; j < st.N; ++j) {\n        st.binItems[j].clear();\n        st.sum[j] = 0;\n        st.rem[j] = st.cap[j];\n    }\n    fill(st.dest.begin(), st.dest.end(), -1);\n    fill(st.itemPos.begin(), st.itemPos.end(), -1);\n    fill(st.locked.begin(), st.locked.end(), 0);\n    vector<int> order(st.totalItems);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), rng);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (st.weights[a] != st.weights[b]) return st.weights[a] > st.weights[b];\n        return a < b;\n    });\n    priority_queue<pair<long long, int>> pq;\n    for (int j = 0; j < st.N; ++j) pq.push({st.rem[j], j});\n    auto popValid = [&]() {\n        while (true) {\n            auto [val, idx] = pq.top();\n            pq.pop();\n            if (val == st.rem[idx]) return idx;\n        }\n    };\n    for (int item : order) {\n        int bin = popValid();\n        st.dest[item] = bin;\n        st.itemPos[item] = st.binItems[bin].size();\n        st.binItems[bin].push_back(item);\n        st.sum[bin] += st.weights[item];\n        st.rem[bin] = st.cap[bin] - st.sum[bin];\n        pq.push({st.rem[bin], bin});\n    }\n    st.penalty = 0;\n    for (int j = 0; j < st.N; ++j) st.penalty += llabs(st.rem[j]);\n}\n\nlong long penaltyDelta(const AssignState &st, int item, int newBin) {\n    int oldBin = st.dest[item];\n    if (oldBin == newBin) return 0;\n    long long w = st.weights[item];\n    long long before = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n    long long after = llabs(st.rem[oldBin] + w) + llabs(st.rem[newBin] - w);\n    return after - before;\n}\n\nvoid moveItem(AssignState &st, int item, int newBin) {\n    int oldBin = st.dest[item];\n    if (oldBin == newBin) return;\n    long long w = st.weights[item];\n    long long oldContribution = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n\n    int pos = st.itemPos[item];\n    int last = st.binItems[oldBin].back();\n    st.binItems[oldBin][pos] = last;\n    st.itemPos[last] = pos;\n    st.binItems[oldBin].pop_back();\n\n    st.sum[oldBin] -= w;\n    st.rem[oldBin] += w;\n\n    st.sum[newBin] += w;\n    st.rem[newBin] -= w;\n\n    st.itemPos[item] = st.binItems[newBin].size();\n    st.binItems[newBin].push_back(item);\n    st.dest[item] = newBin;\n\n    long long newContribution = llabs(st.rem[oldBin]) + llabs(st.rem[newBin]);\n    st.penalty += newContribution - oldContribution;\n}\n\nvoid balance(AssignState &st, bool respectLocked,\n             const chrono::steady_clock::time_point &start, double limitTime) {\n    while (true) {\n        if (elapsedSec(start) > limitTime) break;\n        vector<int> posBins;\n        for (int j = 0; j < st.N; ++j) if (st.rem[j] > 0) posBins.push_back(j);\n        if (posBins.empty()) break;\n        sort(posBins.begin(), posBins.end(),\n             [&](int a, int b) { return st.rem[a] > st.rem[b]; });\n        bool moved = false;\n        for (int pos : posBins) {\n            long long remPos = st.rem[pos];\n            long long bestDiff = 0;\n            int bestItem = -1;\n            for (int neg = 0; neg < st.N; ++neg) {\n                if (st.rem[neg] >= 0) continue;\n                long long remNeg = st.rem[neg];\n                for (int item : st.binItems[neg]) {\n                    if (respectLocked && st.locked[item]) continue;\n                    long long w = st.weights[item];\n                    long long newPos = remPos - w;\n                    long long newNeg = remNeg + w;\n                    long long diff = llabs(newPos) + llabs(newNeg)\n                                   - (llabs(remPos) + llabs(remNeg));\n                    if (diff < bestDiff) {\n                        bestDiff = diff;\n                        bestItem = item;\n                    }\n                }\n            }\n            if (bestItem != -1) {\n                moveItem(st, bestItem, pos);\n                moved = true;\n                break;\n            }\n        }\n        if (!moved) break;\n    }\n}\n\nvoid randomImprove(AssignState &st, bool respectLocked, int maxIter,\n                   const chrono::steady_clock::time_point &start,\n                   double limitTime, mt19937 &rng) {\n    for (int iter = 0; iter < maxIter; ++iter) {\n        if ((iter & 511) == 0 && elapsedSec(start) > limitTime) break;\n        int item = rng() % st.totalItems;\n        if (respectLocked) {\n            int tries = 0;\n            while (tries < 30 && st.locked[item]) {\n                item = rng() % st.totalItems;\n                ++tries;\n            }\n            if (st.locked[item]) continue;\n        }\n        int from = st.dest[item];\n        int bestBin = -1;\n        long long bestDelta = 0;\n        for (int attempt = 0; attempt < 6; ++attempt) {\n            int cand = rng() % st.N;\n            if (cand == from) continue;\n            long long delta = penaltyDelta(st, item, cand);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestBin = cand;\n            }\n        }\n        if (bestBin == -1) continue;\n        moveItem(st, item, bestBin);\n    }\n}\n\nstruct SCCResult {\n    vector<int> comp;\n    int cnt;\n};\n\nSCCResult computeSCC(const vector<int> &a, const vector<int> &b) {\n    int N = a.size();\n    vector<vector<int>> g(N), gr(N);\n    for (int i = 0; i < N; ++i) {\n        g[i].push_back(a[i]);\n        g[i].push_back(b[i]);\n        gr[a[i]].push_back(i);\n        gr[b[i]].push_back(i);\n    }\n    vector<int> used(N, 0), order;\n    auto dfs1 = [&](auto self, int v) -> void {\n        used[v] = 1;\n        for (int to : g[v]) if (!used[to]) self(self, to);\n        order.push_back(v);\n    };\n    for (int i = 0; i < N; ++i) if (!used[i]) dfs1(dfs1, i);\n    vector<int> comp(N, -1);\n    int compId = 0;\n    auto dfs2 = [&](auto self, int v) -> void {\n        comp[v] = compId;\n        for (int to : gr[v]) if (comp[to] == -1) self(self, to);\n    };\n    for (int i = N - 1; i >= 0; --i) {\n        int v = order[i];\n        if (comp[v] == -1) {\n            dfs2(dfs2, v);\n            ++compId;\n        }\n    }\n    return {comp, compId};\n}\n\nint ensureConnectivity(AssignState &st,\n                       const chrono::steady_clock::time_point &start,\n                       double limitTime) {\n    vector<int> a(st.N), b(st.N);\n    for (int i = 0; i < st.N; ++i) {\n        a[i] = st.dest[2 * i];\n        b[i] = st.dest[2 * i + 1];\n    }\n    auto scc = computeSCC(a, b);\n    int K = scc.cnt;\n    if (K == 1) return 0;\n    vector<vector<int>> nodesIn(K);\n    for (int i = 0; i < st.N; ++i) nodesIn[scc.comp[i]].push_back(i);\n    vector<int> order(K);\n    iota(order.begin(), order.end(), 0);\n    int lockedAdded = 0;\n    for (int idx = 0; idx < K; ++idx) {\n        if (elapsedSec(start) > limitTime) break;\n        int fromC = order[idx];\n        int toC = order[(idx + 1) % K];\n        vector<int> existing;\n        for (int node : nodesIn[fromC]) {\n            for (int t = 0; t < 2; ++t) {\n                int item = 2 * node + t;\n                if (st.dest[item] >= 0 && scc.comp[st.dest[item]] == toC) {\n                    existing.push_back(item);\n                }\n            }\n        }\n        if (!existing.empty()) {\n            int bestEdge = existing[0];\n            for (int item : existing) {\n                if (st.weights[item] < st.weights[bestEdge]) bestEdge = item;\n            }\n            st.locked[bestEdge] = 1;\n            ++lockedAdded;\n            continue;\n        }\n        long long bestDelta = (1LL << 60);\n        int bestEdge = -1, bestDest = -1;\n        for (int node : nodesIn[fromC]) {\n            for (int t = 0; t < 2; ++t) {\n                int item = 2 * node + t;\n                if (st.locked[item]) continue;\n                for (int destNode : nodesIn[toC]) {\n                    long long delta = penaltyDelta(st, item, destNode);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestEdge = item;\n                        bestDest = destNode;\n                    }\n                }\n            }\n        }\n        if (bestEdge == -1) continue;\n        moveItem(st, bestEdge, bestDest);\n        st.locked[bestEdge] = 1;\n        ++lockedAdded;\n    }\n    return lockedAdded;\n}\n\nlong long simulatePlan(const vector<int> &a, const vector<int> &b, int L,\n                       const vector<int> &target, vector<int> &cnt) {\n    int N = a.size();\n    if ((int)cnt.size() != N) cnt.assign(N, 0);\n    else fill(cnt.begin(), cnt.end(), 0);\n    int cur = 0;\n    cnt[cur] = 1;\n    for (int step = 1; step < L; ++step) {\n        bool odd = cnt[cur] & 1;\n        int nxt = odd ? a[cur] : b[cur];\n        cur = nxt;\n        cnt[cur]++;\n    }\n    long long err = 0;\n    for (int i = 0; i < N; ++i) err += llabs(1LL * cnt[i] - target[i]);\n    return err;\n}\n\nstruct SimDetail {\n    vector<int> cnt, oddUse, evenUse;\n    long long err;\n};\n\nSimDetail simulateDetailed(const vector<int> &a, const vector<int> &b, int L,\n                           const vector<int> &target) {\n    int N = a.size();\n    SimDetail res;\n    res.cnt.assign(N, 0);\n    res.oddUse.assign(N, 0);\n    res.evenUse.assign(N, 0);\n    int cur = 0;\n    res.cnt[cur] = 1;\n    for (int step = 1; step < L; ++step) {\n        bool odd = res.cnt[cur] & 1;\n        if (odd) res.oddUse[cur]++;\n        else res.evenUse[cur]++;\n        int nxt = odd ? a[cur] : b[cur];\n        cur = nxt;\n        res.cnt[cur]++;\n    }\n    long long err = 0;\n    for (int i = 0; i < N; ++i) err += llabs(1LL * res.cnt[i] - target[i]);\n    res.err = err;\n    return res;\n}\n\nvoid localSearch(vector<int> &a, vector<int> &b, const vector<int> &target, int L,\n                 const chrono::steady_clock::time_point &start, double limitTime,\n                 mt19937 &rng) {\n    int N = a.size();\n    if (N == 0) return;\n    if (elapsedSec(start) >= limitTime) return;\n\n    vector<int> curCnt(N), bestCnt(N), testCnt(N), diff(N);\n    long long curErr = simulatePlan(a, b, L, target, curCnt);\n    long long bestErr = curErr;\n    bestCnt = curCnt;\n    vector<int> bestA = a, bestB = b;\n\n    auto refreshDiff = [&]() {\n        for (int i = 0; i < N; ++i) diff[i] = curCnt[i] - target[i];\n    };\n    refreshDiff();\n    if (bestErr == 0) {\n        a = bestA;\n        b = bestB;\n        return;\n    }\n\n    while (elapsedSec(start) < limitTime) {\n        vector<int> over, under;\n        for (int i = 0; i < N; ++i) {\n            if (diff[i] > 0) over.push_back(i);\n            else if (diff[i] < 0) under.push_back(i);\n        }\n        if (over.empty() || under.empty()) break;\n\n        int destOver;\n        if ((rng() & 7) != 0) {\n            destOver = over[0];\n            for (int idx : over) if (diff[idx] > diff[destOver]) destOver = idx;\n        } else destOver = over[rng() % over.size()];\n\n        int destUnder;\n        if ((rng() & 7) != 0) {\n            destUnder = under[0];\n            for (int idx : under) if (diff[idx] < diff[destUnder]) destUnder = idx;\n        } else destUnder = under[rng() % under.size()];\n\n        vector<pair<int, int>> edges;\n        for (int u = 0; u < N; ++u) {\n            if (a[u] == destOver) edges.emplace_back(u, 0);\n            if (b[u] == destOver) edges.emplace_back(u, 1);\n        }\n        if (edges.empty()) {\n            edges.emplace_back(destOver, 0);\n            edges.emplace_back(destOver, 1);\n        }\n\n        pair<int, int> chosen = edges[rng() % edges.size()];\n        if ((rng() & 3) != 0) {\n            pair<int, int> bestEdge = edges[0];\n            int bestVal = diff[bestEdge.first];\n            for (auto &e : edges) {\n                if (diff[e.first] > bestVal) {\n                    bestVal = diff[e.first];\n                    bestEdge = e;\n                }\n            }\n            chosen = bestEdge;\n        }\n\n        int src = chosen.first;\n        int which = chosen.second;\n        int oldDest = (which == 0) ? a[src] : b[src];\n        if (oldDest == destUnder) continue;\n\n        if (which == 0) a[src] = destUnder;\n        else b[src] = destUnder;\n\n        long long newErr = simulatePlan(a, b, L, target, testCnt);\n        if (newErr <= curErr) {\n            curErr = newErr;\n            curCnt = testCnt;\n            refreshDiff();\n            if (newErr < bestErr) {\n                bestErr = newErr;\n                bestA = a;\n                bestB = b;\n                bestCnt = testCnt;\n                if (bestErr == 0) break;\n            }\n        } else {\n            if (which == 0) a[src] = oldDest;\n            else b[src] = oldDest;\n        }\n\n        if (elapsedSec(start) >= limitTime) break;\n    }\n    a = bestA;\n    b = bestB;\n}\n\nstruct AttemptResult {\n    vector<int> a, b, counts;\n    long long err = (1LL << 60);\n    long long weightPenalty = (1LL << 60);\n};\n\nAttemptResult runAttempt(const vector<int> &supply, const vector<int> &demand,\n                         const vector<int> &target,\n                         const chrono::steady_clock::time_point &start,\n                         double limitTime, int L, uint64_t seed) {\n    AttemptResult res;\n    int N = supply.size();\n    AssignState st;\n    st.setup(N, supply, demand);\n    mt19937 rng(seed);\n\n    initialAssign(st, rng);\n    balance(st, false, start, limitTime);\n    randomImprove(st, false, 200000, start, limitTime, rng);\n    balance(st, false, start, limitTime);\n\n    ensureConnectivity(st, start, limitTime);\n    balance(st, true, start, limitTime);\n    randomImprove(st, true, 120000, start, limitTime, rng);\n    balance(st, true, start, limitTime);\n\n    vector<int> a(N), b(N);\n    for (int i = 0; i < N; ++i) {\n        int da = st.dest[2 * i];\n        int db = st.dest[2 * i + 1];\n        if (da < 0 || da >= N) da = i;\n        if (db < 0 || db >= N) db = i;\n        a[i] = da;\n        b[i] = db;\n    }\n    vector<int> cnt(N);\n    long long err = simulatePlan(a, b, L, target, cnt);\n    res.a = move(a);\n    res.b = move(b);\n    res.counts = move(cnt);\n    res.err = err;\n    res.weightPenalty = st.penalty;\n    return res;\n}\n\nvector<int> buildAdjustedDemand(const vector<int> &base,\n                                const vector<int> &counts,\n                                long long bestErr, int L) {\n    int N = base.size();\n    vector<int> demand(N);\n    double scale = min(1.0, max(0.0, bestErr / 65000.0));\n    double beta = 0.55 + 0.35 * scale;\n    long long total = 0;\n    for (int i = 0; i < N; ++i) {\n        long long diff = (long long)counts[i] - base[i];\n        long long val = llround((double)base[i] - beta * diff);\n        val = max(0LL, min((long long)L, val));\n        demand[i] = (int)val;\n        total += val;\n    }\n    long long gap = (long long)L - total;\n    if (gap > 0) {\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int i, int j) {\n            long long di = (long long)counts[i] - base[i];\n            long long dj = (long long)counts[j] - base[j];\n            if (di != dj) return di < dj;\n            return i < j;\n        });\n        for (int idx : order) {\n            if (gap == 0) break;\n            long long cap = (long long)L - demand[idx];\n            long long add = min(cap, gap);\n            demand[idx] += (int)add;\n            gap -= add;\n        }\n    } else if (gap < 0) {\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int i, int j) {\n            long long di = (long long)counts[i] - base[i];\n            long long dj = (long long)counts[j] - base[j];\n            if (di != dj) return di > dj;\n            return i < j;\n        });\n        gap = -gap;\n        for (int idx : order) {\n            if (gap == 0) break;\n            long long cap = demand[idx];\n            long long remv = min(cap, gap);\n            demand[idx] -= (int)remv;\n            gap -= remv;\n        }\n    }\n    return demand;\n}\n\nvoid usageGuidedImprove(vector<int> &a, vector<int> &b,\n                        vector<int> &counts,\n                        vector<int> &oddUse,\n                        vector<int> &evenUse,\n                        long long &bestErr,\n                        const vector<int> &target, int L,\n                        const chrono::steady_clock::time_point &start,\n                        double limitTime, mt19937 &rng) {\n    while (elapsedSec(start) < limitTime) {\n        int N = a.size();\n        vector<long long> diff(N);\n        vector<int> under;\n        bool hasOver = false;\n        for (int i = 0; i < N; ++i) {\n            diff[i] = (long long)counts[i] - target[i];\n            if (diff[i] > 0) hasOver = true;\n            else if (diff[i] < 0) under.push_back(i);\n        }\n        if (!hasOver || under.empty()) break;\n        sort(under.begin(), under.end(), [&](int i, int j) {\n            if (diff[i] != diff[j]) return diff[i] < diff[j];\n            return i < j;\n        });\n\n        struct EdgeInfo { int u, parity; long long usage; };\n        vector<EdgeInfo> edges;\n        edges.reserve(2 * N);\n        for (int i = 0; i < N; ++i) {\n            if (oddUse[i] > 0) edges.push_back({i, 0, oddUse[i]});\n            if (evenUse[i] > 0) edges.push_back({i, 1, evenUse[i]});\n        }\n        if (edges.empty()) break;\n        sort(edges.begin(), edges.end(),\n             [](const EdgeInfo &x, const EdgeInfo &y) {\n                 if (x.usage != y.usage) return x.usage > y.usage;\n                 if (x.u != y.u) return x.u < y.u;\n                 return x.parity < y.parity;\n             });\n\n        bool improved = false;\n        for (const auto &edge : edges) {\n            if (elapsedSec(start) >= limitTime) break;\n            if (edge.usage == 0) break;\n            int currentDest = (edge.parity == 0) ? a[edge.u] : b[edge.u];\n            if (diff[currentDest] <= 0) continue;\n\n            vector<int> candidates;\n            int top = min(4, (int)under.size());\n            for (int i = 0; i < top; ++i) candidates.push_back(under[i]);\n            if ((int)under.size() > top) {\n                candidates.push_back(under[top + rng() % (under.size() - top)]);\n            }\n            shuffle(candidates.begin(), candidates.end(), rng);\n            for (int cand : candidates) {\n                if (cand == currentDest) continue;\n                int oldDest = currentDest;\n                if (edge.parity == 0) a[edge.u] = cand;\n                else b[edge.u] = cand;\n                SimDetail detail = simulateDetailed(a, b, L, target);\n                if (detail.err <= bestErr) {\n                    bestErr = detail.err;\n                    counts = detail.cnt;\n                    oddUse = detail.oddUse;\n                    evenUse = detail.evenUse;\n                    improved = true;\n                    break;\n                } else {\n                    if (edge.parity == 0) a[edge.u] = oldDest;\n                    else b[edge.u] = oldDest;\n                }\n                if (elapsedSec(start) >= limitTime) break;\n            }\n            if (improved) break;\n        }\n        if (!improved) break;\n    }\n}\n\nvoid finalTweak(vector<int> &a, vector<int> &b, vector<int> &counts,\n                long long &bestErr, const vector<int> &target, int L,\n                const chrono::steady_clock::time_point &start,\n                double limitTime, mt19937 &rng) {\n    vector<int> testCnt(a.size());\n    while (elapsedSec(start) < limitTime) {\n        vector<int> diff(a.size());\n        vector<int> over, under;\n        for (int i = 0; i < (int)a.size(); ++i) {\n            diff[i] = counts[i] - target[i];\n            if (diff[i] > 0) over.push_back(i);\n            else if (diff[i] < 0) under.push_back(i);\n        }\n        if (over.empty() || under.empty()) break;\n        int from = over[rng() % over.size()];\n        vector<pair<int, int>> edges;\n        for (int u = 0; u < (int)a.size(); ++u) {\n            if (a[u] == from) edges.emplace_back(u, 0);\n            if (b[u] == from) edges.emplace_back(u, 1);\n        }\n        if (edges.empty()) {\n            edges.emplace_back(from, 0);\n            edges.emplace_back(from, 1);\n        }\n        auto edge = edges[rng() % edges.size()];\n        int dest = under[rng() % under.size()];\n        int src = edge.first;\n        int which = edge.second;\n        int oldDest = (which == 0) ? a[src] : b[src];\n        if (oldDest == dest) continue;\n        if (which == 0) a[src] = dest;\n        else b[src] = dest;\n        long long newErr = simulatePlan(a, b, L, target, testCnt);\n        if (newErr <= bestErr) {\n            bestErr = newErr;\n            counts = testCnt;\n        } else {\n            if (which == 0) a[src] = oldDest;\n            else b[src] = oldDest;\n        }\n        if (bestErr == 0) break;\n    }\n}\n\nvoid pairSwapImprove(vector<int> &a, vector<int> &b, vector<int> &counts,\n                     long long &bestErr, const vector<int> &target, int L,\n                     const chrono::steady_clock::time_point &start,\n                     double limitTime, mt19937 &rng) {\n    int N = a.size();\n    vector<int> temp(N);\n    while (elapsedSec(start) < limitTime) {\n        int u1 = rng() % N;\n        int p1 = rng() & 1;\n        int u2 = rng() % N;\n        int p2 = rng() & 1;\n        if (u1 == u2 && p1 == p2) continue;\n        int &d1 = (p1 == 0 ? a[u1] : b[u1]);\n        int &d2 = (p2 == 0 ? a[u2] : b[u2]);\n        if (d1 == d2) continue;\n        swap(d1, d2);\n        long long err = simulatePlan(a, b, L, target, temp);\n        if (err <= bestErr) {\n            bestErr = err;\n            counts = temp;\n        } else {\n            swap(d1, d2);\n        }\n        if (bestErr == 0) break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\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    auto start = chrono::steady_clock::now();\n    const double TOTAL_LIMIT = 1.95;\n    const double FINAL_RESERVE = 0.005;\n    const double PAIR_WINDOW = 0.05;\n    const double TWEEK_WINDOW = 0.04;\n    const double USAGE_WINDOW = 0.09;\n\n    double attemptWindow = TOTAL_LIMIT - (USAGE_WINDOW + TWEEK_WINDOW + PAIR_WINDOW + FINAL_RESERVE);\n    attemptWindow = max(0.55, min(attemptWindow, TOTAL_LIMIT - FINAL_RESERVE - 0.02));\n\n    vector<double> attemptLimits;\n    double first = min(0.75, attemptWindow);\n    attemptLimits.push_back(first);\n    if (attemptWindow - first > 0.20)\n        attemptLimits.push_back(attemptWindow);\n    else if (attemptWindow - first > 0.05)\n        attemptLimits.push_back(attemptWindow);\n\n    mt19937 baseRng(chrono::steady_clock::now().time_since_epoch().count());\n    auto nextSeed = [&]() -> uint64_t {\n        return ((uint64_t)baseRng() << 32) ^ baseRng() ^\n               chrono::steady_clock::now().time_since_epoch().count();\n    };\n\n    vector<int> baseDemand = T;\n    vector<int> bestA(N), bestB(N), bestCounts(N, 0);\n    long long bestErr = (1LL << 60), bestPenalty = (1LL << 60);\n    bool haveBest = false;\n\n    for (size_t idx = 0; idx < attemptLimits.size(); ++idx) {\n        double limit = min(attemptLimits[idx], TOTAL_LIMIT - FINAL_RESERVE - 0.02);\n        if (elapsedSec(start) >= limit - 0.01) continue;\n        vector<int> demandUse = baseDemand;\n        bool useAdjusted =\n            haveBest && (bestErr > 52000 || (bestErr > 36000 && idx + 1 == attemptLimits.size()));\n        if (useAdjusted) demandUse = buildAdjustedDemand(baseDemand, bestCounts, bestErr, L);\n\n        uint64_t seed = nextSeed() ^ (0x9e3779b97f4a7c15ULL * (idx + 1));\n        AttemptResult res = runAttempt(T, demandUse, T, start, limit, L, seed);\n        if (!haveBest || res.err < bestErr ||\n            (res.err == bestErr && res.weightPenalty < bestPenalty)) {\n            bestA = res.a;\n            bestB = res.b;\n            bestCounts = res.counts;\n            bestErr = res.err;\n            bestPenalty = res.weightPenalty;\n            haveBest = true;\n        }\n        if (elapsedSec(start) > attemptWindow + 0.05) break;\n    }\n\n    if (!haveBest) {\n        uint64_t seed = nextSeed();\n        double fallbackLimit = min(TOTAL_LIMIT - FINAL_RESERVE - 0.05,\n                                   TOTAL_LIMIT - FINAL_RESERVE - 0.01);\n        AttemptResult res = runAttempt(T, baseDemand, T, start, fallbackLimit, L, seed);\n        bestA = res.a;\n        bestB = res.b;\n        bestCounts = res.counts;\n        bestErr = res.err;\n        bestPenalty = res.weightPenalty;\n        haveBest = true;\n    }\n\n    double lsLimit = TOTAL_LIMIT - (USAGE_WINDOW + TWEEK_WINDOW + PAIR_WINDOW + FINAL_RESERVE);\n    if (lsLimit > elapsedSec(start) + 0.01) {\n        localSearch(bestA, bestB, T, L, start, lsLimit, baseRng);\n        vector<int> cnt(N);\n        bestErr = simulatePlan(bestA, bestB, L, T, cnt);\n        bestCounts = cnt;\n    }\n\n    vector<int> oddUse, evenUse;\n    double usageLimit = TOTAL_LIMIT - (TWEEK_WINDOW + PAIR_WINDOW + FINAL_RESERVE);\n    if (usageLimit > elapsedSec(start) + 0.01) {\n        SimDetail detail = simulateDetailed(bestA, bestB, L, T);\n        bestCounts = detail.cnt;\n        oddUse = detail.oddUse;\n        evenUse = detail.evenUse;\n        bestErr = detail.err;\n        usageGuidedImprove(bestA, bestB, bestCounts, oddUse, evenUse,\n                           bestErr, T, L, start, usageLimit, baseRng);\n    }\n\n    double tweakLimit = TOTAL_LIMIT - (PAIR_WINDOW + FINAL_RESERVE);\n    if (tweakLimit > elapsedSec(start) + 0.005) {\n        finalTweak(bestA, bestB, bestCounts, bestErr, T, L, start, tweakLimit, baseRng);\n    }\n\n    double pairLimit = TOTAL_LIMIT - FINAL_RESERVE;\n    if (pairLimit > elapsedSec(start) + 0.002) {\n        pairSwapImprove(bestA, bestB, bestCounts, bestErr, T, L, start, pairLimit, baseRng);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << bestA[i] << ' ' << bestB[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\n// ---------- Geometry & MST helpers ----------\nlong long hilbertOrder(long long x, long long y, int pow = 15, int rot = 0) {\n    if (pow == 0) return 0;\n    long long h = 1LL << (pow - 1);\n    long long seg = ((x < h) ? 0 : 1) | ((y < h) ? 0 : 2);\n    seg = (seg + rot) & 3;\n    static const int rotateDelta[4] = {3, 0, 0, 1};\n    long long nx = x & (h - 1);\n    long long ny = y & (h - 1);\n    int nrot = (rot + rotateDelta[seg]) & 3;\n    long long subSize = 1LL << (2 * pow - 2);\n    long long add = hilbertOrder(nx, ny, pow - 1, nrot);\n    if (seg == 1 || seg == 2) {\n        return seg * subSize + add;\n    } else {\n        return seg * subSize + (subSize - add - 1);\n    }\n}\n\nvector<int> build_global_parent(const vector<double>& px, const vector<double>& py) {\n    int n = (int)px.size();\n    const double INF = 1e100;\n    vector<double> best(n, INF);\n    vector<int> parent(n, -1);\n    vector<char> used(n, 0);\n    best[0] = 0.0;\n    for (int it = 0; it < n; ++it) {\n        int v = -1;\n        double bv = INF;\n        for (int i = 0; i < n; ++i)\n            if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n        if (v == -1) break;\n        used[v] = 1;\n        for (int u = 0; u < n; ++u) if (!used[u]) {\n            double dx = px[v] - px[u];\n            double dy = py[v] - py[u];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[u]) {\n                best[u] = dist;\n                parent[u] = v;\n            }\n        }\n    }\n    for (int i = 1; i < n; ++i) if (parent[i] == -1) parent[i] = 0;\n    return parent;\n}\n\ndouble group_cost(const vector<int>& nodes, const vector<double>& px, const vector<double>& py) {\n    int k = (int)nodes.size();\n    if (k <= 1) return 0.0;\n    static vector<double> best;\n    static vector<char> used;\n    best.assign(k, 1e100);\n    used.assign(k, 0);\n    best[0] = 0.0;\n    double total = 0.0;\n    for (int iter = 0; iter < k; ++iter) {\n        int v = -1;\n        double bv = 1e100;\n        for (int i = 0; i < k; ++i)\n            if (!used[i] && best[i] < bv) { bv = best[i]; v = i; }\n        if (v == -1) break;\n        used[v] = 1;\n        if (iter > 0) total += sqrt(max(0.0, bv));\n        for (int j = 0; j < k; ++j) if (!used[j]) {\n            double dx = px[nodes[v]] - px[nodes[j]];\n            double dy = py[nodes[v]] - py[nodes[j]];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[j]) best[j] = dist;\n        }\n    }\n    return total;\n}\n\nvector<pair<int,int>> build_group_mst(const vector<int>& nodes,\n                                      const vector<double>& px,\n                                      const vector<double>& py) {\n    int k = (int)nodes.size();\n    vector<pair<int,int>> edges;\n    if (k <= 1) return edges;\n    vector<double> best(k, 1e100);\n    vector<int> parent(k, -1);\n    vector<char> used(k, 0);\n    best[0] = 0.0;\n    for (int iter = 0; iter < k; ++iter) {\n        int v = -1;\n        double bv = 1e100;\n        for (int i = 0; i < k; ++i)\n            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[v], nodes[parent[v]]);\n        for (int j = 0; j < k; ++j) if (!used[j]) {\n            double dx = px[nodes[v]] - px[nodes[j]];\n            double dy = py[nodes[v]] - py[nodes[j]];\n            double dist = dx * dx + dy * dy;\n            if (dist < best[j]) {\n                best[j] = dist;\n                parent[j] = v;\n            }\n        }\n    }\n    if ((int)edges.size() != k - 1) {\n        edges.clear();\n        for (int i = 1; i < k; ++i)\n            edges.emplace_back(nodes[i - 1], nodes[i]);\n    }\n    return edges;\n}\n\n// ---------- Pair helpers ----------\ndouble pair_sequence_cost(const vector<int>& ord,\n                          const vector<double>& px,\n                          const vector<double>& py) {\n    double sum = 0.0;\n    for (size_t i = 0; i + 1 < ord.size(); i += 2) {\n        int a = ord[i], b = ord[i + 1];\n        double dx = px[a] - px[b];\n        double dy = py[a] - py[b];\n        sum += sqrt(max(0.0, dx * dx + dy * dy));\n    }\n    return sum;\n}\n\nvector<int> best_pair_sequence(vector<int> nodes,\n                               const vector<double>& px,\n                               const vector<double>& py,\n                               const vector<long long>& hilb,\n                               uint64_t key) {\n    if (nodes.empty()) return nodes;\n    if (nodes.size() % 2) nodes.pop_back();\n    vector<int> best = nodes;\n    double bestCost = pair_sequence_cost(best, px, py);\n    auto try_order = [&](vector<int> cand) {\n        if (cand.size() != nodes.size()) return;\n        double cost = pair_sequence_cost(cand, px, py);\n        if (cost + 1e-9 < bestCost) {\n            bestCost = cost;\n            best = std::move(cand);\n        }\n    };\n\n    vector<int> tmp;\n\n    tmp = nodes;\n    sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n        if (px[a] != px[b]) return px[a] < px[b];\n        return a < b;\n    });\n    try_order(tmp);\n\n    tmp = nodes;\n    sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n        if (py[a] != py[b]) return py[a] < py[b];\n        return a < b;\n    });\n    try_order(tmp);\n\n    tmp = nodes;\n    sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n        if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n        return a < b;\n    });\n    try_order(tmp);\n\n    tmp = nodes;\n    sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n        double va = px[a] + py[a];\n        double vb = px[b] + py[b];\n        if (va != vb) return va < vb;\n        return a < b;\n    });\n    try_order(tmp);\n\n    tmp = nodes;\n    sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n        double va = px[a] - py[a];\n        double vb = px[b] - py[b];\n        if (va != vb) return va < vb;\n        return a < b;\n    });\n    try_order(tmp);\n\n    tmp.clear();\n    {\n        vector<int> rem = nodes;\n        while (rem.size() >= 2) {\n            int a = rem.back();\n            rem.pop_back();\n            int bestIdx = 0;\n            double bestDist = 1e100;\n            for (int i = 0; i < (int)rem.size(); ++i) {\n                int b = rem[i];\n                double dx = px[a] - px[b];\n                double dy = py[a] - py[b];\n                double dist = dx * dx + dy * dy;\n                if (dist < bestDist) {\n                    bestDist = dist;\n                    bestIdx = i;\n                }\n            }\n            int b = rem[bestIdx];\n            rem.erase(rem.begin() + bestIdx);\n            tmp.push_back(a);\n            tmp.push_back(b);\n        }\n        if (tmp.size() == nodes.size()) try_order(tmp);\n    }\n\n    mt19937 rng_local((uint32_t)(key ^ 0x9e3779b97f4a7c15ULL));\n    tmp = nodes;\n    for (int t = 0; t < 4; ++t) {\n        shuffle(tmp.begin(), tmp.end(), rng_local);\n        try_order(tmp);\n    }\n\n    return best;\n}\n\nvoid improve_pairs(vector<vector<int>>& groups,\n                   const vector<int>& sizeOrder,\n                   const vector<double>& px,\n                   const vector<double>& py,\n                   const vector<long long>& hilb,\n                   uint64_t key) {\n    vector<int> idx;\n    vector<int> nodes;\n    for (int i = 0; i < (int)groups.size(); ++i) {\n        if ((int)groups[i].size() == 2 && sizeOrder[i] == 2) {\n            idx.push_back(i);\n            nodes.push_back(groups[i][0]);\n            nodes.push_back(groups[i][1]);\n        }\n    }\n    if (idx.empty()) return;\n    double curCost = pair_sequence_cost(nodes, px, py);\n    vector<int> bestOrder = best_pair_sequence(nodes, px, py, hilb, key ^ 0xabcdef123456789ULL);\n    double bestCost = pair_sequence_cost(bestOrder, px, py);\n    if (bestCost + 1e-9 >= curCost) return;\n    for (size_t t = 0; t < idx.size(); ++t) {\n        groups[idx[t]][0] = bestOrder[2 * t];\n        groups[idx[t]][1] = bestOrder[2 * t + 1];\n    }\n}\n\n// ---------- Group builders ----------\nbool build_groups_contiguous(const vector<int>& ord, const vector<int>& sizes,\n                             vector<vector<int>>& groups) {\n    int M = sizes.size();\n    groups.assign(M, {});\n    size_t pos = 0;\n    for (int i = 0; i < M; ++i) {\n        int need = sizes[i];\n        if (need < 0 || pos + need > ord.size()) return false;\n        groups[i].assign(ord.begin() + pos, ord.begin() + pos + need);\n        pos += need;\n    }\n    return pos == ord.size();\n}\n\nbool build_groups_greedy(const vector<int>& prefer, int offset,\n                         const vector<int>& sizes,\n                         vector<vector<int>>& groups,\n                         const vector<double>& px,\n                         const vector<double>& py) {\n    int N = prefer.size();\n    int M = sizes.size();\n    if (N == 0) return false;\n    vector<int> order(N);\n    for (int i = 0; i < N; ++i) order[i] = prefer[(i + offset) % N];\n    vector<char> used(N, 0);\n    int ptr = 0;\n    auto pick_seed = [&]() -> int {\n        for (int iter = 0; iter < N; ++iter) {\n            int idx = order[ptr];\n            ptr++;\n            if (ptr == N) ptr = 0;\n            if (!used[idx]) return idx;\n        }\n        for (int idx = 0; idx < N; ++idx)\n            if (!used[idx]) return idx;\n        return -1;\n    };\n    groups.assign(M, {});\n    for (int gi = 0; gi < M; ++gi) {\n        int need = sizes[gi];\n        if (need <= 0) return false;\n        int seed = pick_seed();\n        if (seed == -1) return false;\n        vector<int> grp;\n        grp.reserve(need);\n        used[seed] = 1;\n        grp.push_back(seed);\n        double cx = px[seed], cy = py[seed];\n        while ((int)grp.size() < need) {\n            int best = -1;\n            double bestDist = 1e100;\n            for (int city = 0; city < N; ++city) if (!used[city]) {\n                double dx = px[city] - cx;\n                double dy = py[city] - cy;\n                double dist = dx * dx + dy * dy;\n                if (dist < bestDist) {\n                    bestDist = dist;\n                    best = city;\n                }\n            }\n            if (best == -1) return false;\n            used[best] = 1;\n            grp.push_back(best);\n            double sz = grp.size();\n            cx = (cx * (sz - 1) + px[best]) / sz;\n            cy = (cy * (sz - 1) + py[best]) / sz;\n        }\n        groups[gi] = std::move(grp);\n    }\n    return true;\n}\n\nbool build_groups_two_phase(const vector<int>& prefer, int offset,\n                            const vector<int>& sizes,\n                            vector<vector<int>>& groups,\n                            const vector<double>& px,\n                            const vector<double>& py,\n                            const vector<long long>& hilb,\n                            uint64_t key) {\n    int N = prefer.size();\n    int M = sizes.size();\n    if (N == 0) return false;\n    vector<int> order(N);\n    for (int i = 0; i < N; ++i) order[i] = prefer[(i + offset) % N];\n    vector<char> used(N, 0);\n    groups.assign(M, {});\n    vector<int> idxLarge, idxTwo, idxOne;\n    for (int i = 0; i < M; ++i) {\n        if (sizes[i] >= 3) idxLarge.push_back(i);\n        else if (sizes[i] == 2) idxTwo.push_back(i);\n        else if (sizes[i] == 1) idxOne.push_back(i);\n        else return false;\n    }\n    sort(idxLarge.begin(), idxLarge.end(), [&](int a, int b) {\n        if (sizes[a] != sizes[b]) return sizes[a] > sizes[b];\n        return a < b;\n    });\n    int ptr = 0;\n    auto pick_seed = [&]() -> int {\n        for (int iter = 0; iter < N; ++iter) {\n            int idx = order[ptr];\n            ptr++;\n            if (ptr == N) ptr = 0;\n            if (!used[idx]) return idx;\n        }\n        for (int idx = 0; idx < N; ++idx)\n            if (!used[idx]) return idx;\n        return -1;\n    };\n    for (int idx : idxLarge) {\n        int need = sizes[idx];\n        int seed = pick_seed();\n        if (seed == -1) return false;\n        vector<int> grp;\n        grp.reserve(need);\n        used[seed] = 1;\n        grp.push_back(seed);\n        double cx = px[seed], cy = py[seed];\n        while ((int)grp.size() < need) {\n            int best = -1;\n            double bestDist = 1e100;\n            for (int city = 0; city < N; ++city) if (!used[city]) {\n                double dx = px[city] - cx;\n                double dy = py[city] - cy;\n                double dist = dx * dx + dy * dy;\n                if (dist < bestDist) {\n                    bestDist = dist;\n                    best = city;\n                }\n            }\n            if (best == -1) return false;\n            used[best] = 1;\n            grp.push_back(best);\n            double sz = grp.size();\n            cx = (cx * (sz - 1) + px[best]) / sz;\n            cy = (cy * (sz - 1) + py[best]) / sz;\n        }\n        groups[idx] = std::move(grp);\n    }\n    vector<int> leftover;\n    leftover.reserve(N);\n    for (int idx : order) if (!used[idx]) leftover.push_back(idx);\n    int needPairs = idxTwo.size() * 2;\n    int needSingles = idxOne.size();\n    if ((int)leftover.size() != needPairs + needSingles) return false;\n    vector<int> pairNodes(leftover.begin(), leftover.begin() + needPairs);\n    vector<int> singleNodes(leftover.begin() + needPairs, leftover.end());\n    vector<int> pairOrder = best_pair_sequence(pairNodes, px, py, hilb, key ^ 0xabcdefULL);\n    if (pairOrder.size() != pairNodes.size()) return false;\n    for (size_t t = 0; t < idxTwo.size(); ++t) {\n        groups[idxTwo[t]] = {pairOrder[2 * t], pairOrder[2 * t + 1]};\n        used[pairOrder[2 * t]] = used[pairOrder[2 * t + 1]] = 1;\n    }\n    for (size_t t = 0; t < idxOne.size(); ++t) {\n        groups[idxOne[t]] = {singleNodes[t]};\n        used[singleNodes[t]] = 1;\n    }\n    return true;\n}\n\n// ---------- Size permutation helper ----------\nvector<int> build_perm_from_size_order(const vector<int>& sizeSeq,\n                                       const vector<int>& baseG) {\n    int maxSize = *max_element(baseG.begin(), baseG.end());\n    vector<vector<int>> pos(maxSize + 1);\n    for (int i = 0; i < (int)baseG.size(); ++i) {\n        int s = baseG[i];\n        if (s > maxSize) {\n            pos.resize(s + 1);\n            maxSize = s;\n        }\n        pos[s].push_back(i);\n    }\n    for (auto &vec : pos) reverse(vec.begin(), vec.end());\n    vector<int> perm(sizeSeq.size(), -1);\n    for (int i = 0; i < (int)sizeSeq.size(); ++i) {\n        int s = sizeSeq[i];\n        if (s >= (int)pos.size() || pos[s].empty()) return {};\n        perm[i] = pos[s].back();\n        pos[s].pop_back();\n    }\n    return perm;\n}\n\n// ---------- Main ----------\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    auto global_start = chrono::steady_clock::now();\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) cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n\n    vector<double> px(N), py(N);\n    vector<int> ix(N), iy(N);\n    for (int i = 0; i < N; ++i) {\n        px[i] = 0.5 * (lx[i] + rx[i]);\n        py[i] = 0.5 * (ly[i] + ry[i]);\n        ix[i] = (lx[i] + rx[i]) / 2;\n        iy[i] = (ly[i] + ry[i]) / 2;\n    }\n\n    vector<long long> hilb(N);\n    for (int i = 0; i < N; ++i) hilb[i] = hilbertOrder(ix[i], iy[i], 15, 0);\n\n    vector<int> parent = build_global_parent(px, py);\n    vector<vector<int>> adj(N);\n    for (int v = 1; v < N; ++v) {\n        int p = parent[v];\n        if (p < 0 || p >= N || p == v) p = 0;\n        adj[v].push_back(p);\n        adj[p].push_back(v);\n    }\n    for (int v = 0; v < N; ++v) {\n        auto &nbr = adj[v];\n        sort(nbr.begin(), nbr.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n        nbr.erase(unique(nbr.begin(), nbr.end()), nbr.end());\n    }\n    vector<int> order_mst;\n    order_mst.reserve(N);\n    vector<char> vis(N, 0);\n    auto dfs = [&](auto self, int u, int p) -> void {\n        vis[u] = 1;\n        order_mst.push_back(u);\n        for (int v : adj[u]) if (!vis[v] && v != p) self(self, v, u);\n    };\n    for (int i = 0; i < N; ++i) if (!vis[i]) dfs(dfs, i, -1);\n\n    vector<int> base(N);\n    iota(base.begin(), base.end(), 0);\n\n    uint64_t seed = 314159265;\n    seed = seed * 1000003ULL + N;\n    seed = seed * 1000003ULL + M;\n    seed = seed * 1000003ULL + Q;\n    seed = seed * 1000003ULL + L;\n    seed = seed * 1000003ULL + W;\n    for (int i = 0; i < min(N, 20); ++i) {\n        seed = seed * 1000003ULL + (uint64_t)(ix[i] + 10001);\n        seed = seed * 1000003ULL + (uint64_t)(iy[i] + 10001);\n    }\n    mt19937 rng(static_cast<uint32_t>(seed));\n    uniform_real_distribution<double> uni01(0.0, 1.0);\n\n    auto hash_seq = [&](const vector<int>& seq) -> uint64_t {\n        uint64_t h = 1469598103934665603ULL;\n        for (int v : seq) {\n            h ^= (uint64_t)(v + 1000003);\n            h *= 1099511628211ULL;\n        }\n        return h;\n    };\n\n    vector<vector<int>> cityOrders;\n    vector<uint64_t> cityHashes;\n    unordered_set<uint64_t> cityHashSet;\n\n    auto add_city_order = [&](vector<int> ord) {\n        uint64_t h = hash_seq(ord);\n        if (cityHashSet.insert(h).second) {\n            cityHashes.push_back(h);\n            cityOrders.push_back(std::move(ord));\n        }\n    };\n\n    add_city_order(base);\n    {\n        vector<int> tmp = base;\n        reverse(tmp.begin(), tmp.end());\n        add_city_order(tmp);\n    }\n    add_city_order(order_mst);\n    {\n        vector<int> tmp = order_mst;\n        reverse(tmp.begin(), tmp.end());\n        add_city_order(tmp);\n    }\n    {\n        vector<int> tmp = base;\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n        add_city_order(tmp);\n        reverse(tmp.begin(), tmp.end());\n        add_city_order(tmp);\n    }\n    auto add_sorted = [&](auto cmp) {\n        vector<int> ord = base;\n        sort(ord.begin(), ord.end(), cmp);\n        add_city_order(ord);\n    };\n    add_sorted([&](int a, int b) {\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        if (iy[a] != iy[b]) return iy[a] < iy[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        if (iy[a] != iy[b]) return iy[a] < iy[b];\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] + iy[a];\n        long long kb = (long long)ix[b] + iy[b];\n        if (ka != kb) return ka < kb;\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    add_sorted([&](int a, int b) {\n        long long ka = (long long)ix[a] - iy[a];\n        long long kb = (long long)ix[b] - iy[b];\n        if (ka != kb) return ka < kb;\n        if (ix[a] != ix[b]) return ix[a] < ix[b];\n        return a < b;\n    });\n    for (int iter = 0; iter < 6; ++iter) {\n        vector<int> ord = base;\n        shuffle(ord.begin(), ord.end(), rng);\n        add_city_order(ord);\n    }\n\n    vector<vector<int>> sizeOrders;\n    vector<uint64_t> sizeHashes;\n    vector<vector<int>> sizePerms;\n    unordered_set<uint64_t> sizeHashSet;\n\n    auto add_size_order = [&](vector<int> sizes) {\n        uint64_t h = hash_seq(sizes);\n        auto perm = build_perm_from_size_order(sizes, G);\n        if (perm.empty()) return;\n        if (sizeHashSet.insert(h).second) {\n            sizeHashes.push_back(h);\n            sizeOrders.push_back(std::move(sizes));\n            sizePerms.push_back(std::move(perm));\n        }\n    };\n\n    add_size_order(G);\n    {\n        vector<int> tmp = G;\n        sort(tmp.begin(), tmp.end(), greater<int>());\n        add_size_order(tmp);\n    }\n    {\n        vector<int> tmp = G;\n        sort(tmp.begin(), tmp.end());\n        add_size_order(tmp);\n    }\n    {\n        vector<int> tmp = G;\n        sort(tmp.begin(), tmp.end());\n        vector<int> alt;\n        alt.reserve(M);\n        int l = 0, r = M - 1;\n        while (l <= r) {\n            alt.push_back(tmp[r]);\n            if (l != r) alt.push_back(tmp[l]);\n            ++l; --r;\n        }\n        add_size_order(alt);\n    }\n    for (int i = 0; i < 3; ++i) {\n        vector<int> tmp = G;\n        shuffle(tmp.begin(), tmp.end(), rng);\n        add_size_order(tmp);\n    }\n\n    unordered_set<uint64_t> seenStates;\n    seenStates.reserve(4096);\n    seenStates.max_load_factor(0.7f);\n\n    vector<vector<int>> bestGroups;\n    vector<int> bestSizeOrder;\n    vector<int> bestPerm;\n    double bestCost = 1e100;\n    bool haveBest = false;\n\n    auto evaluate_candidate = [&](const vector<int>& ord, uint64_t hOrd,\n                                  const vector<int>& sizes, uint64_t hSize,\n                                  const vector<int>& perm, int mode) {\n        vector<int> offsets = {0};\n        if (mode >= 1 && N > 0) {\n            uint64_t mix = hOrd ^ (hSize * 911382323ULL) ^ (uint64_t)mode * 1234567ULL;\n            int baseOffset = (int)(mix % N);\n            if (baseOffset < 0) baseOffset += N;\n            offsets.clear();\n            offsets.push_back(baseOffset);\n            if (N >= 3) {\n                offsets.push_back((baseOffset + N / 3) % N);\n                offsets.push_back((baseOffset + 2 * (N / 3)) % N);\n            }\n            sort(offsets.begin(), offsets.end());\n            offsets.erase(unique(offsets.begin(), offsets.end()), offsets.end());\n        }\n        if (mode == 0) offsets = {0};\n        for (int off : offsets) {\n            uint64_t key = (hOrd * 1000003ULL + hSize * 911382323ULL + (uint64_t)mode * 1234567ULL + off) & 0x7fffffffffffffffULL;\n            if (!seenStates.insert(key).second) continue;\n            vector<vector<int>> groups(M);\n            bool ok = false;\n            if (mode == 0) ok = build_groups_contiguous(ord, sizes, groups);\n            else if (mode == 1) ok = build_groups_greedy(ord, off, sizes, groups, px, py);\n            else ok = build_groups_two_phase(ord, off, sizes, groups, px, py, hilb, key);\n            if (!ok) continue;\n            double total = 0.0;\n            for (int i = 0; i < M; ++i) total += group_cost(groups[i], px, py);\n            if (!haveBest || total < bestCost) {\n                haveBest = true;\n                bestCost = total;\n                bestGroups = std::move(groups);\n                bestSizeOrder = sizes;\n                bestPerm = perm;\n            }\n        }\n    };\n\n    for (size_t i = 0; i < cityOrders.size(); ++i)\n        for (size_t j = 0; j < sizeOrders.size(); ++j)\n            evaluate_candidate(cityOrders[i], cityHashes[i],\n                               sizeOrders[j], sizeHashes[j],\n                               sizePerms[j], 0);\n\n    vector<int> greedyCityIdx;\n    int limitCity = min<int>(6, cityOrders.size());\n    for (int i = 0; i < limitCity; ++i) greedyCityIdx.push_back(i);\n    for (int t = 0; t < 4 && (int)cityOrders.size() > limitCity; ++t) {\n        int idx = rng() % cityOrders.size();\n        greedyCityIdx.push_back(idx);\n    }\n    sort(greedyCityIdx.begin(), greedyCityIdx.end());\n    greedyCityIdx.erase(unique(greedyCityIdx.begin(), greedyCityIdx.end()), greedyCityIdx.end());\n\n    vector<int> greedySizeIdx;\n    int limitSize = min<int>(5, sizeOrders.size());\n    for (int i = 0; i < limitSize; ++i) greedySizeIdx.push_back(i);\n    for (int t = 0; t < 3 && (int)sizeOrders.size() > limitSize; ++t) {\n        int idx = rng() % sizeOrders.size();\n        greedySizeIdx.push_back(idx);\n    }\n    sort(greedySizeIdx.begin(), greedySizeIdx.end());\n    greedySizeIdx.erase(unique(greedySizeIdx.begin(), greedySizeIdx.end()), greedySizeIdx.end());\n\n    for (int ci : greedyCityIdx) {\n        for (int si : greedySizeIdx) {\n            evaluate_candidate(cityOrders[ci], cityHashes[ci],\n                               sizeOrders[si], sizeHashes[si],\n                               sizePerms[si], 1);\n            evaluate_candidate(cityOrders[ci], cityHashes[ci],\n                               sizeOrders[si], sizeHashes[si],\n                               sizePerms[si], 2);\n        }\n    }\n\n    if (!haveBest) {\n        vector<vector<int>> groups(M);\n        if (!build_groups_contiguous(base, G, groups)) {\n            cout << \"!\\n\";\n            for (int i = 0; i < M; ++i) cout << '\\n';\n            return 0;\n        }\n        bestGroups = groups;\n        bestSizeOrder = G;\n        bestPerm.resize(M);\n        iota(bestPerm.begin(), bestPerm.end(), 0);\n        bestCost = 0.0;\n        for (int i = 0; i < M; ++i) bestCost += group_cost(bestGroups[i], px, py);\n    }\n\n    if (bestPerm.empty()) {\n        bestPerm.resize(M);\n        iota(bestPerm.begin(), bestPerm.end(), 0);\n    }\n    if (bestSizeOrder.empty()) bestSizeOrder = G;\n\n    improve_pairs(bestGroups, bestSizeOrder, px, py, hilb, seed);\n\n    vector<vector<int>> groups = bestGroups;\n    vector<double> groupCost(M, 0.0);\n    vector<double> sum_x(M, 0.0), sum_y(M, 0.0);\n    double curCost = 0.0;\n    for (int i = 0; i < M; ++i) {\n        groupCost[i] = group_cost(groups[i], px, py);\n        curCost += groupCost[i];\n        for (int v : groups[i]) {\n            sum_x[i] += px[v];\n            sum_y[i] += py[v];\n        }\n    }\n    bestCost = curCost;\n    bestGroups = groups;\n\n    auto recompute_stats = [&](int idx) {\n        double sx = 0.0, sy = 0.0;\n        for (int v : groups[idx]) {\n            sx += px[v];\n            sy += py[v];\n        }\n        sum_x[idx] = sx;\n        sum_y[idx] = sy;\n    };\n\n    const int MAX_CLUSTER_SIZE = 8;\n\n    auto local_reassign = [&](const vector<int>& idxs) -> bool {\n        int k = idxs.size();\n        vector<int> limits(k);\n        vector<int> nodes;\n        nodes.reserve(MAX_CLUSTER_SIZE);\n        double baseVal = 0.0;\n        for (int i = 0; i < k; ++i) {\n            int idx = idxs[i];\n            limits[i] = groups[idx].size();\n            baseVal += groupCost[idx];\n            nodes.insert(nodes.end(), groups[idx].begin(), groups[idx].end());\n        }\n        int total = nodes.size();\n        if (total <= 1 || total > MAX_CLUSTER_SIZE) return false;\n        vector<int> order = nodes;\n        shuffle(order.begin(), order.end(), rng);\n        vector<vector<int>> cur(k), bestAssign(k);\n        vector<double> curCosts(k, 0.0), bestCosts(k, 0.0);\n        double bestVal = baseVal - 1e-9;\n        bool improved = false;\n\n        function<void(int)> dfs_assign = [&](int pos) {\n            if (pos == total) {\n                double sum = 0.0;\n                for (int i = 0; i < k; ++i) {\n                    curCosts[i] = group_cost(cur[i], px, py);\n                    sum += curCosts[i];\n                    if (sum >= bestVal - 1e-9) return;\n                }\n                improved = true;\n                bestVal = sum;\n                bestAssign = cur;\n                bestCosts = curCosts;\n                return;\n            }\n            int node = order[pos];\n            for (int gi = 0; gi < k; ++gi) {\n                if ((int)cur[gi].size() >= limits[gi]) continue;\n                cur[gi].push_back(node);\n                dfs_assign(pos + 1);\n                cur[gi].pop_back();\n            }\n        };\n        dfs_assign(0);\n        if (!improved || bestVal >= baseVal - 1e-9) return false;\n        double delta = bestVal - baseVal;\n        for (int i = 0; i < k; ++i) {\n            int idx = idxs[i];\n            groups[idx] = bestAssign[i];\n            groupCost[idx] = bestCosts[i];\n            recompute_stats(idx);\n        }\n        curCost += delta;\n        if (curCost + 1e-9 < bestCost) {\n            bestCost = curCost;\n            bestGroups = groups;\n        }\n        return true;\n    };\n\n    auto try_local_reassign = [&]() -> bool {\n        if (M <= 1) return false;\n        const int attempts = 30;\n        for (int t = 0; t < attempts; ++t) {\n            int g = rng() % M;\n            int h = rng() % M;\n            if (h == g) continue;\n            vector<int> idxs = {g, h};\n            if (M >= 3 && uni01(rng) < 0.5) {\n                int j = rng() % M;\n                if (j == g || j == h) continue;\n                idxs.push_back(j);\n            }\n            sort(idxs.begin(), idxs.end());\n            idxs.erase(unique(idxs.begin(), idxs.end()), idxs.end());\n            int total = 0;\n            for (int idx : idxs) total += groups[idx].size();\n            if (total <= 1 || total > MAX_CLUSTER_SIZE) continue;\n            if (local_reassign(idxs)) return true;\n        }\n        return false;\n    };\n\n    const double TOTAL_LIMIT = 1.65;\n    auto deadline = global_start + chrono::duration<double>(TOTAL_LIMIT);\n\n    if (M > 1) {\n        for (int k = 0; k < 40 && chrono::steady_clock::now() < deadline; ++k) {\n            if (!try_local_reassign()) break;\n        }\n        const double T0 = 400.0;\n        const double T1 = 1e-3;\n        const double clusterProb = 0.15;\n\n        while (chrono::steady_clock::now() < deadline) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n            double progress = min(1.0, elapsed / TOTAL_LIMIT);\n            double temperature = T0 * pow(T1 / T0, progress);\n\n            if (uni01(rng) < clusterProb) {\n                if (try_local_reassign()) continue;\n            }\n\n            int g = rng() % M;\n            auto choose_partner = [&](int gidx) -> int {\n                if (M <= 1) return gidx;\n                if (uni01(rng) < 0.35) {\n                    int cand = rng() % (M - 1);\n                    if (cand >= gidx) ++cand;\n                    return cand;\n                }\n                double cgx = sum_x[gidx] / groups[gidx].size();\n                double cgy = sum_y[gidx] / groups[gidx].size();\n                double bestd = 1e300;\n                int best = -1;\n                int samples = min(M - 1, 10);\n                for (int t = 0; t < samples; ++t) {\n                    int cand = rng() % M;\n                    if (cand == gidx) continue;\n                    double csx = sum_x[cand] / groups[cand].size();\n                    double csy = sum_y[cand] / groups[cand].size();\n                    double dx = cgx - csx;\n                    double dy = cgy - csy;\n                    double dist = dx * dx + dy * dy;\n                    if (dist < bestd) {\n                        bestd = dist;\n                        best = cand;\n                    }\n                }\n                if (best == -1) best = (gidx + 1 + (rng() % (M - 1))) % M;\n                return best;\n            };\n            int h = choose_partner(g);\n            if (h == g) continue;\n\n            auto pick_index = [&](int grp) -> int {\n                int sz = (int)groups[grp].size();\n                if (sz <= 1) return 0;\n                if ((rng() & 1) == 0) return rng() % sz;\n                double cx = sum_x[grp] / sz;\n                double cy = sum_y[grp] / sz;\n                int bestIdx = rng() % sz;\n                double bestScore = -1.0;\n                int samples = min(sz, 6);\n                for (int t = 0; t < samples; ++t) {\n                    int idx = rng() % sz;\n                    double dx = px[groups[grp][idx]] - cx;\n                    double dy = py[groups[grp][idx]] - cy;\n                    double sc = dx * dx + dy * dy;\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestIdx = idx;\n                    }\n                }\n                return bestIdx;\n            };\n\n            if (groups[g].empty() || groups[h].empty()) continue;\n            int idx_g = pick_index(g);\n            int idx_h = pick_index(h);\n            int node_g = groups[g][idx_g];\n            int node_h = groups[h][idx_h];\n            if (node_g == node_h) continue;\n\n            swap(groups[g][idx_g], groups[h][idx_h]);\n            double newCostG = group_cost(groups[g], px, py);\n            double newCostH = group_cost(groups[h], px, py);\n            double delta = (newCostG + newCostH) - (groupCost[g] + groupCost[h]);\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-delta / max(temperature, 1e-12));\n                if (uni01(rng) < prob) accept = true;\n            }\n            if (accept) {\n                groupCost[g] = newCostG;\n                groupCost[h] = newCostH;\n                curCost += delta;\n                sum_x[g] += px[node_h] - px[node_g];\n                sum_y[g] += py[node_h] - py[node_g];\n                sum_x[h] += px[node_g] - px[node_h];\n                sum_y[h] += py[node_g] - py[node_h];\n                if (curCost + 1e-9 < bestCost) {\n                    bestCost = curCost;\n                    bestGroups = groups;\n                }\n            } else {\n                swap(groups[g][idx_g], groups[h][idx_h]);\n            }\n        }\n    }\n\n    improve_pairs(bestGroups, bestSizeOrder, px, py, hilb, seed ^ 0x12345ULL);\n\n    vector<int> invPerm(M);\n    for (int i = 0; i < M; ++i) invPerm[bestPerm[i]] = i;\n    vector<vector<int>> finalGroups(M);\n    for (int i = 0; i < M; ++i) finalGroups[i] = bestGroups[invPerm[i]];\n    improve_pairs(finalGroups, G, px, py, hilb, seed ^ 0x999999ULL);\n\n    vector<vector<pair<int,int>>> edges(M);\n    for (int i = 0; i < M; ++i) edges[i] = build_group_mst(finalGroups[i], px, py);\n\n    cout << \"!\\n\";\n    for (int i = 0; i < M; ++i) {\n        for (size_t j = 0; j < finalGroups[i].size(); ++j) {\n            if (j) cout << ' ';\n            cout << finalGroups[i][j];\n        }\n        cout << '\\n';\n        for (auto &e : edges[i]) cout << e.first << ' ' << e.second << '\\n';\n    }\n    cout.flush();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int DIRS = 4;\nconst int dr[DIRS] = {-1, 1, 0, 0};\nconst int dc[DIRS] = {0, 0, -1, 1};\nconst char dirc[DIRS] = {'U', 'D', 'L', 'R'};\n\nstruct Planner {\n    int N, B, BLOCK_NONE, TOT, chunk_max;\n    vector<int> row, col;\n    vector<array<vector<int>, DIRS>> rays;\n\n    vector<int> dist, prev_state;\n    vector<char> prev_act, prev_dir;\n    vector<int> touched;\n\n    static constexpr int PEN_BLOCK_BASE = 1;\n    static constexpr int PEN_BLOCK_DIST_DIV = 6;\n\n    Planner(int N_, int chunk_max_) : N(N_), chunk_max(chunk_max_) {\n        B = N * N;\n        BLOCK_NONE = B;\n        TOT = B * (B + 1);\n        int state_count = TOT * (chunk_max + 1);\n\n        row.resize(B);\n        col.resize(B);\n        for (int idx = 0; idx < B; ++idx) {\n            row[idx] = idx / N;\n            col[idx] = idx % N;\n        }\n\n        rays.resize(B);\n        for (int pos = 0; pos < B; ++pos) {\n            int r = row[pos], c = col[pos];\n            for (int d = 0; d < DIRS; ++d) {\n                auto &line = rays[pos][d];\n                int nr = r + dr[d], nc = c + dc[d];\n                while (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                    line.push_back(nr * N + nc);\n                    nr += dr[d];\n                    nc += dc[d];\n                }\n            }\n        }\n\n        dist.assign(state_count, -1);\n        prev_state.assign(state_count, -1);\n        prev_act.assign(state_count, 0);\n        prev_dir.assign(state_count, 0);\n        touched.reserve(state_count);\n    }\n\n    int penalty_for_state(int state, int prog, const vector<int>& next_after) const {\n        int rem = state % TOT;\n        int block = rem % (B + 1);\n        if (block == BLOCK_NONE) return 0;\n        if (prog >= (int)next_after.size()) return PEN_BLOCK_BASE;\n        int penalty = PEN_BLOCK_BASE;\n        int nxt = next_after[prog];\n        if (nxt != -1) {\n            int dist_to_next = abs(row[block] - row[nxt]) + abs(col[block] - col[nxt]);\n            penalty += dist_to_next / PEN_BLOCK_DIST_DIV;\n        }\n        return penalty;\n    }\n\n    bool run_chunk(int chunk_len, int start_pos, int start_block,\n                   const vector<int>& targets, const vector<int>& next_after,\n                   vector<pair<char, char>>& seq,\n                   int& end_block, int& achieved_len) {\n        seq.clear();\n        achieved_len = 0;\n        if (chunk_len <= 0) {\n            end_block = start_block;\n            return true;\n        }\n\n        queue<int> q;\n        touched.clear();\n        auto state_id = [&](int prog, int pos, int block) -> int {\n            return prog * TOT + pos * (B + 1) + block;\n        };\n\n        vector<int> best_state(chunk_len + 1, -1);\n\n        int start_state = state_id(0, start_pos, start_block);\n        q.push(start_state);\n        touched.push_back(start_state);\n        dist[start_state] = 0;\n        prev_state[start_state] = -1;\n\n        while (!q.empty()) {\n            int st = q.front();\n            q.pop();\n            int prog = st / TOT;\n            if (prog > chunk_len) continue;\n\n            if (prog > 0 && best_state[prog] == -1) {\n                best_state[prog] = st;\n                if (prog == chunk_len) break;\n            }\n            if (prog == chunk_len) continue;\n\n            int rem = st % TOT;\n            int pos = rem / (B + 1);\n            int block = rem % (B + 1);\n            int r = row[pos], c = col[pos];\n            int block_idx = (block == BLOCK_NONE ? -1 : block);\n\n            auto push_state = [&](int npos, int nblock, bool can_visit,\n                                  char act, char dir) {\n                int nprog = prog;\n                if (can_visit && nprog < chunk_len && npos == targets[nprog]) {\n                    ++nprog;\n                }\n                int nid = state_id(nprog, npos, nblock);\n                if (dist[nid] != -1) return;\n                dist[nid] = dist[st] + 1;\n                prev_state[nid] = st;\n                prev_act[nid] = act;\n                prev_dir[nid] = dir;\n                q.push(nid);\n                touched.push_back(nid);\n            };\n\n            // Move\n            for (int d = 0; d < DIRS; ++d) {\n                int nr = r + dr[d], nc = c + dc[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int npos = nr * N + nc;\n                if (block_idx == npos) continue;\n                push_state(npos, block, true, 'M', dirc[d]);\n            }\n\n            // Slide\n            for (int d = 0; d < DIRS; ++d) {\n                const auto &line = rays[pos][d];\n                if (line.empty()) continue;\n                int dest = -1;\n                if (block_idx == -1) {\n                    dest = line.back();\n                } else {\n                    int prev_cell = pos;\n                    bool hit = false;\n                    for (int cell : line) {\n                        if (cell == block_idx) {\n                            hit = true;\n                            dest = (prev_cell == pos) ? -1 : prev_cell;\n                            break;\n                        }\n                        prev_cell = cell;\n                    }\n                    if (hit && dest == -1) continue;\n                    if (!hit) dest = line.back();\n                }\n                if (dest == -1 || dest == pos) continue;\n                push_state(dest, block, true, 'S', dirc[d]);\n            }\n\n            // Alter\n            for (int d = 0; d < DIRS; ++d) {\n                int ar = r + dr[d], ac = c + dc[d];\n                if (ar < 0 || ar >= N || ac < 0 || ac >= N) continue;\n                int adj = ar * N + ac;\n                if (block == BLOCK_NONE) {\n                    push_state(pos, adj, false, 'A', dirc[d]);\n                } else if (block_idx == adj) {\n                    push_state(pos, BLOCK_NONE, false, 'A', dirc[d]);\n                }\n            }\n        }\n\n        int chosen_len = 0;\n        int chosen_state = -1;\n        long long chosen_eff = LLONG_MAX;\n        int chosen_penalty = INT_MAX;\n\n        for (int k = 1; k <= chunk_len; ++k) {\n            if (best_state[k] == -1) continue;\n            int state = best_state[k];\n            int d = dist[state];\n            int penalty = penalty_for_state(state, k, next_after);\n            int effective = d + penalty;\n            if (chosen_len == 0) {\n                chosen_len = k;\n                chosen_state = state;\n                chosen_eff = effective;\n                chosen_penalty = penalty;\n                continue;\n            }\n            long long lhs = 1LL * effective * chosen_len;\n            long long rhs = chosen_eff * k;\n            if (lhs < rhs ||\n                (lhs == rhs && (k > chosen_len ||\n                                (k == chosen_len &&\n                                 (effective < chosen_eff ||\n                                  (effective == chosen_eff &&\n                                   penalty < chosen_penalty)))))) {\n                chosen_len = k;\n                chosen_state = state;\n                chosen_eff = effective;\n                chosen_penalty = penalty;\n            }\n        }\n\n        if (chosen_len == 0) {\n            for (int id : touched) dist[id] = -1;\n            touched.clear();\n            return false;\n        }\n\n        vector<pair<char, char>> rev;\n        for (int cur = chosen_state; cur != start_state; cur = prev_state[cur]) {\n            rev.emplace_back(prev_act[cur], prev_dir[cur]);\n        }\n        reverse(rev.begin(), rev.end());\n        seq = move(rev);\n\n        int rem = chosen_state % TOT;\n        end_block = rem % (B + 1);\n        achieved_len = chosen_len;\n\n        for (int id : touched) dist[id] = -1;\n        touched.clear();\n        return true;\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>> pts(M);\n    for (int i = 0; i < M; ++i) cin >> pts[i].first >> pts[i].second;\n\n    const int LIMIT = 2 * N * M;\n    const int CHUNK_MAX = 7;\n\n    Planner planner(N, CHUNK_MAX);\n\n    vector<int> idx(M);\n    for (int i = 0; i < M; ++i) idx[i] = pts[i].first * N + pts[i].second;\n\n    vector<pair<char,char>> answer;\n    answer.reserve(LIMIT);\n    vector<pair<char,char>> segment;\n    vector<int> chunk_targets;\n    vector<int> next_after;\n\n    int current_idx = 0;\n    int block_state = planner.BLOCK_NONE;\n\n    while (current_idx < M - 1 && (int)answer.size() < LIMIT) {\n        int remaining = (M - 1) - current_idx;\n        int chunk_len = min(CHUNK_MAX, remaining);\n\n        chunk_targets.clear();\n        for (int t = 1; t <= chunk_len; ++t) {\n            chunk_targets.push_back(idx[current_idx + t]);\n        }\n\n        next_after.assign(chunk_len + 1, -1);\n        for (int k = 1; k <= chunk_len; ++k) {\n            int global_idx = current_idx + k + 1;\n            if (global_idx < M) next_after[k] = idx[global_idx];\n        }\n\n        int used_len = 0;\n        int next_block = block_state;\n        bool ok = planner.run_chunk(chunk_len, idx[current_idx], block_state,\n                                    chunk_targets, next_after,\n                                    segment, next_block, used_len);\n\n        if (!ok || used_len == 0) {\n            // Fallback: force a single target chunk (should rarely happen)\n            chunk_targets.assign(1, idx[current_idx + 1]);\n            next_after.assign(2, -1);\n            if (current_idx + 2 < M) next_after[1] = idx[current_idx + 2];\n            ok = planner.run_chunk(1, idx[current_idx], block_state,\n                                   chunk_targets, next_after,\n                                   segment, next_block, used_len);\n            if (!ok || used_len == 0) break;\n        }\n\n        if ((int)answer.size() + (int)segment.size() > LIMIT) break;\n\n        answer.insert(answer.end(), segment.begin(), segment.end());\n        block_state = next_block;\n        current_idx += used_len;\n    }\n\n    for (auto [a, d] : answer) {\n        cout << a << ' ' << d << '\\n';\n    }\n    return 0;\n}"}}}