CF1098F Ж-function

cnblogs

纪念一下第一道独立切的 \(\color{maroon}*3500\)

不过这种萌萌套路题是怎么 \(\color{maroon}*3500\) 的?虽然第一次见的时候感觉比较厉害,但这题是我第四次见这个套路,就觉得很板了。

值得注意的是,本题解中的做法不需要用到任何十级算法,且空间是线性的

在阅读本题解之前,请确保你会以下算法:

  • 线性 / \(1\log\) / \(2\log\) 后缀数组
  • 序列分治 / cdq 分治
  • \(1\log\) 二维偏序

毕竟这是一道 \(\color{maroon}*3500\) 的题目,所以主要讲思路,一些较为基础的东西以及实现细节就不细说了。

题目传送门

  • 给出长度为 \(n\) 的字符串 \(s\)。定义 \(Ж(l,r)=\sum\limits_{i=l}^r|\text{lcp}(s[l,r],s[i,r])|\)\(q\) 次询问,每次给出 \(l,r\),查询 \(Ж(l,r)\)

  • \(n,q\le 2\times 10^5\)\(\text{6 s / 500 MB}\)

先后缀排序。

将子串的 \(\text{lcp}\) 搞成后缀的 \(\text{lcp}\),则 \(Ж(l,r)=\sum\limits_{i=l}^r\min\{|\text{lcp}(s[l,n],s[i,n])|,r-i+1\}\)

然后将询问挂在 \(\text{rk}_{l}\) 上,分别计算 \(\text{rk}_i<\text{rk}_l\)\(\text{rk}_i>\text{rk}_l\) 的贡献,最后算上 \(l\) 本身的贡献。此时可以将 \(\text{lcp}\) 的限制转化成 \(\text{height}\) 数组的限制,即:

\[Ж(l,r)=\sum\limits_{i=1}^{\text{rk}_l-1}\left([l\le \text{sa}_i\le r]\cdot \min\left\{\min\limits_{j=i+1}^{\text{rk}_l}\text{height}_j,r-\text{sa}_i+1\right\}\right)+\sum\limits_{i=\text{rk}_l+1}^{n}\left([l\le \text{sa}_i\le r]\cdot \min\left\{\min\limits_{j=\text{rk}_l+1}^{n}\text{height}_j,r-\text{sa}_j+1\right\}\right)+(r-l+1) \]

我们先以 \(\text{rk}_i<\text{rk}_l\) 的情况为例讲一下怎么算贡献。

\(\text{height}\) 数组进行序列分治(其实此处比较像 cdq 分治),记当前分治区间为 \([L,R]\),中点 \(M=\dfrac{L+R}{2}\)\(N=R-L+1\)。考虑当前层右半边对左半边的贡献。

\(\text{pre}_j=\min\limits_{k=M+1}^R\text{height}_k\)。对于左半边按 \(M\rightarrow L\) 的顺序扫描 \(i\),并同时记录 \(\text{mn}=\min\limits_{k=i+1}^M\text{height}_j\)

考虑挂在 \(i\) 上的一个询问 \((l,r)\)

此时,存在 \(p\in[M+1,R]\) 使得当 \(j\in[M+1,p)\)\(\text{mn}\le \text{pre}_j\);当 \(j\in[p,R]\)\(\text{mn}>\text{pre}_j\)

化简第二层 \(\min\{\}\),那么右半边对 \((l,r)\) 的贡献就是:

\[\sum\limits_{j=M+1}^{p-1}([l\le \text{sa}_j\le r]\cdot\min\{\text{mn},r-\text{sa}_j+1\})+\sum\limits_{j=p}^R([l\le \text{sa}_j\le r]\cdot\min\{\text{pre}_j,r-\text{sa}_j+1\}) \]

由于 \(i\) 递减,\(\text{mn}\) 不升,因此 \(p\) 不降,最多递增 \(\mathcal{O}(N)\) 次。

然后将 \(\min\{\}\) 拆开,即讨论一下谁是最小值,此处我们只讨论前面那个数更小(不等于)的情况。因为两种讨论都是类似的。

对于 \(j\in[M+1,p)\) 的部分,我们要求 \(\sum\limits_{j=M+1}^{p-1}([l\le \text{sa}_j\le r\land \text{mn}<r-\text{sa}_j+1]\cdot \text{mn})\),提取公因式 \(\text{mn}\) 后发现是关于 \(j,\text{sa}_j\) 的二维偏序。可以用树状数组维护 \(\text{sa}_j\),在 \(p\) 移动时更新树状数组(就是扫描线)。

对于 \(j\in[p,R]\) 的部分,我们要求 \(\sum\limits_{j=p}^R([l\le \text{sa}_j\le r\land \text{pre}_j<r-\text{sa}_j+1]\cdot \text{pre}_j)\)

接下来是重点,也是这个套路最巧妙的一步。

如果按照之前的方法找偏序关系,发现是关于 \(j,\text{sa}_j,\text{sa}_j+\text{pre}_j\) 的三维偏序。你要是在分治内部再套个树套树 / cdq 分治的话复杂度肯定爆炸。

我们先求 \(\sum\limits_{j=p}^R([l\le \text{sa}_j\le r\land \text{mn}<r-\text{sa}_j+1]\cdot \text{pre}_j)\)。这东西拆开后是二维偏序,树状数组类似维护。

由于右半边 \(\text{pre}_j<\text{mn}\),漏算的贡献是 \(\sum\limits_{j=p}^R([l\le \text{sa}_j\le r\land \text{pre}_j<r-\text{sa}_j+1\le \text{mn}]\cdot \text{pre}_j)\)。你发现这还是个三维偏序,那不是白搞?别急,你发现当 \(j\in[M+1,p)\) 时,\(\text{mn}\le \text{pre}_j\),即 \(\text{pre}_j<r-\text{sa}_j+1\le \text{mn}\) 不成立。因此直接忽略掉 \(j\) 这一维限制即可!那么剩下的就是关于 \(\text{sa}_j,\text{sa}_j+\text{pre}_j\) 的二维偏序,由于扫描的是 \(p\),所以离线下来再树状数组维护即可。

那么这种情况就讨论完了。剩下的一种情况是类似的,尤其是对于 \([p,R]\) 这部分贡献三维偏序转二维偏序的时候,都是将 \(\text{mn}\) 代入二维偏序,再加上 \((\text{pre}_j,\text{mn}]\) 漏算的 / 减去 \((\text{pre}_j,\text{mn}]\) 多算的,然后通过不同区间 \(\text{pre}_j,\text{mn}\) 大小关系忽略 \(j\) 那一维限制。

至于 \(\text{rk}_i>\text{rk}_l\) 的情况,只是需要再分治的时候换成扫描右半边,对左半边维护后缀最小值,计算贡献部分经过瞪眼观察或手推后都可以发现是一模一样的。

那么这题就做完了。

\(i\) 这个位置上挂了 \(Q_i\) 个询问。可以发现一层分治的时间复杂度为 \(\mathcal{O}\left(\left(N+\sum \limits_{i=L}^RQ_i\right)\log n\right)\)。考虑到分治树的深度为 \(\mathcal{O}(\log n)\),且对于同一深度的区间而言 \(\sum N=n,\sum Q_i=q\)。所以总的时间复杂度为 \(\mathcal{O}\left((n+q)\log ^2 n\right)\),空间复杂度为 \(\mathcal{O}(n+q)\)。常数较大,但是目前洛谷最优解第三。实现细节看代码吧。

AC Link & Code

posted @ 2024-04-02 01:24  蒟蒻·廖子阳  阅读(29)  评论(0编辑  收藏  举报