[BZOJ4516][SDOI2016]生成魔咒(后缀自动机)

4516: [Sdoi2016]生成魔咒

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1549  Solved: 899
[Submit][Status][Discuss]

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 次操作加入的魔咒字符。
1≤n≤100000。,用来表示魔咒字符的数字 x 满足 1≤x≤10^9

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

Source

[Submit][Status][Discuss]

SAM裸题?son数组用map存,实时统计mx[i]-mx[fa[i]]即可。

 1 #include<map>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=400100;
 9 map<int,int>son[N];
10 int cnt=1,lst=1,p,np,n,mx[N],fa[N],a[N];
11 ll ans;
12 
13 int F(int x){ return mx[x]-mx[fa[x]]; }
14 
15 void ext(int c){
16     p=lst; np=lst=++cnt; mx[np]=mx[p]+1;
17     while (p && !son[p][c]) son[p][c]=np,p=fa[p];
18     if (!p) fa[np]=1,ans+=F(np);
19     else{
20         int q=son[p][c];
21         if (mx[q]==mx[p]+1) fa[np]=q,ans+=F(np);
22         else{
23             int nq=++cnt; mx[nq]=mx[p]+1; son[nq]=son[q];
24             while (p && son[p][c]==q) son[p][c]=nq,p=fa[p];
25             fa[nq]=fa[q]; ans+=F(nq)-F(q); fa[q]=fa[np]=nq; ans+=F(np)+F(q);
26         }
27     }
28 }
29 
30 int main(){
31     freopen("incantation.in","r",stdin);
32     freopen("incantation.out","w",stdout);
33     scanf("%d",&n);
34     rep(i,1,n) scanf("%d",&a[i]),ext(a[i]),printf("%lld\n",ans);
35     return 0;
36 }

 

posted @ 2018-03-28 17:12  HocRiser  阅读(207)  评论(0编辑  收藏  举报