给定 n 个字符串,求出现或反转后出现在每个字符串中的最长子串。
算法分析:
这题不同的地方在于要判断是否在反转后的字符串中出现。其实这并没有加大题目的难度。
只需要先将每个字符串都反过来写一遍,中间用一个互不相同的且没有出现在字符串中的字符隔开,
再将 n 个字符串全部连起来,中间也是用一个互不相同的且没有出现在字符串中的字符隔开,求后缀数组。
然后二分答案,再将后缀分组。
判断的时候,要看是否有一组后缀在每个原来的字符串或反转后的字符串中出现。
这个做法的时间复杂度为 O(nlogn)。
——代码
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define N 21001 5 6 int len, n, m, max_num, T; 7 int buc[N], x[N], y[N], sa[N], rank[N], height[N], belong[N], s[N]; 8 char a[N]; 9 bool f[101]; 10 11 inline void build_sa() 12 { 13 int i, k, p; 14 for(i = 0; i < m; i++) buc[i] = 0; 15 for(i = 0; i < len; i++) buc[x[i] = s[i]]++; 16 for(i = 1; i < m; i++) buc[i] += buc[i - 1]; 17 for(i = len - 1; i >= 0; i--) sa[--buc[x[i]]] = i; 18 for(k = 1; k <= len; k <<= 1) 19 { 20 p = 0; 21 for(i = len - 1; i >= len - k; i--) y[p++] = i; 22 for(i = 0; i < len; i++) if(sa[i] >= k) y[p++] = sa[i] - k; 23 for(i = 0; i < m; i++) buc[i] = 0; 24 for(i = 0; i < len; i++) buc[x[y[i]]]++; 25 for(i = 1; i < m; i++) buc[i] += buc[i - 1]; 26 for(i = len - 1; i >= 0; i--) sa[--buc[x[y[i]]]] = y[i]; 27 std::swap(x, y); 28 p = 1, x[sa[0]] = 0; 29 for(i = 1; i < len; i++) 30 x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++; 31 if(p >= len) break; 32 m = p; 33 } 34 } 35 36 inline void build_height() 37 { 38 int i, j, k = 0; 39 for(i = 0; i < len; i++) rank[sa[i]] = i; 40 for(i = 0; i < len; i++) 41 { 42 if(!rank[i]) continue; 43 if(k) k--; 44 j = sa[rank[i] - 1]; 45 while(s[i + k] == s[j + k] && i + k < len && j + k < len) k++; 46 height[rank[i]] = k; 47 } 48 } 49 50 inline bool check(int k) 51 { 52 int i, cnt = 1; 53 memset(f, 0, sizeof(f)); 54 f[belong[sa[0]]] = 1; 55 for(i = 1; i < len; i++) 56 if(height[i] >= k && !f[belong[sa[i]]]) 57 { 58 cnt++; 59 f[belong[sa[i]]] = 1; 60 if(cnt == n) return 1; 61 } 62 else if(height[i] < k) 63 { 64 cnt = 1; 65 memset(f, 0, sizeof(f)); 66 f[belong[sa[i]]] = 1; 67 } 68 return 0; 69 } 70 71 inline int solve() 72 { 73 int l = 1, r = len, ans = 0, mid; 74 while(l <= r) 75 { 76 mid = (l + r) >> 1; 77 if(check(mid)) ans = mid, l = mid + 1; 78 else r = mid - 1; 79 } 80 return ans; 81 } 82 83 int main() 84 { 85 int i, j, l; 86 scanf("%d", &T); 87 while(T--) 88 { 89 len = 0; 90 m = 400; 91 scanf("%d", &n); 92 for(i = 0; i < n; i++) 93 { 94 scanf("%s", a); 95 l = strlen(a); 96 for(j = 0; j < l; j++) belong[len] = i, s[len++] = a[j]; 97 belong[len] = i; 98 s[len++] = 130 + (i << 1); 99 for(j = l - 1; j >= 0; j--) belong[len] = i, s[len++] = a[j]; 100 belong[len] = i; 101 s[len++] = 130 + (i << 1 | 1); 102 } 103 len--; 104 build_sa(); 105 build_height(); 106 if(n == 1) 107 { 108 printf("%d ", l); 109 continue; 110 } 111 printf("%d ", solve()); 112 } 113 return 0; 114 }