[JZOJ3975] 串

Description

给定 n 个字符串,询问每个字符串Si有多少子串(不包括空串)是所有 n 个字符串中至少k个字符串的子串。

n,Si105

Analysis(SAM)

首先所有串之间连个符号,一起建个SAM。
然后枚举每一个串,把它所有的子串所在的状态的出现次数+1。
就是 parent 树上 root 到它所有状态+1,但是这样在一个串中会重复+1,所以加到一个当前串中加过的状态就不加了。

这个如果是一维数据结构就离线排序,在树上就按 dfn 序排序。

然后有个小坑,我们想要的一个状态代表的字符串的数目, 不再是 lenplenfap ,因为字符串有可能包含那个符号,所以要重新遍历一次计算一个状态代表的数目,这个就是 cntv=cntu(gou,c=v)

现在计算答案,由串来走,走到一个状态,答案的贡献应该是 root 到它的所有代表的数目(若出现次数大于 k )。

然而看到某人的博客,不用连起来建SAM,只需建完一个字符串把last搞成 root 就行了。(正确性我不太清楚)

有一个小问题:
走到一个结点,当前走过的串是否是该结点的最长子串呢?
答案是肯定的,若不是该结点的最长子串,
但该结点的 Right 集合包含当前的结尾,所以矛盾。

时间复杂度: O(N log N)

Analysis(SA)

首先,一样地,所以的串连起来,中间用一个没出现过的字符,构建SA。预处理出 stepi ,表示 SAi 最少往上多少,使得出现了 k 个字符串。

枚举某个字符串,计算其suffixi,可以扩展到的位置 j 。显然随着i增加, j 也会增加。那么我们在SA中,二分出suffixi往上往下最多到多少,之间的 heightji+1 ,然后看下面二分出的位置的 step 值能否到达上面二分出的位置。

时间时间复杂度: O(N log N)

Summary

虽然SAM做法说起来有点麻烦,但我觉得这种处理方式还是很机智的,有很多值得一提的地方。

  • dfn 序来操作
  • 重新计算每个状态代表的字符串
  • 沿 parent 树更新的思想
  • 连起来一起建SAM时,走到一个状态,当前一定走出其代表的最长子串

而SA做法因有把所有后缀排序的先天优势,所以思路看起来比较简单,但也有值得一提的地方。

  • 在SA上二分合法位置
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值