제출 #1151633

#제출 시각아이디문제언어결과실행 시간메모리
1151633OI_Account회문 (APIO14_palindrome)C++20
0 / 100
29 ms56972 KiB
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 600'000;
const int M = 26;
const int T = 2;
const ll MOD[T] = {1'000'000'007, 1'000'000'009};
const ll B[T] = {47, 47};

int n, a[N + 10];
int counter, last, len[N + 10], cnt[N + 10];
int lnk[N + 10], nxt[N + 10][M + 3];
pair<int, int> h[2][N + 10];
int pw[T][N + 10];

int pre[N + 10], mark[N + 10];
int fen[3][N + 10];
vector<int> st1[N + 10], en1[N + 10];
vector<int> st2[N + 10], en2[N + 10];

void readInput() {
    string str;
    cin >> str;
    n = (int) str.size();
    for (int i = 1; i <= n; i++)
        a[i] = str[i - 1] - 'a';
}

void calcHash() {
    for (int x = 0; x < 2; x++) {
        h[x][0] = {0, 0};
        for (int i = 1; i <= n; i++) {
            h[x][i].first = ((ll) h[x][i - 1].first * B[0] + a[i]) % MOD[0];
            h[x][i].second = ((ll) h[x][i - 1].second * B[1] + a[n - i + 1]) % MOD[1];
        }
    }
}

void calcPw() {
    for (int t = 0; t < T; t++) {
        pw[t][0] = 1;
        for (int i = 1; i <= n; i++)
            pw[t][i] = (ll) pw[t][i - 1] * B[t] % MOD[t];
    }
}

pair<ll, ll> getHash(int t, int l, int r) {
    ll res1 = ((ll) h[t][r].first - (ll) h[t][l - 1].first * pw[0][r - l + 1] % MOD[0] + MOD[0]) % MOD[0];
    ll res2 = ((ll) h[t][r].second - (ll) h[t][l - 1].second * pw[1][r - l + 1] % MOD[1] + MOD[1]) % MOD[1];
    return {res1, res2};
}

bool isPalindrome(int l, int r) {
    pair<ll, ll> p1 = getHash(0, l, r);
    pair<ll, ll> p2 = getHash(1, n - r + 1, n - l + 1);
    //cout << l << ' ' << r << ":::::: " << (p1 == p2) << endl;
    return p1 == p2;
}

int newVer(int v = 0) {
    int u = ++counter;
    if (v)
        for (int j = 0; j < M; j++)
            nxt[u][j] = nxt[v][j];
    return u;
}

int calcFirstHave(int pnt, int newLast, int c) {
    while (pnt && !nxt[pnt][c]) {
        nxt[pnt][c] = newLast;
        pnt = lnk[pnt];
    }
    return pnt;
}

void changeTillHave(int pnt, int c, int x, int y) {
    while (pnt && nxt[pnt][c] == x) {
        nxt[pnt][c] = y;
        pnt = lnk[pnt];
    }
}

void addChar(int c) {
    int idx = calcFirstHave(last, newVer(), c);
    len[counter] = len[last] + 1;
    last = counter;
    if (!idx || len[nxt[idx][c]] == len[idx] + 1) 
        lnk[last] = (idx? nxt[idx][c]: 1);
    else {
        int v = nxt[idx][c], u = newVer(nxt[idx][c]);
        changeTillHave(idx, c, v, u);
        lnk[u] = lnk[v];
        len[u] = len[idx] + 1;
        lnk[v] = lnk[last] = u;
    }
}

void calcSuffixAuto() {
    counter = 1;
    last = 1;
    for (int i = 1; i <= n; i++)
        addChar(a[i]);
}

void calcCnt() {
    for (int pnt = last; pnt != 1; pnt = lnk[pnt])
        cnt[pnt] = 1;
    vector<pair<int, int>> vec;
    for (int i = 1; i <= counter; i++)
        vec.push_back({len[i], i});
    sort(vec.begin(), vec.end());
    for (int i = counter - 1; i >= 0; i--) {
        int u = vec[i].second;
        for (int j = 0; j < M; j++)
            cnt[u] += cnt[nxt[u][j]];
    }
}

