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;
}

posted on 2013-09-28 18:40  仗剑奔走天涯  阅读(1260)  评论(0编辑  收藏  举报

导航