結果

問題 No.5022 XOR Printer
ユーザー Ang1077
提出日時 2025-07-26 15:59:12
言語 C++23
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 1,983 ms / 2,000 ms
コード長 16,554 bytes
コンパイル時間 4,463 ms
コンパイル使用メモリ 338,416 KB
実行使用メモリ 7,716 KB
スコア 5,176,258,371
最終ジャッジ日時 2025-07-26 16:01:00
合計ジャッジ時間 107,997 ms
ジャッジサーバーID
(参考情報)
judge1 / judge3
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 50
権限があれば一括ダウンロードができます

ソースコード

diff #

// #pragma GCC optimize
// "-O3,omit-frame-pointer,inline,unroll-all-loops,fast-math" #pragma GCC target
// "tune=native"
#include <bits/stdc++.h>
// INCLUDE <experimental/simd>
// INCLUDE <atcoder/all>
#include <ext/pb_ds/assoc_container.hpp>
// #include <immintrin.h>
// #include <sys/time.h>
// #include <x86intrin.h>

using namespace std;
// Macros
#define el '\n'
#define all(v) (v).begin(), (v).end()
using i8 = int8_t;
using u8 = uint8_t;
using i16 = int16_t;
using u16 = uint16_t;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
using f32 = float;
using f64 = double;
#define rep(i, n) for (i64 i = 0; i < (i64)(n); i++)
template <class T> using min_queue = priority_queue<T, vector<T>, greater<T>>;
template <class T> using max_queue = priority_queue<T>;
struct uint64_hash {
    static inline uint64_t rotr(uint64_t x, unsigned k) {
        return (x >> k) | (x << (8U * sizeof(uint64_t) - k));
    }
    static inline uint64_t hash_int(uint64_t x) noexcept {
        auto h1 = x * (uint64_t)(0xA24BAED4963EE407);
        auto h2 = rotr(x, 32U) * (uint64_t)(0x9FB21C651E98DF25);
        auto h = rotr(h1 + h2, 32U);
        return h;
    }
    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM =
            std::chrono::steady_clock::now().time_since_epoch().count();
        return hash_int(x + FIXED_RANDOM);
    }
};
template <typename K, typename V, typename Hash = uint64_hash>
using hash_map = __gnu_pbds::gp_hash_table<K, V, Hash>;
template <typename K, typename Hash = uint64_hash>
using hash_set = hash_map<K, __gnu_pbds::null_type, Hash>;

// Constant
constexpr bool DEBUG = false;
const double pi = 3.141592653589793238;
const i32 inf32 = 1073741823;
const i64 inf64 = 1LL << 60;
const string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string abc = "abcdefghijklmnopqrstuvwxyz";
const int MOD = 998244353;
const array<int, 8> dx = {0, 0, -1, 1, -1, -1, 1, 1};
const array<int, 8> dy = {-1, 1, 0, 0, -1, 1, -1, 1};

// Printing (optional)
template <class T> void print_collection(ostream &out, T const &x);
template <class T, size_t... I>
void print_tuple(ostream &out, T const &a, index_sequence<I...>);
namespace std {
template <class... A> ostream &operator<<(ostream &out, tuple<A...> const &x) {
    print_tuple(out, x, index_sequence_for<A...>{});
    return out;
}
template <class... A> ostream &operator<<(ostream &out, pair<A...> const &x) {
    print_tuple(out, x, index_sequence_for<A...>{});
    return out;
}
template <class A, size_t N>
ostream &operator<<(ostream &out, array<A, N> const &x) {
    print_collection(out, x);
    return out;
}
template <class A> ostream &operator<<(ostream &out, vector<A> const &x) {
    print_collection(out, x);
    return out;
}
template <class A> ostream &operator<<(ostream &out, deque<A> const &x) {
    print_collection(out, x);
    return out;
}
template <class A> ostream &operator<<(ostream &out, multiset<A> const &x) {
    print_collection(out, x);
    return out;
}
template <class A, class B>
ostream &operator<<(ostream &out, multimap<A, B> const &x) {
    print_collection(out, x);
    return out;
}
template <class A> ostream &operator<<(ostream &out, set<A> const &x) {
    print_collection(out, x);
    return out;
}
template <class A, class B>
ostream &operator<<(ostream &out, map<A, B> const &x) {
    print_collection(out, x);
    return out;
}
template <class A>
ostream &operator<<(ostream &out, unordered_set<A> const &x) {
    print_collection(out, x);
    return out;
}
} // namespace std
template <class T, size_t... I>
void print_tuple(ostream &out, T const &a, index_sequence<I...>) {
    using swallow = int[];
    out << '(';
    (void)swallow{0, (void(out << (I == 0 ? "" : ", ") << get<I>(a)), 0)...};
    out << ')';
}
template <class T> void print_collection(ostream &out, T const &x) {
    int f = 0;
    out << '[';
    for (auto const &i : x) {
        out << (f++ ? "," : "");
        out << i;
    }
    out << "]";
}

