Border & 最小后缀

Border & 最小后缀

https://www.luogu.com.cn/blog/command-block/border-li-lun-xiao-ji

Border

  1. S[1,p] 是 border <=> S 有周期 len-p。
  2. S 的长度大于等于 n/2 的 border 长度构成一个等差数列。
  3. S 的所有 border 排序后组成的数组,可以划分成 \(O(\log{len})\) 个等差数列。
  4. S 公差大于等于 d 的 border 等差数列的总长度是 \(O(\frac{n}d)\) 的。
  5. 回文 border 理论:S 的回文后缀长度集合,可以划分成 \(O(\log len)\) 个等差数列。

最小后缀

\(ssuf(S)\) 为【存在一种 在 S 后面加一个串 的方案,使得此后缀为最小后缀】的后缀集合。

\(|ssuf(S)|\le O(\log len)\)

例题: ZJOI2017 字符串;节日庆典。

CF917E - Upside Down

https://www.luogu.com.cn/problem/CF917E

这道题不评 3500???还是我目光短浅了!!!

三种情况,一种是 \(u\)\(v\) 的祖先,一种是 \(v\)\(u\) 的祖先,还有以上都不是。(upd:其实不是这样的,是对于一个询问,拆成上面三种情况之和)

对于前面两种:

硬点 \(u\)\(v\) 的祖先,如果不是就把 \(s_k\) 反过来。那么答案就是 \(ans(1,v)-ans(1,u+|s_k|-2)\),后面那个指的是 \(u-v\) 的路径上,\(u\) 的第 \(u+|s_k|-2\) 个儿子,也就是 \(v\) 的第 \(dep_v-dep_u-|s_k|+1\) 个祖先。

于是我们要处理根到 \(x\) 的答案,那么我们 dfs 向前走,对应在 AC 自动机上向前走(回溯的时候就是返回),并给走过的点加权。并把树上的点的询问处理一下。

具体:走的时候给点加一,询问的时候查询对应点的 \(fail\) 树和,用树状数组即可维护。

对于后面一种:

对于一组询问 \((u,v,lca,s)\)。我们预处理出 \(u \to lca\) 的后缀 与 s 的前缀 的 极长匹配串 \(A\);预处理出 \(lca\to v\) 的前缀 与 s 的后缀 的 极长匹配串 \(B\)。(预处理方法见后文)

我们知道将串 T 的长度为 x 的前缀和长度为 y 的后缀拼起来,如果 \(x+y=|T|\),那么拼起来的串就等于 T。

所以我们求出 A 的 border:\(A'\),以及 B 的 border:\(B'\),那么 \(A',B'\) 肯定是 s 的前缀和后缀,而且他们可以通过 lca 处拼接起来。所以我们找到所有的 \(|A'|+|B'|=|s|\) 的 border 就可以了。

由于 border 可以变成 log 段等差数列,那么我们暴力地枚举 A 和 B 的每一段等差数列,那么就相当于求 \(x_1+y_1p+x_2+y_2q=|s|\) 的解(upd:\(p,q\) 是变量),用 exgcd 求出一组解然后算出方案数即可。\(O(\log^2)\)

至于 \(p,q\) 怎么求?相当于是,我要求某个串的前缀的所有 border(后缀就是反串的前缀),那我直接暴力地搞就好了。我的 border 集合就是我的最长 border 并上我的最长 border 的最长 border 集合。然后暴力继承状态就好了,因为是 \(O(\log)\) 的所以可以(吧?)。

怎么预处理出 A,B?(下文说 B,A 可以举一反三)

