• [后缀数组] 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;
    }
    
  • 相关阅读:
    创建数据库命令(含自增id 创建时间 更新时间)
    jvm内存查看操作笔记
    dockerfile学习
    java 泛型
    IDE 改jvm内存大小 打印gc处理日志 jprofile内存分析工具使用和分析
    jvm内存(堆内存)了解
    vue 实现xmind 有空弄一下
    nmap接口扫描工具 有空了解下
    python 操作 redis
    Security 登录实现 这个博主的可以 亲测
  • 原文地址:https://www.cnblogs.com/AEMShana/p/13266521.html
Copyright © 2020-2023  润新知