[后缀数组] POJ 1743 Musical Theme

题目大意

给定一串数字,求两个最长的变化幅度相同的不重叠的子串长度。
因为要求变化幅度相同,所以首先进行一次差分,然后实际上是求不重叠最长重复子串。
用后缀数组求出SA[] 和Height[] ,因为不能重叠,我们去二分不重叠重复子串的长度 (k),对于每个 (k),把Height数组中相邻的大于等于 (k) 的分为一组,对于每组求出SA的最大值和最小值,表示两个前缀相同的后缀开始位置的间距,这道题因为做了差分,所以要满足大于 (k) ,而不是大于等于。
时间复杂度 (O(Nlog 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
",Ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/AEMShana/p/13266521.html