可重叠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次最长可重叠子串长度 )