BZOJ3676 回文串 (回文树)

题目大意

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


题解

回文树裸题,但是这里要注意一定要在最后统一推标记,否则全1串的时候一定会TLE。
这里附上一个写得很好的回文树讲解 回文树介绍(Palindromic Tree)


代码

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;

const int maxn=int(3e5)+111;
struct Palind_Tree {
    int len[maxn],next[maxn][26],fail[maxn],cnt[maxn];
    int siz,suff;

    bool add(char *s,int pos) {
        int cur=suff, curlen=0;
        int ch=s[pos]-'a';

        while(true) {
            curlen=len[cur];
            if(pos-1-curlen>=0 && s[pos-1-curlen]==s[pos])
                break;
            cur=fail[cur];
        }
        if(next[cur][ch]) {
            suff=next[cur][ch];
            cnt[suff]++;
            return false;
        }

        suff=++siz;
        len[siz]=len[cur]+2;
        next[cur][ch]=siz;
        cnt[siz]=1;

        if(len[siz]==1) {
            fail[siz]=2;
            return true;
        }

        cur=fail[cur];
        while(true) {
            curlen=len[cur];
            if(pos-1-curlen>=0 && s[pos-1-curlen]==s[pos])
                break;
            cur=fail[cur];
        }
        fail[siz]=next[cur][ch];
        return true;
    }

    void init() {
        siz=2; suff=2;
        len[1]=-1, fail[1]=1;
        len[2]=0, fail[2]=1;
        return;
    }

    long long get_res() {
        for(int i=siz;i>=2;i--)
            cnt[fail[i]]+=cnt[i];
        long long res=0;
        for(int i=3;i<=siz;i++)
            res=max(res,1ll*len[i]*cnt[i]);
        return res;
    }
}Tree;

int n;
char s[maxn];

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
#endif // ONLINE_JUDGE
    Tree.init();
    scanf("%s",&s);
    n=strlen(s);

    for(int i=0;i<n;i++)
        Tree.add(s,i);
    printf("%lld\n",Tree.get_res());

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值