bzoj4974 字符串大师 KMP

明显的,有$next[i] = i - pre[i]$

根据$next[i]$构造比根据$pre[i]$简单

如果$next[i] \neq 0$,那么我们可以直接取前面的结果

否则,我们可以暴力的寻找$next[i - 1], next[next[i - 1]] ...$后一位中最小没有出现过的字符

暴力的复杂度为$O(n)$

不妨考虑有一棵$next$树

最坏情况下,我们会从每个叶子节点走到根一遍

对于需要走的每个叶子节点$x$,都有$next[x + 1] = 0$

并且从叶子节点走到根的复杂度为$O(next[x])$

由于有$next[i] \leq next[i - 1] + 1$,因此对于满足$next[x + 1] = 0$的$next[x]$的和不会超过$n$

因此复杂度不超过$O(n)$

如果你闲的发慌,可以用可持久化线段树做到$O(n \log \sum)$而不是$O(n \sum)$

其中$\sum$为字符集大小

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
namespace remoon {
    #define de double
    #define le long double
    #define ri register int
    #define ll long long
    #define tpr template <typename ra>
    #define rep(iu, st, ed) for(ri iu = st; iu <= ed; iu ++)
    #define drep(iu, ed, st) for(ri iu = ed; iu >= st; iu --)
    #define gc getchar
    inline int read() {
        int p = 0, w = 1; char c = gc();
        while(c > ‘9‘ || c < ‘0‘) { if(c == ‘-‘) w = -1; c = gc(); }
        while(c >= ‘0‘ && c <= ‘9‘) p = p * 10 + c - ‘0‘, c = gc();
        return p * w;
    }
}
using namespace std;
using namespace remoon;

const int sid = 300050;

int n;
char s[sid];
int nxt[sid];
bool vis[40];

int main() {
    n = read();
    rep(i, 1, n) {
        nxt[i] = i - read();
        if(nxt[i]) s[i] = s[nxt[i]];
        else {
            memset(vis, 0, sizeof(vis));
            for(ri j = nxt[i]; j; j = nxt[j])
                vis[s[j + 1] - ‘a‘] = 1;
            vis[s[1] - ‘a‘] = 1;
            for(ri j = ‘a‘; j <= ‘z‘; j ++)
                if(!vis[j - ‘a‘]) { s[i] = j; break; }
        }
        printf("%c", s[i]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/reverymoon/p/9948835.html

时间: 2024-11-01 11:07:38

bzoj4974 字符串大师 KMP的相关文章

【bzoj4974】字符串大师 逆模拟KMP

题目描述 一个串T是S的循环节,当且仅当存在正整数k,使得S是$T^k$(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节.给定一个长度为n的仅由小写字符构成的字符串S,请对于每个k(1<=k<=n),求出S长度为k的前缀的最短循环节的长度$per_i$.字符串大师小Q觉得这个问题过于简单,于是花了一分钟将其AC了,他想检验你是否也是字符串大师. 小Q告诉你n以及$per_1,per_2,...,per_n$,请找到一个长度为n的小写字符串S,使得S能对应上per. 输入 第一

BZOJ 4974: 字符串大师

一个串T是S的循环节,当且仅当存在正整数k,使得S是T^k(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节 .给定一个长度为n的仅由小写字符构成的字符串S,请对于每个k(1<=k<=n),求出S长度为k的前缀的最短循环节的 长度per_i.字符串大师小Q觉得这个问题过于简单,于是花了一分钟将其AC了,他想检验你是否也是字符串大师. 小Q告诉你n以及per_1,per_2,...,per_n,请找到一个长度为n的小写字符串S,使得S能对应上per. Input 第一行包含一个正

字符串的KMP算法替换

1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 6 7 class myString 8 { 9 private: 10 string mainstr; 11 int size; 12 void GetNext(string p,int next[]); 13 int KMPFind(string p,int next[]); 14 public: 15 myString(); 16 //~myS

字符串匹配算法KMP算法

数据结构中讲到关于字符串匹配算法时,提到朴素匹配算法,和KMP匹配算法. 朴素匹配算法就是简单的一个一个匹配字符,如果遇到不匹配字符那么就在源字符串中迭代下一个位置一个一个的匹配,这样计算起来会有很多多余的不符合的匹配做了冗余的比较.假设源字符串长n,字串长m 该算法最差时间复杂度为 m*(n-m+1),记为O(n*m);这里不做过多解释朴素匹配算法. KMP算法: kmp算法不是在源字符串中下手,他是从字串下手,比如我要在源字符串(acabaabaabcacaabc)中匹配一个字符串字串(ab

关于两个字符串的kmp比对算法

关于两个字符串的kmp比对算法 假设有字符串X和Y,满足len(X)>len(Y),要比对这两个字符串. 我们知道,最朴实的方法,就是现将二者对齐,然后依次比对对应位置的字符.如果能匹配到Y最后位置,则匹配成功:如果匹配失败,则将Y右移一位,再从头进行匹配. 设字符串X为dababeabafdababcg:字符串Y为ababc. 这种比对方法如下所示: 起始时,二者对其,第一个字符不匹配 :| :dababeabafdababcg :ababc 右移一位,比对位置移动到Y起始位置 : | :da

字符串大师

Description 一个串T是S的循环节,当且仅当存在正整数k,使得S是T^k(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节.给定一个长度为n的仅由小写字符构成的字符串S,请对于每个k(1<=k<=n),求出S长度为k的前缀的最短循环节的长度per_i.字符串大师小Q觉得这个问题过于简单,于是花了一分钟将其AC了,他想检验你是否也是字符串大师.小Q告诉你n以及per_1,per_2,...,per_n,请找到一个长度为n的小写字符串S,使得S能对应上per. Input

bzoj4974: [Lydsy八月月赛]字符串大师

传送门 题目可转换为已知一个串kmp之后的nxt数组,求字典序最小的原串. 已知第i位结尾的串循环节长度位x,那么nxt[i]=i-x; 当nxt不为0时,s[i]=s[nxt[i]]; nxt为0时,那么考虑kmp的过程,沿着nxt[i-1]一直往前跑找到的每一个j,s[j+1]都不能是现在的s[i],那么在一路求nxt的过程中就从前往后递推用一个二进制串表示一路的nxt的后一位出现过的字母,然后每次取未出现过的字典序最小的字母即可: //Achen #include<algorithm>

字符串模式匹配KMP算法中的next数组算法及C++实现

一.问题描述: 对于两个字符串S.T,找到T在S中第一次出现的起始位置,若T未在S中出现,则返回-1. 二.输入描述: 两个字符串S.T. 三.输出描述: 字符串T在S中第一次出现的起始位置,若未出现,则返回-1. 四.输入例子: ababaababcbababc 五.输出例子: 5 六.KMP算法解析: KMP算法分为两步,第一步是计算next数组,第二步是根据next数组通过较节省的方式回溯来比较两个字符串. 网络上不同文章关于next数组的角标含义略有差别,这里取参考文献中王红梅<数据结构

字符串匹配算法-KMP

举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 在上面这个例子中,字符串"BBC ABCDAB ABCDABCDABDE"称为主串,字符串"ABCDABD"称为模式串 许多算法可以完成这个任务,Knuth-Morris-Pratt算法(简称KMP)是最常用的之一.下面,我用自己的语言,解释KMP算法. 1.首先,主串"BBC ABCDA