前言:
jz大佬说初二不会后缀数组就退役吧,然后我看了看高二的自己竟然苟过了三年…哈哈哈哈哈哈
题目大意:
求一个最长重复不相交的字符串,长度必须大于5
思路:
因为原题比较长,也没有上面说的那么裸,所以我们先用每个数剪掉前面一个数,然后就转化成上面那样了,
然后用后缀数据求出来就好了。
具体后缀数组应用:
我们先分析一个判定性问题,如何判断两个字符串是相同且不重叠的。解决这个问题要用到里面的height数组。我们把排序后的后缀分成若干组,每个height值不小于一个下限。可以得到最长公共前缀长度不小于k的两个后缀一定在同一组。然后对于每个后缀数组只需要判断后缀sa的最大值和最小值是否不小于k,如果是,则说明存在两个后缀,其公共前缀长度不小于k且互不重叠,反之不存在。(这是一种对height每组讨论的方法,经常使用)。
程序:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<map>
#include<utility>
#include<vector>
#include<set>
#include<algorithm>
#define N 20010
using namespace std;
struct node{int now,next;}d[N];
int x[N],h[N],rank[N],height[N],val[N][2],c[N],sa[N],pos[N];
int n;
void prefix(){
memset(h,0,sizeof(h));
for (int i=1;i<=n;i++) {
if (rank[i]==1) h[i]=0;
else {
int now=0;
if (i>1&&h[i-1]>1) now=h[i-1]-1;
while (now+i<=n&&now+sa[rank[i]-1]<=n&&x[now+i]==x[now+sa[rank[i]-1]])
now++;
h[i]=now;
}
}
for (int i=1;i<=n;i++) height[rank[i]]=h[i];
}
void value(int u,int v,int i){
d[i].next=c[u];
c[u]=i;
d[i].now=v;
}
void Sort(int l,int r){
for (int k=1;k>=0;k--){
memset(c,0,sizeof(c));
for (int i=r;i>=l;i--) value(val[pos[i]][k],pos[i],i);
int t=0;
for (int i=0;i<=20000;i++)
for (int j=c[i];j;j=d[j].next) pos[++t]=d[j].now;
}
int t=0;
for (int i=1;i<=n;i++){
if (val[pos[i]][0]!=val[pos[i-1]][0]||val[pos[i]][1]!=val[pos[i-1]][1]) t++;
rank[pos[i]]=t;
}
}
void array(){
int t=1;
while (t/2<=n){
for (int i=1;i<=n;i++){
val[i][0]=rank[i];
val[i][1]=(((i+t/2<=n)?rank[i+t/2]:0));
pos[i]=i;
}
Sort(1,n);
t*=2;
}
for (int i=1;i<=n;i++) sa[rank[i]]=i;
}
bool cheak(int len){
int Min=n+1,Max=0;
for (int i=1;i<=n;i++)
if (height[i]<len){
if (Max-Min>=len) return 1;
Min=Max=sa[i];
} else {
Min=min(Min,sa[i]);
Max=max(Max,sa[i]);
}
if (Max-Min>=len) return 1;
return 0;
}
int search(int l,int r){
while (l<=r){
int mid=(l+r)/2;
if (cheak(mid)) l=mid+1;
else r=mid-1;
}
return r;
}
void solve(){
for (int i=1;i<=n-1;i++) rank[i]=x[i]=x[i+1]-x[i]+88;
n--;
array();
prefix();
int ans=search(0,n)+1;
ans=((ans<5)?0:ans);
printf("%d\n",ans);
}
int main(){
while (scanf("%d",&n),n>0){
for (int i=1;i<=n;i++) scanf("%d",&x[i]);
solve();
}
}