Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 15932 | Accepted: 5509 |
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
比如1 2 3 4 5 6 7 8 9 10,最长长度为1,因为子串1 2 3 4 5 和 6 7 8 9 10变化都一样的
思路:既然要求变化一样,那么可以让原数组前后相减,然后利用后缀数组height的性质求子串最长公共前缀即可
height性质:1.height[i]表示排名为i和i-1的子串的最长公共前缀
2.由于最相似的子串排名肯定是最接近的,所以height的大小肯定是这样的:大-》小,大-》小,大-》小......
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <queue> #include <algorithm> #include <map> #include <iomanip> #define INF 99999999 typedef long long LL; using namespace std; const int MAX=20000+10; int *rank,r[MAX],sa[MAX],height[MAX]; int wa[MAX],wb[MAX],wm[MAX]; bool cmp(int *r,int a,int b,int l){ return r[a] == r[b] && r[a+l] == r[b+l]; } void makesa(int *r,int *sa,int n,int m){ int *x=wa,*y=wb,*t; for(int i=0;i<m;++i)wm[i]=0; for(int i=0;i<n;++i)wm[x[i]=r[i]]++; for(int i=1;i<m;++i)wm[i]+=wm[i-1]; for(int i=n-1;i>=0;--i)sa[--wm[x[i]]]=i; for(int i=0,j=1,p=0;p<n;j=j*2,m=p){ for(p=0,i=n-j;i<n;++i)y[p++]=i; for(i=0;i<n;++i)if(sa[i]>=j)y[p++]=sa[i]-j; for(i=0;i<m;++i)wm[i]=0; for(i=0;i<n;++i)wm[x[y[i]]]++; for(i=1;i<m;++i)wm[i]+=wm[i-1]; for(i=n-1;i>=0;--i)sa[--wm[x[y[i]]]]=y[i]; for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;++i){ x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++; } } rank=x; } void calheight(int *r,int *sa,int n){ for(int i=0,j=0,k=0;i<n;height[rank[i++]]=k){ for(k?--k:0,j=sa[rank[i]-1];r[i+k] == r[j+k];++k); } } int main(){ int n; while(cin>>n,n){ for(int i=0;i<n;++i)cin>>r[i]; for(int i=0;i<n-1;++i)r[i]=r[i+1]-r[i]+100; r[--n]=0; makesa(r,sa,n+1,200); calheight(r,sa,n);//这里注意不要传递n+1过去,rank[n]-1=0-1=-1 int l=1,r=n+1,mid,L,R; bool flag=false; while(l<=r){ mid=l+r>>1; L=INF,R=-INF,flag=false; for(int i=1;i<=n;++i){ if(height[i]>=mid){ L=min(L,sa[i]); L=min(L,sa[i-1]); R=max(R,sa[i]); R=max(R,sa[i-1]); }else{ if(L+mid+1<=R)flag=true;//这里注意是L+mid+1,因为r[L+mid]=r[L+mid+1]-r[L+mid],从L开始原串中前面那个子串包括L+mid+1 L=INF,R=-INF; } } if(L+mid+1<=R)flag=true; if(flag)l=mid+1; else r=mid-1; } if(l>=5)cout<<l<<endl; else cout<<0<<endl; } return 0; }