[BZOJ 4516] [SDOI 2016] 生成魔咒

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 共有多少种生成魔咒。

Input

第一行一个整数 n。

第二行 n 个数,第 i 个数表示第 i 次操作加入的魔咒字符。

Output

输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量

Sample Input

7
1 2 3 3 3 1 2

Sample Output

1
3
6
9
12
17
22

HINT

对于100%的数据,\(1 \le n \le 100000\)
用来表示魔咒字符的数字 \(x\) 满足 \(1 \le x \le 10^9\)

Solution

插入一个新的字符 \(np\) 时,新增加的本质不同的子串个数为 \(len[np] - len[fa[np]]\)

Code

#include <cstdio>
#include <tr1/unordered_map>

const int N = 200005;
int fa[N], len[N], las = 1, sz = 1, np; long long ans;
std::tr1::unordered_map<int,int> ch[N];

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
void insert(int c) {
    int p = las; np = ++sz, las = np, len[np] = len[p] + 1;
    for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
    if (!p) { fa[np] = 1; return; }
    int q = ch[p][c];
    if (len[p] + 1 == len[q]) { fa[np] = q; return; }
    int nq = ++sz;
    ch[nq] = ch[q], len[nq] = len[p] + 1, fa[nq] = fa[q], fa[np] = fa[q] = nq;
    for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
}
int main() {
    int n = read();
    for (int i = 1; i <= n; ++i)
        insert(read()), ans += len[np] - len[fa[np]], printf("%lld\n", ans);
    return 0;
}

转载于:https://www.cnblogs.com/fly-in-milkyway/p/10415272.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值