hdu-1358(kmp)

题意:给你一个长度为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;
}
    }

  

posted @ 2018-07-09 16:33  荒岛的龟  阅读(268)  评论(0编辑  收藏  举报