• SPOJ 1812 LCS2 [后缀自动机 DP]


    题意:

    求多个串<=10的最长连续子串


    一个串建SAM,然后其他串在上面走

    每个状态记录所有串在这个状态的公共子串的最小值

    一个串在上面走的时候记录与每个状态公共子串的最大值,注意出现次数向父亲传递,一个状态能到达说明了Suffix Link指向的状态可以取到最大子串,这一步对val后基数排序然后倒着更新就行了

    注意两点:

    1.空间要开两倍,基数排序用的东西也要两倍哦

    2.答案不能用mn[1]更新!!!!因为mn[1]没有意义啊root状态一个子串也没有还可能有某些bug

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=2e5+5;
    int n,m;
    char s[N];
    struct State{
        int ch[26],par,val;
    }t[N<<1];
    int sz,root,last;
    inline int nw(int _){t[++sz].val=_;return sz;}
    void iniSAM(){sz=0;root=last=nw(0);}
    void extend(int c){
        int p=last,np=nw(t[p].val+1);
        while(p&&t[p].ch[c]==0) t[p].ch[c]=np,p=t[p].par;
        if(p==0) t[np].par=root;
        else{
            int q=t[p].ch[c];
            if(t[q].val==t[p].val+1) t[np].par=q;
            else{
                int nq=nw(t[p].val+1);
                memcpy(t[nq].ch,t[q].ch,sizeof(t[q].ch));
                t[nq].par=t[q].par;
                t[q].par=t[np].par=nq;
                while(p&&t[p].ch[c]==q) t[p].ch[c]=nq,p=t[p].par;
            }
        }
        last=np;
    }
    int mx[N<<1],mn[N<<1];
    void walk(char s[]){
        int sum=0,u=root,n=strlen(s+1);
        for(int i=1;i<=n;i++){
            int c=s[i]-'a';
            if(t[u].ch[c]) u=t[u].ch[c],mx[u]=max(mx[u],++sum);
            else{
                while(u&&!t[u].ch[c]) u=t[u].par;
                if(!u) u=root,sum=0;
                else sum=t[u].val,u=t[u].ch[c],mx[u]=max(mx[u],++sum);
            }
        }
    }
    
    int c[N<<1],a[N<<1],ans;
    void RadixSort(int len){
        for(int i=1;i<=sz;i++) c[t[i].val]++;
        for(int i=1;i<=len;i++) c[i]+=c[i-1];
        for(int i=sz;i>=1;i--) a[c[t[i].val]--]=i; 
        for(int i=1;i<=sz;i++) mn[i]=t[i].val;
    }
    void solve(){
        iniSAM();
        scanf("%s",s+1);
        int len=strlen(s+1);
        for(int i=1;i<=len;i++) extend(s[i]-'a');
        RadixSort(len);
        while(scanf("%s",s+1)!=EOF){
            walk(s);
            for(int j=sz;j>=1;j--){
                int u=a[j];
                mn[u]=min(mn[u],mx[u]);
                if(mx[u]&&t[u].par) mx[t[u].par]=t[t[u].par].val;
                mx[u]=0;
            }
        }
        for(int i=2;i<=sz;i++) ans=max(ans,mn[i]);
        printf("%d",ans);
    }
    int main(){
        //freopen("in","r",stdin);
        solve();
    }
  • 相关阅读:
    1002. Find Common Characters查找常用字符
    338. Counting Bits_比特位计数_简单动态规划
    Rail_UVa514_栈
    784. Letter Case Permutation C++字母大小写全排列
    C语言实现哈夫曼编码(最小堆,二叉树)
    559. Maximum Depth of N-ary Tree C++N叉树的最大深度
    27. Remove Element C++移除元素
    26. Remove Duplicates from Sorted Array C++ 删除排序数组中的重复项
    linux软件源配置
    linux 下安装 maven
  • 原文地址:https://www.cnblogs.com/candy99/p/6376055.html
Copyright © 2020-2023  润新知