复赛注意事项
# (一)文件输入输出
每年都会有一些选手,尤其是第一次参加第二轮(复赛)的选手,因为文件输入输出语句没写或没写对,遗憾爆0。
文件输入输出有多种方式,最简单的是freopen
。假如题目的标题是apple
,则只需要加入这两行:
freopen("apple.in", "r", stdin);
freopen("apple.out", "w", stdout);
注意,这里的函数名称和参数不能写错,任意一个地方出错都会导致程序爆0。比如,apple.in
不能写成apple.txt
,也不能写成apple.in.txt
。"r"
不能写成"read"
,也不能写成'r'
(这种情况编译器会报错)。
两行freopen
中的三个参数是分别相反的:in文件对应着out文件,读取对应着写入,标准输入对应着标准输出。下面三种常见的错误写法,都会爆0。
第一种:
freopen("apple.in", "r", stdin);
freopen("apple.out", "r", stdout);
第二种:
freopen("apple.in", "r", stdout);
freopen("apple.out", "w", stdout);
第三种:
freopen("candy.in", "r", stdin);
freopen("candy.in", "w", stdout);
另外,建议不要在程序的末尾写fclose
函数。因为程序结束后,所占的内存就都释放了,fclose
函数写不写是一样的。写的越多,意味着犯错的可能性越大。
# (二)程序提交格式
不同省份的提交格式可能不尽相同,常见的有两种。
第一种,在“工作文件夹”(不同的省份这个文件夹的位置不一样,也有可能指的是电脑桌面)中建立以选手准考号命名的文件夹,然后在准考证号文件夹内针对每一题再建立一个文件夹,再把源代码提交到对应的文件夹内。
假如某位选手的准考证号是TJ-00055
,四道题的英文标题分别是apple
、cashier
、dune
、manhattan
,则提交样式如下图所示:
- TJ-00055
- apple
- apple.cpp
- cashier
- cashier.cpp
- dune
- dune.cpp
- manhattan
- manhattan.cpp
如果你是用codeblocks
建立的项目,那么每个项目源代码的名称都是main.cpp
。可把main.cpp
拷贝到准考证命名的文件夹内,然后把main.cpp
重命名成相应的名称比如apple.cpp
,或者保存存储时直接重命名。
若采用这种提交方式,不需要提交多余的文件,比如.in
文件,.out
文件,.exe
文件。.in
和.out
文件用来帮助选手测试,.exe
是运行结果文件。如果把这些文件都提交了,也不会影响分数,因为评分时这些文件会被忽略掉。
第二种方式,以北京为例,是在浏览器中打开一个内网网址,然后把代码直接复制粘贴到网址里面,再点击底部的“提交”按钮即可。这种粘贴代码的网站叫做代码回收系统。
这种方式程序文件名称无所谓(比如codeblocks
项目下的程序文件名叫main.cpp
),只需要把代码直接复制粘贴到网址里即可,跟平时提交到洛谷等在线评测网站的过程是类似的。当然这种方式也不要忘了使用freopen
进行文件输入输出。
# (三)Windows系统的扩展名要显示出来
有些Windows系统的电脑的扩展名是隐藏的,一定要让扩展名显示出来。否则轻则影响测试,重则爆0。比如有些机器隐藏了扩展名,选手将程序命名为apple.cpp
,实际上是apple.cpp.cpp
;选手将输入文件命名为apple.in
,实际上是apple.in.txt
。
# (四)NOILinux建立项目的位置
如果你用的是NOILinux
系统,那么不要把C++项目建立在桌面,因为“桌面”这两个字是汉字,会导致无法编译。建议把项目建立在英文路径下,比如/home/username/
。之后在编译完成后,可以把.cpp
文件放到桌面对应目录中,这样就可以方便地提交代码。
# (五)NOILinux建立.in
文件
.in
文件需要手动创建,.out
文件则不需要手动创建,因为运行程序后会自动生成。
Windows系统中创建.in
文件比较简单,右键点击空白处,选择新建文本文件即可。
NOILinux系统与Windows系统差别较大,在NOILinux系统中,右键点击空白处无法创建文本文件。可用下面三种方式来创建。
第一种,运行代码后,会生成xxx.out
文件比如apple.out
,然后把apple.out
在同一目录下复制粘贴,会生成apple(复件).out
,将apple(复件).out
重命名为apple.in
。
第二种,点击桌面左下角的“九个点”按钮,在弹出的界面中的第一页选择“文本编辑器”,注意文件要保存到程序项目的路径下。
第三种,在终端里进入程序项目所在的路径,然后用touch apple.in
或gedit apple.in
的指令来创建apple.in
文件。
推荐新手使用最简单的第一种。
# (六)文件名都是小写
根据历年csp-js/noip
相关的比赛来看,输入文件名、输出文件名、以及源代码的文件名称都是小写的。
# (七)输出格式
如果题目要求数据之间加空格,那就不能换行输出。比如要求输出:
1 2 3
如果选手输出:
1
2
3
则不能得分。
大小写也要注意,需要仔细看清题目是要求全大写、全小写还是首字母大写。比如要求输出Yes
,则输出YES
、yes
、yES
等均不能得分。
# (八)可多次提交代码
每做出一题,提交一题。每题写出一版代码,先提交上去,后面如果有更好的方法写完再次提交,会把先前提交的代码覆盖掉,以最后一次提交为准。
不要把所有的代码等到最后一次性提交,这样可以避免遇到突发情况来不及提交。
每写若干行代码,可保存一次。这样可以避免因为意外情况比如死机重启导致写好的代码丢失。
# (九)头文件
包含常用的头文件,比如iostream
,cstdio
,algorithm
,或者直接包含万能头文件bits/stdc++.h
# (十)变量名冲突
用了using namespace std;
之后容易产生的问题是,有些自己的变量名比如time
、next
和std
命名空间中的变量名冲突,而且在Windows下编译器不报错,但是在Linux下报错。所以如果需要这几个单词,可以使用首字母大写Time
、Next
;或者做一下变形,比如tim
、nxt
;或者定义成局部变量。
另外time
、next
等作为结构体的成员名是没问题的。
全局变量不要使用y0
、y1
、yn
、j0
、j1
、jn
。因为这些变量名称在C++11标准库里被定义了,不能再用作全局变量,否则编译会有警告或出错。但是这些变量可以用作局部变量。
# (十一)变量初始化
变量的初始化常见有两种方式:输入和赋值。在使用变量之前记得要初始化。如果定义成全局变量,则系统会自动初始化。
# (十二)数组建议用全局数组
全局数组可用的内存空间比局部数组可用的内存空间大很多很多。
# (十三)注意时间和空间限制
1秒内最大循环次数不要超过1亿次。1亿次有可能超时也有可能不超时。但是一两千万次通常不会超时。
通常题目会限制内存不能超过256兆或512兆。所以要学会估计内存。比如全局数组`int a
[1000000]`占内存:
100 0000 * 4 / (1024 * 1024) 兆 ≈ 4兆
全局数组的大小通常最好不要超过1千万。CSP-J2023
第二轮的第一套题,最大的测试数据是10亿,有人把数组开到了10亿从而爆0,这是2023年入门组爆0人数偏多的重要原因之一。
这里我们估算一下10亿数组所占的内存空间,假如数组类型是布尔类型,即bool a[1000000000]
,则占内存:
10,0000,0000 * 1 / (1024 * 1024) ≈ 1000兆 ≈ 1G
这已超过题目的要求(512兆)一倍。如果是定义成32位整型,即int a[1000000000]
,则占内存约4G。
# (十四)注意数组越界
数组越界是最常见的错误之一。比如数组下标从0开始,但是选手写成了从1开始,或者数组下标写成了负数。这种错误在Windows下不会报错,但是在Linux下会报错。检查数组下标是否越界,可以在循环中加入打印语句,看看数组下标是否超出范围。
# (十五)注意死循环
死循环是指循环条件永远不会结束,比如while(1)
,for(;;)
。这种死循环会导致程序超时。记住如果使用死循环,一定要在循环体内加入break
语句。
# (十六)注意递归深度
递归深度不要超过1000层。如果递归深度过深,会导致程序爆栈。
# (十七)注意变量类型
变量类型要选择合适的类型,比如int
、long long
、double
。如果题目要求输出的是整数,那么就不要用double
,而是用int
或long long
。
要检查试卷的监测点数据范围,比如如果数据范围是1 ≤ n ≤ 10^9
,那么就不能用int
,而是要用long long
类型。如果是计算变量预计超出也需要使用long long
类型。
关于long long
类型,可以用%lld
来输出,也可以用%I64d
来输出。但是%I64d
是Microsoft
的编译器才支持的,%lld
是gcc
编译器支持的。
# (十八)注意浮点数精度
浮点数精度问题是指浮点数的精度不够,导致输出结果不准确。比如1.0/3.0
的结果是0.3333333333333333
,但是如果只输出小数点后两位,那么就会输出0.33
。这种情况下,可以用printf("%.2lf", 1.0/3.0)
来输出结果。
如果是计算中给变量赋值,那么可以使用math.h中的函数,比如round
、ceil
、floor
等函数。
比如round(1.0/3.0)
的结果是0
,ceil(1.0/3.0)
的结果是1
,floor(1.0/3.0)
的结果是0
。
他们的功能分别对应的是
round
:四舍五入ceil
:向上取整floor
:向下取整
# (十九)注意头文件引入
不要省略头文件,比如#include <iostream>
,#include <cstdio>
,#include <algorithm>
等。省略头文件会导致编译错误。
可以使用万能头文件#include <bits/stdc++.h>
,这个头文件包含了所有常用的头文件。
# (二十)注意代码风格
代码风格要统一,比如缩进、空格、换行等。可以使用codeblocks
、vscode
等编辑器自带的格式化功能,或者使用clang-format
等工具来格式化代码。
# (二十一)注意代码注释
有时我们调试时没有创建.in
文件,那么我们可以先注释掉freopen
函数,等到提交时再取消注释。千万注意不要忘记取消注释,否则会爆0。
# (二十二)noi 系统使用以及 codeblocks
使用
virtualbox (opens new window) 是一个虚拟机软件,可以在虚拟机中安装NOILinux
系统,然后在NOILinux
系统中使用codeblocks
来编写代码。
NOILinux (opens new window) 是一个Linux
系统,可以在virtualbox
中安装,然后在NOILinux
系统中使用codeblocks
来编写代码。