SPOJ #687 Repeats (后缀数组的应用)
题目描述:
给定字符串,求字符串中最大的连续重复子串出现次数是多少。
解题思路:
如果一个重复子串的长度是$l$,那么它一定跨过$S_0,S_l,S_{l*2},S_{l*\cdots}$中连续的两个,那我们就可以枚举$l$,枚举起始位置$i*l$,用$SA$求出$S_{i * l},S_{i*l+l}$的$lcp$,那么$\frac{lcp}{l}+1$就是答案。对吗?不一定,有可能$S_{i*l}$前面有段可以匹配,那我们就将位置前移多匹配,但不足l的多出来的那段。再求次$lcp$计算。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int N = 5e4 + 10; 7 int T, n, m, st[N][20], ans; 8 int sa[N], height[N], rank[N], tax[N], tp[N]; 9 char s[N]; 10 11 void rsort() { 12 for (int i = 0; i <= m; i ++) tax[i] = 0; 13 for (int i = 1; i <= n; i ++) tax[rank[tp[i]]] ++; 14 for (int i = 1; i <= m; i ++) tax[i] += tax[i - 1]; 15 for (int i = n; i >= 1; i --) sa[tax[rank[tp[i]]] --] = tp[i]; 16 } 17 18 int cmp(int *f, int x, int y, int w) {return f[x] == f[y] && f[x + w] == f[y + w];} 19 20 void SA() { 21 for (int i = 1; i <= n; i ++) rank[i] = s[i] - 'a' + 1, tp[i] = i; 22 m = 2, rsort(); 23 for (int w = 1, p = 1, i; p < n; w <<= 1, m = p) { 24 for (p = 0, i = n - w + 1; i <= n; i ++) tp[++ p] = i; 25 for (int i = 1; i <= n; i ++) if (sa[i] > w) tp[++ p] = sa[i] - w; 26 rsort(), swap(rank, tp), rank[sa[1]] = p = 1; 27 for (int i = 2; i <= n; i ++) rank[sa[i]] = cmp(tp, sa[i], sa[i - 1], w) ? p : ++ p; 28 } 29 int j, k = 0; 30 for (int i = 1; i <= n; height[rank[i ++]] = k) 31 for (k = k ? k - 1 : k, j = sa[rank[i] - 1]; s[i + k] == s[j + k]; k ++); 32 } 33 34 void st_init() { 35 for (int i = 1; i <= n; i ++) st[i][0] = height[i]; 36 for (int j = 1; (1 << j) <= n; j ++) 37 for (int i = 1; i + (1 << j) - 1 <= n; i ++) st[i][j] = min(st[i][j - 1], st[i + (1 << j - 1)][j - 1]); 38 } 39 40 int rmq(int l, int r) { 41 if (l > r) swap(l, r); 42 l ++; 43 int k = 0; 44 while (1 << k + 1 <= r - l + 1) k ++; 45 return min(st[l][k], st[r - (1 << k) + 1][k]); 46 } 47 48 void work() { 49 ans = 0; 50 for (int l = 1; l <= n; l ++) 51 for (int i = 1; i + l <= n; i += l) { 52 int k, r; 53 k = rmq(rank[i], rank[i + l]); 54 r = k % l; 55 if (r) k = max(k, rmq(rank[i - l + r], rank[i + r])); 56 ans = max(ans, k / l + 1); 57 } 58 printf("%d\n", max(ans, 1)); 59 } 60 61 int main() { 62 scanf("%d", &T); 63 while (T --) { 64 scanf("%d\n", &n); 65 scanf("%s", s + 1); 66 SA(); 67 st_init(); 68 work(); 69 } 70 return 0; 71 }