[BZOJ4516][SDOI2016]生成魔咒(后缀自动机)
4516: [Sdoi2016]生成魔咒
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1549 Solved: 899
[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 次操作加入的魔咒字符。1≤n≤100000。,用来表示魔咒字符的数字 x 满足 1≤x≤10^9Output
输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量
Sample Input
7
1 2 3 3 3 1 2Sample Output
1
3
6
9
12
17
22HINT
Source
[Submit][Status][Discuss]
SAM裸题?son数组用map存,实时统计mx[i]-mx[fa[i]]即可。
1 #include<map> 2 #include<cstdio> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 typedef long long ll; 6 using namespace std; 7 8 const int N=400100; 9 map<int,int>son[N]; 10 int cnt=1,lst=1,p,np,n,mx[N],fa[N],a[N]; 11 ll ans; 12 13 int F(int x){ return mx[x]-mx[fa[x]]; } 14 15 void ext(int c){ 16 p=lst; np=lst=++cnt; mx[np]=mx[p]+1; 17 while (p && !son[p][c]) son[p][c]=np,p=fa[p]; 18 if (!p) fa[np]=1,ans+=F(np); 19 else{ 20 int q=son[p][c]; 21 if (mx[q]==mx[p]+1) fa[np]=q,ans+=F(np); 22 else{ 23 int nq=++cnt; mx[nq]=mx[p]+1; son[nq]=son[q]; 24 while (p && son[p][c]==q) son[p][c]=nq,p=fa[p]; 25 fa[nq]=fa[q]; ans+=F(nq)-F(q); fa[q]=fa[np]=nq; ans+=F(np)+F(q); 26 } 27 } 28 } 29 30 int main(){ 31 freopen("incantation.in","r",stdin); 32 freopen("incantation.out","w",stdout); 33 scanf("%d",&n); 34 rep(i,1,n) scanf("%d",&a[i]),ext(a[i]),printf("%lld\n",ans); 35 return 0; 36 }