COCI 2021/2022 题解

看了下赛程,大概只能打 Round 1 和 Round 2 了,之后可能就退役了。

Contest #1

打的时候因为有点事,大概只打了一个多小时。现在终于有时间补完了。

题对于知识点完备的选手比较简单。我显然不是这样的选手,做做就当学点东西了。

C、D、E 题代码可以翻 LOJ,其他三题有需要可以联系我。

A - Ljeto

直接模拟即可。

B - Kamenčići

博弈题。\(n\le 350\),比较小,可以考虑一个大概不超过 \(O(n^3)\) 的 dp。

考虑一个状态有三个要素:左右端点和,以及共取了多少个红色石子(只需要记录一个人的,因为另一个以及可以据此确定)。

那么定义:\(f(l, r, c)\) 表示当前操作者面对的局面是,之前以及取过 \(c\) 个红石子,现在剩下了区间 \([l,r]\),是否有必胜策略。

根据必胜必败态定理得到转移:\(f(l, r, c) = \lnot f(l+1,r, c') \lor \lnot f(l,r,c')\)\(c'\) 是计算得到的对方取过的红石子数。

复杂度 \(O(n^3)\)。据说可以分析性质得到 \(O(n^2)\) 解法,可以到 cf 看看。

C - Logičari

第一次写基环树题!做法可能不是最简洁的。

题意简述:对基环树黑白染色,要求每个点相邻恰好一个黑点。求最小可能黑点数。

先转化为正常的树:任意找一条环边 \((a, b)\) 断开,然后钦定一下断开的边两端的四种颜色组合。

不妨设 \(a\) 为根,每个点四个状态,记录自己和父亲的颜色选择。然后做正常的树形 dp。

但是 \(a, b\)​ 两个点需要是特殊处理的。对于 \(a\),可以试做它的父亲为 \(b\)。而对于 \(b\) 需要额外讨论一下……具体细节就不展开了。

复杂度 \(O(n)\)

D - Set

一下所有数字默认减一(\(\{1, 2, 3\}\to \{0, 1, 2\}\))。

我们挖掘一下题目的性质:对于一个位的三个数字 \((a,b,c)\),其所有合法组合对应的数字加起来都是三的倍数,即 \((a+b+c)\bmod 3 = 0\)

考虑到本质不同三元组个数为 \(3^m\)​,设 \(f[i]\) 表示 \(i\) 三进制表示对应的 \(m\) 元组的个数(\(f[i]\in \{0, 1\}\))。

题目要求选取的三个 \(m\) 元组 \(i,j,k\) 的每一位都满足三进制不进位加法(\(\oplus_3\))为 \(0\),那么就是 \(i\oplus_3 j \oplus_3 k = 0\)

考虑卷积,下标用上面的 \(\oplus_3\),那么最后 \(f\) 自己卷自己三次后 \(f'[0]\) 就是答案。可以用 3 进制 FWT 实现。

E - Volontiranje

有一个传统的流做法,但是应该只能跑 subtask 2。

考虑一个基于贪心的神奇结论:在所有备选 LIS 中,抽出一个反转后字典序最小的必然不劣。

首先感性理解比较真,意识流 证一下也不难:考虑有两组 LIS:\(\{i_1,i_2, \cdots,i_k\}, \{j_1,j_2, \cdots,j_k\}\)​​​​​​,那么我们对应项小的换到 \(i\)​​​​​​,大的换到 \(j\)​​​​​​,即用 \(\{\min(i_1, j_1),\min(i_2, j_2), \cdots,\min(i_k, j_k)\}, \{\max(i_1, j_1),\max(i_2, j_2), \cdots,\max(i_k, j_k)\}\)​​​​​​​ 取代之,不难发现其仍然合法。这个方法可以对一个解集在解之间做调整。但是如果最小的那个本身不被该解集包含,则我们可以不要这个解集,而必然存在另一个“可以向小调整”的解集。(看我题解很难没有疑问(草),想要靠谱点的可以看 cf 或翻官方题解)

然后尝试实现。直接一次 \(O(n)\)​​ 扫一组解必然不对,考虑先做一次 dp 跑出每个位置结尾的 LIS,然后按 dp 值将下标分组。显然的,同一组的按位置升序排好之后,其值必然递减。

那么,如果现在需要选 dp 值为 \(i\) 的组中的位置,上一次选了位置 \(x\)。我们先删去在 \(x\)​ 之后的元素:易知这些元素在本次不可用,之后也不会起作用。

删掉一些后,查看最后面的位置 \(y\) ,是否可以接上 \(x\)。如果 \(a_y > a_x\),那么 \(x\) 就没办法用了。需要注意,这不意味着求解结束,而只是将 \(x\) 删去,\(y\) 可能在枚举字典序更大的一组解是被使用。因此使用搜索回溯实现。

每个位置用一次就会被删除,搜索部分复杂度 \(O(n)\)。总复杂度 \(O(n\log n)\)

Contest #2

A - Kaučuk

签到

B - Kutije

首先转化题意,将给定的 \(p_i\) 转化为图上的 \(i\to p_i\) 的有向边。然后每个询问相当于问是否存在 \(u\)\(v\) 的有向路径。

观察到 \(n\le 1000\),我们可以考虑预处理所有的答案。但这张图是稠密图,连做 \(n\) 次 DFS 的复杂度是 \(O(n^3)\)。不过我们发现一次 DFS 每个点之后访问一次,但主要的时间消耗在于找到第一个没有访问过的相邻点。

于是不难想到用 bitset 加速寻找,复杂度 \(O(n^3/w)\)

草,被自己蠢到了。考虑我们的图是根据排列生成的,也就是若干个置换环叠合而成。那么很显然对于一个连通块(将所有边取消方向),一定就是一个强连通分量。

于是直接对每个连通块 DFS 即可,复杂度 \(O(n)\)

C - Hiperkocka

构造垃圾终于瞎搓成功了!

首先为了让结构更清晰,我们将这些边分为 \(n\)​ 层,根据第 \(k\)​ 位不同产生的边放在第 \(k\) 层,每层有 \(2^{n-1}\)​ 条边。

根据直觉,我们想办法让这 \(n\) 条边的树的每一条都用掉一层的一条边,这样恰好每层用 \(2^{n-1}\) 次。

第一棵树是很好构造的,直接从位置 \(0\)​ 开始 DFS,每次 \(O(n)\) 遍历最小未使用的层。然后我们发现如果从 \(1\) 直接开始 DFS 构造第二棵树就可能冲突,不过根据观察,我们要避开的话,最好是从 \(3\)​ 开始。

这时你可能发现了,位置 \(0\)\(3\) 除了上面几层用的边,其余都是对称的。这启发我们倍增地构造一组靠谱的起始点,使得直接在这些位置 DFS 就能出解(并不会证为什么可以这样,这里如果有人会证可以发个评论)。

考虑从 \([0, 4)\to [4, 8)\)​,如果同样用对应的位置 \(4,7\)​ 的话会冲突,而反过来用位置 \(5, 6\)​ 的话则恰好错开,同时 \(5, 6\)​ 构造出的树也是在低层对称的,同 \(0,3\)​ 一样也不会冲突。

那么不妨尝试如下算法:初始区间 \([0,2)\)\(0\)​ 为起始点,然后复制一份,将是否为起始点状态取反,接在后面。

然后对于每个起始点都搜出一棵即可。

D - Magneti

考虑一个确定的 \(n\) 个磁铁的排列,设要使其不互相吸引的最小长度为 \(d\)(即尽量贴近),我们要将其放置在长度为 \(l\) 的槽中,根据插板法不难得到有 \({l-d+n \choose n}\) 种方法。

那么解题的方向就是,对于 \(d=1, 2, \cdots, l\) 分别计算对应的排列方案数,最后乘上组合数系数求和即为答案。官方解法给出了一个漂亮的动态规划方法:

首先将磁铁按磁力半径 \(r\) 升序排序,然后定义 \(dp(i, j, k)\) 表示放置前 \(i\) 个磁铁,分为 \(j\) 组,每组的最小长度之和 \(=k\) 的方案数。这样的好处是利用了升序排序后,只需要考虑当前的磁力范围而不需要考虑之前的摆放。因此新的长度和 \(k'\) 可以很方便的计算,从而实现组之间的操作即,dp 的转移:

  • \(i\) 个磁铁单独成为一个新的组:\(dp(i-1,j,k) \to dp(i,j+1, k+1)\)
  • \(i\) 个磁铁贴在某个组的端点:\(dp(i-1,j,k)\times 2j \to dp(i, j, k+r_i)\)
  • \(i\) 个磁铁连接了两个组:\(dp(i-1,j,k)\times j(j-1) \to dp(i, j-1, k+(2r_i-1))\)

dp 部分复杂度为 \(O(n^2\times l)\)

这里的状态设计的巧妙之处还在于分组思想:(摘自 CF)This idea is usually used when trying to construct permutations with certain properties.

E - Osumnjičeni

草,赛后发现是 sb 题,但是 C 题搞太久了……

考虑答案的计算方法是确定的:对于询问 \([l,r]\),我们从 \(l\) 开始,找到一个最大的 \(i\le r\),满足 \(l\sim i\) 号身高区间全部不交。那么下一次从 \(i+1\) 开始重复操作即可。最后答案就是操作的轮数(可能反过来再做一次)。

第一是预处理右侧最远的合法位置。考虑建立以身高(离散化)为下标的线段树,从 \(1\) 扫到 \(n\)​。每次查询当前身高区间中的最大值,然后在这个区间做区间赋值。最后做一遍后缀最小值。

第二是快速跳转。不难发现这个可以倍增加速。

最后复杂度 \(O(n\log n)\)

posted @ 2021-10-26 19:27  -Wallace-  阅读(1071)  评论(0编辑  收藏  举报