CTT2021

D1T1 末日魔法少女计划

知识点:DP 求构造,\(B\) 叉树。

感觉最近见到好多用 DP 来求最优构造的题目。

可以将 \(A_{i,j}=1\) 看作拥有区间信息 \([i,j)\),要求构造最少的区间信息,使得任何区间 \([l,r)\) 都可以被最多 \(k\) 个已知区间的加和表示。

考虑 \(k=2\) 的时候,就是要构建猫树。找到一个中点 \(mid\),所有的点都向这个点连边,然后递归到左右子树去处理。

这启发我们在 \(k>2\) 的时候也去搜索这样的结构,但是二叉的树就不一定优了,所以考虑 \(b\) 叉的数。

具体的,我们选择 \(b\) 个节点为关键节点,将这 \(b\) 个点之间递归距离为 \(k-2\) 的子问题,然后这 \(b\) 个节点分成的每一个区间都向左右端点连满边。每一个部分递归处理。

根据直觉,发现选择 \(b\) 个点,那么中间的 \(b-1\) 块应该是均匀的,同时最左和最右的两个块也应该是均匀的,所以考虑设计如下 DP:

\(f_{n,k}\) 表示 \(n\) 个节点,两两距离 \(\le k\) 至少需要多少个信息。

\(g_{n,k}\) 表示构造 \(b\) 叉树及其内部的 \(b\) 个块至少需要多少个信息。

