Submission #63336645


Source Code Expand

#include <vector>
#include <string>
#include <algorithm>
#include <complex>
#include <utility>
#include <unordered_map>
#include <optional>
#include <functional>
#include <deque>
#include <cmath>
#include <iostream>

namespace visualizer {
using std::string;
using std::vector;
using std::optional;
using std::nullopt;
using Point = std::complex<double>;

#define VISUALIZE // 提出時にはここをコメントアウトすること。そうしないとTLEする。

#if (defined(ONLINE_JUDGE) || defined(ATCODER) || defined(NOVIS)) && defined(VISUALIZE)
constexpr bool DO_NOT_VISUALIZE = 1;
#undef VISUALIZE // 誤提出防止
#endif

namespace vis_internal {
    FILE* visFile = nullptr;
    Point visualizer_campus_size;
    bool visualizer_internal_y_upper = false;
    // constexpr int MAX_HIST_LEN = 100*100*3*10000;
    constexpr int MAX_HIST_LEN = 0x7fffffff;
    std::deque<std::size_t> hash_hist;
    constexpr int buf_len = 2048;
    char buf[buf_len];
    int buf_i = 0;
    long long line_number = 1;
    std::size_t get_buf_hash() {
        std::size_t hash = buf_i;
        const char* str = buf;
        while (*str) {
            hash ^= static_cast<std::size_t>(*str++) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
        }
        return hash;
    }
    std::unordered_map<std::size_t, long long> compressor;
    long long start_same_line = -1;
    long long last_same_line = -1;
    inline void pop_line_combo() {
        if (start_same_line == -1) return;
        if (start_same_line == last_same_line) {
            fprintf(visFile, "L%lld\n", start_same_line);
        } else {
            fprintf(visFile, "L%lld:%lld\n", start_same_line, last_same_line-start_same_line+1);
        }
        start_same_line = last_same_line = -1;
    }
    int max_vtime = 0;
    bool vis_time_enable = true;
    int vis_time_interval = 1;
}

void set_vis_time_interval(int interval = 1) {
    vis_internal::vis_time_interval = interval;
}

#ifdef VISUALIZE
constexpr bool DO_NOT_VISUALIZE = 0;
#define VRET ;
    
template<typename... Args>
void print(const char* format, Args... args) {
    VRET;
    using namespace vis_internal;
    if (vis_time_enable == false) {
        return;
    }
    if constexpr (sizeof...(args) > 0) {
        buf_i += std::snprintf(buf + buf_i, buf_len - buf_i, format, args...);
    } else {
        buf_i += std::snprintf(buf + buf_i, buf_len - buf_i, "%s", format);
    }
    if (buf[buf_i-1] != '\n') return;
    ++line_number;
    bool ignore = (buf[0] == '<' && buf[1] == '!');
    static bool warned = false;
    if (line_number >= 0x7fff'ffff && !warned) [[unlikely]] {
        fprintf(stderr, "SVG command number exceeds INT32_MAX.\n");
        std::fflush(stderr);
        warned = true;
        return;
    }
    if (ignore) {
        pop_line_combo();
        fprintf(visFile, "%s", buf);
    } else {
        std::size_t hash = get_buf_hash();
        auto it = compressor.find(hash);
        if (it == compressor.end() || true) {
            compressor.emplace(hash, line_number);
            hash_hist.emplace_back(hash);
            pop_line_combo();
            fprintf(visFile, "%s", buf);
        } else {
            if (start_same_line == -1) {
                start_same_line = last_same_line = it->second;
            } else if (last_same_line + 1 == it->second) {
                last_same_line = it->second;
            } else {
                pop_line_combo();
                start_same_line = last_same_line = it->second;
            }
            it->second = line_number;
            hash_hist.emplace_back(hash);
        }
        // if (hash_hist.size() >= MAX_HIST_LEN) {
        //     std::size_t old_hash = hash_hist.front(); hash_hist.pop_front();
        //     auto it = compressor.find(old_hash);
        //     if (line_number - it->second >= MAX_HIST_LEN) {
        //         compressor.erase(it);
        //     }
        // }
    }
    buf_i = 0;
}

struct visualizer_helper {
    struct StringLike {
        string str;
        StringLike(const char* str) : str(str){}
        StringLike(string str) : str(str){}
        template<typename... Args> StringLike(Args... args) {
            size_t size = snprintf(nullptr, 0, args...) + 1;
            vector<char> buf(size);
            snprintf(buf.data(), size, args...);
            str = string(buf.data(), buf.data() + size - 1);
        }
    };
    visualizer_helper(StringLike filename, Point size, Point origin = Point(), bool y_upper = false) {
        init(filename.str, size, origin, y_upper);
    }
    visualizer_helper(Point size, Point origin = Point(), bool y_upper = false) {
        init("VisCommands.svg", size, origin, y_upper);
    }
    void init(string filename, Point size, Point origin = Point(), bool y_upper = false) {
        using namespace vis_internal;
        if (size.imag() <= 0) { size.imag(size.real()); }
        visualizer_campus_size = size;
        visFile = fopen(filename.c_str(), "w");
        fprintf(visFile, "<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='800' viewBox='%g %g %g %g'", 
                origin.real(), origin.imag(), size.real(), size.imag());
        if (y_upper) {
            visualizer_internal_y_upper = true;
            fprintf(visFile, " transform='scale(1, -1)' transform-origin='0 %g'", size.imag()/2);
            fprintf(visFile, "><style>text {transform: scale(1, -1);}</style");
        }
        fprintf(visFile, ">\n");
    }
    ~visualizer_helper(){
        print("</svg>\n");
        fclose(vis_internal::visFile);
    }
};

#else
#define VRET return;
struct visualizer_helper { template<typename... Args> visualizer_helper(Args... args) {} };
template<typename... Args>
void print(const char* format, Args... args) { return; }
#endif

struct Vopt {
    struct v {
        optional<string> fill = nullopt;
        optional<string> stroke = nullopt;
        optional<float> swidth = nullopt;
        optional<string> text_anchor = nullopt;
        optional<string> dominant_baseline = nullopt;
        optional<string> title = nullopt;
        optional<string> desc_text = nullopt;
        optional<int16_t> z = nullopt;
    } v;
    Vopt(){};
    Vopt(const Vopt& op) : v{op.v} {};
    Vopt(const string fill) { v.fill = fill; }
    Vopt(const char* fill) { v.fill = fill; }
    Vopt(const string stroke, double width) { v.fill = ""; v.stroke = stroke; v.swidth = width; }
    Vopt(const char* stroke, double width) { v.fill = ""; v.stroke = stroke; v.swidth = width; }
    Vopt(const string fill, const string stroke, double width) { v.fill = fill; v.stroke = stroke; v.swidth = width; }
    Vopt(const char* fill, const char* stroke, double width) { v.fill = fill; v.stroke = stroke; v.swidth = width; }
    void p(const optional<string>& a, const char* label, const string empty = "") {
        if(a) print(" %s='%s'", label, (a.value().size() ? a.value() : empty).c_str());
    }
    void p(const optional<float>& a, const char* label) {
        if(a) print(" %s='%g'", label, a.value());
    }
    void operator()(bool close = true) {
        VRET;
        p(v.fill, "fill", "none");
        p(v.stroke, "stroke");
        p(v.swidth, "stroke-width");
        p(v.text_anchor, "text-anchor");
        p(v.dominant_baseline, "dominant-baseline");
        if(v.desc_text) { print(" data-txt='%s'", v.desc_text.value().c_str()); }
        if(v.title) { print("/></g>\n"); if(!close){ printf("Error! %s:%d\n", __FILE__, __LINE__); abort(); } }
        else { if(close) print("/>\n"); }
    }
    void pre() {
        VRET;
        if(v.z) { print("z%d", v.z.value()); }
        if(v.title) { print("<g><title>%s</title>", v.title.value().c_str()); }
    }
    Vopt fill(string s) { Vopt res(*this); res.v.fill = s; return res; }
    Vopt stroke(string s) { Vopt res(*this); res.v.stroke = s; return res; }
    Vopt swidth(float a) { Vopt res(*this); res.v.swidth = a; return res; }
    Vopt stroke(string s, float v) { return stroke(s).swidth(v); }
    Vopt title(string s) { Vopt res(*this); res.v.title = s; return res; }
    Vopt desc(string s) { Vopt res(*this); res.v.desc_text = s; return res; }
    Vopt z(int16_t z) { Vopt res(*this); res.v.z = z; return res; }
    template<typename T> optional<T>& over_write(optional<T>& a, const optional<T>& g) {
        if(!a && g) a = g;
        return a;
    }
};

Vopt fill(string s) { Vopt op; return op.fill(s); }
Vopt stroke(string s) { Vopt op; return op.stroke(s); }
Vopt swidth(float a) { Vopt op; return op.swidth(a); }
Vopt stroke(string s, float v) { Vopt op; return op.stroke(s, v); }

string color(double val) {
    if constexpr (DO_NOT_VISUALIZE) return "";
    val = std::clamp(val, 0.0, 1.0);
    double r, g, b;
    if(val < 0.5) {
        double x = val * 2.0;
        r = std::round(30.0 * (1.0 - x) + 144.0 * x);
        g = std::round(144.0 * (1.0 - x) + 255.0 * x);
        b = std::round(255.0 * (1.0 - x) + 30.0 * x);
    } else {
        double x = val * 2.0 - 1.0;
        r = std::round(144.0 * (1.0 - x) + 255.0 * x);
        g = std::round(255.0 * (1.0 - x) + 30.0 * x);
        b = std::round(30.0 * (1.0 - x) + 70.0 * x);
    }
    char buffer[8];
    std::sprintf(buffer, "#%02x%02x%02x", int(r), int(g), int(b));
    return std::string(buffer);
}

void circle(Point c, float r, Vopt op = {}) { VRET;
    op.pre();
    print("<circle cx='%g' cy='%g' r='%g'", c.real(), c.imag(), r);
    op();
}

void circles(const vector<Point>& cs, float r, Vopt op = {}) { VRET;
    for(auto p : cs) circle(p, r, op);
}

void line(Point p1, Point p2, Vopt op = {}) { VRET;
    op.pre();
    if(op.v.fill && !op.v.stroke && !op.v.swidth) {
        op.v.stroke.swap(op.v.fill);
        op.v.swidth = 1;
    }
    print("<line x1='%g' y1='%g' x2='%g' y2='%g' stroke-linecap='round' stroke-linejoin='round'", p1.real(), p1.imag(), p2.real(), p2.imag());
    op();
}

void rect(Point p, Point size, Vopt op = {}) { VRET;
    op.pre();
    print("<rect x='%g' y='%g' width='%g' height='%g'", p.real(), p.imag(), size.real(), size.imag());
    op();
}

void rect2p(Point p, Point q, Vopt op = {}) { VRET;
    rect(p, q-p, op);
}

void rectc(Point c, Point size, float deg = 0, Vopt op = {}) { VRET;
    const Point p = c - size * 0.5;
    op.pre();
    print("<rect x='%g' y='%g' width='%g' height='%g' transform='rotate(%g %g %g)'", 
          p.real(), p.imag(), size.real(), size.imag(), deg, c.real(), c.imag());
    op();
}

void polygon(const std::vector<Point>& ps, Vopt op = {}) { VRET;
    op.pre();
    print("<polygon points='");
    for(auto p : ps) print("%g,%g ", p.real(), p.imag());
    print("' ");
    op();
}

void polyline(const std::vector<Point>& ps, Vopt op = {}) { VRET;
    op.pre();
    print("<polyline points='");
    for(auto p : ps) print("%g,%g ", p.real(), p.imag());
    print("'");
    op();
}

void text(Point p, string str, float size, Vopt op = {}) { VRET;
    op.pre();
    print("<text x='%g' y='%g' font-size='%g'", p.real(), p.imag(), size);
    if(vis_internal::visualizer_internal_y_upper) { print(" transform-origin='%g %g'", p.real(), p.imag()); }
    op(false);
    print(">%s</text>\n", str.c_str());
}

void text(Point p, int num, float size, Vopt op = {}) { VRET;
    text(p, std::to_string(num), size, op);
}
void text(Point p, double num, float size, Vopt op = {}) { VRET;
    text(p, std::to_string(num), size, op);
}

Vopt align(string align) {
    Vopt op;
    if constexpr (DO_NOT_VISUALIZE) return op;
    if(align.find("R") != string::npos) { op.v.text_anchor = "end"; }
    else if(align.find("L") != string::npos) { op.v.text_anchor = "start"; }
    else { op.v.text_anchor = "middle"; }
    if(align.find("T") != string::npos || align.find("U") != string::npos) { op.v.dominant_baseline = "hanging "; }
    else if(align.find("B") != string::npos || align.find("D") != string::npos) { op.v.dominant_baseline = "text-bottom"; }
    else if(align.find("I") != string::npos) { op.v.dominant_baseline = "ideographic"; }
    else { op.v.dominant_baseline = "middle"; }
    return op;
}
const Vopt alignC = align("");

void vtime(int a = -1, int b = -1){ VRET;
    using namespace vis_internal;
    max_vtime = std::max(std::max(max_vtime, a), b);
    if(vis_internal::vis_time_interval == 1 || a == -1) {
        vis_internal::vis_time_enable = true;
        if(b < 0) return print("<!--time=%d-->\n", a);
        else return print("<!--time=%d:%d-->\n", a, b);
    } else if(b == -1) {
        if(a % vis_internal::vis_time_interval == 0) {
            a /= vis_internal::vis_time_interval;
            vis_internal::vis_time_enable = true;
            return print("<!--time=%d-->\n", a);
        } else {
            vis_internal::vis_time_enable = false;
        }
    } else {
        a = (a + vis_internal::vis_time_interval) / vis_internal::vis_time_interval;
        b /= vis_internal::vis_time_interval;
        if(a > b) { vis_internal::vis_time_enable = false; return; }
        else if(a == b) { print("<!--time=%d-->\n", a); }
        else { print("<!--time=%d:%d-->\n", a, b); }
        vis_internal::vis_time_enable = true;
    }
}

namespace internal {
    struct Segment : public std::pair<Point, Point>{
        Segment(const Point &p1, const Point &p2) : std::pair<Point, Point>(p1, p2) {}
    };
    struct Box {
        Point p, s;
        Box(Point p, Point s) : p(p), s(s) {}
        Point center() const { return p + s * 0.5; }
        operator Point() const { return center(); }
        Point UpLeft() const { return p; }
        Point UpRight() const { return p + Point(s.real(), 0); }
        Point BtLeft() const { return p + Point(0, s.imag()); }
        Point BtRight() const { return p + s; }
        Segment segL() const { return Segment(UpLeft(), BtLeft()); }
        Segment segR() const { return Segment(UpRight(), BtRight()); }
        Segment segU() const { return Segment(UpLeft(), UpRight()); }
        Segment segD() const { return Segment(BtLeft(), BtRight()); }
        Box shrink(double v) const { return {p + Point(v, v), s - Point(v*2, v*2)}; }
    };
    void line(const Segment& seg, Vopt op = {}) { VRET; line(seg.first, seg.second, op); }
    void line(const Box& box, Vopt op = {}) { VRET;
        line(box.UpLeft(), box.UpRight(), op);
        line(box.UpRight(), box.BtRight(), op);
        line(box.BtRight(), box.BtLeft(), op);
        line(box.BtLeft(), box.UpLeft(), op);
    }
    void rect(const Box& box, Vopt op = {}) { VRET; rect(box.p, box.s, op); }
}
 
struct Grid {
    int W_num = 0, H_num = 0;
    Point whole_size{-1, -1}, origin{};
    double cell_w = 0, cell_h = 0;
    Point cell_sz{};
    Grid(int WH_num) : W_num(WH_num), H_num(WH_num) { init(); }
    Grid(int W_num, int H_num, Point whole_size = {-1, -1}, Point origin = {}) : W_num(W_num), H_num(H_num), whole_size(whole_size), origin(origin) {
        init();
    }
    void init() { VRET; if(whole_size.real() < 0) whole_size = vis_internal::visualizer_campus_size;
        cell_w = whole_size.real() / W_num; cell_h = whole_size.imag() / H_num;
        cell_sz = {cell_w, cell_h}; }
    double world_x(int col) const { return origin.real() + cell_w * col; }
    double world_y(int row) const { return origin.imag() + cell_h * row; }
    double world_top() const { return world_y(0); }
    double world_bottom() const { return world_y(H_num); }
    double world_left() const { return world_x(0); }
    double world_right() const { return world_x(W_num); }
    internal::Segment seg_horizontal(int y, int x, int len = 1) const {
        return { Point{world_x(x), world_y(y)}, Point{world_x(x+len), world_y(y)} };
    }
    internal::Segment seg_horizontal(int y) const { return seg_horizontal(y, 0, W_num); }
    internal::Segment seg_vertical(int x, int y, int len = 1) const {
        return { Point{world_x(x), world_y(y)}, Point{world_x(x), world_y(y+len)} };
    }
    internal::Segment seg_vertical(int x) const { return seg_vertical(x, 0, H_num); }
    internal::Box _internal_cell(int x, int y, int w, int h) const {
        return { Point(world_x(x), world_y(y)), Point(cell_w*w, cell_h*h) };
    }
    internal::Box cell(int x, int y, int w, int h) const { return _internal_cell(x, y, h, w); }
    internal::Box cell(int x, int y) const { return _internal_cell(x, y, 1, 1); }
    internal::Box whole() const { return _internal_cell(0, 0, W_num, H_num); }
    internal::Box operator()(int x, int y) const { return cell(x, y); }
    internal::Box operator()() const { return whole(); }
};

void line(const Grid &grid, Vopt op = {}) { VRET;
    for (int y = 0; y <= grid.H_num; ++y) { line(grid.seg_horizontal(y), op); }
    for (int x = 0; x <= grid.W_num; ++x) { line(grid.seg_vertical(x), op); }
}
void rect(const Grid &grid, Vopt op = {}) { VRET; rect(grid(), op); op.v.fill.reset(); line(grid, op); }

} // namespace visualizer

