• luogu4595 [COCI2011-2012#5] POPLOCAVANJE 后缀自动机



    看着就像后缀自动机....

    然后搜了一下,网上一大把的(AC)自动机

    嗯......

    不管了,打一个试试

    然后就过了(QAQ)


    我们考虑对于每个点(i)求出它往前最长能匹配的子串的长度

    可以对街道串建出后缀自动机

    把所有的(L)在后缀自动机上走

    走到的串就打个标记,最后顺着(parent)树下传一遍即可


    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    #define ri register int
    #define ll long long
    #define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
    #define drep(io, ed, st) for(ri io = ed; io >= st; io --)
    
    const int sid = 500060;
    
    char s[sid];
    int n, m, id = 1;
    int fa[sid], mx[sid], val[sid], rig[sid];
    int go[sid][26];
    
    int extend(int lst, int c, int pos) {
        int p = lst, np = ++ id;
        rig[np] = pos; mx[np] = mx[p] + 1;
        for( ; p && !go[p][c]; p = fa[p])
            go[p][c] = np;
        if(!p) fa[np] = 1;
        else {
            int q = go[p][c];
            if(mx[p] + 1 == mx[q]) fa[np] = q;
            else {
                int nq = ++ id;
                mx[nq] = mx[p] + 1;
                fa[nq] = fa[q]; fa[np] = fa[q] = nq;
                memcpy(go[nq], go[q], sizeof(go[q]));
                for( ; p && go[p][c] == q; p = fa[p])
                    go[p][c] = nq;
            }
        }
        return np;
    }
    
    void find(char *s) {
        int n = strlen(s + 1);
        int now = 1;
        rep(i, 1, n) {
            int opt = s[i] - 'a';
            if(!go[now][opt]) return;
            now = go[now][opt];
        }
        val[now] = max(val[now], n);
    }
    
    int nc[sid], ip[sid], na[sid];
    void solve() {
        rep(i, 1, id) nc[mx[i]] ++;
        rep(i, 1, n) nc[i] += nc[i - 1];
        rep(i, 1, id) ip[nc[mx[i]] --] = i;
        rep(i, 1, id) {
            int o = ip[i];
            val[o] = max(val[o], val[fa[o]]);
            if(rig[o]) {
                int L = rig[o] - val[o] + 1, R = rig[o];
                na[L] ++; na[R + 1] --;
            }
        }
        rep(i, 1, n) na[i] += na[i - 1];
        int ans = 0;
        rep(i, 1, n) if(!na[i]) ans ++;
        printf("%d
    ", ans);
    }
        
    int main() {
        cin >> n;
        scanf("%s", s + 1);
        
        int lst = 1;
        rep(i, 1, n) lst = extend(lst, s[i] - 'a', i);
        
        cin >> m;
        rep(i, 1, m) {
            scanf("%s", s + 1);
            find(s);
        }
        
        solve();
        return 0;
    }
    

    不知道为啥机房的人之后都写了后缀自动机....

  • 相关阅读:
    BZOJ 3677 连珠线
    BZOJ 3676 回文串
    BZOJ 3675 序列分割
    BZOJ 4013 实验比较
    BZOJ 4011 落忆枫音
    使用Google BBR加速 VPS
    OSX编译安装Python3及虚拟开发环境Virtualenv
    OSX安装Mysql8.0
    OpenSSL编程之摘要
    OpenCA搭建
  • 原文地址:https://www.cnblogs.com/reverymoon/p/10029241.html
Copyright © 2020-2023  润新知