题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2328
题意: 求 n 个串的字典序最小的最长公共子串
思路: 本题中单个字符串长度不超过 200, 可以暴力枚举一个字符串的所有前缀, 然后用kmp去匹配其他字符串.
我这里是用后缀数组写的. 类似 http://www.cnblogs.com/geloutingyu/p/7450580.html
不过本题是有 n 个字符串, 不能直接暴力判断. 不难想到这里可以直接二分答案长度, 不过 check 函数比较难想到, 具体看代码
代码:

1 #include <iostream>
2 #include <stdio.h>
3 #include <string.h>
4 #define rank Rank
5 using namespace std;
6
7 const int MAXN = 1e6 + 10;
8 int sol;
9 char str[MAXN];
10 int SA[MAXN], rank[MAXN], height[MAXN], sum[MAXN], tp[MAXN], vis[MAXN], tag[(int)(4e3 + 10)];
11
12 bool cmp(int *f, int x, int y, int w){
13 return f[x] == f[y] && f[x + w] == f[y + w];
14 }
15
16 void DA(char *s, int n, int m){
17 for(int i = 0; i < m; i++) sum[i] = 0;
18 for(int i = 0; i < n; i++) sum[rank[i] = s[i]]++;
19 for(int i = 1; i < m; i++) sum[i] += sum[i - 1];
20 for(int i = n - 1; i >= 0; i--) SA[--sum[rank[i]]] = i;
21 for(int len = 1; len <= n; len <<= 1){
22 int p = 0;
23 for(int i = n - len; i < n; i++) tp[p++] = i;
24 for(int i = 0; i < n; i++){
25 if(SA[i] >= len) tp[p++] = SA[i] - len;
26 }
27 for(int i = 0; i < m; i++) sum[i] = 0;
28 for(int i = 0; i < n; i++) sum[rank[tp[i]]]++;
29 for(int i = 1; i < m; i++) sum[i] += sum[i - 1];
30 for(int i = n - 1; i >= 0; i--) SA[--sum[rank[tp[i]]]] = tp[i];
31 swap(rank, tp);
32 p = 1;
33 rank[SA[0]] = 0;
34 for(int i = 1; i < n; i++){
35 rank[SA[i]] = cmp(tp, SA[i - 1], SA[i], len) ? p - 1 : p++;
36 }
37 if(p >= n) break;
38 m = p;
39 }
40 int k = 0;
41 n--;
42 for(int i = 0; i <= n; i++) rank[SA[i]] = i;
43 for(int i = 0; i < n; i++){
44 if(k) k--;
45 int j = SA[rank[i] - 1];
46 while(s[i + k] == s[j + k]) k++;
47 height[rank[i]] = k;
48 }
49 }
50
51 bool check(int mid, int n, int len){
52 int cnt = 1;
53 memset(tag, 0, sizeof(tag));
54 tag[vis[SA[1]]] = 1;
55 for(int i = 2; i <= len; i++){
56 if(height[i] >= mid){
57 if(!tag[vis[SA[i]]]){
58 cnt++;
59 tag[vis[SA[i]]] = 1;
60 if(cnt >= n){
61 sol = SA[i];
62 return true;
63 }
64 }
65 }else{
66 cnt = 1;
67 memset(tag, 0, sizeof(tag));
68 tag[vis[SA[i]]] = 1;
69 }
70 }
71 return false;
72 }
73
74 int main(void){
75 int n;
76 while(~scanf("%d", &n) && n){
77 memset(vis, 0, sizeof(vis));
78 scanf("%s", str);
79 int len = strlen(str);
80 int mx = len;
81 for(int i = 1; i < n; i++){
82 vis[len] = 1;
83 str[len] = '0';
84 scanf("%s", str + 1 + len);
85 mx = max(mx, (int)(strlen(str) - len));
86 len = strlen(str);
87 }
88 str[len] = 0;
89 DA(str, len + 1, 'z' + 1);
90 for(int i = 1; i <= len; i++) vis[i] += vis[i - 1];
91 int l = 1, r = mx;
92 while(l <= r){
93 int mid = (l + r) >> 1;
94 if(check(mid, n, len)) l = mid + 1;
95 else r = mid - 1;
96 }
97 if(l - 1 <= 0){
98 puts("IDENTITY LOST");
99 continue;
100 }
101 for(int i = sol, j = 1; j <= l - 1; i++, j++){
102 printf("%c", str[i]);
103 }
104 puts("");
105 }
106 return 0;
107 }
来源:https://www.cnblogs.com/geloutingyu/p/7467440.html
