多个串的最长公共子串 SPOJ - LCS2 后缀自动机

题意:

求多个串的最长公共子串

这里用的是O(n)的后缀自动机写法

我后缀数组的专题有nlog(n)写法的

 

题解:

对于其中的一个串建立后缀自动机

然后对于后缀自动机上面的每一个节点求出每一个节点最长可以匹配的子串(用maxx【】数组存下)

但是在后缀自动机上面有些节点没有走过,但是是某些走过的点的父亲节点因此也是有值的

for (int i = tot; i; i--)
maxx[fail[i]] = max(maxx[fail[i]], min(len[fail[i]], maxx[i]));

然后求一个所有最小值里面的最大值就好了

  1 #include <set>
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 #include <string>
  9 #include 
 10 #include 
 11 #include 
 12 #include 
 13 #include 
 14 
 15 #define  pi    acos(-1.0)
 16 #define  eps   1e-9
 17 #define  fi    first
 18 #define  se    second
 19 #define  rtl   rt<<1
 20 #define  rtr   rt<<1|1
 21 #define  bug                printf("******\n")
 22 #define  mem(a, b)          memset(a,b,sizeof(a))
 23 #define  name2str(x)        #x
 24 #define  fuck(x)            cout<<#x" = "< 25 #define  sfi(a)             scanf("%d", &a)
 26 #define  sffi(a, b)         scanf("%d %d", &a, &b)
 27 #define  sfffi(a, b, c)     scanf("%d %d %d", &a, &b, &c)
 28 #define  sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
 29 #define  sfL(a)             scanf("%lld", &a)
 30 #define  sffL(a, b)         scanf("%lld %lld", &a, &b)
 31 #define  sfffL(a, b, c)     scanf("%lld %lld %lld", &a, &b, &c)
 32 #define  sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
 33 #define  sfs(a)             scanf("%s", a)
 34 #define  sffs(a, b)         scanf("%s %s", a, b)
 35 #define  sfffs(a, b, c)     scanf("%s %s %s", a, b, c)
 36 #define  sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d)
 37 #define  FIN                freopen("../in.txt","r",stdin)
 38 #define  gcd(a, b)          __gcd(a,b)
 39 #define  lowbit(x)          x&-x
 40 #define  IO                 iOS::sync_with_stdio(false)
 41 
 42 
 43 using namespace std;
 44 typedef long long LL;
 45 typedef unsigned long long ULL;
 46 const ULL seed = 13331;
 47 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
 48 const int maxn = 1e6 + 50;
 49 const int maxm = 8e6 + 10;
 50 const int INF = 0x3f3f3f3f;
 51 const int mod = 1e9 + 7;
 52 char s[maxn];
 53 
 54 struct Suffix_Automaton {
 55     int last, tot, nxt[maxn << 1][26], fail[maxn << 1];//last是未加入此字符前最长的前缀(整个串)所属的节点的编号
 56     int len[maxn << 1];// 最长子串的长度 (该节点子串数量 = len[x] - len[fail[x]])
 57     int maxx[maxn << 1];
 58 
 59     void init() {
 60         tot = last = 1;
 61         fail[1] = len[1] = 0;
 62         for (int i = 0; i < 26; i++) nxt[1][i] = 0;
 63     }
 64 
 65     void extend(int c) {
 66         int u = ++tot, v = last;
 67         for (int i = 0; i < 26; i++) nxt[u][i] = 0;
 68         fail[u] = 0;
 69         len[u] = len[v] + 1;
 70         for (; v && !nxt[v][c]; v = fail[v]) nxt[v][c] = u;
 71         if (!v) fail[u] = 1;
 72         else if (len[nxt[v][c]] == len[v] + 1) fail[u] = nxt[v][c];
 73         else {
 74             int now = ++tot, cur = nxt[v][c];
 75             len[now] = len[v] + 1;
 76             memcpy(nxt[now], nxt[cur], sizeof(nxt[cur]));
 77             fail[now] = fail[cur];
 78             fail[cur] = fail[u] = now;
 79             for (; v && nxt[v][c] == cur; v = fail[v]) nxt[v][c] = now;
 80         }
 81         last = u;
 82         //return len[last] - len[fail[last]];//添加一个新的字符产生的新的本质不同的子串数目
 83     }
 84 
 85     int minn[maxn << 1];
 86 
 87     void match() {
 88         mem(maxx, 0);
 89         int n = strlen(s);
 90         int p = 1, maxlen = 0;
 91         for (int i = 0; i < n; i++) {
 92             int c = s[i] - 'a';
 93             if (nxt[p][c]) p = nxt[p][c], maxlen++;
 94             else {
 95                 for (; p && !nxt[p][c]; p = fail[p]);
 96                 if (!p) p = 1, maxlen = 0;
 97                 else maxlen = len[p] + 1, p = nxt[p][c];
 98             }
 99             maxx[p] = max(maxx[p], maxlen);
100         }
101         for (int i = tot; i; i--)
102             maxx[fail[i]] = max(maxx[fail[i]], min(len[fail[i]], maxx[i]));
103         for (int i = tot; i; i--)
104             if (minn[i] == -1 || minn[i] > maxx[i]) minn[i] = maxx[i];
105     }
106 
107 } sam;
108 
109 
110 int main() {
111 #ifndef ONLINE_JUDGE
112     FIN;
113 #endif
114     sfs(s);
115     int n = strlen(s);
116     sam.init();
117     for (int i = 0; i < n; ++i) sam.extend((s[i] - 'a'));
118     for (int i = 0; i <= sam.tot; i++) sam.minn[i] = -1;
119     while (~sfs(s)) sam.match();
120     int ans = 0;
121     for (int i = 1; i <= sam.tot; i++) ans = max(ans, sam.minn[i]);
122     printf("%d\n", ans);
123 #ifndef ONLINE_JUDGE
124     cout << "Totle Time : " << (double) clock() / CLOCKS_PER_SEC << "s" << endl;
125 #endif
126     return 0;
127 }
View Code

 




你可能感兴趣的:(多个串的最长公共子串 SPOJ - LCS2 后缀自动机)