题目意思是求不重叠的最长相同变化的子串,输出该长度
比如1 2 3 4 5 6 7 8 9 10,最长长度为5,因为子串1 2 3 4 5 和 6 7 8 9 10变化都一样的
思路:既然要求变化一样,那么可以让原数组前后相减,然后利用后缀数组height的性质求子串最长公共前缀即可
height性质:1.height[i]表示排名为i和i-1的子串的最长公共前缀
PS:预处理数组时要留意,把n个数删去第一个 当作n-1个数来求重复子串 (间隔至少为1)然后最长重复子串长度+1就是所求答案
当然小于5时输出0
#include<iostream> #include<cstdio> #include<cstdlib> #include<string.h> #define clear(x) memset(x,0,sizeof(x)) using namespace std; const int MAXN=400000+100; int count[MAXN]; void radix(int *str,int *a,int *b,int n,int m) { clear (count); for(int i=0;i<n;++i)++count[str[a[i]]]; for(int i=1;i<=m;++i)count[i]+=count[i-1]; for(int i=n-1;i>=0;--i)b[--count[str[a[i]]]]=a[i]; } int rank[MAXN],a[MAXN],b[MAXN]; void sorted_suffix_array(int *str,int *sa,int n,int m) { clear (rank);clear(a);clear(b); for(int i=0;i<n;++i)rank[i]=i; radix(str,rank,sa,n,m); rank[sa[0]]=0; for(int i=1;i<n;++i)rank[sa[i]]=rank[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]); for(int i=0;(1<<i) <n;++i) { for(int j=0;j<n;++j) { a[j]=rank[j]+1; b[j]=j+(1<<i)>=n? 0:rank[j+(1<<i)]+1; sa[j]=j; } radix(b,sa,rank,n,n); radix(a,rank,sa,n,n); rank[sa[0]]=0; for(int j=1;j<n;++j) { rank[sa[j]]=rank[sa[j-1]]+(a[sa[j-1]]!=a[sa[j]]||b[sa[j-1]]!=b[sa[j]]); } } } int Rank[MAXN]; void calc_height(int *str,int *sa,int *h,int n) { clear(Rank); int k=0; h[0]=0; for(int i=0;i<n;++i)Rank[sa[i]]=i; for(int i=0;i<n;++i) { k= k==0?0:k-1; if(Rank[i]!=0) while(str[i+k]==str[sa[Rank[i]-1]+k])++k; h[Rank[i]]=k; } } int s[MAXN],sa[MAXN],h[MAXN],duprank[MAXN]; string duplicate_substr(string str,bool is_joint) { string rev; clear (s);clear(sa);clear(h);clear(duprank); int n=str.length(); copy(str.begin(),str.end(),s); for(int i=0;i<n-1;i++) s[i]=s[i+1]-s[i]+100; n--; sorted_suffix_array(s,sa,n,500); calc_height(s,sa,h,n); int ans1=0,pos1=0; for(int i=0;i<n;i++) duprank[sa[i]]=i; for(int i=0;i<n;i++) { if(h[duprank[i]]>ans1){ans1=h[duprank[i]];pos1=i;} } if(is_joint)return str.substr(pos1,ans1); int low=0,high=n-1; int ans2=0,pos21=0,pos22=0; while(low<=high) { int mid=(low+high)/2; bool ok=false; for(int i=0;i<n;) { int j=i+1,minPos=sa[i],maxPos=sa[i]; while(j<n&&h[j]>=mid) { minPos=min(minPos,sa[j]); maxPos=max(maxPos,sa[j]); j++; } if((maxPos-minPos)>mid) { ok=true; if(mid>ans2) { ans2=mid; pos21=minPos; pos22=maxPos; } break; } i=j; } if(ok){low=mid+1;} else{high=mid-1;} } if(!is_joint)return str.substr(pos21,ans2); } int num[MAXN]; int main() {freopen("t.txt","r",stdin); int n; while(scanf("%d",&n)) { string a; if(n==0)return 0; for(int i=0;i<n;i++) { scanf("%d",&num[i]); } for(int i=0;i<n;i++) { char cc[2]; cc[0]=num[i];cc[1]=0; a.append(cc); } int ans=duplicate_substr(a,false).length()+1; if(ans>=5)printf("%d\n",ans); else printf("0\n"); } return 0; }
楼教主的题目 厉害