SPOJ LCS2

LCS2 - Longest Common Substring II

链接

题意:

  求N(N<=10)个串的最长公共子串。

分析:

  poj2774上那道题,对一个串建立后缀自动机,另一个在上面匹配。

  这道题是对多个串求。那么同样,让每个串在后缀自动机上匹配,然后记录在后缀自动机的每个节点上记录,当前串在这个位置和第一个串的最大匹配数,h数组。

  然后mn数组,每次对于这所有的节点的h取小,为从第2个串到现在所有的串,都能在这个节点上匹配的长度。

  因为一旦某个节点匹配上了,那么它的父节点(parent树)的父节点都会匹配上(因为父节点是当前点的后缀),所以按拓扑倒序,更新父节点的h,为父节点的len,(即最大长度)。

  第二种写法是对n-1个字符串建立SAM,然后用最后一个串在n-1个串上匹配,每个自动机上都有一个当前的指针cur,当前答案ans。对最后一个串从头开始扫,求出最后一个串和每个串以当前字符结尾的最大匹配长度,在这里面取小,每次加入一个字符,可以直接判断cur的下一位,不需要从头开始。空间太大。

  

  两种写法大同小异,只枚举举的顺序不同而已。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 inline int read() {
 6     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 7     for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
 8 }
 9 
10 const int N = 100010;
11 
12 struct Suffix_Automaton{
13     int fa[N<<1], trans[N<<1][26], len[N<<1], Last, Index;
14     int v[N], sa[N<<1], mn[N<<1], h[N<<1];
15     char s[N];
16     
17     void extend(int c) {
18         int P = Last,NP = ++Index;
19         len[NP] = len[P] + 1;
20         for (; P&&!trans[P][c]; P=fa[P]) trans[P][c] = NP;
21         if (!P) fa[NP] = 1; //-
22         else {
23             int Q = trans[P][c];
24             if (len[P] + 1 == len[Q]) fa[NP] = Q;
25             else {
26                 int NQ = ++Index;
27                 fa[NQ] = fa[Q];
28                 len[NQ] = len[P] + 1;
29                 memcpy(trans[NQ], trans[Q], sizeof trans[Q]);
30                 fa[Q] = NQ;
31                 fa[NP] = NQ;
32                 for (; P&&trans[P][c]==Q; P=fa[P]) trans[P][c] = NQ;
33             }
34         }
35         Last = NP;
36     }
37     void build() {
38         Last = Index = 1;
39         scanf("%s",s+1);
40         int n = strlen(s+1);
41         for (int i=1; i<=n; ++i) extend(s[i] - 'a');
42         for (int i=1; i<=Index; ++i) v[len[i]] ++;
43         for (int i=1; i<=n; ++i) v[i] += v[i-1];
44         for (int i=1; i<=Index; ++i) sa[ v[len[i]]-- ] = i; // sa[i] 排名为i的节点。按深度排名(拓扑用) 
45     }
46     void calcc() {
47         int n = strlen(s+1), now = 0, p = 1;
48         memset(h, 0, sizeof(h));
49         for (int i=1; i<=n; ++i) {
50             int c = s[i] - 'a';
51             if (trans[p][c]) p = trans[p][c], now ++;
52             else {
53                 for (; p&&!trans[p][c]; p=fa[p]);
54                 if (!p) now = 0, p = 1;
55                 else now = len[p] + 1, p = trans[p][c];
56             }
57             h[p] = max(h[p], now);
58         }
59         for (int i=Index; i>=1; --i) { // 拓扑倒序,parent树中从深度深的到浅的 
60             int t = sa[i];
61             mn[t] = min(mn[t], h[t]);
62             if (h[t] && fa[t]) h[fa[t]] = len[fa[t]];
63         }
64     }
65     void solve() {
66         build();
67         memset(mn, 0x3f, sizeof(mn));
68         while (scanf("%s",s+1) != EOF) calcc();        
69         int ans = 0;
70         for (int i=1; i<=Index; ++i) ans = max(ans, mn[i]);
71         printf("%d",ans);
72     }
73 }sam;
74 
75 int main() {
76     sam.solve();
77     return 0;
78 }
View Code
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 inline int read() {
 6     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 7     for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
 8 }
 9 
10 const int N = 200010;
11 
12 struct SuffixAutomaton{
13     int Last, Index, res, cur, fa[N], trans[N][26], len[N];
14     SuffixAutomaton() {Last = Index = cur = 1; res = 0;}
15     void extend(int c) {
16         int P = Last, NP = ++Index;
17         len[NP] = len[P] + 1;
18         for (; P&&!trans[P][c]; P=fa[P]) trans[P][c] = NP;
19         if (!P) fa[NP] = 1;
20         else {
21             int Q = trans[P][c];
22             if (len[P] + 1 == len[Q]) fa[NP] = Q;
23             else {
24                 int NQ = ++Index;
25                 fa[NQ] = fa[Q];
26                 len[NQ] = len[P] + 1;
27                 memcpy(trans[NQ], trans[Q], sizeof trans[Q]);
28                 fa[Q] = NQ;
29                 fa[NP] = NQ;
30                 for (; P&&trans[P][c]==Q; P=fa[P]) trans[P][c] = NQ;
31             }
32         }
33         Last = NP;
34     }
35     int solve(int c) {
36         if (trans[cur][c]) {cur = trans[cur][c]; res++; return res;}
37         for (; cur&&!trans[cur][c]; cur=fa[cur]);
38         if (!cur) res = 0, cur = 1;
39         else res = len[cur] + 1, cur = trans[cur][c];
40         return res;
41     }
42 }sam[9];
43 
44 char s[N];
45 char str[N];
46 
47 int main() {
48     int n = 0,t = 0,len;
49     scanf("%s",str+1);
50     
51     while (scanf("%s",s+1)!=EOF) {
52         len = strlen(s + 1);
53         for (int i=1; i<=len; ++i) 
54             sam[t].extend(s[i] - 'a');
55         t ++;
56     }
57     int ans = 0;
58     len = strlen(str+1);
59     for (int i=1; i<=len; ++i) {
60         int tmp = 1e9;
61         for (int j=0; j<t; ++j) 
62             tmp = min(tmp, sam[j].solve(str[i] - 'a'));
63         ans = max(ans, tmp);
64     }
65     printf("%d",ans);
66     return 0;
67 }
View Code
原文地址:https://www.cnblogs.com/mjtcn/p/9335863.html