border 专项训练

link

A

显然可以分治计算,我们只需要计算跨过中点(含 \(t\) 也就是的匹配次数,就可以递归处理)

那么这就相当于是枚举匹配位置,查前面的后缀和后面的前缀能否匹配,可以暴力地贪心扩展若干轮直到 \(|s_i|\ge 10^6\),这时候直接利用哈希判断即可。

复杂度大概是 \(O(\sum |w|k)\) 的?可能稍卡,但当层数较大时,我们会发现本质不同的 \(t_i\) 只有 \(26\) 个,所以 \(k\) 是可以降下来的。

不过也可以推一推贡献系数来做?

B

\(f^k(i)\)\(i\) 跳了 \(k\)\(nxt\) 得到的东西,设 \(S(i)=\lbrace f^j(i)|j\in N,f^j(i)>0\rbrace\),要求即为:

\[\sum_{i=1}^n\sum_{j\in S(i)}A_iB_{i-j+1} \]

考虑 \(A\) 是一个附加系数,可以拿出来,不妨设 \(g(i)=\sum_{j\in S_i}B_{i-j+1}\)

问题变为求出 \(g(i)\)

观察下标形式 KMP 算法可以发现,若 \(x\in S(i),x>1\)\(x-1\in S(i-1)\),因为你是一层层叠起来的,第一层是 \([1,nxt_{i-1}+1]=[i-nxt_{i-1},i]\implies [1,nxt_{i-1}]=[i-nxt_{i-1},i-1]\),可以归纳打表证明,这些是不需要改动的,所以我们只需要从 \(g(i)\) 去掉一部分。(其实可以放在 \(nxt\) 树的树链上来看)

\(x=1\) 行不行是可以特判的,我们只考虑剩下的部分。

也就是设 \(T(i)=\lbrace x+1|x\in S(i-1),x+1\notin S(i)\rbrace\)

求出 \(T\) 并减去即可,显然总的 \(T\) 的变化量是 \(O(n)\) 的。

怎么打表发现只会删较小部分啊

根据 \(S(i)=S(nxt_i)\cup\lbrace i\rbrace\),考虑 \(T(i),T(nxt_i)\) 的关系。

啊,我们发现 \(T(nxt_i)\subseteq T(i)\)虽然这近乎显然

  • \(nxt_i\in S(i)\implies nxt_i-1\in S(i-1)\)

则有 \(x\in S(nxt_i-1),x+1\notin S(nxt_i)\implies x\in S(i-1),x+1\notin S(i)\)

然后多出来的部分是什么呢?我们就只需要考虑 \(S(i-1)\)\([nxt_i,i-1]\) 这部分的值了。

而且也恰恰是这一部分值,拿出来计算就好了?你找到第一次跳到 \(nxt_i-1\) 的那个次数 \(c\),将 \([0,c-1]\) 的全部加入 \(T\) 即可。

总变化量 \(O(n)\)

C

感觉和 Two Permutations 是一个题啊。

\(a_{p_i}=i\),也就相当于是 \(h\) 的那个子串离散化后与 \(a\) 相同

考虑指针扫描,加入一个数字相当于:

  1. 查找它的排名,将大于它的元素的排名加一

删除一个也基本一样

利用权值线段树维护位置哈希即可。

D

首先可以拿到特殊情况:无周期的串,显然有 0000…01 这种形式,而全周期的串显然有 111111/000000 这种形式

一个有完整周期的串可以由那个周期,也就是 \(AA\dots AB\) 求解 \(AB\) 还原,可以划分子问题。

接着考虑一个有完整周期的串,也就是 \(2(i-nxt_i)\ge i\implies 2nxt_i\le i\),这个串可以表达为一个不完整循环节,也就是 \(ASA\) 的形式,递归求出 \(A\)(用最大的那个 border 进行递归,这样可以保证有更优的策略可以递归到更小的border从而保证最优性),贪心地给 \(S\) 全放 \(0\)

但是可能会出现问题,也就是形如 000 + 00 + 000 之类的情况,也就是 \(nxt\) 会变小。

不过一个很显然的地方是答案序列第一项肯定是 \(0\),所以我们给 \(S\) 的最后一个位置设置为 \(1\) 即可阻止这类匹配。同时由于 \(S\) 仅有这一个 \(1\),也可以保证不出现新的 border。

E

作为答案的肯定是个 border,而我们所需的是最短的,将其与原串匹配可以覆盖整个原串的border。

考虑 \(dp\),设 \(f_i\)\([1,i]\) 所需最短 \(border\)\(g_i\)\([1,i]\) 可以覆盖到最远位置。

  • \(f_1=g_1=1\)
  • \(i-nxt_i\le g_{f_{nxt_i}}\),则可以扩展到 \([1,i]\),更新 \(f_i=f_{nxt_i},g_{f_{nxt_i}}=i\)
  • 否则只能取自己,\(f_i=g_i=i\)

F

其实就是每个前缀跳 \(nxt_i\) 到底的那个值的和。暴力跳 \(nxt_i\),利用并查集进行路径压缩即可。

G

可以想到一个东西:在字符串 \(S\) 后任意接字符串 \(T\) 可能成为最小后缀的位置至多有 \(O(\log n)\) 个。

有效最小后缀假设存在两个 \([p,n],[q,n]\)\(len(p)\ge 2len(q)\),则显然 \([q,n]\)\([p,n]\) 的 border

那么可以假设 \([p,n]=TTS,[q,n]=TS\),外加一个 \(X\),若 \(TTSX>TSX\implies TSX>SX\) 而这当然是不可能的,因为 \(S\) 优于 \(TS\) 与假设不符

有个想法就是动态 \(i:1\to n\) 维护这些位置集合,每次比较取最优解并删除非法元素

比较这一步如果可以 \(O(1)\) 那也就给出了一个 \(O(n\log n)\) 做法

可以给出Z函数来做,因为有效后缀肯定是互为前缀的 。

对于当前的有效后缀 \([p,i],[q,i]\),假设 \(p<q\),则 \([p,p+i-q]=[q,i]\),后面就转化为了后缀 \([p+i-q+1,i]+[1,i-1]\)\([1,i]\) 的大小关系判断。

利用 Z 函数找到第一个不同位置判断即可。

需要注意的是可能 \(p+i-q+1+z_{p+i-q+1}>i\),这时候相当于跳到了 \(i-(p+i-q+1)+2\) 这个后缀比较了。

判断非法元素是如何做的呢?

很简单啊,所有的串都会新增一个结尾,仅比较这个位置即可,然后还需要用长度来判断一下。

posted @ 2024-10-22 19:19  spdarkle  阅读(6)  评论(0编辑  收藏  举报