洛谷传送门
BZOJ传送门
题目描述
魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1 , 2 1,2 1,2 拼凑起来形成一个魔咒串 [ 1 , 2 ] [1,2] [1,2]。
一个魔咒串 S S S 的非空字串被称为魔咒串 S S S 的生成魔咒。
例如 S = [ 1 , 2 , 1 ] S=[1,2,1] S=[1,2,1] 时,它的生成魔咒有 [ 1 ] [1] [1]、 [ 2 ] [2] [2]、 [ 1 , 2 ] [1,2] [1,2]、 [ 2 , 1 ] [2,1] [2,1]、 [ 1 , 2 , 1 ] [1,2,1] [1,2,1] 五种。 S = [ 1 , 1 , 1 ] S=[1,1,1] S=[1,1,1] 时,它的生成魔咒有 [ 1 ] [1] [1]、 [ 1 , 1 ] [1,1] [1,1]、 [ 1 , 1 , 1 ] [1,1,1] [1,1,1] 三种。最初 S S S 为空串。共进行 n n n 次操作,每次操作是在 S S S 的结尾加入一个魔咒字符。每次操作后都需要求出,当前的魔咒串 S S S 共有多少种生成魔咒。
输入输出格式
输入格式:
第一行一个整数 n n n。
第二行 n n n 个数,第 i i i 个数表示第 i i i 次操作加入的魔咒字符。
输出格式:
输出 n n n 行,每行一个数。第 i i i 行的数表示第 i i i 次操作后 S S S 的生成魔咒数量
输入输出样例
输入样例#1:
7
1 2 3 3 3 1 2
输出样例#1:
1
3
6
9
12
17
22
说明
对于10%的数据, 1 ≤ n ≤ 10 1 \le n \le 10 1≤n≤10
对于30%的数据, 1 ≤ n ≤ 100 1 \le n \le 100 1≤n≤100
对于60%的数据, 1 ≤ n ≤ 1000 1 \le n \le 1000 1≤n≤1000
对于100%的数据, 1 ≤ n ≤ 100000 1 \le n \le 100000 1≤n≤100000
用来表示魔咒字符的数字 x x x 满足 1 ≤ n ≤ 1 0 9 1 \le n \le 10^9 1≤n≤109
解题分析
动态维护本质不同的子串数, 实际上就是 S A M SAM SAM上每个点的 l e n len len减去其 p a r e n t parent parent节点的 l e n len len的和。 我们在修改 p a r e n t parent parent的时候顺带维护即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <map>
#define R register
#define IN inline
#define W while
#define MX 505000
#define ll long long
int par[MX], len[MX];
std::map <int, int> to[MX];
int last, cur, l, cnt;
ll ans;
namespace SAM
{
IN int get(R int now) {return (~par[now]) ? len[now] - len[par[now]] : 0;}
IN void insert(R int id)
{
R int now = last, tar;
cur = ++cnt; len[cur] = len[last] + 1; last = cur;
for (; (~now) && !to[now][id]; now = par[now]) to[now][id] = cur;
if(now < 0) return par[cur] = 0, ans += get(cur), void();
tar = to[now][id];
if(len[tar] == len[now] + 1) return par[cur] = tar, ans += get(cur), void();
int nw = ++cnt; len[nw] = len[now] + 1;
par[nw] = par[tar]; ans += get(nw) - get(tar);
par[tar] = par[cur] = nw; ans += get(cur) + get(tar);
to[nw] = to[tar];
for (; (~now) && to[now][id] == tar; now = par[now]) to[now][id] = nw;
}
}
int main(void)
{
par[0] = -1;
int T, buf; scanf("%d", &T);
W (T--)
{
scanf("%d", &buf);
SAM::insert(buf); printf("%lld\n", ans);
}
}