結果

問題 No.5022 XOR Printer
ユーザー tnktsyk
提出日時 2025-07-26 14:32:57
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 1,922 ms / 2,000 ms
コード長 6,926 bytes
コンパイル時間 2,763 ms
コンパイル使用メモリ 214,080 KB
実行使用メモリ 7,720 KB
スコア 4,009,322,051
最終ジャッジ日時 2025-07-26 14:34:39
合計ジャッジ時間 101,717 ms
ジャッジサーバーID
(参考情報)
judge4 / judge3
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 50
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

// ===== XOR Basis (20-bit) =====
struct XorBasis {
    static const int B = 20;
    int v[B];
    bitset<128> used[B];
    XorBasis(){ memset(v,0,sizeof(v)); }
    void add(int x, const bitset<128>& bs){
        bitset<128> c = bs;
        for(int b=B-1;b>=0;--b){
            if(((x>>b)&1)==0) continue;
            if(v[b]==0){ v[b]=x; used[b]=c; return; }
            x ^= v[b];
            c ^= used[b];
        }
    }
    pair<int, bitset<128>> build(int target) const {
        int t = target, made = 0;
        bitset<128> sel; sel.reset();
        for(int b=B-1;b>=0;--b){
            if(((t>>b)&1)==0) continue;
            if(v[b]==0) continue;
            t ^= v[b];
            made ^= v[b];
            sel ^= used[b];
        }
        return {made, sel};
    }
};

// score for a given s
static inline long long eval_score(const vector<int>& flatA, int s){
    long long sum = 0;
    for(int x: flatA){
        int y = x ^ s;
        sum += (y > x ? y : x);
    }
    return sum;
}

