[1,2...,m] 模板的前缀Pi 的循环节为  clc = i-next[i]   

i % clc == 0 && i != clc  则表示前缀中有 k = i / clc 个循环

 

完全是参考代码模板:

代码如下:

#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#define N 1000005
using namespace std;
char P[N];
int m;
int next[N];
 void Prefix_Func()
 {
     int i,k;
     k=0;
     next[1]=0;
     for(i=2;i<=m;i++)
     {
        while(k>0 && P[k+1]!= P[i])
            k=next[k];
        if(P[k+1] == P[i])
            k++;
        next[i]=k;
     }
 }
int main()
{
    int t=1,clc;

    while(scanf("%d",&m) && m)
    {
        scanf("%s",P+1);
        Prefix_Func();
        cout<<"Test case #"<<t++<<endl;
        for(int i=2;i<=m;i++)
        {
            clc=i-next[i];
            if(i%clc == 0 && i!=clc)
                cout<<i<<" "<<i/clc<<endl;
        }
        cout<<endl;
    }
    return 0 ;
}

 

poj 2406

求字符串有几个周期

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

 

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

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

k    m        x      j       i

k=0.

由上,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]);否则,最小周期为1,。

 

代码如下:

const int Max_N = 1000005;
// 求后缀数组, 求循环节时只能模式下标从1开始,
int next[Max_N];
char P[Max_N];
int m;
void prefix(){
    int i, k=0;
    next[1]=0;
    for(i =2 ; i<= m ; i++){
        while(k>0 && P[k+1] != P[i])
            k=next[k];
        if(P[k+1] == P[i]) k++;
        next[i] = k;
    }
}
int main(){
    while(scanf("%s",P+1) )
    {
        if(P[1] == '.')  break;
        m= strlen(P+1);
        prefix();
        if(m % (m - next[m]) ==0)  printf("%d\n", m / (m - next[m]) );
        else   printf("1\n");
    }
}

 另一份代码为:

 

int next[1000005];

int kmp_next(char *pat)
{
    int i=0,j=-1;
    next[0]=-1;
    int len = strlen(pat);
    while(i<len)
    {
        if(j==-1||pat[i]==pat[j])
            next[++i]=++j;
        else
            j=next[j];
    }
    i=len - j;
    if(len%i==0)
        return len / i;
    else
        return 1;
}

int main()
{
    char s[1000005];
    while(scanf("%s",s)!=EOF)
    {
        if(s[0]=='.')
            break;
        printf("%d\n",kmp_next(s));
    }
    return 0;
}