题意很简单,给一个串,让你找一个子串,形如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;
}