一、题意
有kase组数据(kase<=200)。
每组数据一个字符串(长度<=1000),要求列出该字符串中,包含i个循环节的循环子串的最大长度。
输出列出的答案数组max_cir_len[i].
二、解析
循环节问题考虑使用KMP。
用KMP的Next数组只能求出前缀子串的循环节,而此题要求的是所有子串,因此需要枚举起始点。
考虑时间复杂度O(n^2),不会超时。
三、代码
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
const int maxn = 1000 + 5;
int kase, ans[maxn], Next[maxn];
void getNext(char* p, int m) {
Next[0] = -1;
int i = 0, j = -1;
while(i < m) {
if(j == -1 || p[i] == p[j]) i ++, j ++, Next[i] = j;
else j = Next[j];
}
}
int main() {
cin >> kase;
for(int k = 1; k <= kase; k ++) {
string str;
cin >> str;
int n = str.size();
fill(ans, ans + n + 1, 0);
for(int i = 0; i < n; i ++) {
int len = n - i;
getNext(&str[i], len);
for(int j = 1; j <= len; j ++) {
int p = j;
while(p) {
p = Next[p];
if(p && j % (j - p) == 0) {
int cir_num = j / (j - p);
ans[cir_num] = max(ans[cir_num], j);
}
}
}
}
ans[1] = n;
cout << "Case #" << k << ":";
for(int i = 1; i <= n; i ++) cout << " " << ans[i];
cout << endl;
}
}四、归纳
- 注意KMP算法算出来的循环节长度是最小循环节长度,如果需要算出所有可能循环节长度的话,就要用一个while循环一节一节往回跳+判定,由于往回跳的长度就是循环节的长度,因此实际上这是一个枚举循环节长度的过程。比如字符串aaaa,用KMP算法求出的循环节长度为1,但实际上2也是一个循环节长度,此时就要往回跳+判定来枚举全。
又WA了好久...

京公网安备 11010502036488号