hdu 4763 Theme Section(KMP)

题目链接:  hdu 4763

题目大意:  找出字符串的最长子串,这个子串满足既是前缀和后缀,并且在中间会出现

解题思路:  不妨先找出所有前缀等于后缀的子串长度(poj 2752 解题报告

                  从长到短(长度不大于主串的1/3)枚举子串的长度

                  前缀等于后缀的子串长度为ans[ i ]

                  根据next[ ]的性质,中间再次出现这个串的话,那么next[ ]数组的值必会等于ans[ i ]

                  中间会出现长度依然等于ans[ i ]的子串的nex[ ]t区间必定在[2*ans[ i ],Tlen-ans[ i ]]

代码:

//Final  KMP变形,poj 2752升级版,找出所有字符串的最长子串,这个子串满足既是前缀又是后缀,并且中间也出现(不可以重叠)
#include <stdio.h>
#include <string.h>
#define MAX 1000010
char ch[MAX];
int Tlen,next[MAX],ans[MAX];

void Get_next()       //求字符串的next[]前缀数组
{
    int i=0,j=-1;
    next[0]=-1;
    while(i<Tlen)
    {
        if(j==-1||ch[i]==ch[j])
        {
            i++; j++;
            next[i]=j;
        }
        else
            j=next[j];
    }
}

int main()
{
    int i,j,n,k,kk,pd,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",ch);
        Tlen=strlen(ch);
        memset(next,0,sizeof(next));
        Get_next();
        ans[0]=Tlen;          //本身也是
        n=0; i=Tlen;
        while(next[i]>0)      //根据next[]性质求出所有满足题意的长度
        {
            ans[++n]=next[i];
            i=next[i];
        }
        k=Tlen/3;             //子串的长度最长是主串的1/3
        pd=0;
        for(i=0;i<=n;i++)     //子串长度从长到短枚举
        {
            if(ans[i]>k)      //子串的长度必定会小于或等于Tlen/3
                continue;
            else
            {
                kk=Tlen-ans[i];
                for(j=ans[i]+ans[i];j<=kk;j++)  //根据next[]的性质从区间[2*ans[i],Tlen-ans[i]]寻找
                {
                    if(next[j]==ans[i])
                    {
                        pd=1;
                        break;
                    }
                }
            }
            if(pd==1)
            {
                printf("%d\n",ans[i]);
                break;
            }
        }
        if(pd==0)
            printf("%d\n",0);
    }
    return 0;
}


你可能感兴趣的:(KMP,HDU,4763)