相信很多人应该听说过在CSP-J复赛考试中爆零的现象,所谓CSP-J复赛爆零是指参赛选手在CSP-J复赛中因为各种原因导致得分为零的情况。
爆零的原因有很多种,为尽量减少甚至完全避免爆零的出现,我在这里给出一些比较重要的考试建议和意见。
首先要特别注意试卷上面写的注意事项,每一项都要完全照做,一定要防止出现因为错误操作导致零分,注意事项截图参考下图:

必须特别注意每道题的目录、输入文件名、输出文件名以及提交的源程序文件名要求,如下图所示:

上图中,要求将目录名、源程序命名为什么,必须照做。
这里,我需要特别强调几点:
(1)为防止突发情况,编写程序过程中做到随时存盘。有遇到无法应付的情况随时报告监考老师,比如断电,程序出错等等。
不要在比赛中重新启动电脑,否则很可能导致自己的答题丢失。
(2)每个省对于程序代码提交的位置,提交的文件名可能有不同的要求,一定要以监考老师公布的要求为准。比如很多地方会要求学生在“准考证号→题目目录名”下创建指定的源程序文件,一定不要搞错。
提交文件名,比如第一题叫apple.cpp千万不要出现apple.ccp这样的错误。
不排除有的电脑显示目录文件名时,把文件扩展名隐藏了的可能性,此时apple.cpp中的.cpp就不会显示,这极有可能导致答题者明明想将文件命名为apple.cpp,而实际却变成了apple.cpp.cpp,结果导致零分。
所以,在文件资源管理器中,切记一定要把文件扩展名显示出来,不会设置的参考下图:

上图是我Windows11的资源管理器中,如何设置来把文件扩展名显示出来。不难看到,文件扩展名左侧有个✓,而且也可以观察到,显示的所有文件都带有了扩展名,比如.png或者.cpp等等。
可能不同的Windows版本,文件扩展名的显示设置位置不太一样,但基本都是通过在资源管理器上面的菜单或者工具条里找到选项进行勾选的方式来设置,要细心和耐心的寻找。
(3)通常,在刷题的时候,读入或者输出数据一般采用的是cin、cout或者scanf、printf。但是,在信奥赛比赛中,根据前面截图,不难看到,就以小苹果这个题为例,读入数据要求从apple.in中读入,输出也不再是输出到屏幕,而是输出到apple.out文件中,所以必须对代码进行适当的修改——在main主函数的最开头位置,加入如下两行对freopen函数的调用:
#include <iostream>
using namespace std;
#pragma warning(disable : 4996) //这行注释被我取消
int main()
{
freopen("apple.in", "r", stdin); //若报错则包含#include<cstdio>,若编译器提示freopen函数不安全,报错不让用,则开启#pragma warning(disable : 4996)
freopen("apple.out", "w", stdout);
....
....
}
上面代码行看到了freopen函数,硬记也要把这个函数记住。以往刷题时读入数据都是从键盘读入,输出数据时都是通过屏幕输出,而freopen能够改变缺省的读入数据和输出数据的位置。
看看上面main函数中的第一个freopen函数:第一个参数是文件名,根据题目要求给进来正确的输入文件名;第二个参数是个标识,”r”表示读,因为是要到文件apple.in里去读数据,所以第一个freopen的第2个参数使用”r”;第三个参数是stdin,理解成“键盘”。整个这个freopen函数的目的是告诉系统读入数据时不再从键盘读入,而是从一个叫做apple.in的文件读入。
再看看main函数中的第二个freopen函数:第一个参数是文件名,根据题目要求给进来正确的输出文件名;第二个参数是个标识,”w”表示写,因为是要把内容写到文件apple.out中去,所以第二个freopen的第2个参数使用”w”;第三个参数是stdout,理解成“屏幕”。整个这个freopen函数的目的是告诉系统输出数据不再直接显示在屏幕上,而是把输出内容直接写到一个叫做apple.out的文件中去。
当然,这种通过文件读写的方式不方便调试,所以一般都是使用cin、cout(或者scanf、printf)把程序写完,调试好后,再增加上述两行freopen代码。其他都不用动。
但是,增加了这两个freopen后,代码是否依旧运行正确,需要测试一下,一般要找到编译链接生成的诸如apple.exe这样的可执行文件,和该文件相同的目录下,创建一个纯文本文件叫做apple.in,往里面输入需要的数字,比如这里输入一个数字8,保存后关闭。
这个时候,直接双击apple.exe来执行该可执行程序,此时,和apple.exe相同的目录,会自动产生一个apple.out,用记事本打开后,其内容就应该是以往该程序输出到屏幕上的内容,比如5 5(如果原来已经存在了apple.out文件,该文件内容会被覆盖掉)。参考下图:

