zoukankan      html  css  js  c++  java
  • POJ-3261 Milk Patterns(后缀数组)

    题目大意:找出至少出现K次的子串的最长长度。

    题目分析:二分枚举长度x,判断有没有最长公共前缀不小于x的并且连续出现了至少k次的有序子串区间。

    代码如下:

    # include<iostream>
    # include<cstdio>
    # include<map>
    # include<vector>
    # include<cstring>
    # include<algorithm>
    using namespace std;
    # define mid (l+(r-l)/2)
    
    const int N=20000;
    
    int SA[N+5],cnt[N+5];
    int rk[N+5],tSA[N+5];
    int a[N+5],height[N+5],n;
    
    bool same(int i,int j,int k)
    {
    	if(tSA[i]!=tSA[j]) return false;
    	if(i+k>=n&&j+k>=n) return true;
    	if(i+k>=n&&j+k<n) return false;
    	if(i+k<n&&j+k>=n) return false;
    	return tSA[i+k]==tSA[j+k];
    }
    
    void buildSA(int m)
    {
    	for(int i=0;i<m;++i) cnt[i]=0;
    	for(int i=0;i<n;++i) ++cnt[rk[i]=a[i]];
    	for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];
    	for(int i=n-1;i>=0;--i) SA[--cnt[rk[i]]]=i;
    	
    	for(int k=1;k<=n;k<<=1){
    		int p=0;
    		for(int i=n-k;i<n;++i) tSA[p++]=i;
    		for(int i=0;i<n;++i) if(SA[i]>=k) tSA[p++]=SA[i]-k;
    		
    		for(int i=0;i<m;++i) cnt[i]=0;
    		for(int i=0;i<n;++i) ++cnt[rk[tSA[i]]];
    		for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];
    		for(int i=n-1;i>=0;--i) SA[--cnt[rk[tSA[i]]]]=tSA[i];
    		
    		p=1;
    		swap(rk,tSA);
    		rk[SA[0]]=0;
    		for(int i=1;i<n;++i)
    			rk[SA[i]]=same(SA[i],SA[i-1],k)?p-1:p++;
    		if(p>=n) break;
    		m=p;
    	}
    }
    
    void getHeight()
    {
    	for(int i=0;i<n;++i) rk[SA[i]]=i;
    	int k=0;
    	for(int i=0;i<n;++i){
    		if(rk[i]==0){
    			k=height[rk[i]]=0;
    		}else{
    			if(k) --k;
    			int j=SA[rk[i]-1];
    			while(i+k<n&&j+k<n&&a[i+k]==a[j+k])
    				++k;
    			height[rk[i]]=k;
    		}
    	}
    }
    
    bool ok(int x,int k)
    {
    	int m=(n-SA[0]>=x)?1:0;
    	for(int i=1;i<n;++i){
    		if(m>=k) return true;
    		if(height[i]>=x) ++m;
    		else m=(n-SA[i]>=x)?1:0;
    	}
    	return m>=k;
    }
    
    int main()
    {
    	int k;
    	while(~scanf("%d%d",&n,&k))
    	{
    		int m=0;
    		for(int i=0;i<n;++i){
    			scanf("%d",a+i);
    			m=max(m,a[i]);
    		}
    		
    		buildSA(m+1);
    		getHeight();
    		int l=1,r=n+1;
    		while(l<r){
    			if(ok(mid,k)) l=mid+1;
    			else r=mid;
    		}
    		printf("%d
    ",l-1);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    整数幂的求解
    非递归实现不重复序列的全排列(二)
    完整的将日期时间转换为汉字的代码
    如何得到某集合的所有子集合?
    再谈八皇后问题
    大数阶乘的计算(六)
    非递归实现不重复序列的全排列(一)
    非递归实现不重复序列的全排列(三)
    大数阶乘的计算(五)
    关于走楼梯的递归算法
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/5954634.html
Copyright © 2011-2022 走看看