【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\n",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\n", it->len);
    }

    //  printf("233");

}
posted @ 2021-02-15 17:51  tudouuuuu  阅读(54)  评论(0编辑  收藏  举报