HDU 4763 Theme Section ( KMP )

题意很简单,给一个串,让你找一个子串,形如EAEBE,就是一个串在开头结尾中间各出现一次,问这个E最长是多少。比赛的时候各种拙计,想了一个很土鳖的方法,不知道怎么写RE了,个人觉得应该可以过(很土鳖就不介绍了)。

然后看了一个大神的博客,写的真好啊,用KMP中next数组的性质,就是您老中间那个循环为什么打死我也看不懂啊,然后一天没有了,然后,我把中间循环去掉,发现根本就是无用的,给跪了,不过依然很感谢这位大神给了一个大概的思路(虽然您老的代码有一段略坑,他应该不会来本弱的空间逛游的,不会。。。。)

吐槽完了,给思路:利用KMP的next数组性质可以清楚,next [ i ]决定了1 ~ next [ i ]这个子串一定在str中作为后缀出现(这个子串的开头我们下面再说),那么我们就是要找一个i(从next[n]推来,不行就i = next [ i ] ),要使1 ~ i 在i + 1 ~ str.length() - i 也有这个子串,那么如何保证子串之间不重叠?就是 3 * i <=length 然后枚举2*i到length - i的每一个next[j]看有没有next [ j ] == i 就可以了

必须承认的是,本弱语文水平有限,没解释清楚的地方请看代码脑补

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

#define N 1000005
char str[N];
int next[N];

int GetNext(char *str){
    int i,j;
    int LL=strlen(str);
    int len=LL;
    next[0]=-1;
    j=-1;
    i=0;
    while(i<len){
        if(j==-1||str[i]==str[j]){
            next[++i]=++j;
        }else j=next[j];
    }

    while(len!=0){
        int l=next[len];
        if(3*l<=LL){
            for(i=2*l;i<=LL-l;i++){
                if(next[i]==l)
                    return l;
            }
        }
        len=next[len];
    }
    return len;
}

int main(){
    int i,j;
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%s",str);
        printf("%d\n",GetNext(str));
    }
    return 0;
}


 

你可能感兴趣的:(KMP)