POJ 3261 (后缀数组 二分) Milk Patterns
这道题和UVa 12206一样,求至少重复出现k次的最长字串。
首先还是二分最长字串的长度len,然后以len为边界对height数组分段,如果有一段包含超过k个后缀则符合要求。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 20000 + 10; 7 const int maxm = 1000000 + 10; 8 9 int s[maxn]; 10 int sa[maxn], height[maxn], rank[maxn]; 11 int t[maxn], t2[maxn], c[maxm]; 12 int n, k; 13 14 void build_sa(int m) 15 { 16 int i, *x = t, *y = t2; 17 for(i = 0; i < m; i++) c[i] = 0; 18 for(i = 0; i < n; i++) c[x[i] = s[i]]++; 19 for(i = 1; i < m; i++) c[i] += c[i - 1]; 20 for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i; 21 for(int k = 1; k <= n; k <<= 1) 22 { 23 int p = 0; 24 for(i = n - k; i < n; i++) y[p++] = i; 25 for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k; 26 for(i = 0; i < m; i++) c[i] = 0; 27 for(i = 0; i < n; i++) c[x[y[i]]]++; 28 for(i = 1; i < m; i++) c[i] += c[i - 1]; 29 for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; 30 swap(x, y); 31 p = 1; x[sa[0]] = 0; 32 for(i = 1; i < n; i++) 33 x[sa[i]] = y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? p - 1 : p++; 34 if(p >= n) break; 35 m = p; 36 } 37 } 38 39 void build_height() 40 { 41 int i, j, k = 0; 42 for(i = 0; i < n; i++) rank[sa[i]] = i; 43 for(i = 0; i < n; i++) 44 { 45 if(k) k--; 46 j = sa[rank[i] - 1]; 47 while(s[i + k] == s[j + k]) k++; 48 height[rank[i]] = k; 49 } 50 } 51 52 bool ok(int len) 53 { 54 int cnt = 0; 55 for(int i = 0; i < n; i++) 56 { 57 if(i == 0 || height[i] < len) cnt = 0; 58 if(++cnt >= k) return true; 59 } 60 return false; 61 } 62 63 int main() 64 { 65 //freopen("in.txt", "r", stdin); 66 67 scanf("%d%d", &n, &k); 68 for(int i = 0; i < n; i++) 69 { 70 scanf("%d", &s[i]); 71 s[i]++; 72 } 73 s[n] = 0; 74 build_sa(1000002); 75 build_height(); 76 77 int L = 1, R = n; 78 while(L < R) 79 { 80 int M = (L + R + 1) / 2; 81 if(ok(M)) L = M; 82 else R = M - 1; 83 } 84 85 printf("%d\n", L); 86 87 return 0; 88 }