BZOJ3676 回文串 (回文树)

来源:互联网 发布:飞翔快递打印软件 编辑:程序博客网 时间:2024/06/01 09:32

题目大意

考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为ts中的出现次数乘以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;}
1 0