[APIO2014]回文串(回文自动机)

题意

给你一个由小写拉丁字母组成的字符串 s。我们定义 s 的一个子串的存在值为这个子串在 s 中出现的次数乘以这个子串的长度。

对于给你的这个字符串 s,求所有回文子串中的最大存在值。

|S|<=300000

题解

裸的回文树,我们在每一个节点结束的最长回文后缀上记录一个cnt代表出现次数。

这个最长回文后缀T的每一个回文后缀一定也会出现和cnt[T]一样的次数。

所以倒着统计答案并使cht前移就行了。

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N=300010;
 8 int n,tot,len[N],fail[N],s[N],last,to[N][30],cnt[N];
 9 int L;
10 long long ans;
11 char ch[N];
12 void init(){
13     n=0;tot=1;
14     len[0]=0;len[1]=-1;
15     fail[0]=1;s[0]=-1;last=0;
16     memset(to,0,sizeof(to));
17 }
18 void add(int c){
19     s[++n]=c;
20     int cur,now,tmp;
21     for(cur=last;s[n-len[cur]-1]!=c;cur=fail[cur]);
22     if(!to[cur][c]){
23         tot++;
24         len[tot]=len[cur]+2;now=tot;
25         for(tmp=fail[cur];s[n-len[tmp]-1]!=c;tmp=fail[tmp]);
26         fail[now]=to[tmp][c];
27         to[cur][c]=now;
28     } 
29     last=to[cur][c];
30     cnt[last]++;
31 }
32 void count(){
33     for(int i=tot;i>=1;i--){
34         cnt[fail[i]]+=cnt[i];
35         ans=max(1ll*cnt[i]*len[i],ans);
36     }
37 }
38 int main(){
39     scanf("%s",ch+1);
40     L=strlen(ch+1);
41     init();
42     for(int i=1;i<=L;i++)add(ch[i]-'a');
43     count();
44     printf("%lld",ans);
45     return 0;
46 } 

 

posted @ 2018-08-29 14:58  Xu-daxia  阅读(121)  评论(0编辑  收藏  举报