• bzoj4698


    后缀自动机

    辣鸡四平OJ

    就是多串LCS,有点像AC自动机。先对一个串建立自动机,然后让其他串在上面跑。我们从根节点开始走,每次看儿子是否有这种字符,有的话直接向下走,步数+1,否则沿着par走,直到有为止。par的过程其实是不断缩短当前串来继续匹配。最后按parent树从叶子向上进行dp,每个点保存一个所有串匹配到这里的最小值,如果一个位置被访问过,那么他的父结点的dp值肯定就是val了,因为这个点都能走到,那么父结点肯定也能满足。

    把拓扑序和字符串数组搞混了。。。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 4005; 
    int n, m, answer;
    int a[N], b[N], c[N], f[N], ans[N], tmp[N];
    namespace SAM 
    {
        int sz, last, root;
        struct node {
            int val, par;
            map<int, int> ch;
        } t[N];
        int nw(int x) 
        {
            t[++sz].val = x;
            return sz;
        }
        void iniSAM() 
        {
            sz = 0;
            root = last = nw(0);
        }
        void RadixSort() 
        {
            memset(c, 0, sizeof(c));
            for(int i = 1; i <= sz; ++i) ++c[t[i].val];
            for(int i = 1; i <= sz; ++i) c[i] += c[i - 1];
            for(int i = sz; i; --i) tmp[c[t[i].val]--] = i;
            for(int i = 1; i <= sz; ++i) ans[i] = t[i].val;      
        }
        void extend(int c) 
        {
            int p = last, np = nw(t[p].val + 1);
            while(p && !t[p].ch[c]) t[p].ch[c] = np, p = t[p].par;
            if(!p) t[np].par = root;
            else
            {
                int q = t[p].ch[c];
                if(t[q].val == t[p].val + 1) t[np].par = q;
                else
                {
                    int nq = nw(t[p].val + 1);
                    t[nq].ch = t[q].ch;
                    t[nq].par = t[q].par;
                    t[q].par = t[np].par = nq;
                    while(p && t[p].ch[c] == q) t[p].ch[c] = nq, p = t[p].par;
                }
            }
            last = np;
        }
    } using namespace SAM;
    int main()
    {
        scanf("%d%d", &n, &m);
        iniSAM();
        for(int i = 1; i <= m; ++i) scanf("%d", &b[i]);
        for(int i = 1; i < m; ++i) a[i] = b[i + 1] - b[i], extend(a[i]); 
        RadixSort();
        for(int i = 1; i < n; ++i)
        {
            scanf("%d", &m);
            for(int j = 1; j <= m; ++j) scanf("%d", &b[j]);
            for(int j = 1; j < m; ++j) a[j] = b[j + 1] - b[j];
            int u = root, sum = 0;   
            for(int j = 1; j < m; ++j) 
            {
                int c = a[j];
                if(t[u].ch.count(c)) u = t[u].ch[c], f[u] = max(f[u], ++sum);
                else
                {
                    while(u && !t[u].ch.count(c)) u = t[u].par;
                    if(!u) u = root, sum = 0;
                    else
                    {
                        sum = t[u].val;
                        u = t[u].ch[c];
                        f[u] = max(f[u], ++sum);
                    }
                }
            }
            for(int j = sz; j; --j) 
            {
                int u = tmp[j];
                ans[u] = min(ans[u], f[u]); 
                if(f[u] && t[u].par) f[t[u].par] = t[t[u].par].val;
                f[u] = 0;
            }   
        }
        for(int i = 2; i <= sz; ++i) answer = max(answer, ans[i]);
        printf("%d
    ", answer + 1);
        return 0;
    }
    
    View Code
  • 相关阅读:
    python3中内置函数map 和 reduce函数的使用
    爬山算法和模拟退火算法
    Link-Cut Tree(LCT)
    启发式搜索——A*算法
    树上分块
    CodeChef TRIPS-Children Trips 树上分块
    CodeChef:Chef and Problems(分块)
    莫队算法
    Konig定理及证明
    块状链表
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7857432.html
Copyright © 2020-2023  润新知