【APIO2014T1】回文串-回文自动机(PAM)模板题

测试地址:回文串

做法:这道题可以用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;
}


原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793758.html