首页 > 其他分享 >OI线下比赛注意事项

OI线下比赛注意事项

时间:2023-01-27 18:22:35浏览次数:54  
标签:std OI 使用 程序 C++ fc 线下 版本 注意事项

一些经验之谈。

I. 学会使用 Linux 虚拟机

在日常生活中,我们使用的电脑系统通常是 Windows,线下考场中的电脑也几乎都使用 Windows 系统,而 Linux 系统我们一般很少接触到。不幸的是,几乎所有的 OI 比赛的评测机和 OJ 所使用的系统都是 Linux。同一份代码在不同的系统上的运行结果可能是不同的,这就可能导致:你在考场上辛辛苦苦写了几小时代码,并且它成功通过了所有样例,结果 CCF 给你的评测结果是爆零。

为了避免这种情况,你应该在考试之前学会使用 Linux 系统。你可以在你的电脑上安装一个 NOI Linux —— 这是 CCF 提供的专供 OI 使用的 Linux 系统,所有 CCF 举办的线下比赛所提供的电脑都应该会提供这个东西,所以你在比赛时也可以使用它。

在你比赛写完代码之后,你应该把代码复制到虚拟机上重新测试一遍,如果没有问题,才能保证你的代码不会因为“非智力因素”出错。

II. 不要 using namespace std; & 注意防止重名

using namespace std; 诚然是一个非常方便的语句,这导致它受到了许多 OI 新人的青睐。事实上我以前也很喜欢使用这个语句,并且对网上看到的那些大佬所说的“千万不要使用 using namespace std;”进行了忽视,直到我自己差点在 CSP-S 2022 中因为这个原因爆零,才深刻地认识到了这玩意的险恶之处。

using namespace std; 的优点在于,它可以一次性帮你把几乎所有需要的库函数引入进来,但这也是它的缺点:它引入的函数实在是太多了。std 中包含了浩如烟海的函数,其中很多你连听都没听过。而众所周知,你自己的变量名/函数名等名称若是和库函数重名了,容易造成不可预料的后果,最常见的就是 CE,然后爆零。由于 std 中的函数很多,你的重名机会也大大增加了,这就让你可能会爆零。

