玄学的KMP算法……
题意是给一个字符串,求最小循环节的循环次数
按kmp的一般思路,我们先来求一个p数组(一般叫next数组),p[i]表示模式串第i位如果和文本串当中某一位不匹配、则需退回p[i]位重新和这一位匹配。
明显地,对于模式串来讲,第1位到第p[n]位和第n-p[n]位到第n位是匹配的。如果n%(n-p[n])=0,那么重复连续子串存在且长度为n-p[n](我会说我根本不懂怎么证明么)
但是还是有大神懂怎么证明的,以下转自Euler_M的博客(http://blog.csdn.net/euler_m/article/details/6281903):
======================================================================
假设有这么一个字符串
如果s[a..b]==s[c...d],也就是说,b..c没有被算进去,就是a..c没有前缀和后缀是一样的,很显然next[d]的值肯定是小于l/2的。
l%(l-next[l])!=0.这样的字符串是不存在最小重复子串的就像前面说的abcccab就是这种类型
如果存在最小重复子串那么,next[d]就可以由next[a..b]也就是可以由前面的next[]来构成
我们在构造next时候就是这么构造的,
if(B[j+1]==B[i])
j++;
这里l-next[l]得到的就是a...b,因为后面的next都可以由前面的得到,那么b..d肯定也是由a..b组成的,a..b就是它的最小重复子串。
重复次数就是l/(l-next[l])
=================================================================================好吧,代码如下(其后会纳入模版中):
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define repu(i,r,l) for(int i=r;i>=l;i--)
using namespace std;
int n,m,lena,j,p[1001000];
char a[1001000],ch;
int solve()
{
if (lena==1) return 1;
memset(p,0,sizeof(p));
j=0;
p[1]=0;
rep(i,2,lena)
{
while((a[j+1]!=a[i])&&(j)) j=p[j];
if (a[j+1]==a[i]) j++;
p[i]=j;
}
if (p[lena]==0) return 1;
return lena%(lena-p[lena])?1:int(lena/(lena-p[lena]));
}
int main()
{
lena=0;
ch=getchar();
while((ch>='a')&&(ch<='z'))
{
lena++;
a[lena]=ch;
ch=getchar();
}
while(lena||ch!='.')
{
printf("%d\n",solve());
lena=0;
ch=getchar();
while((ch>='a')&&(ch<='z'))
{
lena++;
a[lena]=ch;
ch=getchar();
}
}
return 0;
}