SCP-J 2026 重现赛
已结束
IOI
开始于: 2026-10-21 17:00
100
小时
主持人:
6
SCP-J 2026 重现赛
/*
========================================
C++ 对拍程序使用说明
========================================
一、什么是对拍?
对拍是一种检查程序正确性的方法。
基本思路:
1. 编写一份自己需要检查的代码(std.cpp)。
2. 编写一份保证正确的暴力代码(brute.cpp)。
3. 随机生成大量测试数据。
4. 让两份程序运行相同的测试数据。
5. 比较两份程序的输出是否一致。
如果输出不一致,说明至少有一份程序存在问题,
此时输出对应的测试数据,方便定位错误。
----------------------------------------
二、使用前的准备工作
需要准备以下三个 C++ 文件:
1. std.cpp
自己编写的待检查代码(通常是正解或优化算法)。
2. brute.cpp
保证正确的暴力代码。
暴力代码可以运行得慢一些,但必须保证结果正确。
3. check.cpp
当前这个对拍程序,用来生成随机数据、
运行两份程序并比较答案。
----------------------------------------
三、编译三个程序
在终端中执行:
g++ std.cpp -o std.exe
g++ brute.cpp -o brute.exe
g++ check.cpp -o check.exe
编译完成后,会生成三个可执行文件:
std.exe
brute.exe
check.exe
----------------------------------------
四、修改输入输出
由于本程序使用文件进行对拍,因此需要保证:
1. std.cpp 从 1.in 读取,向 std.out 输出。
2. brute.cpp 从 1.in 读取,向 brute.out 输出。
可以在两份程序的 main() 开头分别添加:
std.cpp:
freopen("1.in", "r", stdin);
freopen("std.out", "w", stdout);
brute.cpp:
freopen("1.in", "r", stdin);
freopen("brute.out", "w", stdout);
注意:两份程序读取的输入文件必须相同,
但输出文件必须不同。
----------------------------------------
五、修改随机数据生成器
根据题目的输入格式,修改 gen() 函数。
例如当前代码生成的数据格式为:
第一行:一个整数 n,范围为 [1, 10]。
第二行:n 个整数,每个整数范围为 [1, 10]。
如果题目的输入格式发生变化,
则需要修改 gen() 中的数据生成方式。
----------------------------------------
六、开始对拍
在终端运行:
.\check.exe
程序将不断执行:
生成随机数据
↓
运行 std.exe
↓
运行 brute.exe
↓
比较 std.out 和 brute.out
↓
答案相同:继续生成下一组数据
答案不同:输出出错的数据,停止对拍
找到错误后,可以直接查看 1.in 文件,
将其作为反例进行调试。
----------------------------------------
七、注意事项
1. 本程序适用于 Windows 系统。
其中 fc /b 是 Windows 的文件比较命令。
2. 三个 exe 文件应放在同一个工作目录下。
3. 修改 std.cpp 或 brute.cpp 后,必须重新编译。
4. 暴力程序必须保证正确,否则对拍没有意义。
5. 当前程序比较的是输出文件的每个字节,
因此空格、换行不同,也可能被判定为不一致。
6. 如果程序死循环或者运行时间过长,
当前对拍程序不会自动终止超时进程。
========================================
*/
#include <bits/stdc++.h> // 引入 C++ 常用标准库
using namespace std; // 使用标准命名空间
// 创建随机数生成器
// mt19937 是一种高质量的伪随机数生成器
// time(0) 使用当前时间作为随机种子,使每次运行生成的数据不同
mt19937 rnd(time(0));
// 生成一个范围在 [l, r] 内的随机整数(包含两端)
int f(int l, int r)
{
// rnd() 生成一个随机数
// % (r - l + 1) 将其限制在 [0, r-l]
// 再加上 l,得到 [l, r] 内的随机整数
return rnd() % (r - l + 1) + l;
}
// 随机数据生成函数
// 每调用一次,就生成一组新的测试数据
void gen()
{
// 创建输出文件 1.in
// 如果文件已经存在,会覆盖原来的内容
ofstream out("1.in");
// 随机生成一个 [1, 10] 的整数 n
int n = f(1, 10);
// 将 n 写入 1.in,并换行
out << n << "\n";
// 生成 n 个随机整数
for (int i = 1; i <= n; i++)
{
// 随机生成一个 [1, 10] 的整数
int a = f(1, 10);
// 将随机数写入文件,用空格分隔
out << a << " ";
}
// 最后输出一个换行
out << "\n";
// 函数结束后,out 自动关闭
// 此时随机测试数据已经写入 1.in
}
int main()
{
// 无限循环,不断生成数据并进行对拍
// 直到找到两份程序输出不同的测试数据
while (true)
{
// 生成一组新的随机测试数据,保存到 1.in
gen();
// 运行待检查程序 std.exe
// std.exe 读取 1.in,结果写入 std.out
system("std.exe");
// 运行暴力程序 brute.exe
// brute.exe 读取 1.in,结果写入 brute.out
system("brute.exe");
// 比较两个输出文件的内容
// fc 是 Windows 下的文件比较命令
// /b 表示按二进制逐字节比较
// > nul 表示不显示比较命令的输出信息
// 两个文件相同,返回值通常为 0
// 两个文件不同,返回值非 0
int res = system("fc /b std.out brute.out > nul");
// 如果两份程序的输出不一致
if (res != 0)
{
// 打开当前出错的测试数据文件
ifstream in("1.in");
// 将文件中的全部内容输出到控制台
// rdbuf() 可以直接读取文件的整个缓冲区
cout << in.rdbuf();
// 找到反例,退出无限循环,停止对拍
break;
}
// 如果输出一致,就继续下一轮循环
// 再生成一组新数据进行测试
}
// 程序正常结束
return 0;
}
- 状态
- 已结束
- 规则
- IOI
- 题目
- 4
- 开始于
- 2026-10-21 17:00
- 结束于
- 2026-10-25 21:00
- 持续时间
- 100 小时
- 主持人
- 参赛人数
- 6