codevs 3160 最长公共子串(SAM)

 

3160 最长公共子串

 
题目描述  Description

给出两个由小写字母组成的字符串,求它们的最长公共子串的长度。

输入描述  Input Description

读入两个字符串

输出描述  Output Description

输出最长公共子串的长度

样例输入  Sample Input
yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother
样例输出  Sample Output

27

数据范围及提示  Data Size & Hint

单个字符串的长度不超过100000

 

【思路】

 

  SAM求LCS

 

【代码】

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 const int N = 2*1e5+10;
 6 
 7 char s[N];
 8 int sz,root,last,fa[N],ch[N][26],l[N],n;
 9 
10 void add(int x) {
11     int c=s[x]-'a';
12     int p=last,np=++sz; last=np;
13     l[np]=x+1;
14     for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
15     if(!p) fa[np]=root;
16     else {
17         int q=ch[p][c];
18         if(l[p]+1==l[q]) fa[np]=q;
19         else {
20             int nq=++sz; l[nq]=l[p]+1;
21             memcpy(ch[nq],ch[q],sizeof(ch[q]));
22             fa[nq]=fa[q];
23             fa[np]=fa[q]=nq;
24             for(;p&&q==ch[p][c];p=fa[p]) ch[p][c]=nq;
25         }
26     }
27 }
28 void build() {
29     root=last=++sz;
30     scanf("%s",s);
31     n=strlen(s);
32     for(int i=0;i<n;i++) add(i);
33 }
34 void lcs() {
35     scanf("%s",s);
36     n=strlen(s);
37     int p=root,ans=0,len=0;
38     for(int i=0;i<n;i++) {
39         int c=s[i]-'a';
40         if(ch[p][c]) { len++; p=ch[p][c]; }
41         else {
42             for(;p&&!ch[p][c];p=fa[p]);
43             if(!p) { p=root; len=0; }
44             else {
45                 len=l[p]+1; p=ch[p][c];
46             }
47         }
48         if(len>ans) ans=len;
49     }
50     printf("%d",ans);
51 }
52 
53 int main() {
54     build();
55     lcs();
56     return 0;
57 }

 

你可能感兴趣的:(codevs 3160 最长公共子串(SAM))