Description

The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1.

Given a string containing lowercase letters, you are to find a substring of it with maximum repetition number.

Input

The input consists of multiple test cases. Each test case contains exactly one line, which
gives a non-empty string consisting of lowercase letters. The length of the string will not be greater than 100,000.

The last test case is followed by a line containing a '#'.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by the substring of maximum repetition number. If there are multiple substrings of maximum repetition number, print the lexicographically smallest one.

题目大意:给一个字符串,求重复次数最多的连续重复子串,如有多个答案输出字典序最小的。

思路:对于一个由长度为L的字符串重复R次形成的子串,那么对于s[0]、s[L]、s[2*L]……,该子串必然包含其中的两个字符

那么,我们从1~n穷举长度L

对于每一个s[i*L]、s[(i+1)*L]看看它们能往前和往后同时匹配多长

记这个长度为K,那么K/L+1就是可以重复的次数(对于一个字符串如果他是由R个长度为L的字符串重复形成的,那么必然有lcp(suffix(0), suffix(L))==L*(R-1))

然后,从两个点往后匹配好求,但往前匹配就不好办了,虽然可以把字符串反过来再弄一个后缀数组,但是这不够优美。

比较优美的方法就是,对于某个连续重复子串,假设它的包含的最前面的两个是s[i*L]和s[(i+1)*L],设p=L-lcp%L(当lcp mod L ≠ 0)

那么只需要测试lcp(i*L-p, (i+1)*L-p)就行了,因为再往前,重复的次数也不会增加。

然后我们就可以得到最大重复次数了。

但是题目要求的是字典序最小的答案耶……要在算重复次数的时候也算出来好像很有难度(应该说是很麻烦,大概就是DISCUSS里面那个说3个RMQ的人……)

但是,我们再算最大重复次数的时候,把长度也算出来,设为K

那么只要遍历一下字符串,把lcp(i, i + K / R) ≥ K - K / R的找出来,这些都是符合条件的答案开头,因为有后缀数组,直接找rank最小的就行了。

这样,这题就做完了。

代码(313MS):

 #include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std; const int MAXN = ; char s[MAXN];
int sa[MAXN], height[MAXN], rank[MAXN], c[MAXN], tmp[MAXN];
int n; void makesa(int m) {
memset(c, , m * sizeof(int));
for(int i = ; i < n; ++i) ++c[rank[i] = s[i]];
for(int i = ; i < m; ++i) c[i] += c[i - ];
for(int i = ; i < n; ++i) sa[--c[rank[i]]] = i;
for(int k = ; k < n; k <<= ) {
for(int i = ; i < n; ++i) {
int j = sa[i] - k;
if(j < ) j += n;
tmp[c[rank[j]]++] = j;
}
int j = c[] = sa[tmp[]] = ;
for(int i = ; i < n; ++i) {
if(rank[tmp[i]] != rank[tmp[i - ]] || rank[tmp[i] + k] != rank[tmp[i - ] + k])
c[++j] = i;
sa[tmp[i]] = j;
}
memcpy(rank, sa, n * sizeof(int));
memcpy(sa, tmp, n * sizeof(int));
}
} void calheight() {
for(int i = , k = ; i < n; height[rank[i++]] = k) {
if(k > ) --k;
int j = sa[rank[i] - ];
while(s[i + k] == s[j + k]) ++k;
}
} int logn[MAXN];
int best[][MAXN]; void initRMQ() {
logn[] = -;
for(int i = ; i <= n; ++i)
logn[i] = (i & (i - )) == ? logn[i - ] + : logn[i - ];
for(int i = ; i <= n; ++i) best[][i] = height[i];
for(int i = ; i <= logn[n]; ++i) {
int ed = n - ( << i) + ;
for(int j = ; j <= ed; ++j)
best[i][j] = min(best[i - ][j], best[i - ][j + ( << (i - ))]);
}
} int lcp(int a, int b) {
a = rank[a], b = rank[b];
if(a > b) swap(a, b);
++a;
int t = logn[b - a + ];
return min(best[t][a], best[t][b - ( << t) + ]);
} void solve() {
int ans = , ansL = , ansR = ;
for(int i = ; i < n - ; ++i) if(s[i] < s[ans]) ans = i;
for(int i = ; i < n; ++i) {
for(int j = ; j + i < n - ; j += i) {
int t = lcp(j, j + i), p = ;
if(t % i) {
p = i - t % i;
if(j < p) p = ;
t = max(t, lcp(j - p, j + i - p));
}
if(t / i + > ansR || (t / i + == ansR && rank[j] < rank[ans])) {
ans = j - p;
ansR = t / i + ;
ansL = ansR * i;
}
}
}
for(int i = ; i < n - ; ++i)
if(lcp(i, i + ansL / ansR) >= ansL - ansL / ansR && rank[i] < rank[ans]) ans = i;
for(int i = ans; i < ans + ansL; ++i) putchar(s[i]);
puts("");
} int main() {
int kase = ;
while(scanf("%s", s) != EOF) {
if(*s == '#') break;
n = strlen(s) + ;
makesa();
calheight();
initRMQ();
printf("Case %d: ", ++kase);
solve();
}
}

