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
他们的意思如下:

我编译器太老了!(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)

空间往往比时间更容易忽略,并且空间爆了,正解直接会爆零!
有大佬会算空间,比如 10^8int 数组是 400 MB 左右,10^7int 数组是 40 MB 左右……
但有些递归函数就难算了……

//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)(或保证不让代码结束太快的方法),但记得结束测试后删除,接着运行代码:
最后,我们观察“提交”一项(上图的第 3 个数字)就可以快速的知道这个程序的空间啦!(这个程序竟然用了 2 GB!)

注:考试试机时一定要看资源监视器有没有设置密码。
别问我怎么知道的 QWQ

对拍约等于 selfeval!(linux 与 windows)

别再试图直接看大样例了!

虽然说有些样例只用输出一两个数字,但是也有这样的大数据……


但是我们有两大利器:来自 linux 的 diff 指令与来自 Windows 的 fc 函数!
她们的使用也很简单:在终端或 cmd 上输入diff/fc a.out b.out然后查看结果就可以了!

在 Windows 系统中,fc 作用于在 cmd 所在的对应文件夹,所以你可以在文件夹中把路径换成 cmd 后直接使用。

如果出现类似这样的画面,恭喜你,你过大样例了!

对拍不只是 c++!

对拍总之来说就是写一个能支持这些操作的数据结构程序脚本:

一般而言,你可以写这样的 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 测试(记得存自己的编译器!)
关于未定义行为。