题目链接

题意

对于任意的字符串,定义它的 重复次数 为:它最多可被划分成的完全相同的子串个数。例如:ababab 的重复次数为3,ababa 的重复次数为1.

现给定一字符串,求它的一个子串,其重复次数取到最大值,且字典序取到最小值。

思路

参考 hzwer.

首先,重复次数显然至少为\(1\),所以下面只考虑重复次数\(\geq 2\)的情况。

首先枚举子串长度\(L\)。对于长度为\(L\)的子串,其重复次数至少为\(2\),意味着它的其中两个重复部分必为\(s[0],s[L],s[2L],...\)中相邻的两个。

所以只需枚举\(i\),看\(s[i*L]\)和\(s[(i+1)*L]\)向左\((le)\)向右\((ri)\)最多能匹配到多远,记总长度为\(k\),则重复次数\(=k/L+1\).

至于开头位置,则落在\(i*L-le\)和\(i*L-le+(le+ri)\%k\)之间,取字典序最小者。

对于所有重复次数相同的子串,要使其字典序取到最小值,即取\(rank\)值最小者。

上述步骤中,看最长匹配多远(即看最长公共前缀)与取rank最小值均借助\(ST\)表实现。

Code

  1. #include <stdio.h>
  2. #include <iostream>
  3. #include <string.h>
  4. #define maxn 100010
  5. using namespace std;
  6. typedef long long LL;
  7. int wa[maxn], wb[maxn], wv[maxn], wt[maxn], r1[maxn], r2[maxn],
  8. h1[maxn], h2[maxn], rk1[maxn], rk2[maxn], sa[maxn], n, kas, bin[20], Log[maxn];
  9. struct rmqNode { int val, p; } mn[maxn][20];
  10. struct node { int val, pos, len; };
  11. int mn1[maxn][20], mn2[maxn][20];
  12. char s[maxn];
  13. void rmqInit(int n) {
  14. Log[0] = -1; bin[0] = 1;
  15. for (int i = 1; i < 20; ++i) bin[i] = bin[i-1] << 1;
  16. for (int i = 1; i <= n; ++i) Log[i] = Log[i>>1] + 1;
  17. }
  18. bool cmp(int* r, int a, int b, int l) { return r[a] == r[b] && r[a+l] == r[b+l]; }
  19. void init(int* r, int* rk, int* h, int n, int m) {
  20. int* x=wa, *y=wb, *t, i, j, p;
  21. for (i = 0; i < m; ++i) wt[i] = 0;
  22. for (i = 0; i < n; ++i) ++wt[x[i] = r[i]];
  23. for (i = 1; i < m; ++i) wt[i] += wt[i - 1];
  24. for (i = n-1; i >= 0; --i) sa[--wt[x[i]]] = i;
  25. for (j = 1, p = 1; p < n; j <<= 1, m = p) {
  26. for (p = 0, i = n-j; i < n; ++i) y[p++] = i;
  27. for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
  28. for (i = 0; i < n; ++i) wv[i] = x[y[i]];
  29. for (i = 0; i < m; ++i) wt[i] = 0;
  30. for (i = 0; i < n; ++i) ++wt[wv[i]];
  31. for (i = 1; i < m; ++i) wt[i] += wt[i - 1];
  32. for (i = n-1; i >= 0; --i) sa[--wt[wv[i]]] = y[i];
  33. t = x, x = y, y = t, x[sa[0]] = 0;
  34. for (p = 1, i = 1; i < n; ++i) x[sa[i]] = cmp(y, sa[i], sa[i-1], j) ? p - 1 : p++;
  35. }
  36. for (i = 0; i < n; ++i) rk[sa[i]] = i;
  37. int k = 0;
  38. for (i = 0; i < n - 1; h[rk[i++]] = k) {
  39. for (k = k ? --k : 0, j = sa[rk[i] - 1]; r[i+k] == r[j+k]; ++k);
  40. }
  41. }
  42. void rmq1(int* a, int (*mn)[20], int n) {
  43. for (int i = 1; i <= n; ++i) mn[i][0] = a[i];
  44. for (int j = 1; bin[j] <= n; ++j) {
  45. for (int i = 1; i+bin[j-1]-1 <= n; ++i) {
  46. mn[i][j] = min(mn[i][j-1], mn[i+bin[j-1]][j-1]);
  47. }
  48. }
  49. }
  50. void rmq2(int* a, rmqNode (*mn)[20], int n) {
  51. for (int i = 1; i <= n; ++i) mn[i][0] = {a[i-1], i};
  52. for (int j = 1; bin[j] <= n; ++j) {
  53. for (int i = 1; i+bin[j-1]-1 <= n; ++i) {
  54. if (mn[i][j-1].val <= mn[i+bin[j-1]][j-1].val) mn[i][j] = mn[i][j-1];
  55. else mn[i][j] = mn[i+bin[j-1]][j-1];
  56. }
  57. }
  58. }
  59. int query1(int (*mn)[20], int l, int r) {
  60. int k = Log[r-l+1];
  61. return min(mn[l][k], mn[r-bin[k]+1][k]);
  62. }
  63. int query2(rmqNode (*mn)[20], int l, int r) {
  64. int k = Log[r-l+1];
  65. return mn[l][k].val < mn[r-bin[k]+1][k].val ? mn[l][k].p : mn[r-bin[k]+1][k].p;
  66. }
  67. int match(int* rk, int (*mn)[20], int p, int len) {
  68. int rk1 = rk[p], rk2 = rk[p+len];
  69. if (rk1 > rk2) swap(rk1, rk2);
  70. return query1(mn, rk1+1, rk2);
  71. }
  72. void work() {
  73. int tot1=0, tot2=0, m=0, len=strlen(s);
  74. for (int i = 0; i < len; ++i) m = max(r1[tot1++] = s[i], m); r1[tot1++] = 0;
  75. for (int i = len-1; i >= 0; --i) r2[tot2++] = s[i]; r2[tot2++] = 0;
  76. rmqInit(len);
  77. init(r1, rk1, h1, tot1, ++m);
  78. init(r2, rk2, h2, tot2, m);
  79. rmq1(h1, mn1, len);
  80. rmq1(h2, mn2, len);
  81. rmq2(rk1, mn, len);
  82. node ans = {1,0,0};
  83. for (int l = 1; l <= len; ++l) {
  84. int lim = len / l, upp;
  85. if (ans.val > lim+1) break;
  86. if (len % l) upp = lim; else upp = lim-1;
  87. for (int i = 0; i < upp; ++i) {
  88. int ri = match(rk1, mn1, i*l, l),
  89. le = i ? match(rk2, mn2, len-(i+1)*l, l) : 0,
  90. k = le + ri;
  91. int cnt = k/l + 1;
  92. if (cnt >= ans.val) {
  93. int l1 = i*l-le, l2 = l1+k%l,
  94. p = query2(mn, l1+1, l2+1)-1;
  95. if (cnt > ans.val || rk1[p]<rk1[ans.pos]) ans = {cnt, p, cnt*l};
  96. }
  97. }
  98. }
  99. printf("Case %d: ", ++kas);
  100. if (ans.val == 1) {
  101. char ch='z'+1; for (int i = 0; s[i]; ++i) ch = min(ch, s[i]);
  102. putchar(ch); puts("");
  103. }
  104. else {
  105. s[ans.pos+ans.len] = '\0';
  106. puts(s+ans.pos);
  107. }
  108. }
  109. int main() {
  110. while (scanf("%s", s) != EOF && s[0]!='#') work();
  111. return 0;
  112. }

