HDU 1358 Period【KMP】

题意: 一个字符串,从头到某个位置,字符串的前缀最多重复了多少次。

转一相关讲解:

kmp next函数 kmp的周期问题,深入了解kmp中next的原理

-----------------------

-----------------------

 k    m        x      j       i

由上,next【i】=j,两段红色的字符串相等(两个字符串完全相等),s[k....j]==s[m....i]

设s[x...j]=s[j....i](xj=ji)

则可得,以下简写字符串表达方式

kj=kx+xj;

mi=mj+ji;

因为xj=ji,所以kx=mj,如下图所示

 

-------------

      -------------

 k   m        x     j   

看到了没,此时又重复上面的模型了,kx=mj,所以可以一直这样递推下去

所以可以推出一个重要的性质len-next[i]为此字符串的最小循环节(i为字符串的结尾),另外如果len%(len-next[i])==0,此字符串的最小周期就为len/(len-next[i]);

 

 

求给定字符串含前缀的数量

abab

前缀为

a

ab

aba

abab

abab中共有六个子串是前缀a a ab ab aba abab

所以答案为6

利用kmp中的匹配原理可以完美的解决此题

 a---------d-----

   -----a---------d

               i         j

如上所示,假设两串字符完全相等,next[j]=i,代表s[1...i]==sum[j-i+1....j],这一段其实就是前缀

i~j之间已经不可能有以j结尾的子串是前缀了,不然next【j】就不是 i 了

设dp【i】:以string[i]结尾的子串总共含前缀的数量

所以dp[j]=dp[i]+1,即以i结尾的子串中含前缀的数量加上前j个字符这一前缀

View Code
#include<stdio.h>
#include<string.h>
char m[1000002];
int next[1000002];
int n;
void get()
{
    int i=0,j=-1;
    next[0]=-1;
    while(i<n)
    {
        if(j==-1||m[i]==m[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else j=next[j];
    }
}
int main()
{
    int k,i,ca=1;
    while(scanf("%d",&n),n)
    {
        scanf("%s",m);
        get();
        printf("Test case #%d\n",ca++);
        for(i=2;i<=n;i++)
        {
            k=i-next[i];
            if(i%k==0&&i/k>1)
                printf("%d %d\n",i,i/k);
        }
        printf("\n");
    }
}

 

posted @ 2012-04-26 00:45  'wind  阅读(215)  评论(0编辑  收藏  举报