洛谷 - P3649 - 回文串 - 回文自动机

https://www.luogu.org/problem/P3649

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct Node {
    int len, ch[26], fail;
    int cnt;
    Node(int len = 0) : len(len), fail(0) {
        memset(ch, 0, sizeof(ch));
        //下面是维护额外信息
        cnt=0;
    }
};

const int MAXN = 300000;

//PalindromicAutomaton
struct PAM {
    Node nd[MAXN + 5];

    int len, top, last;     // len为字符串长度mtop为节点个数,last为最后插入字符所对应的节点
    char s[MAXN + 5];

    int getfail(int x) {        //沿着fail指针找到第一个回文后缀
        while(s[len - nd[x].len - 1] != s[len])
            x = nd[x].fail;
        return x;
    }

    PAM() : len(0), top(0), last(0) {
        nd[top] = Node(0);
        nd[top].fail = 1;
        nd[++top] = Node(-1);
        nd[top].fail = 0;
        s[0] = '$';
    }

    void extend(char c) {
        s[++len] = c;
        int now = getfail(last);     //找到插入的位置
        if(!nd[now].ch[c - 'a']) {     //若没有这个节点,则新建并求出它的fail指针
            nd[++top] = Node(nd[now].len + 2);
            nd[top].fail = nd[getfail(nd[now].fail)].ch[c - 'a'];
            nd[now].ch[c - 'a'] = top;
        }
        last = nd[now].ch[c - 'a'];
        //下面是维护额外信息
        ++nd[last].cnt;
    }
} pam;

char s[MAXN + 5];

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    scanf("%s", s);
    for(int i = 0; s[i] != '\0'; ++i)
        pam.extend(s[i]);
    ll ans = 0;
    for(int i = pam.top; i >= 2; --i) {
        pam.nd[pam.nd[i].fail].cnt += pam.nd[i].cnt;
        ans = max(ans, 1ll * pam.nd[i].cnt * pam.nd[i].len);
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2019-07-26 16:06  韵意  阅读(179)  评论(0编辑  收藏  举报