hdu3746 --kmp的运用

//题目意思是:求最少需要在结尾后面补几个字符才能凑成两个循环

这里主要讲的是hdu3746,没有讲解kmp

有关kmp的博客推荐去看这个博客:(讲得十分漂亮,令人心花怒放:)不过篇幅比较长,需要静下心来慢慢品味u)

https://blog.csdn.net/v_july_v/article/details/7041827

对于这题,先看一下图:

我们再考虑另一种情况:

|——————|——|——————|

0                    1       x                    2

其中next[len]=x, 0~x与1~2对应那么len-next[len]=0~1(或x~2)是否是周期呢?这个问题我也考虑了许久

根据我的理解来解释下:

因为0~x与1~2是对应的,即相等,又1~x部分是两者共有部分,所以在0处和2处分别取1~x这么长的一段,并且它们都是一样的(结合一下下面的图理解下)

|——|———|——|———|——|

0      x’      1      x           x''    2

这里0~x’,1~x  ,x''~2都是相等的

并且也可以得到x'~1与x~x''相等

结合图可知:

  1. 当以0~1为周期时,只需在0的前面差入x''~2这段即可,即加入长度为len%(n-x)=len%(n-next[len])
  2. 当以0~x这段为周期时,只需在2的后面插入1~x这段即可,即加入长度也为len%(n-x)=len%(n-next[len]);

实现代码如下

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200000+10
int len;
int next1[MAXN];
char sm[MAXN];
void getNext()
{
    int j=0;
    int k=-1;
    next1[0]=-1;
    while(j<len)
    {
        if(k==-1||sm[j]==sm[k])
        {
            k++;
            j++;
            next1[j]=k;
        }
        else
        {
            k=next1[k];
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    getchar();
    while(t--)
    {
        scanf("%s",sm);
        len=strlen(sm);
        getNext();
        int T=len-next1[len]; //T为周期
        if(len%T==0&&len!=T)    //当len==T是应输出的是所有的祖父穿长度len,即T-len%T
        {
            printf("0\n");
        }
        else
            printf("%d\n",T-len%T);
    }
    return 0;
}

参考文献:

1.https://blog.csdn.net/xingyeyongheng/article/details/9285709

猜你喜欢

转载自blog.csdn.net/weixin_42373330/article/details/81227331
今日推荐