对拍教程
作用
用来辅助解决WA。
原理
与正确的暴力代码同时运行随机数据直到找到错误数据。
准备
需要四份代码:
-
std.cpp:暴力的基准程序,必须逻辑完全正确,只是超时 -
my.cpp:待提交程序 -
rand.cpp:生成随机数据 -
dp.cpp:对拍程序,循环调用上面三个程序,对比输出
流程
不妨以P3865为例
题意:给出一个数组,每次询问 \(l\) 到 \(r\) 之间的最大值。
std.cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int a[N];
int main()
{
int n,m;
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> a[i];
while(m--)
{
int l,r;
cin >> l >> r;
int res = a[l];
for(int i=l;i<=r;i++)
res = max(res,a[i]);
cout << res << endl;
}
return 0;
}
my.cpp
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 105;
int st[N][10];
int lg[N];
int main()
{
int n,m;
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> st[i][0];
for(int j=1;j<=7;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j] = max(st[i][j-1], st[i+(1<<(j-1))][j-1]);
while(m--)
{
int l,r;
cin >> l >> r;
int len = r-l+1;
int k = log2(len-1); //bug
int ans = max(st[l][k], st[r-(1<<k)+1][k]);
cout << ans << endl;
}
return 0;
}
ST 表查询 k 计算错误,k应为\(log2(len)\)
rand.cpp
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using namespace std;
int main()
{
srand((unsigned)time(0));
int n = rand()%100 + 1; //1~100
int m = rand()%100 + 1; //1~100
cout << n << " " << m << endl;
for(int i=1;i<=n;i++)
cout << rand()%1000001 << " ";
cout << endl;
for(int i=1;i<=m;i++)
{
int l = rand()%n + 1;
int r = rand()%n + 1;
if(l>r) swap(l,r);
cout << l << " " << r << endl;
}
return 0;
}
dp.cpp
适用于windows系统
#include <iostream>
#include <cstdlib>
using namespace std;
int main(){
int cnt=0;
while(true){
cnt++;
cout<<"Test "<<cnt<<endl;
system("rand.exe > in.txt");
system("std.exe < in.txt > std.txt");
system("my.exe < in.txt > my.txt");
if(system("fc std.txt my.txt >nul")){
cout<<"WA"<<endl;
break;
}
}
return 0;
}
编译&运行
g++ rand.cpp -o rand.exe
g++ std.cpp -o std.exe
g++ my.cpp -o my.exe
g++ dp.cpp -o dp.exe
dp.exe
一旦 WA,in.txt 就是出错测试点,单独调试:my.exe < in.txt
注:linux系统将对拍判断行替换为if(system("diff std.txt my.txt >/dev/null"))
SPJ
普通对拍要求一字不差,但SPJ题目答案不唯一,直接使用对拍可能造成误判
思路
不能对比 std 和 my 的输出文本,专门写一个SPJ校验程序即可。
输入:in.txt(原始输入) + my.txt(你的程序输出)
spj 读入输入 + 读你的输出,判断输出是否符合题目要求,合格返回 0,不合格返回非 0。
对拍器调用 spj,不再对比 std.txt。
修改的dp.cpp
#include <iostream>
#include <cstdlib>
using namespace std;
int main(){
int cnt=0;
while(true){
cnt++;
cout<<"Test "<<cnt<<endl;
system("rand.exe > in.txt");
system("my.exe < in.txt > my.txt");
if(system("spj.exe < in.txt my.txt")){
cout<<"WA"<<endl;
break;
}
cout<<"AC"<<endl;
}
return 0;
}
注意:spj 的参数写法看 spj 代码怎么读文件。两种常见写法:
-
spj.exe in.txt my.txt(命令行传文件名) -
spj.exe < in.txt > ...标准输入读入

对拍
浙公网安备 33010602011771号