对拍方法
对拍很简单,原理是:比较 \(2\) 个代码的输出,也就是用暴力代码检查你的代码的正确性。而只需要你记住程序怎么打就行。
对拍的程序有 \(4\) 个:
my.cpp:你的程序。通常是不确定是否切题的时候,再决定打对拍(做接下来的事)。bl.cpp:暴力程序。一般情况下,造数据时要考虑到其时间复杂度。而且,如果暴力的时间复杂度过高(如指数级别),有可能整场比赛结束了都跑不完,这个时候就不要打对拍了。data.exe:用来造数据的,具体情况视题目而定。最好是记常用的方法:比如造树、图等。checker.exe:用来自动运行前 \(3\) 个程序,并比较你的程序和暴力程序的输出。
顺便提一嘴,你的程序都要加文操,方便 \(\text{checker}\) 自动运行程序。
以 P3178 [HAOI2015] 树上操作 为例。
my.cpp
// 对拍方法(正解)
#include<bits/stdc++.h>
typedef int IT;
typedef long long LL;
typedef __int128 int128;
typedef double DB;
typedef long double LDB;
#define pb push_back
#define fst first
#define sec second
#define psh push
#define mkp make_pair
#define PII pair<IT,IT>
#define PLI pair<LL,IT>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int N=1e5+10,ES=N<<1;
int n,m;
int a[N];
int ecnt,head[N],nxt[ES],to[ES];
void add(int x,int y){
nxt[++ecnt]=head[x];
head[x]=ecnt;
to[ecnt]=y;
return;
}
int dep[N],siz[N],fa[N],son[N];
void dfs1(int x,int fth){
dep[x]=dep[fth]+1;
siz[x]=1;
fa[x]=fth;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fth) continue;
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]])
son[x]=y;
}
}
int top[N];
int id[N],idx;
int newa[N];
void dfs2(int x,int ntop){
top[x]=ntop;
id[x]=++idx;
newa[idx]=a[x];
if(!son[x]) return;
dfs2(son[x],ntop);
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y!=fa[x]&&y!=son[x])
dfs2(y,y);
}
}
struct Seg_Tree{
LL sum;
LL tag;
}t[N<<2];
void pushup(int rt){
t[rt].sum=t[rt<<1].sum+t[rt<<1|1].sum;
return;
}
void downtag(int rt,int l,int r,LL v){
t[rt].sum+=(r-l+1)*v;
t[rt].tag+=v;
return;
}
void pushdown(int rt,int l,int r){
if(t[rt].tag){
int mid=(l+r)>>1;
downtag(rt<<1,l,mid,t[rt].tag);
downtag(rt<<1|1,mid+1,r,t[rt].tag);
t[rt].tag=0;
}
}
void build(int rt,int l,int r){
if(l==r){
t[rt].sum=newa[l];
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
return;
}
void modify(int rt,int l,int r,int ml,int mr,LL v){
if(r<ml||mr<l) return;
if(ml<=l&&r<=mr){
downtag(rt,l,r,v);
return;
}
pushdown(rt,l,r);
int mid=(l+r)>>1;
modify(rt<<1,l,mid,ml,mr,v);
modify(rt<<1|1,mid+1,r,ml,mr,v);
pushup(rt);
return;
}
LL query(int rt,int l,int r,int ql,int qr){
if(r<ql||qr<l) return 0;
if(ql<=l&&r<=qr) return t[rt].sum;
pushdown(rt,l,r);
int mid=(l+r)>>1;
return query(rt<<1,l,mid,ql,qr)+
query(rt<<1|1,mid+1,r,ql,qr);
}
LL SP_query(int x,int y){
LL ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=query(1,1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=query(1,1,n,id[x],id[y]);
return ans;
}
int main(){
freopen("data.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++){
int opt,x,a;
scanf("%d",&opt);
if(opt==1){
scanf("%d%d",&x,&a);
modify(1,1,n,id[x],id[x],a);
}
else if(opt==2){
scanf("%d%d",&x,&a);
modify(1,1,n,id[x],id[x]+siz[x]-1,a);
}
else if(opt==3){
scanf("%d",&x);
printf("%lld\n",SP_query(1,x));
}
}
return 0;
}
bl.cpp
// 对拍方法(暴力)
#include<bits/stdc++.h>
typedef int IT;
typedef long long LL;
typedef __int128 int128;
typedef double DB;
typedef long double LDB;
#define pb push_back
#define fst first
#define sec second
#define psh push
#define mkp make_pair
#define PII pair<IT,IT>
#define PLI pair<LL,IT>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int N=1e5+10,ES=N<<1;
int n,m;
int a[N];
int ecnt,head[N],nxt[ES],to[ES];
void add(int x,int y){
nxt[++ecnt]=head[x];
head[x]=ecnt;
to[ecnt]=y;
return;
}
int dep[N],siz[N],fa[N];
int id[N],idx;
void dfs(int x,int fth){
dep[x]=dep[fth]+1;
siz[x]=1;
fa[x]=fth;
id[x]=++idx;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fth) continue;
dfs(y,x);
siz[x]+=siz[y];
}
}
LL d[N];
int main(){
freopen("data.in","r",stdin);
freopen("bl.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs(1,0);
for(int i=1;i<=n;i++) d[id[i]]=a[i];
for(int i=1;i<=m;i++){
int opt,x,y;
scanf("%d",&opt);
if(opt==1){
scanf("%d%d",&x,&y);
d[id[x]]+=y;
}
else if(opt==2){
scanf("%d%d",&x,&y);
for(int i=id[x];i<=id[x]+siz[x]-1;i++)
d[i]+=y;
}
else if(opt==3){
scanf("%d",&x);
int t=x;
LL ans=0;
while(t!=1){
ans+=d[id[t]];
t=fa[t];
}
ans+=d[1];
printf("%lld\n",ans);
}
}
return 0;
}
data.cpp
// 对拍方法(造数据)
#include<bits/stdc++.h>
typedef int IT;
typedef long long LL;
typedef __int128 int128;
typedef double DB;
typedef long double LDB;
#define pb push_back
#define fst first
#define sec second
#define psh push
#define mkp make_pair
#define PII pair<IT,IT>
#define PLI pair<LL,IT>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int N=2e5+10;
int n,m;
int fa[N];
int findfa(int x){return fa[x]==x?x:fa[x]=findfa(fa[x]);}
struct edge{
int u,v;
}e[N];
int ord[N];
int main(){
srand((int)(time(0)));
freopen("data.in","w",stdout);
n=10;m=10000;
printf("%d %d\n",n,m);
for(int i=1;i<=n;i++){
int x=rand()%IT(1e6)+1;
printf("%d ",x);
}putchar('\n');
// for(int i=2;i<=n;i++){
// e[i].u=i;
// e[i].v=rand()%(i-1)+1;
// }
// for(int i=1;i<n;i++) ord[i]=i+1;
// random_shuffle(ord+1,ord+n);
// for(int i=n;i>=2;i--) ord[i]=ord[i-1];
// for(int i=2;i<=n;i++){
// printf("%d %d\n",e[ord[i]].u,e[ord[i]].v);
// }
for(int i=1;i<=n;i++) fa[i]=i;
int i=1;
while(i<=n-1){
int x=rand()%n+1,y=rand()%n+1;
while(x==y) y=rand()%n+1;
int p=findfa(x),q=findfa(y);
if(p!=q){
fa[p]=q;
i++;
printf("%d %d\n",x,y);
}
}
int R=1e6+1e6+1;
for(int i=1;i<=m;i++){
int opt,x,a;
opt=rand()%3+1;
printf("%d ",opt);
x=rand()%n+1;
a=rand()%R;
a-=1e6;
if(opt==1|opt==2){
printf("%d %d\n",x,a);
}
else if(opt==3) printf("%d\n",x);
}
return 0;
}
checker.cpp
// 对拍方法(checker)
#include<bits/stdc++.h>
typedef int IT;
typedef long long LL;
typedef __int128 int128;
typedef double DB;
typedef long double LDB;
#define pb push_back
#define fst first
#define sec second
#define psh push
#define mkp make_pair
#define PII pair<IT,IT>
#define PLI pair<LL,IT>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int N=2e5+10;
DB st,ed,mt;
int main(){
for(int t=1;t<=500;t++){
printf("Task %d:\n",t);
printf("Generating the data.\n");
system("data.exe");// 造数据
printf("Running bl.cpp program...\n");
st=clock();
system("bl.exe");// 运行暴力程序
ed=clock();
mt=(ed-st)/1e3;
printf("It used %.3lf s.\n",mt);
printf("Running my.cpp program...\n");
st=clock();// 计时
system("my.exe");// 运行你的程序
ed=clock();// 计时
mt=(ed-st)/1e3;// 计算
printf("You used %.3lf s.\n",mt);// 运行所耗时间
if(mt>1){// 超时
printf("TLE!\n");
return 0;
}
if(!system("fc my.out bl.out")) printf("AC!\n\n");// 输出一样
else{// 不一样
printf("WA!\n");
return 0;
}
}
printf("Congratulations!\n");// 这些数据都对了
return 0;
}
(提醒一下同机房的同学:你可以对着打,但不要直接复制)
对拍是个好东西,如果记住了,有时能在考场上发挥大作用。

浙公网安备 33010602011771号