JOISC 2023 题解

First Post:

Last Update:

感觉比 22 年出得阳间一些,D4T1 (通信题) 和 D4T2 (最小内向森林) 不会做,没有这两题的题解。

有些好题会尽量写得详细。

D1T1 两种货币

注意到原图是棵树,那么从 的路径只有一条,用主席树+二分处理路径信息即可。

Submission

D1T2 JOI 国的节日 2

一道较难的好题。

首先明确:

  • 最优策略是按 排序之后贪心选。
  • 最后算答案时,用总数减去 fake 解等于最优解的方案数。

这种将区间作为计数对象的 DP ,一般会尝试设 表示 DP 到第 个位置,前 个位置一共有 个还未闭合的左端点作为状态。下文把这些左端点叫做“接口”。

在这题,我们可以变通一下:设 ,表示 DP 到 第 个位置,设在 之前,最靠右的被选入最优解的区间的右端点,在 以前有 个接口(下文称其为“无用接口”,因为它们不会影响最优解),在 以后有 个接口(下文称其为“有用接口”)。 分别表示:

  • :当前 fake 解没有比最优解少一个区间,但在 fake 策略下无可用接口(即不存在一个接口使得 连向该接口后 fake 解变大)。

  • : 当前 fake 解没有比最优解少一个区间,且在 fake 策略下有可用接口。

  • :当前 fake 解比最优解少一个区间,且在 fake 策略下有可用接口。

我们没有记录 fake 比最优少且无可用接口的情况,因为这种情况不可能转移回 fake 等于最优的情况。

需要指出的是,fake 只可能有 个可用接口,因为如果有的话,必须是 fake 解最靠右的那个区间右边最靠左最左的接口,要不然与 fake 的求解方式相矛盾。

转移分类讨论,即可做到

考虑优化。发现 这一维的存在根本不会影响最优解与 fake 解的情况,只是在转移的时候贡献了一个系数。

所以考虑状态中只记录 ,如果某次转移产生了新的 个无用接口,就直接在后面钦定 个右端点拼上去,转移到 ,系数是

时间复杂度 ,空间需要滚动数组。因为 ,实现时要卡一下 的上下界。

附一张图帮助理解状态:

图中,红线代表 fake 解中最靠右的区间,绿线代表最优解中最靠右的区间,紫色代表 这一维所记录的接口,黄色代表 fake 策略的可用接口,黑色的竖线代表当前 DP 到的位置

图左侧是 fake 比最优解少 的情况,右侧是 fake 解与最优解相等的情况。右侧的黄色接口也被算入 这一维中。

理解状态之后,相信转移分讨起来不是很困难。

Submission

D1T3 护照

考虑如果只要到达 的所有国家怎么做,因为每次可达的点都是一段区间,我们只需能到达 号点即可。问题变为由 中所有点连边,求 的最短路。线段树优化建图即可。

回到原问题,我们可以求出 的最短路,然后令 。这么做有一个问题就是我们会重复计算一些区间,也就是这两条最短路径可能在一开始出现重复部分。

对于边 ,显然有 ,那么我们如果发现 的,就用 来更新 。如此往复,这样就可以保证 的正确性。

如何实现这个操作呢?我们把所有 都丢进一个堆里,每次取出最小的进行松弛即可。这类似一个多源最短路的过程。

Submission

D2T1 传送带

考虑链怎么做。每隔三个点放一个点(这样任意两个产品就不会走到一起了),然后看最后这个点的产品走到哪。每次把已经知道的边的方向调整一下,使其不影响我们对未知边的询问即可。

树的思路也差不多。考虑把点按照 分类,取出点数最多的那一类,每个点放一个产品。这样一次询问之后,放了一个产品的点最少可以确定一条邻边。如果一个点的所有邻边都被确定,我们就将其删去。选择类的时候选出未被删去的点数最多的那一类即可。

每次询问都能至少确定 的边,询问次数上界为

Submission

D2T2 议会

对于一个人 ,如果选他当议长,那么选副议长 的时候,只有那些原来票数就等于 ,且 投了票的议案会从通过变成不通过。那么设 没投票的议案集合为 。选 做议长时,票数等于 的议案集合为 。去掉一些可以快速计算的部分之后,我们只需对每个 算出 即可。

显然上式等价于 。忽略 的限制,只需先做一遍超集和,再做一遍子集和即可。现在要 ,我们只需在统计子集信息时,记录答案最大值、次大值、以及编号与最大值不同的集合中最大的大小即可。

Submission

D2T3 水羊羹 2

首先有一个暴力 DP 的思路,但是这个状态一点也不优美,看上去很难以拓展到原问题。

先发现一个性质:小段长度一定为 。否则可以调整使得不劣。

下文把将一个数作为一个小段称作“选这个数”。

假如我们现在钦定选 ,那下一个选的位置显然要在满足条件的情况下尽量靠前,设其为

表示最大的 满足 ,即 可以同时选。

那么 就是最小的满足 (注意我们这里没写 ,因为如果 ,我们可以把 调整到 的位置,显然也是不劣的,所以 就能取得更小)。

那么我们选小段的过程,就是从 开始向后跳跃, 的过程。

如果不带修的话,可以用个倍增维护跳跃的步数。

如果带修的话,我们需要一个观察:如果 存在,

实际上你考虑 递增的情况就能很容易发现这个性质。

那么单点修改 就只会改变至多 ,且单步跳跃长度也不超过

于是可以写一棵线段树维护跳跃。每个区间记录前 个点在区间内最远跳到的位置和步数即可。

时间复杂度

Submission

D3T1 合唱

首先,我们只关注一个序列能够形成的最少的曲目数,因为一个大曲目可以被拆成若干个小曲目。

经过手玩可以发现,不管曲目如何安排,从左往右第 个 A 一定配上第 个 B。

进一步地说,如果我们要让第 个 A 唱一首歌,那么第 个 B 就要移到这些 A 的后面,设 表示第 个 A 前面有多少个 B,那么对于 ,其就对代价有 的 贡献。

同时可以发现不同曲目之间的代价没有影响,因为一个曲目的移动不会影响后面曲目的

那么设 表示前 个 A 唱了 首歌的最小代价,就有

表示 的最大 ,并将 。设后面这个 。设 的前缀和为 。那么有

证明 函数满足四边形不等式是简单的,拆开之后发现除了 的项都可以消掉。根据 Itst 的博客,可以说明答案关于歌曲数目存在凸性。

那就可以 wqs 二分解决曲目个数的限制,内层 DP 形如 是二分的斜率)。斜率优化 DP 即可。

时间复杂度

好题啊。

D3T2 曲奇