【JZOJ4473】Incantation Solution

【题目大意】
        有 n 次操作,每次往序列 A 末尾插入一个元素,问每次插入后,新产生了多少个本质不同的连续子序列。


【30%】n<=100
        注意新产生的子序列必然是当前 A 的后缀序列,因此我们枚举当前 A 的后缀序列 S,然后再枚举 A 的所有除 S 以外的连续子序列,看看有没有相同,如果都没有相同,那么 ans+1。

        时间复杂度 O(n^4)


【60%】n<=1000
        暴力枚举 A 的所有连续子序列是 30 分做法慢的主要原因,因此我们采用哈希判重。还是枚举当前 A 的后缀序列 S,然后哈希判一下有没有出现过,再把 S加到哈希中。

如果把哈希看成是 O(1)的话,那么时间复杂度是 O(n^2)


【100%解法 1】n<=10^5
        上述文字中出现了“本质不同”“后缀”等字眼,各位应当联想到,我们要把序列抽象成字符串。
        对于 i 位置插入的元素,新产生的子串是 A[1..i]、A[2..i]、A[3..i]……A[i],不考虑本质不同的话贡献就是 i 个。假设存在 j<i,使得 A[j’..j]=A[i’..i],那么对于任意 k∈[i’..i],A[k..i]都是没有贡献的。即如果我们找到了最小的 i’,那么 i’及以后的位置是没贡献的,而 i’以前的位置是有贡献的。如何找这个最小的 i’?我们把A 反序,就会发现,我们实际上是在找 i 开头的后缀与 i’(i<i’)开头的后缀的 LCP(最长公共前缀)。
        我们把 A 反序后建立后缀数组,然后从大到小枚举 i,对于位置 i 的插入操作,我们找后缀 i 与所有后缀 j(i<j)的 LCP,然后 n-i+1-LCP 就是 i 位置新产生的贡献。如何找后缀 i 与后缀 j 的 LCP?可以以 SA 为下标弄一棵线段树,每插入一个位置 i,就在 rank[i]的位置打个标记。当我们要找 LCP 的时候,就从 rank[i]开始,往前找到最近的标记点 j,往后找到最近的标记点 k,那么 max(LCP(i,j),LCP(i,k))就是我们要找的 LCP。这个东西可以用任意一种 log 的数据结构维护,比如线段树、树状数组什么的。

        时间复杂度 O(nlogn)


【100%解法 2】n<=10^5
        既然要找后缀 i 与所有后缀 j(i<j)的 LCP,我们可以直接用后缀自动机,该后缀与之前后缀的最大 LCP 即为其 father 的 maxlen,那么该后缀的贡献应为该点的 maxlen 减 father 的 maxlen。
        时间复杂度远小于 O(n log n)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值