通信题
通信题简介
通信题是一种特殊的题目,它要求选手在一个程序中实现两种功能(以下称为“功能 1”和“功能 2”)。在评测时,选手程序将运行两次,第一次运行时使用“功能 1”,第二次运行时使用“功能 2”,且第一次运行的结果将作为第二次运行的输入。
一个典型的通信题评测流程如下:
- 运行选手程序,读输入文件,输出“功能 1”的结果(T1)。
- 运行通信对端,读 T1,进行一些处理,输出记为 T2。
- 运行选手程序,读 T2,输出“功能 2”的结果,作为最终输出文件。
- 运行比较器,读输出文件和答案文件,进行比较和评分。
一个简单的例子:
- 选手程序读输入文件,进行加密,输出加密后的文件(T1)。
- 通信对端读 T1,验证加密是否正确,并将 T1 原样输出(T2)。
- 选手程序读 T2,进行解密,输出解密后的文件,作为最终输出文件。
- 比较器读输出文件和答案文件,进行比较和评分。
另一个例子(IOI 2011 鹦鹉):
在该例子中,输入文件为“原始消息”,选手完成“编码”和“解码”功能,通信对端实现“重新排列”操作。运行结束后,选手程序的输出文件为“解码后的消息”。
通信题的配置
在题目配置文件中增加 communication on
配置项,即表示该题为通信题。
注意
通信题和交互题(联合编译)不冲突。交互题(联合编译)为选手程序增加了交互库,而通信题将评测流程从运行一次改为运行两次。
但是!通信题和交互题(输入输出)冲突,不能同时启用,因为两种题目均改变了每个测试点的运行方式。
为了让通信题能够评测,需要配置通信对端和比较器。
通信对端
通信对端是一个独立的程序,它保存在题目文件夹下的 require/communicator.cpp
中。该程序可以包含 require
文件夹中的任意头文件。
在评测时,评测系统会使用 g++
来编译它,编译选项为 -O2 -std=c++17
。
比较器
比较器的配置与其他类型题目相同。可以使用内建比较器,也可以使用自定义比较器。
需要注意的是,通信题的比较器将在功能 2 完成后运行,而不是功能 1 和功能 2 之间。后者的文件处理由通信对端完成。
通信题配置的常见问题
关于时间和内存限制
通信题的每个测试点一共运行 4 次。在当前的 OJ 实现中,每次运行的时间内存限制如下:
功能 | 时间限制 | 内存限制 |
---|---|---|
选手程序(输入文件 → T1) | 同测试点配置 | 同测试点配置 |
通信对端(T1 → T2) | 5 秒 | 1024 MB |
选手程序(T2 → 输出文件) | 同测试点配置 | 同测试点配置 |
比较器(输出文件 vs. 答案文件) | 5 秒 | 512 MB |
在选手程序的两次运行中,时间内存限制是独立的。例如时间限制为 1 秒,则选手程序在两次运行中分别用时 0.9 秒和 0.8 秒,不判为超时。
在评测完成后,OJ 会返回选手程序两次运行的最大时间和最大内存。
相同的选手程序运行两次,如何知道是哪一次?
注意,两次运行的输入文件不一样。第一次是测试点的输入文件,第二次是通信对端的输出(T2)。
可以在这两个文件的开头加上一些标记来区分。另外,建议用交互库来完成这样的工作,以减少对选手解题的干扰。
如何在比较器中得到通信对端的输出(T2)或功能 1 的输出(T1)?
无法直接得到。但可以通过交互库,间接获取到相关信息。例如:
- 题目要求选手对数据进行“加密”再“解密”。在加密完成后,通信对端想要保存一些性能指标,用于后续的评分。
- 可以让通信对端直接输出性能指标到 T2,然后在交互库读 T2 时,原样输出性能指标,供比较器读取。
如何保证安全性?即,如何防止选手绕过交互库直接输入输出?
无法根本解决。但可以通过一些手段来减少风险。
- 输出防伪造:交互库在运行结束前才开始输出,且输出的开头为一个秘密字符串。这样,选手因为不知道该字符串,而无法直接输出有效内容。特别注意:每次运行的输出都会由通信对端或比较器读取,此时可以进行秘密字符串的检查。
- 输入防破解:以选手未知的方法(包括不限于加密)保存输入数据和中间结果。这样,只要选手无法得到评测时使用的交互库,输入数据的格式就很难被猜到。
一个好的设计原则是,将选手程序视为不可信的,尽量避免其获得额外信息,或影响评测流程正常进行。
交互库检测到选手程序的不合法操作,能否提前结束评测?
不可以。通信题的整个评测流程必须完整执行。
但是,如果想要中断评测并直接给出评判(如 Wrong Answer),一种可能的方案如下:
- 假设正在运行功能 1,交互库在检测到不合法操作后,输出一个特殊的字符串,结束程序。
- 通信对端读取到此字符串后,原样输出。
- 第二次运行交互库时,检测到此字符串,直接原样输出并结束程序,不运行功能 2。
- 比较器读取到此字符串,给出相应的评判。
注意
在检测到不合法操作后,请不要以非零退出码结束程序,否则:如果非零退出交互库,评测系统会将其判为 Runtime Error;如果非零退出通信对端,评测系统会将其判为 System Error。请在比较器中给出对于不合法操作的评判。