gym 104252 L. Lazy Printing -> 贪心 + Kmp

文章讲述了如何利用KMP算法寻找以S[i]开头的最长子串,使其周期不超过D,从而在保证每段周期不超过D的前提下,最小化字符串S的分割段数。给出了一段C++代码示例来实现这一过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem - L - Codeforces

 题意  : 

给一个字符串 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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值