bzoj3676-回文串

给出一个字符串,一个子串的出现值为字串出现次数乘以长度,求所有回文串中最大的出现值。

分析

回文自动机模版题,建出自动机后直接统计即可。

回文自动机

类似于后缀自动机,不过一条边\((u,v,c)\)的含义是在\(u\)点的串左右两边加上字母\(c\)可以得到\(v\)点代表的串。它的\(fail\)指针和AC自动机类似。这里有一个重要的简化代码,就是开始时设两个点,\(len\)长度分别为0和-1,两个点的fail指针互相指对方,这样可以保证奇数长度回文串长度从1开始,直接-1+2即可。fail往前跳的时候一定能够跳到0号点或1号点。这种写法还是很好的。

代码

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long giant;
int read() {
    int x=0,f=1;
    char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=3e5+1;
const int maxc=26;
struct PAM {
    int s[maxn],n,t[maxn][maxc],len[maxn],link[maxn],cnt[maxn],last,tot;
    PAM () {
        last=tot=1;
        s[n=0]=-1;
        len[0]=0,len[1]=-1;
        link[0]=1,link[1]=0;
    }
    int fail(int x) {
        for (;s[n-len[x]-1]!=s[n];x=link[x]);
        return x;
    }
    void add(int x) {
        s[++n]=x;
        last=fail(last);
        if (!t[last][x]) {
            int nw=++tot;
            len[nw]=len[last]+2;
            link[nw]=t[fail(link[last])][x];
            t[last][x]=nw;
        }
        ++cnt[last=t[last][x]];
    }
    giant run() {
        giant ans=0;
        for (int i=tot;i>1;--i) cnt[link[i]]+=cnt[i],ans=max(ans,(giant)cnt[i]*len[i]);     
        return ans;
    }
} pam;
char s[maxn];
int main() {
    #ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
    #endif
    scanf("%s",s+1);
    int n=strlen(s+1);
    for (int i=1;i<=n;++i) pam.add(s[i]-'a');
    printf("%lld\n",pam.run());
    return 0;
}

转载于:https://www.cnblogs.com/owenyu/p/6724648.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值