// ----------------- 解法本体 -----------------
// ----------------- 解法本体 -----------------
#include <bits/stdc++.h>
using namespace std;
using namespace visualizer;

#define rep(i, n) for (int i = 0; i < (n); i++)

const int INF = 1e9;

int N, M;
vector<string> grid;
int pi, pj; // プレイヤー位置(初期は穴 'A' の位置)

struct Command {
    int op;    // 1:移動, 2:運ぶ, 3:転がす
    char dir;  // 'U','D','L','R'
};
vector<Command> ans;

int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
char dchar[4] = {'U', 'D', 'L', 'R'};

pair<int,int> holePos[26];

vector<vector<int>> computeHoleBFS(int type) {
    vector<vector<int>> dist(N, vector<int>(N, INF));
    queue<pair<int,int>> que;
    int sr = holePos[type].first, sc = holePos[type].second;
    dist[sr][sc] = 0;
    que.push({sr, sc});
    while(!que.empty()){
        auto [r, c] = que.front(); que.pop();
        rep(d, 4) {
            int nr = r + dx[d], nc = c + dy[d];
            if(nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
            char cell = grid[nr][nc];
            if(cell == '.' || cell == char('a' + type) || cell == char('A' + type)){
                if(dist[nr][nc] > dist[r][c] + 1){
                    dist[nr][nc] = dist[r][c] + 1;
                    que.push({nr, nc});
                }
            }
        }
    }
    return dist;
}
 
vector<vector<int>> bfs(int sr, int sc) {
    vector<vector<int>> dist(N, vector<int>(N, INF));
    queue<pair<int,int>> q;
    dist[sr][sc] = 0;
    q.push({sr, sc});
    while(!q.empty()){
        auto [r, c] = q.front(); q.pop();
        rep(d,4) {
            int nr = r + dx[d], nc = c + dy[d];
            if(nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
            if(dist[nr][nc] > dist[r][c] + 1){
                dist[nr][nc] = dist[r][c] + 1;
                q.push({nr, nc});
            }
        }
    }
    return dist;
}
 
vector<pair<int,int>> getPath(int sr, int sc, int tr, int tc) {
    vector<vector<int>> dist(N, vector<int>(N, INF));
    vector<vector<pair<int,int>>> parent(N, vector<pair<int,int>>(N, {-1,-1}));
    queue<pair<int,int>> que;
    dist[sr][sc] = 0;
    que.push({sr, sc});
    while(!que.empty()){
        auto [r, c] = que.front(); que.pop();
        if(r == tr && c == tc) break;
        rep(d,4) {
            int nr = r + dx[d], nc = c + dy[d];
            if(nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
            if(dist[nr][nc] > dist[r][c] + 1){
                dist[nr][nc] = dist[r][c] + 1;
                parent[nr][nc] = {r, c};
                que.push({nr, nc});
            }
        }
    }
    vector<pair<int,int>> path;
    if(dist[tr][tc] == INF) return path;
    int r = tr, c = tc;
    while(!(r == sr && c == sc)){
        path.push_back({r, c});
        auto p = parent[r][c];
        r = p.first; c = p.second;
    }
    path.push_back({sr, sc});
    reverse(path.begin(), path.end());
    return path;
}
 
struct SimResult {
    bool valid;
    bool fell;
    int score;
    int new_r, new_c;
};
 
SimResult simulateCarry(int r, int c, int d_idx, const vector<vector<vector<int>>> &holeDist) {
    SimResult res {false, false, 0, r, c};
    char obj = grid[r][c];
    if(!(obj >= 'a' && obj <= 'z')) return res;
    int type = obj - 'a';
    int nr = r + dx[d_idx], nc = c + dy[d_idx];
    if(nr < 0 || nr >= N || nc < 0 || nc >= N) return res;
    char targetCell = grid[nr][nc];
    if(targetCell != '.' && !(targetCell >= 'A' && targetCell <= 'Z')) return res;
    char correctHole = char('A' + type);
    int oldDist = holeDist[type][r][c];
    if(oldDist == INF) return res;
    if(targetCell >= 'A' && targetCell <= 'Z'){
        if(targetCell == correctHole){
            res.valid = true; res.fell = true; res.score = 100000;
            return res;
        }
        return res;
    }
    int newDist = holeDist[type][nr][nc];
    if(newDist < oldDist){
        res.valid = true; res.fell = false;
        // int min_dis_improvement = (20 - min(abs(nr - holePos[type].first), abs(nc - holePos[type].second)));
        int old_min_dis = min(abs(r - holePos[type].first), abs(c - holePos[type].second));
        int new_min_dis = min(abs(nr - holePos[type].first), abs(nc - holePos[type].second));
        int min_dis_improvement = max(0, old_min_dis - new_min_dis) * 1;
        int improvement = oldDist - newDist;
        res.score = improvement * improvement * 10 + min_dis_improvement;
        res.new_r = nr; res.new_c = nc;
    }
    return res;
}

SimResult simulateRoll(int r, int c, int d_idx, const vector<vector<vector<int>>> &holeDist) {
    SimResult res {false, false, 0, r, c};
    char obj = grid[r][c];
    if (!(obj >= 'a' && obj <= 'z')) return res;
    int type = obj - 'a';
    char correctHole = char('A' + type);
    int oldDist = holeDist[type][r][c];
    if (oldDist == INF) return res;
    int cur_r = r, cur_c = c;
    while (true) {
        int nr = cur_r + dx[d_idx], nc = cur_c + dy[d_idx];
        if (nr < 0 || nr >= N || nc < 0 || nc >= N) break;
        char cell = grid[nr][nc];
        // 新規チェック:もし cell が鉱石なら、その先も確認する
        if (cell >= 'a' && cell <= 'z') {
            int ar = nr + dx[d_idx], ac = nc + dy[d_idx];
            if (ar >= 0 && ar < N && ac >= 0 && ac < N) {
                char cell2 = grid[ar][ac];
                if (cell2 != '.') { // 空きマスでなければペナルティ
                    res.valid = true;
                    res.fell = false;
                    // res.score = -5000;
                    // return res;
                }
            }
            break; // 衝突したのでループ終了
        }
        if (cell >= 'A' && cell <= 'Z') {
            // 穴にぶつかった場合:正しい穴なら落下(消失)として評価
            if (cell == correctHole) {
                res.valid = true;
                res.fell = true;
                res.score = 100000;
            }
            return res;
        }
        if (cell == '@') break;
        cur_r = nr; cur_c = nc;
    }
    int newDist = holeDist[type][cur_r][cur_c];
    if (newDist < oldDist) {
        res.valid = true;
        res.fell = false;
        int improvement = oldDist - newDist;
        res.score += improvement * improvement * 10;
        res.new_r = cur_r; res.new_c = cur_c;
    }
    return res;
}

void performMove(int op, int d_idx) {
    Command cmd; cmd.op = op; cmd.dir = dchar[d_idx];
    ans.push_back(cmd);
    if(op == 1) {
        pi += dx[d_idx]; pj += dy[d_idx];
    } else if(op == 2) {
        int nr = pi + dx[d_idx], nc = pj + dy[d_idx];
        char obj = grid[pi][pj];
        grid[pi][pj] = '.';
        if(grid[nr][nc] >= 'A' && grid[nr][nc] <= 'Z'){
            // 穴なら落下(除去)
        } else {
            grid[nr][nc] = obj;
        }
        pi = nr; pj = nc;
    } else if(op == 3) {
        int r = pi, c = pj;
        char obj = grid[r][c];
        grid[r][c] = '.';
        int cur_r = r, cur_c = c;
        while(true) {
            int nr = cur_r + dx[d_idx], nc = cur_c + dy[d_idx];
            if(nr < 0 || nr >= N || nc < 0 || nc >= N) break;
            char cell = grid[nr][nc];
            if(cell >= 'A' && cell <= 'Z'){
                if(obj == '@') {
                    // 岩の場合は、穴にぶつかったら必ず落下(消失)
                    return;
                } else {
                    // 鉱石の場合は、正しい穴なら落下
                    if(cell == char('A' + (obj - 'a'))){
                        return;
                    }
                    break;
                }
            }
            if(cell == '@' || (cell >= 'a' && cell <= 'z')) break;
            cur_r = nr; cur_c = nc;
        }
        grid[cur_r][cur_c] = obj;
    }
}
 
// drawState: Grid を用いて盤面を描画する(色設定は以前の例通り)
void drawState(const Grid &G) {
    for (int i = 0; i < N; i++){
        for (int j = 0; j < N; j++){
            char cell = grid[i][j];
            if(cell == '@'){
                rect(G(j, i), "gray");
            } else if(cell >= 'a' && cell <= 'z'){
                string col;
                int type = cell - 'a';
                if(type == 0) col = "#ff6666";         // 鉱石 a: 赤系
                else if(type == 1) col = "#66ff66";      // 鉱石 b: 緑系
                else if(type == 2) col = "#6666ff";      // 鉱石 c: 青系
                else col = "#cccccc";
                circle(G(j, i), min(G.cell_sz.real(), G.cell_sz.imag())/4, Vopt(col).stroke(col, 1));
            } else if(cell >= 'A' && cell <= 'Z'){
                string col;
                int type = cell - 'A';
                if(type == 0) col = "#ff0000";         // 穴 A: 赤
                else if(type == 1) col = "#00ff00";      // 穴 B: 緑
                else if(type == 2) col = "#0000ff";      // 穴 C: 青
                else col = "#999999";
                circle(G(j, i), min(G.cell_sz.real(), G.cell_sz.imag())/3, Vopt(col).stroke(col, 1));
            }
        }
    }
    circle(G(pj, pi), min(G.cell_sz.real(), G.cell_sz.imag())/3, Vopt("", "black", 2));
}

void printGrid() {
    rep(i, N) {
        rep(j, N) {
            cerr << grid[i][j];
        }
        cerr << endl;
    }
}

 
// ----- 新規追加:鉱石が存在するエリアを DFS で計算する -----
set<pair<int,int>> getMineralArea() {
    set<pair<int,int>> area;
    vector<vector<bool>> visited(N, vector<bool>(N, false));
    rep(i, N) {
        rep(j, N) {
            // 岩は含まない
            if(grid[i][j] == '@' || visited[i][j]) continue;
            // DFS で連結領域を求める
            vector<pair<int,int>> comp;
            bool containsMineral = false;
            stack<pair<int,int>> st;
            st.push({i,j});
            visited[i][j] = true;
            while(!st.empty()){
                auto [r, c] = st.top();
                st.pop();
                comp.push_back({r, c});
                if(grid[r][c] >= 'a' && grid[r][c] <= 'z') containsMineral = true;
                rep(d,4) {
                    int nr = r + dx[d], nc = c + dy[d];
                    if(nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
                    if(grid[nr][nc] == '@') continue;
                    if(!visited[nr][nc]){
                        visited[nr][nc] = true;
                        st.push({nr, nc});
                    }
                }
            }
            if(containsMineral) {
                for(auto &p : comp) area.insert(p);
            }
        }
    }
    return area;
}
 
// DigCandidate 用構造体
struct DigCandidate {
    int digs;
    int distFromHole;
    pair<int,int> cell;
    int dir; // 0:U,1:D,2:L,3:R
};
 
// evaluateDigCandidate: 指定の境界セル cell と方向 d に対し、
// 隣接する岩群を除去した先のセルが、あらかじめ計算された mineralArea に含まれているかを判定する。
optional<DigCandidate> evaluateDigCandidate(const set<pair<int,int>> &mineralArea,
    const vector<vector<int>> &curDist, pair<int,int> cell, int d) {
    int r = cell.first, c = cell.second;
    int nr = r + dx[d], nc = c + dy[d];
    if(nr < 0 || nr >= N || nc < 0 || nc >= N) return nullopt;
    if(grid[nr][nc] != '@') return nullopt;
    int digs = 0;
    // 岩が連続する部分を数える
    while(nr >= 0 && nr < N && nc >= 0 && nc < N && grid[nr][nc] == '@') {
        digs++;
        nr += dx[d]; nc += dy[d];
    }
    if(nr < 0 || nr >= N || nc < 0 || nc >= N) return nullopt;
    // ここで、候補先は (nr, nc) ですが、実際の掘削操作では、boundary cell から
    // d の反対方向 (oppDir) に digs 回ロールして岩を除去する必要がある。
    int oppDir = (d == 0 ? 1 : (d == 1 ? 0 : (d == 2 ? 3 : 2)));
    
    // 仮想盤面 tempGrid において、候補の岩群を除去するシミュレーション
    auto tempGrid = grid; // grid のコピー
    // 掘削すべき岩は、boundary cell の隣(cell + d 方向)から digs 個
    int rr = r + dx[d], cc = c + dy[d];
    for (int k = 0; k < digs; k++) {
        if(rr < 0 || rr >= N || cc < 0 || cc >= N) break;
        tempGrid[rr][cc] = '.';  // 岩を除去
        rr += dx[d]; cc += dy[d];
    }
    // さらに、候補として実際に反対方向に roll するシミュレーションを行う
    // すなわち、boundary cell から oppDir に1歩移動(実際の掘削操作のセットの前段)をシミュレーション
    int test_r = r + dx[oppDir], test_c = c + dy[oppDir];
    if(test_r < 0 || test_r >= N || test_c < 0 || test_c >= N) return nullopt;
    // tempGrid の該当位置を空にしておく(もし岩であれば、roll により除去されると想定)
    tempGrid[test_r][test_c] = '.';
    // 仮想盤面 tempGrid を用いて、穴 'A' からの BFS を行う局所版 computeHoleBFS
    auto computeHoleBFS_temp = [&tempGrid](int type) -> vector<vector<int>> {
        vector<vector<int>> dist(N, vector<int>(N, INF));
        queue<pair<int,int>> que;
        int sr = holePos[type].first, sc = holePos[type].second;
        dist[sr][sc] = 0;
        que.push({sr, sc});
        while(!que.empty()){
            auto [r, c] = que.front(); que.pop();
            rep(d,4) {
                int nr = r + dx[d], nc = c + dy[d];
                if(nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
                char cell = tempGrid[nr][nc];
                if(cell == '.' || cell == char('a' + type) || cell == char('A' + type)){
                    if(dist[nr][nc] > dist[r][c] + 1){
                        dist[nr][nc] = dist[r][c] + 1;
                        que.push({nr, nc});
                    }
                }
            }
        }
        return dist;
    };
    // M=1 の場合、type は 0 とする
    auto newHoleDist = computeHoleBFS_temp(0);
    // 掘削後、穴 'A' の領域に、mineralArea のどれかのセルが含まれていれば接続成功
    bool connected = false;
    for(auto &p : mineralArea) {
        int r0 = p.first, c0 = p.second;
        if(newHoleDist[r0][c0] < INF) { connected = true; break; }
    }
    if(!connected) return nullopt;
    
    DigCandidate cand {digs, curDist[r][c], {r, c}, d};
    return cand;
}
 
// ----- メインループ -----
// まず、連結エリア内に鉱石がある場合は従来の回収を行い、なければ、連結エリアの境界から掘削候補を評価
void solve() {
    cin >> N >> M;
    visualizer_helper visualizer_helper(Point{N*10.0, N*10.0});
    
    grid.resize(N);
    rep(i, N) {
        cin >> grid[i];
    }
    rep(i, N) {
        rep(j, N) {
            char c = grid[i][j];
            if(c >= 'A' && c <= 'Z'){
                int type = c - 'A';
                holePos[type] = {i, j};
                if(c == 'A'){
                    pi = i; pj = j;
                }
            }
        }
    }
    vector<vector<vector<int>>> holeDist;
    holeDist.resize(M);
    rep(t, M) {
        holeDist[t] = computeHoleBFS(t);
    }
    
    Grid G(N);
    rect(G, "#fff");
    line(G, Vopt("#bbb", 0.2));
    
    vtime(0);
    drawState(G);
    
    int moves = 0;
    while(moves < 10000) {
        // cerr << "moves: " << moves << endl;
        bool mineralExists = false;
        rep(i, N) {
            rep(j, N) {
                if(grid[i][j] >= 'a' && grid[i][j] <= 'z'){
                    mineralExists = true;
                    break;
                }
            }
            if(mineralExists) break;
        }
        if(!mineralExists) {
            cerr << "No mineral found" << endl;
            break;
        }
 
        // 現在地からの距離を計算
        vector<vector<int>> curDist = bfs(pi, pj);
 
        // まず、連結エリア(穴から到達可能なエリア)内に鉱石があるかチェック
        set<pair<int,int>> connectedRegion;
        {
            // ここでは、getConnectedRegion() を既存の方法で計算(省略可)
            // ※既存コード例では region を hole からの BFS で求める
            queue<pair<int,int>> q;
            vector<vector<bool>> vis(N, vector<bool>(N, false));
            int start_r = holePos[0].first, start_c = holePos[0].second;
            q.push({start_r, start_c}); // TODO
            vis[start_r][start_c] = true;
            while(!q.empty()){
                auto [r, c] = q.front(); q.pop();
                connectedRegion.insert({r, c});
                rep(d,4) {
                    int nr = r + dx[d], nc = c + dy[d];
                    if(nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
                    if(!vis[nr][nc] && grid[nr][nc] != '@'){
                        vis[nr][nc] = true;
                        q.push({nr, nc});
                    }
                }
            }
        }
 
        bool hasMineralInRegion = false;
        for(auto &p : connectedRegion) {
            int r = p.first, c = p.second;
            if(grid[r][c] >= 'a' && grid[r][c] <= 'z'){
                hasMineralInRegion = true;
                break;
            }
        }
        // printGrid();

        // cerr << "hasMineralInRegion: " << hasMineralInRegion << endl;
 
        if(hasMineralInRegion) {
            // 通常の回収フェーズ(従来の評価:評価値 = (穴までの距離) - max(0, (現在地からの距離-1))*10000)
            int candidate_target_r = -1, candidate_target_c = -1, candidate_targetType = -1;
            int candidate_bestVal = -1000000000;
            SimResult candidate_bestOpRes;
            bool candidateFound = false;
            rep(i, N) {
                rep(j, N) {
                    if(grid[i][j] >= 'a' && grid[i][j] <= 'z'){
                        int type = grid[i][j] - 'a';
                        int d_h = holeDist[type][i][j];
                        if(d_h == INF) continue;
                        int penalty = max(0, curDist[i][j] - 1) * 10000;
                        if(abs(holePos[type].first - i) == 1 || abs(holePos[type].second - j) == 1){
                            penalty += 100;
                        }


                        int eval = d_h - penalty;
                        SimResult bestOpForCell {false, false, 0, i, j};
                        bool validFoundForCell = false;
                        rep(dir,4) {
                            int score_offset = 0;
                            SimResult resCarry = simulateCarry(i, j, dir, holeDist);
                            SimResult resRoll = simulateRoll(i, j, dir, holeDist);
                            resCarry.score += score_offset;
                            resRoll.score += score_offset;

                            if(resCarry.valid && resCarry.score > bestOpForCell.score){
                                bestOpForCell = resCarry;
                                validFoundForCell = true;
                            }
                            if(resRoll.valid && resRoll.score > bestOpForCell.score){
                                bestOpForCell = resRoll;
                                validFoundForCell = true;
                            }
                        }
                        if(validFoundForCell && eval > candidate_bestVal) {
                            candidate_bestVal = eval;
                            candidate_target_r = i;
                            candidate_target_c = j;
                            candidate_targetType = type;
                            candidate_bestOpRes = bestOpForCell;
                            candidateFound = true;
                        }
                    }
                }
            }
            if(!candidateFound) break;
            vector<pair<int,int>> path = getPath(pi, pj, candidate_target_r, candidate_target_c);
            if(path.empty()) break;
            for (int i = 1; i < (int)path.size() && moves < 10000; i++){
                int cr = path[i-1].first, cc = path[i-1].second;
                int nr = path[i].first, nc = path[i].second;
                int d_idx = -1;
                rep(d,4) {
                    if(cr + dx[d] == nr && cc + dy[d] == nc){
                        d_idx = d;
                        break;
                    }
                }
                performMove(1, d_idx);
                moves++;
                vtime(moves);
                drawState(G);
            }
            int chosenOp = -1, chosenDir = -1;
            if(candidate_bestOpRes.valid){
                int bestScore = candidate_bestOpRes.score;
                rep(d,4) {
                    SimResult r1 = simulateCarry(pi, pj, d, holeDist);
                    if(r1.valid && r1.score == bestScore) { chosenOp = 2; chosenDir = d; break; }
                    SimResult r2 = simulateRoll(pi, pj, d, holeDist);
                    if(r2.valid && r2.score == bestScore) { chosenOp = 3; chosenDir = d; break; }
                }
            }
            if(chosenOp == -1) break;
            performMove(chosenOp, chosenDir);
            moves++;
            vtime(moves);
            drawState(G);
            if (M > 1) rep(t, M) {
                holeDist[t] = computeHoleBFS(t);
            }
        } else {
            // 連結エリア内に鉱石が無い場合:まず、非岩セル同士で連結しているうち、鉱石が存在するエリアを DFS で計算する
            set<pair<int,int>> mineralArea = getMineralArea();
 
            // 連結エリア(hole から到達可能なエリア)の境界(隣接して岩があるセル)を抽出
            vector<pair<int,int>> boundaries;
            for(auto p : connectedRegion) {
                int r = p.first, c = p.second;
                rep(d,4) {
                    int nr = r + dx[d], nc = c + dy[d];
                    if(nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
                    if(grid[nr][nc] == '@'){
                        boundaries.push_back({r, c});
                        break;
                    }
                }
            }
            // 各境界セルについて、各方向の掘削候補を評価
            optional<DigCandidate> bestCand;
            for(auto cell : boundaries) {
                rep(d,4) {
                    auto cand = evaluateDigCandidate(mineralArea, curDist, cell, d);
                    if(cand) {
                        if(!bestCand.has_value() || cand->digs < bestCand->digs ||
                           (cand->digs == bestCand->digs && cand->distFromHole < bestCand->distFromHole))
                        {
                            bestCand = cand;
                        }
                    }
                }
            }
            if(!bestCand.has_value()) break;
            vector<pair<int,int>> path = getPath(pi, pj, bestCand->cell.first, bestCand->cell.second);
            if(path.empty()) break;
            for (int i = 1; i < (int)path.size() && moves < 10000; i++){
                int cr = path[i-1].first, cc = path[i-1].second;
                int nr = path[i].first, nc = path[i].second;
                int d_idx = -1;
                rep(d,4) {
                    if(cr + dx[d] == nr && cc + dy[d] == nc){
                        d_idx = d;
                        break;
                    }
                }
                performMove(1, d_idx);
                moves++;
                vtime(moves);
                drawState(G);
            }
            // cerr << "bestCand.cell: " << bestCand->cell.first << "," << bestCand->cell.second << " " << bestCand->digs << " " << bestCand->dir << "\n";

            // 掘削操作:候補で決定した方向へ、候補の digs 回だけ roll 操作を実行
            int oppDir = (bestCand->dir == 0 ? 1 : (bestCand->dir == 1 ? 0 : (bestCand->dir == 2 ? 3 : 2)));
            rep(i, bestCand->digs) {
                performMove(1, bestCand->dir);
                moves++;
                vtime(moves);
                drawState(G);
                performMove(3, oppDir);
                moves++;
                vtime(moves);
                drawState(G);
            }
            // 掘削後、holeDist を再計算
            rep(t, M) {
                holeDist[t] = computeHoleBFS(t);
            }
            // cerr << "掘削ed: "<< endl;
        }
    }
 
    for(auto &cmd : ans) {
        cout << cmd.op << " " << cmd.dir << "\n";
    }
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
    return 0;
}

Submission Info

Submission Time
Task C - Ore Rolling (C)
User TumoiYorozu
Language C++ 20 (gcc 12.2)
Score 751107275
Code Size 42540 Byte
Status AC
Exec Time 15 ms
Memory 3700 KiB

Compile Error

Main.cpp: In function ‘void solve()’:
Main.cpp:914:67: warning: variable ‘candidate_targetType’ set but not used [-Wunused-but-set-variable]
  914 |             int candidate_target_r = -1, candidate_target_c = -1, candidate_targetType = -1;
      |                                                                   ^~~~~~~~~~~~~~~~~~~~
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {const char*, const char*}]’:
Main.cpp:192:20:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |            ~~~~~~~~~~~~^~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |                                ~~~~^~~~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#1’ [-Wunused-parameter]
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {const char*, float}]’:
Main.cpp:195:20:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |            ~~~~~~~~~~~~^~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |                                ~~~~^~~~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#1’ [-Wunused-parameter]
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {const char*}]’:
Main.cpp:204:32:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |            ~~~~~~~~~~~~^~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |                                ~~~~^~~~~~~~
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {}]’:
Main.cpp:205:28:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |            ~~~~~~~~~~~~^~~~~~
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {short int}]’:
Main.cpp:210:24:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
Main.cpp:169:36: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |                                ~~~~^~~~~~~~
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {double, double, float}]’:
Main.cpp:253:10:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |            ~~~~~~~~~~~~^~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |                                ~~~~^~~~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#1’ [-Wunused-parameter]
Main.cpp:169:36: warning: unused parameter ‘args#2’ [-Wunused-parameter]
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {double, double, double, double}]’:
Main.cpp:267:10:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |            ~~~~~~~~~~~~^~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |                                ~~~~^~~~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#1’ [-Wunused-parameter]
Main.cpp:169:36: warning: unused parameter ‘args#2’ [-Wunused-parameter]
Main.cpp:169:36: warning: unused parameter ‘args#3’ [-Wunused-parameter]
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {double, double, double, double, float, double, double}]’:
Main.cpp:284:10:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |            ~~~~~~~~~~~~^~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |                                ~~~~^~~~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#1’ [-Wunused-parameter]
Main.cpp:169:36: warning: unused parameter ‘args#2’ [-Wunused-parameter]
Main.cpp:169:36: warning: unused parameter ‘args#3’ [-Wunused-parameter]
Main.cpp:169:36: warning: unused parameter ‘args#4’ [-Wunused-parameter]
Main.cpp:169:36: warning: unused parameter ‘args#5’ [-Wunused-parameter]
Main.cpp:169:36: warning: unused parameter ‘args#6’ [-Wunused-parameter]
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {double, double}]’:
Main.cpp:292:27:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |            ~~~~~~~~~~~~^~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |                                ~~~~^~~~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#1’ [-Wunused-parameter]
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {int}]’:
Main.cpp:339:31:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |            ~~~~~~~~~~~~^~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |                                ~~~~^~~~~~~~
Main.cpp: In instantiation of ‘void visualizer::print(const char*, Args ...) [with Args = {int, int}]’:
Main.cpp:340:26:   required from here
Main.cpp:169:24: warning: unused parameter ‘format’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |            ~~~~~~~~~~~~^~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  169 | void print(const char* format, Args... args) { return; }
      |                                ~~~~^~~~~~~~
