题意:给定一个字符串,求至少出现k 次的最长重复子串,这k 个子串可以重叠。

分析:经典的后缀数组求解题:先二分答案,然后将后缀分成若干组。这里要判断的是有没有一个组的符合要求的后缀个数(height[i] >= mid)不小于k。如果有,那么存在
k 个相同的子串满足条件,否则不存在。

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <algorithm>
  5. using namespace std;
  6. #define N 22222
  7. #define M 1111111
  8. #define INF 0x7FFFFFFF
  9. /****后缀数组模版****/
  10. #define F(x)((x)/3+((x)%3==1?0:tb)) //F(x)求出原字符串的suffix(x)在新的字符串中的起始位置
  11. #define G(x)((x)<tb?(x)*3+1:((x)-tb)*3+2) //G(x)是计算新字符串的suffix(x)在原字符串中的位置,和F(x)为互逆运算
  12. int wa[N],wb[N],wv[N],WS[M];
  13. int sa[N*3] ; //第i小的后缀,起始位置在源字符串的位置
  14. int rank1[N],height[N]; //rank 以i为起始位置的后缀在后缀排列中的名次
  15. int r[N*3]; //如果输入是字符串,承接字符串,用来计算
  16.  
  17. int c0(int *r,int a,int b) {
  18. return r[a]==r[b] && r[a+1]==r[b+1] && r[a+2]==r[b+2];
  19. }
  20. int c12(int k,int *r,int a,int b) {
  21. if(k==2)
  22. return r[a]<r[b] || ( r[a]==r[b] && c12(1,r,a+1,b+1) );
  23. else
  24. return r[a]<r[b] || ( r[a]==r[b] && wv[a+1]<wv[b+1] );
  25. }
  26. void sort(int *r,int *a,int *b,int n,int m) {
  27. int i;
  28. for(i=0; i<n; i++)
  29. wv[i]=r[a[i]];
  30. for(i=0; i<m; i++)
  31. WS[i]=0;
  32. for(i=0; i<n; i++)
  33. WS[wv[i]]++;
  34. for(i=1; i<m; i++)
  35. WS[i]+=WS[i-1];
  36. for(i=n-1; i>=0; i--)
  37. b[--WS[wv[i]]]=a[i];
  38. return;
  39. }
  40.  
  41. //注意点:为了方便下面的递归处理,r数组和sa数组的大小都要是3*n
  42. void dc3(int *r,int *sa,int n,int m) { //rn数组保存的是递归处理的新字符串,san数组是新字符串的sa
  43. int i , j , *rn = r+n , *san = sa+n , ta = 0 ,tb = (n+1)/3 , tbc = 0 , p;
  44. r[n] = r[n+1] = 0;
  45. for(i=0; i<n; i++) {
  46. if(i%3!=0)
  47. wa[tbc++]=i; //tbc表示起始位置模3为1或2的后缀个数
  48. }
  49. sort(r+2,wa,wb,tbc,m);
  50. sort(r+1,wb,wa,tbc,m);
  51. sort(r,wa,wb,tbc,m);
  52. for(p=1,rn[F(wb[0])]=0,i=1; i<tbc; i++)
  53. rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
  54. if(p<tbc)
  55. dc3(rn,san,tbc,p);
  56. else {
  57. for(i=0; i<tbc; i++)
  58. san[rn[i]]=i;
  59. }
  60. //对所有起始位置模3等于0的后缀排序
  61. for(i=0; i<tbc; i++) {
  62. if(san[i]<tb)
  63. wb[ta++]=san[i]*3;
  64. }
  65. if(n%3==1) //n%3==1,要特殊处理suffix(n-1)
  66. wb[ta++]=n-1;
  67. sort(r,wb,wa,ta,m);
  68. for(i=0; i<tbc; i++)
  69. wv[wb[i] = G(san[i])]=i;
  70. //合并所有后缀的排序结果,保存在sa数组中
  71. for(i=0,j=0,p=0; i<ta&&j<tbc; p++)
  72. sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
  73. for(; i<ta; p++)
  74. sa[p]=wa[i++];
  75. for(; j<tbc; p++)
  76. sa[p]=wb[j++];
  77. return;
  78. }
  79.  
  80. //height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀
  81. void calheight(int *r,int *sa,int n) {
  82. int i,j,k=0;
  83. for(i=1; i<=n; i++)
  84. rank1[sa[i]]=i;
  85. for(i=0; i<n; height[rank1[i++]]=k)
  86. for(k?k--:0,j=sa[rank1[i]-1]; r[i+k]==r[j+k]; k++);
  87. }
  88.  
  89. bool judge(int mid,int n,int k) {
  90. int cnt = 1;
  91. for(int i=1; i<=n; i++) {
  92. if(height[i] >= mid) {
  93. cnt ++;
  94. } else cnt = 1;
  95. if(cnt >= k) return true;
  96. }
  97. return false;
  98. }
  99.  
  100. int main() {
  101. int n,k;
  102. cin >> n >> k;
  103. for(int i=0; i<n; i++) {
  104. scanf("%d",&r[i]);
  105. r[i] ++;
  106. }
  107. r[n] = 0; //要保证结尾最小
  108. dc3(r,sa,n+1,1000010);
  109. calheight(r,sa,n);
  110. int l=1, r=n,mid; //枚举长度
  111. int ans = 0;
  112. while(l <= r) {
  113. mid = (l+r) >> 1;
  114. if(judge(mid,n,k)) {
  115. ans = mid;
  116. l = mid + 1;
  117. } else {
  118. r = mid - 1;
  119. }
  120. }
  121. cout << ans << endl;
  122. return 0;
  123. }