// Random
struct RNG {
    uint64_t s[2];
    RNG(u64 seed) { reset(seed); }
    RNG() { reset(time(0)); }
    using result_type = u32;
    constexpr u32 min() { return numeric_limits<u32>::min(); }
    constexpr u32 max() { return numeric_limits<u32>::max(); }
    u32 operator()() { return randomInt32(); }
    static __attribute__((always_inline)) inline uint64_t rotl(const uint64_t x,
                                                               int k) {
        return (x << k) | (x >> (64 - k));
    }
    inline void reset(u64 seed) {
        struct splitmix64_state {
            u64 s;
            u64 splitmix64() {
                u64 result = (s += 0x9E3779B97f4A7C15);
                result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9;
                result = (result ^ (result >> 27)) * 0x94D049BB133111EB;
                return result ^ (result >> 31);
            }
        };
        splitmix64_state sm{seed};
        s[0] = sm.splitmix64();
        s[1] = sm.splitmix64();
    }
    uint64_t next() {
        const uint64_t s0 = s[0];
        uint64_t s1 = s[1];
        const uint64_t result = rotl(s0 * 5, 7) * 9;
        s1 ^= s0;
        s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
        s[1] = rotl(s1, 37);                   // c
        return result;
    }
    inline u32 randomInt32() { return (u32)next(); }
    inline u64 randomInt64() { return next(); }
    inline u32 random32(u32 r) { return (((u64)randomInt32()) * r) >> 32; }
    inline u64 random64(u64 r) { return randomInt64() % r; }
    inline u32 randomRange32(u32 l, u32 r) { return l + random32(r - l + 1); }
    inline u64 randomRange64(u64 l, u64 r) { return l + random64(r - l + 1); }
    inline double randomDouble() {
        return (double)randomInt32() / 4294967296.0;
    }
    inline float randomFloat() { return (float)randomInt32() / 4294967296.0; }
    inline double randomRangeDouble(double l, double r) {
        return l + randomDouble() * (r - l);
    }
    template <class T> void shuffle(vector<T> &v) {
        i32 sz = (i32)v.size();
        for (i32 i = sz; i > 1; i--) {
            i32 p = random32(i);
            swap(v[i - 1], v[p]);
        }
    }
    template <class T> void shuffle(T *fr, T *to) {
        i32 sz = (i32)distance(fr, to);
        for (int i = sz; i > 1; i--) {
            int p = random32(i);
            swap(fr[i - 1], fr[p]);
        }
    }
    template <class T> inline int sample_index(vector<T> const &v) {
        return random32((u32)v.size());
    }
    template <class T> inline T sample(vector<T> const &v) {
        return v[sample_index(v)];
    }
} rng;

// Timer
struct timer {
    chrono::high_resolution_clock::time_point t_begin;
    timer() { t_begin = chrono::high_resolution_clock::now(); }
    void reset() { t_begin = chrono::high_resolution_clock::now(); }
    float elapsed() const {
        return chrono::duration<float>(chrono::high_resolution_clock::now() -
                                       t_begin)
            .count();
    }
};

// Bits helpers
__attribute__((always_inline)) inline u64 bit(u64 x) { return 1ull << x; }

