zoukankan      html  css  js  c++  java
  • P4081 [USACO17DEC]Standing Out from the Herd P

    题面

    自己去看吧

    题解

    明显的广义后缀自动机, 关键怎么算, 只能按字符串出遍历每个节点

    再根据link去标记节点, 最后根据标记去算贡献

    struct EXSAM { //trie一样的空间 N * M, 再建自动机为 N * M << 1
        static const int N = 1e5 + 5, M = 26, C = 'a', NUM = 15;//N字串总长度,NUM字符串个数
        struct Node { int len, fa, ne[M]; } tr[N << 1];
        int tot, mxlen, tax[N << 1], rk[N << 1];
        int newNode() { return memset(tr[++tot].ne, 0, sizeof tr[0].ne), tot; }
        void init() { 
            memset(tr[0].ne, 0, sizeof tr[0].ne); 
            tot = mxlen = 0; tr[0].fa = -1;
        }
        int insertSAM(int las, int ch) {
            int cur = tr[las].ne[ch], p = tr[las].fa;
            tr[cur].len = tr[las].len + 1;
            for (; p != -1 && !tr[p].ne[ch]; p = tr[p].fa) tr[p].ne[ch] = cur;
            if (p == -1) return tr[cur].fa = 0, cur;
            int q = tr[p].ne[ch];
            if (tr[p].len + 1 == tr[q].len) return tr[cur].fa = q, cur;
            int nq = ++tot; tr[nq].len = tr[p].len + 1; tr[nq].fa = tr[q].fa;
            rep (i, 0, M - 1) tr[nq].ne[i] = tr[tr[q].ne[i]].len ? tr[q].ne[i] : 0;
            for (; p != -1 && tr[p].ne[ch] == q; p = tr[p].fa) tr[p].ne[ch] = nq;
            return tr[cur].fa = tr[q].fa = nq, cur;
        }
        int insertTrie(int cur, int ch) {
            if (!tr[cur].ne[ch]) tr[cur].ne[ch] = newNode();
            return tr[cur].ne[ch];
        }
        int insert(const char *s) {
            int len = 0;
            for (int& i = len, p = 0; s[i]; p = insertTrie(p, s[i++] - C));
            return umax(mxlen, len), len;
        }
        void build() {
            queue<pair<int, int>> q;
            rep (i, 0, M - 1) if (tr[0].ne[i]) q.push({ i, 0 });
            while (!q.empty()) {
                PII it = q.front(); q.pop();
                int las = insertSAM(it.se, it.fi);
                rep (i, 0, M - 1) if (tr[las].ne[i]) q.push({ i, las });
            }
        }
        int tag[N << 1], ans[N];
        void dfs(int p, int id) {
            for (; p != -1 && tag[p] != id && tag[p] != -1; p = tr[p].fa) tag[p] = tag[p] ? -1 : id;
        }
        void difsub(char *s, int* len, int n) {
            rep (i, 1, n) for (int j = len[i - 1], p = tr[0].ne[s[j] - C]; j < len[i]; p = tr[p].ne[s[++j] - C]) dfs(p, i);
            rep (i, 0, tot) if (tag[i] != -1) ans[tag[i]] += tr[i].len - tr[tr[i].fa].len;
            rep (i, 1, n) cout << ans[i] << '
    ';
        }
    } exSam;
    
    const int N = 1e5 + 5, inf = 0x3f3f3f3f;
    
    int n, m, _, k;
    int len[N], ans[N];
    char s[N];
    
    int main() {
        exSam.init(); read(n);
        rep (i, 1, n) { cin >> s + len[i - 1]; len[i] = exSam.insert(s + len[i - 1]) + len[i - 1]; }
        exSam.build(); exSam.difsub(s, len, n);
        return 0;
    }
    
  • 相关阅读:
    按照两种模式排序用户列表
    WINDOWS系统属性符号说明
    一个无敌删除命令
    SQL判断某列中是否包含中文字符、英文字符、纯数字
    泰勒公式的发现以及证明
    陶哲轩实分析 引理7.1.4 证明
    多项式函数在某一点处的泰勒展开
    域上多项式的带余除法
    陶哲轩实分析 命题7.18 证明
    陶哲轩实分析 引理7.1.4 证明
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/14173883.html
Copyright © 2011-2022 走看看