void calcPre() {
    pre[0] = 1;
    for (int i = 1; i <= n; i++)
        pre[i] = nxt[pre[i - 1]][a[i]];
    for (int i = 1; i <= n; i++)
        if (!mark[pre[i]])
            for (int j = pre[i]; j != 1 && !mark[j]; j = lnk[j])
                mark[j] = i;
}

void update(int t, int idx, int val) {
    for (; idx <= n; idx += idx & -idx)
        fen[t][idx] += val;
}

int get(int t, int idx) {
    int res = 0;
    for (; idx; idx -= idx & -idx)
        res += fen[t][idx];
    return res;
}

int getFirst(int t, int low) {
    int idx = 0, remain = get(t, low - 1);
    for (int j = M; j >= 0; j--)
        if (idx + (1 << j) <= n && fen[t][idx + (1 << j)] <= remain) {
            idx += (1 << j);
            remain -= fen[t][idx];
        }
    return idx + 1;
}

pair<int, int> calcSeg1(int i) {
    int l = 0, r = min(i, n - i + 1);
    while (r - l > 1) {
        int mid = (l + r) >> 1;
        if (isPalindrome(i - mid, i + mid))
            l = mid;
        else
            r = mid;
    }
    return {i, i + l};
}

pair<int, int> calcSeg2(int i) {
    int l = 1, r = min(i, n - i + 2);
    while (r - l > 1) {
        int mid = (l + r) >> 1;
        if (isPalindrome(i - mid, i + mid - 1))
            l = mid;
        else
            r = mid;
    }
    return {i, i + l - 1};
}

void calcStEn() {
    for (int i = 1; i <= n; i++) {
        //cout << "p1 " << endl;
        pair<int, int> p1 = calcSeg1(i);
        st1[p1.first].push_back(i);
        en1[p1.second].push_back(i);
        //cout << "p2" << endl;
        if (1 < i && a[i] == a[i - 1]) {
            pair<int, int> p2 = calcSeg2(i);
            st2[p2.first].push_back(i);
            en2[p2.second].push_back(i);
        }
        //cout << i << ": " << p1.first << ' ' << p1.second << endl;
    }
    for (int i = 1; i <= n; i++) {
        st1[i].shrink_to_fit();
        en1[i].shrink_to_fit();
        st2[i].shrink_to_fit();
        en2[i].shrink_to_fit();
    }
}

ll check1(int l, int r, int u) {
    int mid1 = (r + l + 1) / 2;
    mid1 = getFirst(1, mid1);
    if (mid1 <= r)
        return (ll) (2 * (r - mid1) + 1) * (ll) cnt[u];
    return 0;
}

ll check2(int l, int r, int u) {
    if (l == r)
        return 0;
    int mid2 = (r + l + 2) / 2;
    mid2 = getFirst(2, mid2);
    if (mid2 <= r)
        return (ll) (2 * (r - mid2 + 1)) * (ll) cnt[u];
    return 0;
}

ll calcAns(int i) {
    if (mark[pre[i]] != i)
        return 0;
    ll res = 0;
    for (int u = pre[i]; u != 1 && mark[u] == i; u = lnk[u]) {
        int r = i;
        int l = i - len[u] + 1;
        res = max(res, check1(l, r, u));
        res = max(res, check2(l, r, u));
    }
    return res;
}

void calcAns() {
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        for (auto idx: st1[i])
            update(1, idx, 1);
        for (auto idx: st2[i])
            update(2, idx, 1);
        ans = max(ans, calcAns(i));
        for (auto idx: en1[i])
            update(1, idx, -1);
        for (auto idx: en2[i])
            update(2, idx, -1);
    }
    cout << ans << flush;
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    readInput();
    calcHash();
    calcPw();
    calcSuffixAuto();
    calcCnt();
    calcPre();
    calcStEn();
    calcAns();
    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...