bzoj3676 [Apio2014]回文串

4 篇文章 0 订阅

Description


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

一个串是回文的,当且仅当它从左到右读和从右到左读完全一样。
数据满足1≤字符串长度≤300000。

Solution


第一次接触,吓得我赶紧学习一波
具体就是每个节点记录长度,x向y连边权为w表示x通过首尾添加一个字符w能得到回文串y
与ac自动机类似的,用一个fail记录最长同后缀的回文串。一个比较神奇的操作就是建两个点长度为0、-1来表示奇偶性不同的回文串
需要注意的是统计的时候不能漏一个回文串包含另一个回文串的情况

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
typedef long long LL;
const int N=300005;
char st[N];
struct pam {
    int last,cnt,fail[N],rec[N][26],len[N],size[N];
    pam() {len[1]=-1; fail[0]=fail[1]=1; cnt=1;}
    void ins(int x,int n) {
        int p=last;
        while (st[n-len[p]-1]!=st[n]) p=fail[p];
        if (!rec[p][x]) {
            int now=++cnt,k=fail[p]; len[now]=len[p]+2;
            while (st[n-len[k]-1]!=st[n]) k=fail[k];
            fail[now]=rec[k][x]; rec[p][x]=now;
        }
        last=rec[p][x];
        size[last]++;
    }
    void solve() {
        LL ans=0;
        drp(i,cnt,1) {
            size[fail[i]]+=size[i];
            ans=std:: max(ans,(LL)size[i]*len[i]);
        }
        printf("%lld\n", ans);
    }
}pam;
int main(void) {
    // freopen("palindrome.in","r",stdin);
    // freopen("palindrome.out","w",stdout);
    scanf("%s",st+1);
    int len=strlen(st+1);
    rep(i,1,len) {
        pam.ins(st[i]-'a',i);
    }
    pam.solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值