• poj 1743 Musical Theme


    Musical Theme

     POJ - 1743 

    题目大意:

    给定一个数组,求最长重复子串,这两个子串不能重叠。

    /*
        后缀数组不用说了
        首先最长允许重复的子串就是max{height}
        不允许重复也就是限制了两字符串之间的距离,可以二分答案来做
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 22222
    #define INF (1<<30)
    using namespace std;
    int n,wa[maxn],wb[maxn],c[maxn],sa[maxn],rk[maxn],h[maxn],a[maxn],s[maxn];
    void SA(int *s,int n,int m){
        int *x=wa,*y=wb;
        for(int i=0;i<m;i++)c[i]=0;
        for(int i=0;i<n;i++)c[x[i]=s[i]]++;
        for(int i=1;i<m;i++)c[i]+=c[i-1];
        for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
        int k=1,p=0;
        while(k<=n){
            for(int i=n-k;i<n;i++)y[p++]=i;
            for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
            for(int i=0;i<m;i++)c[i]=0;
            for(int i=0;i<n;i++)c[x[y[i]]]++;
            for(int i=1;i<m;i++)c[i]+=c[i-1];
            for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
            swap(x,y);x[sa[0]]=0;p=1;
            for(int i=1;i<n;i++){
                if((y[sa[i-1]]==y[sa[i]])&&((y[sa[i-1]+k]==y[sa[i]+k]&&sa[i]+k<n&&sa[i-1]+k<n)||(sa[i]+k>=n&&sa[i-1]+k>=n)))x[sa[i]]=p-1;
                else x[sa[i]]=p++;
            }
            if(p>=n)break;
            m=p;p=0;k<<=1;
        }
        for(int i=1;i<n;i++)rk[sa[i]]=i;
        k=0;
        for(int i=0;i<n-1;h[rk[i++]]=k){
            if(k)k--;
            int j=sa[rk[i]-1];
            while(s[i+k]==s[j+k])k++;
        }
    }
    bool check(int mid){
        bool flag=0;
        int mn=INF,mx=-INF;
        for(int i=2;i<=n;i++){
            if(h[i]>=mid){
                mn=min(mn,min(sa[i],sa[i-1]));
                mx=max(mx,max(sa[i],sa[i-1]));
                if(mx-mn>mid)return 1;
            }
            else{mx=-INF;mn=INF;}
        }
        return 0;
    }
    int main(){
        while(1){
            scanf("%d",&n);
            if(n==0)return 0;
            memset(s,0,sizeof(s));
            memset(sa,0,sizeof(sa));
            memset(rk,0,sizeof(rk));
            memset(h,0,sizeof(h));
            for(int i=0;i<n;i++)scanf("%d",&a[i]);
            n--;
            for(int i=0;i<n;i++)s[i]=a[i+1]-a[i]+88;
            s[n]=0;
            SA(s,n+1,176);
            int l=0,r=n>>1;
            while(l<r){
                int mid=(l+r+1)>>1;
                if(check(mid))l=mid;
                else r=mid-1;
            }
            if(l>=4)printf("%d
    ",l+1);
            else puts("0");
        }
        return 0;
    }
  • 相关阅读:
    转char varchar nvarchar区别
    NHibernate和Spring.Net框架介绍(一)
    ASP.NET面试题(一)
    存储过程编写经验和优化措施
    软件工程师不可不知的10个概念
    优化数据库前问自己的10个问题
    ZOJ 1610 Count the Colors (线段树)
    POJ 3667 Hotel (线段树)
    HDU Best Reward (扩展KMP)
    POJ 3277 City Horizon (线段树)
  • 原文地址:https://www.cnblogs.com/thmyl/p/8324745.html
Copyright © 2020-2023  润新知