oi中一些神秘技巧
前言
文章主要介绍在 oi 赛制 中能减少挂分或加快编码速度的小技巧,因为我很菜,大概率没涵盖完,欢迎各位进行补充。
每个技巧的使用前提会在标题旁标明,请针对性阅读。
我说编译器特别重要
编译选项(devc++,linux 可配合终端编译食用)
__int128 QWQ;
int awa()
{
int u=abs(QWQ);
a=1919810;
if(u=114514)cout<<u;
}
//判断QWQ的绝对值是否为114514,输出a
哇,多么好的代码啊!
但是,我们的代码有不少问题:这段代码有多处会导致我们编译错误或者输出错误的陷阱!
那问题来了,怎么才能让编译器乖乖地报错/警告呢?
我们点击 devc++ 顶端的“工具”一栏,选择“编译选项”(红圈)
不出意外,你应该可以看到一个白框:
勾选“编译时加入以下命令”,然后把以下的妙妙代码加入到框里:
-Wall -std=c++14 -O2 -Wl,--stack=233333333
他们的意思如下:
- 让编译器对于一些不规范的/可能出问题的地方做警告(上图的黄色部分)
- 让编译器按 c++14 的标准来编译
(因为ccf是这么要求的) - 开启 O2 优化让编译器优化你代码的一部分,从而让你代码跑的更快。
- 举个例子,开启 O2 优化并对
for(int i=1;i<=n;i++)中的变量i添加查看,运行代码时会显示optimized out,代表i这个变量的运行被编译器给优化了。如果你想查看这个值,你可以把-O2改成-O0(代表什么编译优化都不做)来进行查看。 - 但是,这样做可能会让你的未定义行为(简称为 ub)不被运行(比如数组越界)从而导致出现开
-O2与不开-O2结果不同,所以开启-O2后请避免出现未定义行为(你可以在参考文献中找到对其的进一步解释)。 - 同时,NOI 系列赛事均开启 O2 优化,所以在编译选项开启
-O2更接近评测环境。
- 举个例子,开启 O2 优化并对
-
设定栈空间为一个值(所以
-Wl,--stack=233333333为一条!)- 具体而言,我们 dfs 之内的递归函数使用栈空间,但是它太小了,可能装不下像对
10^6 量级对树遍历的空间,然后直接向你报告 re 的结果(但实际评测不会),所以加大栈空间是必要的 qwq。 - 但有一个事情是如果出现死循环的递归在老电脑上有卡死风险,所以不要开特别大。
- 具体而言,我们 dfs 之内的递归函数使用栈空间,但是它太小了,可能装不下像对
我编译器太老了!(devc++/vscode 同理)
如果你 devc++ 太老了,连 c++14 都没有,此时我的建议是重装 devc++。
在考场上但编译器太老时……(devc++,可能有地域因素导致不同情况)
有人就会说了: 我在考场上怎么下 devc++!
不用怕,一般情况下,下发文件中会有个叫 mingw 的神秘文件,它实际上是比较新的编译器(至少有 c++14),那么我们只要安装它就可以了!
首先我们把压缩包解压到 Dev-cpp 这个文件夹。
然后,我们把 MinGW64 这个文件夹移动到一个地方(防止你出问题),把刚才解压出来的文件夹重命名为 MinGW64。
接下来还是点开编译选项:
点击这个黄色加号安装编译器,选择确定:
然后你的编译器就装好啦!
记得重新写编译指令!
我说 namespace 好函数多用(只要是 c++ 就可以用!)
避免冲突
#include<bits/stdc++.h>
using namespace std;
//一段神秘代码
int main()
{
int y1,y0;
scanf("%d%d",&y0,&y1);
cout<<y0+y1;
return 0;
}
//又一段神秘代码
int y0,y1;
完啦!这可是两个函数名(实际上,他们是算贝塞尔函数的),你交上去包过不了编译的……吗?
再看看真正的原代码:
#include<bits/stdc++.h>
using namespace std;
namespace kanade//正常的字符串就行
{
int main()
{
int y1,y0;
scanf("%d%d",&y0,&y1);
cout<<y0+y1;
return 0;
}
}
int main()
{
kanade::main();
return 0;
}
namespace kanade 就是解决变量名冲突的一种使用方法!
原理也很简单:既然这个东西在 std 的命名空间下冲突,那我们可以把我们创造的新东西(包括 main() 函数)都放到 kanade 这个命名空间内不就行了!
但 c++ 代码需要一个不在命名空间的 main(),所以我们使用 kanade::main(); 调用即可(建议考场上把 freopen 放到这个不在命名空间的 main(),可以检查自己的 freopen。)
注:请把全局变量/函数放到
namespace内!
当然,如果你的一些代码经过封装(如fread模版),可以放到namespace外面。
封装代码
小 A 有个习惯,她习惯把她的平衡树与线段树都命名成 tree 数组,直到有一天,她遇到了一道又要用线段树又要用平衡树的毒瘤题 QWQ。
此时就可以使用 namespace 把平衡树与线段树的代码打包起来,就可以做到既清晰又解决了冲突!
//就像这样!
namespace fhq
{
int tree[1000010];
void ins();
}
int tree[1000010];
int main()
{
fhq::tree[0]=1;//调用命名空间的元素
fhq::ins();//调用命名空间的函数
tree[0]=2;//原住民
return 0;
}
资源管理器看空间特别强!(windows)
空间往往比时间更容易忽略,并且空间爆了,正解直接会爆零!
有大佬会算空间,比如 int 数组是 int 数组是
但有些递归函数就难算了……
//warning:不要轻易使用极大栈空间运行此代码!
void mafuyu(int k)//开始k=1
{
vector<int> mizuki;
int kanade=rand()%10000+1;
for(int i=1;i<=kanade;i++)mizuki.push_back(25);
if(k==100000)
{
cout<<"ena!";
return ;
}
mafuyu(k+1);
//实际上,不加下面这段代码前面使用的空间可能会被优化掉
for(int i=1;i<=kanade;i++)cout<<mizuki[i-1]<<endl;
}
更何况,这么多的函数与数组,要一个个算吗?
资源管理器堂堂登场!
找到它实际上很容易:
1.点开电脑下方的 Windows 按钮(红圈)
2.找到“Windows 管理工具”这个文件夹
3.点开并在最下方找到“资源监视器”即可。
注:当然你也可以打开任务管理器-选择性能,在页面下方打开资源监视器。
接下来,我们会看到这个画面,点击“内存”一项。
然后,在代码末尾加上 while(1)(或保证不让代码结束太快的方法),但记得结束测试后删除,接着运行代码:
最后,我们观察“提交”一项(上图的第
注:考试试机时一定要看资源监视器有没有设置密码。
别问我怎么知道的 QWQ
对拍约等于 selfeval!(linux 与 windows)
别再试图直接看大样例了!
虽然说有些样例只用输出一两个数字,但是也有这样的大数据……
但是我们有两大利器:来自 linux 的 diff 指令与来自 Windows 的 fc 函数!
她们的使用也很简单:在终端或 cmd 上输入diff/fc a.out b.out然后查看结果就可以了!
在 Windows 系统中,
fc作用于在 cmd 所在的对应文件夹,所以你可以在文件夹中把路径换成cmd后直接使用。
如果出现类似这样的画面,恭喜你,你过大样例了!
对拍不只是 c++!
对拍总之来说就是写一个能支持这些操作的数据结构程序脚本:
- 打开你写的数据生成器。
- 打开你的暴力。
- 打开你的要测试的代码。
- 使用
diff指令或fc指令并判断结果。 - 支持多次使用。
一般而言,你可以写这样的 c++ 代码(以 Windows 系统为例):
#include<bits/stdc++.h>
using namespace std;
int main(){
while(1){
system("make.exe");//生成数据
system("std.exe");//暴力代码
system("code.exe");//测试代码
if(system("fc std.out code.code"))break;//fc是有不同返回true!
}
return 0;
}
但有人就问了,主播主播,你的 c++ 代码很强,但有没有什么更好写的方法吗?
有的!在 Windows 系统,我们可以编写 bat 程序来直接对拍!
具体的,先新建一个记事本,往里面写下这样的代码(在 // 及之后的内容是注释,记得删除!)
:loop //不 要 写 反
make //跟c++代码本质相同
tree
std
fc ans.out tree.out
if %errorlevel% == 0 goto loop //判断,返回循环开头
pause //结束
然后你把文件后缀的 txt 改为 bat 后运行,你就发现你的程序就开始对拍了!
关于 linux 的脚本,个人认为较为繁琐,所以放在参考文献中供读者参考。
参考文献
C++对拍讲解。
一位大佬的 linux 对拍脚本。
爱来自 vjudge。
可以在此处参考教程下载 mingw 测试(记得存自己的编译器!)
关于未定义行为。