Apio2014 回文串

题目描述

题解:

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

PS.PAM已更新。

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

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;
}

 这里是回文自动机:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 300050
#define ll long long
char s[N];
ll ans;
struct node
{
    int trs[28],pre,len;
    ll wgt;
}p[N];
struct PAM
{
    int las,tot;
    PAM()
    {
        las = tot = 1;
        p[0].pre = p[1].pre = 1;
        p[1].len = -1;
    }
    bool mis(int i,int x)
    {
        return s[i]!=s[i-p[x].len-1];
    }
    void insert(int i)
    {
        int np,lp,tmp;
        lp = las;
        int c = s[i]-'a'+1;
        while(mis(i,lp))lp=p[lp].pre;
        if(!p[lp].trs[c])
        {
            np=++tot;
            p[np].len = p[lp].len+2;
            tmp=p[lp].pre;
            while(mis(i,tmp))tmp=p[tmp].pre;
            p[np].pre = p[tmp].trs[c];
            p[lp].trs[c]=np;
        }
        las = p[lp].trs[c];
        p[las].wgt++;
    }
    void build()
    {
        for(int i=tot;i>=1;i--)
        {
            p[p[i].pre].wgt+=p[i].wgt;
            ans = max(ans,1ll*p[i].len*p[i].wgt);
        }
    }
}pam;
int main()
{
    scanf("%s",s+1);
    int len = strlen(s+1);
    for(int i=1;i<=len;i++)
        pam.insert(i);
    pam.build();
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-12-15 10:23  LiGuanlin  阅读(152)  评论(0编辑  收藏  举报