SPOJ687 Repeats
本篇是罗穗骞《后缀数组——处理字符串的有力工具》的读书笔记。
知识点: 后缀数组、RMQ
解题思路:
枚举长度 \(L\),然后检查长度为 \(L\) 的子串最多能连续重复几次。
对于给定的字符串 \(S\),我们只关注其上坐标为 \(0, L, 2L, ......\) 的点。
如果连续重复子串的首字符恰好在这些点上,那么连续重复子串出现的次数恰好是 \( \frac{lcp(L_1, L_2)}{L} + 1\),(注:\(lcp\) 为 Longest Common Prefix 的简写),如图 1 所示;
否则,我们先计算出 \(lcp(L_1, L_2)\) 中 模 \( L\) 后余下的长度 \(L'\),如图 2 中橙色圈里的片段,可以推测出连续重复子串真正的首字符位于 \( pos = L_1 - (L - L')\),如果 \(0 \le pos\),则连续重复子串出现的次数为:\( \frac{lcp(pos, pos+L)}{L} + 1\)。
记录出现的最多次数,即为答案。最长公共前缀的查询要用 RMQ 优化。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm> using namespace std;
const int maxn = + , inf = 0x7fffffff;
int len, tk;
int Rank[maxn], tmp[maxn];
int S[maxn];
int sa[maxn], lcp[maxn]; bool compare_sa(int i, int j) {
if (Rank[i] != Rank[j]) return Rank[i] < Rank[j];
else {
int ri = i + tk <= len ? Rank[i + tk] : -;
int rj = j + tk <= len ? Rank[j + tk] : -;
return ri < rj;
}
} void construct_sa() {
for (int i = ; i <= len; i++) {
sa[i] = i;
Rank[i] = i < len ? S[i] : -;
} for (tk = ; tk <= len; tk *= ) {
sort(sa, sa + len + , compare_sa);
tmp[sa[]] = ;
for (int i = ; i <= len; i++) {
tmp[sa[i]] = tmp[sa[i - ]] + (compare_sa(sa[i - ], sa[i]) ? : );
}
for (int i = ; i <= len; i++) {
Rank[i] = tmp[i];
}
}
} void construct_lcp() {
int h = ;
lcp[] = ;
for (int i = ; i < len; i++) {
int j = sa[Rank[i] - ]; if (h > ) h--;
for (; j + h < len && i + h < len; h++) {
if (S[j + h] != S[i + h]) break;
}
lcp[Rank[i] - ] = h;
}
} int RMQ[maxn];
int mm[maxn], best[][maxn];
void initRMQ(int n) {
mm[] = -;
for (int i = ; i <= n; i++)
mm[i] = ((i&(i - )) == ) ? mm[i - ] + : mm[i - ];
for (int i = ; i <= n; i++) best[][i] = i;
for (int i = ; i <= mm[n]; i++) {
for (int j = ; j + ( << i) - <= n; j++) {
int a = best[i - ][j];
int b = best[i - ][j + ( << (i - ))];
if (RMQ[a] < RMQ[b]) best[i][j] = a;
else
{
best[i][j] = b;
}
}
}
}
int askRMQ(int a, int b) {
int t;
t = mm[b - a + ];
b -= ( << t) - ;
a = best[t][a]; b = best[t][b];
return RMQ[a] < RMQ[b] ? a : b;
}
int find_lcp(int a, int b) {
if (a>b) swap(a, b);
return lcp[askRMQ(a, b - )];
}
int main()
{
char inp[];
int H;
scanf("%d", &H);
while (H--) {
scanf("%d", &len);
for (int i = ; i<len; i++) {
scanf("%s", inp);
if (inp[] == 'a') S[i] = ;
else S[i] = ;
}
construct_sa();
construct_lcp();
for (int i = ; i <= len; i++) RMQ[i] = lcp[i];
initRMQ(len);
int ans = ;
for (int i = ; i <= len; i++) {
int ret = ;
for (int j = ; j + i<len; j += i) {
int r1 = Rank[j], r2 = Rank[j + i];
int L = find_lcp(r1, r2);
int temp = L / i + ;
int k = j - (i - L%i);
if (k >= ) {
temp = find_lcp(Rank[k], Rank[k + i]) / i + ;
}
ret = max(ret, temp);
}
ans = max(ans, ret);
}
printf("%d\n", ans);
}
return ;
}
SPOJ687 Repeats的更多相关文章
- spoj687 REPEATS - Repeats (后缀数组+rmq)
A string s is called an (k,l)-repeat if s is obtained by concatenating k>=1 times some seed strin ...
- spoj687 后缀数组重复次数最多的连续重复子串
REPEATS - Repeats no tags A string s is called an (k,l)-repeat if s is obtained by concatenating k& ...
- SPOJ REPEATS 后缀数组
题目链接:http://www.spoj.com/problems/REPEATS/en/ 题意:首先定义了一个字符串的重复度.即一个字符串由一个子串重复k次构成.那么最大的k即是该字符串的重复度.现 ...
- SPOJ 687 Repeats(后缀数组+ST表)
[题目链接] http://www.spoj.com/problems/REPEATS/en/ [题目大意] 求重复次数最多的连续重复子串的长度. [题解] 考虑错位匹配,设重复部分长度为l,记s[i ...
- 687. Repeats spoj (后缀数组 重复次数最多的连续重复子串)
687. Repeats Problem code: REPEATS A string s is called an (k,l)-repeat if s is obtained by concaten ...
- spoj687(后缀数组)
http://www.spoj.com/problems/REPEATS/ 题意:给一串字符,需要你求这一串字符中有连续重复的字符的重复次数....... 思路:这是和poj3693一种类型的题目.. ...
- SPOJ Repeats(后缀数组+RMQ-ST)
REPEATS - Repeats no tags A string s is called an (k,l)-repeat if s is obtained by concatenating k& ...
- SPOJ - REPEATS —— 后缀数组 重复次数最多的连续重复子串
题目链接:https://vjudge.net/problem/SPOJ-REPEATS REPEATS - Repeats no tags A string s is called an (k,l ...
- Spoj REPEATS 后缀自动机+set
REPEATS - Repeats 链接:http://www.spoj.com/problems/REPEATS 题意:求S串中某个子串连续循环次数最多的次数. 想法: 从暴力开始,枚举所有串,求出 ...
随机推荐
- Spring Boot Starters介绍
文章目录 Web Start Test Starter Data JPA Starter Mail Starter 结论 对于任何一个复杂项目来说,依赖关系都是一个非常需要注意和消息的方面,虽然重要, ...
- C++操作Kafka使用Protobuf进行跨语言数据交互
C++操作Kafka使用Protobuf进行跨语言数据交互 Kafka 是一种分布式的,基于发布 / 订阅的消息系统.主要设计目标如下: 以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对 T ...
- MYSQL隔离级别 与 锁
1.四种隔离级别下数据不一致的情况 脏读 不可重复读 幻读 RU 是 是 是 RC(快照读) 否 是 是 RC(当前读) 否 否 是 RR(快照读) 否 否 是 RR(当前读) 否 否 否 Ser ...
- 澳大利亚公共服务部门神速完成Win10部署:4个月完成44000台设备升级
不到一年时间,澳大利亚公共服务部门已经完成Win10系统部署升级,涉及到全部的35000名员工.在2015年,澳大利亚公共服务部门IT员工告知微软,需要更创新的方式远程为居民提供服务,并且效率要更快. ...
- 搭建Springboot+mybatis+redis+druid
2019独角兽企业重金招聘Python工程师标准>>> 准备工作 JDK:1.8 使用技术:SpringBoot.Dubbo.Mybatis.Druid 开发工具:Intelj ID ...
- Extmail邮件过滤和杀毒
前面整合好了extmail,不过没有测试使用foxmail这种客户端去测试收发邮件功能,今天测试的时候发现了蛮多问题,大部分和/etc/authmysqlrc这个文件的配置和权限相关,都是小问题,折腾 ...
- [bzoj5329] P4606 [SDOI2018]战略游戏
P4606 [SDOI2018]战略游戏:广义圆方树 其实会了圆方树就不难,达不到黑,最多算个紫 那个转换到圆方树上以后的处理方法,画画图就能看出来,所以做图论题一定要多画图,并把图画清楚点啊!! 但 ...
- B. Heaters 思维题 贪心 区间覆盖
B. Heaters 这个题目虽然只有1500的分数,但是我还是感觉挺思维的,我今天没有写出来,然后看了一下题解 很少做这种区间覆盖的题目,也不是很擅长,接下来讲讲我看完题解后的思路. 题目大意是:给 ...
- A. A Twisty Movement dp
https://codeforces.com/problemset/problem/933/A 这个是一个dp,但是我并没有看出来,然后也不太会写, 这种题一般应该要想到先预处理前缀和后缀,然后再进行 ...
- spring学习笔记(三)我对AOP理解
首先我们要知道AOP是什么?AOP全称Aspect OrientedProgramming,即面向切面编程.在这里我不想去说什么是切面,什么是切点,什么是通知等等,相关博客很多,如果大家想知道可以自己 ...