UVALive 3026 period(周期) kmp算法的应用

周期
     给定一个长度为n的字符串S,求它的每个前缀的最短循环节,换句话说,对于每个i,i属于2到n,求一个最大的整数K>1(如果K存在)使得S的前i个字符组成的前缀是某个字符串重复K次得到的。输出所有存在K的i和对应的K。
样例输入:
12
aabaabaabaab

3
aaa

样例输出:
     Test case #1
2 2
6 2
9 3
12 4

Test case #2
2 2
3 3

解题思路:
这题的要求对Kmp算法有比较熟练的掌握。
对于kmp算法,每次匹配出现错误的时候,他会转移到一个之前的一个状态
这个状态保存在失配函数中(其实就是一个数组)
那么分析这个失配函数

对于例子:aabaabaabaab
处理之后

01234567891011
aabaabaabaab
001012345678

第一行是字符串的字符的位置
第二行是字符
第三行是失配函数
那么分析位置2如果这里发生失配了,要转移到位置1,那么意味着k[1..1] = k[0..0]
接下来分析位置6如果这里发生失配了,要转移到位置3,那么意味着k[3..5] = k[0..2]
再来分析位置9如果这里发生失配了,要转移到位置6,那么意味着k[6..8]=k[3..5]  ;  k[3..8] = k[0..5]

那么仔细观察会发现:失配的位置i减去要转移的位置f[i]就是循环节的长度,那么就要看看,这个循环节的长度是不是能完全覆盖长度i
即i%(i-f[i])是不是等于0的就可以了,如果等于0就意味着我们找到了这个循环节。


#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 1000005 ;
char p[maxn] ;
int f[maxn] ;
int main(){
    int n,kase=0 ;
    while(scanf("%d",&n),n){
        scanf("%s",p);
        f[0] = 0 ;
        f[1] = 0 ;
        for(int i = 1 ;i<n ;i++){
            int j = f[i] ;
            while(j&&p[i]!=p[j])j=f[j] ;
            f[i+1] = (p[i] == p[j]?j+1:0 );
        }
        printf("Test case #%d\n",++kase);
        for(int i = 2;i<=n;i++){
            if(f[i]>0 && i%(i-f[i])==0){
                printf("%d %d\n",i,i/(i-f[i]));
            }
        }
        printf("\n");
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值