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();
}

 

posted @ 2017-02-07 21:49  Candy?  阅读(1093)  评论(0编辑  收藏  举报