bzoj4974 字符串大師 KMP

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

根據$next[i]$構造比根據$pre[i]$簡單spa

若是$next[i] \neq 0$,那麼咱們能夠直接取前面的結果code

不然,咱們能夠暴力的尋找$next[i - 1], next[next[i - 1]] ...$後一位中最小沒有出現過的字符blog

暴力的複雜度爲$O(n)$rem

 

不妨考慮有一棵$next$樹get

最壞狀況下,咱們會從每一個葉子節點走到根一遍string

對於須要走的每一個葉子節點$x$,都有$next[x + 1] = 0$it

而且從葉子節點走到根的複雜度爲$O(next[x])$io

因爲有$next[i] \leq next[i - 1] + 1$,所以對於知足$next[x + 1] = 0$的$next[x]$的和不會超過$n$class

所以複雜度不超過$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;
}
相關文章
相關標籤/搜索