码迷,mamicode.com
首页 > Windows程序 > 详细

Apio2014 回文串

时间:2018-12-15 11:49:51      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:def   pre   query   name   ret   amp   insert   int   return   

题目描述

题解:

这篇题解是关于manacher+SAM的。

因为我还不会回文自动机我会学的

SAM支持给出一个串,求出现次数。

manacher支持找回文串。

然后放在一起,当每个节点回文半径扩展时查询。

这样时间是O(n^2)的。

为了时间,我们可以O(nlogn)预处理每个节点沿pre指针条2^k次到哪个点。

然后查询O(nlogn)。

貌似只有bz卡空间?

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 300050
#define ll long long
char s0[N],s1[2*N];
int len,n;
struct node{int pre,len,trs[26];}p[2*N];
int siz[2*N],rt[N];
struct SAM
{
    int tot,las;
    SAM(){tot=las=1;}
    int insert(int c)
    {
        int np,nq,lp,lq;
        np=++tot;
        siz[np]=1;
        p[np].len = p[las].len+1;
        for(lp=las;lp&&!p[lp].trs[c];lp=p[lp].pre)
            p[lp].trs[c]=np;
        if(!lp)p[np].pre = 1;
        else
        {
            lq = p[lp].trs[c];
            if(p[lq].len==p[lp].len+1)p[np].pre = lq;
            else
            {
                nq=++tot;
                p[nq]=p[lq];
                p[nq].len = p[lp].len+1;
                p[lq].pre = p[np].pre = nq;
                while(p[lp].trs[c]==lq)
                {
                    p[lp].trs[c]=nq;
                    lp=p[lp].pre;
                }
            }
        }
        return las = np;
    }
    int hs[2*N],topo[2*N],fa[2*N][21];
    int i,j,x;
    void build()
    {
        for(i=1;i<=tot;i++)hs[p[i].len]++;
        for(i=1;i<=tot;i++)hs[i]+=hs[i-1];
        for(i=1;i<=tot;i++)topo[hs[p[i].len]--]=i;
        for(i=tot;i>=1;i--)
        {
            x = topo[i];
            siz[p[x].pre]+=siz[x];
            fa[x][0]=p[x].pre;
        }
        for(i=1;i<=tot;i++)
        {
            x = topo[i];
            for(j=1;j<=20;j++)
                fa[x][j]=fa[fa[x][j-1]][j-1];
        }
    }
    int len;
    int query()
    {
        x = rt[x];
        for(i=20;i>=0;i--)
        {
            if(p[fa[x][i]].len>=len)
            {
                x=fa[x][i];
            }
        }
        return x;
    }
}sam;
void init()
{
    s1[0]=!;
    s1[++n]=#;
    for(int i=1;i<=len;i++)
    {
        s1[++n]=s0[i];
        s1[++n]=#;
    }
    s1[n+1]=@;
}
int rp[2*N];
ll manacher()
{
    init();
    ll ans = 0;
    int mid = 0,mx = 0,i,u;
    for(i=1;i<=n;i++)
    {
        if(i<=mx)rp[i]=min(rp[2*mid-i],mx-i+1);
        else
        {
            rp[i]=1;
            if(i%2==0)ans=max(ans,1ll*siz[p[1].trs[s1[i]-a]]);
        }
        while(s1[i-rp[i]]==s1[i+rp[i]])
        {
            rp[i]++;
            if((i-rp[i]+1)%2==0)
            {
                sam.x = (i+rp[i]-1)/2,sam.len = rp[i];
                u = sam.query();
                ans = max(ans,1ll*siz[u]*rp[i]);
            }
        }
        if(i+rp[i]-1>mx)mx=i+rp[i]-1,mid=i;
    }
    return ans;
}
int main()
{
    scanf("%s",s0+1);
    len = strlen(s0+1);
    for(int i=1;i<=len;i++)
        rt[i]=sam.insert(s0[i]-a);
    sam.build();
    printf("%lld\n",manacher());
    return 0;
}

 

Apio2014 回文串

标签:def   pre   query   name   ret   amp   insert   int   return   

原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10122644.html

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