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串中某个子串连续循环次数最多的次数. 想法: 从暴力开始,枚举所有串,求出 ...
随机推荐
- UVALive 7501 Business Cycle
细心题 #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) # ...
- 【shell】Shell变量基础及深入
1. 什么是变量 变量就是用一个固定的字符串(也可能是字符数字等的组合),替代更多更复杂的内容,这个内容里可能还会包含变量和路径,字符串等其他内容. 变量的定义是存在内存中. x=1 y=2 2. 变 ...
- Linux命令(4):touch
功能说明: touch命令参数可创建新文件以及更改文档或目录的日期时间,包括存取时间和更改时间. 命令格式: touch [选项]... 文件... 命令参数: -a 或--time=atime或 ...
- Linux下必知必会文件和目录
转载于:https://blog.51cto.com/xiyuxingxia/2372712
- js数组排序和打乱
js数组根据不同的业务需求,会要求数组有序或者无序,记录一下流传较广,通用性较强的排序和乱序方法. 数组排序: arr.sort(function(a,b){//从小到大 return a-b;[re ...
- MySQL - Show Global Status 整理
2019独角兽企业重金招聘Python工程师标准>>> MySQL - Show Global Status 整理 原文来源:MySQL 5.5 Reference Manual 部 ...
- Bomb Enemy 炸弹人
Given a 2D grid, each cell is either a wall 'W', an enemy 'E' or empty '0' (the number zero), return ...
- INTERVIEW #0
一.造成网络延迟的可能原因 1,WiFi所有用户上下行流量共用一个信道,当用户太多或者有人在下载大的资源时带宽不够,丢包: 2,线路质量不佳导致信噪比太低,比如光纤损耗太大等. 二.IPv6优势 1, ...
- 蓝色展开收缩悬浮QQ客服代码
放在我的博客首页上的的预览图: 在文章区的预览图如下: 代码如下: <div class="scrollsidebar" id="scrollsidebar&quo ...
- B. Modulo Sum dp
https://codeforces.com/contest/577/problem/B 先读懂题意,substring 这个是子串说明不可以跳 subsequence这个是子序列可以跳 这个题目是一 ...