• CF700E Cool Slogans 后缀自动机+right集合线段树合并+树形DP


    题目描述

    给出一个长度为n的字符串s[1],由小写字母组成。定义一个字符串序列s[1....k],满足性质:s[i]在s[i-1] (i>=2)中出现至少两次(位置可重叠),问最大的k是多少,使得从s[1]开始到s[k]都满足这样一个性质。

    发现 $s[1...k]$ 之间一定是互为后缀关系. 那么就可以建出后缀树,令 $dp_{u}$ 表示 $u$ 节点代表子串的答案

    维护 $top_{u}$ 表示 $u$ 以及 $u$ 在后缀树的祖先中合法的且答案最大(答案相同则最短)的节点编号

    $dp_{u}Rightarrow dp_{top_{fa}}+1$ ,$fa$ 在 $u$ 中出现大于等于2次

    $dp_{u}=1,top_{u}=top_{fa}$,$fa$ 在 $u$ 中仅出现 $1$ 次

    #include<bits/stdc++.h>
    #define maxn 400002 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;   
    namespace tr 
    {
        #define lson t[x].l 
        #define rson t[x].r 
        #define mid ((l+r)>>1) 
        int cnt; 
        struct Node { int l,r; }t[maxn*20]; 
        void modify(int &x,int l,int r,int k)
        {
            if(!x) x=++cnt; 
            if(l==r) return; 
            if(k<=mid) modify(lson,l,mid,k); 
            else modify(rson,mid+1,r,k); 
        }
        int merge(int u,int v) 
        {
            if(!u||!v) return u+v; 
            int x=++cnt; 
            lson=merge(t[u].l,t[v].l); 
            rson=merge(t[u].r,t[v].r);    
            return x;             
        }
        int query(int x,int l,int r,int L,int R)
        {
            if(!x) return 0; 
            if(l>=L&&r<=R) return 1; 
            int tmp=0; 
            if(L<=mid) tmp+=query(lson,l,mid,L,R); 
            if(R>mid) tmp+=query(rson,mid+1,r,L,R); 
            return tmp; 
        }
    }; 
    namespace SAM 
    { 
        char str[maxn]; 
        int last,tot,n;  
        int trans[maxn][27],f[maxn],len[maxn],C[maxn],rk[maxn],top[maxn],dp[maxn],pos[maxn],rt[maxn];  
        void init() { last=tot=1; }
        void extend(int c,int i) 
        {  
            int np=++tot,p=last; 
            len[np]=len[p]+1,last=np; 
            while(p&&!trans[p][c]) trans[p][c]=np,p=f[p]; 
            if(!p) f[np]=1; 
            else 
            {
                int q=trans[p][c]; 
                if(len[q]==len[p]+1) f[np]=q; 
                else 
                {
                    int nq=++tot; 
                    len[nq]=len[p]+1; 
                    pos[nq]=pos[q];  
                    memcpy(trans[nq],trans[q],sizeof(trans[q])); 
                    f[nq]=f[q], f[np]=f[q]=nq; 
                    while(p&&trans[p][c]==q) trans[p][c]=nq,p=f[p]; 
                }
            }
            pos[np]=i; 
            tr::modify(rt[last],1,n,i);   
        }
        void prepare() 
        {
            int i,j; 
            init(); 
            scanf("%d%s",&n,str+1);  
            for(i=1;i<=n;++i) extend(str[i]-'a',i);  
            for(i=1;i<=tot;++i) ++C[len[i]]; 
            for(i=1;i<=tot;++i) C[i]+=C[i-1]; 
            for(i=1;i<=tot;++i) rk[C[len[i]]--]=i;    
            for(i=tot;i>1;--i) 
            {
                int u=rk[i]; 
                rt[f[u]]=tr::merge(rt[f[u]],rt[u]);  
            }                     
        }
        void calc() 
        {
            int i,j,ans=1; 
            for(i=2;i<=tot;++i) 
            {
                int u=rk[i],ff=f[rk[i]];  
                if(ff==1) { top[u]=u,dp[u]=1; continue; }  
                if(tr::query(rt[top[ff]],1,n,pos[u]-len[u]+len[top[ff]],pos[u]-1))
                    top[u]=u,dp[u]=dp[top[ff]]+1; 
                else 
                    top[u]=top[ff];       
                ans=max(ans,dp[u]);                 
            }
            printf("%d
    ",ans);  
        }
    }; 
    int main()
    {
        //msetIO("input"); 
        SAM::prepare();                  
        SAM::calc(); 
        return 0; 
    }
    

      

  • 相关阅读:
    哪有什么互联网寒冬?只是你穿的少而已!
    我不是机器人:谷歌最新版验证码系统ReCaptcha破解已开源
    Gradle更小、更快构建APP的奇淫技巧
    一篇文章让你了解Android各个版本的历程
    快速开发android,离不开这10个优秀的开源项目
    年底Android面试整理(附答案)
    最近Android真的凉凉了?
    Android 应用防止被二次打包指南
    开发了5年android,我开始了go学习之旅
    做了5年的Android,我转Java后台了!
  • 原文地址:https://www.cnblogs.com/guangheli/p/11141107.html
Copyright © 2020-2023  润新知