U245150 这是一道送分题 - IO交互
题目背景
是的这是一道送分题。
tsawke 成功 hack 进了 neooj.com:8082/oldoj,但是他只获得了数据库中大量用户密码的 md5 形式,tsawke 需要获取这些用户的明文密码来勒索 llq,但是他不知道如何做,只能帮你进行 md5 的正向过程,靠你来实现 md5 的破解。
为了机房的未来,这道题一定要切呀!
题目描述
我们得到了 llq 网站数据库中 $ n $ 个用户密码的 md5,你需要**一次性**读入这些数据,在这之后你可以进行至多 $ 10^4 $ 次询问,每次询问一个字符串,然后获得这个字符串的 md5,当你询问完成后需要输出一个 ` "Completely Hacked!" `,并在这之后输出着 $ n $ 个用户的明文密码。
Tips:此题时间复杂度可以通过一些优化而去掉一个 $ \log $,但因交互题一般不要求时间复杂度,而是要求函数调用次数或询问次数,所以本题也不会去卡时间复杂度。
Tips:同时这道题也并不是一个优秀的交互题,因为此题并没有去可变地限制函数调用次数,当成练手题即可。
实现过程:
这里我们规定,“**输入**”即为从**标准输入**中获取,“**输出**”即为向**标准输出**中输出,**并刷新缓冲区**。
Tips:这里的**输入**实际上指的是交互库输出的返回值,你进行读入,**输出**即为向交互库传参。
第一行**输入**一个整数 $ n $,代表用户密码个数。
接下来 $ n $ 行每行**输入**一个字符串,表示第 $ i $ 个密码的 md5。
接下来至多 $ 10^4 \times 2 $ 行,对于每两行:
1. 第一行**输出**一个字符串,表示某个密码的明文。
2. 第二行**输入**一个字符串,表示该密码明文对应的 md5。
接下来一行**输出** ` Completely Hacked! `,表示询问结束。
接下来 $ n $ 行每行**输出**一个字符串,表示用户密码的明文。
输入格式
见题目描述-实现过程
输出格式
见题目描述-实现过程
说明/提示
### 数据规模
令明文字符串长度为 $ len $。
对于 $ 50\% $ 的数据,保证 $ 1 \le n \le 100, 1\le len \le 2 $。
对于 $ 100\% $ 的数据,保证 $ 1 \le n \le 10^4, 1 \le len \le 4 $,保证字符串中仅含有数字且不含前导 $ 0 $。
### 评分标准
若你的询问次数超过 $ 10^4 $,则获得 $ 0\texttt{pts} $。
若你的输出不合法,则获得 $ 0\texttt{pts} $。
若你输出的密码明文有任何错误,则 tsawke 将无法成功勒索 llq,获得 $ 0\texttt{pts} $。
若你的输出全部正确,获得 $ 100\texttt{pts} $。
### 关于本地调试
对于 IO 交互题,似乎一般难以进行本地调试,可能也就是因此,NOI 系列比赛都采用的是 grader 交互,这里为了方便各位调试提供了一个头文件。
你可以调用一个叫做 ` md5_hash_hex ` 的函数,其原型是:
```cpp
inline std::string websocketpp::md5::md5_hash_hex(std::string const &)
```
使用方法:在需要生成 md5 的 cpp 文件引入如下头文件:
```cpp
#include "md5.h"
```
调用该函数,并在将明文字符串作文参数传入,将会返回 md5 形式的字符串。
注意在提交的程序中不能使用 md5.h。
**以下是对于交互题的介绍。**
# 关于交互题
## 关于这两道交互题
以下信息均为个人理解,不保证正确性,如果发现不对的地方随时跟我说~
一般来讲交互题大致分为两种,grader 交互和 IO 交互。
grader 交互题大多是给你一个可以调用的函数,并让你实现一个函数。你只需要将提供给你的函数声明出来,并写好需要实现的函数,最终提交这一部分代码即可,而不需要实现 ` main()` 函数。
而对于 IO 交互题,大多会“重载”你的输入与输出,通过 stdout 来向提供的交互库传参,通过 stdin 来获取交互库的返回值,同时需要注意这类题均需要在每次询问后清空缓冲区。
回到本题,因为 T1 不可做,为了保证标准的 $ 400\texttt{pts} $,而我又不想改题号,所以 T3 被分割为了 T3-1 和 T3-2,各自 $ 100\texttt{pts} $,这两道题将会分别使用两种交互方式实现,可以当作对于交互题的练习。
同时对于这几道交互题和 SPJ,tsawke 会尽力去使其严谨,但不保证不会漏下在交互库里对所有数据的大小范围的限定,所以烦请各位不要特意去卡超出范围的数据,否则可能有直接 RE 的可能。
## 关于交互具体如何实现
对于刷新缓冲区,一般有以下几种写法:
```cpp
fflush(stdout);
std::cout 1, res; l > 1) {
std::cout res;
if (res == 0) {
return 0;
} else if (res == -1) {
l = mid + 1;
} else if (res == 1) {
r = mid - 1;
} else {
puts("OvO, I AK IOI"); // this statement will never be executed.
}
}
return 0;
}
```
对于以上的程序我们通过 ` cout ` 来向交互库传递参数,并刷新缓冲区,此时交互库便会返回一个值,我们通过 ` cin` 来实现获取交互库的返回值。需要注意这里并不必须是 ` cin ` 或 ` cout `,只要使用的是标准输入输出的均适用。当程序结束时 ` return 0; `。
而对于 grader 交互题,有如下 Luogu 上的样例:
```cpp
#include // 在本题中并不是必须的
extern "C" int Seniorious(int); // 在这里需要声明一次交互库给出的函数。
extern "C" int Chtholly(int n, int OvO) { // 在这里实现交互库要求你实现的函数。
int ans = 1;
for (int l = 1, r = n, mid = (l + r) >> 1; l > 1) if (Seniorious(mid) >= 0) {
r = (ans = mid) - 1;
} else {
l = mid + 1;
}
return ans;
}
```
首先我们需要在全局作用域声明交互库中的函数,与你需要实现的函数,见样例程序。
然后你需要实现这个函数,如样例程序,可以直接通过调用声明过的交互库中的函数,即 ` Seniorious(int) `,计算结束后返回要求的返回值即可,提交时也只需要提交这些代码片段。
## 关于交互如何本地调试
Tips:因为咱们大多为 Windows 环境,所以这里以 Windows 为例,Linux 可以类比一下,差别不大。
Tips:以下均对于 grader 交互题而言,若为 IO 交互题,则仅需按一般形式测试即可。
对于交互题一般会给交互库的源代码,假设交互库为 ` interactive_lib.cpp `,提交的程序为 ` submit.cpp `,假设两个文件在同一目录,且命令行中所在位置为文件所在位置,那么可以使用如下命令:
```bash
g++ interactive_lib.cpp submit.cpp -o 1.exe -std=c++14 -lm -Wl,--stack=2147483647
```
即可生成名为 ` 1.exe ` 的可执行文件。
关于 g++ 的配置,命令行和 powershell 的用法等,这里不再赘述。
生成可执行文件后在命令行输入:
```bash
1.exe
(examples)
```
也就是说,回车后输入将**样例输入**输入,即可得到程序的输出。
## 关于这两种交互题
似乎 NOI 系列的比赛均采用 grader 交互?不太确定。
如果 IO 类的交互 NOI 系列赛不考的话,可以把这个当成一个小拓展~