CF126B Password
题面:
Asterix,Obelix和他们的临时伙伴Suffix、Prefix已经最终找到了和谐寺。然而和谐寺大门紧闭,就连Obelix的运气也没好到能打开它。
不久他们发现了一个字符串S(|S|<=1000000),刻在和谐寺大门下面的岩石上。Asterix猜想那一定是打开寺庙大门的密码,于是就大声将字符串朗读了出来,然而并没有什么事发生。于是Asterix又猜想密码一定是字符串S的子串T。
Prefix认为T是S的前缀,Suffix认为T是S的后缀,Obelix却认为T应该是S中的某一部分,也就是说,T既不是S的前缀,也不是S的后缀。
Asterix选择子串T来满足所有伙伴们的想法。同时,在所有可以被接受的子串变形中,Asterix选择了最长的一个(因为Asterix喜欢长的字符串)当Asterix大声读出子串T时,寺庙的大门开了。 (也就是说,你需要找到既是S的前缀又是S的后缀同时又在S中间出现过的最长子串)
现在给你字符串S,你需要找到满足上述要求的子串T。
输入格式:
一个长度在[1,1000000]间的只包含小写字母的字符串S。
输出格式:
输出子串T,如果T不存在,输出 "Just a legend",不包含引号。
一句话翻译
就是找出最长的相同的前缀,中缀(大概能这么叫?),后缀,并输出,如果不存在直接输出 Just a legend.
思路分析
我们先不管中缀的事情,最后的答案一定至少是相同前后缀,这提醒我们用 kmp 算法中的 next 数组。那如何处理中缀这件事呢?
考虑前 i 个字符组成的子串,如果符合要求的中缀出现在这个子串里面,那么它一定是这个子串的某个相同前缀后缀,或者前缀的相同前缀后缀 etc.朴素的方法是对每个 i ,都来检验是否有这样的中缀,但是这样太耗时间了,我们只需要对具有最大的最大相同前缀后缀的子串来检查就好了。
AC CODE
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1000010;
int ne[N];
char t[N];
int main(){
scanf("%s",t+1);
int n = strlen(t+1),maxn = 0;
for(int i = 2, j = 0;i <= n;i++){
while(j && t[j+1] != t[i]) j = ne[j];
if(t[j+1] == t[i]) j++;
ne[i] = j;
if(i != n)maxn = max(maxn,ne[i]);
}
int len = ne[n];
if(!len || !maxn){
puts("Just a legend");
return 0;
}
while(len>maxn)len = ne[len];
if(!len){
puts("Just a legend");
return 0;
}
for(int i = 1; i <= len; i ++)printf("%c",t[i]);
return 0;
}
最后,某谷上dalao的这篇题解还挺清楚的。
https://www.luogu.com.cn/blog/chenggeorshidao/zi-fu-chuan-lian-xi-password

浙公网安备 33010602011771号