[WC2022] 猜词(民间数据)
题目背景
**滥用本题评测将直接封号。**
**由于评测机环境限制,请勿使用 C++14 (GCC 9) 语言提交本题,否则可能导致编译错误。**
使用了 出题人 发送的官方数据,但是由于存在争议先保留民间数据称号。
60 s, 1 GiB, -O2, 交互
在洛谷提交时请注意以下两点:
- **请去除代码中的 `word.h` 头文件。**
- **不要使用 `rand()` 进行随机。** 请更换为 `mt19937` 。注意不要重名了,不然会 CE。具体请查看[此处](https://www.luogu.com.cn/discuss/405355)。
**这是一道交互题。**
题目描述
在本题中,你需要和交互库玩一款经典的游戏。在每局游戏中,交互库会从词库中生成一个 $5$ 个字母的单词,并告诉你它的首字母,你需要在 $5$ 次机会内猜中它。
每次猜测都需要猜一个词库中存在的单词。如果猜对了,游戏结束;在每次猜错后,交互库会返回哪些字母的位置是正确的(以金色表示),以及哪些字母在待猜单词中出现了但位置是错误的(以银色表示)。
具体来说,交互库会返回两个布尔类型的数组 $\texttt{gold}$ 和 $\texttt{silver}$。`gold[i]`($0 \leq i < 5$,下同)表示第 $i$ 个字母是否猜对了(位置和内容均正确);`silver[i]` 表示如果第 $i$ 个字母没猜对(即不为金色),这个字母是否在本次猜测非金色字母的部分出现过。
例如,待猜单词为 $\texttt{panic}$,猜测 $\texttt{paper}$ 后交互库会返回 `gold[0] = true`($\texttt{p}$ 正确),`gold[1] = true`($\texttt{a}$ 正确),其余均为 `false`(注意 $\texttt{paper}$ 中的第二个 $\texttt{p}$ 虽然在 $\texttt{panic}$ 中出现过,但出现位置为本次猜测中的金色字母部分,因此 `silver[2] = false`)。
又如,待猜单词为 $\texttt{apple}$,猜测 $\texttt{paper}$ 后交互库会返回 `gold[2] = true`($\texttt{p}$ 正确),`silver[0] = true`($\texttt{p}$ 在本次猜测非金色字母的部分出现过),`silver[1] = true`($\texttt{a}$ 出现过),`silver[3] = true`($\texttt{e}$ 出现过),其余均为 `false`。
**【评分方式】**
由于每局游戏具有较高的随机性,在本题中,你需要连续玩 $T = 1000$ 局游戏。每局游戏的评分标准如下:
- 如果任意一次猜测单词的长度不等于 $5$,或者**猜测的单词不在词库中**,得 $0$ 分;
- 如果第 $1$ 次猜测猜对,得 $150$ 分;
- 如果第 $2$ 次猜测猜对,得 $120$ 分;
- 如果第 $3$ 次猜测猜对,得 $100$ 分;
- 如果第 $4$ 次猜测猜对,得 $90$ 分;
- 如果第 $5$ 次猜测猜对,得 $85$ 分;
- 如果 $5$ 次猜测均错,得 $0$ 分。你在本题中的得分为【$1000$ 局游戏的平均分】和 $100$ 分的较小值。
**【如何使用交互库】**
本题只支持 C++。
你只能提交一个源文件 `word.cpp` 实现下列函数,并且遵循下面的命名和接口。
你需要包含头文件 `word.h`。
你不需要,也不应该实现主函数。
你需要实现的函数有:
```cpp
const char *guess(int num_testcase, int remaining_guesses, char initial_letter, bool *gold, bool *silver);
void init(int num_scramble, const char *scramble);
```
其中,第 $i$ 局游戏的 `num_testcase` 参数为 $i$($1 \leq i \leq T$),每局游戏会调用 $1 \sim 5$ 次 `guess` 函数,第 $j$ 次调用的 `remaining_guesses` 参数为 $6-j$($1 \leq j \leq 5$)。`initial_letter` 参数为当前局游戏待猜单词的首字母(保证为小写字母)。保证每次调用 `guess` 函数的 `num_testcase` 单调不降;保证 `num_testcase` 相同时 `initial_letter` 不变且 `remaining_guesses` 单调递降。如果某次猜测猜对或非法,则该局游戏结束,下次调用 `guess` 函数为下一局游戏。
`gold` 和 `silver` 为如上所述的两个布尔数组。当 `remaining_guesses` 参数为 $5$ 时,`gold` 和 `silver` 数组不可用(即,可能为空指针),请避免使用它们;当 `remaining_guesses` 参数小于 $5$ 时,`gold` 和 `silver` 为两个大小为 $5$ 的布尔数组,存储着上一次猜测的结果。
`guess` 函数的返回值需要是一个长度为 $5$ 的字符串,表示猜测的单词。该单词需要在词库中。
`init` 函数会在调用所有 `guess` 函数之前调用恰好一次。其中 `num_scramble` 参数是词库大小,`scramble` 是一个长度为 $\texttt{num\_scramble} \times 5$ 的字符串,存储着词库中的所有单词,每个单词长度为 $5$,中间没有任何分隔符。
**【附加文件】**
本题下发的文件有 `word.h, word_sample.cpp, play.cpp, grader.cpp, scramble.txt, scramble.csv, scramble_pure.txt`。
`word_sample.cpp` 是你要实现的 `word.cpp` 的一个样例。
`grader.cpp` 为示例评测程序(编译命令:`g++ ‐o grader grader.cpp word.cpp`)。
`scramble.txt, scramble.csv, scramble_pure.txt` 均为本题所使用的词库文件,其中 `scramble.txt` 以换行符分隔单词,`scramble.csv` 以逗号分隔单词,`scramble_pure.txt` 不分隔单词(即,与 `init` 函数中的 `scramble` 参数内容相同)。
`play.cpp` 是一个可以让你和你的程序玩这个游戏的程序(编译命令:`g++ ‐o play play.cpp word.cpp`)。下面介绍 `play.cpp` 的输入与输出格式。
输入输出格式
输入格式
**【样例输入格式】**
输入第一行包含一个正整数 $T$,表示游戏局数。
接下来 $T$ 局游戏,每局游戏第一行输入一个小写字母,表示待猜单词的首字母。
接下来 $0 \sim 4$ 行,每行一个长度为 $5$ 的由 $\texttt{g}$、$\texttt{s}$、$\texttt{-}$ 组成的字符串,其中第 $i$ 位($0 \leq i < 5$,下同)是 $\texttt{g}$ 表示 `gold[i] = true`,第 $i$ 位是 $\texttt{s}$ 表示 `silver[i] = true`,第 $i$ 位是 $\texttt{-}$ 表示 `gold[i] = silver[i] = false`。如果猜对或猜测单词非法,则该局游戏结束,因此输入的行数是可变的。
输出格式
**【样例输出格式】**
对于除了第一行游戏局数以外的每行输入,输出一个长度为 $5$ 的字符串,表示猜测的单词。样例输出加入了额外的空行以便阅读。
输入输出样例
输入样例 #1
7
p
gg---
gg---
ggg--
a
g----
ssgs-
a
g---g
gggg-
a
g---g
g---g
g---g
g---g
a
a
c
-sss-
输出样例 #1
paper
paths
panda
panic
aargh
paper
apple
afore
apply
apple
apple
apple
apple
apple
apple
abcde
apple
kraal
cobra
说明
**【样例解释】**
对于第 $1$ 局游戏,待猜单词为 $\texttt{panic}$,在第 $4$ 次猜测猜对。
对于第 $2$ 局游戏,待猜单词为 $\texttt{apple}$,在第 $3$ 次猜测猜对。
对于第 $3$ 局游戏,待猜单词为 $\texttt{apple}$,在第 $3$ 次猜测猜对。注意即使每个位置都有至少一次猜测为金色,也需要额外一次猜测才算猜对。
对于第 $4$ 局游戏,待猜单词为 $\texttt{above}$,$5$ 次猜测均错。注意第 $5$ 次猜测的结果并不需要输入,也不会传入 `guess` 函数。
对于第 $5$ 局游戏,待猜单词为 $\texttt{apple}$,第 $1$ 次猜测非法(不在词库内),该局游戏直接结束。注意样例程序并不会自动识别这种情况。
对于第 $6$ 局游戏,待猜单词为 $\texttt{apple}$,在第 $1$ 次猜测猜对。
对于第 $7$ 局游戏,待猜单词为 $\texttt{cobra}$。注意猜测 $\texttt{kraal}$ 时两个 $\texttt{a}$ 均为银色。注意由于样例程序并不知道待猜单词是什么,需要手动结束程序。
**【数据范围】**
对于 $100\%$ 的数据,$T = 1000$,$\texttt{num\_scramble} = 8869$。每次待猜的单词均在词库中所有单词这一范围内独立均匀随机生成,这些单词在调用 `guess` 函数之前已经完全确定,不会根据和你的程序的交互过程动态构造。交互库本身使用的时间不超过 $1$ 秒,使用的内存不超过 16 MiB。
由于本题只有 $1$ 组评测数据,运行错误、超时、内存超限等错误都会导致本题总分为 $0$ 分。建议仔细检查避免此类错误。