Bzoj4516 [Sdoi2016]生成魔咒

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 947  Solved: 529

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

 

字符串 后缀自动机

刷刷水题233

每添加一个字符,ans+=L[np]-L[fa[np]]

想一想,为什么?(逃)

 

后缀自动机上一个结点存的可能是多个后缀(也就是多个串),根据SAM的基本概念可以知道,这些串的长度互不相同且连续变化,记其中最长的长度为max,最短的长度为min,那么就有max-min+1个不同的串。

又根据SAM的性质可以知道min[x]=max[fa[x]]+1,所以这个结点有$ max[x]-(max[fa[x]]+1) +1 $个不同的串。

后缀自动机上不同的结点存的串本质不同,所以可以如上累加。

 

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<vector>
 8 #include<map>
 9 #define LL long long
10 using namespace std;
11 const int mxn=201010;
12 int read(){
13     int x=0,f=1;char ch=getchar();
14     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
15     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
16     return x*f;
17 }
18 void write(LL x){
19     if(x<0)putchar('-'),x=-x;
20     if(x>9)write(x/10);
21     putchar(x%10+'0');
22     return;
23 }
24 struct SAM{
25     map<int,int>t[mxn];
26     int fa[mxn],l[mxn];
27     int S,last,cnt;
28     LL ans;
29     void init(){
30         S=last=cnt=1;ans=0;
31         return;
32     }
33     void add(int c){
34         int p=last,np=++cnt;last=np;
35         l[np]=l[p]+1;
36         for(;p && !t[p][c];p=fa[p])t[p][c]=np;
37         if(!p){fa[np]=S;}
38         else{
39             int q=t[p][c];
40             if(l[q]==l[p]+1){
41                 fa[np]=q;
42             }
43             else{
44                 int nq=++cnt;
45                 l[nq]=l[p]+1;
46                 t[nq]=t[q];
47                 fa[nq]=fa[q];
48                 fa[q]=fa[np]=nq;
49                 for(;p && t[p][c]==q;p=fa[p])t[p][c]=nq;
50             }
51         }
52         ans+=l[np]-l[fa[np]];
53         return;
54     }
55 }sa;
56 int n,x;
57 int main(){
58     int i,j;
59     n=read();
60     sa.init();
61     for(i=1;i<=n;i++){
62         x=read();
63         sa.add(x);
64         write(sa.ans);puts("");
65     }
66     return 0;
67 }

 

posted @ 2017-03-31 21:43  SilverNebula  阅读(330)  评论(2编辑  收藏  举报
AmazingCounters.com