我在 CSP-S 2022 的 T2 中给一个数组取名为 bzero,这看起来是一个很正常的名字,没想到它居然也是 std 中的一个库函数名。更为致命的是, Windows 系统下编译,这种问题既不会报错,也不会警告,这就让我差点爆零了。为什么是“差点”?因为我很幸运,我无意把这个数字定义成了局部变量而不是全局变量,避免了因为这种非智力因素爆零。后来我兴奋地把这件事发到了洛谷上,然后发现一位老哥和我犯了同样的错,用了同一个变量名。不过他就没有这么幸运了,他定义的是全局变量,然后他就爆零了(

说回正题,如果不能写 using namespace std;,我们该怎么使用 std 中的函数呢?

有两个方法:一是在程序的开头写上 using std::function_name,其中 function_name 是你要使用的语法名字,之后你就可以在程序中随意使用了。这样写不仅可以引入单个函数,也可以引入一个 C++ 容器的所有成员函数。比如如果写 using std::queue,就可以同时把 queue.push() queue.front() 等函数都引入进来。二是在你要使用这个语法时,在它前面紧挨着的地方写上 std::,比如 std::cout << "Hello" << std::endl;。相比起前一种方法,这种方法每使用一次次只能引入紧挨着它后面的一个常量/函数,下次你如果还要使用,你还得再写一次,而第一种方法是一劳永逸的:只要在程序开头写一次,之后就不用再写了。

不过要说明:即使你像我说的做了种种防止重名的方法,你还是有可能重名。所以你讲那么多干什么?一个很可能的原因是你的名称和 C 语言的库函数重名了。(这次敌人终于不来自 std 了。)众所周知,C++ 向下兼容了所有 C 的函数,而这些来自 C 的函数在使用时并不用 std,比如你不需要把 printf() 写成 std::printf()。这就导致我上面说的那些方法对这种错误不起作用,你要是不小心把变量名/函数名写得和 C 语言中的库函数名重名了,照样会 CE。一个出名的例子是 <cmath> 库中的 x0 之类的变量名。

那么这种问题要这么防范呢?这时候还是得使用我们预防非智力因素错误的超级大法:在 Linux 系统下编译,就像我在第一条建议中说的那样。因为这些错误虽然在 Windows 下不会显现出来,但是在 Linux 下编译是会报错的。你只要把程序修改得在 Linux 系统下也不会报错,它大概就真的没有问题了。

III. 学会对拍

在学习对拍之前,要先了解 fc 的使用。它是 Windows 下比较文件的命令行工具。使用它,我们可以很方便地判断两个文件是否相同。它可以在命令行(cmd)下使用,也可以把它写到 C++ 的 system 函数中使用。下面我将具体介绍它的使用方法。

  1. 在 cmd 下使用。
    按下 Win + R,输入 "cmd",打开命令提示符。把要比较的两个文件放在同一文件夹下,在命令提示符中使用 cd 语句切换到这个目录。然后就可以使用 fc 了,它的格式如下:fc filename1 filename2,注意文件名包含后缀。如果两个文件相同,命令提示符会显示“找不到差异”,否则会显示第一次找到差异的地方。

  1. 在 C++ 中使用。
    在 C++ 中使用的关键是 system() 函数。这个函数可以执行一些命令行工具,方法就是直接把语句粘贴进去就行了。比如想比较 1.txt 和 2.txt 两个文件,就可以写成system("fc 1.txt 2.txt"); —— 引号里面的东西和直接写在 cmd 里的是一样的!屏幕上显示的东西也和命令提示符是一样的,这里就不在赘述了。

(这只是 fc 的基本用法,它的更多用法可以自行上网查阅。)

我们已经知道了 fc 语句的用法,那么它在 OI 中有什么用呢?首先,它可以比较你的输出和标答是否相同。如果输出规模较小,你通常可以使用瞪眼大法,用肉眼比对。不过用人眼比较终究是有风险的,而且如果输出规模比较大,瞪眼大法就根本不可行。这时候 fc 就派上用场了:你可以把答案输出到一个文件里,然后把这个文件和标答比较,就能准确地知道是否相同了。

fc 的另一个用法就是我们重点要讲的——对拍。

什么是对拍?对拍是一种检验程序是否正确的方法。有的时候你的程序通过了所有的样例,你却还是会担心样例太弱了,无法查出程序的一些问题,这时候就可以用到对拍了。

那么究竟如何对拍呢?对拍需要四个 cpp 文件:一个数据生成器(generator),一个需要检验正确性的程序,一个能保证正确性的程序,以及一个用于执行对拍的程序。

啥是“能保证正确性的程序”(下面简称为暴力程序,虽然这个程序不一定是暴力)?你或许会问。如果我能写出一个能保证正确的程序,我还用得着对拍吗?事实上,这个程序并不是指能 AC 的程序,而是指能保证它的输出结果是正确的,但是时间复杂度太高,会导致 TLE 的程序,比如说暴力程序。如果直接提交这个程序,可能会因为 TLE 而只能得到部分的分数,但是我们在本地使用它时,可以接受它的时间复杂度稍微大一点(当然也不能过于大了,如果你的程序一天都跑不出结果那也是万万不行的)。所以对拍的原理就是:用数据生成器生成数据,让两个程序分别运行。其中暴力程序输出的是正确的结果,把这个正确的结果和待检测程序的结果相比较,就能知道待检测程序是否正确的。

当然,只测一次往往是不能验证正确性的,所以我们通常将对拍程序写在一个循环里,如果运行多次都没有发现差异,就说明待检测程序是正确的。至于要循环多少次,当然是循环得越多越能保证正确性,循环次数越多越好。不过这通常受限于你暴力程序的运行时间,如果你的暴力程序运行一次要十几甚至几十秒,那你恐怕也对拍不了几组。

对拍代码如下:

#include <bits/stdc++.h>

int main() {
  // For Windows
  // 对拍时不开文件输入输出
  while (1) // 也可以写成 for 循环中指定组数
  {
    system("gen > test.in");  // 数据生成器将生成数据写入输入文件
    system("test1.exe < test.in > a.out");  // 获取程序1输出
    system("test2.exe < test.in > b.out");  // 获取程序2输出
    if (system("fc a.out b.out")) {
      // 该行语句比对输入输出
      // fc返回0时表示输出一致,否则表示有不同处
      system("pause");  // 方便查看不同处
      return 0;
      // 该输入数据已经存放在test.in文件中,可以直接利用进行调试
    }
  }
}

(这一段代码来自 OI wiki

IV. 记得文件读写怎么写

文件读写就是 freopen,每年都有因为这个写错或者不写而挂掉的。CCF 举办的比赛中都要求写文件读写,千万不要忘记了,否则你将会失去这一题全部的分数。

文件读写的格式如下:

int main()
{
    freopen("filename.in", "r", stdin);
    freopen("filename.out", "w", stdout);
    /* Your code*/
    fclose(stdin);
    fclose(stdout);
    return 0;
}

其中,freopen 的两行是必须写的,fclose 可以不写,但是可能会有小概率出问题,所以最好还是写上。(其实关于 fclose 要不要写我也不是很懂。)

文件读写的作用不仅仅是让你不爆零,它在代码调试的过程中也是非常有用的。比如样例太大的时候,你无法通过 Ctrl + C/V 复制粘贴到程序的运行窗口中,这时候你就只能通过文件读写读入样例。所以请你一定要记得文件读写怎么写,否则你连样例都测试不了。

V. 注意 C++ 版本

根据《关于NOI系列活动中编程语言使用限制的补充说明》,C++ 程序编译默认采用的语言标准为 C++14。而我们使用的 Dev 编译采用的默认版本通常比较老旧(通常是 C++98),导致我们无法使用一些较晚版本更新的语法,或者让我们无意间使用了过于老旧的、在新版本中已经被废除看的语法而无法察觉。这就要我们手动给 Dev 选择高版本的 C++。

怎么给 Dev 选定 C++ 版本呢?点击工具-编译选项-编译器,找到“编译时加入以下命令”,点亮这行文字左边的√,在下方写上 -std=c++14,即可把版本设为 C++14。这行语句中的 c++14 也可以替换成其它的 C++ 版本,比如 -std=c++11 就能把版本设为 C++11。

设置版本之后,许多较新的语法都可以使用了。比如大名鼎鼎的 mt19937——它于 C++11 中被更新进来,如果你不会手动选择 Dev 的 C++ 版本,你就无法使用它,而只能使用老旧的 rand() 函数。曾经有一位同学让我把一道题的数据发给他,我就把一个用 mt19937 写的 generator 发给了他,但是由于他不知道如何选择 C++ 版本,他就不会运行这个 generator 了,可见学会手动选择 C++ 版本的重要。

这里我给大家推荐一篇洛谷日报:link,它总结了一些 C++ 的实用语法,其中大部分语法都在 C++98 以后,C++14 及以前的版本里,你可以放心地在考场上使用它——只要你会手动选择 Dev 的 C++ 版本。其中许多语法能极大地便利代码的书写。

结尾

本篇文章开始写于 2023/01/24 晚上8点左右,耗时大约 2.5 小时写完。

Upd on 2023/01/25:新增加了第 V 条。

标签:std,OI,使用,程序,C++,fc,线下,版本,注意事项
From: https://www.cnblogs.com/dengstar/p/17069134.html

相关文章

  • [NOIP2016提高组] 愤怒的小鸟
    洛谷传送门AcWing解题思路\(\qquad\)这题可以转化为一个重复覆盖问题,由于三个点可以确定一条抛物线,而这里的抛物线必定经过原点,所以可以用不是原点的两个点确定一条抛物......
  • AndroidBench&eMMC内存测试速度&Android
    提问: 问题:手机eMMC内存,我用AndroidBench/安兔兔/鲁大师测出来的速度很快,而自己写AndroidTool测试的速度确很慢,这是为什么呢?主要信息:   同样是SequenceWrite操作,An......
  • Could not locate aapt. Please ensure you have the Android buildtools installed.E
    Flutter开发调试一直报错Couldnotlocateaapt.PleaseensureyouhavetheAndroidbuildtoolsinstalled.Exception:ProblembuildingAndroidapplication:seeab......
  • Cesium Ellipsoid(十四)
    由方程(x/A)^2+(y/b)^2+(z/c)^2=1在笛卡尔坐标系中定义的二次曲面。Cesium主要用来表示行星体的形状。通常使用提供的常量之一,而不是直接构造此对象。 不用new,直接就可以使用......
  • metasploit
    1.PortScanwithMetasploit$msfconsole msf6>searchportscan msf6>searchpath:portscanmsf6>searchtype:exploitmsf6>useauxiliary/scanner/portscan/s......
  • Android2.2 开发环境搭建
    Android2.2开发环境搭建cheungmine2010-11-28深夜昨天到不夜城买了一个HTCG7Android手机。周六的时候,人却很少。火车站对面梅园路口那个金色的大厦就是。买的当然是水的,......
  • Serverless应用优化与注意事项
    通过冷启动优化、对无状态性的认识、Serverless架构下的资源评估、开发者工具的加持等方面的介绍对Serverless架构下的应用优化与注意事项进行总结。函数基础与资源编排1......
  • Android Files.delete()使用try-catch依旧出错
    提问: 我想做一个供自己使用的文件编辑器,其中有一个删除指定文件的功能(第105行开始):  我使用了catch语句抓住错误,可是当找不到指定文件时仍旧闪退。具体详情:  ......
  • Android View VISIBLE,INVISIBLE和GONE的区别
    AndroidViewVISIBLE,INVISIBLE和GONE的区别首先整理一下View的三种显示的形式,VISIBLE,INVISIBLE和GONE。/***Thisviewisvisible.*Usewith{@link......
  • Android高级控件之下拉框和几种适配器
    7.1下拉框首先介绍下拉框在xml文件中的两种表达形式,再介绍在代码中的两种写法在xml文件中,下拉框控件Spinner的写法如下所示:<Spinner android:id="@id/sp_XXX"  ......