Submission #1211938

#TimeUsernameProblemLanguageResultExecution timeMemory
1211938uranium235Sateliti (COCI20_satellti)Java
110 / 110
948 ms54416 KiB
// package ojuz;

import java.io.*;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

public class Main {
    public static final long mod = (1L << 61) - 1, b = ThreadLocalRandom.current().nextLong(mod);
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));

        String[] first = reader.readLine().split(" ");
        int n = Integer.parseInt(first[0]), m = Integer.parseInt(first[1]);
        String[] grid = new String[n];
        for (int i = 0; i < n; i++) grid[i] = reader.readLine();
        Hash hash = new Hash(grid);

        int[] best = new int[2];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int cmp = hash.compare(best[0], best[1], i, j);
                if (cmp > 0) {
                    best[0] = i;
                    best[1] = j;
                }
            }
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                writer.write(grid[(i + best[0]) % n].charAt((j + best[1]) % m));
            }
            writer.newLine();
        }
        writer.flush();
    }

    static class Hash {
        public final long[][] grid;
        public final long[] inv;
        public final String[] str;
        public final int n, m;
        public Hash(String[] strs) {
            this.n = strs.length;
            this.m = strs[0].length();

            this.str = strs;

            // inv[i] = mod inverse of (b ** i)
            this.inv = new long[n * m];
            this.inv[n * m - 1] = pow(b, mod - n * m);
            for (int i = n * m - 2; i >= 0; i--) inv[i] = mult(inv[i + 1], b);
            this.grid = new long[2 * n][2 * m];

            long current = 1;
            for (int i = 1; i < 2 * n; i++) {
                for (int j = 1; j < 2 * m; j++) {
//                    grid[i][j] = m * (i - 1L) + j - 1;
//                    grid[i][j] += grid[i - 1][j] + grid[i][j - 1] - grid[i - 1][j - 1];
                    grid[i][j] = ((grid[i - 1][j] + grid[i][j - 1] - grid[i - 1][j - 1]) + mult(current, strs[(i - 1) % n].charAt((j - 1) % m))) % mod;
                    grid[i][j] = (grid[i][j] + mod) % mod;
                    current = mult(current, b);
                }
                current = mult(current, inv[m - 1]);
            }
        }


        public long get(int r, int c, int l) {
            int full = l / m;
            long result = (grid[r + full][c + m] - grid[r][c + m] - grid[r + full][c] + grid[r][c]) % mod;
            result = (result + mod) % mod;
            int remain = l % m;
            if (remain != 0) {
                result += (grid[r + full + 1][c + remain] - grid[r + full][c + remain] - grid[r + full + 1][c] + grid[r + full][c]) % mod;
                result = (result + mod) % mod;
            }
            return mult(result, inv[r * m + c]);
        }

        public int compare(int r1, int c1, int r2, int c2) {
            int lo = 0, hi = n * m;
            while (lo < hi) {
                int mid = lo + (hi - lo + 1) / 2;
                if (get(r1, c1, mid) == get(r2, c2, mid)) lo = mid;
                else hi = mid - 1;
            }
            if (lo == n * m) return 0;
            r1 += lo / m;
            r2 += lo / m;
            c1 += lo % m;
            c2 += lo % m;
            r1 %= n;
            r2 %= n;
            c1 %= m;
            c2 %= m;
            int cmp = Character.compare(str[r1].charAt(c1), str[r2].charAt(c2));
            if (cmp == 0) throw new RuntimeException();
            return cmp;
        }
    }

    public static long mult(long a, long b) {
        long low = a * b;
        return ((low & mod) + ((low >>> 61) | (Math.multiplyHigh(a, b) << 3))) % mod;
    }

    public static long pow(long a, long b) {
        long result = 1;
        while (b > 0) {
            if (b % 2 == 1) result = mult(result, a);
            a = mult(a, a);
            b /= 2;
        }
        return result;
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...