// move helper
static inline void move_to(int &r,int &c,int tr,int tc, vector<char>& ops){
    while(r<tr){ ops.push_back('D'); ++r; }
    while(r>tr){ ops.push_back('U'); --r; }
    while(c<tc){ ops.push_back('R'); ++c; }
    while(c>tc){ ops.push_back('L'); --c; }
}

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

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

    // flatten
    vector<int> flatA(N*N);
    for(int i=0;i<N;i++) for(int j=0;j<N;j++) flatA[i*N+j] = A[i][j];

    // --- initial candidates ---
    int s0 = 0; // your greedy
    for(int i=0;i<N;i++) for(int j=0;j<N;j++) if(s0 < (s0 ^ A[i][j])) s0 ^= A[i][j];

    int s1_target = 0; // per-bit gain
    for(int b=0;b<20;b++){
        int cnt0=0,cnt1=0;
        for(int x: flatA){ if((x>>b)&1) cnt1++; else cnt0++; }
        if(cnt0 > cnt1) s1_target |= (1<<b);
    }

    // basis
    XorBasis basis;
    for(int i=0;i<N;i++) for(int j=0;j<N;j++){
        bitset<128> bs; bs.reset(); bs.set(i*N + j);
        basis.add(A[i][j], bs);
    }

    auto [s0_real, cells0] = basis.build(s0);
    auto [s1_real, cells1] = basis.build(s1_target);

    long long sc0 = eval_score(flatA, s0_real);
    long long sc1 = eval_score(flatA, s1_real);

    int S = s0_real; bitset<128> needC = cells0; long long bestScore = sc0;
    if(sc1 > sc0){ S = s1_real; needC = cells1; bestScore = sc1; }

    // ===== Deterministic hill climbing (1,2,3 XOR) =====
    auto single_step = [&](int &Sref, long long &cur){
        long long base = cur;
        int bestIdx = -1; long long bestGain = 0;
        for(int i=0;i<N*N;i++){
            int ns = Sref ^ flatA[i];
            long long sc = eval_score(flatA, ns);
            if(sc - base > bestGain){ bestGain = sc - base; bestIdx = i; }
        }
        if(bestGain>0){ Sref ^= flatA[bestIdx]; cur += bestGain; return true; }
        return false;
    };
    auto pair_step = [&](int &Sref, long long &cur){
        long long base = cur; long long bestGain = 0; int bi=-1,bj=-1;
        for(int i=0;i<N*N;i++){
            for(int j=i+1;j<N*N;j++){
                int ns = Sref ^ flatA[i] ^ flatA[j];
                long long sc = eval_score(flatA, ns);
                if(sc - base > bestGain){ bestGain=sc-base; bi=i; bj=j; }
            }
        }
        if(bestGain>0){ Sref ^= flatA[bi]; Sref ^= flatA[bj]; cur += bestGain; return true; }
        return false;
    };
    auto triple_step = [&](int &Sref, long long &cur){
        long long base = cur; long long bestGain = 0; int bi=-1,bj=-1,bk=-1;
        for(int i=0;i<N*N;i++){
            for(int j=i+1;j<N*N;j++){
                for(int k=j+1;k<N*N;k++){
                    int ns = Sref ^ flatA[i] ^ flatA[j] ^ flatA[k];
                    long long sc = eval_score(flatA, ns);
                    if(sc - base > bestGain){ bestGain=sc-base; bi=i; bj=j; bk=k; }
                }
            }
        }
        if(bestGain>0){ Sref ^= flatA[bi]; Sref ^= flatA[bj]; Sref ^= flatA[bk]; cur += bestGain; return true; }
        return false;
    };

    // loop until no improvement
    while(true){
        if(single_step(S, bestScore)) continue;
        if(pair_step(S, bestScore))   continue;
        if(triple_step(S, bestScore)) continue;
        break;
    }

    // ===== Optional random search within time budget =====
    auto start = chrono::steady_clock::now();
    mt19937 rng(1234567);
    auto time_ok = [&](){
        return chrono::duration<double>(chrono::steady_clock::now()-start).count() < 1.85; // adjust margin
    };
    vector<int> idxs(N*N); iota(idxs.begin(), idxs.end(), 0);

    while(time_ok()){
        int k = 1 + (rng()%4); // 1..4 elements
        shuffle(idxs.begin(), idxs.end(), rng);
        int ns = S;
        for(int i=0;i<k;i++) ns ^= flatA[idxs[i]];
        long long sc = eval_score(flatA, ns);
        if(sc > bestScore){
            S = ns; bestScore = sc;
            // after a random improvement, run deterministic singles again
            while(true){
                if(single_step(S, bestScore)) continue;
                if(pair_step(S, bestScore))   continue;
                if(triple_step(S, bestScore)) continue;
                break;
            }
        }
    }

    // rebuild for final S
    auto [S_real, cells_final] = basis.build(S);
    if(S_real != S){
        long long sc_real = eval_score(flatA, S_real);
        if(sc_real >= bestScore){ S = S_real; bestScore = sc_real; needC = cells_final; }
        else needC = cells_final; // keep S; slight mismatch unlikely but allow
    } else {
        needC = cells_final;
    }

    // ===== Construct operations =====
    vector<char> ops;
    int r=0,c=0;

    // snake path
    vector<pair<int,int>> snake; snake.reserve(N*N);
    for(int i=0;i<N;i++){
        if(i%2==0) for(int j=0;j<N;j++) snake.emplace_back(i,j);
        else        for(int j=N-1;j>=0;j--) snake.emplace_back(i,j);
    }

    if(!snake.empty()){
        move_to(r,c, snake[0].first, snake[0].second, ops);
        for(size_t k=0;k<snake.size();k++){
            int rr = snake[k].first, cc = snake[k].second;
            int id = rr*N + cc;
            if(needC.test(id)) ops.push_back('C');
            if(k+1<snake.size()){
                auto [nr,nc] = snake[k+1];
                move_to(r,c,nr,nc,ops);
            }
        }
    }

    // reverse snake for W
    if(!snake.empty()){
        for(size_t k=0;k<snake.size();k++){
            auto [rr,cc] = snake[snake.size()-1-k];
            if(k>0) move_to(r,c, rr, cc, ops);
            int x = A[rr][cc];
            if( (x ^ S) > x ) ops.push_back('W');
        }
    }

    if((int)ops.size() > T) ops.resize(T); // unlikely, but safeguard

    for(char ch: ops) cout << ch << '\n';
    return 0;
}
0