JZOJ3654. 【APIO2014】回文串(palindrome)
Description
考虑一个只包含小写拉丁字母的符串 s。我们定义 s的一个子串 t的“出现值”为 t在 s中的出现次数乘以t的长度。 请你求出s的所有 回文子串中的最大出现值。
Input
输入只有一行,为一个只包含小写字母 (a−z) 的非空字符串 s。
Output
输出 一个整数,为 所有 回文子串 的最大 出现 值。
Sample Input
输入1:
abacaba
输入2:
www
Sample Output
输出1:
7
输出2:
4
Data Constraint
见hint
len(s)<=300000
想法:
回文树
#include <cstdio>
#include <cstring>
#include <iostream>
#define max(a,b) (((a)>(b))?(a):(b))
using namespace std;
const int maxN=300010;
char s[maxN];
int n,i,ans;
struct huiwen_tree{
long long ans,cur,i,s[maxN],next[maxN][26],fail[maxN],cnt[maxN],len[maxN],num[maxN],last,now,n,p;
int newnode(int x){
for (i=0;i<26;i++) next[p][i]=0;
cnt[p]=num[p]=fail[p]=0;
len[p]=x;
return p++;
}
void init(){
p=0;
newnode(0);
newnode(-1);
len[1]=-1;
fail[0]=1;
s[0]=-1;
last=0;
n=0;
}
int get_fail(int last){
while (s[n]!=s[n-len[last]-1]) last=fail[last];
return last;
}
void add(int c,int x){
c-='a';
s[++n]=c;
cur=get_fail(last);
if (!next[cur][c]){
now=newnode(len[cur]+2);
fail[now]=next[get_fail(fail[cur])][c];
next[cur][c]=now;
num[now]=num[fail[now]]+1;
}
last=next[cur][c],cnt[last]++;
}
void count(){
for (i=p-1;i>-1;i--) cnt[fail[i]]+=cnt[i];
}
void prans(){
ans=0;
for (i=0;i<p;i++)
ans=max(ans,cnt[i]*len[i]);
printf("%lld",ans);
}
}run;
int main(){
freopen("palindrome.in","r",stdin);
freopen("palindrome.out","w",stdout);
scanf("%s",s+1);
n=strlen(s+1),s[0]=' ';
run.init();
for (i=1;i<=n;i++)
run.add(s[i],i);
run.count();
run.prans();
}