原题:YbtOJ-高效进阶2021-「字符串算法」第3章 KMP 算法-【例题4】
- 做这道题呢,大概是为了更好地理解KMP的结构。
- 每一个字符串呢,都是类似于 A + A + … + A 这种形式的,
不同的是这些字串A的数量以及可能会重叠在一起,
而KMP就是给这些子串打上标记(一开始是为了方便回退用的)。- 对于这道题而言,我们的任务就是判断,首尾两个字串A是否连在一起。是的话排除,否的话答案加一。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
char n[16000], s[16000];
int m, ans, len, k, t, next[16000];
int main() {
scanf("%s", n + 1);
m = strlen(n + 1);
scanf("%d", &t);
for (int i = 1; i <= m; i++) { //不断左调左边界,把所有子串找出来
len = m - i + 1;
for (int j = 1; j <= len; j++)
s[j] = n[i + j - 1]; //复制子串
k = 0; //先跑一遍KMP,把next[]求出来
for (int j = 1; j <= len; j++) {
while (k != 0 && s[j + 1] != s[k + 1])
k = next[k];
if (s[j + 1] == s[k + 1])
k++;
next[j + 1] = k;
}
k = 0;
for (int j = 1; j <= len; j++) {
while (k != 0 && s[j + 1] != s[k + 1])
k = next[k];
if (s[j + 1] == s[k + 1])
k++;
while(k * 2 > j) k = next[k]; //不断调小A
if (k >= t) //A长度必须大于t
ans++;
}
memset(next, 0, sizeof(next));
memset(s, 0, sizeof(s));
}
printf("%d", ans);
}