zoukankan      html  css  js  c++  java
  • 【poj1743】Musical Theme【后缀数组】

    题目链接
    题解:首先,由于可以变调,我们把字符串每个字符变成相邻两个字符的差。然后跑后缀自动机,得到sa,rnk和height。二分答案k,k表示原字符串的某个不重复公共子串的长度,就变成了判定问题。把所有排名相邻且height>=k-1的字符串分为一组,然后如果这组中sa的最大值和sa的最小值的差>=k,原串中就可以找到满足条件的2个长度为k的字符串。感性的证明:长得像的后缀都排到了一起!(捂脸)
    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=20005;
    int m,n,a[N],c[N],t1[N],t2[N],sa[N],rnk[N],h[N];
    bool cmp(int *y,int p,int q,int k){
        int a=p+k>=n?-1:y[p+k];
        int b=q+k>=n?-1:y[q+k];
        return y[p]==y[q]&&a==b;
    } 
    void build_sa(int m){
        int *x=t1,*y=t2;
        for(int i=0;i<m;i++){
            c[i]=0;
        }
        for(int i=0;i<n;i++){
            c[x[i]=a[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;
        }
        for(int k=1;k<=n;k<<=1){
            int p=0;
            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);
            p=1;
            x[sa[0]]=0;
            for(int i=1;i<n;i++){
                x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?p-1:p++;
            }
            if(p>=n){
                break;
            }
            m=p;
        }
        for(int i=0;i<n;i++){
            rnk[sa[i]]=i;
        }
        for(int i=0,j,k=0;i<n;i++){
            if(k){
                k--;
            }
            if(!rnk[i]){
                continue;
            }
            j=sa[rnk[i]-1];
            while(a[i+k]==a[j+k]){
                k++;
            }
            h[rnk[i]]=k;
        }
    }
    bool check(int k){
        int maxn=sa[0],minn=sa[0];
        for(int i=1;i<n;i++){
            if(h[i]>=k-1){
                maxn=max(maxn,sa[i]);
                minn=min(minn,sa[i]);
            }else{
                maxn=minn=sa[i];
            }
            if(maxn-minn>=k){
                return true;
            }
        }
        return false;
    }
    int main(){
        while(scanf("%d",&m)&&m){
            n=m-1;
            for(int i=0;i<m;i++){
                scanf("%d",&a[i]);
            }
            for(int i=0;i<n;i++){
                a[i]=a[i]-a[i+1]+88;
            }
            build_sa(200);
            int l=0,r=m/2;
            while(l<r){
                int mid=(l+r+1)/2;
                if(check(mid)){
                    l=mid;
                }else{
                    r=mid-1;
                }
            }
            printf("%d
    ",l<5?0:l);
        }
        return 0;
    }
  • 相关阅读:
    使用WinDbg调试SQL Server——入门
    SQL Server里如何随机记录集
    相关列的基数计算
    自增长的聚集键值不会扩展(scale)
    使用正确的筛选参数来提高查询性能
    可更新聚集列存储索引幻想
    在SQL Server 2014里可更新的列存储索引 (Updateable Column Store Indexes)
    SQL Server 2014里的IO资源调控器
    SQL Server 2014里的针对基数估计的新设计(New Design for Cardinality Estimation)
    缓存池扩展 (Buffer Pool Extension)实践
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476895.html
Copyright © 2011-2022 走看看