struct EvalResult {
    u64 sum = 0;
    vector<char> ops;
    vector<vector<u32>> A;
};

struct Simulator {
    int N, T;
    vector<vector<u32>> A0;

    // working state
    vector<vector<u32>> A;
    vector<char> ops;
    vector<u8> written; // each cell W at most once
    int r, c;           // 0-indexed
    u32 s;              // current s (register)
    int used;

    inline int idx(int i, int j) const { return i * N + j; }
    inline int manhattan(int r1, int c1, int r2, int c2) const {
        return abs(r1 - r2) + abs(c1 - c2);
    }

    inline void move_to(int tr, int tc) {
        while (r < tr) {
            ops.push_back('D');
            ++r;
            ++used;
        }
        while (r > tr) {
            ops.push_back('U');
            --r;
            ++used;
        }
        while (c < tc) {
            ops.push_back('R');
            ++c;
            ++used;
        }
        while (c > tc) {
            ops.push_back('L');
            --c;
            ++used;
        }
    }
    inline bool can_spend(int cost) const { return used + cost <= T; }

    // simulate with a fixed visiting order; within each target: choose 0C or 1C
    // (best) under remaining turns.
    EvalResult simulate_with_order(const vector<int> &order,
                                   bool store_ops_matrix) {
        // reset state
        A = A0;
        if (store_ops_matrix) {
            ops.clear();
            ops.reserve(5000);
        } else {
            // still need to collect ops to count used moves; but we can avoid
            // storing by using a dummy buffer
            ops.clear();
            ops.reserve(16);
        }
        written.assign(N * N, 0);
        r = 0;
        c = 0;
        s = 0;
        used = 0;

        bool progressed = true;
        while (progressed && used < T) {
            progressed = false;
            for (int id : order) {
                if (used >= T)
                    break;
                int wr = id / N, wc = id % N;
                if (written[id])
                    continue;

                int rem = T - used;

                // Option 0C
                long long best_new_val_0 = LLONG_MIN;
                int cost0 = manhattan(r, c, wr, wc) + 1;
                if (cost0 <= rem) {
                    u32 new_val = (A[wr][wc] ^ s);
                    if ((long long)new_val > (long long)A[wr][wc]) {
                        best_new_val_0 = new_val;
                    }
                }

                // Option 1C
                long long best_new_val_1 = LLONG_MIN;
                int best_pr = -1, best_pc = -1, best_cost1 = 0;
                for (int pr = 0; pr < N; ++pr) {
                    for (int pc = 0; pc < N; ++pc) {
                        int total_cost = manhattan(r, c, pr, pc) + 1 +
                                         manhattan(pr, pc, wr, wc) + 1;
                        if (total_cost > rem)
                            continue;
                        u32 s2 = s ^ A[pr][pc];
                        u32 new_val = (A[wr][wc] ^ s2);
                        if ((long long)new_val > (long long)A[wr][wc]) {
                            if ((long long)new_val > best_new_val_1 ||
                                ((long long)new_val == best_new_val_1 &&
                                 total_cost < best_cost1)) {
                                best_new_val_1 = new_val;
                                best_pr = pr;
                                best_pc = pc;
                                best_cost1 = total_cost;
                            }
                        }
                    }
                }

                // pick better action (by resulting value; tie -> cheaper; tie
                // -> 0C優先)
                int mode = -1; // 0=0C,1=1C
                int chosen_cost = 0;
                if (best_new_val_0 == LLONG_MIN &&
                    best_new_val_1 == LLONG_MIN) {
                    continue; // cannot improve this target within budget
                } else if (best_new_val_0 != LLONG_MIN &&
                           best_new_val_1 == LLONG_MIN) {
                    mode = 0;
                    chosen_cost = cost0;
                } else if (best_new_val_0 == LLONG_MIN &&
                           best_new_val_1 != LLONG_MIN) {
                    mode = 1;
                    chosen_cost = best_cost1;
                } else {
                    if (best_new_val_1 > best_new_val_0) {
                        mode = 1;
                        chosen_cost = best_cost1;
                    } else if (best_new_val_1 < best_new_val_0) {
                        mode = 0;
                        chosen_cost = cost0;
                    } else {
                        if (best_cost1 < cost0) {
                            mode = 1;
                            chosen_cost = best_cost1;
                        } else {
                            mode = 0;
                            chosen_cost = cost0;
                        }
                    }
                }

                // execute
                if (mode == 0) {
                    if (!can_spend(chosen_cost))
                        continue;
                    move_to(wr, wc);
                    ops.push_back('W');
                    ++used;
                    A[wr][wc] ^= s;
                    written[id] = 1;
                    progressed = true;
                } else {
                    if (!can_spend(chosen_cost))
                        continue;
                    move_to(best_pr, best_pc);
                    ops.push_back('C');
                    ++used;
                    s ^= A[best_pr][best_pc];
                    move_to(wr, wc);
                    ops.push_back('W');
                    ++used;
                    A[wr][wc] ^= s;
                    written[id] = 1;
                    progressed = true;
                }
            }
        }

        EvalResult res;
        res.sum = 0;
        for (int i = 0; i < N; ++i)
            for (int j = 0; j < N; ++j)
                res.sum += A[i][j];
        if (store_ops_matrix) {
            res.ops = ops;
            res.A = A;
        }
        return res;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, T;
    if (!(cin >> N >> T))
        return 0;
    vector<vector<u32>> A(N, vector<u32>(N));
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < N; ++j)
            cin >> A[i][j];

