[SPOJ1811]Longest Common Substring 后缀自动机 最长公共子串

[SPOJ1811]Longest Common Substring 后缀自动机 最长公共子串

题目链接:http://www.spoj.com/problems/LCS/

题意如题目,求两个串的最大公共子串LCS。

首先对其中一个字符串A建立SAM,然后用另一个字符串B在上面跑。

用一个变量Lcs来记录当前答案,如果能转移到下一个状态则Lcs++。

若不能转移说明需要重新选择状态,则不断地跳到当前状态的fa状态,如果发现能够转移就停下来,Lcs变为当前状态的len+1并转移到下一个可行状态。

这里很像AC自动机的fail指针的跳跃。因为fa状态是当前状态的后缀,已经被匹配过,而fa状态有更多的机会转移。

于是最后的答案就是所有状态下Lcs的最大值。这样做的总体思想是求出对于每一个位置能向前扩展的最大长度。值得注意的是对于一个成功匹配状态s的匹配长度显然也可以作为它fa的匹配长度。因为fa的right集合一定包含了s的right集合,即都包含了当前的Lcs串的结束位置,从s开始向上更新一遍就好了,不过这里好像不需要。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int n,m;
 6 char a[250010],b[250010];
 7 struct State{
 8     int ch[26],fa,len;
 9     void init(){
10         fa=-1;
11         len=0;
12         memset(ch,-1,sizeof(ch));
13     }
14 }T[500010];
15 int cnt=0,la;
16 void Extend(int c){
17     int end=++cnt,tmp=la;
18     T[end].init();
19     T[end].len=T[tmp].len+1;
20     while((~tmp)&&(!~T[tmp].ch[c])){
21         T[tmp].ch[c]=end;
22         tmp=T[tmp].fa;
23     }
24     if(!~tmp) T[end].fa=0;
25     else{
26         int ne=T[tmp].ch[c];
27         if(T[tmp].len+1==T[ne].len) T[end].fa=ne;
28         else{
29             int np=++cnt;
30             T[np]=T[ne];
31             T[np].len=T[tmp].len+1;
32             T[end].fa=T[ne].fa=np;
33             while((~tmp)&&T[tmp].ch[c]==ne){
34                 T[tmp].ch[c]=np;
35                 tmp=T[tmp].fa;
36             }
37         }
38     }
39     la=end;
40 }
41 void solve(){
42     int ans=0;
43     T[0].init();
44     for(int i=1;i<=n;i++) Extend(a[i]-'a');
45     int Lcs=0,o=0;
46     for(int i=1;i<=m;i++){
47         int c=b[i]-'a';
48         if(~T[o].ch[c]){
49             o=T[o].ch[c];
50             ans=max(ans,++Lcs);
51         }
52         else{
53             while((~o)&&(!~T[o].ch[c])) o=T[o].fa;
54             if(!~o) o=Lcs=0;
55             else{
56                 Lcs=T[o].len+1;
57                 o=T[o].ch[c];
58                 ans=max(ans,Lcs);
59             }
60         }
61     }
62     printf("%d
",ans);
63 }
64 int main(){
65     scanf("%s%s",a+1,b+1);
66     n=strlen(a+1);
67     m=strlen(b+1);
68     solve();
69     return 0;
70 }