[BZOJ2946][Poi2000]公共串 后缀自动机

2946: [Poi2000]公共串

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 1367  Solved: 612
[Submit][Status][Discuss]

Description

 
       给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
任务:
l        读入单词
l        计算最长公共子串的长度
l        输出结果
 

Input

 
文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。
 

Output

仅一行,一个整数,最长公共子串的长度。
 

Sample Input

3
abcb
bca
acbc

Sample Output

HINT

 

Source

 

第一次写后缀自动机,感觉非常神奇。

对第一个串建立后缀自动机,多串进行匹配。

每次匹配的时候对于后缀自动机中的每个节点维护ans,ls,表示的是到达该节点所能匹配上的最大后缀长度(每个节点都可能是多个节点的儿子,所以从根到该点的路径长度可能是不同的)。

我们还需要按照step从大到小,用每个节点取更新他的link节点,因为如果匹配到一个状态,那么实际上他link链上的所有状态都匹配了,for(int i=cnt;i;i--) ls[link[pos[i]]]=max(ls[pos[i]],ls[link[pos[i]]]);

然后对于每个串匹配后得到的每个位置的ls数组取min得到数组ans,ans的最大值极为答案。 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<algorithm>
 7 #define maxn 4005
 8 using namespace std;
 9 char ch[maxn];
10 struct data {
11     int son[maxn][30],step[maxn],link[maxn],last,cnt;
12     int ans[maxn],v[maxn],pos[maxn],ls[maxn];
13     data() {last=cnt=1;}
14     void extend(int c) {
15         int p=last,np=last=++cnt;step[np]=step[p]+1;
16         while(!son[p][c]&&p) son[p][c]=np,p=link[p];
17         if(!p) link[np]=1;
18         else {
19             int q=son[p][c];
20             if(step[q]==step[p]+1) link[np]=q;
21             else {
22                 int nq=++cnt;
23                 step[nq]=step[p]+1;
24                 memcpy(son[nq],son[q],sizeof(son[q]));
25                 link[nq]=link[q];
26                 link[np]=link[q]=nq;
27                 while(son[p][c]==q) son[p][c]=nq,p=link[p];
28             }
29         }
30     }
31     void pre() {
32         for(int i=1;i<=cnt;i++) {ans[i]=step[i];v[step[i]]++;}
33         for(int i=1;i<=cnt;i++) v[i]+=v[i-1];
34         for(int i=cnt;i;i--) pos[v[step[i]]--]=i;
35     }
36     void solve() {
37         memset(ls,0,sizeof(ls));
38         scanf("%s",ch+1);
39         int l=strlen(ch+1),p=1,tmp=0;
40         for(int i=1;i<=l;i++) {
41             int c=ch[i]-'a';
42             while(!son[p][c]&&p) p=link[p];
43             if(!p) p=1,tmp=0;
44             else tmp=min(tmp,step[p])+1,p=son[p][c];
45             ls[p]=max(ls[p],tmp);
46         }
47         for(int i=cnt;i;i--) ls[link[pos[i]]]=max(ls[pos[i]],ls[link[pos[i]]]);
48         for(int i=1;i<=cnt;i++) ans[i]=min(ans[i],ls[i]);
49     }
50     void getans() {
51         int an=0;
52         for(int i=1;i<=cnt;i++) an=max(an,ans[i]);
53         printf("%d\n",an);
54     }
55 }sam;
56 int main() {
57     int n;
58     scanf("%d",&n);
59     scanf("%s",ch+1);
60     int l=strlen(ch+1);
61     for(int i=1;i<=l;i++) sam.extend(ch[i]-'a');
62     sam.pre();
63     for(int i=2;i<=n;i++) sam.solve();
64     sam.getans();
65 }
View Code

 

posted @ 2018-01-08 21:27  wls001  阅读(160)  评论(0编辑  收藏  举报