[SPOJ1812]LCS2 - Longest Common Substring II-后缀自动机

    xiaoxiao2021-03-25  54

    LCS2 - Longest Common Substring II

    Description

    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

    //不开心.jpg ┏┻┻┻┻┻┻┻┓ ┃ ┏┓ ┏┓ ┃ ┃ ┗┛ ^ ┗┛ ┃ ┗┏━┓━┏━┓┛ ┗━┛ ┗━┛ | | //spoj有毒.jpg

    spoj还我青春!!! 在此向所有做这道题的人一个提醒:样例错了!!! 样例输出是3!!!不是2!!! 调了我一晚上啊啊啊

    (╯‵□′)╯︵┻━┻

    发泄完了回归正文: 思路: 先对第一个串建后缀自动机~ 然后跟1811一样的思路,但由于是多个串,所以需要我们维护每个节点能匹配的最短匹配值,最后取其最大值作为答案。

    具体方法是在每次匹配时开一个数组记录当前匹配过程中当前节点匹配到的最长匹配值,在每次结束匹配后用它的值更新最短匹配值即可。

    需要注意的是,在更新时,需要对每个经过的节点,更新它们的父亲为其len值并传递下去,因为根据后缀自动机的性质,经过了当前节点,其父亲相当于也被经过了一次,只是在匹配中实际走到的是其等价的后缀节点而不是这个父亲节点。

    问题来了:怎么保证刚好传递完所有的理应被经过的点? 其实,把所有节点根据长度做一遍基数排序,按顺序更新就可以保证不会出错,跑出来的更新顺序一定是拓扑序,刚好满足传递完所有的要传递的点。 为什么呢? 因为建自动机时拓扑序在后的节点len值更大啊~ 所以就没有然后了~

    #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; const int N=200233; struct SAM { int next[N][26],fa[N],len[N]; int pool,u,id[N],b[N]; int mn[N],mx[N]; inline void init() { pool=u=1; memset(next,0,sizeof(next)); memset(len,0,sizeof(len)); memset(mn,127,sizeof(mn)); memset(fa,0,sizeof(fa)); memset(id,0,sizeof(id)); } inline void add(int v) { int now=++pool; len[now]=len[u]+1; while(!next[u][v] && u) next[u][v]=now,u=fa[u]; if(!u) fa[now]=1; else { int q=next[u][v]; if(len[q]==len[u]+1) fa[now]=q; else { int newq=++pool; len[newq]=len[u]+1; fa[newq]=fa[q]; memcpy(next[newq],next[q],sizeof(next[q])); fa[q]=fa[now]=newq; while(next[u][v]==q) next[u][v]=newq,u=fa[u]; } } u=now; } inline void topsort(int lenn) { for(int i=1;i<=pool;i++) ++b[len[i]]; for(int i=1;i<=lenn;i++) b[i]+=b[i-1]; for(int i=1;i<=pool;i++) id[b[len[i]]--]=i; } inline void run(char *s) { int now=1; int tmp=0; int lenn=strlen(s+1); memset(mx,0,sizeof(mx)); for(int i=1;i<=lenn;i++) { while(!next[now][s[i]-'a'] && now) now=fa[now],tmp=len[now]; if(!now) now=1,tmp=0; else tmp++,now=next[now][s[i]-'a']; mx[now]=max(mx[now],tmp); } for(int i=pool;i>=1;i--) { int v=id[i]; mn[v]=min(mn[v],mx[v]); if(mx[v] && fa[v]) mx[fa[v]]=len[fa[v]]; } } inline int calc() { int ans=0; for(int i=1;i<=pool;i++) ans=max(ans,mn[i]); return ans; } }koishi; int main() { koishi.init(); char s[N]; scanf("%s",s+1); int len=strlen(s+1); for(int i=1;i<=len;i++) koishi.add(s[i]-'a'); koishi.topsort(strlen(s+1)); while(scanf("%s",s+1)!=EOF) koishi.run(s); printf("%d\n",koishi.calc()); return 0; } //spoj还我青春!!!
    转载请注明原文地址: https://ju.6miu.com/read-36923.html

    最新回复(0)