对拍教程

作用

用来辅助解决WA。

原理

与正确的暴力代码同时运行随机数据直到找到错误数据。

准备

需要四份代码:

  1. std.cpp:暴力的基准程序,必须逻辑完全正确,只是超时

  2. my.cpp:待提交程序

  3. rand.cpp:生成随机数据

  4. 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 代码怎么读文件。两种常见写法:

  1. spj.exe in.txt my.txt (命令行传文件名)

  2. spj.exe < in.txt > ... 标准输入读入

posted @ 2026-10-02 20:56  axiom  阅读(9)  评论(0)    收藏  举报
/* 设置动态特效 */