Runs 学习笔记
定义一个字符串 \(|S|\) 里的一个 run,指其内部一段两侧都不能扩展的周期子串,且周期至少完整出现两次。
严格地说,一个 run 是一个 三元组 \((i,j,p)\),满足 \(p\) 是 \(S[i..j]\) 的最小周期,\(j-i+1 \ge 2p\),且满足如下两个条件:
- 要么 \(i=1\),要么 \(S[i-1]\ne S[i-1+p]\);
- 要么 \(j=n\),要么 \(S[j+1] \ne S[j+1-p]\)。
性质一:\(|\{(l,r,p)\}|\) 为 \(\mathcal{O}(n)\) 级别的。
性质二:\(\sum\frac{r-l+1}{p}\) 也是 \(\mathcal{O}(n)\) 级别的。
性质三:\(\sum r-l+1-2p\) 是 \(\mathcal{O}(n\log n)\) 级别的。
性质四:Runs on sam (我取的神秘名字)
怎么求出所有的 runs?
考虑进行 优秀的拆分 的套路,先求出所有的“伪 Runs”(两边不能再拓展,但是周期不一定是最小)。
注意到这些“伪 Runs”只是 \(p\) 不对,于是对于所有 \((l, r)\) 保留最大的唯一的 \(p\)。
第一步求的伪 Runs 是 \(\mathcal{O}(n)\) 的,第二步进行基数排序可以减小常数。
感觉实际上直接用个 map<pair<int, int>> 去重就,差不多得了。
例题一:区间 \(A^2\) 串计数(不要求本质不同)
分两种,若 Runs \(l, r\) 被区间 \(L, R\) 完全包含,则可以用扫描线计算贡献。否则,相当于和区间相交于 \(L-1\) 或 \(R+1\),这种 Runs 共有 \(\mathcal{O}(\log n)\) 个,直接拿出来求贡献即可。
例题二:区间本质不同 \(A^k(k\ge 2)\) 串计数
例题三:区间本质不同 \(A^2\) 串计数
求出所有 Runs。
对于一个询问 \(l, r\),将有贡献的 Runs 分成两种:
- \(R\le r\)
- \(R>r\)
对于第一种,我们扫描线维护,由于我们扫的时候能确定这个 Runs 内所有的本质不同 \(A^2\) 串的出现位置,所以我们直接用树状数组维护即可。
第二种只有 \(\mathcal{O}(\log n)\) 个。
所以我们扫描线,扫到 \(r\) 的时候找出所有包含 \(r\) 的 Runs 中的最长 \(A^2\) 串,消去它之前的贡献,然后把所有以 \(r\) 结尾的 Runs 的贡献加到 BIT 里。
核心思想是一口去处理单个 runs 内的所有的 \(A^2\) 串。(需要维护一个 \(A^2\) 串最后出现在哪个 Runs 里,而不是具体位置)。
部分做法需要一个称之为 「斜线加,矩形求和」的东西。
即:在一开始给出若干条射线,从 \((x, y)\) 开始向右上,斜率为 \(1\)。
最后有若干次矩形查询。
考虑将矩形查询分成跨过一条平行 \(x\) 轴的线和平行 \(y\) 轴的线。
不妨以跨过平行于 \(y\) 轴的线为例。
\((x, y)\) 过 \((X,0) - (X,Y)\) 的条件为
- \(x\le X\)
- \(y+X-x\le Y\),变形后得 \(y-x\le Y-X\)。
贡献是 \(X-x\)。则我们可以用一个线段树维护这个过程。
过平行于 \(x\) 轴的线类似。(以上皆为口胡,因为笔者并没有真正写过这个做法)。
斜线加矩形求和将成为时代的眼泪。—— 我。

浙公网安备 33010602011771号