为了方便处理,记中间变量 \(f'_{n,k}=f_{n,k}+n\) 以及 \(f''_{n,k}=f_{n,k}+2n\)

可以得到如下转移:

\(f_{n,k}=\min\limits_{i=1}^{\left\lfloor\frac{n}{2}\right\rfloor}\{g_{n-2i,k}+2f'_{i,k}\}\)

\(g_{n,k}=\min\limits_{b}\{f_{b,k-2}+(b-1-((n-b)\mod (b-1))(f''_{\left\lfloor\frac{n-b}{b-1}\right\rfloor}{k})+((n-b)\mod (b-1)(f''_{\left\lfloor\frac{n-b}{b-1}\right\rfloor+1}{k})\}\)

需要特殊处理 \(k\le 2\) 或者 \(n=1\) 的一些 corner case,时间复杂度是 \(O(n^2k)\) 的,发现刚好可以满足题目要求的限制。

D1T2 魔塔 OL

知识点:四维偏序,Monster Hunter

先不考虑题目要求的限制,发现问题就是一个 Monster Hunter 问题,做法就是让 \(a_i<b_i\) 的靠前处理,按照 \(a_i\) 从小到大排序;将 \(a_i\ge b_i\) 的靠后处理,按照 \(b_i\) 从大到小排序,可以证明这样构造是最优的。

但是发现这个问题不好使用数据结构维护,所以考虑使用四维偏序的暴力做法:bitset。

我们将所有的怪物先全部存储下来,按照 Monster Hunter 的最优顺序排序,那么任何一个怪物集合的答案序列就是这个序列的子序列。那么答案变成了在这个序列上可以合并的半群信息了。

我们每 \(B=O(\log n)\) 个数分成一块,对于块内,我们预处理出所有 \(2^B\) 中子序列的答案。

那么对于一个询问包含的点集,就可以用四个手写的 bitset 结构且在一起来表示,然后直接取出每一个块内的信息,将它们顺序合并即可。

时间复杂度 \(O(\dfrac{n^2}{\log n})\)

D1T3 基因编辑

知识点:贪心

考虑什么样的 \((i,j)\) 可以做出贡献,首先有 \(i<l\)\(r<j\)。同时要求 \((i,j)\) 是唯一的 \((s_i,s_j)\),那么有:

  1. \(i\) 是第一个颜色为 \(s_i\) 的位置,\(j\) 是最后一个颜色为 \(s_j\) 的位置。
  2. \(j\)\(i\) 的下一个颜色为 \(s_i\) 的位置的左侧。
  3. \(i\)\(j\) 的上一个颜色为 \(s_j\) 的位置的右侧。

发现对于第一个限制,就是确定了哪些点能够做 \(i\),哪些点能够做 \(j\)

对于第三个限制,决定了 \(j\) 只对一段区间内的 \(i\) 有用,所以我们从 \(1\) 扫到 \(l\),那么每一个 \(j\) 都会在某一个时刻开始可以被选;由于 \(j\)\(i\) 的下一个同色位置的左侧,所以只需要检验最小的 \(j\) 是否比它小即可。

时间复杂度 \(O(n\log n)\) 或者 \(O(n)\)

D2T1 简单数据结构

知识点:整体二分,李超线段树,线段树。

一开始做这道题的时候没有看到 \(1\) 操作也是全局操作,想了半天发现不会,鉴定为没有仔细读题。

考虑如果初始有 \(a_i=0\),发现这时 \(1\) 操作和 \(2\) 操作都有很强的单调性。

具体的,如果序列保证单调不降,也就是 \(a_i\le a_{i+1}\),那么显然有 \(a_i+i\le a_{i+1}+i+1\),所以 \(2\) 操作不会改变单调性,同时 \(1\) 操作会修改的就是一段后缀,仍然不影响单调性。

\(1\) 操作进行的修改,这也就意味着,如果 \(a_i\) 在某一时刻它进行了被 \(1\) 修改了,我们就可以认为 \(a_i\) 是一个初始从零开始的数。也就是所有被 \(1\) 操作修改过的 \(a_i\) 是单调不降的

这也就意味着,我们如果知道每一个数被 \(1\) 操作修改的时刻,就可以分别维护没有被 \(1\) 操作修改的部分和已经被 \(1\) 操作修改过的部分。而这两个部分都是可以使用线段树维护做到 \(O(q\log^2n)\) 地。

现在的问题就变成如何求出每一个数被 \(1\) 操作修改的时刻了。

考虑对于一次 \(1\) 操作 \(v\),如果它前面有 \(c\)\(2\) 操作,它要修改 \(a_i\) 至少要有 \(a_i+ci>v\),移项成 \(a_i>v-ci\),那么我们就是要找到第一个 \(v-ci<a_i\) 的位置,而前缀最小值 \(\min(v-ci)\) 是可以进行二分的。

所以我们可以使用整体二分+李超线段树找到每一个 \(a_i\) 被修改的时间,时间复杂度 \(O(n\log n\log q)\)

D2T2 Datalab

知识点:进制运算,交互,ad-hoc

发现我们查询操作大概率只能得到 \(sgn_i\) 的相对关系。

考虑如果询问 \(x=100\dots 00\)\(y=100\dots 00\),我们会得到 \(01111\dots 10\dots 00\),其中最后一个是 \(1\) 的位置和 \(sgn_0\) 同号,其余的 \(1\) 位置和 \(sgn_0\) 异号。

这样操作我们最劣会得到一对 \(sgn\) 的相对关系,那么最劣情况下就需要 \(8190\) 次询问。

考虑我们一次只问一个位置比较劣,考虑同时处理多个位置,但是多个询问只见可能会出现干扰。

考虑分块,我们均匀地询问 \(\sqrt{k}\) 个位置,如果他们没有互相干扰,那么一次就至少会获得 \(\sqrt{k}\) 个有效信息。

如果他们之间互相干扰了,就说明有一个位置至少向前延伸了 \(\sqrt{k}\) 个位置,我们单独 chk 一下这个位置,就能够确定至少 \(\sqrt{k}\) 个信息。

这样操作需要 \(2\sqrt{k}\) 次询问,是标程的方法。

D2T3 随机游走

知识点:期望,贪心,打表找规律

显然,我们想要最大化小 A 走的步数,那么我们连的所有边都会连向 \(1\) 号点。

我们假设第 \(i\) 个位置向 \(1\) 连了 \(a_i\) 条边,设 \(f_i\) 表示小 A 中第 \(i\) 个位置开始走到 \(n\) 的期望步数。

容易得到:\(f_n=0\)\(f_i=\dfrac{a_i}{a_i+1}f_1+\dfrac{1}{a_i+1}f_{i+1}+1\)

最后可以得到 \(f_1=\dfrac{a_1}{a_1+1}f_1+\dfrac{1}{a_1+1}\left(\dfrac{a_2}{a_2+1}f_1+\dfrac{1}{a_2+1}(\dots)+1\right)+1\)

整理一下可以得到 \(f_1=(1-\prod\limits_{i=1}^{n-1}\dfrac{1}{a_i+1})f_1+\sum\limits_{i=1}^{n-1}\prod\limits_{j=1}^{i-1}\dfrac{1}{a_j+1}\)

最后有 \(f_1=\sum\limits_{i=1}^{n-1}\prod\limits_{j=i}^{n-1}(a_j+1)\)

考虑如何求这个东西,我们设 \(dp_{i,j}\) 表示在 \(n=i+1\)\(\sum\limits_{k=1}^i a_k=j\) 的情况下,最大的 \(f_1\) 为多少。

可以得到 DP 转移 \(dp_{i,j}=\max\limits_{a=0}^{j}\{(dp_{i-1,j-a}+1)(a+1)\}\),我们同时记录最优的转移点 \(a\)

通过打表发现,对于 \(i>1,j>1\),有 \(a=\left\lfloor\dfrac{j}{i}\right\rfloor+1\)

既然知道了转移点,我们就可以考虑快速求值了。

发现从 \(dp_{i,j}\)\(dp_{i-1,j-a}\),由于 \(a=\left\lfloor\dfrac{j}{i}\right\rfloor+1\),所以转移之后的 \(a\) 有很大概率是仍然保持不变的。

具体的,我们设 \(q=\dfrac{j}{i}\)\(r=(j\mod i)\),那么如果 \(r\neq i-1\),那么前 \(r+1\) 轮的转移的都有 \(a=q+1\);如果 \(r=i-1\),那么前 \(r\) 轮的转移的都有 \(a=q+1\)

对于第一种情况有转移 \(f_{i,j}=f_{i-r-1,j-(q+1)(r+1)}\times (q+2)^{r+1}+\sum\limits_{i=1}^{r+1}(q+2)^i\),其中快速幂和等比数列求和都是可以做到 \(O(\log n)\) 的。第二种情况的转移类似。

同时,我们可以证明,直接使用递归求 \(f\),最多只会递归 \(3\) 层。证明如下:

  • 如果 \(r=i-1\),那么下一轮有 \(i=1\) 会直接得到结果;
  • 否则会有 \(j-(q+1)(r+1)\mod (i-r-1)=(qi+r-q(r+1)-r-1)\mod (i-r-1)=(q(i-r-1)-1)\mod (i-r-1)=i-r-2\),那么变成了 \(r=i-1\) 的问题。

所以直接递归求解的时间复杂度是单次 \(O(\log n)\) 的,总的时间复杂度为 \(O(T\log n)\)

D3T1 小明的树

知识点:点减边 Trick,线段树

考虑我们要如何检验一个数在某一个状态下是否是美丽的。发现检验被点亮了的点是不好维护的,因为检验子树信息是基于树形态的,也就是点之间的父子关系会跟随树的变化而变化。所以考虑检验没有被点亮了的点。

发现美丽的限制等价于没有被点亮的点形成了一个连通块,而森林的连通块的数量等价于 \(|V|-|E|\)。对于 \(i\) 时刻,有 \(|V|=n-i\)\(|E|\) 等于当前时刻两端都是没点亮的边的数量。记点 \(u\) 被点亮的时刻为 \(t_u\),那么边 \((u,v)\) 作为两端都没有被点亮的边的时间段为 \([1,\min\{t_u,t_v\} )\)

在考虑计算贡献,在满足美丽的情况下,点亮的点的连通块数就等于只有一边点亮的边的数量,同样,一条边 \((u,v)\) 做贡献的时刻就是 \([\min\{t_u,t_v\},\max\{t_u,t_v\})\)

使用线段树维护即可,时间复杂度 \(O((n+m)\log n)\)

D3T2 出题高手

知识点:随机性质,贪心,二维数点

对于这一类题目,经典的想法就是找到所有可能做出贡献的区间,然后二维数点。

考虑什么样的区间是不优的,记 \(sum_i=\sum\limits_{j=1}^ia_j\),发现答案求的式子就是 \(\dfrac{(sum_r-sum_{l-1})^2}{r-l+1}\),记 \(l=l-1\),就是 \(\dfrac{(sum_r-sum_l)^2}{r-l}\)

对于 \(sum_l<sum_r\) 的情况,如果存在 \(l<l_0<r\),使得 \(sum_{l_0}\le sum_l\),那么 \(\dfrac{(sum_r-sum_{l_0})^2}{r-l_0}\ge \dfrac{(sum_r-sum_l)^2}{r-l_0}\ge \dfrac{(sum_r-sum_l)^2}{r-l}\)\(sum_l>sum_r\) 的情况同理。

所以对于一个 \(r\),可以做贡献的 \(l\) 就是 \(sum_i\) 序列的每一个前缀的后缀最大值或者最小值,可以使用单调栈维护。

由于数据随机,所以感觉单调栈内的元素不会很多,实际测出来大概就是 \(O(n\sqrt{n})\) 的量级,但是仍然太多了,没有办法接受再加上二维数点的 \(O(\log n)\)

但是考虑上面的 \(sum_{l_0}\le sum_l\) 我们进行了两次放缩,所以这个限制是很松的,所以我们在实际加入区间的时候,对于 \(\dfrac{(sum_r-sum_l)^2}{r-l}\)\(sum_l>sum_r\le \dfrac{(sum_r-sum_{l_0})^2}{r-l_0}\)\(l\),可以不加入后面的二维数点了。这样时间复杂度是 \(O(S(n)\log n+m\log n)\),其中 \(S(n)\) 为我们加入的区间数量。可以通过 \(n\le 10^5\) 的部分。

考虑还有一档 \(n\le 5\times 10^5\) 的分,我们还是需要优化,已经不能把这个大约 \(O(n\sqrt{n})\) 的区间扫一遍了。

考虑对于 \(sum_l<sum_r\),如果存在 \(l<r_0<r\),使得 \(sum_{r_0}\ge sum_r\),那么 \(l,r\) 一定不是最优的,后面更小的 \(l\) 都不优,所以我们可以直接结束遍历单调栈。发现实现之后可以通过。

D3T3 扑克比大小

知识点:后缀数组,border理论,二维数点

题目就是要求对于 \(s=S[l:r]\) 有多少个本质不同的 \(t=S[l':r']\),使得 \(t^{+\infty}<s^{+\infty}\)

我们认为空串是无穷大,也就是如果 \(S'\)\(S\) 的前缀,\(S'\) 的字典序比 \(S\) 大。

首先我们找到所有 \(t<s^{+\infty}\) 的串,这些串是在 \(t\) 还没有走到第二轮就已经确定了大小。就是要在后缀数组中找到 \(s^{+\infty}\) 的原串中的位置,现在的问题就是如何比较 \(s^{+\infty}\) 和原串的一个后缀 \(S[l_0,n]\) 的 LCP。

先比较 \(S[l_0,n]\)\(S[l,n]\),如果长度小于 \(|s|\) 那么 LCP 就直接确定了,否则比较 \(S[l_0,n]\)\(S[l_0+|S|,n]\),如果结果为 \(t\),那么 LCP 长度就是 \(t+|s|\)

发现确定了 \(t<s^{+\infty}\) 之后,不计算贡献的就只有 \(t\)\(s^{+\infty}\) 的前缀的情况了。

不妨假设 \(t=s^ka\),通过讨论发现 \(s^ka\)\(a\)\(s\) 比较时的大小关系是等价的。

那么只需要找到 \(s^{+\infty}\) 在原串中的最长的前缀,就可以知道每一个 \(a\) 具体会出现多少次。

考虑比较 \(s^\infty\)\(a^\infty\),同样可以证明等价于比较 \(bs^\infty\)\(s^\infty\)

如果 \(b\) 不是 \(s\) 的前缀,那么就是要找 \(b>s\),可以找到 \(s\) 在后缀数组中的位置 \(l\),那么要数的就是开始位置在 \(l\) 之后,\(sa_i\) 在某一个区间内的数的数量。

但是如果 \(b\)\(s\) 的前缀,那么这个统计就是有误的。如果 \(b\)\(s\) 的前缀,那么 \(b\) 就是 \(s\) 的 border。

假设 \(s=bc\),那么就是比较 \(s^{\infty}\)\(cs^{\infty}\)

如果 \(c=a\),那么就不会计入答案。否则,在 \(a>c\) 的时候计入答案。

那么我们就可以减去比较 \(bt\)\(st\) 比较错误的贡献,然后加上 \(b\)\(s\) 比较正确的贡献就可以了。

考虑对于 border \(b\),我们使用基本子串字典求出每一个 border group,每一个 group 中 \(b=A,AB,ABB,ABBB\dots\) ,而他们的字典序是单调的,所以可以二分出一个位置,其中前缀/后缀是计算错误,或者应该是正确的。

具体的,就是 \(bt\)\(st\) 错误比较的贡献就是 \(bt>st\) 的数量,而由于 \(b\)\(\{A,AB,ABB,ABBB\dots \}\),所以不合法的必然是一段前缀或者后缀,可以通过二分得到。

而正确的,我们要求 \(a>c\) 的数量,而每一个 \(b\) 对应的 \(c\) 也应该是单调的,所以仍然是可以二分得到的。

时间复杂度 \(O(n\log n+q\log^2n)\),细节较多。

D4T1 算术

知识点:数学

考虑对于某一个 \(k\),如果它满足条件,就有 \(b^{k+1}\equiv -1\pmod P\)

显然 \(b,P\) 不互质的时候无解。

考虑先找到 \(b^{k'}\equiv 1\pmod P\) 的最小的 \(k'\)。由于 \(b^{\varphi(P)}\equiv 1\pmod P\),所以有 \(k'|\varphi(P)\)

所以我们可以枚举 \(\varphi(P)\) 的因子 \(g\),看除掉 \(g\) 之后是否仍然满足 \(b^{k'}\equiv 1\pmod P\)

找到 \(k'\) 之后,我们检验是否有 \(2|k'\)\(b^{\frac{k'}{2}}\equiv -1\pmod P\),如果有,那么就有 \(k=\dfrac{k'}{2}-1\)

当然可能要判断一些 \(P=2\) 或者 \(k'=2\) 的 corner case。

时间复杂度 \(O(\sqrt{P}+T\log^2P)\)

D4T2 经典游戏

知识点:博弈论,长剖,树状数组,Trie 树

这是一个博弈论问题,考虑算出一个节点的 SG 函数,容易得到 \(u\) 点处棋子的 SG 函数就是 \(u\) 子树的深度,那么我们就可以通过 dfs 和换根来求出初始状态下每一个点的 SG 值 \(S_i\)

考虑什么情况下先手必赢,设 \(u\) 的深度为 \(dep_u\)(此处 \(dep\)\(0\) 开始),那么放棋子可以选择任意的 \([0,dep_u]\),所以只有 \(S_u>dep_u\) 的时候才是必赢的。

考虑放入一个棋子,对于对他贡献 \(dep\) 的子树的节点会异或上次深值,对于其他节点会异或上 \(dep\),可以直接用树状数组维护。

但是我们需要查询一个半径为 \(1\) 的领域的 \(S_u\) 是否大于 \(dep_u\),考虑我们要检验 \(S_u\oplus x>dep_u\) 的数量,可以直接使用 Trie 树。只要所有的节点都能够异或上同一个值,将其记录下来即可。发现如果进行长链剖分,然后维护所有短儿子的信息。这样可能异或上不同的情况就只有 \(u\) 的最深点是从父亲贡献的这一种情况了,单独修改即可。

时间复杂度 \(O((n+q)\log n)\)

D4T3 随机数据

知识点:博弈论,万能欧几里得,线段树

首先考虑 \(n,q\le 10^5\) 怎么做。

发现原题就是在 \(g=\gcd(n,d)\) 个环上面进行取数,过程是 A 取一个然后 B 取于 A 相邻的一个。可以证明 B 的最优策略中不会出现能取不取的情况。如果我们让环上的边 \((a,b)\) 的权值设为 \(\min\{a,b\}\),那么发现原问题变成了求环上的最大权匹配

而环的最大权匹配可以先断环为链,变成序列上的最大权匹配,而序列上的最大权匹配是可以用可合并信息去维护答案的:\(be\)\(en\) 表示序列的第一个元素和最后一个元素,\(num_{0/1,0/1}\) 为序列的第一个元素是否被匹配,最后一个元素是否被匹配的情况下的最大权匹配。

直接使用线段树维护就可以做到 \(O(n+q\log n)\) 了。

现在考虑如何解决 \(n\) 更大的问题。如果没有修改,怎么求出一个序列的权值。

对于第 \(r=0,1,\dots g-1\) 个环,上面的第 \(i\) 个物品(\(i=0,1,\dots \dfrac{n}{g}-1\))编号是 \((di+r)\bmod n\),那么对应到 \(w\) 序列中就是 \((di+r)\bmod n\bmod m\),两层取模不好处理,所以考虑去掉内层的取模,则有编号为 \((di+r-n\left\lfloor\dfrac{di+r}{n}\right\rfloor)\bmod m\),发现这个结构就是万能欧几里得可以维护的,使用万能欧几里得维护信息合并即可。

我们可以拉出被修改了的 \(q\) 个节点,那么对于其他的 \(O(q)\) 个区间,我们想要快速得到它的信息。由于上面万能欧几里得都是二元合并,将这个合并的结构拉出来就是一棵深度为 \(O(\log n)\) 的二叉树,那么我们就可以在其上做类似线段树的区间查询,就可以得到区间的信息了。

最后再用线段树维护就可以了。

时间复杂度 \(O((m+q)\log n)\)

posted @ 2024-08-26 22:03  Xun_Xiaoyao  阅读(4)  评论(0编辑  收藏  举报
/* 鼠标点击求赞文字特效 */