zoukankan      html  css  js  c++  java
  • 【后缀数组】【二分答案】poj3261

    注意:对整型数组求sa时,s[n]请置成-1。

    请离散化。

    可重叠的 k 次最长重复子串(pku3261)
    给定一个字符串,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠。
    算法分析:
    先二分答案,然后将后缀分成若干组。 不
    同的是,这里要判断的是有没有一个组的后缀个数不小于 k。如果有,那么存在
    k 个相同的子串满足条件,否则不存在。这个做法的时间复杂度为 O(nlogn)。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define N 20001
    struct Point{int p,v;}T[N];
    bool operator < (Point a,Point b){return a.v<b.v;}
    int s[N],tong[N],t[N],t2[N],rank[N],lcp[N],sa[N];
    int n,K,zy=1,ma[N];
    bool cmp(int *y,int i,int k)
    {
    	return ((y[sa[i-1]]==y[sa[i]])&&((sa[i-1]+k>=n?-1:y[sa[i-1]+k])==(sa[i]+k>=n?-1:y[sa[i]+k])));
    }
    void build_sa(int range)
    {
    	int *x=t,*y=t2;
    	memset(tong,0,sizeof(int)*range);
    	for(int i=0;i<n;++i) tong[x[i]=s[i]]++;
    	for(int i=1;i<range;++i) tong[i]+=tong[i-1];
    	for(int i=n-1;i>=0;--i) sa[--tong[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;
    		memset(tong,0,sizeof(int)*range);
    		for(int i=0;i<n;++i) tong[x[y[i]]]++;
    		for(int i=1;i<range;++i) tong[i]+=tong[i-1];
    		for(int i=n-1;i>=0;--i) sa[--tong[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,i,k)?p-1:p++;
    	  	if(p>=n) break;
    	  	range=p;
    	  }
    }
    void get_lcp()
    {
    	int k=0;
    	for(int i=0;i<n;++i) rank[sa[i]]=i;
    	for(int i=0;i<n;++i) if(rank[i])
    	  {
    	  	if(k) --k;
    	  	int j=sa[rank[i]-1];
    	  	while(s[i+k]==s[j+k]) ++k;
    	  	lcp[rank[i]]=k;
    	  }
    }
    bool check(int x)
    {
    	int cnt=1;
        for(int i=1;i<=n;++i)
          {
            if(lcp[i]<x||i==n)
              {
                if(cnt>=K) return 1;
                cnt=1;
              }
            else if(lcp[i]>=x) ++cnt;
          }
        return 0;
    }
    int main()
    {
    	scanf("%d%d",&n,&K);
    	for(int i=0;i<n;++i)
    	  {
    	  	scanf("%d",&T[i].v);
    	  	T[i].p=i;
    	  }
    	sort(T,T+n);
        for(int i=1;i<n;++i)
          {
            if(T[i].v!=T[i-1].v) ++zy;
            s[T[i].p]=zy-1;
          }
        s[n]=-1;
        build_sa(zy);
        get_lcp();
        int l=0,r=n;
        while(r>l)
          {
          	int mid=(l+r+1>>1);
          	if(check(mid)) l=mid;
          	else r=mid-1;
          }
        printf("%d
    ",l);
    	return 0;
    }
  • 相关阅读:
    〖Linux〗Kubuntu设置打开应用时就只在打开时的工作区显示
    〖Linux〗Kubuntu, the application 'Google Chrome' has requested to open the wallet 'kdewallet'解决方法
    unity, dll is not allowed to be included or could not be found
    android check box 自定义图片
    unity, ios skin crash
    unity, Collider2D.bounds的一个坑
    unity, ContentSizeFitter立即生效
    类里的通用成员函数应声明为static
    unity, Gizmos.DrawMesh一个坑
    直线切割凹多边形
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/4462156.html
Copyright © 2011-2022 走看看