HDU 3746 Cyclic Nacklace(KMP:补齐循环节)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013480600/article/details/22954037

HDU 3746 Cyclic Nacklace(KMP:补齐循环节)

http://acm.hdu.edu.cn/showproblem.php?pid=3746

题意:

        给你一个串,要你在串头或尾添加最少的字符,使得该串至少有2个循环节,问你最少需要加几个字符.

分析:

       首先要明白:如果一个串需要至少添加x(x>=0)个字符才能是有>=2个循环节的串,那么我可以只在串末尾添加,不需要去串头添加.(比如串cabc,循环节是abc,我可以在尾部添加ab即可.)

       首先如果原始串已经有至少两个循环节就不必添加.当f[m]>0&&m%(m-f[m])==0时,不必添加.(结合之前的KMP循环节题目看看是不是这样.)

       现在假设条件 f[m]>0&&m%(m-f[m])==0 不成立的时候呢?

重要结论:不论串S是不是循环的,如果想要S是一个循环串的话,那么它的最小循环节长度一定是len-f[len]. 其中len是串S的长度.

即不论S是不完整的循环串还是完整的循环串,len-f[len]一定是串S中去除末尾残缺部分之后,存在的最小循环节长度.现在来例证一下:


假设f[len]=0,那么是不是该串完全没有由部分子串构成最小循环节呢?是的.

只要一个串是上面的形式a或b,那么就不可能f[len]=0.

只要f[len]=0 (类似上面的形式c),那么它一定是单独成循环节,需要添加len个字符.

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXM=100000+100;
int f[MAXM],m;
char P[MAXM];
void getFail(char *P,int *f)
{
    f[0]=f[1]=0;
    for(int i=1;i<m;i++)
    {
        int j=f[i];
        while(j && P[i]!=P[j]) j=f[j];
        f[i+1]= (P[i]==P[j])?j+1:0;
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",P);
        m=strlen(P);
        getFail(P,f);
        if(f[m]==0)
        {
            printf("%d\n",m);
            continue;
        }
        if(m%(m-f[m])==0) printf("0\n");
        else
        {
            int len1=m-f[m];
            printf("%d\n",len1-m%len1);
        }
    }
    return 0;
}


没有更多推荐了,返回首页