• SPOJ 1812 LCS2


    思路

    后缀自动机求多串的最长公共子串
    对第一个建出后缀自动机,其他的在SAM上匹配,更新到一个节点的匹配长度最大值即可,最后对所有最大值取min得到一个节点的答案,对所有节点答案求max即可
    然后注意,因为parent树上的父节点是是子节点的后缀,所以一旦子节点匹配,也需要更新父节点的最大匹配值(min(maxlen[fa],max(mx[son],mx[fa])))

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    int maxlen[202000],suflink[202000],barrel[202000],trans[202000][26],Nodecnt,ranks[202000];
    int New_state(int _maxlen,int *_trans,int _suflink){
        ++Nodecnt;
        maxlen[Nodecnt]=_maxlen;
        if(_trans)
            for(int i=0;i<26;i++)
                trans[Nodecnt][i]=_trans[i];
        suflink[Nodecnt]=_suflink;
        return Nodecnt;
    }
    int add_len(int u,int c){
        int z=New_state(maxlen[u]+1,NULL,0);
        while(u&&trans[u][c]==0){
            trans[u][c]=z;
            u=suflink[u];
        }
        if(!u){
            suflink[z]=1;
            return z;
        }
        int v=trans[u][c];
        if(maxlen[v]==maxlen[u]+1){
            suflink[z]=v;
            return z;
        }
        int y=New_state(maxlen[u]+1,trans[v],suflink[v]);
        suflink[v]=suflink[z]=y;
        while(u&&trans[u][c]==v){
            trans[u][c]=y;
            u=suflink[u];
        }
        return z;
    }
    void c_sort(int n,int lim){
        memset(barrel,0,sizeof(barrel));
        for(int i=1;i<=n;i++)
            barrel[maxlen[i]]++;
        for(int i=1;i<=lim;i++)
            barrel[i]+=barrel[i-1];
        for(int i=1;i<=n;i++)
            ranks[barrel[maxlen[i]]--]=i;        
    }
    int Ans[202000],mx[202000];  
    char s[202000];
    int main(){
        // freopen("test.in","r",stdin);
        int cnt=0,last=1;
        Nodecnt=1;
        int len;
        while(~scanf("%s",s+1)){
            ++cnt;
            len=strlen(s+1);
            if(cnt==1){
                for(int i=1;i<=len;i++)
                    last=add_len(last,s[i]-'a');
                c_sort(Nodecnt,200010);    
                for(int i=1;i<=Nodecnt;i++)
                    Ans[i]=maxlen[i];
            }
            else{
                memset(mx,0,sizeof(mx));
                int nowp=1,lent=0;
                for(int i=1;i<=len;i++){
                    if(trans[nowp][s[i]-'a']){
                        lent++;
                        nowp=trans[nowp][s[i]-'a'];
                    }
                    else{
                        while(nowp&&trans[nowp][s[i]-'a']==0)
                            nowp=suflink[nowp];
                        if(!nowp){
                            nowp=1;
                            lent=0;
                            continue;
                        }
                        else{
                            lent=maxlen[nowp]+1;
                            nowp=trans[nowp][s[i]-'a'];
                        }
                    }
                    mx[nowp]=max(mx[nowp],lent);
                }
                for(int i=Nodecnt;i>=1;i--){
                    int t=ranks[i];
                    mx[suflink[t]]=max(mx[suflink[t]],mx[t]);                
                }
                for(int i=1;i<=Nodecnt;i++)
                    Ans[i]=min(Ans[i],mx[i]);
            } 
        }
        int ans=0;
        for(int i=1;i<=Nodecnt;i++)
            ans=max(Ans[i],ans);
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    HTTP POST GET 本质区别详解
    本人完成的代码生成器,请多提些建议
    .net实现控件视图状态ViewState
    专门用于微信公众平台的Javascript API导言
    [学习笔记]验证上传文件后缀名类型
    专门用于微信公众平台的Javascript API
    1个月成为HTML5前端工程师
    js中用正则表达式 过滤特殊字符, 校验所有输入域是否含有特殊符号
    SharePoint 2010 根据不同的用户权限显示不同的导航
    (原创)Sharepoint webpart中调用web service报错
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10733708.html
Copyright © 2020-2023  润新知