    Simulator sim;
    sim.N = N;
    sim.T = T;
    sim.A0 = A;

    // initial order: row-major
    vector<int> order(N * N);
    iota(order.begin(), order.end(), 0);

    timer tim;

    // Evaluate initial order
    EvalResult cur = sim.simulate_with_order(order, false);
    EvalResult best = cur;
    vector<int> best_order = order;

    // SA params
    const double TIME_LIMIT = 1.98; // seconds
    const double T0 = 1e7;          // initial temperature
    const double T1 = 1e-3;         // final temperature

    int iters = 0;
    while (true) {
        double t = tim.elapsed();
        if (t >= TIME_LIMIT)
            break;
        ++iters;

        // temperature schedule (exponential)
        double temp = T0 * pow(T1 / T0, t / TIME_LIMIT);

        // generate neighbor by adjacent swap or 1-point insertion
        vector<int> cand_order = order;
        if (rng.random32(2)) {
            // adjacent swap
            int i = rng.random32((u32)max(1, (int)cand_order.size() - 1));
            swap(cand_order[i], cand_order[i + 1]);
        } else {
            // 1-point insertion
            int n = (int)cand_order.size();
            int i = rng.random32((u32)n);
            int j = rng.random32((u32)(n - 1));
            if (j >= i)
                ++j; // ensure j != i
            int v = cand_order[i];
            if (i < j) {
                for (int k = i; k < j; ++k)
                    cand_order[k] = cand_order[k + 1];
                cand_order[j] = v;
            } else {
                for (int k = i; k > j; --k)
                    cand_order[k] = cand_order[k - 1];
                cand_order[j] = v;
            }
        }

        // evaluate neighbor (no need to store ops/A unless it's new global
        // best)
        EvalResult cand = sim.simulate_with_order(cand_order, false);
        long long delta = (long long)cand.sum - (long long)cur.sum;

        bool accept = false;
        if (delta >= 0) {
            accept = true;
        } else {
            double prob = exp(delta / temp);
            double r = rng.randomDouble();
            if (r < prob)
                accept = true;
        }

        if (accept) {
            order.swap(cand_order);
            cur = cand;
            if (cand.sum > best.sum) {
                // store full best (ops + A)
                EvalResult full = sim.simulate_with_order(order, true);
                best = full;
                best_order = order;
            }
        }
    }

    // --- デバッグ出力(stderr) ---
    cerr << best.ops.size() << '\n';
    u64 out_sum = 0;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cerr << best.A[i][j] << " ";
            out_sum += best.A[i][j];
        }
        cerr << '\n';
    }
    cerr << out_sum << '\n';

    // --- 解の出力(stdout) ---
    for (char ch : best.ops)
        cout << ch << '\n';
    return 0;
}
0