bzoj4516: [Sdoi2016]生成魔咒(SAM)

4516: [Sdoi2016]生成魔咒

题目:传送门 

 


 

 

题解:

   真奥义之SAM裸题...

   其实对于当前新增节点x的操作,每次对ans的贡献就是dep[x]-dep[fail[x]](根据fail指针的定义随便YY)

   然后有思路之后乍看题目每个x是10^9...瞬间GG

   %了已发cc然后被D飞,直接上map啊

    


 

 

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<map>
 7 using namespace std;
 8 typedef long long LL;
 9 int a[110000],root,last,cnt,n;
10 LL ans;
11 map<int,int>ch[210000];
12 int fail[210000],dep[210000];
13 void add(int k)
14 {
15     int x=a[k];
16     int p=last,np=++cnt;dep[np]=k;
17     while(p && ch[p][x]==0)ch[p][x]=np,p=fail[p];
18     if(p==0)fail[np]=root,ans+=LL(dep[np]);
19     else
20     {
21         int q=ch[p][x];
22         if(dep[q]==dep[p]+1)fail[np]=q,ans+=LL(dep[np]-dep[q]);
23         else
24         {
25             int nq=++cnt;dep[nq]=dep[p]+1;
26             ch[nq]=ch[q];fail[nq]=fail[q];
27             fail[q]=fail[np]=nq;
28             while(p && ch[p][x]==q)ch[p][x]=nq,p=fail[p];
29             ans+=LL(dep[np]-dep[nq]);
30         }
31     }
32     last=np;
33 }
34 int main()
35 {
36     scanf("%d",&n);ans=0;
37     cnt=0;root=last=++cnt;
38     for(int i=1;i<=n;i++)
39     {
40         scanf("%d",&a[i]);add(i);
41         printf("%lld\n",ans);
42     }
43     return 0;
44 }

 

posted @ 2018-04-03 21:01  CHerish_OI  阅读(151)  评论(0编辑  收藏  举报