POJ 3693 Maximum repetition substring(后缀数组)的更多相关文章

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

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

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

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

  3. POJ 3693 Maximum repetition substring (后缀数组+RMQ)

    题意:给定一个字符串,求其中一个由循环子串构成且循环次数最多的一个子串,有多个就输出最小字典序的. 析:枚举循环串的长度ll,然后如果它出现了两次,那么它一定会覆盖s[0],s[ll],s[ll*2] ...

  4. POJ3693 Maximum repetition substring 后缀数组

    POJ - 3693 Maximum repetition substring 题意 输入一个串,求重复次数最多的连续重复字串,如果有次数相同的,则输出字典序最小的 Sample input ccab ...

  5. POJ3693 Maximum repetition substring [后缀数组 ST表]

    Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9458   Acc ...

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

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

  7. Maximum repetition substring 后缀数组

    Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7578   Acc ...

  8. POJ3693 Maximum repetition substring —— 后缀数组 重复次数最多的连续重复子串

    题目链接:https://vjudge.net/problem/POJ-3693 Maximum repetition substring Time Limit: 1000MS   Memory Li ...

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

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

随机推荐

  1. ubnutu 安装protocol buffer

    工作中需要使用protocol buffer,需要编译出protocol buffer的动态链接库,然后在别的makefile中链接它, 我的环境是ubnutu16.04,64bit,使用的proto ...

  2. golang刷Leetcode系列 --- 加1

    加一 给定一个非负整数组成的非空数组,在该数的基础上加一,返回一个新的数组. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. 示例 ...

  3. 判断FreeMarker是否为空

    转自:https://blog.csdn.net/lwt976647637/article/details/73135933 (1)判断Map数据是否为空 <#ifmaster??&&a ...

  4. 一、Vue项目构建

    Attention:以下内容为Mac机上运行,windows可能有所偏差- Step1 打开终端,键入npm install -g vue-cli,使用vue-cli脚手架搭建vue项目能省很多事儿- ...

  5. 大数据学习--day02(标识符、变量、数据类型、类型转换、进制转换、原码反码补码)

    标识符.变量.数据类型.类型转换.进制转换.原码反码补码 标识符: java50个关键字不能做标识符,以数字开头不能做标识符(这个老是忘记写一个类名的时候) 变量: 变量分为成员变量和局部变量,注意作 ...

  6. 虚拟机搭建hadoop的步骤

    1.首先是安装Vmware Workstation,下载地址:https://www.vmware.com/products/workstation-player/workstation-player ...

  7. Python学习:6.python内置函数

    Python内置函数 python内置函数,是随着python解释器运行而创建的函数,不需要重新定义,可以直接调用,那python的内置函数有哪些呢,接下来我们就了解一下python的内置函数,这些内 ...

  8. Java学习笔记十七:Java中static使用方法

    Java中static使用方法 一:Java中的static使用之静态变量: 我们都知道,我们可以基于一个类创建多个该类的对象,每个对象都拥有自己的成员,互相独立.然而在某些时候,我们更希望该类所有的 ...

  9. java 学习知识汇总

    一:常见模式与工具 学习Java技术体系,设计模式,流行的框架与组件是必不可少的: 常见的设计模式,编码必备 Spring5,做应用必不可少的最新框架 MyBatis,玩数据库必不可少的组件 二:工程 ...

  10. 优步UBER司机全国各地奖励政策汇总 (3月21日-3月27日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...