POJ 1743 Musical Theme
题目
给n个数组成的串,求是否有多个“相似”且不重叠的子串的长度大于等于5,两个子串相似当且仅当长度相等且每一位的数字差都相等。
Input
The input contains several test cases. The first line of each test case contains the integer N. The following n integers represent the sequence of notes.
The last test case is followed by one zero.
Output
The last test case is followed by one zero.
For each test case, the output file should contain a single line
with a single integer that represents the length of the longest theme.
If there are no themes, output 0.
Sample Input30
25 27 30 34 39 45 52 60 69 79 69 60 52 45 39 34 30 26 22 18
82 78 74 70 66 67 64 60 65 80
0
Sample Output
5
不考虑相似的定义,先考虑相同
即不可重叠最长重复子串
先求出h数组,二分答案k
然后分成若干组,每组的h都大于k,如果该区间内Max_SA-Min_SA>=k
就说明存在长为k的不可重叠最长重复子串
本题从相同变成"相似"
其实把原数组差分,这样得出的新串如果有两个长度为n的子串相同,那么它们对应在原串的长度n+1的子串也就相似
也就转化为求差分数组不可"相交"最长重复子串
即两个子串至少要隔一个数
因为如果两个子串靠在一起这样反应到原串那两个子串各自的首尾是重合的
记得h[i]在最后加一个0,不然最后一组不会统计
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int s[200001],c[200001],SA[200001],h[200001],n,m,x[200001],y[200001],rank[200001],Max,Min,ans; 8 void radix_sort() 9 {int i; 10 for (i=0;i<m;i++) 11 c[i]=0; 12 for (i=0;i<n;i++) 13 c[x[y[i]]]++; 14 for (i=1;i<m;i++) 15 c[i]+=c[i-1]; 16 for (i=n-1;i>=0;i--) 17 SA[--c[x[y[i]]]]=y[i]; 18 } 19 void build_SA() 20 {int i,j,k,p; 21 for (i=0;i<n;i++) 22 x[i]=s[i],y[i]=i; 23 m=1000; 24 radix_sort(); 25 for (k=1;k<=n;k<<=1) 26 { 27 p=0; 28 for (i=n-k;i<n;i++) 29 y[p++]=i; 30 for (i=0;i<n;i++) 31 if (SA[i]>=k) y[p++]=SA[i]-k; 32 radix_sort(); 33 p=1;swap(x,y); 34 x[SA[0]]=0; 35 for (i=1;i<n;i++) 36 x[SA[i]]=((y[SA[i]]==y[SA[i-1]])&&((SA[i]+k<n?y[SA[i]+k]:-1)==(SA[i-1]+k<n?y[SA[i-1]+k]:-1)))?p-1:p++; 37 if (p>=n) break; 38 m=p; 39 } 40 for (i=0;i<n;i++) 41 rank[SA[i]]=i; 42 int L=0; 43 for (i=0;i<n;i++) 44 if (rank[i]>0) 45 { 46 if (L>0) L--; 47 j=SA[rank[i]-1]; 48 while (i+L<n&&j+L<n&&(s[j+L]==s[i+L])) L++; 49 h[rank[i]]=L; 50 } 51 } 52 bool check(int mid) 53 {int i; 54 Max=-1e9;Min=1e9; 55 h[n]=0; 56 for (i=1;i<=n;i++) 57 { 58 if (h[i]>=mid) 59 { 60 Max=max(max(SA[i],SA[i-1]),Max); 61 Min=min(min(SA[i],SA[i-1]),Min); 62 } 63 else 64 { 65 if (Max-Min>mid) 66 return 1; 67 Max=-1e9;Min=1e9; 68 } 69 } 70 return 0; 71 } 72 int main() 73 {int i,now,last; 74 while (cin>>n&&n) 75 { 76 scanf("%d",&last); 77 if (n==1) 78 { 79 cout<<0<<endl; 80 continue; 81 } 82 for (i=0;i<n-1;i++) 83 { 84 scanf("%d",&now); 85 s[i]=now-last+88; 86 last=now; 87 } 88 n--; 89 s[n]=0; 90 build_SA(); 91 int l=0,r=n/2; 92 ans=0; 93 while (l<=r) 94 { 95 int mid=(l+r+1)/2; 96 if (check(mid)) ans=mid,l=mid+1; 97 else r=mid-1; 98 } 99 if (ans<4) printf("0\n"); 100 else 101 printf("%d\n",ans+1); 102 } 103 }