我们建出 \(s\) 的后缀数组,然后就可以二分出 B 可以匹配到 \(s\) 的哪个位置。check 的方式就是找到 【当前二分到的后缀 \(B'\)】与 \(lca\to v\) 的大小关系,也就是比对 lcp 的下一位。用 hash + 二分即可。\(O(\log^2)\)

但是找到匹配的位置后,可能 \(B'\) 的长度大于 \(lca\to v\),于是就跳到 \(B'\) 的最大 border。如果还是大于,那就再跳到最大 border...一直跳到 \(B'\) 的长度小于等于 \(lca\to v\) 为止。因为求 border 可以用 KmP 实现,所以倍增 KmP 即可。倍增 KmP 就相当于连边 \(i\to kmp_i\)\(i\)\(2^j father\)

代码:http://www.gdfzoj.com/submission/131585 当然是没有调试的,因为实在是太 NT 了!

loj6681 - yyw 与回文串

https://loj.ac/p/6681

考虑点分治,跨过分治中心的点 \(c\) 的回文串有多少。

那么回文串肯定是这样的:比如某个子树的 \(u\) 到另一个子树的 \(v\) 是回文串,且 \(|s[u\to c]|>|s[c\to v]|\) 那么 \(s[u\to c]=T+S,s[c\to v]=S\) 其中 \(T\) 是一个回文串。

我们把前面的子树都塞进 ACAM 中(对应的结束节点权值加一),于是考虑当前 dfs 的子树的贡献。

边走边在 ACAM 上对应地走。

如何判断现在的串是不是一个回文串?用哈希判断正串与反串是否全等即可!

我们维护现在所有的回文后缀,那么如果我现在 dfs 到的字符串长度为 \(l\),而某一个回文后缀长度为 \(x\),那么贡献就是 ACAM 点的 \(l-x\) 辈祖先的权值。

但是可能有千军万马的回文后缀。不过,根据 Border 定理 5,可以变成 Log 个等差数列。

于是我们记录所有等差数列的 首项 \(a_0\),公差 \(d\),末项 \(a_a\),然后我就看 ACAM 点的 \(l-a_0,l-a_0-d,l-a_0-d-d...\) 辈祖先即可。也就是 \(x\) 辈祖先,\(x\bmod d=a_0\bmod d,x\in [l-a_0,l-a_a]\)

对于 \(d\le sqrt(n)\) (实测 \(d\le 4\) 更快)的,我们开一个桶,就是 \(box[i][j]\) 就是 \(\% i=j\) 的祖先的权值和。

对于 \(d\le sqrt(n)\) 的暴力即可。

CF1286E - Fedya the Potter Strikes Back

https://www.luogu.com.cn/problem/CF1286E

对于第 \(n\) 次操作,答案就是 \(n-1\) 的答案加上 \(s[1,n]\) 的 border。

定义一个 border 的颜色,就是其下一个字符是什么。

于是每次都将 \(n\) 插入 KmP 自动机,找到所在点 到根 的所有颜色不等于 \(s[n]\) 的点,将其对应的 border 删除(不是在自动机上删除)。

现在有两个问题:

  1. KMP 树上的节点为什么不需要删除?
  2. 删除后,剩下 border 集合,是否需要全部 +1?
  3. 代码中为什么写 del(i-u)

答案:

  1. 如果一个 border 被删除了,他可能之后又会被加上来,所以不用删除。但是如何证明其正确性?显然我每一次都会把 \(i\) 号节点接在他的 border 上面,所以是正确的(原来这么简单,亏我想了好久)。
  2. 不需要,我们每一次会把 \(i\) 号节点接在他的 border 上面,所以对应的 border 集合,其实就是他的祖先们。
  3. 因为 border 的长度是 i-u

CF1043G - Speckled Band

https://www.luogu.com.cn/problem/CF1043G

如果 \([l,r]\) 中没有相同的字母,那么就无解,显然。下面讨论有解情况!

答案肯定不超过四,因为我可以找到任意两个相同的字母的位置 \(x,y\),最劣答案就是 \([l,x-1],[x,x],[x+1,y-1],[y,y],[y+1,r]\),其中 \([x,x],[y,y]\) 是本质相同的,所以答案是 4.

然后我们依次 check 能不能有更优解:

  1. ans=1 即 AAAA,枚举 len 的所有质因子,看是否有这个周期。这是 \(O(\sqrt n)\)

  2. ans=2 即 AAB,BAA,ABA。

    对于前两者:预处理出 \(L_i,R_i\) 代表从 \(i\) 开始 向左/向右 最短的 AA 串长度。

    对于后者:要求出最 \([l,r]\) 的 border。

  3. ans=3 即 ABAC,BACA,BAAC。

    对于前两者:A肯定是单个字母。于是判断是否有一个和开头相同的字母;是否有一个和末尾相同的字母即可!

    对于后者:找到中间一个位置 \(i\) 使得 \(R_i\le r\),ST 表即可。

  4. ans=4 如果上面的所有的一切的最终的全部的情况全部判定失败那么就是 4。

于是我们发现最难处理的就是 ans=2 的情况。会了 ans=2 其它都迎刃而解,大闹天宫!


\(L_i,R_i\)

我们枚举 A 的长度为 len,然后每隔 len 就设立一个关键点:

-----O-----O-----O----...

如果一个串包含两个关键点,那么他就有可能是一个 AA 串。

对于两个关键点间组成的串,我们算出他的 LcS 和 LcP:二分+Hash。据说可以用 Height 数组 ST 地 \(O(1)\) 处理,但是因为我连 Height 都不知道是什么,只好遗憾地向世界谢幕。

如果 LcS+LcP \(\ge\) len 那么就是一个可行的方案。具体看https://www.luogu.com.cn/problem/solution/P1117

出现的区间是:从 lcs 开始 +2Xlen,直到现在位置 +2Xlen 大于 lcp 为止。

也就是:\(i-lcs\sim i+lcp-len+1\)


注:这里我还是没理解……

\([l,r]\) 的最短 Border:

有一个奇怪的做法:先判断有没有 \(1\sim sqrt(len)\) 的 border,如果没有,那么最短 border 与原串的后缀排名小于 \(sqrt(len)\)

问题:这里的后缀排名是 \(s[l,r]\) 的后缀排名,还是 \(s[1,n]\) 的后缀排名?

经过瞪眼代码,是 \(s[1,n]\) 的。

比如 abbabbabbabb,然后 \(sqrt(len)=2\)(就先这样假设着),那么最短 border 是 abb,其它 border 还有 abbabbabbabbabb 等等……

待填。。。

P4156 - 论战捆竹竿

https://www.luogu.com.cn/problem/P4156

显然我们求出所有的周期(即 n-|border|),然后就变成了同余最短路。

设周期集合为 \(a_i\),我们即求 \(\sum a_ix_i\le w\) 的方案数(其中 \(w:=w-n\))。

暴力去连边可以得到 30分的好成绩

因为这样是 \(O(n^2)\) 的。

但是由于周期可以变成 \(O(\log )\) 个等差数列。我们对于每一个等差数列分别考虑!

假设现在有一个等差数列 \(a_0,a_0+d,a_0+2d,a_0+3d...a_0+kd\),那么在 \(\bmod a_0\) 的剩余系下,我们可以得到 \(\gcd(d,w)\) 个环。对于每个环我们用 \(O(环长)\) 的时间复杂度去考虑,那么总共就是 \(O(n\log n)\) 的!

那么怎么样考虑呢?我们相当于用 \(dis_i\) 去更新 \(dis_{i+x}\) 什么的,显然 \(dis\) 最小的点是不会被更新的。

而且,在一个环中,相当于我们每次可以走 \(d,2d,3d...kd\) 步。那么用一个单调队列维护即可。

那么怎么从一个 \(a\) 剩余系转移到 \(b\) 剩余系?

考虑 \(dis_i\) 的意义,就是达到 \(\pmod a\) 的意义下,余 \(i\) 的最小数字是什么。那么 \(dis_x\to dis_{dis_x\bmod b}\) 即可。

PS:这道题好像只是用字符串做表象,掩盖其是毒瘤图论题的真相 23333

posted @ 2022-03-15 21:19  BlankAo  阅读(295)  评论(0编辑  收藏  举报