对拍+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.cpp
和 WA.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
为读入,ans.out
为正确输出。
$$\texttt{Debug}$$
众所周知,输出调试法是一种很方便的 Debug 方法,但这个世界上,往往有些人是记忆力不佳的比如我,常常会忘记删除调试语句导致爆 \(0\),那么有没有什么东西是可以避免的呢?那就是 cerr
。
一些知识
当你没有 freopen
时。
你的程序有三个读入输出部分 stdin
(标准读入),stdout
(标准输出),还有一个神秘的非缓冲输出流,评测系统是不会接收它的。
活 用 cerr
比如你要输出一个变量 \(x\),你可以 cerr << x;
类似用法很多,但注意:cerr
的时间复杂度比 cout
更高!
所以尽量还是要记得注释或删除调试语句哦!
Update
upd2023.07.27
今日突然发现,run.bat 是可以双击运行的,但貌似在某些情况下会出 bug,任务管理器首次遇到劲敌。(感谢 @yabnto 的奉献)