zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",ans);
        return 0;
    }
  • 相关阅读:
    Codeforces Round #326 (Div. 2)
    UVAlive 6611 Alice's Print Service 二分
    codeforces868D Huge Strings
    [HNOI2016]大数
    [NOI 2015]软件包管理器
    幻方
    poj3728 商务旅行
    [SCOI2016]背单词
    [USACO12FEB]牛的IDCow IDs
    [Cqoi2010]扑克牌
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10122644.html
Copyright © 2011-2022 走看看