https://loj.ac/problem/2033
题意:这道题是中文题。就是给你一个字符串,询问每一个前缀中有多少个不同子串。
做法:说到不同子串的数量,应该想到的是某种字符串算法。
这道题应该用后缀自动机解决。
首先一个字符串中不同子串的数量就是从空串起点
出发有多少条路径。
我们可以利用SAM的树形结构跑一个动态规划
就可以了,但不过这道题这样写似乎很难维护。
我们就可以换一种方法维护。
另一种方法是利用后缀自动机的树形结构。每个节点对应的子串数量是
,对自动机所有节点求和即可。
这道题没加入一个字符就加上这个结点的值,不用管加入过程中
的结点,你可以画一个图,发现他对答案的总和并不影响。
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f;
struct state {
int len, link;
// int next[26];
unordered_map<int, int> next;
} st[maxn << 1];
int sz, last;
void init() {
st[0].len = 0;
st[0].link = -1;
sz++;
last = 0;
}
void extend(int c) {
int cur = sz++;
st[cur].len = st[last].len + 1;
int p = last;
while (p != -1 && !st[p].next[c]) {
st[p].next[c] = cur;
p = st[p].link;
}
if (p == -1) {
st[cur].link = 0;
} else {
int q = st[p].next[c];
if (st[p].len + 1 == st[q].len) {
st[cur].link = q;
} else {
int clone = sz++;
st[clone].len = st[p].len + 1;
// memcpy(st[clone].next, st[q].next, sizeof(st[q].next));
st[clone].next = st[q].next;
st[clone].link = st[q].link;
while (p != -1 && st[p].next[c] == q) {
st[p].next[c] = clone;
p = st[p].link;
}
st[q].link = st[cur].link = clone;
}
}
last = cur;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int n, x;
ll ans = 0;
cin >> n;
init();
for (int i = 1; i <= n; i++) {
cin >> x;
extend(x);
ans += st[last].len - st[st[last].link].len;
cout << ans << endl;
}
return 0;
}