bzoj 3676: [Apio2014]回文串 回文自动机

题意

考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。

分析

回文自动机板子题,在这里记一个代码
其实很多地方和SAM很相似
跳fail的时候不用桶排,因为本来深度比较大的编号也自然比较大(SAM有新开一个点的操作,这个没有)

算是维护一个后缀回文链

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 300010;
char s[N]; ll n;
struct node
{
  ll fail[N],step[N],tot,last,g[N][27],siz[N];
  node(){}
  void init()
  {
    fail[1] = 1; fail[0] = 1; step[1] = -1; step[0] = 0; tot = 1;
  }
  void insert(ll nx)
  {
    n++; ll p = last;
    while(s[n - step[p] - 1] != s[n]) p = fail[p];
    if(!g[p][nx])
    {
      ll np = ++tot; step[np] = step[p]+2;
      ll q = fail[p];
      while(s[n - step[q] - 1] != s[n]) q = fail[q];
      fail[np] = g[q][nx]; g[p][nx] = np;
    }p = g[p][nx]; siz[p]++; last = p;
  }
}p;
int main()
{
  scanf("%s",s+1); int len = strlen(s+1); p.init();
  n = 0; for(ll i=1;i<=len;i++) p.insert(s[i]-'a'+1);
  for(ll i=p.tot;i>=1;i--) if(p.fail[i]) p.siz[p.fail[i]] += p.siz[i];
  ll ans = 0; for(ll i=1;i<=p.tot;i++) ans = max(ans , p.siz[i] * p.step[i]);
  return printf("%lld\n",ans),0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39708759/article/details/80139749