因为m太大,而n只有2w,简单的离散化之后,基数排序效率提高,总效率也提高了

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <algorithm>
  5. using namespace std;
  6. #define N 22222
  7. #define INF 0x7FFFFFFF
  8. /****后缀数组模版****/
  9. #define F(x)((x)/3+((x)%3==1?0:tb)) //F(x)求出原字符串的suffix(x)在新的字符串中的起始位置
  10. #define G(x)((x)<tb?(x)*3+1:((x)-tb)*3+2) //G(x)是计算新字符串的suffix(x)在原字符串中的位置,和F(x)为互逆运算
  11. int wa[N],wb[N],wv[N],WS[N];
  12. int sa[N*3] ; //第i小的后缀,起始位置在源字符串的位置
  13. int rank1[N],height[N]; //rank 以i为起始位置的后缀在后缀排列中的名次
  14. int r[N*3]; //如果输入是字符串,承接字符串,用来计算
  15.  
  16. int c0(int *r,int a,int b) {
  17. return r[a]==r[b] && r[a+1]==r[b+1] && r[a+2]==r[b+2];
  18. }
  19. int c12(int k,int *r,int a,int b) {
  20. if(k==2)
  21. return r[a]<r[b] || ( r[a]==r[b] && c12(1,r,a+1,b+1) );
  22. else
  23. return r[a]<r[b] || ( r[a]==r[b] && wv[a+1]<wv[b+1] );
  24. }
  25. void sort(int *r,int *a,int *b,int n,int m) {
  26. int i;
  27. for(i=0; i<n; i++)
  28. wv[i]=r[a[i]];
  29. for(i=0; i<m; i++)
  30. WS[i]=0;
  31. for(i=0; i<n; i++)
  32. WS[wv[i]]++;
  33. for(i=1; i<m; i++)
  34. WS[i]+=WS[i-1];
  35. for(i=n-1; i>=0; i--)
  36. b[--WS[wv[i]]]=a[i];
  37. return;
  38. }
  39.  
  40. //注意点:为了方便下面的递归处理,r数组和sa数组的大小都要是3*n
  41. void dc3(int *r,int *sa,int n,int m) { //rn数组保存的是递归处理的新字符串,san数组是新字符串的sa
  42. int i , j , *rn = r+n , *san = sa+n , ta = 0 ,tb = (n+1)/3 , tbc = 0 , p;
  43. r[n] = r[n+1] = 0;
  44. for(i=0; i<n; i++) {
  45. if(i%3!=0)
  46. wa[tbc++]=i; //tbc表示起始位置模3为1或2的后缀个数
  47. }
  48. sort(r+2,wa,wb,tbc,m);
  49. sort(r+1,wb,wa,tbc,m);
  50. sort(r,wa,wb,tbc,m);
  51. for(p=1,rn[F(wb[0])]=0,i=1; i<tbc; i++)
  52. rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
  53. if(p<tbc)
  54. dc3(rn,san,tbc,p);
  55. else {
  56. for(i=0; i<tbc; i++)
  57. san[rn[i]]=i;
  58. }
  59. //对所有起始位置模3等于0的后缀排序
  60. for(i=0; i<tbc; i++) {
  61. if(san[i]<tb)
  62. wb[ta++]=san[i]*3;
  63. }
  64. if(n%3==1) //n%3==1,要特殊处理suffix(n-1)
  65. wb[ta++]=n-1;
  66. sort(r,wb,wa,ta,m);
  67. for(i=0; i<tbc; i++)
  68. wv[wb[i] = G(san[i])]=i;
  69. //合并所有后缀的排序结果,保存在sa数组中
  70. for(i=0,j=0,p=0; i<ta&&j<tbc; p++)
  71. sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
  72. for(; i<ta; p++)
  73. sa[p]=wa[i++];
  74. for(; j<tbc; p++)
  75. sa[p]=wb[j++];
  76. return;
  77. }
  78.  
  79. //height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀
  80. void calheight(int *r,int *sa,int n) {
  81. int i,j,k=0;
  82. for(i=1; i<=n; i++)
  83. rank1[sa[i]]=i;
  84. for(i=0; i<n; height[rank1[i++]]=k)
  85. for(k?k--:0,j=sa[rank1[i]-1]; r[i+k]==r[j+k]; k++);
  86. }
  87.  
  88. bool judge(int mid,int n,int k) {
  89. int cnt = 1;
  90. for(int i=1; i<=n; i++) {
  91. if(height[i] >= mid) {
  92. cnt ++;
  93. } else cnt = 1;
  94. if(cnt >= k) return true;
  95. }
  96. return false;
  97. }
  98. int xx[N],x[N];
  99. int search(int v,int m) {
  100. int l = 0,r = m-1;
  101. while(l <= r) {
  102. int mid = (l + r) /2;
  103. if(x[mid] == v)
  104. return mid;
  105. if(v < x[mid])
  106. r = mid-1;
  107. else
  108. l = mid+1;
  109. }
  110. return -1;
  111. }
  112. int main() {
  113. int n,k;
  114. cin >> n >> k;
  115. for(int i=0; i<n; i++) {
  116. scanf("%d",&x[i]);
  117. xx[i] = x[i];
  118. }
  119. int m = 1;
  120. for (int i=1; i<n; i++) { //离散化去重
  121. if (x[i] != x[i-1]) x[m ++] = x[i];
  122. }
  123. sort(x,x+m);
  124. for(int i=0; i<n; i++) r[i] = search(xx[i],m) + 1;
  125. // for(int i=0; i<n; i++) cout << r[i] << ' ';
  126. // cout << endl;
  127. r[n] = 0; //要保证结尾最小
  128. dc3(r,sa,n+1,20001);
  129. calheight(r,sa,n);
  130. int l=1, r=n,mid; //枚举长度
  131. int ans = 0;
  132. while(l <= r) {
  133. mid = (l+r) >> 1;
  134. if(judge(mid,n,k)) {
  135. ans = mid;
  136. l = mid + 1;
  137. } else {
  138. r = mid - 1;
  139. }
  140. }
  141. cout << ans << endl;
  142. return 0;
  143. }

