zoukankan      html  css  js  c++  java
  • pku1743

    这个地址上的题解已经好详细了

    http://wenku.baidu.com/view/87f5b7f80242a8956bece4df.html

    不过本人觉得,加上这部分题解的话,会更好理解

     若在假设重复子串的长度最多为L的限制下有解, 则对于任意一个比L小的限制L'<L, 也一定有解. 这就说明存在解的连续性, 这样就可以用二分查找答案长度L.

         给出一个关于LCP的定理LCP(SA[i], SA[j]) = RMQ(Height[i+1..j]). 由此, 若存在k, 满足Height[k] < L, 则对于所有i, j 满足i < k < j, 有LCP(SA[i], SA[j]) < L. 即公共长度至少为L的两个后缀, 不会跨过一个小于L的Height低谷k, 所以我们可以得到一些由这些低谷划分开的连续的.

         在某段内, 若存在i, j 满足SA[i]+L<SA[j], 则存在一个长度至少为L的2个相同不交迭子串. 实现时只要记录在每段内, 最大和最小的SA值即可.

                                                                                   --Amber大牛,《男人不容易系列Solution》

     

    #include <iostream>
    using namespace std;
    
    #define MAXN 20010
    
    int a[MAXN],b[MAXN],array[4][MAXN],*sa,*nsa,*rank1,*nrank,height[MAXN],n;
    
    void make_sa(){
        int i,k;
    
        sa=array[0];
        nsa=array[1];
        rank1=array[2];
        nrank=array[3];
    
        memset(b,0,sizeof(b));
        for(i=0;i<n;i++)
            b[a[i]]++;
        for(i=1;i<=256;i++)
            b[i]+=b[i-1];
        for(i=n-1;i>=0;i--)
            sa[--b[a[i]]]=i;
    
        for(rank1[sa[0]]=0,i=1;i<n;i++){
            rank1[sa[i]]=rank1[sa[i-1]];
            if(a[sa[i]]!=a[sa[i-1]])
                rank1[sa[i]]++;
        }
    
        for(k=1;k<n && rank1[sa[n-1]]<n-1;k*=2){
            for(i=0;i<n;i++)
                b[rank1[sa[i]]]=i;
            for(i=n-1;i>=0;i--)
                if(sa[i]-k>=0)
                    nsa[b[rank1[sa[i]-k]]--]=sa[i]-k;
            for(i=n-k;i<n;i++)
                nsa[b[rank1[i]]--]=i;
            for(nrank[nsa[0]]=0,i=1;i<n;i++){
                nrank[nsa[i]]=nrank[nsa[i-1]];
                if(rank1[nsa[i]]!=rank1[nsa[i-1]] || rank1[nsa[i]+k]!=rank1[nsa[i-1]+k])
                    nrank[nsa[i]]++;
            }
            int *t=sa;sa=nsa;nsa=t;
            t=rank1;rank1=nrank;nrank=t;
        }
    }
    
    void cal_height(){
        int i,j,k;
        for(k=0,i=0;i<n;i++){
            if(rank1[i]==0)
                height[rank1[i]]=0;
            else{
                for(j=sa[rank1[i]-1];a[i+k]==a[j+k];k++);
                height[rank1[i]]=k;
                if(k>0)
                    k--;
            }
        }
    }
    bool OK(int len){
        int i,mn,mx;
        mn=n;
        mx=0;
        for(i=1;i<n;i++){
            if(height[i]<len){
                mn=n;
                mx=0;
            }
            else{
                if(sa[i]>mx)
                    mx=sa[i];
                if(sa[i]<mn)
                    mn=sa[i];
                if(sa[i-1]>mx)
                    mx=sa[i-1];
                if(sa[i-1]<mn)
                    mn=sa[i-1];
                if(mx-mn>=len)
                    return true;
            }
        }
        return false;
    }
    
    int main(){
        int i,ans,l,r,len;
        while(scanf("%d",&n) && n){
            for(i=0;i<n;i++)
                scanf("%d",&a[i]);
            for(i=1;i<n;i++)
                a[i-1]=a[i]-a[i-1]+88;
            n--;
            a[n++]=0;
    
            make_sa();
            cal_height();
            ans=0;
            l=0;r=n-1;
            while(l<=r){
                len=(l+r)/2;
                if(OK(len)){
                    ans=len;
                    l=len+1;
                }
                else
                    r=len-1;
            }
    		if(ans>=4)
            printf("%d\n",ans+1);
    		else printf("0\n");
    
        }
        return 0;
    }
    #include <stdio.h>   
    #include <stdlib.h>   
    #include <string.h>   
      
    int const N= 20100;   
    int wa[N], wb[N], ws[N], wv[N];   
    int rank[N], sa[N], height[N], r[N], n, k;   
      
    int cmp( int* r, int a, int b, int L ){   
        return r[a]== r[b] && r[a+ L]== r[b+ L];   
    }   
      
    void da( int* r, int* sa, int n, int m ){   
        int i, j, p, *x= wa, *y= wb, *t;   
        for( i= 0; i< m; ++i ) ws[i]= 0;   
        for( i= 0; i< n; ++i ) ws[ x[i]= r[i] ]++;   
        for( i= 1; i< m; ++i ) ws[i]+= ws[i-1];   
        for( i= n- 1; i>= 0; i-- ) sa[ --ws[ x[i] ] ]= i;   
      
        for( j= 1, p= 1; p< n; j*= 2, m= p ){   
            for( p= 0, i= n- j; i< n; ++i ) y[p++]= i;   
            for( i= 0; i< n; ++i )   
                if( sa[i]>= j ) y[p++]= sa[i]- j;   
      
            for( i= 0; i< n; ++i ) wv[i]= x[y[i]];   
            for( i= 0; i< m; ++i ) ws[i]= 0;   
            for( i= 0; i< n; ++i ) ws[ wv[i] ]++;   
            for( i= 1; i< m; ++i ) ws[i]+= ws[i-1];   
            for( i= n- 1; i>= 0; i-- ) sa[ --ws[ wv[i] ] ]= y[i];   
      
            t= x, x= y, y= t, p= 1; x[ sa[0] ]= 0;   
            for( i= 1; i< n; ++i )   
                x[ sa[i] ]= cmp( y, sa[i-1], sa[i], j )? p- 1: p++;   
        }   
    }   
      
    void callheight( int* r, int*sa, int n ){   
        int i, j, k= 0;   
        for( i= 1; i<= n; ++i ) rank[ sa[i] ]= i;   
      
        for( i= 0; i< n; height[ rank[i++] ]= k )   
            for( k?k--:0, j= sa[ rank[i]- 1]; r[i+k]== r[j+k]; k++ );   
    }  
    bool OK(int len)
    {
    	int mx=0,mi=n;
    	for(int i=1;i<n;i++)
    	{
    		if(height[i]<len)
    		{
    			mx=0;mi=n;
    		}
    		else 
    		{
    			if(sa[i]>mx)
    				mx=sa[i];
    			if(sa[i-1]>mx)
    				mx=sa[i-1];
    			if(sa[i]<mi)
    				mi=sa[i];
    			if(sa[i-1]<mi)
    				mi=sa[i-1];
    			if(mx-mi>=len)
    				return true;
    		}
    	}
    	return false;
    }
    int main(){  
    
        int i,ans,l,len,right;  
    
        while(scanf("%d",&n) && n){  
    
            for(i=0;i<n;i++)  
    
                scanf("%d",&r[i]);  
    
            for(i=1;i<n;i++)  
                r[i-1]=r[i]-r[i-1]+88;  
            n--;    r[n++]=0; 
    		da(r,sa,n+1,180);//最后一个参数表示r[]数组的最大值,数组ws[]的大小随最后一个参数而变
    		callheight(r,sa,n);
          
            ans=0;  
    
            l=0;right=n-1;  
    
            while(l<=right){  
    
                len=(l+right)/2;  
    
                if(OK(len)){  
    
                    ans=len;  
    
                    l=len+1;  
    
                }  
    
                else 
    
                    right=len-1;  
    
            }  
    
            if(ans>=4)  
    
            printf("%d\n",ans+1);  
    
            else printf("0\n");  
    
       
    
        }  
    
        return 0;  
    
    } 
    
  • 相关阅读:
    SQL命令优化
    C# 实现快捷键几种方法
    实现把dgv里的数据完整的复制到一张内存表
    DataGridView上下方向键定位
    《大型网站技术架构:核心原理与案例分析》-- 读书笔记 (2) : 大型网站核心架构要素(2) -- 可用性
    《大型网站技术架构:核心原理与案例分析》-- 读书笔记 (2) : 大型网站核心架构要素(1) -- 性能
    Solr6.7 学习笔记(01) -- 目录结构
    《大型网站技术架构:核心原理与案例分析》-- 读书笔记 (1):大型网站发展历程
    浅淡Java多线程
    java 多线程学习笔记(二) -- IO密集型任务
  • 原文地址:https://www.cnblogs.com/nanke/p/2049414.html
Copyright © 2011-2022 走看看