测试地址:回文串
做法:这道题可以用Manacher+后缀数组来做,但是很慢,于是本人用了一个上午去学习了回文自动机(Palindromic Automaton,PAM)这个东西,它是一个可以接受字符串的所有回文子串的自动机,并且可以很方便地求出所有本质不同的回文子串的一些信息,教程可以看这个。看完之后其实这就是一道PAM的裸题了,求出每一个本质不同的回文子串的长度和出现的次数,然后枚举求最大值就可以了。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
int n,now=0,tot=1,pos;
ll ans=0;
char s[300010];
struct PAMnode
{
ll len,cnt;
int fail,ch[30];
}nd[300010];
int getfail(int x)
{
while (s[pos-nd[x].len-1]!=s[pos]) x=nd[x].fail;
return x;
}
void insert(int c)
{
c-='a';
now=getfail(now);
if (!nd[now].ch[c])
{
int son=++tot;
nd[now].ch[c]=son;
nd[son].fail=nd[getfail(nd[now].fail)].ch[c];
nd[son].len=nd[now].len+2;
nd[son].cnt=1;
for(int i=0;i<=25;i++) nd[son].ch[i]=0;
}
else nd[nd[now].ch[c]].cnt++;
now=nd[now].ch[c];
}
int main()
{
s[0]='#';
scanf("%s",&s[1]);
n=strlen(s)-1;
nd[0].len=nd[0].cnt=0,nd[0].fail=1;
for(int i=0;i<=25;i++) nd[0].ch[i]=0;
nd[1].len=nd[n+1].len=-1,nd[1].fail=n+1,nd[1].cnt=0;
for(int i=0;i<=25;i++) nd[1].ch[i]=nd[n+1].ch[i]=0;
for(pos=1;pos<=n;pos++)
insert(s[pos]);
for(int i=tot;i>=2;i--)
nd[nd[i].fail].cnt+=nd[i].cnt;
for(int i=2;i<=tot;i++)
ans=max(ans,nd[i].len*nd[i].cnt);
printf("%lld",ans);
return 0;
}