Main.cpp:169:36: warning: unused parameter ‘args#1’ [-Wunused-parameter]
Main.cpp: In instantiation of ‘visualizer::visualizer_helper::visualizer_helper(Args ...) [with Args = {std::complex<double>}]’:
Main.cpp:824:62:   required from here
Main.cpp:167:77: warning: unused parameter ‘args#0’ [-Wunused-parameter]
  167 | struct visualizer_helper { template<typename... Args> visualizer_helper(Args... args) {} };
      |                                                                         ~~~~^~~~~~~~
Main.cpp:985:33: warning: ‘candidate_bestOpRes.SimResult::score’ may be used uninitialized [-Wmaybe-uninitialized]
  985 |                     if(r2.valid && r2.score == bestScore) { chosenOp = 3; chosenDir = d; break; }
      |                        ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
Main.cpp:916:23: note: ‘candidate_bestOpRes.SimResult::score’ was declared here
  916 |             SimResult candidate_bestOpRes;
      |                       ^~~~~~~~~~~~~~~~~~~

Judge Result

Set Name test_ALL
Score / Max Score 751107275 / 1500000000
Status
AC × 150
Set Name Test Cases
test_ALL test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt, test_0100.txt, test_0101.txt, test_0102.txt, test_0103.txt, test_0104.txt, test_0105.txt, test_0106.txt, test_0107.txt, test_0108.txt, test_0109.txt, test_0110.txt, test_0111.txt, test_0112.txt, test_0113.txt, test_0114.txt, test_0115.txt, test_0116.txt, test_0117.txt, test_0118.txt, test_0119.txt, test_0120.txt, test_0121.txt, test_0122.txt, test_0123.txt, test_0124.txt, test_0125.txt, test_0126.txt, test_0127.txt, test_0128.txt, test_0129.txt, test_0130.txt, test_0131.txt, test_0132.txt, test_0133.txt, test_0134.txt, test_0135.txt, test_0136.txt, test_0137.txt, test_0138.txt, test_0139.txt, test_0140.txt, test_0141.txt, test_0142.txt, test_0143.txt, test_0144.txt, test_0145.txt, test_0146.txt, test_0147.txt, test_0148.txt, test_0149.txt
Case Name Status Exec Time Memory
test_0000.txt AC 8 ms 3404 KiB
test_0001.txt AC 6 ms 3524 KiB
test_0002.txt AC 5 ms 3464 KiB
test_0003.txt AC 6 ms 3508 KiB
test_0004.txt AC 6 ms 3488 KiB
test_0005.txt AC 5 ms 3676 KiB
test_0006.txt AC 9 ms 3556 KiB
test_0007.txt AC 6 ms 3480 KiB
test_0008.txt AC 6 ms 3456 KiB
test_0009.txt AC 5 ms 3592 KiB
test_0010.txt AC 5 ms 3524 KiB
test_0011.txt AC 6 ms 3600 KiB
test_0012.txt AC 11 ms 3528 KiB
test_0013.txt AC 7 ms 3604 KiB
test_0014.txt AC 7 ms 3568 KiB
test_0015.txt AC 5 ms 3488 KiB
test_0016.txt AC 5 ms 3548 KiB
test_0017.txt AC 5 ms 3608 KiB
test_0018.txt AC 6 ms 3568 KiB
test_0019.txt AC 10 ms 3700 KiB
test_0020.txt AC 5 ms 3464 KiB
test_0021.txt AC 5 ms 3496 KiB
test_0022.txt AC 4 ms 3564 KiB
test_0023.txt AC 7 ms 3544 KiB
test_0024.txt AC 4 ms 3504 KiB
test_0025.txt AC 6 ms 3480 KiB
test_0026.txt AC 6 ms 3680 KiB
test_0027.txt AC 8 ms 3552 KiB
test_0028.txt AC 6 ms 3504 KiB
test_0029.txt AC 6 ms 3556 KiB
test_0030.txt AC 5 ms 3600 KiB
test_0031.txt AC 2 ms 3492 KiB
test_0032.txt AC 9 ms 3488 KiB
test_0033.txt AC 6 ms 3600 KiB
test_0034.txt AC 8 ms 3548 KiB
test_0035.txt AC 6 ms 3552 KiB
test_0036.txt AC 6 ms 3504 KiB
test_0037.txt AC 5 ms 3552 KiB
test_0038.txt AC 5 ms 3400 KiB
test_0039.txt AC 10 ms 3620 KiB
test_0040.txt AC 6 ms 3496 KiB
test_0041.txt AC 7 ms 3504 KiB
test_0042.txt AC 5 ms 3520 KiB
test_0043.txt AC 8 ms 3604 KiB
test_0044.txt AC 6 ms 3548 KiB
test_0045.txt AC 8 ms 3504 KiB
test_0046.txt AC 10 ms 3612 KiB
test_0047.txt AC 5 ms 3548 KiB
test_0048.txt AC 5 ms 3500 KiB
test_0049.txt AC 6 ms 3568 KiB
test_0050.txt AC 8 ms 3500 KiB
test_0051.txt AC 6 ms 3512 KiB
test_0052.txt AC 9 ms 3520 KiB
test_0053.txt AC 5 ms 3516 KiB
test_0054.txt AC 6 ms 3540 KiB
test_0055.txt AC 7 ms 3548 KiB
test_0056.txt AC 6 ms 3568 KiB
test_0057.txt AC 6 ms 3460 KiB
test_0058.txt AC 4 ms 3600 KiB
test_0059.txt AC 6 ms 3404 KiB
test_0060.txt AC 5 ms 3456 KiB
test_0061.txt AC 5 ms 3480 KiB
test_0062.txt AC 7 ms 3688 KiB
test_0063.txt AC 4 ms 3476 KiB
test_0064.txt AC 5 ms 3500 KiB
test_0065.txt AC 6 ms 3496 KiB
test_0066.txt AC 5 ms 3548 KiB
test_0067.txt AC 4 ms 3680 KiB
test_0068.txt AC 7 ms 3548 KiB
test_0069.txt AC 5 ms 3400 KiB
test_0070.txt AC 6 ms 3524 KiB
test_0071.txt AC 5 ms 3516 KiB
test_0072.txt AC 5 ms 3596 KiB
test_0073.txt AC 6 ms 3604 KiB
test_0074.txt AC 5 ms 3508 KiB
test_0075.txt AC 7 ms 3480 KiB
test_0076.txt AC 1 ms 3512 KiB
test_0077.txt AC 5 ms 3520 KiB
test_0078.txt AC 6 ms 3552 KiB
test_0079.txt AC 4 ms 3680 KiB
test_0080.txt AC 5 ms 3520 KiB
test_0081.txt AC 6 ms 3688 KiB
test_0082.txt AC 6 ms 3556 KiB
test_0083.txt AC 5 ms 3472 KiB
test_0084.txt AC 7 ms 3552 KiB
test_0085.txt AC 7 ms 3688 KiB
test_0086.txt AC 7 ms 3496 KiB
test_0087.txt AC 8 ms 3660 KiB
test_0088.txt AC 6 ms 3504 KiB
test_0089.txt AC 10 ms 3548 KiB
test_0090.txt AC 8 ms 3492 KiB
test_0091.txt AC 7 ms 3408 KiB
test_0092.txt AC 4 ms 3400 KiB
test_0093.txt AC 5 ms 3604 KiB
test_0094.txt AC 5 ms 3496 KiB
test_0095.txt AC 5 ms 3564 KiB
test_0096.txt AC 5 ms 3556 KiB
test_0097.txt AC 4 ms 3484 KiB
test_0098.txt AC 4 ms 3608 KiB
test_0099.txt AC 7 ms 3548 KiB
test_0100.txt AC 6 ms 3504 KiB
test_0101.txt AC 6 ms 3500 KiB
test_0102.txt AC 6 ms 3544 KiB
test_0103.txt AC 6 ms 3524 KiB
test_0104.txt AC 7 ms 3528 KiB
test_0105.txt AC 7 ms 3468 KiB
test_0106.txt AC 9 ms 3552 KiB
test_0107.txt AC 5 ms 3684 KiB
test_0108.txt AC 5 ms 3600 KiB
test_0109.txt AC 5 ms 3544 KiB
test_0110.txt AC 6 ms 3552 KiB
test_0111.txt AC 8 ms 3540 KiB
test_0112.txt AC 7 ms 3404 KiB
test_0113.txt AC 12 ms 3572 KiB
test_0114.txt AC 5 ms 3680 KiB
test_0115.txt AC 10 ms 3612 KiB
test_0116.txt AC 7 ms 3600 KiB
test_0117.txt AC 7 ms 3496 KiB
test_0118.txt AC 10 ms 3512 KiB
test_0119.txt AC 5 ms 3496 KiB
test_0120.txt AC 5 ms 3564 KiB
test_0121.txt AC 4 ms 3600 KiB
test_0122.txt AC 5 ms 3568 KiB
test_0123.txt AC 5 ms 3680 KiB
test_0124.txt AC 15 ms 3492 KiB
test_0125.txt AC 6 ms 3560 KiB
test_0126.txt AC 5 ms 3600 KiB
test_0127.txt AC 4 ms 3500 KiB
test_0128.txt AC 7 ms 3600 KiB
test_0129.txt AC 5 ms 3684 KiB
test_0130.txt AC 5 ms 3596 KiB
test_0131.txt AC 6 ms 3520 KiB
test_0132.txt AC 8 ms 3544 KiB
test_0133.txt AC 5 ms 3544 KiB
test_0134.txt AC 4 ms 3552 KiB
test_0135.txt AC 4 ms 3680 KiB
test_0136.txt AC 6 ms 3516 KiB
test_0137.txt AC 6 ms 3492 KiB
test_0138.txt AC 5 ms 3564 KiB
test_0139.txt AC 5 ms 3404 KiB
test_0140.txt AC 7 ms 3608 KiB
test_0141.txt AC 8 ms 3600 KiB
test_0142.txt AC 6 ms 3504 KiB
test_0143.txt AC 6 ms 3548 KiB
test_0144.txt AC 6 ms 3516 KiB
test_0145.txt AC 4 ms 3680 KiB
test_0146.txt AC 4 ms 3560 KiB
test_0147.txt AC 6 ms 3476 KiB
test_0148.txt AC 5 ms 3456 KiB
test_0149.txt AC 5 ms 3536 KiB