1743:Musical Theme
题意
给一个序列,找两个子串,满足:
- 长度至少为5
- 相同或者转置后相同(转置:序列每个数字加减相同的数字后变成的序列)
- 两个子串不能有公共部分。
思路
对于第二个条件,就是差分后相同(奇妙的转化)。那么就是求一个串的出现2次,不可重叠的最长的子串。
后缀数组,二分一个长度x,判断是否满足。
判断:可以height划分成多个子段(每个子段是连续的一段序列且所有的height的值都要>x),那么对于每个子段的中对应的后缀任意两个都满足公共子串>x,所以在当前子段中找到最左边的点,和最右边的点,要求判断是否重叠(即r-l>x)。
代码
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 6 const int N = 20010; 7 8 int t1[N],t2[N],c[N],height[N],rnk[N],sa[N],s[N],a[N]; 9 int n,m; 10 11 void get_sa() { 12 m = 180; 13 int *x = t1,*y = t2,p,i; 14 for (i=0; i<m; ++i) c[i] = 0; 15 for (i=0; i<n; ++i) x[i]=s[i],c[x[i]]++; 16 for (i=1; i<m; ++i) c[i] += c[i-1]; 17 for (i=n-1; i>=0; --i) sa[--c[x[i]]] = i; 18 for (int k=1; k<=n; k<<=1) { 19 p = 0; 20 for (i=n-k; i<n; ++i) y[p++] = i; 21 for (i=0; i<n; ++i) if (sa[i]>=k) y[p++] = sa[i]-k; 22 for (i=0; i<m; ++i) c[i] = 0; 23 for (i=0; i<n; ++i) c[x[y[i]]]++; 24 for (i=0; i<m; ++i) c[i] += c[i-1]; 25 for (i=n-1; i>=0; --i) sa[--c[x[y[i]]]] = y[i]; 26 swap(x,y); 27 p = 1; 28 x[sa[0]] = 0; 29 for (i=1; i<n; ++i) 30 x[sa[i]] = (y[sa[i-1]]==y[sa[i]] && sa[i-1]+k<n && sa[i]+k<n && y[sa[i-1]+k]==y[sa[i]+k]) ? p-1 : p++; 31 if (p >= n) break; 32 m = p; 33 } 34 } 35 void get_height() { 36 for (int i=0; i<n; ++i) rnk[sa[i]] = i; 37 int k = 0; 38 height[0] = 0; 39 for (int i=0; i<n; ++i) { 40 if (!rnk[i]) continue; 41 if (k) k--; 42 int j = sa[rnk[i]-1]; 43 while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++; 44 height[rnk[i]] = k; 45 } 46 } 47 bool check(int x) { 48 int l = sa[0],r = sa[0]; 49 for (int i=1; i<n; ++i) { 50 if (height[i] < x) l = r = sa[i]; 51 else { 52 l = min(l,sa[i]);r = max(r,sa[i]); 53 if (r - l >= x) return true; // r-l 不是r-l+1,模拟一下 54 } 55 } 56 return false; 57 } 58 void solve() { 59 int L = 1,R = n/2,ans = -1; 60 while (L <= R) { 61 int mid = (L + R) / 2; 62 if (check(mid)) ans = mid,L = mid + 1; 63 else R = mid - 1; 64 } 65 if (ans < 4) puts("0"); 66 else printf("%d ",ans+1); 67 } 68 int main() { 69 while (~scanf("%d",&n) && n){ 70 for (int i=0; i<n; ++i) scanf("%d",&a[i]); 71 for (int i=1; i<n; ++i) s[i] = a[i] - a[i-1] + 88; 72 get_sa(); 73 get_height(); 74 solve(); 75 } 76 return 0; 77 }