CF 合集 1751-1775
1753. Codeforces Round #829 (Div. 1)
Performance 2343.
A2. Make Nonzero Sum (hard version)
如果序列和为奇数,即不为 \(0\) 的数的个数为奇数,显然无解。
考虑两个不为 \(0\) 的数 \(a_x, a_y\),满足 \(a_{x + 1} \sim a_{y - 1}\) 都是 \(0\)。
- 
如果 \(a_x + a_y = 0\),可以分成 \([x, y - 1]\) 和 \([y, y]\)。
 - 
否则 \(a_x = a_y\)。若 \(x + 1 = y\) 则分成 \([x, y]\),否则分成 \([x, y - 2]\) 和 \([y - 1, y]\)。
 
我们将 \([x, y]\) 分成了若干段,它们的权值之和为 \(0\)。将第 \(2k + 1\) 个不为 \(0\) 的数和第 \(2k + 2\) 个不为 \(0\) 的数像这样配对,剩下来没有被覆盖的所有数均为 \(0\),容易得到一组分段方案。
时间复杂度 \(\mathcal{O}(n)\)。代码。
B. Factorial Divisibility
设 \(cnt_i\) 表示 \(a_j = i\) 的 \(j\) 的数量,从 \(1\) 到 \(x - 1\) 枚举 \(i\),若 \(i + 1\nmid cnt_i\) 则无法整除,否则进位,令 \(cnt_{i + 1}\gets \dfrac {cnt_i} {i + 1}\)。
时间复杂度 \(\mathcal{O}(n + x)\),代码。
*C. Wish I Knew How to Sort
Wish I knew how I can come up with the solution.
这题把我送走了。
注意到最终态形如前面 \(cnt_0\) 个位置(称为前缀)上是 \(0\),后面 \(cnt_1\) 个位置(称为后缀)上是 \(1\)。
改变前缀上 \(0\) 的个数的交换,必然形如选择前缀上的 \(1\) 和后缀上的 \(0\) 交换。设当前前缀上 \(1\) 的个数为 \(x\),则后缀上 \(0\) 的个数必然为 \(x\),共有 \(x ^ 2\) 对选择后可以将 \(x\) 减去 \(1\) 的 \((i, j)\)。因此,每步操作令 \(x\) 减 \(1\) 的概率为 \(\dfrac {x ^ 2} {\binom n 2}\)。
综上,设初始前缀上 \(1\) 的个数为 \(x\),则答案为 \(\dbinom n 2 \sum\limits_{i = 1} ^ x \dfrac 1 {x ^ 2}\)。时间复杂度 \(\mathcal{O}(n\log n)\) 或 \(\mathcal{O}(n)\)。代码。
*D. The Beach
相似题目。
注意到一个位置可以空出来当且仅当对应的若干位置之一可以空出来,这种 具有依赖关系 的题目一看就是图论。
如果 \(s_{i, j} = \texttt L\),那么从 \((i - 1, j + 1)\) 和 \((i + 1, j + 1)\) 向 \((i, j)\) 连边,权值为 \(p\),表示如果 \((i, j)\) 要空出来,那么这两个位置需要有一个空出来,且花费 \(p\) 的代价旋转这张床。同理,\((i, j + 2)\) 向 \((i, j)\) 连边,权值为 \(q\)。
对于 \(s_{i, j}\) 为其它方向字符的情况同理。
我们发现连边只在 \(i + j\) 奇偶性相同的位置之间进行,所以两张图互不影响。如果一张床的两个位置都要求被移动,我们可以先将对应目标位置变成空地,那么这张床周围与它四连通的位置有两个都是空地。此时可以只进行一次移动,然后就有 \(1\times 2\) 的空地给我们摆放床了。
从 \(s_{i, j} = \texttt .\) 的位置开始跑最短路,因为每条路径代表一个移动床的路径,所以 \(f_{i, j}\) 表示为使得 \((i, j)\) 空出来的最小代价。我们发现连边枚举所有相邻位置 \((i, j), (i', j')(|i - i'| + |j - j'| = 1)\),则 \(\min f_{i, j} + f_{i', j'}\) 即为所求。
时间复杂度 \(\mathcal{O}(nm\log (nm))\)。代码。
E. N Machines
根据乘法对加法的分配律,我们最终值的贡献拆成所有加法的贡献之和。每个加法的贡献形如 \(a_i\) 乘以在它后面的所有乘法的积,即 \(a_i \prod\limits_{i < j \land s_j = \texttt *} a_j\)。这个拆贡献的思想非常重要,是本题的核心。
因为加法总和与乘法之积的和不超过 \(2\times 10 ^ 9\),所以答案不超过 \(x (2\times 10 ^ 9 - x)\) 的最大值,即 \(10 ^ {18}\)。
进一步地,为了让每个加法的贡献最大,如果选择移动加法运算,一定会把它放在最前面;如果移动乘法运算,一定会把它放在最后面。
将所有乘 \(1\) 删去,这样乘法数量不超过 \(\log_2 V \approx 31\)。直接枚举选中哪些乘法无法接受,但是如果两个乘法数值相等,我们一定会优先将位置较前的乘法移动到最后面,调整法容易证明。根据上述结论,可能更新答案的情况数为 \(\prod (cnt_i + 1)\)。因此,假设有 \(31\) 个乘 \(2\),那么可能更新答案的情况数不是 \(2 ^ {31}\),而是 \(32\)。
感性理解这个值的最大值在所有情况下的最大值是很小的,即在 \(\prod x_i ^ {c_i} \leq 2 \times 10 ^ 9\) 的限制下 \(\prod (c_i + 1)\) 的最大值不会很大,比约数个数数量级多一点。设最大值为 \(F\),爆搜可知 \(F = 4608\)。
在已经确定选择哪些乘法移动的前提下,我们会尽可能多地移动加法,这样一定不劣。设还可以进行 \(rem\) 次加法。去掉选择的所有乘法,设它们的乘积为 \(move\)。
首先求出不移动任何加法的当前值 \(sum\)。
考虑每个加法移动到最前面的贡献,形如 \(a_i \times (pre_i - 1) \times suf_i\),其中 \(pre_i\) 表示 \(i\) 前面没有被选择的乘法之积,\(suf_i\) 表示 \(i\) 后面没有被选择的乘法之积。我们只需求出贡献前 \(rem\) 大的权值之和。二分找到最小的 \(k\) 使得贡献 \(\geq k\) 的加法数量 \(plus \leq rem\),同时求出对应贡献之和 \(cont\),则可以用 \((sum + cont + (rem - plus) (k - 1)) \times prod\)。当 \(k\) 不存在(即 \(rem\) 过大)时,可以令 \(k = 1\),刚好消去 \(rem - plus\) 的不正确的贡献。
对于原序列,如果两个加法 \(a_i\) 和 \(a_j\) 之间没有乘法,那么任意情况下 \((pre_i - 1) \times suf_i = (pre_j - 1) \times suf_j\)。所有乘法将序列分成不超过 \(\log V\) 段加法,每段对于当前二分值 \(k\) 都会选择最大的若干个数。将每段按 \(a\) 从大到小排序后做前缀和,容易二分得到使得乘上当前 \((pre - 1) suf\) 后不小于 \(k\) 的加法数量,以及这样的数的贡献之和。
时间复杂度 \(\mathcal{O}(F\log ^ 2 V\log n + n\log n)\)。代码。
1758. Codeforces Round #836 (Div. 2)
A. SSeeeeiinngg DDoouubbllee
显然,输出 \(ss ^ R\) 即可。
B. XOR = Average
当 \(n\) 是奇数时,构造 \(n\) 个 \(1\)。当 \(n\) 是偶数时,构造 \(n - 2\) 个 \(2\) 和一对 \(1, 3\)。
*C. Almost All Multiples
挺奇妙的。
设 \(x\) 的倍数有 \(c\) 个,\(p_1\) 占了一个,如果不是 \(n\) 空出来,就无解了。因为只有 \(c - 1\) 个 \(x\) 的倍数,却要填入 \(c\) 个位置。因此,当 \(x\nmid n\) 时,无解。
从 \(i\to p_i\) 连边。不是 \(x\) 倍数的位置上,除了 \(p_1\) 以外,其它位置都要满足 \(p_i = i\),因为除了自环,一个环上必然有至少一个 \(i\) 满足 \(i\nmid p_i\)。因为 \(p_1 = x\),\(p_n = 1\),所以唯一非自环形如 \(n\to 1\to x\to \cdots \to n\),而除了 \(n\) 以外,每个在环上的位置 \(i\) 需要满足 \(p_i\) 是 \(i\) 的倍数,因此相当于找到字典序最小的链 \(x\to a_1\to \cdots \to n\),使得后一个数是前一个数的约数。贪心枚举倍数即可。
时间复杂度 \(\mathcal{O}(n)\)。代码。
D. Range = √Sum
\(n\) 是偶数时,构造 \(\forall i\in [1, \frac n 2], n\pm i\)。极差为 \(n\) 且和为 \((n - i + n + i) \times \frac n 2 = n ^ 2\)。
将偶数的思路沿用至奇数,注意到如果要配对则极差一定是偶数,因此 \(n\) 是奇数时,构造 \(\forall i\in [0, \frac n 2), 3n+ i, 5n - i\) 和 \(4n\)。极差为 \(2n\) 且和为 \(4n ^ 2\)。代码。
E. Tick, Tock
对相同列或相同行的操作可以合并。设给第 \(i\) 行加上 \(r_i\),第 \(j\) 列加上 \(c_j\),则 \(a_{i, j} + r_i + c_j = 0\)。这给出 \(r_i\) 和 \(c_j\) 之间的关系式。
将关系式建出二分图来,\((i, j)\) 权值为 \(r_i + c_j\) 被要求等于的值。因为关系式只描述了 相对大小,对绝对大小没有限制,所以对于每个连通块,我们钦定其中一个点等于 \(0\),通过任意生成树推出其它所有点的权值,再检查每条边是否被满足。如果所有连通块均合法,则每个连通块的第一个点可以有 \(h\) 种取值,其它点随着第一个点的权值的确定而确定,答案即 \(h\) 的连通块数次方。
时间复杂度 \(\mathcal{O}(nm)\)。代码。
*F. Decent Division
一个自然的想法是,从左往右检查每个 \(1\),设它的位置为 \(i\),如果它没有被覆盖,那么找到下一个符合条件的位置 \(j\),也就是将 \(1\) 视为 \(1\),\(0\) 视为 \(-1\),做前缀和之后第一个满足 \(s_j = s_{i - 1}\) 的位置,可以线段树二分求出。设 \(j = f(i)\)。
考虑将位置 \(i\) 从 \(0\) 变成 \(1\)。如果它被 \([l, r]\) 覆盖,那么令 \(p = l\),否则令 \(p = i\)。然后加入区间 \([p, f(p)]\)。我们把所有涉及到的区间删除。可以证明,删除这些区间并加入 \([p, f(p)]\) 之后,不会出现没有被覆盖的 \(1\)。根据 \(f\) 的定义,结合前缀和序列连续,即 \(s_i = s_{i - 1}\pm 1\),不存在 \(p < q < f(q) < f(p)\)。因此,区间不会只相交不包含。
考虑将位置 \(i\) 从 \(1\) 变成 \(0\)。设它被 \([l, r]\) 覆盖,则将 \([l, r]\) 删去。然后从 \(l\) 开始找到第一个仍为 \(1\) 的位置 \(p\),加入 \([p, f(p)]\),然后令 \(l \gets f(p) + 1\) 不断进行下去,直到 \(p > r\)。也许读者会认为不断操作某个位置可以卡掉这种做法,就比如说先操作 \(2, 4, 6, \cdots\),然后不断操作 \(3\),确实是可以卡掉的,但是这份代码可以 通过。
实际上存在很简单的修补方法。只需将 \(f(i)\) 的定义改为最后一个满足 \(s_j = s_{i - 1}\) 且 \(s_i\sim s_j\) 均不小于 \(s_j\) 的位置 \(j\),即第一个满足 \(s_{j'} = s_{i - 1} - 1\) 的位置 \(j'\) 减去 \(1\)。这样,每个区间的下一个位置都留有一个作为缓冲的 \(0\),这使得将位置从 \(1\) 变成 \(0\) 时,至多拆出三个区间。因为每拆出一个区间,都意味着原区间的总和要减小 \(1\),最后一个顶到 \(r\) 的区间除外。因为单次操作最多新增两个区间,所以操作数上界为 \(4n\)。举个例子,\(110100100\),不断操作 \(2\) 即可卡满上界。
时间复杂度 \(\mathcal{O}(n\log n)\)。代码。
1761. Pinely Round 1 (Div. 1 + Div. 2)
A. Two Permutations
若 \(a + b + 2\leq n\) 显然可行,否则 \(p = q\),故 \(a = b = n\) 可行。其他情况不可行。
B. Elimination of a Ring
首先当序列只有两个不同元素时,\(a_1\) 和 \(a_2\) 交替出现,每次删去一个数都会使得其相邻两个数合并成一个数,除了最后一次操作。因此答案为 \(\frac n 2 + 1\)。
当序列有三个或以上不同元素时,因相邻元素不同,必然存在相邻三个不同的数且至少有一个数出现次数大于 \(1\),除了 \(n = 3\) 的平凡态。若中间的数出现不只一次,可直接删去,否则删去其左边或右边的出现次数大于 \(1\) 的数必然不会引起合并。因此答案为 \(n\)。
时间复杂度 \(\mathcal{O}(n)\)。代码。
C. Set Construction
这题就很蠢了。
因保证无解,将真子集关系写成有向无环图,令每个集合包含所有能到达它的集合的编号即可。
时间复杂度 \(\mathcal{O}(n ^ 2)\)。代码。
*D. Carry Bit
考虑钦定一些位置进位,设 \(f(x)\) 表示第 \(x\) 位是否被钦定进位。除去进位的影响,每一位的决策显然是独立的。
- 若 \(f(x) = 1\) 且 \(f(x - 1) = 1\),则 \(a_x\) 和 \(b_x\) 不能同时为 \(0\),有 \(3\) 种方案。
 - 若 \(f(x) = 1\) 且 \(f(x - 1) = 0\),则 \(a_x\) 和 \(b_x\) 必须同时为 \(1\),有 \(1\) 种方案。
 - 若 \(f(x) = 0\) 且 \(f(x - 1) = 1\),则 \(a_x\) 和 \(b_x\) 必须同时为 \(0\),有 \(1\) 种方案。
 - 若 \(f(x) = 0\) 且 \(f(x - 1) = 0\),则 \(a_x\) 和 \(b_x\) 不能同时为 \(1\),有 \(3\) 种方案。
 
我们发现对于一个极长进位段 连带着它前面一位,对方案数的贡献为 \(3 ^ {\mathrm{length} - 2}\)。也就是说,本来方案数为 \(3 ^ n\),但每个极长进位段会让方案数的指数减小 \(2\),除了顶到最高位的进位段只会让方案数的指数减小 \(1\)。
考虑枚举进位段数 \(i\in [1, k]\) 且最高位是否进位。首先有将 \(k\) 个进位位分成 \(i\) 段的方案数 \(\dbinom {k - 1} {i - 1}\)。
- 若进位,则剩余 \(r = n - k + i + 1\) 个自由位,需要插到 \(i\) 个空隙当中(最高位之前不能插),方案数为 \(3 ^ {n - 2i + 1} \dbinom {r + i - 1} {i - 1}\)。
 - 若不进位,则剩余 \(r = n - k + i\) 个自由位,需要插到 \(i + 1\) 个空隙当中,方案数为 \(3 ^ {n - 2i} \dbinom {r + i} i\)。
 
时间复杂度 \(\mathcal{O}(n)\),注意特判 \(k = 0\) 的情况。代码。
*E. Make It Connected
考虑到如果一个连通块不是完全图,那么找到不同时与该连通块内所有点有边的某点 \(x\),对 \(x\) 执行操作,就可以让整张图连通。
因此,若整张图连通,答案为 \(0\)。
否则,考虑到对孤立点操作可以使它同时与所有点连通,所以若存在孤立点,则答案为 \(1\)。
否则,若存在至少一个不为完全图的连通分量,则答案为 \(1\)。
否则,考虑到对任意一个点 \(x\) 执行操作会断开它和它所在连通块内所有点的边,并和其它所有点连边,所以
- 当连通块数为 \(2\) 时,这会让被操作点所在完全图大小减去 \(1\),另一个完全图大小增加 \(1\),此时答案即较小连通块大小。
 - 当连通块数大于 \(2\) 时,执行操作后满足至少存在一个不为完全图的连通分量,只需再执行一次操作,所以答案为 \(2\)。
 
很好,简单题,写一发交上去,结果 WA on test 4? 怎么回事呢?肯定是算法假了而不是写挂了(确信。
想想看,对 \(x\) 执行操作为什么能使整张图连通?它断开了和它相连的所有边,把其它连通块连起来,并且和原连通块有至少一条边相连。这些都建立在一个前提下,就是执行操作后 \(x\) 所在连通块仍连通。不连通那不就寄了嘛!
所以,我们对 \(x\) 还有一个要求,就是它不是割点。而这样的点必然存在,直接暴力判断即可。
证明:根据之前的条件,可知连通块大小 \(m \geq 3\)。建出连通块的圆方树。若整个连通块点双连通,显然。否则选择一个叶子圆点即可。我们知道圆方树的叶子圆点均不是割点,且它不可能和所有点均直接相连,否则它就和其它所有点同时点双连通,结合 \(m\geq 3\),与叶子圆点矛盾。正比。
时间复杂度 \(\mathcal{O}(n ^ 2)\)。代码。
*F1. Anti-median (Easy Version)
考察合法排列的形态。
对于长为 \(3\) 的子区间 \([p_1, p_2, p_3]\),必然有 \(p_2 > p_1, p_3\) 或 \(p_2 < p_1, p_3\),因此排列呈波浪形。
对于长为 \(5\) 的子区间 \([p_1, p_2, p_3, p_4, p_5]\),不妨设 \(p_3 > p_2, p_4\),则 \(p_3\) 必须至少大于 \(p_1\) 和 \(p_5\) 中的一个数。因此,若排列所有奇数位为峰,则仅考虑奇数位时不能存在谷。因此奇数位必然先增后减。同理,此时偶数位先减后增。
对于更长子区间的限制,应该怎么办?我们发现,假设中间的数为峰,则根据上述限制,必然存在一侧所有数全部小于它,且另一侧与它相邻的数也小于它,限制自然满足。
综上,我们得到合法排列的充要条件。接下来考虑 DP。
我们从合法排列的性质中抽出一些简化 DP。不妨设奇数位置为峰,偶数位置为谷,则 \(n\) 在奇数位置且向两端单调递减,\(1\) 在偶数位置且向两端单调递增。注意到在两端处一定有 \(p_1 > p_2\),\(p_{n - [2\mid n]} > p_{n - [2\nmid n]}\),所以从数值 \(n\) 开始,按 \(p ^ {-1}_n \to \cdots \to 3 \to 1 \to 2 \to 4 \to \cdots \to p ^ {-1}_1\) 走到数值 \(1\),数值单调递减。从右侧走同理。
这启发我们将偶数位置从左到右排列,再将奇数位置从右往左接在后面,首尾相连形成一个环。考虑数值 \([1, k](1 \leq k \leq n)\),它在环上一定形成一段子区间。据此,考虑区间 DP,设 \(f_{l, r}\) 表示往环子区间填入 \(1\) 到 \(\begin{cases} r - l + 1 & l \leq r \\ r + (n - l + 1) & l > r\end{cases}\) 的方案数。这样的 DP 方式保证了在所有长为 \(3\) 的子区间合法的前提下,所有长为 \(5\) 的子区间合法,因此我们只需保证长为 \(3\) 的子区间合法。转移时 \(\mathcal{O}(1)\) 检查即可,实现细节较多。
时间复杂度 \(\mathcal{O}(n ^ 2)\)。代码。
1762. Codeforces Round #838 (Div. 2)
A. Divide and Conquer
若奇偶性不对,则求出使得每个数第一次改变奇偶性的代价,取最小值即可。
B. Make Array Good
把每个数补齐到不小于它的最小的 \(2\) 的幂即可。
C. Binary Strings are Fun
将 \(0\) 视为 \(-1\),除了最后一段连续的数,之前每一段连续的数补齐之后对应偶数位的前缀和必须为 \(0\),方案唯一。则方案数即 \(2\) 的最后一段连续的数的长度减去 \(1\) 次幂。
时间复杂度 \(\mathcal{O}(n)\),代码。
*D. GCD Queries
不会做,哈哈。
询问一个数和其它所有数的 \(\gcd\),因为 \(\gcd(0, x) = x\),所以最大值一定是它本身。如果这个数大于 \(1\),则其所有倍数除以这个数之后递归进入子问题,直到只剩两个数,说明一个是当前数,另一个是 \(0\)。若第一次询问没有抽到 \(1\),则询问次数至多为 \(n + \frac n 2 + \frac n 4 + \cdots < 2n\)。如果第一次询问抽到 \(1\),则需要额外花费 \(n\) 次询问,一个解决方法是不断随机直到得到一对 \(\gcd > 1\) 的数。不知道能不能过,没写。
正解就非常巧妙了。对于任意三个位置 \(a, b, c\),根据 \(\gcd(0, x) = x\) 的关键性质:
- 若 \(\gcd(a, b) = \gcd(a, c)\),则 \(a\) 一定不是 \(0\)。
 - 若 \(\gcd(a, b) > \gcd(a, c)\),则 \(c\) 一定不是 \(0\)。
 - 若 \(\gcd(a, b) < \gcd(a, c)\),则 \(b\) 一定不是 \(0\)。
 
我们用两次询问确定一个位置不是 \(0\),直到候选集合只剩两个数。询问次数 \(2n - 4\),可以通过。代码。
第一种思路和第二种思路究竟差在哪里?前者在 \(n\geq 4\) 时可以确定 \(0\) 的位置,没有利用好题目只要返回两个可能为 \(0\) 的位置的性质。后者巧妙利用了题目要求,但无法确定 \(0\) 的位置。
E. Tree Sum
设 \(d_i\) 表示与 \(i\) 相连的边权乘积。
因为每条边对 \(\prod d_i\) 的贡献恒为 \((\pm 1) ^ 2 = 1\),所以,当 \(n\) 为奇数时,\(\prod d_i = -1\) 的要求无法被满足,不存在合法的树,答案为 \(0\)。
否则,我们通过经典的剥叶子套路,证明当树的形态确定时,赋边权使得合法的方案唯一。
直接枚举 \(d(1, n)\) 显然不好做,我们将贡献摊至路径上的每条边。直接枚举产生贡献的边两侧的子树大小 \(L, n - L\)。当 \(L\) 为奇数时,因为两棵子树内部 \(\prod d_i\) 为 \(1\),为使得除了与当前边相连的两点以外的所有点的 \(d_i = -1\),则与当前边相连的两点的 \(d_i = 1\),故当前边权值为 \(-1\)。当 \(L\) 为偶数时,当前边权值为 \(1\)。
求方案数:两侧子树均选择一个根作为两端。因为大小为 \(n\) 的有标号有根树的数量为 \(n ^ {n - 1}\),再从 \(2\sim n - 1\) 中选出与 \(1\) 同侧的 \(L - 1\) 个点,故方案数为 \(L ^ {L - 1} (n - L) ^ {n - L - 1} \binom {n - 2} {L - 1}\)。
时间复杂度 \(\mathcal{O}(n\log n)\)。代码。
*F. Good Pairs
首先,如果路径先下降后上升,即 \(a_x > a_y < a_z\),则 \(x\) 可达 \(z\)。因此,路径上所有点的权值 单调不降 或 单调不增。这两个问题解法几乎完全相同,且仅在 \(a_i = a_j\) 时重叠。接下来只讨论单调不降的情况,此时 \(a_i \leq a_j\)。
- 若 \(a_j\leq a_i + k\),则 \(i\) 直接可达 \(j\)。
 - 若 \(a_j > a_i + k\),则 \(i\) 会跳到第一个满足 \(a_i\leq a_{p_i}\leq a_i + k\) 的后继 \(p_i\),这样显然是不劣的。
 
对权值从大到小扫描线,用 set 维护权值落在 \([v, v + k]\) 的所有位置,即可快速求出 \(p_i\)。
关于求答案,难道我们要求出 \(a_{p_i}\) 所有 \(a_j > a_i + k\) 且可达的位置 \(j\) 吗?其实不然。考虑以 \(l = p_i\) 的合法对数量,一定满足 \(a_r \geq a_{p_i}\)。而 \(a_i\leq a_j < a_{p_i}\) 的 \(j\) 是一步可达的,所以 \(l = i\) 的合法对数量,即 \(l = p_i\) 的合法对数量,加上 \(j > i\) 且 \(a_i\leq a_j < a_{p_i}\) 的 \(j\) 的数量,容易 DP + BIT 维护。
时间复杂度 \(\mathcal{O}(n\log V)\)。代码。
1763. Codeforces Round #840 (Div. 2)
A. Absolute Maximization
输出所有数的按位或减去所有数的按位与。
B. Incinerate
将所有怪兽按 \(p\) 从小到大排序,记录当前所有怪物扣除的血量,暴力模拟即可。
时间复杂度 \(\mathcal{O}(n\log n + k)\)。代码。
实际上 \(k\) 可以出到 \(10 ^ 9\),因为经过 \(\mathcal{O}(\sqrt h)\) 轮之后要么 \(k\) 小于 \(0\),要么 \(h\) 小于 \(0\)。
*C. Another Array Problem
连 Div. 2 C 都不会做了,哈哈嗨。
当 \(n \geq 4\) 时,我们可以操作 \([l, r]\) 两次使得一段区间变成 \(0\),所以答案为 \(n\max a_i\)。
当 \(n = 2\) 时,答案为 \(\max(a_1 + a_2, 2|a_1 - a_2|)\)。
当 \(n = 3\) 时,可以类似 \(n\geq 4\) 做到 \(3a_1\) 和 \(3a_3\),剩下 \(a_2\) 为最大值的情况,类似分析得到 \(\max(a_1 + a_2 + a_3, 3(a_2 - a_1), 3(a_2 - a_3))\)。
时间复杂度 \(\mathcal{O}(n)\),代码。
D. Valid Bitonic Permutations
简单区间 DP,设 \(f_{l, r}\) 表示将 \(n - (r - l)\sim n\) 填入 \([l, r]\) 的方案数,转移枚举 \(n - (r - l)\) 填在 \(l\) 或 \(r\) 即可。
时间复杂度 \(\mathcal{O}(n ^ 2)\),代码。
应该可以通过分类讨论 + 组合数做到 \(\mathcal{O}(n)\)。
E. Node Pairs
注意到强连通具有传递性,所以一组强连通分量产生的贡献为点数选 \(2\)。
将 SCC 们连成一条链,即可在总点数 \(n\) 和强连通点对数 \(p\) 确定时最大化单向可达关系数:\(\dbinom n 2 - p\)。因此第二问的答案为第一问的答案选 \(2\) 减去 \(p\)。
至于第一问,因为 \(n\leq \mathcal{O}(p)\),完全背包即可。时间复杂度 \(\mathcal{O}(p\sqrt p)\)。代码。
F. Edge Queries
这题是不是有点裸?题目给的性质乱七八糟,完全没用。
建出圆方树,则 \(a, b\) 之间涉及到的所有点双即 \(a, b\) 在圆方树简单路径上的所有方点。
对于 \(a, b\) 路径上的一个点双,如果其不为两点一边即割边,则删去其中任意一条边 \(a, b\) 仍相互可达。因此,对于所有点双,若其为两点一边,则给其对应方点赋值 \(0\),否则赋点双内部边的条数作为权值,则询问 \(a, b\) 的答案即 \(a, b\) 在圆方树上的简单路径上的所有方点的权值之和。
视 \(n, m, q\) 同级,时间复杂度 \(\mathcal{O}(n\log n)\)。代码。
1764. Codeforces Global Round 24
A. Doremy's Paint
选择 \([1, n]\) 显然是最优的。
B. Doremy's Perfect Math Class
辗转相减,可知 \(d = \gcd(a_1, a_2, \cdots, a_n)\) 一定能被表出。所以答案即最大值除以 \(d\)。
C. Doremy's City Construction
将 \(a\) 从小到大排序,则根据题目限制,对于每个点,和它相连的所有点必须要么全部比它大,要么全部比它小,除非所有数全部相同,此时答案显然为 \(\frac n 2\)。
枚举 \(a_i\neq a_{i + 1}\) 的分割点 \(i\) 取最大值即可,时间复杂度 \(\mathcal{O}(n\log n)\)。代码。
D. Doremy's Pegging Game
枚举最终绑在两侧的点的距离 \(i\)。设 \(a\) 的最后一个元素有 \(r\) 种可能,则对于 \(n\) 为偶数,\(r = i\),对于 \(n\) 为奇数,\(r = i - 1\)。
枚举绑在两侧的点之间保留的数的个数 \(j\),则答案为 \(n \sum_i r \times \sum_{j = 0} ^ {i - 2} \binom {i - 2} {j} (n - 3 - j)!\)。\(\binom {i - 2} j\) 表示从两侧点之间选 \(j\) 个保留,\((n - 3 - j)!\) 表示任意安排不保留且不是最后一个点的所有点的顺序,\(r\) 表示最后一个元素有 \(r\) 种可能,\(n\) 表示任意安排绑在两侧的点。
注意特判 \(i = 1\) 的情况。对于 \(n\) 为偶数,\(i\) 的枚举范围为 \([1, \frac n 2]\),对于 \(n\) 为奇数,\(i\) 的枚举范围为 \([2, \frac {n + 1} 2]\)。时间复杂度 \(\mathcal{O}(n ^ 2)\)。代码。
*E. Doremy's Number Line
显然,当 \(a_1 \geq k\) 时有解, \(a_1 + b_1 < k\) 时无解。此时有 \(a_1 < k\) 且 \(a_1 + b_1 \geq k\),则 \(p_1\) 不可能为 \(1\),我们将 \((a_1, b_1)\) 删去。
首先,因为可以点亮负数,所以 \(x\) 必须未点亮这个限制可以当做不存在。
进一步地,如果 \(x\) 可以被点亮,则任何小于 \(x\) 的位置均可被点亮,这一点根据对 \(x\) 的限制容易证明。因此,除了 \(p_1\),其它 \(p_i\) 对应的 \((a_{p_i}, b_{p_i})\) 都是尽量往数轴右侧扩张,使得可扩张到不小于 \(k - b_1\) 的位置,若可以则有解,否则无解。
枚举 \(p_1\),设 \(c\) 表示当前扩张的位置,则接下来的每个 \((a, b)\) 都相当于 \(c\gets \min(a, c) + b\)。感性理解我们会先花掉 \(a\) 较小的 \((a, b)\) 尽量扩张,使得花较大的 \((a, b)\) 时 \(\min(a, c)\) 的限制尽量小。严谨证明直接考虑邻相交换即可。
不妨设 \(a_i \leq a_{i + 1}\)。
直接做的复杂度为 \(\mathcal{O}(n ^ 2)\)。但是若 \(p_1 = k\),则所有 \(j < k\) 的 \((a_j, b_j)\) 都会对 \(c\) 产生 \(a_j + b_j\) 的贡献。因此从小到大枚举 \(k\),维护 \(a_j + b_j\) 的前缀 \(\max\),即可求出 \(p_1 = k\) 时处理前 \(k\) 个 \((a, b)\) 之后得到的 \(c\)。和 \(p_1 < k\) 时处理前 \(k - 1\) 个 \((a, b)\) 得到的最大的 \(c\) 在经过 \((a_k, b_k)\) 更新后的值取 \(\max\) 即可,可以看成一种动态规划。
时间复杂度 \(\mathcal{O}(n\log n)\)。代码。
*F. Doremy's Experimental Tree
标算的确厉害:注意到若 \(i, j\) 不直接相连,则存在 \(k\) 使得 \(f(i, k)\) 和 \(f(j, k)\) 均大于 \(f(i, j)\),这和最大生成树的性质如出一辙。因此,我们断言原树结构即 \((i, j, f(i, j))\) 的最大生成树。
得到 \((i, j)\) 边权 \(w\) 很容易。考虑到 \(f(i, i) - f(i, j)\) 相当于 \(w\) 乘以 \(j\) 在以 \(i\) 为根时的子树大小,所以 \(w = \frac {f(i, i) + f(j, j) - 2f(i, j)} {n}\)。
接下来讲讲我的做法。
考虑检查 \(i, j\) 是否直接相连。考虑到若 \(i, j\) 直接相连,则对于所有 \(k\),\(f(k, i) - f(k, j)\) 要么等于 \(f(i, i) - f(i, j)\),此时 \(k\) 在 \(i\) 子树内,要么等于 \(f(j, i) - f(j, j)\),此时 \(k\) 在 \(j\) 子树内。反之,则对于不在 \(i, j\) 子树内的 \(k\),必然有 \(f(k, i) - f(k, j)\) 不等于上述两者。考虑按随机顺序枚举 \(k\) 检查,若 \(i, j\) 子树大小和为 \(c\),则期望检查 \(\frac n {n - c + 1}\) 次找到反例。
考虑一条链的极限情况,期望检查次数为 \(\sum_{i = 1} ^ n \frac {n ^ 2} {i}\),时间复杂度 \(\mathcal{O}(n ^ 2\ln n)\)。代码。
**G3. Doremy's Perfect DS Class (Hard Version)
这种题目一般都考虑从较特殊的 \(k = 2\) 或 \(k = n\) 入手。\(k = n\) 看起来不太可行,因此考虑 \(k = 2\)。
从 \(30\) 次询问限制可以想到二分。设 \(\mathrm{solve}(l, r)\) 表示已知答案 \(a \in [l, r]\),希望确定答案。设 \(m = \frac {l + r} 2\)。
关键问题在于确定答案究竟在 \([l, m]\) 还是 \([m + 1, r]\) 中。这里有个有趣的思想,就是我们不能将眼光仅局限于 \([l, r]\),因为 \(\mathrm{solve}(l, r)\) 并不是一个严格的子问题,\(l\sim r\) 并不是 \(1\sim r - l + 1\) 的排列,我们依然需要依靠 \(p_1\sim p_n\)。换言之,我们只需要确定答案在 \([1, m]\) 或 \([m + 1, r]\) 中。
根据这样的思想,考虑如何询问。
将 \(p_i\) 全部除以 \(2\) 下取整,称 \(x, y\) 配对当且仅当 \(p_x, p_y\) 除以 \(2\) 下取整相同。
当 \(n\) 为奇数时,除了 \(a\) 以外的所有位置均有与其配对的位置,而询问 \(Q(l, r, 2)\) 相当于求出 \(r - l + 1\) 减去区间配对数,则区间落单数可由 \(r - l + 1\) 减去两倍区间配对数得到,即 \(2Q(l, r, 2) - (r - l + 1)\)。设 \(f(l, r)\) 表示 \([l, r]\) 的区间落单数,则对于 \(f(1, m)\) 和 \(f(m + 1, n)\),因为每个除了 \(a\) 以外的区间落单位置会同时在 \([1, m]\) 和 \([m + 1, n]\) 中出现,所以只需递归进入 \(f\) 较大的那个区间即可。时间复杂度询问次数 \(2\lceil\log_2 n\rceil \leq 20\)。
当 \(n\) 为偶数时,设 \(p_b = n\),则 \(a, b\) 均没有与其配对的位置。类似地,求出 \(f(1, m)\) 和 \(f(m + 1, n)\)。若已知 \(b\leq m\) 或 \(b > m\),则扣除 \(b\) 的贡献后类似 \(n\) 为奇数做。否则,若 \(f(1, m) > f(m + 1, n)\),说明 \(a, b\leq m\)。若 \(f(1, m) < f(m + 1, n)\),说明 \(a, b > m\)。若 \(f(1, m) = f(m + 1, n)\),说明 \(a, b\) 在 \(m\) 的两侧。
考虑确定 \(b\) 的位置。注意到将所有数除以 \(n\) 下取整之后,只有 \(p_b = 1\),其它均为 \(0\)。利用这一点,我们断言若 \(r - l + 1 \geq 2\),则 \(b\in [l, r]\) 当且仅当 \(Q(l, r, n) = 2\)。因此,若 \(m > 1\),可直接询问 \(Q(1, m, n)\) 确定 \(b\) 是否在 \([1, m]\) 中。否则 \(m = 1\),因为 \(n\geq 3\),所以询问 \(Q(m + 1, n, n)\) 确定 \(b\) 是否在 \([m + 1, n]\) 中。
确定 \(b\) 的位置后,因我们向相反方向递归,所以若此时 \(b\leq m\) 则接下来一定有 \(b\leq m'\),若此时 \(b > m\) 则接下来一定有 \(b > m'\)。询问次数 \(2\lceil\log_2 n\rceil + 1 \leq 21\),可以通过 G2。
最后优化通常是通过已知信息简少询问次数。
考虑到卡满 \(\lceil \log_2 n\rceil\) 上界的二分过程必然经过 \(r - l + 1 = 2\) 的情形。当 \(l \neq 1\) 时,我们必然询问过 \(Q(1, l - 1, 2)\),否则 \(Q(1, l - 1, 2) = 0\)。当 \(r\neq n\) 时,我们必然询问过 \(Q(1, r, 2)\),否则 \(Q(1, r, 2) = \lfloor \frac n 2\rfloor + 1\)。对于 \(Q(l, n, 2), Q(r + 1, n, 2)\) 同理。
考虑 \([l, r]\) 中不是 \(a\) 的位置 \(x\)。我们容易根据此时是否确定 \(b\) 来判断 \(x\) 是否等于 \(b\)。若 \(x = b\),则直接进入判断 \(b\) 的位置的分支,只需花掉一次询问。若 \(x\neq b\),则考虑与 \(x\) 配对的位置,若与 \(x\) 配对的位置 \(< l\),则 \(Q(1, r, 2) - Q(1, l - 1, 2) = 1\) 且 \(Q(l, n, 2) - Q(r + 1, n, 2) = 2\)。若与 \(x\) 配对的位置 \(> r\),则情况相反,不再赘述。
基于此,不妨设与 \(x\) 配对的位置 \(< l\),则若 \(Q(1, l, 2) = Q(1, l - 1, 2)\),说明 \(x = l\),\(a = r\),否则说明 \(x = r\),\(a = l\)。同样只需花掉一次询问。
综上,我们在 \(r - l + 1 = 2\) 的分支少花掉了一次询问,询问次数 \(2(\lceil \log_2 n\rceil - 1) + 1 + 1\leq 20\)。代码。
*H. Doremy's Paint 2
难题。
破环成链。考虑一次询问。
对于没有被任何区间覆盖的位置,它们对答案产生 \(1\) 的贡献,这是显然的。扫描线计算这部分的答案。
对于被某个区间覆盖的位置,它们产生贡献的必要条件是为某个区间的左端点,这也是显然的。这使得我们可以将位置对答案的贡献转化为一个区间左端点对答案的贡献。
现在问题来了,一个区间左端点 \(l_i\) 对答案产生贡献的充要条件是什么?
首先,这个左端点不能被之前的区间覆盖掉。因此,我们设 \(f_i\) 表示上一个覆盖 \(l_i\) 的区间,容易线段树维护。
其次,这个区间内所有位置不能被其它区间覆盖掉。因此,我们设 \(g_i\) 表示区间所有位置被彻底覆盖掉的时刻。如何维护呢?
设 \(v_j\) 表示从当前时刻,位置 \(j\) 上的颜料被彻底覆盖掉的时刻,那么有 \(g_i = \max_{p = l_i} ^ {r_i} v_p\)。然后考虑 \([l_i, r_i]\) 产生的影响。根据实际意义,有 \(v_{l_i}\gets g_i\),而 \(v_{l_i + 1}\sim v_{r_i} \gets i\),同样线段树维护。
求出 \(f_i, g_i\) 之后,可知 \(l_i\) 对询问 \([L, R]\) 产生贡献当且仅当 \(f_i < L\),\(R < g_i\) 且 \(L\leq i\leq R\)。这是三维偏序,但由于 \(R - L + 1\) 为定值,所以 \(l_i\) 产生贡献的询问是一段区间,树状数组维护即可。
视 \(n, m, k\) 同级,时间复杂度 \(\mathcal{O}(n\log n)\)。代码。
官方题解太抽象了,说得不是很清楚。
大概理解了一下,就是固定断点 \(p\),批量处理所有跨过断点 \(p\) 的询问。如何处理呢?一个 set 维护前半部分的连续段 \([*, p]\),另一个 set 维护后半部分的连续段 \([p + 1, *]\)。前半部分左端点每次向左扩展 \(1\),这个修改是容易处理的。后半部分右端点每次向右缩减 \(1\),怎么维护呢?先从 \([p + 1, p + 1]\) 开始,右端点不断向右扩展,记录修改,这样就可以撤销了。每次对任意 set 的修改都可以在另一个 set 通过 \(\mathcal{O}(1)\) 次查询得到修改对答案的影响。再加上离散化,单组处理 \(\mathcal{O}(k\log k)\)。总时间复杂度也是 \(\mathcal{O}(n\log n)\)。写起来稍微有点抽象,细节一大堆。感觉不如子睿五郎黄的做法。
1765. 2022-2023 ICPC, NERC, Southern and Volga Russian Regional Contest
A. Access Levels
设 \(S_i\) 表示有权限查看第 \(i\) 份文件的人。
探究文件 \(i\) 和文件 \(j\) 可在同一组的充要条件。因为权限值较大的人可查看的题目一定包含权限值较小的人可查看的题目,且若满足该条件则容易构造出权限值,所以充要条件为 \(S_i\) 包含或包含于 \(S_j\)。
这说明放在一组的文件 \(i_1, i_2, \cdots, i_k\) 满足 \(S_{i_1}\supseteq S_{i_2} \supseteq \cdots\supseteq S_{i_k}\)。若 \(S_i\supseteq S_j\) 则 \(i\) 向 \(j\) 连边,注意若 \(S_i = S_j\),为防止产生环,当且仅当 \(i < j\) 时连边。问题转化为 DAG 最小路径覆盖,网络流解决即可。
求出最小路径覆盖后,构造方案是平凡的。建图复杂度为 \(n ^ 3 / w\),网络流部分复杂度为 \(n ^ {2.5}\)。代码。
B. Broken Keyboard
这就属于究极签到题了吧。
C. Card Guessing
根据期望的线性性,将答案摊到每次猜测。
第 \(i\) 次猜测的已知卡片数量为 \(c = \min(i - 1, k)\)。设四种卡片落在已知卡片区的张数分别为 \(c_1\sim c_4\),需要满足 \(c = \sum c_i\),则安排这些卡片的方案数为
我们要从所有出现次数最小的卡片中选一个放到下一个位置上。设出现次数最小的卡片数量为 \(d\),则有 \(d\) 种方案,但因为 Monocarp 会从这 \(d\) 张卡片中随机选择,所以一乘一除抵消掉了。设最小值为 \(mn = \min c_i\),则贡献至答案的式子为
即
枚举最小值 \(p\),设 \(f_i\) 表示使得 \(c = i\) 的方案数之和,做背包即可。
时间复杂度 \(\mathcal{O}(n ^ 3)\)。代码。
D. Watch the Videos
每部电影的下载时间肯定会算满,唯一可以节省时间的地方在于同时观看和下载电影。我们先将观看电影的时间也算上,即令初始答案为 \(n + \sum a_i\)。
考虑观看顺序 \(b_1, b_2, \cdots, b_n\)。如果 \(a_{b_i} + a_{b_{i + 1}}\leq m\),则代价减少 \(1\)。我们希望找到排列 \(b\) 使得这样的 \(i\) 尽量多。
将 \(a\) 从小到大排序,假设有 \(k\) 对这样的 \(i\),选择最小的 \(k + 1\) 个数构造 \(k + 1, 1, k, 2, \cdots\) 是最优的,它保证了相邻两个数之和的 \(\max\) 最小。二分检查即可。
简化二分过程,可以双指针做到除排序外 \(\mathcal{O}(n)\)。代码。
E. Exchange
若 \(a > b\),只要一次。否则需要 \(\lceil \frac n a\rceil\) 次。
*F. Chemistry Lab
挺趣味的一道题,让我对线性组合产生了新的理解。
考虑两种试剂 \(i, j\) 以及对应体积 \(a_i, a_j\),则浓度为 \(a_ix_i + a_jx_j\),价格为 \(a_ic_i + a_jc_j\)。不妨 \(x_i \geq x_j\),设给定浓度 \(x\in [x_i, x_j]\),得方程组 \(\begin{cases} a_i + a_j = 1 \\ a_ix_i + a_jx_j = x \end{cases}\),解得 \(\begin{cases} a_i = \frac {x - x_j} {x_i - x_j} \\ a_j = \frac {x_i - x} {x_i - x_j} \end{cases}\)。再乘上价格作为系数,可以发现价格是关于浓度的线性函数,且当浓度为 \(x_i\) 时,价格为 \(c_i\),当浓度为 \(x_j\) 时,价格为 \(c_j\)。
将每种试剂 \((x_i, c_i)\) 视为平面上的点 \(P_i\),则 \(i, j\) 组合出的试剂落在线段 \(P_iP_j\) 上,而浓度为 \(x\) 时的价格即横坐标为 \(x\) 时对应纵坐标 \(c\) 的值。期望值即 \(c\) 在 \([x_j, x_i]\) 上的积分,即线段和横坐标围成的梯形面积 \(g(j, i) = \frac {(c_i + c_j)(x_i - x_j)} 2\)。
进一步地,当存在多种试剂时, 它们组合出的试剂在这些试剂对应的点的凸包上,而我们只关心上凸包的积分。这是一个经典结论,但我不太会证:若干个点的权重之和为 \(1\) 的线性组合形成的区域为这些点的凸包。2022 杭电多校第四场 08 也用到了这个结论。
将所有试剂按 \(x\) 从小到大排序,设 \(f_i\) 表示选择第 \(i\) 种试剂时,在前 \(1\sim i\) 种试剂中的答案,则有转移 \(f_i = -w_i + \max(0, \max_{j = 1} ^ {i - 1} f_j + g(j, i))\)。转移下凸一定是不优的,对答案没有影响。
时间复杂度 \(\mathcal{O}(n ^ 2)\)。代码。
*G. Guess the String
先询问出 \(s_2\),然后询问位置 \(4, 6, 8, \cdots\)。设当前询问位置 \(i\),可以确定 \(s_i\)。
- 当返回值不小于 \(2\) 时,可以确定 \(s_{i - 1}\)。
 - 否则,根据 \(s_1\) 是否等于 \(s_2\),询问类型以及返回值为 \(1\) 或 \(0\),分类讨论可证当询问类型随机时,有一半的概率可以确定 \(s_{i - 1}\),剩下一半情况必须再询问一次 \(i - 1\)。
 
期望询问次数 \(\frac 3 4n\),有 \(39\) 次冗余询问,询问超出限制次数的概率非常小,可以通过。代码。
*H. Hospital Queue
赛时做法:答案具有可二分性。设当前检查是否有 \(p_i\leq k\),相当于 \(p_i := k\) 并检查是否有解。检查是否有解:设 \(a_i\) 表示 \(i\) 能到达的所有点 \(j\) 的 \(p_j\) 的最小值,拓扑排序时贪心选取当前队列中 \(a_i\) 最小的点并扩展。若当前取出的点已经打破限制,则无解。时间复杂度 \(\mathcal{O}(nm\log ^ 2 n)\),TLE。因为取出的点的 \(a_i\) 单调不降,所以将优先队列换成若干个桶可以做到 \(\mathcal{O}(nm\log n)\),勉强通过。
官方做法:很巧妙!将整个过程倒过来,将 \(i\) 尽量往后放,也就是从 \(n\) 到 \(i\) 找到第一个时刻 \(j\) 使得除了 \(i\) 以外,当前没有可以取出的位置,则 \(j\) 即为 \(i\) 的答案。当时刻不大于一个位置的限制时,它可以被取出,优先队列或若干个桶维护。时间复杂度 \(\mathcal{O}(nm)\)。代码。
I. Infinite Chess
直接 BFS,复杂度高达 \(8\times 10 ^ 8\),无法接受。
注意到行数很少,这样斜向攻击只会影响到半径为 \(8\) 的列邻域。而对于横向攻击,我们可以把一段每行被攻击状态相同的列缩成一列,相当于离散化。注意国王可以斜向走,所以两侧还要保留 \(8\) 列。
离散化后模拟得到每个格子是否被攻击,跑最短路即可。时间复杂度 \(\mathcal{O}(n\log n)\)。代码。
*J. Hero to Zero
操作顺序无关,因此设 \(x_i\) 表示将第 \(i\) 行所有数减去 \(x_i\),\(y_i\) 表示将第 \(j\) 行所有数减去 \(y_j\)。
如果 \(x = y = 0\),则代价为 \(\sum c_{i, j}\),\(x_i\) 或 \(y_j\) 每增加 \(1\),代价减小 \(n - 1\),但 \(x_i + y_j\) 不能超过 \(c_{i, j}\)。
因此,相当于找到一组 \(x, y\),使得 \(x_i + y_j \leq c_{i, j}\) 并最大化 \(\sum x_i + y_i\)。注意到这很像最大权完美匹配的 KM 算法中的顶标,不过不等号限制换了一个方向。这启发我们猜测 \(\sum x_i + y_i\) 的最大值即 \(i, j\) 之间连边 \(c_{i, j}\) 的二分图的最小权完美匹配。
证明:最大不会超过最小权完美匹配是显然的,能达到该值则可借助 KM 算法证明。
综上,我们将问题转化为求 \(\sum |a_i - b_{p_i}|\) 的最小值,其中 \(p\) 是 \(1\sim n\) 的排列。从小到大排序后对应匹配即可。初始 \(\sum c_{i, j}\) 也容易求。
时间复杂度 \(\mathcal{O}(n\log n)\),瓶颈在排序。代码。
K. Torus Path
赛时做法:从某一列的最后一行跨越至第一行后,无法从某一行的最后一列跨越至第一列,否则路径必然交叉。因此,设 \(f_{i, j, k}\) 表示第一次进入第 \(i\) 列的位置为 \((k, i)\),当前位置为 \((j, i)\) 的最大收益。根据实际意义转移。注意行列交换再做一次。时间复杂度 \(\mathcal{O}(n ^ 3)\)。代码。
官方做法:手玩几组 \(n\) 较小时的简单情况,发现无论怎么走,至少一个副对角线上的元素无法经过,且除此以外所有位置都能经过。证明即考虑可达副对角线的位置共 \(n\) 个,但 \((n, n)\) 作为终点,所以最多 \(n - 1\) 次经过可达副对角线的位置。钦定某位置不可达后,可用简单策略生成 \((1, 1)\) 到 \((n, n)\) 的路径:每次向下走,只有向下走非法时才向右走。时间复杂度 \(\mathcal{O}(n ^ 2)\)。
赛时做法可以解决 \(a_i < 0\) 的情况,但标算不行。是否存在 \(\mathcal{O}(n ^ 2)\) 且能解决 \(a_i < 0\) 的做法?
设 \(f_{i, j}\) 表示第 \(i\) 列经过最后一个格子为 \((j, i)\) 的最大收益,则对于 \(k\geq j\),产生 \(f_{i, j} + \sum_{p = j} ^ k a_{p, i + 1}\) 贡献。对于 \(k < j\),产生 \(f_{i, j} + \sum_{p = j} ^ n a_{p, i + 1} + \sum_{p = 1} ^ k a_{p, i + 1}\) 贡献。容易前缀和,前后缀 \(\max\) 优化。时间复杂度 \(\mathcal{O}(n ^ 2)\)。代码懒得写了。
L. Project Manager
设 \(N = \sum p\)。
考虑到每个没有节假日的周必然存在至少一个项目被完成,所以答案不超过 \(M = 7(N + m)\)。对于 \(h_i > M\) 的节假日,一律无用。
因为一个人会选择编号较小的项目推进,所以按编号从小到大依次模拟每个项目的进度。设当前处理到项目的第 \(i\) 部分,在第 \(cur\) 天处理了第 \(i - 1\) 部分。求出第 \(a_i\) 个人在第 \(cur + 1\) 天起,第一个工作且没有处理编号更小的项目的日期。
星期一到星期日相互独立,因此考虑对一星期的七天,如果 \(a_i\) 在这天工作,分别求后继,再取最小值。这样,在第 \(h_i\) 天的假期相当于从 \(h_i\) 跳到了 \(h_i + 7\)。类似的,一个被占用处理编号更小的项目的日期 \(p\) 相当于从 \(p\) 跳到了 \(p + 7\)。对于前者,直接预处理出 \(suc_i\) 表示从 \(i\) 开始的对应类型的第一天工作日。对于后者,用 map 维护并查集即可。注意这里并查集是一条链,所以执行 find 的总次数为总点数的线性,而每新增一个点,都意味着找到一个工作且未被占用的后继,所以总点数为 \(\mathcal{O}(N)\) 级别。
时间复杂度 \(\mathcal{O}(m + N\log N)\)。不压行且两空格缩进的 代码 竟然获得了 CF 最短解(2022.12.16)?跑得也非常快,前提是开了 ios::sync_with_stdio(0)。
M. Minimum LCM
设 \(d = \gcd(a, b)\),则它们的 \(\operatorname{lcm}\) 为 \(dxy\),且 \(d(x + y) = n\)。因为 \(x + y\) 为定值 \(c = \frac n d\),为使得 \(xy\) 最小,令 \(x = 1\),\(y = c - 1\) 最优,对应 \(\operatorname {lcm}\) 为 \(d(c - 1)\) 即 \(n - d\)。
因此,找到 \(n\) 的最大真因数 \(d\),则 \(n - d\) 即为答案,构造 \(d\) 和 \(n - d\) 即可。
时间复杂度 \(\mathcal{O}(\sqrt n)\)。代码。
N. Number Reduction
将 \(x\) 当成字符串,从前往后贪心。设当前考虑到第 \(i\) 位,剩余可以删去的位数为 \(k\)。当 \(cur + k > n\) 时,剩下来所有位都可以删去,直接退出。否则,根据贪心原则,我们找到最小的在 \([i, i + k - 1]\) 位出现过的数码,跳到它的下一次出现位置 \(p\),将位置 \(i\sim p - 1\) 上的数码全部删掉。维护 \(suc_{i, j}\) 表示从 \(i\) 开始 \(j\) 的第一次出现位置即可。注意特判第一次不能跳数码 \(0\)。时间复杂度 \(\mathcal{O}(n)\),有 \(10\) 倍常数。代码。
1766. Educational Codeforces Round 139
A. Extremely Round
将 \(n\) 视为字符串,显然答案为 \(9(|n| - 1) + n_0\)。
B. Notepad#
因为只需检查操作次数是否小于 \(n\),所以粘贴长度大于 \(2\) 的子串不优于粘贴长度等于 \(2\) 的子串。只需检查是否存在不交且相等的长度为 \(2\) 的子串即可。
时间复杂度 \(\mathcal{O}(n)\),代码。
C. Hamiltonian Wall
分析性质:从 \((i, j)\) 出发,一旦 \(j\) 增大,就永远不会回来了。这是因为,如果从第 \(j\) 列走到第 \(k(j < k)\) 列又回到第 \(j\) 列,说明第 \(j\) 列到第 \(k\) 列之间的每一列都有两个黑格子,我们可以将路线改变为蛇形。
因此,我们可以断言,若存在解,则存在从第一列某个黑格子开始,纵坐标不减小的路径。确定起始点后这样的路径唯一,暴力即可。
时间复杂度 \(\mathcal{O}(n)\)。代码。
D. Lucky Chains
固定 \(x, y, d\),考虑最小的 \(k\) 使得 \(\gcd(x + k, y + k) = d\)。当 \(d\nmid y - x\) 时,显然无解。否则若 \(x + k\) 为 \(d\) 的倍数,则 \(y + k\) 同样为 \(d\) 的倍数。
因此,当 \(d\mid x\) 时,答案为 \(0\)。否则还需要 \(d - (x\bmod d)\) 次操作使得 \(x\) 变为 \(d\) 的倍数。
考虑 \(y - x\) 的所有约数 \(d_i\),对它们的答案取最小值即为所求。时间复杂度 \(\mathcal{O}(nd(y))\),无法接受。
若 \(d_i\mid d_j\),则当 \(x + k\) 为 \(d_j\) 的倍数时,\(x + k\) 显然为 \(d_i\) 的倍数。所以只需考虑 \(y - x\) 的所有素因子。埃氏筛或线性筛出每个数的最小质因子,时间复杂度 \(\mathcal{O}(n\log y)\)。代码。
*E. Decomposition
这题还蛮不错的。
先考虑 \(f(1, n)\)。
首先,\(0\) 是相对特殊的。每个 \(a_i = 0\) 恰好产生一个空序列,且不产生其他任何影响,对 \(f(1, n)\) 的贡献为 \(1\)。
不妨设序列里面没有 \(0\)。
我们注意到,因为 \(3\) 可以和所有数(\(1\sim 3\) 相邻),所以 \(3\) 一定放在第一个序列里,不会影响到其它序列。
因此,除了第一个序列以外,其它序列要么全是 \(1\),要么全是 \(2\),\(f(1, n)\leq 3\)。
因为只有三个序列,且我们只关心序列的最后一个数,可能的状态很少,这启发我们设 \(f_{i, j, k, l}\) 表示在所有 \(f(a[p, i]) (p \leq i)\) 当中,三个序列末尾分别为 \(j, k, l\) 的 \(p\) 的数量,其中若 \(j / k / l = 0\) 则表示对应序列不存在。
直接枚举 \(j, k, l\),结合对应的 \(a_i\) 通过模拟题目要求转移即可。答案即 \(\sum f_{i, j, k, l} ([j > 0] + [k > 0] + [l > 0])\)。
当序列里面有 \(0\) 时,它对所有包含它的区间产生 \(1\) 的贡献,这是容易计算的。
可以记录是否存在全 \(1\) 序列和全 \(2\) 序列取代 \(k, l\),将总状态数除以 \(4\),但不必要。
时间复杂度 \(\mathcal{O}(n)\)。代码。
*F. MCF
一个自然的想法是,对于所有容量为奇数的边,它的流量至少为 \(1\)。我们钦定它流 \(1\) 单位流量。也就是说,将原图每条边的容量变成 \(\lfloor \frac c 2\rfloor\),跑最小费用可行流,则每条边的流量为其新图流量的两倍,加上它的奇偶性。问题在于没有考虑到原来每条奇边的 \(1\) 流量的影响。
简单,对于每个不为 \(1\) 或 \(n\) 的点,设它在仅考虑奇边的 \(1\) 单位流量时,流入流量减去流出流量为 \(in_i\)。若 \(in_i\) 为奇数,显然无解。否则,若 \(in_i > 0\),说明所有奇边对 \(i\) 的影响是让它多出 \(in_i\) 滴流量。因此,在新图上从 \(s\to i\) 连容量 上下界 \(\frac {in_i} 2\) 的边。费用任意,反正钦定流满了。
这样,我们将问题转化为 有负权边的上下界最小费用可行流。尽管原图保证无负环,但是为求可行流而连出的 \(t\to s\) 可能导致新图产生负环,如样例 1。因此,还需使用负环费用流的技巧,钦定负权边流满,在反边上退流。
时间复杂度是一次费用流,注意构造方案的细节。代码。
1767. Educational Codeforces Round 140
A. Cut the Triangle
检查是否为直角三角形即可。
B. Block Towers
将 \(a_2\sim a_n\) 从小到大排序后不断和 \(a_1\) 合并即可,有点像国王饮水记。
时间复杂度 \(\mathcal{O}(n\log n)\),代码。
C. Count Binary Strings
设 \(f_i\) 表示 \(i\) 前缀的答案,枚举极长段,\(f_i\) 可以从 \(f_j\) 转移当且仅当不存在 \(j < j' \leq i' \leq i\) 使得 \(a_{j', i'} = 2\),且不存在 \(j'\leq j < i'\) 使得 \(a_{j', i'} = 1\),因为 \(s_{j + 1} \sim s_i\) 完全相同,且 \(s_{j}\neq s_{j + 1}\)。
最后将答案乘以 \(2\),时间复杂度 \(\mathcal{O}(n ^ 2)\)。偷懒写了 \(n ^ 4\)。代码。
D. Playoff
设 \(0\) 的数量为 \(a\),\(1\) 的数量为 \(b\),则答案为 \([2 ^ b, 2 ^ n - 2 ^ a + 1]\)。结论是容易证明的。
时间复杂度 \(\mathcal{O}(2 ^ n)\),代码。
E. Algebra Flash
如果存在两个连续的平台未被激活,则不合法。
因此,存在相邻的颜色分别为 \(i\) 和 \(j\) 的平台,则在 \((i, j)\) 之间连边。在 \(c_1\) 和 \(c_n\) 连自环,则问题转化为选择点权和最小的点集,使得每条边至少被一个点覆盖。根据经典结论,它等价于点权和减去最大权独立集。
最大权独立集有一个非常经典的做法:枚举前 \(n / 2\) 个点是否选择,对剩余 \(n / 2\) 个点的状态记忆化搜索即可。
相关资料:《浅谈信息学竞赛中的独立集问题》 - 学习笔记 - p_b_p_b。
时间复杂度 \(\mathcal{O}(n + 2 ^ {m / 2})\),注意自环。代码。
*F. Two Subtrees
设 \(n, q\) 同阶。
做法一:
出现次数,考虑根号分治。
对于出现次数大于 \(B\) 的值,不超过 \(\frac n B\) 个,可以直接暴力,这部分复杂度 \(\mathcal{O}(\frac {n ^ 2} B)\)。
对于出现次数小于 \(B\) 的值,我们可以将整棵树的 DFS 序划分为 \(\mathcal{O}(occ)\) 段,使得每一段所有点的子树内该值的出现次数相同,共有 \(\mathcal{O}(occ ^ 2)\) 种组合方案。每种组合方案相当于往矩形内加入一个值,询问相当于单点查最优值。这个问题在一般限制下只能做到 \(\log ^ 2\),所以这部分复杂度 \(\mathcal{O}(nB\log ^ 2 n)\)。
取 \(B = \frac {\sqrt n} {\log n}\),得到最优复杂度 \(\mathcal{O}(n\sqrt n \log n)\)。但是空间复杂度为 \(n\sqrt n\),看上去不太好。注意到第二部分查询单点的复杂度仅为 \(\log n\),查询总复杂度 \(n\log n\),从这点下手,我们每次只处理一些出现次数小于 \(B\) 的值,使得它们的 \(\mathcal{occ}\) 之和不超过 \(K\),这样产生了 \(\frac n K\) 轮查询,但空间降为 \(KB\log n\)。令 \(K = \sqrt n\),得到空间复杂度 \(\mathcal{O}(n)\),时间复杂度不变。
没写,看起来太难写了,也不知道能不能通过。
做法二:
考虑只有一个点 \(u\),DFS 拍平后相当于区间查询出现次数最大的数的最小值。区间众数是经典不可 \(\mathrm{polylog}\) 问题,考虑莫队。对于众数最小值,则需要对记录每个值出现次数的序列分块,以避免移动指针时产生 \(\log\)。这样单次查询复杂度为 \(\mathcal{O}(\sqrt n)\)。
两个点类似,四维莫队,时间复杂度 \(\mathcal{O}(n ^ {7 / 4})\)。
没写,太无脑了。
做法三:
做法二只是将树拍平到了序列上,但 子树在 DFS 序上形成的区间 \([l_u, r_u]\) 存在比序列上的随机区间更好的性质。或者说,把树拍平会损失一些性质。
考虑 dsu on tree 的过程,轻子树暴力遍历,重子树直接继承。重子树回到它的父亲的时候,需要重新添加轻子树的信息。离开轻子树时,需要清空轻子树内所有节点产生的影响。根据轻子树大小之和为 \(\mathcal{O}(n\log n)\) 的性质,dsu on tree 的复杂度为 \(\mathcal{O}(n\log n)\)。
借鉴思想,我们优先访问轻儿子,再访问重儿子,然后将根加入遍历序列。在遍历序列中移动时,如果当前点 \(u\) 和目标 \(v\) 之间有祖先后代关系,那么相当于将 \(l_u\) 移动至 \(l_v\),\(r_u\) 移动至 \(r_v\)。否则直接删去 \(l_u\sim r_u\),加入 \(l_v\sim r_v\)。可以证明从序列头移动至序列尾的代价为 \(\mathcal{O}(n\log n)\),那么带权莫队即可,相当于在一个长为 \(n\log n\) 的序列上进行 \(q\) 次 “区间” 询问。时间复杂度 \(\mathcal{O}(n\sqrt n\log n)\)。
因为常数较小,所以跑得很快。代码。
1770. Good Bye 2022
A. Koxia and Whiteboards
每次选最小的改成 \(b_j\) 显然不劣。
B. Koxia and Permutation
注意是最小化 \(c\) 的最大值。
\(k = 1\) 是平凡的,而 \(k > 1\) 时最大值至少为 \(n + 1\),构造 \(n, 1, n - 1, 2, \cdots\) 即可。
*C. Koxia and Number Theory
好题。
首先若 \(a\) 并非两两不同则无解。
思考数据规模较小的情形,发现两奇两偶无解。研究其本质后推广至一般结论:若存在 \(p\) 使得对每个 \(0\leq r < p\),模 \(p\) 余 \(r\) 的 \(a_i\) 的数量均不小于 \(2\),则无解,因为 \(x\) 模 \(p\) 不能为 \(0\sim p - 1\),这样的 \(x\) 不存在。
否则,对每个质数 \(p\),找到使得模 \(p\) 余 \(r\) 的 \(a_i\) 的数量小于 \(2\) 的 \(r\),则可令 \(x\equiv r\pmod p\),中国剩余定理保证满足同余方程组的 \(x\) 存在。
根据抽屉原理,只需检查所有小于 \(n\) 的质数即可。如果不想筛素数,也可检查所有数。时间复杂度 \(\mathcal{O}(\frac {n ^ 2} {\log n})\) 或 \(\mathcal{O}(n ^ 2)\)。代码。
D. Koxia and Game
易知 \(c\) 合法的充要条件为每个可重集的绝对众数存在且这些众数形成 \(1\sim n\) 的排列。
因此,如果一个数在序列 \(a, b\) 中总共只出现了一次,那么对应的 \(c_i\) 必须为该数。
在 \((a_i, b_i)\) 之间连边,可知合法的充要条件是基环树森林。
- 
一个非自环产生 \(2\) 的贡献,因为任意确定环上某条边填 \(a_i\) 或 \(b_i\) 之后整个环的形态就确定了。
 - 
一个自环产生 \(n\) 的贡献。
 
时间复杂度 \(\mathcal{O}(n\log n)\) 或 \(\mathcal{O}(n)\)。代码。
E. Koxia and Tree
根据期望的线性性,将答案摊到每条边上。
确定 \((u, v)\) 方向时,最多一只蝴蝶在两棵子树之间移动。记录 \(p_u\) 表示节点 \(u\) 有蝴蝶的概率,则 \(u\) 的蝴蝶移动至 \(v\) 处的概率为 \(P_u = \frac 1 2 p_u(1 - p_v)\)。设两棵子树在一开始包含的蝴蝶数量分别为 \(s_u, s_v\),则该边对答案的贡献为
\(p\) 的更新是平凡的。
最后将答案除以 \(\frac {k (k - 1)} 2\) 即可。时间复杂度 \(\mathcal{O}(n)\)。代码。
*F. Koxia and Sequence
这题,太牛逼了。
- 第一步,根据对称性,\(a_i = t\) 的序列数量相等,所以 \(n\) 为偶数时答案为 \(0\),\(n\) 为奇数时答案为所有 \(a_1\) 的异或和。
 - 第二步,拆位,对每个 \(i\) 计算 \(a_1\) 第 \(i\) 位为 \(1\) 的方案数。这一步比较平凡。以下将 \(a_1\) 减去 \(2 ^ i\)。
 
接下来有两个方向:
一是继续把每一位的贡献拆开来,这样比较容易满足按位或为 \(y\) 的限制,但不容易满足总和为 \(x\) 的限制。
二是直接考虑 \(\sum a_i = x\),但不容易满足按位或为 \(y\) 的限制。
对第一个方向进行每一位的贡献系数不大于 \(n\) 的容斥,组合数上指标出现了 \(n\)。尽管我们只关心组合数奇偶性,即 \(\binom n m\bmod 2 = [m\subseteq n]\),但是 \(n\) 非常大,依然困难。这也是我比赛时的思路,最后没做出来。
- 
第三步,容斥,设 \(f(y)\) 表示按位或为 \(y\) 的子集的方案数,则按位或恰为 \(y\) 的方案数为 \(\sum\limits_{y'\subseteq y} (-1) ^ {|y| - |y'|} f(y')\)。因为只关心奇偶性,故可进一步写为 \(\bigoplus\limits_{y'\subseteq y} f(y')\)。接下来着眼于每个 \(y'\)。
 - 
第四步,也是最牛逼的一步,即逆用组合数奇偶性公式,你不是要 \([a_i\subseteq y']\) 嘛,我直接写成 \(\binom {y'} {a_i} \bmod 2\)。
 - 
第五步,根据范德蒙德卷积化简公式:
\[\begin{aligned} \mathrm{ans} & = \bigoplus\limits_{\sum a_i = x - 2 ^ i} [a_1\subseteq (y' - 2 ^ i)] [a_2\subseteq y'] \cdots [a_n\subseteq y'] \\ & = \left(\sum\limits_{\sum a_i = x - 2 ^ i} \binom {y' - 2 ^ i} {a_1} \binom {y'} {a_2} \cdots \binom {y'} {a_n}\right)\bmod 2 \\ & = \binom {ny' - 2 ^ i} {x - 2 ^ i}\bmod 2 \\ & = [(x - 2 ^ i) \subseteq (ny' - 2 ^ i)] \end{aligned} \] 
对每个 \(i\) 和 \(y'\),可以 \(\mathcal{O}(1)\) 计算对应方案数奇偶性。时间复杂度 \(\mathcal{O}(y\log y)\)。代码。
1771. Codeforces Round #837 (Div. 2)
这场 Div. 2 的题太烂啦!
A. Hossam and Combinatorics
若所有数相同,答案为 \(n(n - 1)\),否则答案为最小值数量乘以最大值数量乘以 \(2\)。
B. Hossam and Friends
设 \(lim_i\) 表示最小的 \(j\) 使得 \(i < j\) 且 \(i, j\) 不是朋友,则 \([a, b]\) 合法当且仅当 \(\min_{i = a} ^ b lim_i > b\)。显然具有单调性,双指针维护即可。维护最小值可以单调队列或 set。
时间复杂度 \(\mathcal{O}(n)\) 或 \(\mathcal{O}(n\log n)\)。代码。
C. Hossam and Trainees
直接分解质因数即可,时间复杂度 \(\mathcal{O}(n\pi(a_i))\)。代码。
Pollard-Rho 可以做到 \(\mathcal{O}(n\sqrt[4]{a_i})\)。
D. Hossam and (sub-)palindromic tree
设 \(f(u, v)\) 表示 \(G(u, v)\) 的最长回文子序列。按 \(dis(u, v)\) 从小到大 DP 即可。
时间复杂度 \(\mathcal{O}(n ^ 2)\)。代码。
E. Hossam and a Letter
分成 m 在中间和 m 在两侧讨论。枚举竖线的两列,两种情况均可直接双指针维护。
时间复杂度 \(\mathcal{O}(nm ^ 2)\)。代码。
F. Hossam and Range Minimum Query
XOR-Hash 套上线段树二分即可。注意强制在线,所以需要主席树。
时间复杂度 \(\mathcal{O}((n + q)\log n)\)。代码。
1773. 2022-2023 ICPC, NERC, Northern Eurasia Onsite
*A. Amazing Trick
记号:\(p\circ a\) 表示 \(p\) 作用于 \(a\),即 \(a_i\to a_{p_i}\):将序列 \(a\) 位置为 \(i\) 上的数移动至位置 \(p_i\)。
问题等价于构造两个错排 \(p, q\),使得 \(q\circ p \circ a = \epsilon\),其中 \(\epsilon_i = i\)。
随机法:
直接随机打乱 \(\epsilon\) 有 \(\frac 1 e\) 的概率得到错排 \(p\)。而因为 \(p\) 随机,所以 \(p\circ a\) 也有 \(\frac 1 e\) 的概率为错排,使得 \(q\) 为错排。注意这个分析并不严谨,因为 \(p\) 并非在所有排列里随机,而是只在错排中随机,但是 \(p\circ a\) 为错排的概率不会很低。随机 \(10 ^ 3\) 次已经足够,代码。
构造法:
首先 \(n = 1\) 显然无解。
将排列视为若干置换环。从 \(a_i\) 向 \(i\) 连边,则需要找到错排(环长大于 \(1\))\(p\) 使得不存在边 \(i\to p_i\),因为边 \(i\to p_i\) 使得 \(a_{p_i} = i\)。
注意到对于二元环 \((i, j)\)(\(a_i = j\) 且 \(a_j = i\)),\(i, j\) 要么不在 \(p\) 的相同环,要么在相同环上不相邻。
当不存在二元环时,用一个大环将所有环串起来。
当存在至少两个二元环时,用一个环把所有二元环的一个点和其它所有不在二元环上的点串起来,用另一个环把所有二元环的另一个点串起来。
当恰存在一个二元环时,若 \(n < 4\) 显然无解,否则可以类似构造出两个环,使得环上的点数均大于 \(1\)。
时间复杂度 \(\mathcal{O}(n)\),代码。
B. BinCoin
问题等价于给出 \(k\) 组有根树 \(T\) 的优先访问随机儿子的中序遍历 \(A_1, A_2, \cdots, A_k\),要求还原 \(T\)。
考虑定根。如果 \(u\) 为根,则 \(u\) 在任意 \(A_i\) 中不为两端,且两侧集合分别为其两棵子树的所有节点。因此,\(u\) 满足如下性质:
- 对于任意 \(A_i\),\(u\) 不在其两端。
 - 对于任意 \(A_i\),设 \(u\) 两侧集合分别为 \(L_i, R_i\),则对于任意 \(1\leq i, j\leq k\),要么 \((L_i, R_i) = (L_j, R_j)\),要么 \((L_i, R_i) = (R_j, L_j)\)。实际上我们只需用到 \(|\bigcup_{i = 1} ^ k \{L_i, R_i\}| = 2\)。
 
因为数据随机,所以其它点极大概率不同时满足这些性质。
定根后递归进入子问题。总共 \(\mathcal{O}(n)\) 次定根,\(\mathcal{O}(n ^ 2)\) 次检查。单次检查的复杂度为 \(\mathcal{O}(nk)\),无法接受。两种方法:
- 预处理后快速求出 \(L_i, R_i\) 的 XOR-Hash。
 - 先判是否有 \(|\bigcup_{i = 1} ^ k \{|L_i|, |R_i|\}| = 2\),若是则进一步检查。
 
时间复杂度 \(\mathcal{O}(n ^ 2k)\)。代码。
*D. Dominoes
判定多米诺骨牌是否可以密铺整个网格:黑白染色,一个多米诺骨牌代表一条边,可密铺的充要条件为二分图存在完美匹配。
对于一个连通块,若黑白格数量相差超过 \(2\) 或为奇数,删去任意两格均无解。否则若相差 \(2\),则必须删去两个较多颜色的格子。否则相等,必须删去两个不同颜色的格子。因此,删去两格有解的方案数不超过 \(\frac {n ^ 2} 4\)。
因为答案只要和 \(10 ^ 6\) 取较小值,所以若空地数量 \(N > 2000\) 则答案一定为 \(10 ^ 6\)。
若 \(N\) 为奇数,无论怎么删都无解。否则,枚举删去的格子之一,求出二分图匹配,若匹配大小小于 \(\frac N 2 - 1\),无论怎么删都无解。否则,若删去后有解,不妨设左部图较大,则另一个格子为匹配的非必经左部点。
求匹配必经点是经典问题:从每个左部非匹配点出发,遍历它的所有右部匹配点邻居对应的左部匹配点,则所有被遍历到的左部匹配点均为非必经点,因为从它们开始存在交错路径使得终点为非匹配点,将匹配边换成路径下一条边即可。
时间复杂度 \(\mathcal{O}(N ^ {2.5})\)。代码。
对原图跑一遍最大匹配。若最大匹配为 \(\frac N 2\),那么求出删去每个点之后大小为 \(\frac N 2 - 1\) 的匹配是平凡的。若最大匹配为 \(\frac N 2 - 1\),那么求出删去某左部点之后大小为 \(\frac N 2 - 1\) 的匹配,若该点为非匹配点则平凡,否则只需从该点找到一条以左部非匹配点结尾的交错路。这样可避免每次重新跑最大匹配。时间复杂度 \(\mathcal{O}(N ^ 2)\)。
E. Easy Assembly
将塔视为序列,分裂操作等价于将一个序列切成两半,合并操作等价于将两个序列相接。
考虑初始序列及其相邻两个数 \(x, y\),如果 \(x\) 在最终序列的后继不是 \(y\),则 \(x, y\) 之间需要用至少一次分裂操作分开。
通过执行上述必需的分裂操作,我们得到一些序列,它们是最终序列的极长连续段。设至少分裂 \(c\) 次,则得到 \(n + c\) 个序列。对它们执行 \(n + c - 1\) 次合并操作即可达到目标。
如何检查 \(x\) 在最终序列的后继是否为 \(y\):将所有数离散化。设 \(x, y\) 离散化后得到 \(x', y'\),则充要条件为 \(x' + 1 = y'\)。
- 另一种自然地分析合并次数的方向:考虑最终序列及其相邻两个数 \(x, y\),如果 \(x\) 在初始序列的后继不是 \(y\),则 \(x, y\) 之间需要用至少一次合并操作连接。
 
设 \(m = \sum k_i\),则时间复杂度为 \(\mathcal{O}(m\log m)\)。代码。
F. Football
签到题。
在总和的限制下我们可能不得不让一些比赛打成 \(0 : 0\),因此为了让平局数尽可能少,选择 \(1 : 0\) 和 \(0 : 1\) 是最优的。
当 \(n = 1\) 时,比分只能为 \(a : b\)。
当 \(n > 1\) 时,总能安排 \(A = \min (n - 1, a)\) 场 \(x : 0(x > 0)\) 和 \(B = \min(b, n - A)\) 场 \(0 : y(y > 0)\),因为 \(1\leq A\leq a\) 且 \(1\leq B \leq b\)。当 \(C = n - A - B > 0\) 时,剩下来 \(C\) 场只能打成 \(0 : 0\)。
注意当 \(b = 0\) 时,\(a\) 不需要给 \(b\) 留一场,此时 \(A = \min(n, a)\)。
时间复杂度 \(\mathcal{O}(n)\),代码。
*G. Game of Questions
随着游戏进行,留在场上的人会越来越少,这提供了自然的 DP 转移方向:枚举子集。
设 \(f_S\) 表示任意时刻恰有集合 \(S\) 的人留在场上的概率。对于每道题目 \(s_i\),假设它可以第二次被抽到,我们发现它不产生任何影响。因此,转移时,求出 \(c\) 表示使得 \(S\) 改变的题目数量,即所有使得 \(s_i\cap S\neq \varnothing, S\) 的 \(s_i\),则这些题目在变成 \(S\) 之前一定没有被抽到过,否则剩下的人就不是 \(S\) 了。
若 \(c = 0\),则 \(f_S\) 表示最终结果有 \(f_S\) 的概率是 \(S\)。否则 \(S\) 一定会变得更小:枚举第一个使得 \(S\) 减小的 \(s_j\),因为它在所有 \(s_i\) 中第一次出现的概率为 \(\frac 1 c\),所以 \(\frac {f_S} {c}\to f_{S\cap S_i}\)。
注意 \(s_j\) 是没有 \(S\) 的子集限制的,所以时间复杂度为 \(\mathcal{O}(4 ^ n)\),无法接受。
设 \(g_{S, T}\) 表示使得 \(s_i\cap S = T\) 的 \(s_i\) 的数量,则有转移 \(g_{S, T} = g_{S \cup \{p\}, T} + g_{S\cup \{p\}, T\cup \{p\}}\),其中 \(p\) 是任意不在 \(S\) 中的元素。在 \(\mathcal{O}(3 ^ n)\) 的时间内求出所有 \(g_{S, T}\)。
易知 \(c = \sum_{T\neq \varnothing, S} g_{S, T}\),转移时直接枚举 \(T\neq \varnothing, S\),则 \(\frac {f_S g_{S, T}} {c}\to f_T\)。
综上,时空复杂度均为 \(\mathcal{O}(3 ^ n)\)。代码。
*H. Hot and Cold
考虑信息的本质。
设上一次询问 \((ax, ay)\),本次询问 \((x, y)\),它们连线段的垂直平分线为 \(l\)。若返回 Closer,则答案在 \(l\) 包含 \((x, y)\) 一侧的半平面内。若返回 Further,则答案在 \(l\) 包含 \((ax, ay)\) 一侧的半平面内。若返回 At the same distance,则答案在 \(l\) 上。
我们肯定要尽快确定 Closer 和 Further 的短语 \(c, f\)。可以想到询问 \((0, 0)\) 后再询问 \((1, 1)\),则当且仅当答案为 \((1, 0)\) 和 \((0, 1)\) 时 \(c\) 不为返回值,可以直接枚举。接下来询问 \((1, 1)\) 后再询问 \((0, 0)\),得到返回值为 \(f\)。我们用了 \(6\) 次询问得到 \(c, f\)。实际上可以更优,但已经足够了:询问 \((0, 0)\),询问 \((1, 1)\),返回值作为 \(c\),询问 \((0, 0)\),返回值作为 \(f\)。若 \(c = f\) 说明答案为 \((0, 1)\) 或 \((1, 0)\)。这样只需要 \(3\) 次询问。
考虑二分横坐标 \(x\)。
设上一次询问 \((l, 0)\),本次询问 \((r, 0)\)。若返回 \(c\),说明 \(2x > l + r\)。若返回 \(f\),说明 \(2x < l + r\)。否则,\(2x = l + r\)。这样,我们可以用两次询问确定 \(x\) 在 \(\frac {l + r} 2\) 左侧还是右侧。
加上纵坐标,总询问次数为 \(4\lceil\log_2 V\rceil\),无法接受。但注意到我们的第一次询问总没有产生任何信息,很浪费,能不能利用起来呢?
设上一次询问 \((p, 0)\),当前区间为 \([l, r]\)。注意 \(p\) 不一定等于 \(l, r\)。设 \(m = \lfloor\frac {l + r} 2\rfloor\),则询问 \((2m - p, 0)\) 即可直接确定。问题在于 \(2m - p\) 不一定符合 \([0, 10 ^ 6]\) 的限制,且 \(p\) 可能等于 \(m\)。没关系,我们只需令 \(p = m - 1\) 或 \(m + 1\) 先询问一次即可。这样的情况发生的次数很少,大部分时候 \(p\) 在 \(m\) 附近震荡,读者可以想象一下。感性理解当坐标靠近边界时询问次数会稍微多一点,但依然可以接受。代码。
官方正解应该是将横坐标和纵坐标放在一起二分,这样只需要 \(3\lceil\log_2 V\rceil\) 次询问。
*I. Interactive Factorial Guessing
一个想法是二分找到第一个非零位置,但这并不可行,因为非零位置不满足可二分性。
我们发现,如果找到一个非零的位置 \(p\),通过它的邻域信息,我们可以直接确定 \(n\)。因此,如果问到一个非零位置,我们可以几乎认为猜中了 \(n\)。
第 \(i\) 次询问在当前范围 \(R_i\) 下非零值最多的位 \(p_i\),然后将第 \(p_i\) 位非零的所有数从范围中删去,进行下一轮猜测。我们发现询问 \(10\) 后恰剩余一个数,即 \(|R_{11}| = 1\)。初始 \(R_1 = [1, 5982]\)。
还有一个问题,就是第一次得到非零信息后,我们只剩下 \(10 - i\) 次询问机会。但由于当 \(i\) 较大时 \(R_i\) 较小,所以依然可以确定所有 \(n\in [1, 5982]\)。
代码。
*J. Jumbled Trees
将生成树视为长度为 \(m\) 的列向量,第 \(i\) 个数表示第 \(i\) 条边是否在生成树内。生成树数量很大,但我们只要 \(m\) 棵线性无关的生成树。或者说,求出所有生成树的 “基生成树”。
这似乎很困难,我们猜一些结论:找出任意生成树 \(T\),考虑将一条树边替换为一条非树边形成的生成树 \(T'\)。所有 \(T'\) 的列向量组 \(B\) 和所有生成树的列向量组 \(A\) 列等价。
这个结论很离谱,我不太了解它的本质。
证明:\(T' - T\) 得到一个恰有一个 \(1\) 和 \(-1\),其它位置均为 \(0\) 的向量。它表示 边的替换。在两条边之间相连,表示它们可相互替换,则一条边可以替换为其连通块内任意边。
- 因为 \(B\) 是 \(A\) 的子集,所以 \(B\) 能组合出的列向量,\(A\) 同样能组合出。
 - 考虑形成 \(T'\) 和边的替换的过程,可以看出 同简单环内的边可相互替换,进一步推出 同点双内的边可相互替换。将原图点双缩点,则对于任意生成树 \(U\),它相对于 \(T\) 只改变了每个点双内部的生成树形态。这说明 \(U\) 一定可以由 \(T\) 替换得到,所以 \(B\) 的每个列向量能被 \(A\) 组合出,进而证明 \(A\) 能组合出的列向量,\(B\) 同样能组合出。
 
综上,\(A, B\) 列等价。
这样,我们得到 \(m ^ 2\) 个生成树,还不够优秀。但注意到若 \(T' - T\) 的替换关系成环,删去环上任意一条边均保留所有替换关系。用并查集维护是否成环即可。具体地,对于每条非树边 \(e_i\) 和其两端之间的所有树边 \(e_j\),若 \((i, j)\) 在 “替换图” 上不连通,则将 \(e_j\) 替换为 \(e_i\) 加入 \(B\),并在替换图上连接 \((i, j)\)。
这样,我们得到至多 \(m - 1\) 棵生成树。加上 \(T\) 本身,共有不超过 \(m\) 棵生成树。高斯消元的复杂度为 \(\mathcal{O}(m ^ 3)\),使用取模优化后可以通过。代码。
实际上,从替换关系的角度考虑,我们可以对列使用主元法,即 \(I_1x_1 + I_2x_2 = J\) 写成 \(I_1(x_1 + x_2) + (I_2 - I_1) x_2\),做到 \(\mathcal{O}(m)\) 求解方程。但构造方案使得复杂度下界为 \(\mathcal{O}(nm)\)。
*K. King's Puzzle
首先特判掉 \(n = 1\) 的特殊情况。
\(n > 1\) 时,每个点的度数在 \(1\sim n - 1\) 之间,因此若 \(k = n\) 则无解。
当 \(k = 1\) 时,要求所有点的度数相同,将 \(n\) 个点连成一个环即可。注意特判 \(n = 2\) 且 \(k = 1\) 的情况。
否则,我们考虑这样构造:
首先,为保证图连通,将 \(n\) 和 \(1\sim n\) 相连。此时 \(a_1\sim a_{n - 1} = 1\),且 \(a_n = n\)。
维护 \([l, r]\) 表示当前度数相同的连续段,\(a_l\sim a_r = l\),且 \(a_i = i(1\leq i < l)\),\(a_i(r < i\leq n) = i - 1\),初始值 \(l = 1\),\(r = n - 1\)。设 \(c\) 表示当前度数集合大小。时刻保证 \(l < r\),可知 \(c = l + (n - r)\)。重复以下操作直到 \(c = k\):
- 若 \(c + 1 = k\),则加边 \((l, r)\),并直接退出。原本 \(l\sim r\) 度数相同,现在 \(a_l = a_r = a_i + 1(l < i < r)\)。
 - 否则,将 \(r\) 和 \(l + 1\sim r - 1\) 相连,并令 \(l\gets l + 1\),\(r\gets r + 1\)。原本 \(l\sim r\) 度数相同,现在 \(a_l + 1 = a_i(l < i < r)\) 且 \(a_r = r - 1\),\(c\) 增加了 \(2\)。
 
时间复杂度 \(\mathcal{O}(nk)\)。代码。
1774. Polynomial Round 2022 (Div. 1 + Div. 2)
Performance 3084.
A. Add Plus Minus Sign
如果下一个是 \(0\),随便添加什么。
如果下一个是 \(1\),则当前结果为 \(0\) 时添加加号,否则添加负号。
代码。
B. Coloring
检查第 \(i\) 大的数是否不大于 \(\lfloor \frac n k\rfloor + [i \leq (n\bmod k)]\) 即可。
代码。
*C. Ice and Fire
观察样例可知答案为 \(i\) 减去以 \(s_i\) 结尾的最长的相同字符段的长度。证明也是容易的。
代码。
D. Same Count One
如果 \(1\) 的数量总和不是 \(n\) 的倍数,显然无解。
否则,在 \(0\) 的个数较少的序列和 \(0\) 的个数较大的序列之间交换一些列,贪心配对即可。
时间复杂度 \(\mathcal{O}(nm)\),代码。
*E. Two Chess Pieces
如果第一颗棋子要经过 \(i\),相当于第二颗棋子要经过 \(i\) 的 \(d\) 级祖先。用 DP 实现该过程,设 \(d_i\) 表示 \(i\) 子树内距离 \(i\) 最远的第二颗棋子必须经过的位置与 \(i\) 的距离,对于第二颗棋子的 \(d\) 级祖先也是类似。答案即第一颗棋子必须经过的位置的虚树大小的两倍,加上第二颗棋子必须经过的位置的虚树大小的两倍。
时间复杂度 \(\mathcal{O}(n)\),代码。
*F1. Magician and Pigs (Easy Version)
关于 F1,有一个依赖 \(x\leq 2\times 10 ^ 5\) 的势能分析的做法:从后往前暴力模拟,操作 \(2\) 的次数不超过 \(2\times 10 ^ 5\)。遇到一个操作 \(3\) ,我们暴力递归两次。遇到一个操作 \(2\) ,将当前值加上 \(x_i\)。遇到一个操作 \(1\) ,如果 \(x_i\) 大于当前值,则将答案加上 \(1\)。注意要对一段连续的操作 \(1\) 批量处理,否则遇到的操作 \(1\) 就无法用操作 \(2\) 的次数限制,也就是求出一段区间内大于某值的数的个数,主席树维护。
交上去发现 TLE,为什么呢?这是因为在一开始没有操作 \(2\) 的极长段,我们会花费大量时间模拟,但没有使得当前值增大。预处理一开始没有操作 \(2\) 的极长段,求出每个操作 \(1\) 的 \(x_i\) 被复制了多少次,加到权值线段树里面,即可在递归到该段时 \(\mathcal{O}(\log x)\) 求出贡献。
这样,执行操作 \(3\) 的次数关于执行操作 \(2\) 和 \(n\) 线性:想象一个二叉树,底层是操作 \(2\) ,其它节点是操作 \(3\),而非叶子节点数关于叶子节点树线性。又因为每次执行一段操作 \(1\) 之前必然执行过操作 \(2\) 或操作 \(3\),所以操作 \(1\) 的次数也是线性。
总复杂度 \(\mathcal{O}((n + x)\log x)\)。代码。
*F2. Magician and Pigs (Hard Version)
直接模拟整个过程不太可行,考虑直接对每次操作 \(1\),算出它会被复制多少次。
仍然是从后往前逆推,算出第一次遇到操作 \(1\) 时已经减去的值 \(s\)。若 \(s\geq x_i\),显然它不会产生贡献。否则,考虑它之后的所有操作 \(3\):\(p_0, p_1, \cdots, p_{k - 1}\)。
预处理 \(c_i\) 表示位置 \(i\) 的操作 \(3\) 复制一次会使得血量多减去的数值。考虑求出该操作 \(1\) 在复制第 \(a\) 次的时候减去的值 \(s_a\),若 \(s_a \geq x_i\),说明复制次数小于 \(a\),否则复制次数不小于 \(a\)。
求 \(s_a\)。如果 \(a\) 的第 \(p_i\) 位为 \(1\),则在 \(p_i\) 处进入复制前的分支,\(s_a\) 增加整个复制后的分支让会血量减去的值,即 \(c_{p_i}\)。因此,\(s_a = s + \sum_{a_d = 1} c_{p_d}\),可以 \(\mathcal{O}(\log a)\) 计算。
问题在于 \(a\) 可能很大,因为 \(c\) 的一段前缀可以等于 \(0\),但一旦遇到操作 \(2\),\(c\) 变成非零,\(c\) 就会以指数级增长,使得 \(a\leq x\)。特判掉等于 \(0\) 的前缀即可,等价于特殊处理一开始没有操作 \(2\) 的极长段。
时间复杂度 \(\mathcal{O}(n\log ^ 2x)\),代码。将二分换成从高位到低位贪心即可做到 \(\mathcal{O}(n\log x)\),代码。
*G. Segment Covering
非常好的题目!
不在区间上挖一些性质是很难做的,而区间最常见且最有用的一个性质就是 不包含。
考虑两个区间 \([x', y']\subset [x, y]\),则对于任意包含 \([x, y]\) 的方案,是否选择 \([x', y']\) 对答案没有影响,总贡献一正一负抵消掉了,相当于钦定不包含 \([x, y]\),即将其删去。最终区间互不包含,满足 \(x_i\) 递增且 \(y_i\) 递增。
注意是删去较大的区间而不是删去较小的区间,这保证了对于任意区间 \([l, r]\),对所有包含于 \([l, r]\) 的区间做上述操作等价于对所有区间做上述操作后包含于 \([l, r]\) 的区间。
现在考虑一次询问以及所有相关区间 \(I_1, I_2, \cdots, I_k\)。设 \(f_i\) 表示选择 \(I_i\) 覆盖 \([x_1, y_i]\) 的区间数为偶数的方案数减去区间数为奇数的方案数,则 \(f_i = -\sum_{j = 1} ^ {i - 1} f_j [x_i\leq y_j]\)。
分析:
\(f_1\) 显然为 \(-1\)。
如果 \(y_1 < x_2\),则 \(f_2 = 0\),且根据端点单调的性质,接下来所有 \(f\) 也等于 \(0\)。否则 \(f_2 = 1\)。
接下来,对于所有 \(x_i\leq y_1\) 的 \(i\),其 \(f_i\) 等于 \(\sum_{j = 1} ^ {i - 1} f_j = 0\),可以跳到第一个使得 \(y_1 < x_i\) 的 \(i\)。如果 \(y_2 < x_i\),说明 \(f_i = 0\),且接下来所有 \(f\) 也等于 \(0\),否则 \(f_i = -f_2 = -1\)。进入了形式相同但规模更小的子问题。
我们尝试描述上述过程的核心思想,即维护 \((u, v) = (1, 2)\),每次交替令 \(u\gets p_u\) 和 \(v \gets p_v\),其中 \(p_i\) 表示使得 \(y_i < x_j\) 的最小的 \(j\)。任何时刻,若 \(v\gets p_v\) 后出现 \(y_u < x_v\),或 \(u\gets p_u\) 后 \(y_v < x_u\) 则无解。不妨设使得第一次出现无解的情况是 \(y_v < x_u\),则接下来令 \(v\gets p_v\) 将使得 \(v = u\),如下图:

不断执行操作,直到 \(x_{p_u} > r\) 且 \(x_{p_v} > r\)。若 \(u = v\),说明出现了断开的情况,无解。否则,若 \(x_u < r\) 且 \(x_v < r\),说明 \(f_k = 0\)。否则若 \(x_u = r\) 则 \(f_k = -1\),因为 \(u\) 维护了过程中所有 \(f_u = -1\) 的位置。同理,若 \(x_v = r\) 则 \(f_k = 1\)。
加入多组询问,\(i\to p_i\) 连边后树上倍增即可。
注意:
- 若不存在 \(i\) 使得 \(x_i = l\),无解。
 - 若不存在 \(i\) 使得 \(y_i = r\),无解。
 - 注意特判初始情况,\(y_u = r\) 时答案为 \(-1\),\(y_u > r\) 时答案为 \(0\)。
 
时间复杂度 \(\mathcal{O}((n + q)\log n)\)。代码。

                
            
        
浙公网安备 33010602011771号