CSP 赛前温馨提示

郑朝曦zzx

2022-08-10 22:18:28

Personal

很快 CSP 就要比赛了,我整理了一下我学 OI 以来经常犯得错误,一是警示自己不要重蹈覆辙,二是给各位读者赛前提个醒。 # 一 文件读写与输出格式 文件读写是最重要的,不然正规考试就零分了。 正确的读写方式是这样的: ```cpp freopen("xxx.in", "r", stdin); freopen("xxx.out", "w", stdout); // xxx 是试卷会给好的输入、输出文件名 ``` - 我听说有人输出文件后缀写成 .txt 的,还有 .ans 的,这都是**不对了**!!! - 我的老师并不建议文件读写复制粘贴,别粘贴后,"r" 没改成 "w",就悲剧了。 个人建议,如果您考试前 10 分钟把该打的暴力/骗分都打完了,就检查一些文件读写,删除注释,输出格式之类的问题。您不要指望您最后 10 分钟能想出正解并无误地打出代码(大佬勿喷)。 - 收卷前检查好是否**注释了调试语句**,行末**是否要换行**。 # 二 注意数据范围 OI 界有一句关于 long long 的俗话,大家应该都知道吧。 对于 **中间运算结果(不只是答案)** 有可能超过 int 范围内的,请开 long long,一定要都开全了,宁可多开,不要少开(如果空间卡的紧,请认真计算)。 - **特别注意:** 对于 unsigned long long 也不够的情况,请手动特判。 近几年提高组卡了两次 unsigned long long,一次是格雷码,一次是动物园,位运算超出运算上线,需要手动特判。 - 个人**不建议**使用 `#define int long long` 本人在 codeforces VP 比赛这样写遇到过几次玄学的错误,问老师,老师也不建议这么写,乖乖写就好了。如果是收卷前两分钟发现精度问题那就另当别论,但是注意 `int main` 要改成 `signed main`。 - 输出使用 `cout` 或者 `printf("%lld", )` 一定是 `lld` 不然都白干了。 - 注意 int 除以 int 结果还是 int,若是要取浮点数,请注意转换。 # 三 数据清空与多测的注意事项 如果题目是多测,一定要把用于打标记和一些解题相关数组清空。 - 注意,清空**二维数组**谨慎用 memset, 打过 codeforces 的应该都知道,单次 memset (如果是后面填 `sizeof(a)`的话)二维数组时间复杂度是 $O(n^2)$ 的,如果**测试数据很多但是每组数据很小**,memset 会 TLE。这样的情况我建议使用**循环清空数组**。 感谢各位大佬提出的建议,我之前这里说的不太严谨。 - 对于多测的题目,就算您输入中途就能得到答案,也要把**本组数据读完**,不然会影响到输入下一组数据。 - 还有 memset 是不要犯这种低级错误: ```cpp memset(a, 0, sizeof(b)); ``` # 四 字符串读入的注意事项 众所周知, Windows 系统字符串行末换行符和 Linux 系统不一样,所以遇到输入字符串的题目**一定要小心**。 比赛时建议到 Linux 系统上实测一下,看有没有问题。 如果您还不放心,遇到字符串输入,而且输入数据不大,直接 cin 了。 # 五 头文件 我有一个同班同学,去年参加 CSP-J,由于疫情原因,他的考场临时调整到(所以电脑是 windows 的,还没装虚拟机)我们学校图书馆楼上。但是我们学校电脑编译器版本很旧,他使用 memset 的时候头文件打成了: ```cpp #include <string> ``` 结果编译器没查出错,于是他那题就零分了。 记住 memset 头文件是 cstring 或者 string.h。 - 深基上说现在能用万能头了。 # 六 数组与变量 - 数组建议比数据上限开大一点,避免溢出。 - 数组开的大小建议提前 define 或者 const 一下,千万别打错了。 - 算不清楚上限的情况下建议使用 vector, queue 之类的 stl 容器,而且 stl 开 O2 跑的飞快。 - dp 转移状态的时候小心访问数组溢出到 -1。 - 变量开在**主函数内**是没有初始化的,请手动初始化。 # 七 开题顺序 这一点很重要,CSP 题目难度**不一定是递增的**,比如去年 J 组比赛,T2 正解相对不太好想(大佬勿喷),而 T3 是个很水的模拟,T4 交个 $n^2$ 的暴力就有 70 分。再比如前年的提高组,T1 儒略日模拟起来很恶心,而 T2 动物园是个位运算的简单题。 **所以我建议拿到试题后前整体浏览题目,再进行做题。** # 八 一些奇怪的问题 ## 循环 二维循环很容易写成这样: ```cpp for (int i = 1; i <= n; ++i) for (int i = 1; i <= m; ++i) ``` 或者这样: ```cpp for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++i) ``` 这样的错误很难检查出来。 ## 位运算优先级问题 我不太了解位运算的优先级的问题,反正该加括号的地方都加上就没错了,不要冒险。 ## define 的优先级问题 也是加括号避免奇怪的运算顺序 ## 函数返回值问题 没有返回值是 void, 有返回值是相应类型,不要写错了,有一次月赛我写错了,交上去就 RE 了,本机还没报错(不知道考场的机器会不会报错) ## 相似的函数名别写错 我有一次写树剖犯了这样的错误: ```cpp void dfs1(xxx) { xxx dfs1(); } void dfs2(xxx) { xxx dfs1(xxx); } ``` ## set 里二分 一定要这么写: ```cpp s.lower_bound(x); ``` 而不是: ```cpp lower_bound(s.begin(), s.end(), x); ``` 后者时间复杂度是**错误的**,本人 Atcoder 试验过。 # 九 养成好的代码习惯 - 代码风格确定了就不要改了,自己看着舒服(比如打不打空格,大括号换不换行之类的) - 常用的解题步骤请**打包成函数**,不要复制粘贴,要改的话也好改。 - 不要用与现成变量名,函数名重复的变量、函数名称,比如 next, y2 之类的。 # 十 提前熟悉 Linux 编码环境 竞赛新手的话赛前请装个 NOI 的 Linux 虚拟机,提前熟悉一下编码环境。不要像我去年那样比赛开始编译器出现文件路径问题用不了,白白浪费快一个小时,与普及一等就变成了二等(T3 最后没来得及开)。 # 十一 好的考场心态 好的考场心态很重要,试卷很难的话您做不出来,别人也做不出来。把该拿的分数都拿到就很好了,不要留下遗憾就行。 最后祝大家比赛顺利。 鸣谢: 感谢:@UnyieldingTrilobite 大佬指出文章的错误