题意 :
给一个字符串 S 和整数 D , 要把 S 分割成若干段, 使得每段的周期 ≤ D , 求最少的分割段数
题解 :
首先考虑贪心, 首先考虑以S[1]开头的最长的子串, 其周期 ≤ D, 然后把这一段取出来, pop_front掉, 然后重复这个过程, 现在的问题就是变成了怎么找到以S[i]开头的最长的子串使得其周期 ≤ D, 这里推荐使用 Kmp 算法, 不妨设 fail 指针为 link[] 数组, 然后我们知道 n-link[n] 就是长度为 n 的串的最小周期, 并且这个值会随着 n 的增大单调不减, 于是我们只需要考虑以 S[i] 开始跑 Kmp 算法, 直到某个位置的周期>D 就停下即可, 以下是带注释的C++代码
const int N = 4e5 + 20; // 两倍空间防止RE
int link[N];
int kmp(char *s, int lim) {
for (int i = 1, j = 0;; i++) { // KMP
while (j and s[i] != s[j])
j = link[j - 1];
j += (s[i] == s[j]);
link[i] = j;
if (i - j + 1 > lim) // 周期(i-j+1)不能大于lim
return i; // 返回周期小于等于lim的最大长度
}
}
char s[N];
int main() {
int n, d, ans = 0;
std::cin >> s >> d;
n = strlen(s);
for (int i = 0; i < n;) {
ans++;
i += kmp(&s[i], d); // 贪心跳跃
}
std::cout << ans;
}