• 【POJ3261】Milk Patterns-后缀数组+二分答案


    测试地址:Milk Patterns

    题目大意:求数列中至少出现K次的重复子串的最长长度。

    做法:和重复子串有关的题目,一下子就想到后缀数组。先对数列求一遍后缀数组,再求出height数组。我们发现答案是具有单调性的,所以我们二分答案M,将排序后的后缀序列按height数组分成几个连续区间,如果height[i]<M就把SA[i-1]与SA[i]划分在两个区间内。然后观察每个区间内的后缀个数,如果一个区间内后缀个数≥K,则说明存在长度为M的出现至少K次的重复子串,如果每个区间内都没有则说明不存在。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,k,a[20010],x[50010]={0},y[20010],s[20010],t[1000010];
    int rank[20010],sa[20010],height[20010];
    
    void DA()
    {
      int up=1000000,p=1;
      for(int i=1;i<=n;i++) x[i]=a[i];
      while(p<n)
      {
        for(int i=1;i<=n;i++) y[i]=x[i+p];
    	
    	memset(t,0,sizeof(t));
    	for(int i=1;i<=n;i++) t[y[i]]++;
    	for(int i=1;i<=up;i++) t[i]+=t[i-1];
    	for(int i=up;i>=1;i--) t[i]=t[i-1];
    	t[0]=0;
    	for(int i=1;i<=n;i++) s[++t[y[i]]]=i;
    	
    	memset(t,0,sizeof(t));
    	for(int i=1;i<=n;i++) t[x[s[i]]]++;
    	for(int i=1;i<=up;i++) t[i]+=t[i-1];
    	for(int i=up;i>=1;i--) t[i]=t[i-1];
    	t[0]=0;
    	for(int i=1;i<=n;i++) y[++t[x[s[i]]]]=s[i];
    	
    	up=1;
    	s[y[1]]=1;
    	for(int i=2;i<=n;i++)
    	{
    	  if (x[y[i]]!=x[y[i-1]]||x[y[i]+p]!=x[y[i-1]+p]) up++;
    	  s[y[i]]=up;
    	}
    	
    	for(int i=1;i<=n;i++) x[i]=s[i];
        p<<=1;
      }
      for(int i=1;i<=n;i++)
      {
        rank[i]=x[i];
    	sa[rank[i]]=i;
      }
    }
    
    void calc_height()
    {
      for(int i=1,j=0;i<=n;i++)
      {
        if (rank[i]==1) continue;
    	while(a[i+j]==a[sa[rank[i]-1]+j]) j++;
    	height[rank[i]]=j;
    	if (j>0) j--;
      }
      height[n+1]=0;
    }
    
    bool check(int m)
    {
      int start=1;
      for(int i=1;i<=n;i++)
      {
        if (height[i+1]<m)
    	{
    	  if (i-start+1>=k) return 1;
    	  start=i+1;
    	}
      }
      return 0;
    }
    
    int main()
    {
      scanf("%d%d",&n,&k);
      for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
      DA();
      calc_height();
      
      int l=0,r=n,ans=0;
      while(l<=r)
      {
        int mid=(l+r)>>1;
    	if (check(mid))
    	{
    	  ans=max(ans,mid);
    	  l=mid+1;
    	}
    	else r=mid-1;
      }
      
      printf("%d",ans);
      return 0;
    }
    


  • 相关阅读:
    Linux环境下配置Google Test、TBB、OpenMP和OpenCV
    构建一个真实的应用电子商务SportsStore(六)
    编写简单的c运行库(一)
    构建一个真实的应用电子商务SportsStore(七)
    Entity Framework性能测试
    C++在VS下创建、调用dll
    Contextfree Grammar的编译器设计和实现
    XP方法概述
    项目代码风格要求
    WCF学习 第三天 事务的使用
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793768.html
Copyright © 2020-2023  润新知