IOI2020 mushrooms 题解

· · 题解

IOI2020 mushrooms 题解

题意

交互题. 给定 n, 有一个长度为 n 的 01 序列 a_0, a_1, \cdots a_{n-1}, 你不知道 a_1, a_2, \cdots a_{n-1} 的值, 但你知道 a_0 = 0.

我们定义一次操作为给定 k(2\leq k\leq n) 和一个长度为 k 的, 不含重复值的序列 b_0, b_1, \cdots b_{k-1}, 然后交互库返回 \sum\limits_{i=0}^{k-2} [b_i \not= b_{i+1}].

你需要通过若干次操作, 求出 \sum\limits_{i=0}^{n-1} (1-b_{i}).

具体细节参见题面.

Note: 你需要 #include "mushrooms.h".

解法

为了方便, 以下我们将不加申明的将 ret 用作上一次 \texttt{query} 操作的返回值, 读者可以根据上下文知道这个 ret 的值.

Method 1

我们考虑朴素暴力: 对所有 i\in [1, n-1] 执行操作 \texttt{query}(\{0, i\}), 这是一个时间复杂度 O(n) 的算法, 可以获得 ... 10 分.

Method 2

我们发现: 如果已知有 k 个 0, 分别是 a_{f_1}, a_{f_2}, \cdots a_{f_k}, 那么可以执行这样的一次操作来求出长度为 k 的序列 g_1, g_2, \cdots g_k 中 0 的个数: \texttt{query}(\{g_1, f_1, g_2, f_2, \cdots g_k, f_k\}). 容易知道 \sum\limits_{i=1}^k g_i = \lceil\frac{ret}{2}\rceil. 有 k 个 1 的情况下同理.

而如何求出 f_1, f_2, \cdots f_k 呢? 显然直接套用 Method 1 即可. 我们使用类似根号分治的思想可以做到 O(\sqrt n) 的复杂度(实际上后续都是常数优化, 并没有超越这个复杂度.)

Optimize 1

我们考察这种操作: \texttt{query}(\{g_1, f_1, g_2, f_2, \cdots g_k, f_k\}). 那么可以根据 ret 的奇偶性判断 g_1 的值, 具体来说, 由于 g_2, g_3, \cdots g_{k} 左右均为相同的值, 故不管这些数如何取值, 均不会影响 ret 的奇偶性, 所以 ret 的奇偶性只由 a_{g_1}, a_{f_1} 决定, 也即可以得出 a_{g_1} 的具体值. 于是我们可以动态的维护当前 0/1 的个数和这些 0/1 的位置然后每次启发式的用 0/1 去询问.

以上优化的代码

Optimize 2

这同时也可以对 Method 1 的过程做出优化: 在有两个相同值的数 a_x, a_y 时, 每次可以通过 \texttt{query\{p, x, q, y\}} 确定 a_p, a_q 的具体值.

Optimize 3

Method 2 的过程已经难以优化, 接下来我们来优化 Method 1 的过程.

不妨考虑我们有充分多的 0 和充分多的 1, 接下来我们考虑如何更优的询问, 具体来说, 我们将用 2 询问次得到 5 个数的具体值.

我们设 p_i 为所有 0 的位置序列, q_i 为所有 1 的位置序列. 即 必有 a_{p_i}=0, a_{q_i}=1.

我们先进行询问 \texttt{query}(\{x, p_1, y, p_2, z, p_3\}). 根据返回值讨论: 首先可以发现根据 ret 的奇偶性确定 a_x, 然后我们令 ret\leftarrow \lfloor\frac{ret}{2}\rfloor, 这样就有 a_{y}+a_{z} = ret. 显然只需要考虑 ret = 1 的情况.

如果 ret = 1, 我们接下来进行询问 \texttt{query}(\{q_1, y, q_2, p_1, z, p_2, u, p_3, v\}), 然后令 ret\leftarrow ret-1(这是因为有相邻的 q_2, p_1).

首先考察 ret 的奇偶性以确定 v, 然后令 ret\leftarrow \lfloor \frac{ret}{2}\rfloor, 这样就有 1-a_y+a_z+a_u = ret, 也即 2a_z+a_u = ret, 这样又可以根据 ret 的奇偶性来确定 a_u, 从而确定 a_za_y.

以上优化的代码

Optimize 4

调整你的参数.

AC 代码