SPOJ LCS2

LCS2 - Longest Common Substring II

链接

题意:

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

分析:

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

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

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

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

代码:

 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 }

猜你喜欢

转载自www.cnblogs.com/mjtcn/p/9335863.html