对拍很简单,原理是:比较 \(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;
}
(提醒一下同机房的同学:你可以对着打,但不要直接复制)
对拍是个好东西,如果记住了,有时能在考场上发挥大作用。