后缀自动机专题

mac2024-07-29  84

这个专题只是用来记录刷题的,不放代码了,而且以前刷过不少的都不会放上来。只记录从2019.10.31后的。

[Poi2000]公共串

给出几个串,问你他们的最长公共子串。

SOLUTION:其实这题因为长度太小,所以SAM和广义SAM都随便做。 SAM的话,取最小的串建SAM,然后用其他的串在上面跑,每次更新每个节点匹配的最长len,每次再对答案取min就行,这样的复杂度就是 O ( m i n l e n ∗ n ) O(minlen * n) O(minlenn)的。 如果是广义SAM,建好了之后树上打标记,拓扑排序就可以维护啦。 但是这样的复杂度是 O ( m a x l e n ∗ n ) O(maxlen *n) O(maxlenn)的。

2019南京区域赛热身赛D

题意就是,给你若干个串,命名为 T 1 , T 2 , . . . , T n T_1,T_2,...,T_n T1,T2,...,Tn,需要计算 ∑ ∀ s t r i n g S ∏ i = 1 n r i ( S ) \sum_{\forall string S} \prod_{i = 1}^n r_i(S) stringSi=1nri(S) 其中 r i ( S ) r_i(S) ri(S)表示 S S S这个串在 T i T_i Ti中作为子串出现了多少次。 数据范围满足 ∑ i = 1 n s t r l e n ( T i ) ≤ 8 e 5 \sum_{i = 1}^n strlen(T_i) \leq 8e5 i=1nstrlen(Ti)8e5

SOLUTION:用SAM的话同上,取最小的串建SAM,然后每次跑一遍维护一下每个节点的right即可。 如果是广义SAM,就很日了。因为 O ( m a x l e n ∗ n ) O(maxlen*n) O(maxlenn)是不可以接受的,所以你需要虚树,每次打标记的时候,在虚树上差分,打乘法标记,以及要对一些节点清0,于是还需要打被多少个串覆盖了的标记。

BZOJ 4180 字符串计数

题意:给你一个字符串T,你可以选择它的若干子串拼成长为n的字符串S,定义S的拼接次数为最少的子串个数使得他们拼起来为S,现在给出T和n,问你对于所有的S来说,最大的拼接次数为多少? SOLUTION:因为子串的特殊性质,所以只要判断这个子串往后拼接的下一个子串的首字符是否能和这个子串拼起来得到的还是T中的子串就行(因为你要加入的子串长度应该是极大的),那么你考虑对于全局来说,也就是可以用 f i , j f_{i,j} fi,j来表示 i i i这个字母后面拼 j j j这个字母在满足极大情况下的最短长度是多少。 接下来就是考虑怎么求 f i . j f_{i.j} fi.j,建SAM,极大这个条件会表现为 s t st st这个状态是否有 j j j这个儿子。(在转移的trie中考虑),那么设 g i , j g_{i,j} gi,j表示 i i i这个状态后面不能接 j j j这个字母的最小长度。 转移就是 g i , j = m i n ( g c h [ i ] [ k ] , j ) ,   i f   c h [ i ] [ k ] ! = N U L L g_{i,j} = min(g_{ch[i][k], j}) , \ if \ ch[i][k] != NULL gi,j=min(gch[i][k],j), if ch[i][k]!=NULL 初值为 g i , j = 1 , i f   c h [ i ] [ j ] = = N U L L g_{i,j} = 1, if \ ch[i][j] == NULL gi,j=1,if ch[i][j]==NULL g i , j = I N F , i f   c h [ i ] [ j ] ! = N U L L g_{i,j} = INF, if \ ch[i][j] != NULL gi,j=INF,if ch[i][j]!=NULL 然后我们可以二分答案,然后MIN-PLUS Product来获得这样的长度是否会小于等于n Remark:貌似数据有点问题,比如 4 4 4 D D A A B B D D B D DDAABBDDBD DDAABBDDBD 这个答案是3不是4,但是所有A掉的代码都是4…好像是他们认为如果最后二分完的答案不够N的长度的话要+1?然而因为定义的是最小操作次数所以不应该+1(x

最新回复(0)