题目连接: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到最后……
思路
对于后缀自动机,其实是有三种情况进行分类讨论的:
-
直接连到起始节点,这种情况不会出现重复。
-
直连,类似 (aa),这种情况会出现重复。
-
之前出现过的状态,需要复制节点信息,这种情况会出现重复。
综上,需要对 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");
}