算法竞赛进阶指南---0x15 (KMP) Period

题面

在这里插入图片描述
在这里插入图片描述

题解

在这里插入图片描述

看数据范围,如果使用暴力,双重循环n2 ,字符串长度是1e6 ,肯定会超时,下面讲解正确解法

  1. 首先要知道KMP的 ne[i]=j 以i为终点的后缀和从1开始的前缀最大重合是j(蓝色部分的长度)
  2. 我们可以发现,区间1和区间2,3的字符串是相等的,然后继续划分,使 1 = 4 ,然后 自然 4 = 5 ,5 = 6 ,6 = 7 …一直这样划分,就可以划分出长度为 i -ne[i] 的区间 满足循环
  3. 循环长度已经确定,怎样保证它就是最小的呢(只有区间长度最小,才能划分出更多),如果这个长度不是最小,还可以更小,那么这个子字符串的ne[i]就会相应的增大,就互相矛盾
  4. 我们只需要判断这个循环的长度是否满足条件即可,循环区间肯定大于1个,所以长度肯定小于i,其次就是这个长度必须能被i整除

代码

#include<bits/stdc++.h>

using namespace std;
const int N = 1e6 + 10;

int n;
char p[N];
int ne[N];

int main() {

    int t = 0;
    while (cin >> n && n) {
        for (int i = 1; i <= n; i++) cin >> p[i];
        for (int i = 2, j = 0; i <= n; i++) {
            while (j && p[i] != p[j + 1]) {
                j = ne[j];
            }
            if (p[i] == p[j + 1]) {
                j++;
            }
            ne[i] = j;
        }
        cout << "Test case #" << ++t << endl;

        for (int i = 2; i <= n; i++) {
            int len=i-ne[i];
            if(len!=i&&i%len==0){
                cout<<i<<" "<<i/len<<endl;
            }
        }
        cout << endl;
    }


    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值