传送门
代码:
二分答案。
然后对于预处理的heightheightheight数组分成几段。
保证每一段中都是连续的几个heightheightheight并且这些heightheightheight都不小于二分的值。
然后查询是否有一个段中两个长度的差满足条件就行了。
#include<iostream>
#include<cstdio>
#define ri register int
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=2e4+5,inf=0x3f3f3f3f;
int n,m,sa[N],sa2[N],rk[N],ht[N],a[N],num[N];
inline void Sort(){
static int cnt[N];
for(ri i=1;i<=m;++i)cnt[i]=0;
for(ri i=1;i<=n;++i)++cnt[rk[i]];
for(ri i=2;i<=m;++i)cnt[i]+=cnt[i-1];
for(ri i=n;i;--i)sa[cnt[rk[sa2[i]]]--]=sa2[i];
}
inline void getsa(){
for(ri i=1;i<=n;++i)rk[i]=a[i],sa2[i]=i;
m=176,Sort();
for(ri w=1,p=0;m!=n;w<<=1,p=0){
for(ri i=n-w+1;i<=n;++i)sa2[++p]=i;
for(ri i=1;i<=n;++i)if(sa[i]>w)sa2[++p]=sa[i]-w;
Sort(),swap(rk,sa2),rk[sa[1]]=p=1;
for(ri i=2;i<=n;++i)rk[sa[i]]=(sa2[sa[i]]==sa2[sa[i-1]]&&sa2[sa[i]+w]==sa2[sa[i-1]+w])?p:++p;
m=p;
}
for(ri i=1,k=0,j;i<=n;ht[rk[i++]]=k)for(k?--k:k,j=sa[rk[i]-1];a[i+k]==a[j+k];++k);
}
inline bool check(int mid){
for(ri i=1,mx=-inf,mn=inf;i<=n;++i){
if(ht[i]>=mid){
mx=max(mx,max(sa[i],sa[i-1])),mn=min(mn,min(sa[i],sa[i-1]));
if(mx-mn>mid)return 1;
}
else mx=-inf,mn=inf;
}
return 0;
}
int main(){
while(n=read(),n){
for(ri i=1;i<=n;++i)num[i]=read();
--n;
if(!n){puts("0");continue;}
for(ri i=1;i<=n;++i)a[i]=num[i+1]-num[i]+88;
getsa();
int l=4,r=n,ans=0;
while(l<=r){
int mid=l+r>>1;
if(check(mid))l=mid+1,ans=mid;
else r=mid-1;
}
printf("%d\n",ans?ans+1:0);
}
return 0;
}