上图表示成功使用了freopen函数,这样就可以了。接着如果有要求保留apple.in或者apple.out,则按要求执行,如果没要求,可以直接把这两个文件删除。
千万要注意,如果中间为了调试方便把freopen函数注释了,则最终的程序代码中一定要把注释取消掉。
为了养成良好的编程习惯,既然使用了freopen,也建议在main函数return之前,利用fclose来关闭从文件读和向文件中写这件事,虽然这不是必须的,但体现出了专业性和良好的编程习惯:
fclose(stdin);
fclose(stdout);
(4)给文件取名的时候,能用Ctrl+C和Ctrl+V复制和粘贴的,就不要自己打字,否则一旦打错就可能得0分。
(5)万能头文件:
我个人很少使用万能头文件“bits/stdc++.h”,因为该文件并不是C++标准的一部分(而是GNU C++编译器GCC提供的一个非标准头文件),所以有些编译器并不支持该头文件。
但是,请记住如何包含一个万能头文件的代码行:
#include <bits/stdc++.h>
在考试的时候,如果能够包含上面这行代码而不编译报错,就尽量使用这个万能头文件,这个头文件的作用是将大部分常用的C和C++标准库头文件一次性包含进来,从而简化了代码的编写过程,特别是在算法竞赛等场景下可以节省时间,因为开发者不需要单独引入每个所需的头文件。尤其是需要用到某个函数但是却不记得这个函数包含在哪个头文件中时,万能头文件可以给编程带来很大便利。
(6)有些程序包含大量的输入和输出,可能一不小心,会出现因为大量的输入输出导致程序执行超时。
当输入的数据量达到10^6的规模或者输出的数据量达到10^5规模,不要再用cin、cout,而改用scanf和printf,当然,平时使用scanf和printf来取代cin和cout也是极好的。《本系列第2门课 图论算法 并查集》中,在求解1389(亲戚)题时,曾经对输入输出的超时有进一步探讨,注意参照。
此外,特别记一下,如果用printf输出long long类型数据时,格式符记得用%lld,比如:
printf("%lld\n", 123);
如果用printf输出double类型数据时,格式符记得用%lf。
(7)注意编写程序的内存限制:
在定义数组、变量时,往往会定义成全局的,这样做有几点好处简要说明一下:
第一个好处是全局变量中的初始内容一般会被系统自动清0,这可能会将某些隐藏错误消灭于萌芽之中。
第二个好处是全局变量的存储位置所在的存储空间一般都比较大,不容易导致程序内存溢出。
第三个好处是全局变量的使用避免了函数之间传递参数导致代码的复杂性。
但是,在定义数组这样的全局变量时,要注意内存限制。比如某个题目的内存限制明确写出是512MiB(1 MiB等于1024 KiB,1 KiB等于1024字节),大概就是512兆字节的内存。
比如说定义如下这个数组
int a[1000000];
占用的内存有多大呢?记住一个大概的估算,一般1后边有6个0,代表的就是1兆也就是1M字节。而一个int类型数据又占4个字节,所以int a[1000000];大概要占4M字节,即4MiB。
如果需要定义的数组太大,可能导致程序编译或者运行出错,此时可以考虑采用vector这种容器(也是动态数组)来取代传统固定大小的数组。
(8)一些数列递推问题,使用int非常容易超出范围。尤其是在使用一些int类型数据计算中间结果时,一旦溢出,整个结果可能就是错的,所以尽量都使用long long来解决问题,不再使用int。
对于浮点数,都采用double类型,不要采用float类型。
(9)答题策略:因为整个考试时间是有限的,所以,拿到题后,先大概浏览一下,通读一下所有题,如果发现有比较熟悉的能够比较快做出来的,则优先做,不非一道一道顺序做,因为一般后面的题会比前面的题难度高,优先挑容易得分的题做,每个题目第一遍不要花费过多时间,对于很难的题目,不要钻牛角尖,先去做更容易的题。在必要的情况下,果断放弃完全没思路的题。做题一定要讲战略,不要在可能耗费更多时间的题上耽误超出性价比的功夫。
(10)答完题目后要仔细检查,该注释的语句注释掉,尤其是一些调试语句,修改完源代码后立即保存。
如果一个文件内容改动后没有保存,那么文件名前面或者后面一般会有个*号提醒,如下图所示,千万要注意及时保存:

