标签:
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 22953 | Accepted: 7839 |
Description
Input
Output
Sample Input
30 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
Hint
Source
【思路】
不可重叠最长重复子串。
1) 据题意处理字符串
2) 后缀数组。二分长度k,问题成为了判定是否存在两个及以上长度不小于k且互不重叠的子串。根据height数组划分后缀,满足两个条件:一是一组内height值不小于k(保证组内任两个长度不小于k),二是组内后缀sa值的最大最小值之差大于等于k(保证两个子串不重叠)。
需要注意n==1时需要特判。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 5 using namespace std; 6 7 const int maxn = 40000+10; 8 9 int s[maxn]; 10 int sa[maxn],t[maxn],t2[maxn],c[maxn],n; 11 //字符串s长度为n 12 //build_sa中参数m表示字符最大为m 13 void build_sa(int m) { 14 int i,*x=t,*y=t2; 15 for(int i=0;i<m;i++) c[i]=0; 16 for(int i=0;i<n;i++) c[x[i]=s[i]]++; 17 for(int i=1;i<m;i++) c[i]+=c[i-1]; 18 for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i; 19 20 for(int k=1;k<=n;k<<=1) { 21 int p=0; 22 for(int i=n-k;i<n;i++) y[p++]=i; 23 for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; 24 25 for(int i=0;i<m;i++) c[i]=0; 26 for(int i=0;i<n;i++) c[x[y[i]]]++; 27 for(int i=0;i<m;i++) c[i]+=c[i-1]; 28 for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; 29 30 swap(x,y); 31 p=1; x[sa[0]]=0; 32 for(int i=1;i<n;i++) 33 x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; 34 if(p>=n) break; 35 m=p; 36 } 37 } 38 //构造height数组表示lcp(suffix(sa[i-1]),suffix(sa[i])) 39 int rank[maxn],height[maxn]; 40 void getHeight() { 41 int i,j,k=0; 42 for(int i=0;i<n;i++) rank[sa[i]]=i; 43 for(int i=0;i<n;i++) { 44 if(k) k--; 45 int j=sa[rank[i]-1]; 46 while(s[i+k]==s[j+k]) k++; 47 height[rank[i]]=k; 48 } 49 } 50 51 bool can(int k) { 52 int min=sa[0],max=sa[0]; 53 for(int i=1;i<n;i++) { 54 if(height[i]<k) min=max=sa[i]; //新组的开始 55 if(sa[i]<min) min=sa[i]; 56 if(sa[i]>max) max=sa[i]; 57 if(max-min>=k) return true; 58 } 59 return false; 60 } 61 62 int main() { 63 while(scanf("%d",&n)==1 && n) 64 { 65 for(int i=0;i<n;i++)scanf("%d",&s[i]); 66 for(int i=n-1;i>0;i--)s[i]=s[i]-s[i-1]+100; 67 n--;//减少一个长度 68 for(int i=0;i<n;i++)s[i]=s[i+1]; 69 s[n]=0; //n==1时防止 RE 70 build_sa(200); 71 getHeight(); 72 int L=0,R=n/2; 73 while(L<R) { 74 int M=L+(R-L+1)/2; 75 if(can(M)) L=M; else R=M-1; 76 } 77 L++; //对应有L+1个音符 78 if(L<=4) printf("0\n"); 79 else printf("%d\n",L); 80 } 81 return 0; 82 }
标签:
原文地址:http://www.cnblogs.com/lidaxin/p/5001802.html