首页 > 编程语言 > 详细

后缀数组专题总结

时间:2019-12-25 19:23:48      阅读:91      评论:0      收藏:0      [点我收藏+]


曾经一度以为SA是大神知识点来着

后来才发现其实是泽州哥哥讲得太深奥了我等蒟蒻不能参透

理解了之后题还是可以做的

因为大多数都不是在SA上做文章而是与其他知识点结合

\(\% \% \%\)迪哥讲 \(SA\)\(SAM\) 钛聚啦)

放例题

  • 1.差异
    ?题意描述:求\(\sum\limits_{1\le i<j\le n}len(T_i)+len(T_j)-2\times lcp(T_i,T_j)\)

?算是SA的板子题了吧
?求出每个点能控制的区间,单调栈\(/\)二分都行,直接统计就行了

?

  • 2.Sandy的卡片
    ?题意描述:有n个串,求是所有串子串的最长串(相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串)

?SA一个套路就是把所有串连起来然后一块跑
?这题要求有相同的趋势,显然需要差分
?那么我们把原字符串差分之后连在一起跑一遍SA
?又发现答案显然有单调性,可以二分
?那么我们直接看是否有一个 \(height\) 始终\(>mid\) 的区间包含所有串就行了

?

  • 3.喵星球上的点名
    ?题意描述:\(a180285\) 幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择 \(M\) 个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用 \(ASCII\) 码来表示。为了方便描述,\(a180285\)决定用数串来表示喵星人的名字。
    现在你能帮助 \(a180285\) 统计每次点名的时候有多少喵星人答到,以及\(M\)次点名结束后每个喵星人答到多少次吗?

?把所有名,姓和询问串连起来跑一遍$ SA$,求出每个询问串能控制的区间
?然后问题就变成了询问区间内颜色个数以及每种颜色被多少种区间覆盖
?直接求不容易处理,考虑莫队
?第一问是板子,不讲
?第二问,只要在某种颜色出现时记录一下,然后在消失时统计答案就行了

?

  • 4.字符串
    ?题意描述:询问子串 \(s[a..b]\) 的所有子串和 \(s[c..d]\) 的最长公共前缀的长度的最大值

?发现答案满足单调性可以二分
?现在考虑询问某个串的子串中是否有和 \(s[c,d]\)\(lcp\ge mid\) 的串
?而我们可以很容易得到和一个串 \(lcp\ge mid\)\(rk\) 区间 \([l,r]\)
?那么我们只需要统计\([a,b-mid+1]\)中是否有排名\([l,r]\)之间的点了
?这个可以主席树维护

?

  • 5.相似子串
    ?题意描述:询问排名\(i\)\(j\)的子串的 \(lcp^2+lcs^2\)

?首先,一个串本质不同子串个数为\(\sum\limits_{i=1}^n n-sa[i]-height[i]\)且单调递增
?那么对于某个排名,我们可以二分出该串属于的后缀以及长度
?这样就可以求 \(lcp\)\(lcs\)

?

  • 6.品酒大会
    ?题意描述:两杯酒的相似度定义为他们的公共前缀(不一定最长),求所有相似度分别有多少对,以及每个相似度中能匹配的点最大的 \(a_i\times a_j\)

?考虑由低相似度\(i\)转到高相似度\(i+1\)
?发现相当与在所有 \(height=i\) 的点把序列断开
?然后发现总共的断开操作有n次
?所以我们从小到大枚举相似度,链表\(/ set\) 维护分界点
?每次插入一个分界点时,二分找到他两边的分界点,把之前区间的贡献减掉,再把新区间的贡献加上
?然后计算贡献我们需要找区间最大,次大,最小,次小值,用 \(RMQ\) 可以 \(O(1)\) 得到

?

  • 7.SvT
    ?题意描述:有一个长度为 \(n\) 的仅包含小写字母的字符串 \(S\),现在有若干组询问,对于每一个询问,我们给出若干个后缀,求这些后缀两两之间的 \(LCP\) 的长度之和

?这个东西怎么看怎么像单调栈
?我们排序后求出所有\(b[i]=lcp(a[i],a[i+1]) \ (1\ge i<t)\)
?用 \(b\) 数组做单调栈,求出控制区间,就可以直接统计答案了

?

  • 8.跳蚤
    ?题意描述:很久很久以前,森林里住着一群跳蚤。一天,跳蚤国王得到了一个神秘的字符串,它想进行研究。首先,他会把串分成不超过 \(k\) 个子串,然后对于每个子串 \(S\),他会从 \(S\) 的所有子串中选择字典序最大的那一个,并在选出来的 \(k\) 个子串中选择字典序最大的那一个。他称其为“魔力串”。现在他想找一个最优的分法让魔力串字典序最小。

?大神题啊
?首先这个万意显然是单调的,可以二分
?我们知道有了排名可以唯一确定一个子串t
?那么我们二分排名,得到了这个排名的子串,考虑怎么 \(check\)
?我们从后往前贪心,发现如果之前是合法的,那么当且仅当s[i,lst]合法时目前状态合法
?那么我们只需要比较s[i,lst]和t的大小关系
?这个东西可以用RMQ弄出来

?

  • 9.股市的预测
    ?题意描述:求一个串中 \(ABA\)‘(\(A,A\)‘趋势相同)的段数

?(并不知道思路是怎么想到的)
?考虑设置关键点
?首先枚举A的长度L,然后在 \(1,1+L,1+2L\)......设置关键点
?然后对于每个关键点 \(i\),求出 \(i\)\(i+m+L\)\(lcp\)\(lcs\)
?发现所有和 \([i-lcs,i+lcp],[i+m+L-lcs,i+m+L+lcp]\) 同时有交的长度为 \(m\) 的区间都会贡献答案
?这个答案为 \(min(min(L,lcp)+min(L,lcs))-L\)
?又因为同一长度下一个区间被且仅被一个关键点经过
?所以这样可以做到不重不漏

后缀数组专题总结

原文:https://www.cnblogs.com/mikufun-hzoi-cpp/p/12098432.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!