标签:
题意:
给出一列数据,问你其中重复的最长连续子串的长度
但是有要求:
1. 长度至少为 5 .
2. 两串可以不相等,但两串每个对应位置的数字相减差值固定 (即相同变化)
分析:
因为子串变化相同,故可先把原数组前后相减, 则求出差值数组的最长重复子串的长度再 +1 就是答案.
最长重复子串的长度:
使用后缀数组.
先将问题变为判定是否存在长度为 x 的重复子串,再用二分寻找答案.
用 height数组 将长度大于 x 的划为同区,则每个区里的每个后缀的公共前缀至少为 x
再找每个区的后缀的 sa 的最大值和最小值,若最大值和最小值之差不小于x,那两个后缀的公共前缀则不重叠,即有解
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int MAXN = 20010; 6 struct SuffixArray 7 { 8 int wa[MAXN], wb[MAXN], wsf[MAXN], wv[MAXN]; 9 10 int Cmp(int r[], int a, int b, int k) 11 { 12 return r[a] == r[b] && r[a+k] == r[b+k]; 13 } 14 void GetSa(int r[], int sa[], int n, int m) 15 { 16 int i, j, p, *x = wa, *y = wb, *t; 17 for (i = 0; i < m; i++) wsf[i] = 0; 18 for (i = 0; i < n; i++) wsf[x[i]=r[i]]++; 19 for (i = 1; i < m; i++) wsf[i] += wsf[i-1]; 20 for (i = n-1; i >= 0; i--) sa[--wsf[x[i]]] = i; 21 for (p = j = 1; p < n; j *= 2, m = p) { 22 for (p = 0, i = n - j; i < n; i++) y[p++] = i; 23 for (i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j; 24 for (i = 0; i < n; i++) wv[i] = x[y[i]]; 25 for (i = 0; i < m; i++) wsf[i] = 0; 26 for (i = 0; i < n; i++) wsf[wv[i]]++; 27 for (i = 1; i < m; i++) wsf[i] += wsf[i-1]; 28 for (i = n-1; i >= 0; i--) sa[--wsf[wv[i]]] = y[i]; 29 swap(x, y); 30 x[sa[0]] = 0; 31 for (p = i = 1; i < n; i++) 32 x[sa[i]] = Cmp(y, sa[i-1], sa[i], j) ? p - 1 : p++; 33 } 34 } 35 void GetHeight(int r[], int sa[], int rnk[], int height[], int n) 36 { 37 int i, j, k = 0; 38 for (i = 1; i <= n; i++) 39 rnk[sa[i]] = i; 40 for (i = 0; i < n; i++) 41 { 42 if (k) k--; 43 j = sa[rnk[i]-1]; 44 while (r[i+k] == r[j+k]) k++; 45 height[rnk[i]] = k; 46 } 47 } 48 }suffixArray; 49 int r[MAXN], sa[MAXN], rnk[MAXN], height[MAXN]; 50 int s[MAXN]; 51 int n; 52 53 bool Query(int x) 54 { 55 int Min, Max; 56 Min = Max = sa[1]; 57 for(int i = 2; i < n; i++) 58 { 59 if(height[i] >= x) 60 { 61 Min = min(Min, sa[i]); 62 Max = max(Max, sa[i]); 63 if(Max - Min >= x) return 1; 64 } 65 else Min = Max = sa[i]; 66 } 67 return 0; 68 } 69 int solve(int l,int r) 70 { 71 int mid,pos; 72 while(l<=r) 73 { 74 int mid=(l+r)>>1; 75 if(Query(mid)) pos=mid,l=mid+1; 76 else r=mid-1; 77 } 78 return pos; 79 } 80 int main() 81 { 82 while(~scanf("%d",&n) && n) 83 { 84 for (int i = 0; i < n; i++) scanf("%d",&s[i]); 85 n--; 86 for (int i = 0; i < n; i++) 87 r[i] = s[i+1] - s[i] + 100; 88 r[n] = 0; 89 suffixArray.GetSa(r,sa,n+1,200); 90 suffixArray.GetHeight(r,sa,rnk,height,n); 91 int l = 0, r = n; 92 int ans = solve(l, r) + 1; 93 printf("%d\n", ans < 5 ? 0 : ans); 94 } 95 }
POJ 1743 - Musical Theme 最长不重叠重复子串
标签:
原文地址:http://www.cnblogs.com/nicetomeetu/p/5763236.html