This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
#define f1r(i, a, b) for (int i = a; i < b; i++) 
#define f0r(i, a) f1r(i, 0, a)
#define eb emplace_back
#define pb push_back
#define f first
#define s second
#define mp make_pair
#define sz(x) (int) (x).size()
#define all(x) (x).begin(), (x).end()
typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pi;
typedef vector<pi> vpi;
template <class T> struct SparseTable {
    std::vector<T> v;
    std::vector<std::vector<int>> jump;
    int level(int x) {
        return 31 - __builtin_clz(x);
    }
    int comb(int a, int b) {
        return v[a] == v[b] ? std::min(a, b) : (v[a] < v[b] ? a : b);
    }
    void init(const std::vector<T>& _v) {
        v = _v;
        jump = {std::vector<int>((int) v.size())};
        iota(jump[0].begin(), jump[0].end(), 0);
        for (int j = 1; (1 << j) <= (int) v.size(); j++) {
            jump.push_back(std::vector<int>((int) v.size() - (1 << j) + 1));
            for (int i = 0; i < (int) jump[j].size(); i++) 
                jump[j][i] = comb(jump[j - 1][i], jump[j - 1][i + (1 << (j - 1))]);
        }
    }
    int index(int l, int r) {
        assert(l <= r);
        int d = level(r - l + 1);
        return comb(jump[d][l], jump[d][r - (1 << d) + 1]);
    }
    T query(int l, int r) {
        return v[index(l, r)];
    }
};
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define F0R(i, a) FOR(i,0,a)
#define ROF(i, a, b) for (int i = (b) - 1; i >= (a); --i)
#define R0F(i, a) ROF(i, 0, a)
#define trav(a, x) for (auto& a : x)
typedef string str;
template<class T> struct RMQ { // floor(log_2(x))
    int level(int x) { return 31-__builtin_clz(x); } 
    vector<T> v; vector<vi> jmp;
    int comb(int a, int b) { // index of min
        return v[a]==v[b]?min(a,b):(v[a]<v[b]?a:b); } 
    void init(const vector<T>& _v) {
        v = _v; jmp = {vi(sz(v))}; iota(all(jmp[0]),0);
        for (int j = 1; 1<<j <= sz(v); ++j) {
            jmp.pb(vi(sz(v)-(1<<j)+1));
            F0R(i,sz(jmp[j])) jmp[j][i] = comb(jmp[j-1][i],
                                    jmp[j-1][i+(1<<(j-1))]);
        }
    }
    int index(int l, int r) { // get index of min element
        assert(l <= r); int d = level(r-l+1);
        return comb(jmp[d][l],jmp[d][r-(1<<d)+1]); }
    T query(int l, int r) { return v[index(l,r)]; }
};
struct SuffixArray {
    str S; int N; vi sa, isa, lcp;
    void init(str _S) { N = sz(S = _S)+1; genSa(); genLcp(); }
    void genSa() {
        sa = isa = vi(N); sa[0] = N-1; iota(1+all(sa),0);
        sort(1+all(sa),[&](int a, int b) { return S[a] < S[b]; });
        FOR(i,1,N) { int a = sa[i-1], b = sa[i];
            isa[b] = i > 1 && S[a] == S[b] ? isa[a] : i; }
        for (int len = 1; len < N; len *= 2) { // currently sorted by first len chars
            vi s(sa), is(isa), pos(N); iota(all(pos),0); 
            trav(t,s) { int T = t-len; if (T >= 0) sa[pos[isa[T]]++] = T; }
            FOR(i,1,N) { int a = sa[i-1], b = sa[i];
                isa[b] = is[a] == is[b] && is[a+len] == is[b+len] ? isa[a] : i; }
        }
    }
    void genLcp() { // Kasai's Algo
        lcp = vi(N-1); int h = 0;
        F0R(b,N-1) { int a = sa[isa[b]-1];
            while (a+h < sz(S) && S[a+h] == S[b+h]) h ++;
            lcp[isa[b]-1] = h; if (h) h--; }
        R.init(lcp); /// if we cut off first chars of two strings
        /// with lcp h then remaining portions still have lcp h-1 
    }
    RMQ<int> R; 
    int getLCP(int a, int b) { // lcp of suffixes starting at a,b
        if (a == b) return sz(S)-a;
        int l = isa[a], r = isa[b]; if (l > r) swap(l,r);
        return R.query(l,r-1);
    }
};
// struct SuffixArray {
//     int n;
//     std::vector<int> sa, isa, lcp;
//     std::string s;
//     SparseTable<int> S;
//     void init(std::string s_) {
//         n = (int) (s = s_).size() + 1;
//         gen_suffix_array();
//         gen_lcp_array();
//     }
//     void gen_suffix_array() {
//         sa = isa = std::vector<int>(n);
//         sa[0] = n - 1;
//         iota(1 + sa.begin(), sa.end(), 0);
//         sort(1 + sa.begin(), sa.end(), [&](int a, int b) {
//             return s[a] < s[b]; });
//         for (int i = 1; i < n; i++) {
//             int a = sa[i - 1], b = sa[i];
//             isa[b] = i > 1 && s[a] == s[b] ? isa[a] : i;
//         }
//         for (int len = 1; len < n; len *= 2) { 
//             std::vector<int> ss(sa), is(isa), pos(n);
//             iota(pos.begin(), pos.end(), 0);
//             for (auto& t : ss) {
//                 int tt = t - len;
//                 if (tt >= 0) 
//                     sa[pos[isa[tt]]++] = tt;
//             }
//             for (int i = 1; i < n; i++) {
//                 int a = sa[i - 1], b = sa[i];
//                 isa[b] = is[a] == is[b] && is[a + len] == is[b + len] ? isa[a] : i;
//             }
//         }
//         sa.erase(sa.begin());
//     }
//     void gen_lcp_array() {
//         lcp = std::vector<int>(n - 1);
//         int h = 0;
//         for (int b = 0; b < n - 1; b++) {
//             int a = sa[isa[b]];
//             while (a + h < (int) s.size() && s[a + h] == s[b + h])
//                 h++;
//             lcp[isa[b] - 1] = h;
//             if (h)
//                 h--;
//         }
//         S.init(lcp);
//     }
//     int get_lcp(int a, int b) {
//         if (a == b) 
//             return (int) s.size() - a;
//         int l = isa[a], r = isa[b];
//         if (l > r) 
//             std::swap(l, r);
//         return S.query(l, r - 1);
//     }
// };
std::vector<int> manacher(std::string s) {
    std::string t = "@";
    for (auto& c : s) 
        t += c, t += '#';
    t.back() = '&';
    std::vector<int> res((int) t.size() - 1);
    int lo = 0, hi = 0;
    for (int i = 1; i < (int) t.size() - 1; i++) {
        if (i != 1)
            res[i] = std::min(hi - i, res[hi - i + lo]);
        while (t[i - res[i] - 1] == t[i + res[i] + 1])
            res[i]++;
        if (i + res[i] > hi)
            lo = i - res[i], hi = i + res[i];
    }
    res.erase(res.begin());
    for (int i = 0; i < (int) res.size(); i++)
        if ((i & 1) == (res[i] & 1))
            res[i]++;
    return res;
}
ll solve(vi v) {
    int n = sz(v);
    SparseTable<int> S; S.init(v);
    ll ret = 0;
    f0r(i, n) {
        int l, r;
        {
            int lo = 0;
            int hi = i;
            while (hi - lo > 1) {
                int mid = (lo + hi) / 2;
                if (S.query(mid, i) == v[i]) hi = mid;
                else lo = mid + 1;
            }
            if (S.query(lo, i) == v[i]) l = lo;
            else l = hi;
        }
        {
            int lo = i;
            int hi = n-1;
            while (hi - lo > 1) {
                int mid = (lo + hi) / 2;
                if (S.query(i, mid) == v[i]) lo = mid;
                else hi = mid - 1;
            }
            if (S.query(i, hi) == v[i]) r = hi;
            else r = lo;
        }
        ret = max(ret, 1LL * (r - l + 2) * v[i]);
    }
    return ret;
}
int main() {
    cin.tie(0)->sync_with_stdio(0);
    string s; cin >> s;
    int n = sz(s);
    SuffixArray S; S.init(s);
    vi m = manacher(s);
    ll ans = 0;
    // take care of palindromes that occur exactly once
    // We'll consider PAL the 'extension'
    for (ll x : m) ans = max(ans, x);
    {
        // handle even palindromes
        // even length palindrome
        // say loc i, len L
        // consider a contiguous array in suffix array
        // [l, r]
        // Say they have lcp of x
        // min(x, min(PAL [l, r])) * 2 * (r - l + 1)
        // each thing has in common at most x
        // and each loc has palinndrome size at most PAL
        // replace with inner splices, set to min(lcp, PAL[i, i+1]) * 2
        // maximize min(l, r) * (r - l + 1) is the new problem?
        // check the min gap
        // and bash
        // okay that works
        vi pal(n);
        f0r(i, n) {
            if (i) pal[i] = m[2*i-1] / 2;
        }
        vi use(n-1);
        f0r(i, n-1) {
            int i1 = S.sa[i+1];
            int i2 = S.sa[i+2];
            int val = min(pal[i1], pal[i2]);
            val = min(S.getLCP(i1, i2), val);
            val *= 2;
            use[i] = val;
        }
        ans = max(ans, solve(use));
    }
    {
        // handle odd palindromes
        // consider a contiguous array in suffix array
        // [l, r]
        // say they have lcp of x
        // We're considering all of these as the center piece
        // (min(x - 1, min(PAL [l, r])) * 2 + 1) * (r - l + 1)
        // replace with inner splices, set to min(lcp - 1, PAL[i, i+1]) * 2 + 1
        // maximize min(l, r) * (r - l + 1) 
        // same sub problem
        vi pal(n);
        f0r(i, n) {
            pal[i] = m[2*i] / 2;
        }
        vi use(n-1);
        f0r(i, n-1) {
            int i1 = S.sa[i+1];
            int i2 = S.sa[i+2];
            int val = min(pal[i1], pal[i2]);
            val = min(val, S.getLCP(i1, i2) - 1);
            val = 2 * val + 1;
            use[i] = val;
        }
        ans = max(ans, solve(use));
        // f0r(i, n) cout << S.sa[i] << " " ;
        // cout << endl;
        // f0r(i, n-1) cout << S.getLCP(i, i+1) << " " ;
        // cout << endl;
        // f0r(i, n) cout << pal[i] << " ";
        // cout << endl;
        // f0r(i, n-1) cout << use[i] << " ";
        // cout << endl;
        // f0r(i, n-1) {
        //     cout << S.getLCP(S.sa[i], S.sa[i+1]) << " ";
        // }
        // cout << endl;
    }
    cout << ans << '\n';
    return 0;
}
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... |