检查文件名取的是否对,是否做到了一切要求的内容。程序的输出结果是否和题目给的输入输出样例完全一样。
(11)题目描述中往往会带有一些“特殊性质”类的描述,如果一个题无法完全解出,但可以解出其特殊性质中提到的一些结果,那么也会得到部分分。所以一旦遇到无法把整个题完全解出,但能够按照特殊性质的描述把满足这些特殊性质时的解解出,也是能得到一定分数的。而且,当遇到一个问题而没有解题思路时,特殊性质往往能提供解题思路。
(12)定义数组大小时,比如想的很清楚,1000就够。
int a[1000];
那么为了避免出现一些意外或者麻烦,一般定义的时候多加10个,也就是:
int a[1010];
(13)CSP-J复赛考试所采用的操作系统和开发编译环境,不同的年份,不同的考试地区可能会有所不同,通常情况下,考试所用的操作系统为Windows或NOI Linux 2.0。其中,NOI Linux 2.0是专门为信息学竞赛定制的操作系统,基于Ubuntu 20.04.1版本。
某些省份可能会明确指出使用Windows的某个版本作为考试的操作系统环境,而在其他一些地方,可能会使用NOI Linux 2.0。
在Windows操作系统下,一般会使用如Dev-C++ 5.11这样的集成开发环境来进行编程。而在Linux操作系统下,常用Code::Blocks或Geany等集成开发环境进行编程。
通常,你在学习信息学奥赛知识过程中,最常使用的是Windows操作系统下的Dev-C++集成开发环境,而对NOI Linux操作系统和其中的Code::Blocks或Geany集成开发环境的使用相对陌生。所以,在正式参加信息学奥赛考试之前,一定要对NOI Linux以及Code::Blocks或Geany有所熟悉:
在信奥赛官网 www.noi.cn,在右上角搜索框输入“NOI Linux”,可以看到相关的帖子。希望你能够读一遍。
对于NOI Linux这个上机考试使用的操作系统,2021年发布了它的2.0版本。注意相关的帖子(https://www.noi.cn/gynoi/jsgz/2021-07-16/732450.shtml)中列出了系统情况,包括语言环境、集成开发环境等。在集成开发环境中,要重点注意和C/C++有关的内容。
希望你在自己家中都能下载安装一个NOI Linux开发环境,熟悉它的操作,并且熟悉其中的C++集成开发环境Code::Blocks或Geany的使用(NOI Linux2.0装好后,里面自动就会带有Code::Blocks、Geany)。
可能有的人不会进行NOI Linux开发环境的安装操作,不要紧,请到b站即www.bilibili.com,在最上边的搜索框里输入 NOI Linux,并查看相关的帖子,尤其是查找离现在时间最近的帖子。
在参加CSP-J考试之前,一定要留出一周的时间把这个环境整个搭建和熟悉起来,成功的在这个环境下完成至少一个往年的CSP-J复赛考试题,以免在考试中用的就是这个环境。
(14)比赛前一天好好休息,放松心情,保持充足的体力和精神。
(15)按规定时间准时进入考场,严格遵守考场规定,比如不得携带任何电子设备进入考场,包括但不限于手机、U盘、计算器等;同时也不允许带入书籍或其他参考资料。此外,在比赛开始前和结束后的特定时间段内,选手不能随意操作计算机,以免被视为违规。