SPOJ - LCS2 后缀自动机

A string is finite sequence of characters over a non-empty finite set Σ.

In this problem, Σ is the set of lowercase letters.

Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string.

Now your task is a bit harder, for some given strings, find the length of the longest common substring of them.

Here common substring means a substring of two or more strings.

Input
The input contains at most 10 lines, each line consists of no more than 100000 lowercase letters, representing a string.

Output
The length of the longest common substring. If such string doesn’t exist, print “0” instead.

Example
Input:
alsdfkjfjkdsal
fdjskalajfkdsla
aaaajfaaaa

Output:
2
Notice: new testcases added

题意:找出n个串中最长公共子串。
做法:对一个串建后缀自动机,剩余的串在上面跑,把跑过的点标记一下,没有跑的点删除,那么剩下的自动机中的状态就是所有的公共子串,有两种处理方式.
1:因为做到一个状态x,当前最长后缀为l,说明这个状态里后缀小于等于l的子串都是符合的,那么对于每个状态保存一个cnt,代表当前状态最大可以匹配的长度,然后对所有的节点的cnt求最大就是答案了,
2:因为如果一个节点在跑了一个字符串之后没有被走过,那么这个点就可以删除,但是当走到一个状态的时候可能这个状态里面的子串只有一部分是符合的,那么就要把这个状态拆开,然后把这个状态和他的所有祖先标记,那么跑完字符串之后,得到的有标记得点就是当前所有的公共子串了。

做法一:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 3e5;
char st[N];
struct SAM{
    int pre[2*N],nex[2*N][26],mx[2*N],last,top,ans;
    int mn[2*N];
    int mp[2*N];
    void init(){
        ans = 0;
        top = 2;
        last = 1;
        memset(nex[1],0,sizeof(nex[1]));
    }
    int newnode(int x){
        mx[top] = x;
        mn[top] = x;
        for(int i = 0;i < 26;i ++) nex[top][i] = 0;
        return top ++;
    }
    void add(int x){
        int np = newnode(mx[last]+1);
        int p = last;
        while(p && nex[p][x] == 0) {
            nex[p][x] = np;
            p = pre[p];
        }
        if(!p){
            pre[np] = 1;
        }
        else{
            int q = nex[p][x];
            if(mx[q] == mx[p]+1){
                pre[np] = q;
            }
            else {
                int nq = newnode(mx[p]+1);
                for(int i = 0;i < 26;i ++) nex[nq][i] = nex[q][i];
                pre[nq] = pre[q];
                pre[np] = pre[q] = nq;
                while(p && nex[p][x] == q){
                    nex[p][x] = nq;
                    p = pre[p];
                }
            }
        }
        last = np;
    }
    void solve(char* st){
        memset(mp,0,sizeof(mp));
        int len = strlen(st);
        int p = 1;
        int nl = 0;
        for(int i = 0;i < len;i ++){
            if(nex[p][st[i]-'a']){
                nl ++;
                p = nex[p][st[i]-'a'];
                mp[p] = max(mp[p],nl);
            }
            else{
                while(p && nex[p][st[i]-'a']==0){
                    p = pre[p];
                }
                if(p == 0) {
                    p = 1,nl = 0;
                }
                else{
                    int q= nex[p][st[i]-'a'];
                    nl= mx[p] +1;
                    mp[q] = max(mp[q],nl);
                    p = q;
                }
            }
            int ps = pre[p];
            while(ps && mp[ps] != mx[ps]) mp[ps] = mx[ps],ps = pre[ps];
            //cout << i << ' '<<nl <<' '<<st[i]<< ' '<< mp[p] << endl;
        }
        ans = 0;
        for(int i = 0;i < top ;i ++) {
            mn[i] = min(mn[i],mp[i]);
            ans = max(ans,mn[i]);
        }
    }
}sa;
int main(){
    sa.init();
    scanf("%s",st);
    int len = strlen(st);
    for(int i = 0;i < len;i ++) sa.add(st[i]-'a');
    while(scanf("%s",st)!= -1){
        sa.solve(st);
    }
    printf("%d\n",sa.ans);
    return 0;
}

做法二

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 3e5;
char st[N];
struct SAM{
    int pre[12*N],nex[12*N][26],mx[12*N],last,top,ans;
    bool vis[12*N];
    void init(){
        ans = 0;
        top = 2;
        last = 1;
        memset(nex[1],0,sizeof(nex[1]));
    }
    int newnode(int x){
        mx[top] = x;
        for(int i = 0;i < 26;i ++) nex[top][i] = 0;
        return top ++;
    }
    void add(int x){
        int np = newnode(mx[last]+1);
        int p = last;
        while(p && nex[p][x] == 0) {
            nex[p][x] = np;
            p = pre[p];
        }
        if(!p){
            pre[np] = 1;
        }
        else{
            int q = nex[p][x];
            if(mx[q] == mx[p]+1){
                pre[np] = q;
            }
            else {
                int nq = newnode(mx[p]+1);
                for(int i = 0;i < 26;i ++) nex[nq][i] = nex[q][i];
                pre[nq] = pre[q];
                pre[np] = pre[q] = nq;
                while(p && nex[p][x] == q){
                    nex[p][x] = nq;
                    p = pre[p];
                }
            }
        }
        last = np;
    }
    void solve(char* st){
        memset(vis,false,sizeof(vis));
        int len =strlen(st);
        int p = 1;
        vis[p] = true;
        for(int i= 0;i < len;i ++){
            while(p && nex[p][st[i]-'a'] == 0) p = pre[p];
            if(p == 0){
                p = 1;
            }
            else{
                int q = nex[p][st[i]-'a'];
                if(mx[q] == mx[p]+1){
                    p = q;
                }
                else {
                    int nq = newnode(mx[p]+1);
                    for(int i = 0;i < 26;i ++) nex[nq][i] = nex[q][i];
                    pre[nq] = pre[q];
                    pre[q] = nq;
                    while(p && nex[p][st[i]-'a']== q){
                        nex[p][st[i]-'a'] = nq;
                        p = pre[p];
                    }
                    p = nq;
                }
            }
            int ps = p;
            while(ps && vis[ps] == false) {vis[ps] = true;ps = pre[ps];}
        }
        ans = 0;
        for(int i = 1;i < top;i ++){
            for(int j = 0;j < 26;j ++){
                if(vis[nex[i][j]] == false) nex[i][j] = 0;
            }
            if(vis[i]) ans = max(ans,mx[i]);
        }
    }
}sa;
int main(){
    sa.init();
    scanf("%s",st);
    int len = strlen(st);
    for(int i = 0;i < len;i ++) sa.add(st[i]-'a');
    while(scanf("%s",st)!= -1){
        sa.solve(st);
    }
    printf("%d\n",sa.ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zstu_zy/article/details/81257445