bzoj3676 [Apio2014]回文串(回文自动机)

bzoj3676 [Apio2014]回文串

原题地址
http://www.lydsy.com/JudgeOnline/problem.php?id=3676

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

数据范围
1≤字符串长度≤300000

题解:
一篇回文自动机讲解
惨啊惨啊,昔日Apio2014的题沦为裸题…

当然,我这个串出现次数就是我这个节点的cnt和所有包含我的节点的cnt和,
所谓

父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!

注意:
ch[tmp][c]=tail;放在后边,
否则可能在上面找fail时又找到了自己 。
例如0和1的fail是互指的。
1加了v节点,fail[1]=0,于是从0开始找f又找到1,这时候1的ch[c]已经是v了,于是变成了自己指向自己。


等有时间写了SAM+manacher再来UPD一发吧。


代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int N=300005;
int n=0;
char s[N];
struct PAM
{
    int ch[N][26],len[N],fail[N],cnt[N],S[N],num[N],tail,last;
    void init()
    {
        len[0]=0; len[1]=-1; fail[0]=1; last=0; S[0]=-1; tail=1;
    }
    void insert(int c)
    {
        S[++n]=c; int tmp=last;
        while(S[n-len[tmp]-1]!=S[n]) tmp=fail[tmp];
        if(!ch[tmp][c])
        {
            len[++tail]=len[tmp]+2; 
            int f=fail[tmp]; 
            while(S[n-len[f]-1]!=S[n]) f=fail[f];
            fail[tail]=ch[f][c];
            num[tail]=num[fail[tail]]+1;
            ch[tmp][c]=tail; 
        }                  
        cnt[ch[tmp][c]]++; 
        last=ch[tmp][c];
    }
}pam;

int main()
{
    scanf("%s",s+1); int lens=strlen(s+1);
    pam.init();
    for(int i=1;i<=lens;i++) pam.insert(s[i]-'a');
    LL ret=0;
    for(int i=pam.tail;i>=0;i--) 
    {
        pam.cnt[pam.fail[i]]+=pam.cnt[i];
        ret=max(ret,1LL*pam.len[i]*pam.cnt[i]);
    }
    printf("%lld\n",ret);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值