HDU4763 - Theme Section(KMP)

题目描述

给定一个字符串S,要求你找到一个最长的子串,它既是S的前缀,也是S的后缀,并且在S的内部也出现过(非端点)

题解

CF原题不解释。。。。http://codeforces.com/problemset/problem/126/B

KMP的失配函数fail[i]的值就是s[0..i]的最长前缀且是后缀的长度~~~,因此我们从S的末尾位置开始沿着失配函数跑即可,对于当前fail[i],判断前缀s[0…i]是否在s[i+1..length(s)-i]是否出现即可~~~~如果存在则是最长子串的长度,否则继续判断长度为fail[fail[i]]的前缀是否符合上述情况,一直到找到就OK了。。。

一个多小时才看到此题~~~~~坑爹。。。。

代码:

#include <iostream>

#include <cstring>

#include <algorithm>

#include <cstdio>

using namespace std;

#define MAXN 1000005

char s[MAXN];

int f[MAXN];

void getfail(char *p,int len)

{

    int j;

    f[0]=j=-1;

    for(int i=1; i<len; i++)

    {

        while(j>=0&&p[j+1]!=p[i]) j=f[j];

        if(p[j+1]==p[i]) j++;

        f[i]=j;

    }

}

int find(int len)

{

    int x=strlen(s);

    int j=-1;

    for(int i=len-1; i<x-len; i++)

    {

        while(j>=0&&s[j+1]!=s[i]) j=f[j];

        if(s[j+1]==s[i]) j++;

        if(j+1==len) return len;

    }

    return -1;

}

int main()

{

    int n;

    scanf("%d",&n);

    while(n--)

    {

        int pp=-1;

        scanf("%s",s);

        if(strlen(s)<3) printf("0\n");

        else

        {

            getfail(s,strlen(s));

            int j=strlen(s)-1;

            while(f[j]>=0)

            {

                if(f[j]+1>pp)

                {

                    int t=find(f[j]+1);

                    if(t>pp)

                    {

                        pp=t;

                        break;

                    }

                }

                j=f[j];

            }

            if(pp!=-1)

                printf("%d\n",pp);

            else

                printf("0\n");

        }

    }

    return 0;

}

你可能感兴趣的:(theme)