题目描述
瓜瓜特工接到了一个新任务——保护CB直到毕业。 于是瓜瓜就装作实验室的集训队员潜伏在集训队,同时暗中保护CB的安全,并装弱让CB不要对ACM丧失信心。 某天早上,瓜瓜发现CB不在实验室,便打了个电话。 电话接通了,但是电话那头传来了陌生男人的声音。 “CB现在在我们手上,嘿嘿嘿♂ ……”。电话那头说完这句话就挂断了。 “CB!!!”瓜瓜大喊。 冷静下来的瓜瓜,发现了 CB 留下的纸条,上面的答案就是 CB 所在位置(聪明的 CB 自然不可能白白被抓走)。 rbq("wobeihuairenzhuazoulewwwkuailaijiuwoguagua")
这个rbq(string)
之前跟瓜瓜讲过 LSP 库里的一个函数。
这个函数的参数是一个字符串,返回的是 string
中子串的最大循环次数。
CB 为了不让坏人发现,把这个字符串用很多无用的字符填充了起来。但是字符串太长了,瓜瓜根本无法肉眼看出来。
于是瓜瓜找到了你,希望你能写个程序告诉他 CB 所在位置。
输入描述
第一行包含一个整数 T T T,代表总共有 T ( 1 ≤ T ≤ 1 0 3 ) T(1≤T≤10^3) T(1≤T≤103)组字符串。
接下来 T T T行,每行包含一个长度小于 5 ∗ 1 0 3 5∗10^3 5∗103的字符串,字符串仅包含大小写字母与数字。数据保证 ∑ ∣ s t r i n g ∣ ≤ 5 ∗ 1 0 3 ∑|string|≤5∗10^3 ∑∣string∣≤5∗103
输出描述
每一组输出一个整数,代表rbq(str)
样例输入
2
psdababab2345
avabcdad
样例输出
3
1
说明
rbq(psdababab2345)=3
因为子串 ababab
有循环节 ab
,并且循环了 3次,所以答案为 3。
rbq(avabcdad)=1
, 因为任何一个子串都没有循环次数超过 1的循环节,所以答案为 1。
解题思路
思路很容易想到:
三重循环:1)尝试每一种长度;2)尝试每一个起始位置;3)循环匹配。
for (int i = 1; i <= (len + 1 >> 1); i++) {
for (int j = 1; j <= len - i + 1; j++) {
/* 获取子串 */;
int temp = 1, k = j + i;
while (k <= len - i + 1 && /* 循环匹配 */) {
temp++;
k += i;
}
ans = max(ans, temp);
}
}
(没错就是这么简单粗暴,没有高级的算法)
很明显我们需要多次访问字符串,采用正常的方式会产生很大的开销,所以我们采用字符串哈希。
哈希算法就是将一个元素用一个索引来表示,字符串哈希也是如此,将每一个子串用一个索引表示。
这里推荐一篇博客,来自CSDN博主FoLiaGe丶:字符串哈希【算法】(绝对不是因为我懒得写一遍)
AC代码如下:
#include <iostream>
using namespace std;
const unsigned long long base = 13131;
const int max_len = 5e3;
unsigned long long arr[max_len + 1], power[max_len + 1];
unsigned long long get_hash(int l, int r) {
return arr[r] - arr[l - 1] * power[r - l + 1];
}
int main() {
power[0] = 1;
for (int i = 1; i <= max_len; i++) {
power[i] = power[i - 1] * base;
}
int t;
cin >> t;
while (t--) {
string str;
cin >> str;
int len = str.size();
for (int i = 1; i <= len; i++) {
arr[i] = arr[i - 1] * base + (unsigned long long)(str[i - 1]);
}
int ans = 1;
for (int i = 1; i <= (len + 1 >> 1); i++) {
for (int j = 1; j <= len - i + 1; j++) {
unsigned long long hash = get_hash(j, j + i - 1);
int temp = 1, k = j + i;
while (k <= len - i + 1 && hash == get_hash(k, k + i - 1)) {
temp++;
k += i;
}
ans = max(ans, temp);
}
}
cout << ans << endl;
}
return 0;
}