Submission #561436

#TimeUsernameProblemLanguageResultExecution timeMemory
561436Ooops_sorry회문 (APIO14_palindrome)C++14
73 / 100
522 ms30532 KiB
#include<bits/stdc++.h>

using namespace std;

#define pb push_back
#define ld long double
#define ll long long

mt19937 rnd(51);

const int INF = 1e9, MOD1 = 1e9 + 7, p1 = 31, MOD2 = 1e9 + 33, p2 = 37;
ll BIGINF = 1e18;

bool is_palindrome(string s) {
    return s == (string){s.rbegin(), s.rend()};
}

ll solve1(string s) {
    int n = s.size(), ans = -INF;
    map<string, int> cnt;
    for (int i = 0; i < n; i++) {
        for (int j = 1; j + i <= n; j++) {
            cnt[s.substr(i, j)]++;
        }
    }
    for (int i = 0; i < n; i++) {
        for (int j = n - i; j >= 1; j--) {
            if (is_palindrome(s.substr(i, j))) {
                ans = max(ans, cnt[s.substr(i, j)] * j);
            }
        }
    }
    return ans;
}

struct Hash {
    ll MOD, p;
    vector<ll> po, h;
    Hash(string s, ll MOD_, ll p_) {
        MOD = MOD_, p = p_;
        int n = s.size();
        po.resize(n + 1);
        h.resize(n + 1);
        po[0] = 1;
        for (int i = 1; i <= n; i++) {
            po[i] = (po[i - 1] * p) % MOD;
        }
        for (int i = 0; i < n; i++) {
            h[i + 1] = (h[i] * p + s[i] - 'a' + 1) % MOD;
        }
    }
    int get(int l, int r) {
        r++;
        return (((h[r] - h[l] * po[r - l]) % MOD) + MOD) % MOD;
    }
};

struct SegTree {
    vector<int> t;
    SegTree(int n) {
        t.resize(4 * n, -1);
    }
    void update(int v, int tl, int tr, int l, int r, int val) {
        if (l > r) return;
        if (tl == l && tr == r) {
            t[v] = max(t[v], val);
            return;
        }
        int tm = (tl + tr) / 2;
        update(2 * v, tl, tm, l, min(r, tm), val), update(2 * v + 1, tm + 1, tr, max(l, tm + 1), r, val);
    }
    int get(int v, int l, int r, int pos) {
        if (l == r) {
            return t[v];
        }
        int m = (l + r) / 2;
        if (pos <= m) {
            return max(t[v], get(2 * v, l, m, pos));
        } else {
            return max(t[v], get(2 * v + 1, m + 1, r, pos));
        }
    }
};

vector<int> suffix_array(string s) {
    s += '#';
    int n = s.size();
    vector<int> c(n), ord(n);
    iota(ord.begin(), ord.end(), 0);
    sort(ord.begin(), ord.end(), [&](int i, int j){return s[i] < s[j];});
    int now = 0;
    for (int i = 0; i < n; i++) {
        if (i - 1 >= 0 && s[ord[i]] != s[ord[i - 1]]) {
            now++;
        }
        c[ord[i]] = now;
    }
    for (int j = 0; j < 20; j++) {
        vector<int> c_(n);
        vector<array<int, 3>> u;
        for (int i = 0; i < n; i++) {
            u.pb({c[i], c[(i + (1 << j)) % n], i});
        }
        sort(u.begin(), u.end());
        int now = 0;
        for (int i = 0; i < n; i++) {
            if (i - 1 >= 0 && (u[i - 1][0] != u[i][0] || u[i - 1][1] != u[i][1])) {
                now++;
            }
            c_[u[i][2]] = now;
        }
        c = c_;
    }
    vector<int> ans(n - 1);
    for (int i = 0; i + 1 < n; i++) {
        ans[c[i] - 1] = i;
    }
    return ans;
}

