首页 > 代码库 > 【BZOJ4516】【SDOI2016】生成魔咒 [SAM]

【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 SAM30 {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             else45             {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

 

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