zoukankan      html  css  js  c++  java
  • 【模板】字符串

    1 字符串 Hash

    const ll mod[3] = {900000011, 998244353, 1000000007};
    const ll bas[3] = {4493, 8111, 8527};
    // you can choose your bases and modulos
    
    char s[S];
    ll pw[3][S], Hash[3][S];
    
    inline ll getHash(int id, int L, int R){ // str[L..R-1]
        ll J = (Hash[id][R] - Hash[id][L] * pw[id][R - L]) % mod[id];
        return J < 0 ? J + mod[id] : J;
    }
    
    // following is the pretreatment
    ll *f, *g;
    for(j = 0; j < 3; j++){
        f = Hash[j]; f[0] = 0;
        g = pw[j]; g[0] = 1;
        for(i = 0; i < n; i++){
            f[i + 1] = (f[i] * bas[j] + (s[i] - 'a')) % mod[j];
            g[i + 1] = g[i] * bas[j] % mod[j];
        }
    }

    2 KMP 模式匹配

    // pretreatment (border) 
    for (j = *f = -1, i = 1; i < n; f[++i] = ++j)
        for (; ~j && s[j] != s[i]; j = f[j]);
    
    // KMP
    for (j = i = 0; i < _n; ++i) {
        for (; ~j && s[j] != m[i]; j = f[j]);
        if (++j == n) printf("%d ", i - s_n + 2);
    }

    3 字典树

    void append(char *s){
        char *p = s;
        int t = 1, id; // t = 0 is also OK
        for(; *p; ++p){
            id = *p - 97;
            t = d[t][id] ? d[t][id] : (d[t][id] = ++V);
        }
        ++val[t];
    }
    
    // the process of matching is just like going on a DFA, so omit it.

    4 Aho-Corasick 自动机

    void build(){
        int h, ta = 1, i, t, id;
        que[0] = 1;
        f[1] = 0;
        for(h = 0; h < ta; ++h)
            for(i = que[h], id = 0; id < 26; ++id){ // 26 is the size of char-set
                t = (f[i] ? d[f[i]][id] : 1); // 1 or 0 depend on the root of trie
                int &u = d[i][id];
                if(!u) {u = t; continue;}
                f[u] = t; val[u] |= val[t]; que[ta++] = u;
                la[u] = (v[t] ? t : la[t]);
            }
    }

    5 后缀数组 (倍增构造与最长公共前缀

    struct LCP {
        int n, *sa, *rnk, *st[LN];
        LCP () : n(0), sa(NULL), rnk(NULL) {memset(st, 0, sizeof st);}
        ~LCP () {
            if (sa) delete [] sa;
            if (rnk) delete [] rnk;
            for (int i = 0; i < LN; ++i) if (st[i]) delete [] st[i];
        }
        void construct(const char *s) {
            int i, j, k, m = 256, p, limit; n = strlen(s);
            int *x = new int[n + 1], *y = new int[n + 1], *buf = new int[max(n, m)], *f, *g = new int[n + 1];
            auto cmp = [this] (const int *a, const int u, const int v, const int l) {return a[u] == a[v] && (u + l >= n ? 0 : a[u + l]) == (v + l >= n ? 0 : a[v + l]);};
            if (sa) delete [] sa; sa = new int[n];
            if (rnk) delete [] rnk;
            for (i = 0; i < LN; ++i) if (st[i]) delete [] st[i], st[i] = 0;
            for (i = 0; i < n; ++i) sa[i] = i, x[i] = (unsigned char)s[i];
            std::sort(sa, sa + n, [s] (const int u, const int v) {return (unsigned char)s[u] < (unsigned char)s[v];});
            for (j = 1; j < n; j <<= 1, m = ++p) {
                std::iota(y, y + j, n - j), p = j;
                for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
                memset(buf, 0, m << 2);
                for (i = 0; i < n; ++i) ++buf[ x[y[i]] ];
                for (i = 1; i < m; ++i) buf[i] += buf[i - 1];
                for (i = n - 1; i >= 0; --i) sa[ --buf[ x[y[i]] ] ] = y[i];
                std::swap(x, y);
                x[*sa] = p = 1, x[n] = 0;
                for (i = 1; i < n; ++i) x[sa[i]] = (cmp(y, sa[i - 1], sa[i], j) ? p : ++p);
                if (p >= n) break;
            }
            if (rnk = x, n == 1) *x = 0;
            else for (i = 0; i < n; ++i) --x[i];
            delete [] buf, delete [] y;
            for (p = i = 0; i < n; ++i) {
                if (p && --p, !x[i]) continue;
                for (j = sa[x[i] - 1], limit = n - max(i, j); p < limit && s[i + p] == s[j + p]; ++p);
                g[ x[i] - 1 ] = p;
            }
            *st = g, k = n - 1;
            for (j = 0; 1 << (j + 1) < n; ++j) {
                k -= 1 << j, f = g, g = st[j + 1] = new int[k + 1];
                for (i = 0; i < k; ++i)
                    g[i] = min(f[i], f[i + (1 << j)]);
            }
        }
        inline int operator () (const int u, const int v) {
            assert((unsigned)u < (unsigned)n && (unsigned)v < (unsigned)n);
            if (u == v) return n - u;
            int L, R, c; std::tie(L, R) = std::minmax(rnk[u], rnk[v]), c = lg2(R - L);
            return min(st[c][L], st[c][R - (1 << c)]);
        }
    };

    6 后缀自动机

    #define q d[p][x]
    int extend(int x) {
        for (p = np, val[np = ++cnt] = val[p] + 1; p && !q; q = np, p = pa[p]);
        if (!p) pa[np] = 1;
        else if (val[p] + 1 == val[q]) pa[np] = q;
        else {
            int nq = ++cnt;
            val[nq] = val[p] + 1, memcpy(d[nq], d[q], 104);
            pa[nq] = pa[q], pa[np] = pa[q] = nq;
            for (int Q = q; p && q == Q; q = nq, p = pa[p]);
        }
        return f[np] = 1, np;
    }
    #undef q
     
    
    7 根据后缀自动机构造后缀树
    void build() {
        int i, j, c; used[1] = true;
        for (i = cnt; i; --i) if (~pos[i])
            for (j = i; !used[j]; j = pa[j])
                c = pos[j] - val[pa[j]], pos[pa[j]] = pos[j],
                child[pa[j]][int(s[c])] = j, used[j] = true;
    //    dfs(1);
    }

    8 Z 算法

    void Z() {
        int i, Max = 0, M = 0;
        for (i = 1; i < n; ++i) {
            z[i] = (i < Max ? std::min(z[i - M], Max - i) : 0);
            for (; s[z[i]] == s[i + z[i]]; ++z[i]);
            if (i + z[i] > Max) Max = i + z[i], M = i; 
        }
    }

    9 Manacher 回文串

    void Manacher() {
        int n = 2, i, Max = 0, M = 0;
        t[0] = 2, t[1] = 1;
        for (i = 0; i < S; ++i) t[n++] = s[i], t[n++] = 1; t[n++] = 3;
        for (i = 0; i < n; ++i){
            f[i] = (i < Max ? std::min(f[M * 2 - i], Max - i) : 1);
            for(; t[i + f[i]] == t[i - f[i]]; ++f[i]);
            if (i + f[i] > Max) Max = i + f[i], M = i;
        }
    }

    10 回文自动机

    int get_fail(int x) {for (; ptr[~val[x]] != *ptr; x = fail[x]); return x;}
    
    int extend(int x) {
        int &q = d[p = get_fail(p)][x];
        if (!q) fail[++cnt] = d[get_fail(fail[p])][x], val[q = cnt] = val[p] + 2;
        return p = q;
    }
    
    val[1] = -1, p = 0, *fail = cnt = 1;

    11 多串后缀自动机 / 广义后缀自动机

    #define q d[p][x]
    #define try_split(v) { 
        if (val[p] + 1 == val[q]) v = q; 
        else { 
            int nq = ++cnt; 
            val[nq] = val[p] + 1, memcpy(d[nq], d[q], 104); 
            pa[nq] = pa[q], v = pa[q] = nq; 
            for (int Q = q; p && q == Q; q = nq, p = pa[p]); 
        } 
    }
    
    int extend(int x) {
        if (p = np, q) try_split(np)
        else {
            for (val[np = ++cnt] = val[p] + 1; p && !q; q = np, p = pa[p]);
            if (p) try_split(pa[np]) else pa[np] = 1;
        }
        return np;
    }
    #undef q
  • 相关阅读:
    简明Python3教程 12.问题解决
    简明Python3教程 11.数据结构
    【SPOJ 694】Distinct Substrings
    【codeforces Manthan, Codefest 17 C】Helga Hufflepuff's Cup
    【CF Manthan, Codefest 17 B】Marvolo Gaunt's Ring
    【CF Manthan, Codefest 17 A】Tom Riddle's Diary
    【SPOJ 220】 PHRASES
    【POJ 3261】Milk Patterns
    【POJ 3294】Life Forms
    【POJ 1226】Substrings
  • 原文地址:https://www.cnblogs.com/lau1997/p/12665736.html
Copyright © 2011-2022 走看看