四月 Atcoder 做题记录
Arc_170_a
简要题意:
给定由 A 和 B 构成的长度为 \(N\) 的字符串 \(S\) 和 \(T\)。每一次操作,你可以选择满足 \(1 \leq i < j \leq N\) 的整数 \(i,j\)。然后将 \(S_i\) 替换为 A,将 \(S_j\) 替换为 B。请判断是否可以使 \(S\) 与 \(T\) 相同,如果可能,请输出所需的最小操作次数。\(n \leq 2\times 10^5\)。
题解
细节好题。
贪心从前往后配一定不劣。因此我们可以双指针维护当前需要 A\(\rightarrow\)B 的指针 \(atob\) 和 B\(\rightarrow\)A 的指针 \(btoa\)。然后从前往后模拟。如果 \(btoa \leq atob\) 直接匹配即可。如果 \(atob < btoa\),说明最近的一个 \(btoa\) 都不能与它匹配,需要看 \(atob\) 之前是否有字母 A 才能进行替换。
当然一定会有 \(atob\) 和 \(btoa\) 没有走到头的情况。对于 \(atob\) 也是要判断 \(atob\) 之前是否有字母 A;对于 \(btoa\) 需要判断 \(btoa\) 之后是否有字母 B。
Arc_170_b
简要题意
给定一个长度为 \(N\) 的数列 \(A_1,A_2,\cdots,A_N\),求满足条件“存在正整数 \(i,j,k\) 满足 \(1 \leq l \leq i<j<k \leq r\) 且 \(A_j−A_i=A_k−A_j\)” 的数对 \((l,r)\) 的个数。\(n \leq 10^5,1\leq A_i \leq 10\)。
题解
先开一个数组存每一个 \([1,10]\) 数值的下标,然后预处理出每一个数值 \(i \in [1,10]\) 所对应的数组的 lower_bound。
首先枚举左端点,然后枚举自左端点以后第一个出现的数值,其次枚举等差数列的差,在 lower_bound 数组中迭代 \(3\) 次就是这一次枚举到的最小的右端点。对于每一个左端点,维护右端点的最小值 \(r_{min}\),答案需要增加 \(n-r_{min}+1\)。
Arc_170_c
简要题意
给定 \(N,M\) 和序列 \(S_i \in [0,1]\) 计算满足以下条件的长度为 \(N\) 的数列 \(A_{1 \sim N}\) 的数量对 \(998244353\) 取模的结果:
-
\(0 \leq A_i \leq M\)。
-
对于所有 \(1 \leq i \leq N\),如果 \(S_i=1\),则 \(A_i=\text{mex}(A_1,A_2,…,A_{i−1})\);如果 \(S_i=0\),则 \(A_i\ne \text{mex}(A_1,A_2,…,A_{i−1})\)。
\(n \leq 5000\),\(m\) 的范围不重要。
题解
我们对于 \(M\) 进行分类讨论。
-
如果 \(M \ge N\) 说明对于每一个 \(A_i=0\) 的数都有 \(m\) 种填数方案,又因为 \(\text{mex}\) 不能超过 \(n\),所以可以直接乘。
-
如果 \(M<N\),我们考虑转化题意。\(\text{mex}\) 这个东西实际上不好处理,但是我们实际上不需要知道 \(\text{mex}\) 具体的值是多少。
我们把题意转化成在 \(0,1,2,\cdots,m\) 这 \(m+1\) 的格子中填数。
设 \(dp_{i,j}\) 表示前 \(i\) 个数,\(j\) 个格子有数的方案数。
那么如果 \(A_i=1\),那么 \(dp_{i,j}=dp_{i-1,j-1}\),因为这个数只能在未有数的格子中选择。
如果 \(A_i=0\),那么 \(dp_{i,j}=j \times dp_{i-1,j}+(m-j+1)\times dp_{i-1,j-1}\)。如果填之前填过的数,那么有 \(j\) 种;如果填之前没有填过的数,那么有 \(m+1-(j-1)=m-j+2\) 个格子空闲,因为 \(\text{mex}\) 不可填,所以有 \(m-j+1\) 个填数方案。
Arc_170_d
简要题意
Alice 和 Bob 又双叒叕在玩一个游戏。
最初,Alice 和 Bob 各有 \(N\) 张写着整数的卡片,分别为 \(A_i\),\(B_i\)。然后,Alice,Bob,Alice 轮流把自己的一个卡片粘在黑板上。最后,如果可以用黑板上的三个整数的边长能组成一个三角形,则 Alice 获胜;否则,Bob 获胜。你需要确定当双方都采取最优行动时谁赢。
共有 T 组测试数据。\(\sum N \leq 2 \times 10^5\)。
题解
假设 Alice 第一次选了 \(a\),第三次选了 \(c\),Bob 第二次选了 \(b\),那么 Bob 选的 \(b\),只能使在除掉 \(a\) 的 \(A_i\) 与 \([|a-b|+1,a+b-1]\) 不存在交集。
对于 \(a\) 的取值,我们可以首先对 \(b\) 进行分类讨论:
如果 \(a>=b\) 那么原区间就是 \([a-b+1,a+b-1]\),那么对于 \(b\) 来讲,肯定要使区间长度越小越好。因此我们可以首先对 \(B\) 进行排序,然后枚举所有的 \(a\)。如果对于一个 \(a\),在区间 \([|a-B_1|+1,a+B_1-1]\) 中有数,那么这个 \(a\) 就符合条件,因为剩下的 \(a\),只要选择了,Bob 一定赢。
如果 \(a<b\) 那么原区间就是 \([b-a+1,b+a-1]\),那么对于 \(a\) 来讲,肯定要使区间长度越大越好。因此我们可以对符合以上条件的 \(a\) 进行排序,枚举 \(b\),并判断符合条件的最大的 \(a\) 对于所有的 \(b\) 都是否符合条件。只要存在一个 \(b\) 不符合条件,那么 Bob 一定赢。
是否存在一种情况,选取最大的 \(a\) 实际不优?也就是说 \(b-a_n\) 覆盖不到 \(a_i\),但 \(b-a_i\) 能覆盖到 \(a_n\)。
实际上不存在。假设存在,设选取 \(a_i\) 更优,且 \(a_i<a_n\),\(b-a_i<a_n\),\(b-a_n \ge a_i\)。后两个不等式很容易看出来矛盾性。
Arc_170_e
简要题意
生成一个长为 \(N\) 的序列 \(D\),初始值全为 \(-1\)。同时有一双端队列 \(Q\),其中有一个二元组 \((1,0)\)。反复执行以下操作,直到 \(Q\) 为空:
- 设 \((v,d)\) 是 \(Q\) 中开头的二元组,并且将其从 \(Q\) 开头删除。
- 如果 \(D_v=−1\),\(D_v \leftarrow d\)。
- 然后,在 2. 的条件下,令 \(x\) 与 \(v\) 相邻,特殊地,\(n\) 与 \(1\) 相邻。对于所有的 \(x\),如果 \(D_x=-1\),那么有 \(\frac{P}{100}\) 的概率将 \((x,d+1)\) 加入队头,否则加入队尾。
你需要找到操作完成后,\(D\) 中所有元素之和的期望。答案对 \(998244353\) 取模。有 \(T\) 组测试。\(N \leq 10^{18},T \leq 10^4\)。
题解
队列是用来唬人的。实际上,队列中只能有 \(2\) 个元素。一个元素的坐标是从前往后的,一个元素的坐标是从后往前的。对于每一次的概率操作 \(P\),实际上就是交换队头队尾。
我们考虑线性期望 \(dp\)。
- 设 \(f_{i,0}\) 表示有 \(i\) 个数,与初始方向相同的期望长度;
- 设 \(f_{i,1}\) 表示有 \(i\) 个数,与初始方向相反的期望长度;
- 设 \(f_{i,2}\) 表示有 \(i\) 个数,这些数的期望值之和。
令 \(p=\frac{P}{100}\),有转移
- \(f_{i,0}=p \times (f_{i-1,0}+1)+(1-p) \times (f_{i-1,1}+1)\)
- \(f_{i,1}=f_{i-1,0}+f_{i-1,1}+1-f_{i,0}\)
- \(f_{i,2}=f_{i-1,2}+p \times f_{i-1,0}+(1-p) \times f_{i-1,1}+1\)
整理可得
- \(f_{i,0}=p \times f_{i-1,0}+(1-p) \times f_{i-1,1}+1\)
- \(f_{i,1}=(1-p) \times f_{i-1,0}+p \times f_{i-1,1}\)
- \(f_{i,2}=f_{i-1,2}+p \times f_{i-1,0}+(1-p) \times f_{i-1,1}+1\)
构造矩阵满足
使用矩阵快速幂即可。
Arc_170_f
简要题意
给定一个 \(n\) 个点的树。对于一个长度为 \(n\) 的排列 \(P\) 满足:对于树上每个点 \(i\),其点权为 \(P_i\)。
\(A(P)\) 是一个初始为空的序列,给定 \(P\) 后,对于 \(i=1,2,⋯,n\),依次进行操作:
- 如果 \(i\) 没有和其它的点连边,将 \(0\) 加入 \(A(P)\) 末尾,否则,选择和 \(i\) 相邻且点权最小的点 \(j\),将 \(P_j\) 加入 \(A(P)\) 末尾,并删除边 \((i,j)\)。
对于所有排列 \(P\),找到字典序最小的 \(A(P)\)。\(n \leq 2 \times 10^5\)。
题解
定义
- 如果边 \((i,j)\) 在第 \(i\) 次操作被删除,那么我们称点 \(i\) 被确定,同时称点 \(j\) 为点 \(i\) 的 目标点;反之,如果边没有删除,那么我们称点 \(i\) 未被确定。
- 在第 \(i\) 次操作中,如果点 \(i\) 未被确定,在下述的算法中,我们会把一些数 \(x\) 写在与 \(i\) 相邻的点 \(v\) 上,我们称数 \(x\) 放置在了点 \(v\) 上;同时,我们称 \(i\) 为点 \(v\) 与数 \(x\) 的临时源点。
算法
因为我们最后是使字典序最小,所以对于每一个从 \(1 \sim n\) 从前往后遍历的 \(i\),我们可以使用贪心算法尽可能最小化 \(A_i\),不需要考虑进行操作后对 \((i+1) \sim n\) 的影响。
现在我们考虑怎么最小化 \(A_i\)。
1. 判断 \(A_i=0\) 是否可行
这与点 \(i\) 的度数有关。
- 如果点 \(i\) 的度数为 \(0\),也就是点 \(i\) 被孤立,我们可以直接令 \(A_i=0\)。
- 如果点 \(i\) 的度数为 \(1\),设与 \(i\) 相邻的点为 \(j\),\(A_i=0\) 可行当且仅当 \(i > j\),且 \(j\) 未被确定。此时,我们可以令 \(j\) 的目标点为 \(i\),使 \(i\) 确定,当执行完这一步后 \(i\) 就孤立了,可以为 \(0\)。
简要证明:如果 \(i<j\),那么边 \((i,j)\) 会一直存在直到遍历到 \(i\)。如果 \(j\) 被确定,那么点 \(j\) 无法更改目标点为 \(i\),这样可能会改变之前算好的 \(A_i\)。
- 如果点 \(i\) 的度数大于等于 \(2\),可以证明 \(A_i=0\) 不可行。
简要证明:假设存在两个未处理的相邻点 \(u\) 和 \(v\),此时无论如何操作,\(i\) 必须选择一个邻居,导致至少一条边未被删除,无法使 \(i\) 孤立,不能为 \(0\)。
2. 点 \(i\) 不存在相邻节点被放置数
因为 \(1 \sim i-1\) 都放置在了与 \(i\) 不相邻的点上,所以此时 \(A_i=\max_{j=1}^{i-1}A_j+1\)。在代码中,我们可以记录一个数 \(cnt\) 表示此时的 \(\max_{j=1}^{i-1}A_j\)。
然后,我们把点 \(i\) 的所有相邻节点 \(v\) 都放置上 \(A_i\)。(此时任意的一个 \(v\),\(i\) 都是它们的临时源点)
如果点 \(i\) 的度数为 \(1\),设点 \(v\) 与 \(i\) 相邻,那么我们可以直接确定点 \(v\) 为点 \(i\) 的目标点,使点 \(i\) 确定。
3. 点 \(i\) 存在相邻节点被放置数
此时,我们找到与 \(i\) 相邻的最小的放置数 \(x\),并找到对应节点 \(t\)。
此时 \(A_i\) 的最小值就是 \(x\)。所以我们考虑将点 \(t\) 作为点 \(i\) 的目标点,使点 \(i\) 确定。
但是这样显然不够,我们还需要考虑点 \(t\) 的临时源点 \(s\),是点 \(s\) 将 \(x\) 放置在了 \(t\) 上,所以我们还需要把点 \(t\) 作为点 \(s\) 的目标点,使点 \(s\) 确定。
细节
你以为黑题就这样结束了?
1. 连锁确定反应
当点 \(s\) 确定时,设其目标点为 \(t\),边 \((s,t)\) 会被删除。这会使点 \(t\) 的度数减少。如果点 \(t\) 的度数变成了 \(1\),且满足 \(t < s\),设其相邻点为 \(v\),如果 \(v\) 也没有被确定,我们此时必须使点 \(t\) 的目标点为 \(v\),使 \(t\) 确定。此时又会使点 \(v\) 的度数减少……
所以每次确定后需要考虑以上的连锁确定。
2. 在『算法』的 3. 中一些节点不能选择
- 一个点 \(i\) 可能给很多点都放置 \(x\),但是最终只会选择一个点作为目标点。所以在判断的时候,如果数 \(x\) 的『临时源点』被确定了,那么这个 \(x\) 所代表的点就不能被选择了。
- 设当前遍历到的点为 \(i\),选择的点为 \(j\),如果点 \(j\) 没有被确定,度数为 \(2\) 且 \(i>j\),那么点 \(j\) 也不能选择。
简要证明:设点 \(j\) 的临时源点为 \(k\),看起来使点 \(j\) 作为点 \(i\) 和点 \(k\) 的目标点是没有问题的。但是如果删除了边 \((j,k)\) 后,点 \(j\) 的度数就变成了 \(1\),此时点 \(j\) 必须选择点 \(i\) 作为目标点。所以出现了矛盾。
总结
按照 \(1,2,\cdots,n\) 的顺序使 \(A_i\) 取得最小,并且注意以上的细节,我们就可以得到字典序最小的 \(A_i\)。添加、删除、查询最小值的操作可以用 set 来实现。时间复杂度 \(O(n \log n)\)。
提交记录。
在代码中使用了 \(tgt\) 数组记录目标顶点。注意如果一个点 \(i\) 的目标顶点 \(j\) 已确定后,边 \((i,j)\) 是删除状态,所以代码中有很多关于 \(tgt\) 的判断,实际上就是判断这个点是否确定,或者边 \((i,j)\) 是否删除。

浙公网安备 33010602011771号