/*
POJ1743 后缀数组
求字符串中至少重复1次或者且不重叠的最长长度
这里重复指的是两个字符串对应位置相减的差相等。

读入字符串后,前一位减后一位,生成一个新的字符串,转化为求不重合最长重复子川问题
(对应位置相减的差相同,意味着两个字符串增长的趋势相同,所以
一上来相减相当于把趋势给提炼出来)太菜给跪
Author: lcy
Time: 2017-10-6
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;
#define ll long long
#define fr(i,a,b) for(int i=a;i<=b;i++)
#define frr(i,a,b) for(int i=a;i>=b;i--)
#define ms(a,b) memset(a,b,sizeof(a))
#define scfd(a) scanf("%d",a)
#define scflf(a) scanf("%lf",a)
#define scfs(a) scanf("%s",a)
#define ptfd(a) printf("%d\n",a)
#define ptfs(a) printf("%s\n",a)
#define showd(a,b) printf(a"=%d\n",b)
#define showlf(a,b) printf(a"=%lf\n",b)
#define shows(a,b) printf(a"=%s\n",b)
#define mmcp(a,b) memcpy(a,b,sizeof(b))
#define pb(a) push_back(a)

#define L 0
#define S 1
const int MAXN=21005;
inline bool same(int *s,int *tp,int l,int a,int b){
    while(a<=l&&b<=l){
        if(s[a++]!=s[b++])
            return false;
        if(tp[a]==S&&tp[a-1]==L)
            break;
        if(tp[b]==S&&tp[b-1]==L)
            break;
    }
    return s[a]==s[b];
}
//s数组字符编码从1开始,0等价于'#'
int *sais(int *s,int l){
    //s数组第l位为0(#)
    s[l]=0;
    int SIGMA=*max_element(s,s+l+1)+13;
    int *cnt=new int[SIGMA];
    int *lp=new int[SIGMA];
    int *sp=new int[SIGMA];
    int *sa=new int[l+13];
    int *s1=new int[l+13];
    int *tp=new int[l+13];
    int *name=new int[l+13];
    int *pos=new int[l+13];
    tp[l]=S;//末尾最小
    //标记LS
    frr(i,l-1,0)
        if(s[i]>s[i+1])tp[i]=L;
        else if(s[i]<s[i+1])tp[i]=S;
        else tp[i]=tp[i+1];
    //求LSM数组
    fill(cnt,cnt+SIGMA,0);
    fr(i,0,l)cnt[s[i]]++;
    fr(i,1,SIGMA-1)cnt[i]+=cnt[i-1];//字符数量的前缀和
    lp[0]=0;
    fr(i,1,SIGMA-1)lp[i]=cnt[i-1];//求每个字符桶L型的起始位置
    fr(i,0,SIGMA-1)sp[i]=cnt[i]-1;//求每个字符桶S型的起始位置
    fill(sa,sa+l+1,-1);//注意在结尾添加了#,长度为l+1
    fr(i,1,l)if(tp[i]==S&&tp[i-1]==L)sa[sp[s[i]]--]=i;//任意顺序先放*型字符
    fr(i,0,l)if(sa[i]>0&&tp[sa[i]-1]==L)sa[lp[s[sa[i]-1]]++]=sa[i]-1;//诱导L型后缀
    fr(i,0,SIGMA-1)sp[i]=cnt[i]-1;//还原S型起始位置
    frr(i,l,0)if(sa[i]>0&&tp[sa[i]-1]==S)sa[sp[s[sa[i]-1]]--]=sa[i]-1;//诱导S型后缀
    fill(name,name+l+1,-1);
    int cur=0,last=-1,ed=0;
    bool is_same=false;
    fr(i,0,l)
        if(sa[i]>0&&tp[sa[i]]==S&&tp[sa[i]-1]==L){
            if(last!=-1){
                if(!same(s,tp,l,sa[i],last))cur++;
                else is_same=true;
            }
            name[sa[i]]=cur;
            last=sa[i];
        }
    fr(i,0,l)if(name[i]>=0){pos[ed]=i,s1[ed]=name[i];ed++;}//pos[i]表示s1[i]在s中对应的下标
    lp[0]=0;
    fr(i,1,SIGMA-1)lp[i]=cnt[i-1];//求每个字符桶L型的起始位置
    fr(i,0,SIGMA-1)sp[i]=cnt[i]-1;//求每个字符桶S型的起始位置
    fill(sa,sa+l+1,-1);//注意在结尾添加了#,长度为l+1
    //求s1的后缀数组sa1
    int *sa1;
    if(is_same)//如果s1字符串中有相同元素,那么需要递归求sa1
        sa1=sais(s1,ed-1);//s1[ed]一定为0(#排最小),所以s1递归下去长度只有ed-1(最后1位不算)
    else{//如果s1字符串中每个元素不同,直接桶排序生成sa1即可
        sa1=new int[ed+3];
        fill(sa1,sa1+ed+3,-1);
        fr(i,0,ed-1)sa1[s1[i]]=i;
    }
    //sa1诱导sa
    frr(i,ed-1,0)sa[sp[s[pos[sa1[i]]]]--]=pos[sa1[i]];//逆向添加*型,因为桶中的S的下标是倒着移动的
    fr(i,0,l)if(sa[i]>0&&tp[sa[i]-1]==L)sa[lp[s[sa[i]-1]]++]=sa[i]-1;//诱导L型后缀
    fr(i,0,SIGMA-1)sp[i]=cnt[i]-1;//还原S型起始位置
    frr(i,l,0)if(sa[i]>0&&tp[sa[i]-1]==S)sa[sp[s[sa[i]-1]]--]=sa[i]-1;//诱导S型后缀
    delete[] cnt;
    delete[] lp;
    delete[] sp;
    delete[] s1;
    delete[] sa1;
    delete[] pos;
    delete[] name;
    delete[] tp;
    return sa;
}

void getheight(int *s,int *sa,int *rk,int *hei,int l){
    //hei[i]:suf[sa[i]...l]与suf[sa[i-1]...l]的最长前缀,即排名第i的与排名第i+1的最长前缀
    //h[i] = hei[rank[i]] 即suf[i...l]与suf[p...l]的最长前缀,其中suf[p...l]排在suf[i...1]之前1位
    //有 h[i] >= h[i-1] - 1
    fr(i,0,l)rk[sa[i]]=i;
    int k=0;
    fr(i,0,l)
        if(rk[i]>0){//没写这个条件,RE很久
            if(k)k--;
            while(s[i+k]==s[sa[rk[i]-1]+k])k++;//sa[rk[i]-1]代表后缀数组中排在suf[i...l]前1位的后缀起始点
            hei[rk[i]]=k;
    }
}
int n;
int s[MAXN],rk[MAXN],hei[MAXN];
bool ok(int x,int *sa){
    int now=1,st=-1,mx=-1,mn=MAXN+100;
    while(now<=n){
        if(hei[now]>=x){
            if(st==-1)st=now;
            mx=max(mx,sa[now]);
            mx=max(mx,sa[now-1]);
            mn=min(mn,sa[now-1]);
            mn=min(mn,sa[now]);
        }
        else{
            if(st>=0){
                //printf("x=%d,mx=%d,mn=%d",x,mx,mn);
                if(mx-mn>=x)return true;
                mx=-1,mn=MAXN+100,st=-1;
            }
        }
        now++;
    }
    if(mx-mn>=x)return true;
    return false;
}
int ss[MAXN];
int main(){

    while(scfd(&n)&&n){
        fr(i,0,n-1)scfd(ss+i);
        if(n==1){
            printf("0\n");continue;
        }
        fr(i,1,n-1)s[i-1]=ss[i]-ss[i-1]+100;
        n--;
        int l=0,r=n+1;
        int *sa=sais(s,n);
        getheight(s,sa,rk,hei,n);
        // printf("S:    |");fr(i,0,n)printf("%4d",s[i]);printf("\n");
        // printf("SA:   |");fr(i,0,n)printf("%4d",sa[i]);printf("\n");
        // printf("HEI:  |");fr(i,0,n)printf("%4d",hei[i]);printf("\n");
        while(l<r-1){
            int mid=(l+r)/2;
            if(ok(mid,sa))
                l=mid;
            else 
                r=mid;
        }
        //printf("l=%d\n",l);
        if(l>=4)printf("%d\n",l+1);
        else printf("0\n");
        delete[] sa;
    }
    return 0;
}
 posted on 2017-10-06 17:06  cylcy  阅读(139)  评论(0)    收藏  举报