题目大意:
两种操作:
对字符串s(初始为空串)
1: 在s末尾加一个小写字母
2:删除s的第一个元素(保证删除后s非空)
每完成一个操作,记sum[i]为当前s串的不同子串, 求sigma{sum[i]}
...比赛期间怎么也想不到做法...基本上乱七八糟的做法都想过...还是不会...
后来看了ACRush的代码,终于会了...
做法如下:
记串[i,n) 为suffix[i]
---------
以样例来演示:
8
+ a
+ b
+ a
+ a
-
-
-
+ a
得到串"abaaa"
求一次后缀数组,得到
a
aa
aaa
abaaa
baaa
当前s=0, t=-1
+ a
---------
s = 0, t = 0
加入suffix[0]
a | baaa (0) ( | 用来划分有效长度)
+ a
---------
s = 0, t = 1
加入suffix[1]
ab | aaa (0)
b | aaa (1)
+ a
---------
s = 0, t = 2
加入suffix[2]
a | aa (2)
aba | aa (0)
ba | aaa (1)
+ a
---------
s = 0, t = 3
加入suffix[3]
a | a (3)
aa | a (2)
abaa | a (0)
baaa | a (1)
-
---------
s = 1, t = 3
删除suffix[0]
a | a (3)
aa | a (2)
baaa | a (1)
-
---------
s = 2, t = 3
删除suffix[1]
a | a (3)
aa | a (2)
-
---------
s = 3, t = 3
删除suffix[2]
a | a (3)
+ a
---------
s = 3, t = 4
加入suffix[4]
a (4)
aa (3)
以上操作可以通过 set + 链表实现
set<int>::iterator e = S.lower_bound(rank[g]);
if(e == S.begin()) pre = n;
else pre = sa[*(--e)];
那么现在要做的就是完成以上操作的同时得到不同子串个数。
记子串个数为cur
记与以前重复的串个数为over
记答案为ans
对于 + 操作
我们插入suffix[t]
那么
更新链表/set
over -= lcp(pre[t], next[t]);
over += lcp(pre[t], t)
over += lcp(t, next[t])
同时要注意。如果lcp(pre[t], t) 或者 lcp(t, next[t])大于suffix[t]的有效长度,则暂不插入。因为当前来说这个串及它后面的串都是重复串。
简单证明如下。suffix[t+1] 是 suffix[t]的子串, 现在suffix[t]是 某个串的子串, 则suffix[t+1]也是某个串的子串。
对于 - 操作
更新链表/set
over -= lcp(pre[t], t)
over -= lcp(t, next[t])
over += lcp(pre[t], next[t])
cur 可以通过简单计算得到
ans += cur - over
搞定~