bzoj4974 字符串大师 KMP

Posted reverymoon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4974 字符串大师 KMP相关的知识,希望对你有一定的参考价值。

技术分享图片

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

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

如果$next[i] eq 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;
}

 

以上是关于bzoj4974 字符串大师 KMP的主要内容,如果未能解决你的问题,请参考以下文章

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

BZOJ 4974: 字符串大师

bzoj4974: [Lydsy1708月赛]字符串大师

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

BZOJ4641基因改造 KMP

KMP模板例题回文大师