poj 3693 Maximum repetition substring 重复次数最多的连续子串的更多相关文章

  1. 【POJ 3693】Maximum repetition substring 重复次数最多的连续重复子串

    后缀数组的论文里的例题,论文里的题解并没有看懂,,, 求一个重复次数最多的连续重复子串,又因为要找最靠前的,所以扫的时候记录最大的重复次数为$ans$,扫完后再后从头暴力扫到尾找重复次数为$ans$的 ...

  2. POJ - 3693 Maximum repetition substring(重复次数最多的连续重复子串)

    传送门:POJ - 3693   题意:给你一个字符串,求重复次数最多的连续重复子串,如果有一样的,取字典序小的字符串. 题解: 比较容易理解的部分就是枚举长度为L,然后看长度为L的字符串最多连续出现 ...

  3. POJ 3693 Maximum repetition substring(连续重复子串)

    http://poj.org/problem?id=3693 题意:给定一个字符串,求重复次数最多的连续重复子串. 思路: 这道题确实是搞了很久,首先枚举连续子串的长度L,那么子串肯定包含了r[k], ...

  4. POJ 3693 Maximum repetition substring(后缀数组)

    Description The repetition number of a string is defined as the maximum number R such that the strin ...

  5. POJ 3693 Maximum repetition substring(后缀数组+ST表)

    [题目链接] poj.org/problem?id=3693 [题目大意] 求一个串重复次数最多的连续重复子串并输出,要求字典序最小. [题解] 考虑错位匹配,设重复部分长度为l,记s[i]和s[i+ ...

  6. 后缀数组 POJ 3693 Maximum repetition substring

    题目链接 题意:给定一个字符串,求重复次数最多的连续重复子串. 分析:(论文上的分析)先穷举长度 L,然后求长度为 L 的子串最多能连续出现几次.首先连续出现 1 次是肯定可以的,所以这里只考虑至少 ...

  7. POJ 3693 Maximum repetition substring(最多重复次数的子串)

    Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10461   Ac ...

  8. poj 3693 Maximum repetition substring (后缀数组)

    其实是论文题.. 题意:求一个字符串中,能由单位串repeat得到的子串中,单位串重复次数最多的子串.若有多个重复次数相同的,输出字典序最小的那个. 解题思路:其实跟论文差不多,我看了很久没看懂,后来 ...

  9. POJ 3693 Maximum repetition substring ——后缀数组

    重复次数最多的字串,我们可以枚举循环节的长度. 然后正反两次LCP,然后发现如果长度%L有剩余的情况时,答案是在一个区间内的. 所以需要找到区间内最小的rk值. 两个后缀数组,四个ST表,$\Thet ...

随机推荐

  1. jenkins+svn+pipeline+kubernetes部署java应用(三)

    将jar包.Dockerfile.kubernetes部署yaml文件上传至svn自定义目录 一.生成流水线脚本 二.配置jenkins pipeline构建语句 三.点击构建java工程

  2. 【CSS】非常简单的css实现div悬浮页面底部

    <div id="demo_div"></div> <style> #demo_div{ left:; position: fixed; bot ...

  3. MySQL批量插入大量数据方法

    在MySQL数据库中,如果要插入上百万级的记录,用普通的insert into来操作非常不现实,速度慢人力成本高,推荐使用Load Data或存储过程来导入数据,我总结了一些方法分享如下,主要基于My ...

  4. python各种操作列表的方法及案例

    一.循环的使用方法 names = ["张真","刘德华","哈林","谢霆锋","张柏芝"] fo ...

  5. JZOJ 4738. 神在夏至祭降下了神谕 DP + 线段树优化

    4738. 神在夏至祭降下了神谕 Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed Limits   Goto ProblemSet D ...

  6. jQuery的select2下拉框的搜索功能(使用select2插件,方便简单)

    第一步: 引入我们用使用的插件 jquery: select2: css: js: 第二步: 创建一个html页面,body内容: <div> <select class=" ...

  7. linux的发展过程

    1. 操作系统 人与计算机硬件直接的中介 2. Linux系统组成 3. Linux的发展过程 蛋-人-人-人 unix于诞生贝尔实验室 人-谭教授 谭宁邦 minix mini unix. 主要用于 ...

  8. Birthday Paradox

    Birthday Paradox Sometimes some mathematical results are hard to believe. One of the common problems ...

  9. Eclipse 读取config目录下文件

    最近在一个项目,在项目下新建了一个config配置文件夹,添加一个配置文件config.properties. 使用classpath:config.properties方式加载配置文件, 具体实现代 ...

  10. 高亮T4模板

    http://t4-editor.tangible-engineering.com/Download_T4Editor_Plus_ModelingTools.html