zoukankan      html  css  js  c++  java
  • 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();
    }
  • 相关阅读:
    Java对象的生命周期与作用域的讨论(转)
    [置顶] Oracle学习路线与方法
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
  • 原文地址:https://www.cnblogs.com/candy99/p/6376055.html
Copyright © 2011-2022 走看看