【BZOJ4516】【SDOI2016】生成魔咒 [SAM]

生成魔咒

Time Limit: 10 Sec  Memory Limit: 128 MB
[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 次操作加入的魔咒字符。

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

  1≤n≤100000

Main idea

  询问在加入每一个字符后当前有多少个本质不同的子串。

Solution

  直接用SAM,根据SAM的性质,每次增多的子串个数就是len[New] - len[fa[New]]

Code

 1 #include<iostream>    
 2 #include<string>    
 3 #include<algorithm>    
 4 #include<cstdio>    
 5 #include<cstring>    
 6 #include<cstdlib>
 7 #include<cmath>
 8 #include<map>
 9 using namespace std;  
10 typedef long long s64;
11 
12 const int ONE = 400005;
13 const int INF = 2147483640;
14 
15 int n,x;
16 s64 Ans;
17 
18 int get()
19 {    
20         int res=1,Q=1;char c;    
21         while( (c=getchar())<48 || c>57 ) 
22         if(c=='-')Q=-1; 
23         res=c-48;     
24         while( (c=getchar())>=48 && c<=57 )    
25         res=res*10+c-48;    
26         return res*Q;
27 }
28 
29 struct SAM
30 {
31         map <int, int> a[ONE];
32         int len[ONE], fa[ONE];
33         int last, cnt;
34         SAM() {last = cnt = 1;}
35         void Add(int c)
36         {
37             int x = last, New = last = ++cnt;
38             len[New] = len[x] + 1;
39             while(x && !a[x][c]) a[x][c] = New, x = fa[x];
40             if(!x) {fa[New] = 1; Ans += len[New] - len[fa[New]]; return;}
41             
42             int q = a[x][c];
43             if(len[x] + 1 == len[q]) fa[New] = q;
44             else
45             {
46                 int Nq = ++cnt;    len[Nq] = len[x] + 1;
47                 a[Nq] = a[q];
48                 fa[Nq] = fa[q];
49                 fa[New] = fa[q] = Nq;
50                 while(a[x][c] == q) a[x][c] = Nq, x = fa[x];
51             }
52             Ans += len[New] - len[fa[New]];
53         }
54 }S;
55 
56 int main()
57 {
58         n = get();
59         while(n--)
60         {
61             x = get();
62             S.Add(x);
63             printf("%lld\n", Ans);
64         }
65         
66 }
View Code

 

posted @ 2017-05-28 16:21  BearChild  阅读(237)  评论(0编辑  收藏  举报