[HDU2328]Corporate Identity(后缀数组)
求 n 个串的字典序最小的最长公共子串。
和 2 个串的处理方法差不多。
把 n 个串拼接在一起,中间连上一个没有出现过的字符防止匹配过界。
求出 height 数组后二分公共子串长度给后缀数组分组。
然后 check,每一组中是否所有的字符串都包含。
直接遍历 sa 数组,第一个满足的结果就是字典序最小的。
——代码
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define N 900005 5 #define M 4001 6 7 int n, len, m, start; 8 int buc[N], x[N], y[N], sa[N], rank[N], height[N], belong[N]; 9 char s[N], a[M]; 10 bool f[M]; 11 12 inline void build_sa() 13 { 14 int i, k, p; 15 for(i = 0; i < m; i++) buc[i] = 0; 16 for(i = 0; i < len; i++) buc[x[i] = s[i]]++; 17 for(i = 1; i < m; i++) buc[i] += buc[i - 1]; 18 for(i = len - 1; i >= 0; i--) sa[--buc[x[i]]] = i; 19 for(k = 1; k <= len; k <<= 1) 20 { 21 p = 0; 22 for(i = len - 1; i >= len - k; i--) y[p++] = i; 23 for(i = 0; i < len; i++) if(sa[i] >= k) y[p++] = sa[i] - k; 24 for(i = 0; i < m; i++) buc[i] = 0; 25 for(i = 0; i < len; i++) buc[x[y[i]]]++; 26 for(i = 1; i < m; i++) buc[i] += buc[i - 1]; 27 for(i = len - 1; i >= 0; i--) sa[--buc[x[y[i]]]] = y[i]; 28 std::swap(x, y); 29 p = 1, x[sa[0]] = 0; 30 for(i = 1; i < len; i++) 31 x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++; 32 if(p >= len) break; 33 m = p; 34 } 35 } 36 37 inline void build_height() 38 { 39 int i, j, k = 0; 40 for(i = 0; i < len; i++) rank[sa[i]] = i; 41 for(i = 0; i < len; i++) 42 { 43 if(!rank[i]) continue; 44 if(k) k--; 45 j = sa[rank[i] - 1]; 46 while(s[i + k] == s[j + k] && i + k < len && j + k < len) k++; 47 height[rank[i]] = k; 48 } 49 } 50 51 inline bool check(int k) 52 { 53 int i, cnt = 1; 54 memset(f, 0, sizeof(f)); 55 f[belong[sa[0]]] = 1; 56 for(i = 1; i < len; i++) 57 if(height[i] >= k) 58 { 59 if(!f[belong[sa[i]]]) cnt++; 60 f[belong[sa[i]]] = 1; 61 if(cnt == n) 62 { 63 start = sa[i]; 64 return 1; 65 } 66 } 67 else 68 { 69 memset(f, 0, sizeof(f)); 70 f[belong[sa[i]]] = 1; 71 cnt = 1; 72 } 73 return 0; 74 } 75 76 int main() 77 { 78 int i, j, l, r, mid, leng; 79 while(scanf("%d", &n) && n) 80 { 81 len = 0; 82 m = 256; 83 memset(belong, 0, sizeof(belong)); 84 for(i = 1; i <= n; i++) 85 { 86 scanf("%s", a); 87 for(j = 0; a[j] ^ '\0'; j++) s[len++] = a[j]; 88 s[len++] = '#'; 89 belong[len] = 1; 90 } 91 len--; 92 build_sa(); 93 build_height(); 94 for(i = 1; i < len; i++) belong[i] += belong[i - 1]; 95 l = 1, r = len, leng = 0, start = -1; 96 while(l <= r) 97 { 98 mid = (l + r) >> 1; 99 if(check(mid)) leng = mid, l = mid + 1; 100 else r = mid - 1; 101 } 102 if(leng && start ^ -1) 103 { 104 for(i = start; i < start + leng; i++) putchar(s[i]); 105 putchar('\n'); 106 } 107 else puts("IDENTITY LOST"); 108 } 109 return 0; 110 }