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 }