[字尾陣列] POJ 1743 Musical Theme
阿新 • • 發佈:2020-07-08
題目大意
給定一串數字,求兩個最長的變化幅度相同的不重疊的子串長度。
因為要求變化幅度相同,所以首先進行一次差分,然後實際上是求不重疊最長重複子串。
用字尾陣列求出SA[] 和Height[] ,因為不能重疊,我們去二分不重疊重複子串的長度 \(k\),對於每個 \(k\),把Height陣列中相鄰的大於等於 \(k\) 的分為一組,對於每組求出SA的最大值和最小值,表示兩個字首相同的字尾開始位置的間距,這道題因為做了差分,所以要滿足大於 \(k\) ,而不是大於等於。
時間複雜度 \(O(N\log N)\)。
Code
#include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cstdio> #include <vector> using namespace std; #define RG register int #define LL long long template<typename elemType> inline void Read(elemType &T){ elemType X=0,w=0; char ch=0; while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); T=(w?-X:X); } const int maxn=20010; const int INF=1<<30; struct Suffix_Array{ int str[maxn]; int SA[maxn],Rank[maxn],B[maxn],x[maxn],y[maxn],Height[maxn]; int LenS,Base; Suffix_Array():Base(176){} void clear(){ memset(B,0,sizeof(B)); Base=176; } void Get_SA(){ clear(); int *X=x,*Y=y; for(RG i=1;i<=LenS;++i) ++B[X[i]=str[i]]; for(RG i=2;i<=Base;++i) B[i]+=B[i-1]; for(RG i=1;i<=LenS;++i) SA[B[X[i]]--]=i; for(RG k=1;k<=LenS;k<<=1){ RG Index=0; for(RG i=LenS-k+1;i<=LenS;++i) Y[++Index]=i; for(RG i=1;i<=LenS;++i) if(SA[i]>k) Y[++Index]=SA[i]-k; for(RG i=1;i<=Base;++i) B[i]=0; for(RG i=1;i<=LenS;++i) ++B[X[i]]; for(RG i=2;i<=Base;++i) B[i]+=B[i-1]; for(RG i=LenS;i>=1;--i) {SA[B[X[Y[i]]]--]=Y[i];Y[i]=0;} swap(X,Y); X[SA[1]]=1;Index=1; for(RG i=2;i<=LenS;++i) X[SA[i]]=(Y[SA[i-1]]==Y[SA[i]] && Y[SA[i-1]+k]==Y[SA[i]+k])?Index:++Index; if(Index==LenS) break; Base=Index; } return; } void Get_LCP(){ RG k=0; for(RG i=1;i<=LenS;++i) Rank[SA[i]]=i; for(RG i=1;i<=LenS;++i){ if(Rank[i]==1) continue; if(k) --k; RG j=SA[Rank[i]-1]; while(i+k<=LenS && j+k<=LenS && str[i+k]==str[j+k]) ++k; Height[Rank[i]]=k; } return; } }; Suffix_Array SA; int Data[maxn]; int N; bool Judge(int k){ int Max,Min; Max=Min=SA.SA[1]; for(int i=2;i<=N;++i){ if(SA.Height[i]>=k){ Min=min(Min,SA.SA[i]); Max=max(Max,SA.SA[i]); continue; } if(Max-Min>k) return true; Max=Min=SA.SA[i]; } if(SA.Height[N]>=k && Max-Min>k) return true; return false; } int Solve(){ int L=0,R=N,Res=0; while(L<=R){ int mid=(L+R)>>1; if(Judge(mid)){Res=mid;L=mid+1;} else R=mid-1; } return Res; } int main(){ while(~scanf("%d",&N)){ if(N==0) break; for(RG i=1;i<=N;++i) Read(Data[i]); for(RG i=1;i<N;++i) SA.str[i]=Data[i+1]-Data[i]+88; SA.str[N]=0; SA.LenS=--N; SA.Get_SA(); SA.Get_LCP(); int Ans=Solve()+1; if(Ans<5) Ans=0; printf("%d\n",Ans); } return 0; }