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;
}

原文地址:https://www.cnblogs.com/zhanhonhao/p/11333321.html

时间: 2024-10-11 06:08:18

Codeforces A. Password(KMP的nxt跳转表)的相关文章

Codeforces 126B. Password (KMP)

<题目链接> 题目大意:给定一个字符串,从中找出一个前.中.后缀最长公共子串("中"代表着既不是前缀,也不是后缀的部分). 解题分析:本题依然是利用了KMP中next数组的性质.具体做法见代码. #include <bits/stdc++.h> using namespace std; const int N = 1e6+5; char str[N]; int vis[N],nxt[N]; void getNext(int len){ int j=0,k=-1;

poj 2406 Power Strings(kmp的nxt数组找最小循环节)

题目链接:poj 2406 Power Strings 题意: 给你一个字符串,让你找出这个字符串的最大循环次数,及最小循环节. 题解: 用kmp的nxt数组搞搞,L=j-nxt[j],为前缀j的最小循环节. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define F(i,a,b) for(int i=(a);i<=(b);++i) 5 using namespace std;

CodeForces 25E Test KMP

题目链接:点击打开链接 题意: 给定3个字符串,进行拼接 重复的一段可以覆盖,问拼接后最小的长度(若一个串s1是s2的子串,则s1可以认为嵌入了s2内,不需要进行拼接 思路: kmp搞一下. #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <math.h> #include <set> using name

Codeforces 542D Superhero&#39;s Job 数论 哈希表 搜索

原文链接https://www.cnblogs.com/zhouzhendong/p/CF542D.html 题目传送门 - CF542D 题目传送门 - 51Nod1477 题意 定义公式 $J(x) = \sum_{1 \leq k \leq x 且 k|x 且 \gcd (k,x/k) = 1} k$ . 现在给定一个整数 $A$ ,要求有多少正整数 $x$ ,满足 $J(x)=A$ . $x|n$ 表示 $x$ 是 $n$ 的因子. $\gcd(a,b) 表示 $a$ 和 $b$ 的最大

跳转表

Dictionary.hpp #ifndef Dictionary_hpp #define Dictionary_hpp #define N_CHAR (0x80 - 0x20) //只考虑可打印字符 //词典Dictionary模版类 template <typename K,typename V> struct Dictionary { public: virtual int size() const = 0; //当前词条总数 virtual bool put(K,V) = 0; //插

让你的代码更加优雅的编程技巧-跳转表

前言 前面我们讲到了<函数指针>,今天我们看一个编程技巧-函数跳转表.我们先来看如何实现一个简易计算器. 初始版本 让我们实现一个简易计算器,我们首先能想到的方式是什么?switch语句或者if else语句.没错,初学就会想到的两种方式,我们来看看这种实现方式.这里我们选择switch语句,定义一个操作类型,用户选择操作类型与操作类型匹配时,选择对应的处理函数进行处理,calc1.c代码如下: /*calc1.c*/#include<stdio.h>#include<std

汇编中Switch逆向基础(跳转表)

跳转表产生的条件     应该是case 之间的差应该是大于4 小于一 定的数量吧 才会产生  如果跳转表太大的话性能也不高 过程 跳转表(case 不是太多也不是太少才会产生) 过程 先把Switch(a)  a中的数值减去 case: 中的最小值  假设这个值为B 然后再去判断case 中最大值-最小值 假设为 C 比较BC大小 如果 B>C(至于那些最大最小值人家怎么找的这我真不知道) 说明不再这个switch里面执行default 或者 跳出判断 如果 B<=C的话说明这个数在Swit

LeetCode开心刷题五十一天——118. Pascal&#39;s Triangle 接触跳转表概念,不知用处 lamda逗号导致表达式加法奇怪不理解119. Pascal&#39;s Triangle II

118. Pascal's Triangle Easy 87984FavoriteShare Given a non-negative integer numRows, generate the first numRows of Pascal's triangle. In Pascal's triangle, each number is the sum of the two numbers directly above it. Example: Input: 5 Output: [ [1],

codeforces #30E Tricky and Clever Password KMP+Manacher+二分

题目大意:给定一个字符串S,要求分成A+prefix+B+middle+C+suffix6段,满足: |prefix|=|suffix| |middle|为奇数 prefix+middle+suffix为回文串 除middle外所有段长度都可以为0 要求最大化|prefix|+|middle|+|suffix|,输出一组方案(|prefix|=|suffix|=0时只输出middle) 首先我们发现suffix串是顶着右端点的,因此我们可以枚举|suffix| 对于每个|suffix|我们需要求