善用系统自带工具以提高赛场上的效率

· · 科技·工程

前置条件

这里假定各位使用 Windows 操作系统完成编码,考场附带基于 Virtual Box 的 NOI Linux 2.0 虚拟机。这是广州大学附属中学大学城校区的配置。

本篇文章记录了我在赛场上调试、对拍使用的方法,供大家参考。

调试输出

使用如下代码:

//程序开头
#define debug//注释掉它即可关闭调试

//freopen
freopen("task.in","r",stdin);
#ifndef debug
freopen("task.out","w",stdout);
#endif

//调试输出
#ifdef debug
printf("debug text\n");
#endif

为了防止忘删调试、freopen("task1.in","r",stdin) 的惨剧,freopen 代码一经书写,不再改动。所有输入一定从正式文件中输入,先将样例复制进 task.in 才运行程序,无论是否为调试。

调试与初步对拍——在 Windows 操作系统下进行

关闭调试开关,编译程序。

之后,我一般采用如下窗口布局:

左上角:正式输入文件

右上角:文件列表,包括编译好的程序和样例

左下角:不重要

右下角:终端

中间:打开的样例文件,不刻意安排空间,因为将样例文件复制到正式输入文件之后就可以关掉了

步骤如下:

  1. 打开命令行终端,使用 cd 进入正确的目录。
  2. 打开样例文件,将样例复制到正式输入文件,关闭样例文件。
  3. 双击 exe 文件运行程序。
  4. 在终端写下 fc task.out task1.ans 命令比对答案。
  5. 重复 2~4 步,直到所有样例比较完毕。

fc仅在 Windows 系统下 cmd(命令提示符)下可用的文件比对命令,传入两个文件的文件名即可。以下是我实操中发现的特性:

  1. 不忽略行末空格,但忽略文件末换行;
  2. 当一行文件太长时,性能会下降。即,10^6 个数,一行一个的比对时间,远远低于一行写完的比对时间。

在 Linux 操作系统下 fc 是另外一个命令。

fc 在 Power Shell 下也不可用:

然而 Windows 10 及以上操作系统下,按住 Shift+右键单击文件夹空白键,打开的是 Power Shell 而不是 cmd。解决方法是直接输入 cmd 命令,进入 cmd 环境。

cmd 命令提示符有个特性:

可以发现,cd 命令进入其它磁盘的目录下,当前的目录仍然不会改变。使用 D: 目录进入磁盘,就能进入对应目录。这是因为 cmd 对于每个磁盘都维护了一遍“当前目录”,切换磁盘时保留了这些信息。

Linux 下的 bash 则没有这个特性,因为 Linux 下的文件路径形如 /home/abcd/,“磁盘”这个概念不在这里体现。

二次对拍——在 NOI Linux 2.0 操作系统下进行

本步骤是为了防止一些 Windows 能过而 Linux 不能的问题。

根据我在广州大学附属中学大学城校区的经验,D 盘根目录下有个名为 public 的文件夹,这就是与虚拟机的共享目录。

在开始复制之前,先运行 CCF 提供的 checker.exe,检查源代码修改时间,并将 md5 校验和记录进一个随意命名的 txt 中(可以只记录前 8 位)。

将文件复制进 public 文件夹后,在虚拟机中把文件剪切home 目录。这样,Windows 下的 public 目录就会被清空。为防止代码反向复制导致代码丢失,只有在虚拟机中操作时才可以允许文件覆盖。尽量不要在虚拟机中编辑,而是在 Windows 中编辑好后再次复制,防止编辑不同步,收上去的代码不是更新的代码。

其实我已经忘了虚拟机下关于 public 的目录具体路径,但桌面上有个 home 文件夹直达图标,双击它即可打开文件管理器。public 要么在左边栏,要么在 home 文件夹下。实在找不到的话,可以试试将文件夹直接拖动进虚拟机,或者举手向监考老师询问。

Linux 的 bash 和 Windows 的 cmd 大同小异。进入代码对应的目录后,输入 md5sum task.cpp 命令计算 md5 校验和,并与 checker.exe 的输出比对,字母大小写无所谓。

确认无误后,输入编译命令:

g++ task.cpp -O2 -std=c++14 -Wall -Wextra -o task

其中,-Wall -Wextra 是输出警告内容,比如函数没有返回值、使用变量前可能没有初始化之类。

freopenscanf 函数的使用也可能引发警告,因为这俩函数实际上是有返回值的,用于判断文件操作是否无异常。这个就可以不接收,因为我们假定一切文件读写正常,就算是不正常的你也没什么办法。

编译后,目录下便会多出 task 可执行文件。

之后,依次执行以下命令:

cp task1.in task.in
./task
diff task.out task1.ans

从上到下分别为:复制样例、运行程序、比对程序输出。

虚拟机下文件编辑有点难,尤其是大文件,复制进剪贴板会导致虚拟机卡顿。所以我使用 cp 命令进行复制。

Windows 下使用命令复制可能导致文件意外覆盖,Linux 下就不用担心,覆盖了再从 Windows 下拉一份即可。

在实操中,我发现了一些 diff 命令的特性:

  1. 当文件相同时不会输出任何内容;
  2. 不忽略行末换行。

若运行程序时提示 Permission denied 之类,可以使用 chmod +x task 为文件赋予可执行权限。

提交前检查——为了确保万无一失

提交前检查在比赛结束前 15 分钟进行。

在 Windows 操作系统下,通篇阅读源代码,确认数组空间有没有开够,文件读写正不正确,所有调试代码是否无效化。

我在 CSP-S 2023 中因为数组空间吃了大亏,这个和这个提交记录,只因为一个数组空间,样例都能过,提交差距 80 分。

这也是我在赛场上最惨痛的教训,在比赛结束前不足半小时调出大模拟的喜悦,被这么一个挂分消耗殆尽。

再次运行 CCF 提供的 checker.exe,确认文件 md5 校验和是否与之前记录的一致。

参照二次对拍的相关内容,最后检查一遍样例。

检查无误后就可以准备提交了。