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

posted @ 2021-05-01 16:54  今天AC了吗  阅读(68)  评论(0)    收藏  举报