jzoj3654 [APIO2014] Palindrome (Palindrome, Automata)

topic

Consider a string s containing only lowercase Latin letters. We define the "occurrence value" of a substring t of s as the number of occurrences of t in s times the length of t. Please find the largest occurrence of all palindromic substrings of s.

Palindromic Tree Naked Questions

Palindromic tree: A point represents a palindrome with the same content. Transition means prefixing and suffixing this palindrome with letters.
fail points to the longest palindrome suffix of the current palindrome.
last is the point where the longest palindrome suffix of the total string currently added is located. (for the next letter)

The title requirement is length * maximum number of occurrences.
The cnt maintained at the beginning is the sum of the occurrences of such a palindrome.

codetrick:
0 is an even root, 1 is an odd root, fail[0]=1, fail[1]=-1 (convenient to judge no palindrome suffix)
len[1]=-1, which is convenient for dealing with odd lengths.

the complexity

At most n essentially distinct palindrome strings. It can be seen from the palindrome construction method. (The process of horse-drawn carriage can also be explained)

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N=3e5+10;
char s[N];
int n,last,len[N],fail[N],cnt[N],p,nex[N][26];

int main() {
    freopen("palindrome.in","r",stdin);
//  freopen("palindrome.out","w",stdout);
    scanf("%s",s+1); n=strlen(s+1);
    p=1; len[1]=-1; fail[0]=1; fail[1]=-1;
    //要记住的Trick!
    //1 odd root
    for (int i=1; i<=n; i++) {
        while (s[i-len[last]-1] != s[i]) //寻找能接上的最长回文后缀
            last=fail[last];
        int &g=nex[last][s[i]-'a'];
        if (!g) { //若不存在新建节点与fail
            g=++p,len[g]=len[last]+2;
            int k=fail[last];
            while (k!=-1 && s[i-len[k]-1] != s[i]) k=fail[k];
            //维护fail
            if (k==-1) fail[g]=0; //如没有是指向空串的。
            else fail[g]=nex[k][s[i]-'a'];
        }
        cnt[g]++; //其实g的fail链上出现次数全部+1了,因此后面再扫一遍统计。相当于打tag。
        last=g;
    }
    for (int i=p; i>=0; i--) cnt[fail[i]]+=cnt[i];
    long long ans=0;
    for (int i=1; i<=p; i++) ans=max(ans,(long long)len[i]*cnt[i]);
    cout<<ans<<endl;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325551107&siteId=291194637