题目描述
给定若干个的字符串,询问每个字符串最多是由多少个相同的子字符串重复连接而成的。如:ababab 最多由 个 ab 连接而成。
输入
输入若干行,每行有一个字符串,字符串仅含英文字母。特别的,字符串可能为.即一个半角句号,此时输入结束。
输出
输出每个字符串最多是由多少个相同的子字符串重复连接而成。
解
处理Kmp值是肯定的。那么如何判断字符串是否符合条件呢?
我们略推一下数据:
…
…
ababab
a | b | a | b | a | b | |
---|---|---|---|---|---|---|
kmp | 0 | 0 | 1 | 2 | 3 | 4 |
abcabc
a | b | c | a | b | c | |
---|---|---|---|---|---|---|
kmp | 0 | 0 | 0 | 1 | 2 | 3 |
abadab
a | b | a | d | a | b | |
---|---|---|---|---|---|---|
kmp | 0 | 0 | 1 | 0 | 1 | 2 |
abadab
a | b | a | b | c | b | |
---|---|---|---|---|---|---|
kmp | 0 | 0 | 1 | 2 | 0 | 1 |
如此,我们可以发现:由重复子串构成的串的性质大概如下:
设一个循环节的长度为 k k k
则从 k + 1 k+1 k+1 位直到结束的 k m p kmp kmp 为 1 , 2 , 3... n − k − 1 , n − k 1,2,3...n-k-1,n-k 1,2,3...n−k−1,n−k 。
易得 k = n − k m p [ n ] k = n-kmp[n] k=n−kmp[n] ,循环节数为 n / k n/k n/k
代码
#include <cstdio>
#include <string>
#include <iostream>
using namespace std;
string a, b;
int j, n, kmp[1000010];
int main() {
cin >> a;
while (a != ".") {
n = a.size();
a = " " + a; //便于处理
kmp[0] = kmp[1] = j = 0;
for (int i = 2; i <= n; ++i) {
while (a[i] != a[j + 1] && j) j = kmp[j];
if (a[i] == a[j + 1])
++j;
kmp[i] = j;
}
if (n % (n - kmp[n]) == 0)
printf("%d\n", n / (n - kmp[n]));
else
printf("1\n");
cin >> a;
}
}