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;
}
发布了104 篇原创文章 · 获赞 127 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_33330876/article/details/71043156