[bzoj4516][Sdoi2016]生成魔咒——后缀自动机
2017-03-14 21:45
411 查看
Brief Description
魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1、2 拼凑起来形成一个魔咒串 [1,2]。
一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。
例如 S=[1,2,1] 时,它的生成魔咒有 [1]、[2]、[1,2]、[2,1]、[1,2,1] 五种。S=[1,1,1] 时,它的生成魔咒有 [1]、
[1,1]、[1,1,1] 三种。最初 S 为空串。共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符。每次操作后都
需要求出,当前的魔咒串 S 共有多少种生成魔咒。
Algorithm Design
后缀自动机。每次加入一个新的节点的时候统计。
Code
#include <cstdio> #include <map> const int maxn = 100010; int n, m, tot = 1, last = 1; #define ll long long ll ans; int len[maxn << 1], fa[maxn << 1]; std::map<int, int> ch[maxn << 1]; int calc(int x) { return len[x] - len[fa[x]]; } void insert(int x) { int p = last, np = last = ++tot; len[np] = len[p] + 1; while (p && !ch[p][x]) ch[p][x] = np, p = fa[p]; if (!p) fa[np] = 1, ans += calc(np); else { int q = ch[p][x]; if (len[p] + 1 == len[q]) fa[np] = q, ans += calc(np); else { int nq = ++tot; len[nq] = len[p] + 1; ch[nq] = ch[q]; fa[nq] = fa[q]; ans += calc(nq) - calc(q); fa[q] = fa[np] = nq; ans += calc(np) + calc(q); while (p && ch[p][x] == q) ch[p][x] = nq, p = fa[p]; } } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { int x; scanf("%d", &x); insert(x); printf("%lld\n", ans); } }
相关文章推荐
- BZOJ.4516.[SDOI2016]生成魔咒(后缀自动机 map)
- bzoj 4516 [Sdoi2016]生成魔咒 后缀自动机
- [BZOJ4516][Sdoi2016]生成魔咒(后缀数组+链表||后缀自动机)
- BZOJ 4516: [Sdoi2016]生成魔咒 后缀自动机
- [BZOJ4516] [SDOI2016] 生成魔咒 - 后缀数组/后缀自动机
- BZOJ4516 [Sdoi2016]生成魔咒 后缀自动机
- BZOJ 4516: [Sdoi2016]生成魔咒 [后缀自动机]
- BZOJ4516 [Sdoi2016]生成魔咒 【后缀自动机】
- 【bzoj4516】[Sdoi2016]生成魔咒 后缀自动机
- bzoj 4516: [Sdoi2016]生成魔咒 (后缀自动机)
- [BZOJ4516][SDOI2016]生成魔咒(后缀自动机)
- [BZOJ4516][Sdoi2016]生成魔咒(后缀数组+set/后缀自动机)
- [BZOJ4516][SDOI2016]生成魔咒(后缀自动机)
- BZOJ 4516 [Sdoi2016]生成魔咒 ——后缀自动机
- BZOJ.4516.[SDOI2016]生成魔咒(后缀数组 RMQ)
- 【BZOJ4516】【Sdoi2016】生成魔咒 后缀数组 线段树
- bzoj 4516: [Sdoi2016]生成魔咒 后缀数组
- BZOJ 4516: [Sdoi2016]生成魔咒
- BZOJ 4516: [Sdoi2016]生成魔咒
- BZOJ 4516: [Sdoi2016]生成魔咒——后缀数组、并查集