• 【Gym102878E/BIT校赛15thE】Eigen Substring(后缀自动机+set维护)


    题目连接:https://codeforces.ml/gym/102878/problem/E
    出题人题解:https://ws28.cn/f/43pu39cl3mw
    参考题解:https://blog.csdn.net/sigh_/article/details/110877961

    题目大意

    给定一个长度为 (n) 的字符串,对于前缀 (1..i),找到最短的字符串,使其在整个长度为 (n) 的字符串中只出现一次,输出长度。

    模拟赛中

    遍历知识点,认为可用后缀自动机的 (maxlen) 数组来维护性质,再来个 (set),因为刚好符合插入的 (O(n)) 复杂度,用 (set) 来增改, (O(n log n)) 的时间复杂度够两秒。

    但是因为没有真正掌握后缀自动机自己板子中 (x) 这个变量的特性,导致一直WA到最后……

    思路

    对于后缀自动机,其实是有三种情况进行分类讨论的:

    1. 直接连到起始节点,这种情况不会出现重复。

    2. 直连,类似 (aa),这种情况会出现重复。

    3. 之前出现过的状态,需要复制节点信息,这种情况会出现重复。

    综上,需要对 2 和 3 两种情况进行讨论。

    剩下的思路看参考题解会更加清晰

    AC代码

    #include <bits/stdc++.h>
    
    #define inf 0x3f3f3f3f
    #define llinf 0x3f3f3f3f3f3f3f3f
    typedef long long ll;
    using namespace std;
    
    const int MAXN = 2e6 + 5;
    const int MAXC = 26;
    
    
    struct node {
        int id, len;
    
        node(int _id = 0, int _len = 0) : id(_id), len(_len) {}
    
        bool operator<(const node &tb) const {
            if (len != tb.len) return len < tb.len;
            else return id < tb.id;
        }
    };
    
    set<node> st;
    
    
    class SAM {
    public:
        int rt, link[MAXN], maxlen[MAXN], trans[MAXN][MAXC];
        int val[MAXN];
    
        void init() {
            rt = 1;
            link[1] = maxlen[1] = 0;
            memset(trans[1], 0, sizeof(trans[1]));
        }
    
    
        int insert(int ch, int last) {
            int z = ++rt, p = last;
            val[z] = 1;
            memset(trans[z], 0, sizeof(trans[z]));
            maxlen[z] = maxlen[last] + 1;
            while (p && !trans[p][ch])trans[p][ch] = z, p = link[p];
    
            if (!p) link[z] = 1;
            else {
                int x = trans[p][ch];
                if (maxlen[p] + 1 == maxlen[x]) {
                    link[z] = x;
                    if (val[x]) val[x] = 0, st.erase(node(x, maxlen[link[x]] + 1));
                } else {
                    int y = ++rt;
                    maxlen[y] = maxlen[p] + 1;
                    if (val[x]) st.erase(node(x, maxlen[link[x]] + 1));
                    for (int i = 0; i < MAXC; i++) trans[y][i] = trans[x][i];
                    while (p && trans[p][ch] == x) trans[p][ch] = y, p = link[p];
                    link[y] = link[x], link[z] = link[x] = y;
                    if (val[x]) st.insert(node(x, maxlen[link[x]] + 1));
                }
            }
            //printf("link[%d] = %d
    ",z,link[z]);
            st.insert(node(z, maxlen[link[z]] + 1));
    //        if (link[z] != 1) st.erase(node(link[z], maxlen[link[link[z]]] + 1));
    
            return z;
        }
    
    
    } sa;
    
    char s[MAXN];
    
    int main() {
        int n;
        scanf("%d", &n);
        sa.init();
        scanf("%s", s + 1);
        int last = 1;
        for (int i = 1; i <= n; i++) {
            last = sa.insert(s[i] - 'a', last);
            set<node>::iterator it = st.begin();
            //it--;
            printf("%d
    ", it->len);
        }
    
        //  printf("233");
    
    }
    
  • 相关阅读:
    Java笔记
    多态
    JavaScript this
    JavaScript 对象的遍历以及判断方法
    javaScript 对象访问属性的另一种方式
    JavaScript 实现jquery方法连续调用效果
    JavaScript 命名空间
    JavaScript 继承
    python django 配置文件和url参数配置
    c# 6.0 新增功能
  • 原文地址:https://www.cnblogs.com/tudouuuuu/p/14404130.html
Copyright © 2020-2023  润新知