可重叠k次最长重复子串

Posted -ackerman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可重叠k次最长重复子串相关的知识,希望对你有一定的参考价值。

题目链接:https://cn.vjudge.net/contest/318888#overview

 

题意:约翰注意到奶牛产奶的之类是不断变化的,虽然他不能预测从当天到下一天的变化情况但是他知道变化是有规律的,牛奶的质量由一个整数表示,范围从0到1000000,现在给定一个长度为n的序列,要求找到一个最大子序列,该子序列重复出现至少k次,各个出现部分可有重叠,求最长的长度。简单来说就是可重叠的k 次最长重复子串。

思路:直接根据09年oi论文<<后缀数组——出来字符串的有力工具>>的解法,先二分答案x,然后将后缀分成若干组(每组的height值不小于x)。不同的是,这里要判断的是有没有一个组的后缀个数不小于k。如果有,那么存在k 个相同的子串满足条件,否则不存在。这个做法的时间复杂度为O(nlogn)。

其实最主要的就是height的分组操作,正是因为height的独特性质导致我们可以去二分去寻找答案。技术图片

 

 

仔细理解下上面这句话,那么就可以明白了

 

然后这道题再注意一下离散化,因为数据0->1000000 有点大

  1 #include <stdio.h>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <string.h>
  5 #include <stdlib.h>
  6 #include <math.h>
  7 #include <queue>
  8 #include <set>
  9 
 10 #define INF 0x3f3f3f3f
 11 #define pii pair<int,int>
 12 #define LL long long
 13 using namespace std;
 14 typedef unsigned long long ull;
 15 const int maxn = 2e6+6;
 16 
 17 int s[maxn];
 18 int sa[maxn],t[maxn],t2[maxn],c[maxn];
 19 int Rank[maxn],height[maxn];
 20 
 21 void build_sa(int n,int m)
 22 
 23     int i,j,*x=t,*y=t2;
 24     for (i=0;i<m;i++)
 25         c[i] = 0;
 26     for (i=0;i<n;i++)
 27         c[x[i] = s[i]]++;
 28     for (i=1;i<m;i++)
 29         c[i] += c[i-1];
 30     for (i=n-1;i>=0;i--)
 31         sa[--c[x[i]]] = i;
 32     for (int k=1;k<=n;k<<=1)
 33     
 34         int p = 0;
 35         for (i=n-k;i<n;i++)
 36             y[p++] = i;
 37         for (i=0;i<n;i++)
 38         
 39             if (sa[i]>=k)
 40                 y[p++] = sa[i]-k;
 41         
 42         for (i=0;i<m;i++)
 43             c[i] = 0;
 44         for (i=0;i<n;i++)
 45             c[x[y[i]]]++;
 46         for (i=1;i<m;i++)
 47             c[i] += c[i-1];
 48         for (i=n-1;i>=0;i--)
 49             sa[--c[x[y[i]]]] = y[i];
 50         swap(x,y);
 51         p = 1;
 52         x[sa[0]] = 0;
 53         for (i=1;i<n;i++)
 54             x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
 55         if (p>=n)
 56             break;
 57         m = p;
 58     
 59 
 60 
 61 
 62 void getHeight(int n)
 63     int i,j,k=0;
 64     for (i=1;i<=n;i++)
 65         Rank[sa[i]] = i;
 66     
 67     for (i=0;i<n;i++)
 68         if (k)
 69             k--;
 70         j = sa[Rank[i]-1];
 71         while (s[i+k] == s[j+k])
 72             k++;
 73         height[Rank[i]] = k;
 74     
 75 
 76 
 77 int n,k;
 78 int b[maxn];
 79 
 80 void Discretization()
 81     for (int i=0;i<=n;i++)
 82         b[i] = s[i];
 83     
 84     sort(b,b+n+1);
 85     int size = unique(b,b+n+1)-b;
 86     for (int i=0;i<=n;i++)
 87         s[i] = lower_bound(b,b+size,s[i])-b;
 88     
 89 
 90 
 91 bool check(int x)
 92     int tot = 1;
 93     for (int i=1;i<=n;i++)
 94         if (height[i]>=x)
 95             tot++;
 96         else
 97             if (tot>=k)
 98                 return true;
 99             tot = 1;
100         
101     
102     return tot>=k;
103 
104 
105 int main()
106     while (~scanf("%d%d",&n,&k))
107         for (int i=0;i<n;i++)
108             scanf("%d",&s[i]);
109         
110         s[n] = 0;
111         Discretization();
112         build_sa(n+1,n+1);
113         getHeight(n);
114         int l=0,r=n,mid;
115         while (l<=r)
116             mid = (l+r)>>1;
117             if (check(mid))
118                 l = mid+1;
119             
120             else
121                 r = mid-1;
122             
123         
124         printf("%d\\n",r);
125     
126     return 0;
127 

 

以上是关于可重叠k次最长重复子串的主要内容,如果未能解决你的问题,请参考以下文章

POJ 3261 Milk Patterns(后缀数组[可重叠的k次最长重复子串])

POJ 3261 Milk Patterns(后缀数组[可重叠的k次最长重复子串])

POJ 3261 Milk Patterns ( 后缀数组 && 出现k次最长可重叠子串长度 )

hiho121 后缀数组一·重复旋律2字符串--后缀数组--最长可重叠重复K次子串问题

可重叠最长重复子串

hiho120 后缀数组一·重复旋律2字符串--后缀数组--最长不可重叠重复子串问题