[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 }