WOJ3750—子串查找(后缀自动机)

给定一个字符串 A和1个字符串 B ,求 B 和 A 中的最长公共子串。(len(a、b)<=2e5)

只需要对一个串建一个samsam

然后把另一个串在上面跑就是了

如果发现当前已匹配好的地方的下一个字符不一样,就沿着当前节点的linklink一直往上跳,跳到第一个能匹配的地方跳下去就可以了

因为endposendpos的性质这显然是对的

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
struct node{
    int len,link,nxt[27];
    bool cl;
};
#define max(a,b) (((a)>(b))?a:b)
const int N=200005;
node st[N<<1];
int tot,ans,last;
char a[N];
inline void init(){
    tot=last=0;
    st[0].len=0,st[0].link=-1;
    ++tot;
}
inline void sa_extend(int c){
    int cur=tot++;
    st[cur].len=st[last].len+1;
    int p;
    for(p=last;p!=-1&&!st[p].nxt[c];p=st[p].link) st[p].nxt[c]=cur;
    if(p==-1)st[cur].link=0;
    else{
        int q=st[p].nxt[c];
        if(st[p].len+1==st[q].len)st[cur].link=q;
        else {
            int clo=tot++;
            st[clo]=st[q];
            st[clo].len=st[p].len+1;
            for(;p!=-1&&st[p].nxt[c]==q;p=st[p].link)st[p].nxt[c]=clo;
            st[q].link=st[cur].link=clo;
        }
    }
    last=cur;
}
int main(){
    scanf("%s",a+1),init();
    int len=strlen(a+1);
    for(int i=1;i<=len;i++)sa_extend(a[i]-'a'+1);
    scanf("%s",a+1),len=strlen(a+1);
	int pos=0,tmp=0;
	for(int i=1;i<=len;i++){
		int nx=a[i]-'a'+1;
		if(st[pos].nxt[nx])pos=st[pos].nxt[nx],tmp++;
		else {
			while(pos!=-1&&!st[pos].nxt[nx])pos=st[pos].link;
			if(pos==-1)pos=0,tmp=0;
			else tmp=st[pos].len+1,pos=st[pos].nxt[nx];
		}
		ans=max(ans,tmp);
	}
	cout<<ans;
}
posted @ 2018-12-20 23:29  Stargazer_cykoi  阅读(120)  评论(0编辑  收藏  举报