P9512 [JOI Open 2023] 古代机器 2 / Ancient Machine 2

题目背景

**译自 [JOI Open 2023](https://contests.ioi-jp.org/open-2023/index.html) T1 「[古代の機械 2](https://s3-ap-northeast-1.amazonaws.com/data.cms.ioi-jp.org/open-2023/ancient2/2023-open-ancient2-statement.pdf) / [Ancient Machine 2](https://s3-ap-northeast-1.amazonaws.com/data.cms.ioi-jp.org/open-2023/ancient2/2023-open-ancient2-statement-en.pdf)」** **这是一道交互题。** **在提交本题前请务必仔细阅读以下内容。** 本题只支持 C++ 语言提交(建议使用 C++14,请不要使用 C++14 (GCC9))。 由于洛谷特殊的交互机制,在提交本题时,请去掉代码中的 ```#include "ancient2.h"``` 语句,并将添加以下语句粘贴到代码最开头: ```cpp int Query(int m, std::vector a, std::vector b); ```

题目描述

Bitaro 和 Bibako 是挖掘和调查 JOI 王国废墟的考古学家。在废墟中,Bitaro 发现了一块古老的石板,Bibako 发现了一台古老的机器。 从研究结果中,Bitaro 发现石板上写有一个长为 $N$ 的字符串 $S$。字符串中每个字符要么是 `0`,要么是 `1`。然而,他还不知道字符串 $S$ 中的每个字符是什么。 另一方面,从研究结果中,Bibako 弄清了如何使用机器。为了使用它,我们需要将石板放在机器上,输入一个整数 $m$ 和两个整数序列 $a,b$,然后做一次查询。这里整数 $m$ 和整数序列 $a,b$ 需满足如下条件: - 整数 $m$ 在 $1$ 和 $1\ 002$ 之间(包括两端)。 - 序列 $a$ 和 $b$ 的长度均为 $m$。 - 序列 $a,b$ 中的元素都是 $0$ 和 $m-1$ 之间的整数(包括两端)。 如果我们把石板放在机器上,输入一个整数 $m$ 和两个整数序列 $a,b$,然后做一次查询,机器会按如下方式操作并显示一个整数。 1. 机器对其**内存区域**置 $0$。 2. 机器进行如下的 $N$ 次操作。第 $i+1$ 次($0\le i\le N-1$)操作按如下方式进行。 令 $x$ 表示机器内存区域中当前的整数。机器读取字符 $S_i$。这里,$S_i$ 是字符串 $S$ 中的第 $i$ 个字符(下标从 $0$ 开始)。 - 如果 $S_i$ 是 `0`,机器会将内存区域置为 $a_x$。其中 $a_x$ 是序列 $a$ 中第 $x$ 个元素(下标从 $0$ 开始)。 - 如果 $S_i$ 是 `1`,机器会将内存区域置为 $b_x$。其中 $b_x$ 是序列 $b$ 中第 $x$ 个元素(下标从 $0$ 开始)。 3. 这个机器将展示内存区域中最终置为的整数。 使用这个机器,Bitaro 想要确定石板上写的字符串。然而,因为这个机器十分脆弱,查询的次数不能超过 $1\ 000$。此外,输入机器的整数 $m$ 的最大值需要越小越好。 使用这个机器,写一个程序确定石板上写的字符串。 **【实现细节】** 你需要在程序一开始使用预处理指令 `#include` 引入库 `ancient2.h`。它应当实现如下函数。 - `std::string Solve(int N)` 这个函数在每组测试数据中仅被调用一次。这个函数需要返回和石板上所写的字符串 $S$ 相同的字符串。 - 参数 `N` 表示石板上写的字符串 $S$ 的长度 $N$。 - 这个函数需要返回一个长度为 $N$ 的字符串。如果字符串长度不为 $N$,你的程序会被判为 **Wrong Answer [1]**。 - 返回值中每个字符要么是 `0`,要么是 `1`。如果该条件不满足,你的程序会被判为 **Wrong Answer [2]**。 - 返回值应当与石板上写的字符串 $S$ 相同。如果该条件不满足,你的程序会被判为 **Wrong Answer [3]**。 你的程序可以调用如下函数。 - `int Query(int m, std::vector a, std::vector b)` 使用这个函数,你的程序可以做一次查询。 - 参数 `m` 是输入机器的整数 $m$。 - 参数 `a`,`b` 是输入机器的两个整数序列 $a,b$。 - 返回值是当我们把石板放在机器上,并输入上述整数和序列,做一次查询是机器最后显示的整数。 - 参数 `m` 应当在 $1$ 和 $1\ 002$ 之间(包括两端)。如果该条件不满足,你的程序会被判为 **Wrong Answer [4]**。 - 序列 `a` 和 `b` 的长度均应等于 $m$。如果该条件不满足,你的程序会被判为 **Wrong Answer [5]**。 - 序列 `a` 和 `b` 中元素均应在 $0$ 和 $m-1$ 之间(包括两端)。如果该条件不满足,你的程序会被判为 **Wrong Answer [6]**。 - 函数 `Query` 的调用次数不能超过 $1\ 000$ 次。如果超过 $1\ 000$ 次,你的程序会被判为 **Wrong Answer [7]**。 **【注意事项】** - 你的程序可以实现其它函数供内部使用,或者使用全局变量。 - 你的程序禁止使用标准输入输出。你的程序禁止通过任何方式与其他文件通信。然而,你的程序可以将调试信息输出到标准错误输出。 **【编译和测试运行】** 你可以在「文件」中的「附加文件」下载样例 grader 来测试你的程序。「附加文件」中也包含一份你的程序的样例源程序。 样例交互器是文件 `grader.cpp`。为了测试你的程序,你需要将 `grader.cpp`,`ancient2.cpp` 和 `ancient2.h` 三个文件放在同一文件夹下,并且执行如下命令编译你的程序。你也可以运行 `compile.sh` 来编译你的程序。 ```shell g++ -std=gnu++17 -O2 -o grader grader.cpp ancient2.cpp ``` 当编译成功时,会生成一个可执行文件 `grader`。 请注意,实际的交互器和样例不同。样例交互器会作为单进程运行,即它会从标准输入中读取输入数据,并输出结果到标准输出。

输入格式

第一行一个整数 $N$。 第二行一个长为 $N$ 的字符串 $S$。

输出格式

样例交互器会输出如下内容到标准输出。 - 如果你的程序被判为正确,它会输出 `Query` 函数中参数 `m` 的最大值,如 `Accepted: 22`。然而,如果你的程序没有调用 `Query` 函数并被判为正确,它会输出 `Accepted: 0`。 - 如果你的程序被判为任一类的答案错误,样例交互器会输出其类别,如 `Wrong Answer [4]`。 如果程序满足多种答案错误的类别,样例交互器只会输出其中一个。

说明/提示

**【样例解释】** 样例函数调用如下。 | 对 `Solve` 的调用 | 返回值 | 对 `Query` 的调用 | 返回值 | | :---------------: | :--------: | :------------------------------------: | :-----------: | | `Solve(3)` | | | | | | | `Query(4, [3, 3, 2, 2], [2, 2, 1, 0])` | `3` | | | | `Query(2, [0, 1], [1, 0])` | `0` | | | | `Query(1, [0], [0])` | `0` | | | | `Query(3, [1, 1, 1], [1, 1, 1])` | `1` | | | `"110"` | | | 假设写在石板上的字符串 $S$ 是 `110`。如果我们把石板放在机器上,输入 $(m,a,b)=(4,[3,3,2,2],[2,2,1,0])$ 并做一次查询,机器将按如下方式操作。 1. 机器将内存区域置为 $0$。 2. 对于第一次操作,因为 $S_0$ 是 `1`,机器会将内存区域置为 $b_0$,即 $2$。 3. 对于第二次操作,因为 $S_1$ 是 `1`,机器会将内存区域置为 $b_2$,即 $1$。 4. 对于第三次操作,因为 $S_2$ 是 `0`,机器会将内存区域置为 $a_1$,即 $3$。 5. 因为最终内存区域被置为的整数是 $3$,所以机器显示 $3$。 注意这组样例输入不满足限制 $N=1\ 000$。在文件中,`sample-02.txt` 满足这个限制。 **【数据范围】** 对于全部数据,满足: - $N=1\ 000$ - $S$ 是一个长为 $N$ 的字符串 - $S$ 中的每个字符要么是 `0`,要么是 `1` 对于每组数据,实际的交互器 **不是**适应性的。这意味着交互器在开始时答案就已经确定了。 如果你的程序在任意一组数据上被判为任意一种答案错误,在本题你将获得 $0$ 分。 如果你的程序在所有数据上都被判为正确,你的分数由 $M$ 确定,其中 $M$ 是所有数据的 `Query` 函数中参数 `m` 的最大值。然而,如果你的程序没有调用 `Query` 函数并且被判为正确,你的分数由 $M=0$ 确定。 - 如果 $103\le M\le 1\ 002$,你的得分为 $10+\lfloor \frac{(1002-M)^2}{9000}\rfloor$ - 如果 $0\le M\le 102$,你将获得 $100$ 分。 这里 $\lfloor x\rfloor$ 表示不超过 $x$ 的最大整数。