题目链接
知识点
KMP算法,最小循环节问题
实现
码前思考
- 典型地利用KMP算法中的
nex
数组求解循环节的问题,之前做过一道相似的题目; - 对于求循环节的问题,主要就是在原始的
getNex
操作之后加入一些操作就好,实质还是利用nex
数组,可见其重要性; - 理解
nex[i]
的含义,其含义是子串s[0...i]
的最长匹配前缀; - 这道题目不允许输出
K==1
的情况,因此需要在循环节的基础代码上,再增加一些限制;
5.循环节的思路:
① 得到理想中的最小循环节长度mod = (len-1) - next[len-1]
,例如对于ababa
的理想mod = 4 - 2 = 2
;
② 使用len%mod
进行判断,如果len%mod==0
,那么最小循环节长度就是mod
,否则最小循环节长度就是len
,舍去。
③由于此题的特殊性,因此要在len%mod==0
之后还要继续判断最小循环节长度是否是len
,是的话得舍去。例如abc
,它的每个循环节都是当前len
得舍去!
代码实现
//使用KMP求解循环节的问题
//需要掌握循环节的公式
#include <cstdio>
#include <cstring>
const int maxn = 1e6+10;
char p[maxn];
int nex[maxn];
int n;
void getNex(){
int len = strlen(p);
nex[0] = -1;
int j = -1;
for(int i=1;i<len;i++){
while(j!=-1&&p[i]!=p[j+1]){
j=nex[j];
}
if(p[i]==p[j+1]){
j++;
}
nex[i] = j;
//下面是判断循环节
int mod = i - nex[i];
if(nex[i]!=-1 && (i+1)%mod == 0){
printf("%d %d\n",i+1,(i+1)/mod);
}
}
}
int main(){
int cnt=0;
while(scanf("%d",&n) && n!=0){
scanf("%s",p);
printf("Test case #%d\n",++cnt);
getNex();
printf("\n");
}
return 0;
}
码后反思
- 还是要特别掌握KMP中
nex
数组的含义; - 一定要背下循环节的计算思路!!!同时要加以一定的理解,直到那两步操作的结果是什么~~