一、题目描述
Description
我们都知道哈希是一个很有趣的数据处理方式,尤其是水题的时候23333。
比如我们可以使用哈希加二分在nlogn的复杂度下解决O(n)的马拉车题目,
再比如我们可以在同样O(n)的复杂度下解决一部分KMP问题,
再比如我们可以在O(nlognlogn)的复杂度下解决O(nlogn)的后缀数组题目…
现在给你若干个字符串,需要你找到每个字符串最大的循环节。(KMP裸题+小声bb
Input
T组数据。(T<20)
每组一个字符串。长度小于1e6。
Output
对于每个字符串都在独立一行输出最大的循环节长度
Sample Input Copy
3
abcd
ababab
aaaaa
Sample Output Copy
1
3
5
一、题目思路
题目的意思给你一个字符串,让你找出它是由多少个相同的子串构成的,输出该子串的最大个数。
1、字符串哈希
处理串的哈希值遍历每次遍历跑就成,具体细节看代码,也就懂了。然后下面是一个单哈希的简单模板(蒟蒻)
#include <iostream>
#include <string>
using namespace std;
const int n = 1e5 + 7;
const int base = 133; //p为将字符转化为数字的进制数,一般为质数
unsigned long long h[n]; //hash数组,记录值,使用unsigned long long 会自动溢出,取模
unsigned long long p[n]; //预处理p的n次方
char s[n];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> s + 1; //从下标为1开始读
int len = strlen(s + 1);
h[0] = 0;
for (int i = 1; i <= len; i++) {
h[i] = (h[i - 1] * base) + s[i];
}
//abcdef
//对应的映射值(哈希值)
//a-228 ab-29966 abc-3925645 abcd-514259595 abcde-67368007046 abcdef-8825208923128
for (int i = 1; i <= len; i++) {
cout << h[i] << " ";
}
cout << endl;
//求子串的hash值 [L,R] 闭区间 1 <= L <= R <= N
//hash = hash[R] - hash[L - 1] *p[R - L + 1]
return 0;
}
//不对的请斧正
2、kmp
这个博主写得超级好,可以看这边文章学习kmp
链接: kmp的详解.
使用next数组简单过
三、AC代码
1、哈希做法
#include <iostream>
#define uzl unsigned long long
using namespace std;
const int base = 133;
const int M_X = 1e6 + 10;
uzl p[M_X], h[M_X];
char s[M_X];
int t, len;
uzl get_h(int L, int R) { //计算区间L到R的哈希值
return h[R] - h[L - 1] * p[R - L + 1];
}
bool check(int x) { //计算X相邻串的哈希值
for (int i = 2 * x; i <= len; i += x) {
if (h[x] != get_h(i - x + 1, i))
return false;
}
return true;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> t;
while (t-- && cin >> s + 1) { //从1开始读
len = strlen(s + 1);
h[0] = 0, p[0] = 1; //预处理
for (int i = 1; i <= len; i++) {
h[i] = h[i - 1] * base + s[i]; //哈希函数
p[i] = p[i - 1] * base; //处理p的乘方,方便公式计算
}
for (int i = 1; i <= len; i++) {
if (len % i == 0 && check(i)) {
cout << len / i << endl;
break;
}
}
}
return 0;
}
2、kmp做法
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int M_X = 1e6 + 7;
int t,len,ans, nnext[M_X];
char s[M_X];
void get_next()
{
nnext[1] = 0;
int j = 1, k = 0;
while (j <= len) {
if (k == 0 || s[j] == s[k]){
k++;
j++;
nnext[j] = k;
}else{
k = nnext[k];
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> t;
while (t-- && cin >> s + 1) {
len = strlen(s + 1);
ans = 0;
get_next();
ans = len / (len + 1 - nnext[len + 1]);
if (len % (len + 1 - nnext[len + 1]) == 0)
cout << ans << endl;
else
cout << "1" << endl;
}
return 0;
}