Submission #1210565

#TimeUsernameProblemLanguageResultExecution timeMemory
1210565uranium235Palinilap (COI16_palinilap)Java
0 / 100
54 ms11328 KiB
package ojuz;

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

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

        String s = reader.readLine();
        int n = s.length();

        Hash hash = new Hash(s);
        int l = 0, r = 0;
        long base = 0;
        long[][] buffs = new long[n][26];
        long[] nerfs = new long[n];
        while (r < n) {
            int bound = Math.min(l + 1, n - r);
            int best = hash.palindrome(l, r);
            base += best;
            // the letters that break the palindrome
            int left = l - best;
            int right = r + best;
            // if palindrome can be extended
            if (best < bound) {
                // swap the positions if length is even and letters dont match
                int add = 1 + ((left > 0 && right < n - 1) ? hash.palindrome(left - 1, right + 1) : 0);
                // change the right side to the left, or vice versa leads to more palindromes
                buffs[left][s.charAt(right) - 'a'] += add;
                buffs[right][s.charAt(left) - 'a'] += add;
            }
            for (int i = left + 1; i < l + (l == r ? 0 : 1); i++) nerfs[i] += (i - left);
            for (int i = right - 1; i > r - (l == r ? 0 : 1); i--) nerfs[i] += (right - i);

            if (l < r) l++;
            else r++;
        }

        long ans = 0;
        for (int i = 0; i < n; i++) {
            long max = 0;
            for (long j : buffs[i]) max = Math.max(max, j);
            ans = Math.max(ans, max - nerfs[i]);
        }

        System.out.println(base + ans);
    }

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

    static class Hash {
        public final String s;
        public final long[] pows, hash, rash;
        public Hash(String s) {
            this.s = s;
            this.pows = new long[s.length() + 1];
            pows[0] = 1;
            for (int i = 1; i < pows.length; i++) pows[i] = mult(b, pows[i - 1]);
            this.hash = new long[s.length() + 1];
            for (int i = 1; i < hash.length; i++) hash[i] = (mult(b, hash[i - 1]) + s.charAt(i - 1)) % m;
            this.rash = new long[s.length() + 1];
            for (int i = rash.length - 2; i >= 0; i--) rash[i] = (mult(b, rash[i + 1]) + s.charAt(i)) % m;
        }

        public long hash(int a, int b) {
            return (hash[b + 1] - mult(hash[a], pows[b - a + 1]) + m) % m;
        }

        public long rash(int a, int b) {
            return (rash[a] - mult(rash[b + 1], pows[b - a + 1]) + m) % m;
        }

        public int palindrome(int l, int r) {
            if (s.charAt(l) != s.charAt(r)) return 0;
            // longest "palindrome" from l going left and from r going right
            int hi = Math.min(l + 1, s.length() - r);
            int lo = 0;
            while (lo < hi) {
                int mid = lo + (hi - lo + 1) / 2;
                if (hash(r, r + mid - 1) == rash(l - mid + 1, l)) lo = mid;
                else hi = mid - 1;
            }
            return lo;
        }
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...