善用系统自带工具以提高赛场上的效率
前置条件
这里假定各位使用 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 操作系统下进行
关闭调试开关,编译程序。
之后,我一般采用如下窗口布局:
左上角:正式输入文件
右上角:文件列表,包括编译好的程序和样例
左下角:不重要
右下角:终端
中间:打开的样例文件,不刻意安排空间,因为将样例文件复制到正式输入文件之后就可以关掉了
步骤如下:
- 打开命令行终端,使用
cd进入正确的目录。 - 打开样例文件,将样例复制到正式输入文件,关闭样例文件。
- 双击 exe 文件运行程序。
- 在终端写下
fc task.out task1.ans命令比对答案。 - 重复 2~4 步,直到所有样例比较完毕。
fc 是仅在 Windows 系统下 cmd(命令提示符)下可用的文件比对命令,传入两个文件的文件名即可。以下是我实操中发现的特性:
- 不忽略行末空格,但忽略文件末换行;
- 当一行文件太长时,性能会下降。即,
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 是输出警告内容,比如函数没有返回值、使用变量前可能没有初始化之类。
freopen、scanf 函数的使用也可能引发警告,因为这俩函数实际上是有返回值的,用于判断文件操作是否无异常。这个就可以不接收,因为我们假定一切文件读写正常,就算是不正常的你也没什么办法。
编译后,目录下便会多出 task 可执行文件。
之后,依次执行以下命令:
cp task1.in task.in
./task
diff task.out task1.ans
从上到下分别为:复制样例、运行程序、比对程序输出。
虚拟机下文件编辑有点难,尤其是大文件,复制进剪贴板会导致虚拟机卡顿。所以我使用 cp 命令进行复制。
Windows 下使用命令复制可能导致文件意外覆盖,Linux 下就不用担心,覆盖了再从 Windows 下拉一份即可。
在实操中,我发现了一些 diff 命令的特性:
- 当文件相同时不会输出任何内容;
- 不忽略行末换行。
若运行程序时提示 Permission denied 之类,可以使用 chmod +x task 为文件赋予可执行权限。
提交前检查——为了确保万无一失
提交前检查在比赛结束前 15 分钟进行。
在 Windows 操作系统下,通篇阅读源代码,确认数组空间有没有开够,文件读写正不正确,所有调试代码是否无效化。
我在 CSP-S 2023 中因为数组空间吃了大亏,这个和这个提交记录,只因为一个数组空间,样例都能过,提交差距 80 分。
这也是我在赛场上最惨痛的教训,在比赛结束前不足半小时调出大模拟的喜悦,被这么一个挂分消耗殆尽。
再次运行 CCF 提供的 checker.exe,确认文件 md5 校验和是否与之前记录的一致。
参照二次对拍的相关内容,最后检查一遍样例。
检查无误后就可以准备提交了。