POJ 3261 Milk Patterns(后缀数组+二分答案+离散化)的更多相关文章

  1. Poj 3261 Milk Patterns(后缀数组+二分答案)

    Milk Patterns Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk g ...

  2. poj 3261 Milk Patterns 后缀数组 + 二分

    题目链接 题目描述 给定一个字符串,求至少出现 \(k\) 次的最长重复子串,这 \(k\) 个子串可以重叠. 思路 二分 子串长度,据其将 \(h\) 数组 分组,判断是否存在一组其大小 \(\ge ...

  3. POJ 3261 Milk Patterns 后缀数组求 一个串种 最长可重复子串重复至少k次

    Milk Patterns   Description Farmer John has noticed that the quality of milk given by his cows varie ...

  4. POJ 3261 Milk Patterns(后缀数组+单调队列)

    题意 找出出现k次的可重叠的最长子串的长度 题解 用后缀数组. 然后求出heigth数组. 跑单调队列就行了.找出每k个数中最小的数的最大值.就是个滑动窗口啊 (不知道为什么有人写二分,其实写啥都差不 ...

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

    题意 : 给出一个长度为 N 的序列,再给出一个 K 要求求出出现了至少 K 次的最长可重叠子串的长度 分析 : 后缀数组套路题,思路是二分长度再对于每一个长度进行判断,判断过程就是对于 Height ...

  6. Poj 1743 Musical Theme(后缀数组+二分答案)

    Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...

  7. BZOJ 1717 [USACO06DEC] Milk Patterns (后缀数组+二分)

    题目大意:求可重叠的相同子串数量至少是K的子串最长长度 洛谷传送门 依然是后缀数组+二分,先用后缀数组处理出height 每次二分出一个长度x,然后去验证,在排序的后缀串集合里,有没有连续数量多于K个 ...

  8. POJ 1226 Substrings(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=1226 [题目大意] 求在每个给出字符串中出现的最长子串的长度,字符串在出现的时候可以是倒置的. [题解] 我们将每个字符串倒置,用 ...

  9. poj 3294 Life Forms - 后缀数组 - 二分答案

    题目传送门 传送门I 传送门II 题目大意 给定$n$个串,询问所有出现在严格大于$\frac{n}{2}$个串的最长串.不存在输出'?' 用奇怪的字符把它们连接起来.然后求sa,hei,二分答案,按 ...

随机推荐

  1. (C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单

    原文 (C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单 接上一节:(C#)Windows Shell 编程系列2 - 解释,从“桌面”开始展开这 ...

  2. BZOJ 1672: [Usaco2005 Dec]Cleaning Shifts 清理牛棚

    题目 1672: [Usaco2005 Dec]Cleaning Shifts 清理牛棚 Time Limit: 5 Sec  Memory Limit: 64 MB Description Farm ...

  3. Mysql5.6.24 zip解压缩版配置及修改默认编码方法

    win64位下载地址: http://dev.mysql.com/downloads/file.php?id=456319 下载完毕后解压 配置环境变量 在Path后加上mysql解压后bin文件夹所 ...

  4. c语言编写经验逐步积累4

    寥寥数笔,记录我的C语言盲点笔记,仅仅为以前经历过,亦有误,可交流. 1.逻辑表达式的使用 取值 = 表达式 ? 表达式1:表达式2: 比方x = y > z ? y:z 2."+,- ...

  5. .NET使用NPOI组件将数据导出Excel

    .NPOI官方网站:http://npoi.codeplex.com/ 可以到此网站上去下载最新的NPOI组件版本 2.NPOI在线学习教程(中文版): http://www.cnblogs.com/ ...

  6. 循环训练(for的嵌套、while、do while)以及异常处理

    For的嵌套 练习一: 练习二: 练习三: 练习四: while的使用方法: 示例一: 示例二: 示例三: while的练习题: do while的使用示例: 异常处理示例: try   catch  ...

  7. Visual Studio Tools for Unity安装及使用

    Visual Studio Tools for Unity安装及使用 转载自:CSDN 晃了一下,10.1到现在又过去两个月了,这两个月什么也没有学,整天上班下班,从这周末开始拾起unity,为了年后 ...

  8. Spring源码地址和相关介绍的网址

    Spring源码地址下载: https://github.com/spring-projects/spring-framework/tags >多图详解Spring框架的设计理念与设计模式:ht ...

  9. Xcode 插件优缺点对比(推荐 20 款插件)

    链接地址:http://mp.weixin.qq.com/s?__biz=MjM5OTM0MzIwMQ==&mid=402439598&idx=1&sn=e8800cb0aa2 ...

  10. Debian(Linux)系统目录简单说明

    bin:基础命令执行档 boot:引导装置器的静态链接文件 dev:设备档 etc:主机特定的系统配置 lib:基本共享库及基本内核模块 mnt:用于临时挂载一个文件系统 proc:系统信息的虚拟目录 ...