这道题主要涉及后缀数组求最长不重叠公共字串,主要方法是二分答案k,把height数组分组组内后缀之间的height值要大于k,小于k的组就不考虑了。组内起始位置的差值也要大于k,这样才能保证不重叠。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=25000;
int c[maxn],t1[maxn],t2[maxn],sa[maxn],height[maxn],n,ans,rank[maxn];
int s[maxn];
void build_sa(int m)
{
int *x=t1,*y=t2;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[i]=s[i]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;i++) y[p++]=i;
for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[y[i]]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1,x[sa[0]]=0;
for(int i=1;i<n;i++)
x[sa[i]]= y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k] ? p-1 : p++;
if(p>=n) break;
m=p;
}
}
void get_height()
{
int j,k=0;
for(int i=1;i<=n;i++) rank[sa[i]]=i;
for(int i=1;i<n;i++)
{
if(k) k--;
j=sa[rank[i]-1];
while(s[j+k]==s[i+k]) k++;
height[rank[i]]=k;
}
}
bool check(int k)
{
int i,maxn,minn;
maxn = minn = sa[1];
for(int i=1;i<n;i++)
{
if(height[i]>=k&&i<n)
{
minn=min(minn,sa[i]);
maxn=max(maxn,sa[i]);
continue;
}
if(maxn-minn>=k) return true;
maxn=minn=sa[i];
}
return false;
}
int main()
{
while(scanf("%d",&n))
{
if(n==0) return 0;
for(int i=0;i<n;i++)
{
scanf("%d",&s[i]);
}
for(int i=0;i<n-1;i++)
{
s[i] = s[i+1]-s[i]+100;
}
build_sa(205);
get_height();
int l=1,r=n;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))
{
ans = mid;
l=mid+1;
}
else r=mid-1;
}
ans++;
printf("%d\n",ans<5?0:ans);
}
return 0;
}