Codeforces A. Password(KMP的nxt跳转表)
Posted zhanhonhao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces A. Password(KMP的nxt跳转表)相关的知识,希望对你有一定的参考价值。
题目描述:
Password
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Asterix, Obelix and their temporary buddies Suffix and Prefix has finally found the Harmony temple. However, its doors were firmly locked and even Obelix had no luck opening them.
A little later they found a string s, carved on a rock below the temple‘s gates. Asterix supposed that that‘s the password that opens the temple and read the string aloud. However, nothing happened. Then Asterix supposed that a password is some substring t of the string s.
Prefix supposed that the substring t is the beginning of the string s; Suffix supposed that the substring t should be the end of the string s; and Obelix supposed that t should be located somewhere inside the string s, that is, t is neither its beginning, nor its end.
Asterix chose the substring t so as to please all his companions. Besides, from all acceptable variants Asterix chose the longest one (as Asterix loves long strings). When Asterix read the substring t aloud, the temple doors opened.
You know the string s. Find the substring t or determine that such substring does not exist and all that‘s been written above is just a nice legend.
Input
You are given the string s whose length can vary from 1 to 106 (inclusive), consisting of small Latin letters.
Output
Print the string t. If a suitable t string does not exist, then print "Just a legend" without the quotes.
Examples
Input
Copy
fixprefixsuffix
Output
Copy
fix
Input
Copy
abcdabc
Output
Copy
Just a legend
思路:
题目的意思是给一个字符串,看是否存在这样一个满足条件的最长字符子串:字串为前缀,后缀和中间的位置出现。刚开始时就把跟字符串的首字母相同的位置全部拿出来,因为只有这些位置可能会有满足条件的子串。然后从前往后,看从该位置出发到末尾的字串是否满足条件1是一种前缀2中间出现过。结果妥妥的在第52个测试点超时(一开始还以为能够过呢)。然后把string类全部改为c字符数组,写了字符串的比较函数,vector改用数组,加了读入优化,输出用puts,甚至吸了O2,还是超时。于是我动起了不好的念头,字符串的比较改用随机函数,只要每次随机的位置都相等,我就认为两个字符串相等,就不用每次线性的时间扫描了。嘿嘿,果然还是在第52个测试点T了。
此路不通,换条路。其实当题目提到前后缀时我就不自觉联想到了KMP算法,因为我隐约记得这是字符串的模式匹配(废话,当然是╭(╯^╰)╮),而且里面有个步骤就是跟前后缀有关的,还是线性时间复杂度,但是我已经不记得了(不,你根本就不知道(* ^ ▽^ *))。其实这道题就和KMP算法中的next表有关。next[i]表示的是模式串第i个位置之前的相同前后缀的最大长度,也是i个位置失效后要跳转的位置。那么我们再求出next后就可以根据它来判断最长相同前后缀是否在中间出现过,不是的话看次长相同前后缀在中间出现过没,再不是看次次长,...,直到跳到字符串外的-1
那么怎么判断是否在中间出现过呢?我们只需要在求出nxt表时同时用一个数组标记出nxt[i]的值是否出现。最后从末尾的末尾(len)位置开始,看nxt[i]值是否已被标记出现,出现就说明中间有这个长度的相同前后缀,没有标记就nxt[nxt[i]]地看次长位置中间标记没有,直到找到标记,记录长度后退出或者都不满足结束。
代码:
#include <iostream>
#include <string>
#define max_n 1000005
using namespace std;
string s;
int len;
int nxt[max_n];
int cnt[max_n];
int length = 0;
int get_nxt()
int j = 0;
int k = -1;
nxt[0] = -1;
while(j<len)
if(k==-1||s[k]==s[j])
++k;
++j;
nxt[j] = k;
else
k=nxt[k];
for(int i = 0;i<len;i++)
cnt[nxt[i]] = 1;
//cout << nxt[i] << " ";
//cout << endl;
int main()
cin >> s;
len = s.size();
get_nxt();
int k = nxt[len];
int flag = 0;
while(k>0)
if(cnt[k])
flag = 1;
length = k;
break;
k = nxt[k];
//cout << "k " << k << endl;
if(flag)
for(int i = len-length;i<len;i++)
cout << s[i];
cout << endl;
else
cout << "Just a legend" << endl;
return 0;
以上是关于Codeforces A. Password(KMP的nxt跳转表)的主要内容,如果未能解决你的问题,请参考以下文章
codeforces 655A A. Amity Assessment(水题)
codeforces 632A A. Grandma Laura and Apples
Codeforces Round #353 (Div. 2) A. Infinite Sequence