码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ2342][SHOI2011]双倍回文

时间:2018-03-31 23:14:42      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:scanf   extend   一半   gpo   php   后缀树   include   body   init   

bzoj

sol

首先求出以每个位置结尾的最长回文后缀长度。
然后你实际上就是要求:对于一个长度为\(4\)的倍数的回文子串,是否存在一个长度为他的一半的回文后缀。
这个可以沿后缀树\(dfs\)一遍。因为一个回文子串的所有回文后缀一定都是他在回文树上的祖先。

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 5e5+5;
int last,tot,tr[N][26],fa[N],len[N],to[N],nxt[N],head[N],cnt,vis[N],ans;
char s[N];
void link(int u,int v)
{
    to[++cnt]=v;nxt[cnt]=head[u];
    head[u]=cnt;
}
void init()
{
    fa[0]=fa[1]=1;len[tot=1]=-1;
    link(1,0);
}
void extend(int c,int n)
{
    int v=last;
    while (s[n-len[v]-1]!=s[n]) v=fa[v];
    if (!tr[v][c])
    {
        int u=++tot,k=fa[v];
        len[u]=len[v]+2;
        while (s[n-len[k]-1]!=s[n]) k=fa[k];
        fa[u]=tr[k][c];tr[v][c]=u;
        link(fa[u],u);
    }
    last=tr[v][c];
}
void dfs(int u)
{
    if (len[u]%4==0&&vis[len[u]/2]) ans=max(ans,len[u]);
    ++vis[len[u]];
    for (int e=head[u];e;e=nxt[e]) dfs(to[e]);
    --vis[len[u]];
}
int main()
{
    int n;scanf("%d",&n);
    scanf("%s",s+1);
    init();
    for (int i=1;i<=n;++i) extend(s[i]-'a',i);
    dfs(1);
    printf("%d\n",ans);return 0;
}

[BZOJ2342][SHOI2011]双倍回文

标签:scanf   extend   一半   gpo   php   后缀树   include   body   init   

原文地址:https://www.cnblogs.com/zhoushuyu/p/8684552.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!