結果

問題 No.5022 XOR Printer
ユーザー EvbCFfp1XB
提出日時 2025-07-26 16:51:00
言語 Java
(openjdk 23)
結果
AC  
実行時間 1,918 ms / 2,000 ms
コード長 16,352 bytes
コンパイル時間 3,163 ms
コンパイル使用メモリ 104,888 KB
実行使用メモリ 65,116 KB
スコア 4,844,436,367
最終ジャッジ日時 2025-07-26 16:52:54
合計ジャッジ時間 101,385 ms
ジャッジサーバーID
(参考情報)
judge5 / judge6
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 50
権限があれば一括ダウンロードができます

ソースコード

diff #

import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    enum Move {
        U, D, L, R, W, C,;
    }

    private static Watch2 watch;
    private static final PCG_XSH_RR rng = new PCG_XSH_RR(System.nanoTime());

    public static void main(final String[] args) {
        try (final Scanner sc = new Scanner(System.in)) {
            final int N = sc.nextInt();
            watch = new Watch2();
            final int T = sc.nextInt();
            final int[][] A = new int[N][N];
            for (int r = 0; r < N; r++) {
                for (int c = 0; c < N; c++) {
                    A[r][c] = sc.nextInt();
                }
            }
            final int[][] copyA = new int[N][N];
            for (int r = 0; r < N; r++) {
                for (int c = 0; c < N; c++) {
                    copyA[r][c] = A[r][c];
                }
            }
            ArrayList<Move> solution = greedy(N, T, copyA);
            {
                for (int r = 0; r < N; r++) {
                    for (int c = 0; c < N; c++) {
                        copyA[r][c] = A[r][c];
                    }
                }
                int score = calculateScore(N, T, copyA, 0, 0, 0, solution);
                Utils.debug("score", score);
            }
            sa(N, T, A, copyA, solution);
            {
                for (int r = 0; r < N; r++) {
                    for (int c = 0; c < N; c++) {
                        copyA[r][c] = A[r][c];
                    }
                }
                int score = calculateScore(N, T, copyA, 0, 0, 0, solution);
                Utils.debug("score", score);
            }
            System.out.println(solution.stream().map(move -> move.name())
                    .reduce("", (sum, move) -> sum + move + "\n"));
            System.out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static ArrayList<Move> greedy(final int N, final int T, int[][] A)
            throws AssertionError {
        ArrayList<Move> solution = new ArrayList<>();
        {
            int r0 = 0;
            int c0 = 0;
            int v = 0;
            for (int shift = 19; shift >= 0; shift--) {
                final int mask = 1 << shift;
                if (solution.size() >= T) {
                    break;
                }
                int bestR = -1;
                int bestC = -1;
                int bestR2 = -1;
                int bestC2 = -1;
                int bestR3 = -1;
                int bestC3 = -1;
                int bestR4 = -1;
                int bestC4 = -1;
                int bestDistance = (int) 1e9;
                for (int r = 0; r < N; r++) {
                    for (int c = 0; c < N; c++) {
                        if (((v ^ A[r][c]) & mask) != 0) {
                            int distance = distance(r, c, r0, c0);
                            if (distance < bestDistance) {
                                bestR = r;
                                bestC = c;
                                bestR2 = -1;
                                bestC2 = -1;
                                bestR3 = -1;
                                bestC3 = -1;
                                bestR4 = -1;
                                bestC4 = -1;
                                bestDistance = distance;
                            }
                        }
                        for (int r2 = 0; r2 < N; r2++) {
                            for (int c2 = 0; c2 < N; c2++) {
                                if (((v ^ A[r][c] ^ A[r2][c2]) & mask) != 0) {
                                    int distance = distance(r, c, r0, c0)
                                            + distance(r, c, r2, c2);
                                    if (distance < bestDistance) {
                                        bestR = r;
                                        bestC = c;
                                        bestR2 = r2;
                                        bestC2 = c2;
                                        bestR3 = -1;
                                        bestC3 = -1;
                                        bestR4 = -1;
                                        bestC4 = -1;
                                        bestDistance = distance;
                                    }
                                }
                                for (int r3 = 0; r3 < N; r3++) {
                                    for (int c3 = 0; c3 < N; c3++) {
                                        if (((v ^ A[r][c] ^ A[r2][c2]
                                                ^ A[r3][c3]) & mask) != 0) {
                                            int distance = distance(r, c, r0,
                                                    c0) + distance(r, c, r2, c2)
                                                    + distance(r2, c2, r3, c3);
                                            if (distance < bestDistance) {
                                                bestR = r;
                                                bestC = c;
                                                bestR2 = r2;
                                                bestC2 = c2;
                                                bestR3 = r3;
                                                bestC3 = c3;
                                                bestR4 = -1;
                                                bestC4 = -1;
                                                bestDistance = distance;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if (bestR < 0) {
                    break;
                }
                move(r0, c0, bestR, bestC, solution);
                r0 = bestR;
                c0 = bestC;
                if (bestR2 >= 0) {
                    move(r0, c0, bestR2, bestC2, solution);
                    r0 = bestR2;
                    c0 = bestC2;
                    if (bestR3 >= 0) {
                        move(r0, c0, bestR3, bestC3, solution);
                        r0 = bestR3;
                        c0 = bestC3;
                        if (bestR4 >= 0) {
                            move(r0, c0, bestR4, bestC4, solution);
                            r0 = bestR4;
                            c0 = bestC4;
                        }
                    }
                }
                v = copy(r0, c0, v, A, solution);
                move(r0, c0, 0, 0, solution);
                r0 = 0;
                c0 = 0;
                for (int r = 0; r < N; r++) {
                    if (r % 2 == 0) {
                        for (int c = 0; c < N; c++) {
                            if ((A[r][c] & mask) == 0) {
                                move(r0, c0, r, c, solution);
                                r0 = r;
                                c0 = c;
                                write(r, c, v, A, solution);
                            }
                        }
                    } else {
                        for (int c = N - 1; c >= 0; c--) {
                            if ((A[r][c] & mask) == 0) {
                                move(r0, c0, r, c, solution);
                                r0 = r;
                                c0 = c;
                                write(r, c, v, A, solution);
                            }
                        }
                    }
                }
            }
        }
        while (solution.size() > T) {
            solution.remove(solution.size() - 1);
        }
        return solution;
    }

    private static void write(int r, int c, int v, int[][] A,
            ArrayList<Move> solution) {
        solution.add(Move.W);
        A[r][c] = v ^ A[r][c];
    }

    private static int copy(int r, int c, int v, int[][] A,
            ArrayList<Move> solution) {
        solution.add(Move.C);
        return v ^ A[r][c];
    }

    private static void move(int r0, int c0, int r, int c,
            ArrayList<Move> solution) {
        while (r0 < r) {
            r0++;
            solution.add(Move.D);
        }
        while (r0 > r) {
            r0--;
            solution.add(Move.U);
        }
        while (c0 < c) {
            c0++;
            solution.add(Move.R);
        }
        while (c0 > c) {
            c0--;
            solution.add(Move.L);
        }
    }

    private static int distance(int r, int c, int r0, int c0) {
        return Math.abs(r - r0) + Math.abs(c - c0);
    }

    private static void sa(int N, int T, int[][] A, int[][] copyA,
            ArrayList<Move> solution) {
        final double startTemperature = 1e4;
        final double endTemperature = 1e1;
        double temperature = startTemperature;
        final double startTime = watch.elapsedSecond();
        final double endTime = 1.75;
        for (int r = 0; r < N; r++) {
            for (int c = 0; c < N; c++) {
                copyA[r][c] = A[r][c];
            }
        }
        int score = calculateScore(N, T, copyA, 0, 0, 0, solution);
        final int mask = (1 << 7) - 1;
        for (int iteration = 0;; iteration++) {
            if ((iteration & mask) == mask) {
                final double time = watch.elapsedSecond();
                if (time > endTime) {
                    System.err.println(
                            "Iteration: " + iteration + ", Temperature: "
                                    + temperature + ", score: " + score);
                    break;
                }
                temperature = startTemperature
                        + (endTemperature - startTemperature)
                                * ((time - startTime) / (endTime - startTime));
                System.err.println("Iteration: " + iteration + ", Temperature: "
                        + temperature + ", score: " + score);
            }
            final double random = 2 * rng.nextDouble();
            if (random < 1) {
                final int i = rng.nextInt(solution.size());
                int j = rng.nextInt(solution.size() - 1);
                if (j >= i) {
                    j++;
                }
                if (i < j) {
                    for (int k = i; k < j; k++) {
                        solution.set(k, solution.set(k + 1, solution.get(k)));
                    }
                } else {
                    for (int k = i; k > j; k--) {
                        solution.set(k, solution.set(k - 1, solution.get(k)));
                    }
                }
                for (int r = 0; r < N; r++) {
                    for (int c = 0; c < N; c++) {
                        copyA[r][c] = A[r][c];
                    }
                }
                int deltaScore = calculateScore(N, T, copyA, 0, 0, 0, solution)
                        - score;
                if (accept(temperature, deltaScore)) {
                    score += deltaScore;
                } else {
                    if (i < j) {
                        for (int k = j; k > i; k--) {
                            solution.set(k,
                                    solution.set(k - 1, solution.get(k)));
                        }
                    } else {
                        for (int k = j; k < i; k++) {
                            solution.set(k,
                                    solution.set(k + 1, solution.get(k)));
                        }
                    }
                }
            } else if (random < 2) {
                int i = rng.nextInt(solution.size());
                Move current = solution.get(i);
                solution.set(i,
                        Move.values()[rng.nextInt(Move.values().length)]);
                for (int r = 0; r < N; r++) {
                    for (int c = 0; c < N; c++) {
                        copyA[r][c] = A[r][c];
                    }
                }
                int deltaScore = calculateScore(N, T, copyA, 0, 0, 0, solution)
                        - score;
                if (accept(temperature, deltaScore)) {
                    score += deltaScore;
                } else {
                    solution.set(i, current);
                }
            }
        }
    }

    private static boolean accept(double temperature, int deltaScore) {
        return deltaScore >= 0
                || rng.nextDouble() < Math.exp(deltaScore / temperature);
    }

    private static int calculateScore(int N, int T, int[][] A, int r, int c,
            int v, ArrayList<Move> solution) {
        for (Move op : solution) {
            switch (op) {
            case U: {
                r--;
                if (r < 0) {
                    return (int) -1e9;
                }
                break;
            }
            case D: {
                r++;
                if (r >= N) {
                    return (int) -1e9;
                }
                break;
            }
            case L: {
                c--;
                if (c < 0) {
                    return (int) -1e9;
                }
                break;
            }
            case R: {
                c++;
                if (c >= N) {
                    return (int) -1e9;
                }
                break;
            }
            case W: {
                A[r][c] ^= v;
                break;
            }
            case C: {
                v ^= A[r][c];
                break;
            }
            default:
                return (int) -1e9;
            }
        }
        return calculateScore(N, A);
    }

    private static int calculateScore(int N, int[][] A) {
        int score = 0;
        for (int r = 0; r < N; r++) {
            for (int c = 0; c < N; c++) {
                score += A[r][c];
            }
        }
        return score;
    }
}

class PCG_XSH_RR {
    private long state = 5342;

    public PCG_XSH_RR(final long state) {
        this.state = state;
    }

    public int nextInt() {
        final long oldstate = state;
        state = oldstate * 6364136223846793005L + 521L;
        final int xorshift = (int) (((oldstate >>> 18) ^ oldstate) >>> 27);
        final int rotation = (int) (oldstate >>> 59);
        return (xorshift >>> rotation) | (xorshift << (-rotation & 31));
    }

    public int nextInt(int n) {
        return (int) (n * nextDouble());
    }

    public int nextInt2(int n) {
        final int k = 16;
        final int x = (nextInt() & ((1 << k) - 1));
        return (x * n) >>> k;
    }

    public double nextDouble() {
        return (nextInt() >>> 1) * 4.6566128730773926E-10;
    }
}

class Watch2 {
    private final long start;

    public Watch2() {
        start = System.nanoTime();
    }

    public double elapsedSecond() {
        return (System.nanoTime() - start) * 1e-9;
    }

    @Override
    public String toString() {
        final long elapsedSecond = (long) (1e3 * elapsedSecond());
        return formatElapsedTimeWithUnits(elapsedSecond);
    }

    public static String formatElapsedTimeWithUnits(final long elapsedMillis) {
        final Duration duration = Duration.ofMillis(elapsedMillis);
        final long hours = duration.toHours();
        final long minutes = duration.toMinutesPart();
        final long seconds = duration.toSecondsPart();
        final long millis = duration.toMillisPart();
        final StringBuilder sb = new StringBuilder();
        if (hours > 0) {
            sb.append(hours).append("h");
        }
        if (minutes > 0 || hours > 0) {
            sb.append(minutes).append("m");
        }
        sb.append(seconds);
        if (minutes > 0 || hours > 0) {
        } else {
            sb.append(".").append(String.format("%03d", millis));
        }
        sb.append("s");
        return sb.toString().trim();
    }
}

class Utils {
    private Utils() {
    }

    public static final void debug(Object... o) {
        System.err.println(toString(o));
        System.err.flush();
    }

    public static final String toString(Object... o) {
        return Arrays.deepToString(o);
    }

    public static boolean isValid(int v, int min, int minUpper) {
        return v >= min && v < minUpper;
    }
}
0