您的位置:首页 > 产品设计 > UI/UE

CodeChef | September Challenge 2013 | To Queue or not to Queue

2013-09-17 01:16 483 查看
题目大意:

两种操作:

对字符串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

搞定~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: