hdu-1358(kmp)

时间:2022-04-17 23:14:47

题意:给你一个长度为n的字符串,问你一共有多少Xi——从0开始到Xi的这段长度这个字符子串是循环串,并输出最多的循环节的次数;

解题思路:用kmp的next数组,我们从next数组的值中可以看出这个字串是否为循环串,例如:

void get_next()
{
int j,k;
j=0;k=-1;next1[0]=-1;
while(j<tlen)
{
if(k==-1||t[j]==t[k])
next1[++j]=++k;
else
k=next1[k];
}
}

  

ababa

next【0】=-1,next【1】=0,next【2】=0,next【3】=1,next【4】=2;next【5】=3;

从next数组中可以看出,如果一个字串是循环的,那么对应的next【i+1】(这里的next数组是除去本身的最大前后缀,所以退后一位)*2一定是>=当前字串长度的;不然,就没有循环节覆盖整个字符子串,但这只是前提,从例子中next【5】=3也满足,但长度为5的字串并不是循环节,所以再加入条件:

if(next1[i]*2>=i)
{
if(i%(i-next1[i])==0) {
ans[++cot][1]=i;
ans[cot][2]=i/(i-next1[i]);
}
}

  这个条件是判定这个字串是否正好被循环节完全覆盖;这样在记录一下满足的位置就行了;

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<math.h>
#include<cstdlib>
using namespace std;
char t[1005000];
int next1[1005000];
int tlen;
int ans[1005000][3];
void get_next()
{
int j,k;
j=0;k=-1;next1[0]=-1;
while(j<tlen)
{
if(k==-1||t[j]==t[k])
next1[++j]=++k;
else
k=next1[k];
}
}
int main()
{
int tt=0; while(scanf("%d",&tlen)!=EOF)
{
if(tlen==0)
return 0;
tt++;
scanf("%s",t);
get_next();
int cot=0;
for(int i=0;i<=tlen;i++)
{
if(next1[i]*2>=i)
{
if(i%(i-next1[i])==0) {
ans[++cot][1]=i;
ans[cot][2]=i/(i-next1[i]);
}
}
}
printf("Test case #%d\n",tt);
for(int i=1;i<=cot;i++)
printf("%d %d\n",ans[i][1],ans[i][2]);cout<<endl;
}
}