可重叠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 }

原文地址:https://www.cnblogs.com/-Ackerman/p/11332809.html

时间: 2024-08-29 10:28:10

可重叠k次最长重复子串的相关文章

POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)

Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14094   Accepted: 6244 Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation,

poj 3261 求可重叠的k次最长重复子串

题意:求可重叠的k次最长重复子串的长度 链接:点我 和poj1743差不多 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000

可重叠的k次最长重复子串

题目链接:https://cn.vjudge.net/contest/318888#problem/B 题意: 约翰注意到奶牛产奶的之类是不断变化的,虽然他不能预测从当天到下一天的变化情况但是他知道变化是有规律的,牛奶的质量由一个整数表示,范围从0到1000000,现在给定一个长度为n的序列,要求找到一个最大子序列,该子序列重复出现至少k次,各个出现部分可有重叠,求最长的长度.简单来说就是可重叠的k 次最长重复子串. 简单来说就是求可重叠的k次最长重复子串 思路: 这题首先先看数据的范围,发现相

POJ 3261 可重叠的 k 次最长重复子串【后缀数组】

这也是一道例题 给定一个字符串,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠.算法分析:这题的做法和上一题差不多,也是先二分答案,然后将后缀分成若干组.不同的是,这里要判断的是有没有一个组的后缀个数不小于 k.如果有,那么存在k 个相同的子串满足条件,否则不存在.这个做法的时间复杂度为 O(nlogn). Source Code: //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include

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

Description Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation, he discovered that although he can't predict the quality of milk from one day to the next, there are some regular pattern

[Poj3261] [Bzoj1717] [后缀数组论文例题,USACO 2006 December Gold] Milk Patterns [后缀数组可重叠的k次最长重复子串]

和上一题(POJ1743,上一篇博客)相似,只是二分的判断条件是:是否存在一段后缀的个数不小于k 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cmath> 7 #include <ctime> 8 #include <map&

KMP(最长重复子串 &amp; 最小覆盖)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 如果一个长度 L 字符串是由 n 个长度 L / n 子串构成的.那么最后一个字符的next值是L-L/n吧: 例如: 一个字符串:abbabbabbabbabb(一共15个字符) next[15]=12吧! 我们拿:15 - 12 = 3 就是最长重复子串的长度 现在说一般情况: 假设 next[length] = k 如果 k % length == 0 那 length /

【POJ1743】不可重叠最长重复子串

题意:求一个字符串里两个不重叠的最长重复子串 代码如下: 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 int sa[20010],rank[20010],y[20010],Rsort[20010]; 8 int wr[20010],a[20010],height[20010],n; 9 10

字符串----不可重叠的最长重复子串

题目:给定一个字符串,求最长重复子串,这两个子串不能重叠.例如,str = "acdcdcdcd",则不可重叠的最长子串为"cdcd". 思路:二分枚举+height数组分组.这道题的思想很巧妙,后面要仔细推敲.先二分答案,把题目变成判定性问题:判断是否存在两个长度为k的子串是相同的,且不重叠.解决这个问题的关键还是利用height数组.把排序后的后缀分成若干组,其中每组的后缀之间的height值都不小于k.例如,字符串为“aabaaaab”,当k=2时,后缀分成了