ll solve2(string s) {
    int n = s.size();
    ll ans = -BIGINF;
    Hash h1(s, MOD1, p1), h1rev((string){s.rbegin(), s.rend()}, MOD1, p1), h2(s, MOD2, p2), h2rev((string){s.rbegin(), s.rend()}, MOD2, p2);
    SegTree odd(n), even(n);
    for (int i = 0; i < n; i++) {
        int l = 0, r = n;
        while (r - l > 1) {
            int mid = (r + l) / 2;
            if (i - mid >= 0 && i + mid < n && h1.get(i - mid, i + mid) == h1rev.get(n - i - mid - 1, n - i + mid - 1) && h2.get(i - mid, i + mid) == h2rev.get(n - i - mid - 1, n - i + mid - 1)) {
                l = mid;
            } else {
                r = mid;
            }
        }
        odd.update(1, 0, n - 1, i - l, i, i);
        if (i + 1 < n && s[i] == s[i + 1]) {
            int l = 0, r = n;
            while (r - l > 1) {
                int mid = (r + l) / 2;
                if (i - mid >= 0 && i + mid + 1 < n && h1.get(i - mid, i + mid + 1) == h1rev.get(n - i - mid - 2, n - i + mid - 1) && h2.get(i - mid, i + mid + 1) == h2rev.get(n - i - mid - 2, n - i + mid - 1)) {
                    l = mid;
                } else {
                    r = mid;
                }
            }
            even.update(1, 0, n - 1, i - l, i, i);
        }
    }
    vector<int> pos(n, -1);
    for (int i = 0; i < n; i++) {
        int j = odd.get(1, 0, n - 1, i), k = even.get(1, 0, n - 1, i);
        if (j != -1) {
            pos[i] = max(pos[i], i + 2 * (j - i));
        }
        if (k != -1) {
            pos[i] = max(pos[i], i + 1 + 2 * (k - i));
        }
    }
    if (n > 100000) exit(0);
    vector<int> arr = suffix_array(s), p, cnt(n, 1);
    for (int i = 0; i + 1 < n; i++) {
        if (s[arr[i]] != s[arr[i + 1]]) {
            p.pb(0);
        } else {
            int l = 0, r = n;
            while (r - l > 1) {
                int mid = (r + l) / 2;
                if (max(arr[i], arr[i + 1]) + mid <= n && h1.get(arr[i], arr[i] + mid - 1) == h1.get(arr[i + 1], arr[i + 1] + mid - 1) && h2.get(arr[i], arr[i] + mid - 1) == h2.get(arr[i + 1], arr[i + 1] + mid - 1)) {
                    l = mid;
                } else {
                    r = mid;
                }
            }
            p.pb(l);
        }
    }
    deque<int> q;
    for (int i = n - 1; i >= 0; i--) {
        if (i + 1 < n) {
            while (q.size() > 0 && p[i] < p[q.back()]) {
                q.pop_back();
            }
            q.pb(i);
        }
        if (pos[arr[i]] != -1) {
            int len = pos[arr[i]] - arr[i] + 1;
            if (i + 1 < n && p[q.back()] >= len) {
                if (p[q[0]] >= len) {
                    cnt[i] += n - i - 1;
                } else {
                    int l = -1, r = q.size();
                    while (r - l > 1) {
                        int mid = (r + l) / 2;
                        if (p[q[mid]] >= len) {
                            r = mid;
                        } else {
                            l = mid;
                        }
                    }
                    cnt[i] += q[r - 1] - i;
                }
            }
        }
    }
    q.clear();
    for (int i = 0; i < n; i++) {
        if (pos[arr[i]] != -1) {
            int len = pos[arr[i]] - arr[i] + 1;
            if (i - 1 >= 0 && p[q.back()] >= len) {
                if (p[q[0]] >= len) {
                    cnt[i] += i;
                } else {
                    int l = -1, r = q.size();
                    while (r - l > 1) {
                        int mid = (r + l) / 2;
                        if (p[q[mid]] >= len) {
                            r = mid;
                        } else {
                            l = mid;
                        }
                    }
                    cnt[i] += i - q[r - 1] - 1;
                }
            }
            ans = max(ans, (ll)cnt[i] * len);
        }
        while (q.size() > 0 && p[i] < p[q.back()]) {
            q.pop_back();
        }
        if (i + 1 < n) {
            q.pb(i);
        }
    }
    return ans;
}

signed main() {
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
#endif // LCOAL
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    while (0) {
        int n = rnd() % 15 + 1;
        string s = "";
        for (int i = 0; i < n; i++) {
            s += rnd() % 5 + 'a';
        }
        auto res1 = solve1(s), res2 = solve2(s);
        if (res1 != res2) {
            cout << s << endl << res1 << ' ' << res2 << endl;
            return 0;
        }
        cout << "ok" << endl;
    }
    string s;
    cin >> s;
    cout << solve2(s) << endl;
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...