对拍+Debug

$$\texttt{对拍}$$

\(\color{red}\texttt{调用对拍前请先使用非第四类编辑器(codeblocks)运行一遍代码,生成 exe 文件后继续(感谢 yabnto 提醒)}\)

对拍,可以解决程序出错而又不能靠静态差错或手造数据 hack 的问题,让电脑来查找 hack 数据。

前置准备

在同一目录下的文件:AC.cpp(存储正确但可能 TLE 的代码),WA.cpp(存储你需要对拍的代码),gen.cpp(随机数生成程序,因题而异)。

代码准备

随机数程序:gen.cpp

有一个东西,叫 rand(),直接输出它,却发现根本不随机,因为没有给出随机种子。

在前面加上一个 srand(time(0)),给它一个随机种子,再度尝试,发现它变得随机了!兴奋之下,一下连点了许多下运行,却发现好像又不那么随机。

因为 time(0) 其实返回的是当前时间距离 1970 年 1 月 1 日 00:00:00 的秒数(格林尼治标准时间),所以当你在 1 秒内输出多个随机出来的数,这些数都是相等的。

这时候,就要请出我们的 mt19937 了。

示例代码

int main (int argc, char *argv[]) {
  // mt19937_64 rnd(atoi(argv[1])); // long long 范围
  mt19937 rnd(atoi(argv[1])); // 随机种子,随机性强,int 范围
  int x; // 随机范围
  cin >> x;
  int n = rnd() % x; // 调用随机生成函数
  ......
}

加强版!

using u64 = unsigned long long;

int main (int argc, char *argv[]) {
  u64 seed = time(0);
  if (argc > 1) {
    seed = seed * 32768 + atoi(argv[1]);
  }
  mt19937 rnd(seed); // 随机种子,随机性更强,int 范围
  int x; // 随机范围
  cin >> x;
  int n = rnd() % x; // 调用随机生成函数
  ......
}

运行方法

要求:至少为 C++14。

新建一个 random.bat,与 gen.cpp 在同一目录下。

接下来操作见下方。

AC.cppWA.cpp

略,不用freopen

正式开始对拍

新建一个 run.bat,与前面的文件在同一目录下。

注意你不能直接运行这个文件,可以考虑用记事本或其他的编辑器(VS Code 可以)打开。

另:它只能在 Windows 系统下执行。

代码部分

@echo off
:flag
gen %RANDOM% > test.in
ac < test.in > ans.out
wa < test.in > test.out
fc ans.out test.out
if not errorlevel 1 goto flag
pause

代码解析

  • @echo off 减少部分终端的无用输出,可以不要。
  • :flag 一个循环部分的开始。
  • gen %RANDOM% > test.in 调用 gen.cpp,生成读入文件 test.in
  • ac < test.in > ans.out 调用 AC.cpp(大小写不敏感),输入 test.in,输出 ans.out
  • wa < test.in > test.out 调用 WA.cpp,输入 test.in,输出 test.out
  • fc ans.out test.out 判断 ans.out 是否和 test.out 相同。
  • if not errorlevel 1 goto flag 如果相同,则继续执行 flag 循环;否则终止。
  • pause 在部分系统下,bat 会直接终止,这行代码会强行暂停,等待按下任意键。

调用方法

打开 cmd,进入存储的文件夹,再输入 run 即可,没能 hack 的数据会被覆盖。


cmd 的部分使用方法:

  • 进入 D 盘:D:
  • 打开名为 abc 的文件夹:cd abc
  • 退回上一个打开的文件夹(例如 D:/abc/def 去往 D:/abc):cd ..

所以,最终剩下的就是 hack 数据了!test.in 为读入,test.out 为正确输出。

$$\texttt{Debug}$$

众所周知,输出调试法是一种很方便的 Debug 方法,但这个世界上,往往有些人是记忆力不佳的比如我,常常会忘记删除调试语句导致爆 \(0\),那么有没有什么东西是可以避免的呢?那就是 cerr

一些知识

当你没有 freopen 时。

你的程序有三个读入输出部分 stdin(标准读入),stdout(标准输出),还有一个神秘的非缓冲输出流,评测系统是不会接收它的。

活 用 cerr

比如你要输出一个变量 \(x\),你可以 cerr << x;

类似用法很多,但注意:cerr 的时间复杂度比 cout 更高!

所以尽量还是要记得注释或删除调试语句哦!

Update

upd2023.07.27

今日突然发现,run.bat 是可以双击运行的,但貌似在某些情况下会出 bug,任务管理器首次遇到劲敌。(感谢 @yabnto 的奉献)

posted @ 2023-07-18 16:09  wnsyou  阅读(219)  评论(2编辑  收藏  举报