浅谈spj

SPJ(special judge)是个好玩的东西,毕竟各种神奇的题目SPJ常常做为救火工具(好比说一不当心出成验证类的题目)。ios

但SPJ是个坑,毕竟只让用个“testlib.h”,输入还特别奇怪。今天我就带你们来玩一玩这个奇怪的东西框架

写在前面:函数

原本已经退役了暂时不打算补坑,但今天赶上了静静(咱们教练)让我教她SPJ,因而索性把这篇文章的坑补完工具

1、明确内容ui

SPJ整体上主要分两大类:精度判断(lemon上叫实数比较)和方案验证。这两个东西其实思路彻底不是一码事。spa

不过因为都是基于SPJ比较的大框架,因此都被纳入SPJ。在开动以前咱们必须明确你到底要写哪一个,否则可能绕来绕去费上老半天劲儿还得返工。3d

2、操做简介(如下内容部分来自luogu的SPJ帮助,可是有部分修改,请当心食用)指针

1.读入部分code

void registerTestlibCmd(argc, argv)

初始化checker,必须在最前面调用一次。blog

char a=readChar()

读入一个char,指针后移一位。

char a=readChar(char c)

和上面同样,可是只能读到一个字母c

char a=readSpace()

同 readChar(' ').

string a=readToken()

读入一个字符串,可是遇到空格、换行、eof为止、

long long a=readLong()

读入一个longlong/int64

long long a=readLong(long long L, long long R)

同上,可是限定范围(包括L,R)

int a=readInt()

读入一个int

int a=readInt(int L, int R),

同上,可是限定范围(包括L,R)`

double a=readReal()

读入一个实数

double a=readReal(double L, double R),

同上,可是限定范围(包括L,R)

double a=readStrictReal(double L, double R, int minPrecision, int maxPrecision),

读入一个限定范围精度位数的实数。

string a=readString(), string a=readLine()

读入一行string,到换行或者eof为止

void readEoln()

读入一个换行符

void readEof()

读入一个eof

int a=eof()

2.输出部分

给出AC

quitf(\_ok, "The answer is correct. answer is %d", ans);

给出WA

quitf(\_wa, "The answer is wrong: expected = %f, found = %f", jans, pans);

给出PC(Partially Correct),而且能够得到该点50%的分数

quitp(0.5,"Partially Correct get %d percent", 50);

步骤分解:

关于输入:

输入部分没有什么好强调的,写过快读的同窗都知道正确的写法。定义一个变量等于输入函数返回的值便可。

但须要注意的是,SPJ不是一个普通的C++程序,他使用的库是

#include“testlib.h”

因此,C++的不少操做在SPJ里是不能使用的。典型表明就是输入输出。你能且仅能使用上面提供的的读入方式。"cin",“printf”之类的东西都会让你CE

关于输出:

一句话说不清,各位请看下图

 AC版

引号里的内容等价于上图的黑底白字部分

WA版

PC版(这个与上面的稍有不一样)

3、实例分析

精度判断

精度判断相对于后者很简单,由于精度判断其实基本与常规评测模式并没有差别。咱们一般只须要判断选手答案与正确答案的差别是否在精度范围内。

因此使用SPJ的方式读入标准答案文件与选手输出文件,进行进度比较便可。

实战样例:

luoguP2164

这道题的SPJ属于典型的精度比较类

由于保留一位小数,因此存在向下,向上,四舍五入等多种保留方式(题目中并无规定)

因此咱们考虑规定偏差为0.1,直接偏差比较便可

实例代码:

#include"testlib.h"//专属头文件不可少
using namespace std; #define rii register int i 
double eps=0.1; int n,m; int main(int argc,char *argv[])//流文件操做莫忘掉
{ registerTestlibCmd(argc,argv);//初始化checker要记牢
    n=inf.readInt(); m=inf.readInt(); for(rii=1;i<=m;i++) { double a1=ans.readDouble(); double a2=ouf.readDouble(); if(abs(a1-a2)>eps)//貌似cmath库直接集成,不须要本身写
 { quitf(_wa,"wrong answer on line %d",i);//给出错误结果 } } quitf(_ok,"correct answer");//给出正确结果 return 0; }

 luoguP3516

这是一个典型的验证类SPJ

给定一个方案,让你检验是否能达到要求的目的

两类操做:

(a) 将最后一个数移到最前面

(b) 把第三个数移到最前面

对于每一个操做,咱们简单的写一个双向链表维护便可

而后对于完成全部操做的序列,咱们须要进行一次比较

判断得出的序列与给定的标准序列是否相同

而后按位比较便可

具体操做详见代码中的注释(以码风为界,分别为我和苏卿念写的【哪一个是谁靠本身猜吧】)

#include "testlib.h" #include <ctime> 
using namespace std; struct lb{ int pre,nxt,val; }x[2005]; int n,cnt,head,tail; void ltof(int num)//一号双向链表操做,把末尾的元素移到头部 { while(num--) { int ls=x[tail].pre; x[ls].nxt=0; x[tail].nxt=head; x[tail].pre=0; x[head].pre=tail; head=tail; tail=ls; } } void ttof(int num)//二号双向链表操做:第三个移到第一个 { while(num--) { int cnt=0; int ls=head; for(int i=1;i<=2;i++) { ls=x[ls].nxt; } int forth=x[ls].nxt; int kkk=x[ls].pre; x[forth].pre=kkk; x[kkk].nxt=x[ls].nxt; x[ls].pre=0; x[ls].nxt=head; x[head].pre=ls; head=ls; } } void change(int num,int cz){//此函数用于判断操做 if(cz==0) ltof(num); else ttof(num); } char opt;int now; char pos; int m; int main(int argc,char *argv[]) {//真正的spj主程序开始了 registerTestlibCmd(argc,argv);、、初始化输入 n=inf.readInt(); for(int i=1;i<=n;i++) x[i].val=inf.readInt(),x[i].pre=i-1,x[i].nxt=i+1;//输入原始序列,并构造链表 head=1,tail=n;int qnt=1; opt=ans.readChar();//读入操做类型 if(opt=='N') {//判断操做类型 pos=ouf.readChar();//读入操做数 if(pos!='N') quitf(_wa,"expect NIE found %c.score:pqp",pos); pos=ouf.readChar(); if(pos!='I') quitf(_wa,"expect IE found %c.score:pqp",pos); pos=ouf.readChar(); if(pos!='E') quitf(_wa,"expect E found %c.score:pqp",pos); pos=ouf.readChar(); if(pos=='\n'||pos==3||pos==26) quitf(_ok,"the answer ios corect .score:qaq"); if(pos!=' ') quitf(_wa,"expect found %c.score:pqp",pos); pos=ouf.readChar(); if(pos!='D') quitf(_wa,"expect DA found %c.score:pqp",pos); pos=ouf.readChar(); if(pos!='A') quitf(_wa,"expect A found %c.score:pqp",pos); pos=ouf.readChar(); if(pos!=' ') quitf(_wa,"expect found %c.score:pqp",pos); pos=ouf.readChar(); if(pos!='S') quitf(_wa,"expect SIE found %c.score:pqp",pos); pos=ouf.readChar(); if(pos!='I') quitf(_wa,"expect IE found %c.score:pqp",pos); pos=ouf.readChar(); if(pos!='E') quitf(_wa,"expect E found %c.score:pqp",pos); quitf(_ok,"the answer ios corect .score:qaq"); } m=ouf.readInt(); if(n==1&&m==0) {quitf(_ok,"correct answer");return 0;} else if(n==1) {quitf(_wa,"wrong answer");return 0;} for(int i=1;i<=m;i++){ pos=0;now=0; pos=ouf.readChar(); while(pos>'9'||pos<'0') pos=ouf.readChar(); while(pos<='9'&&pos>='0') now=now*10+pos-'0',pos=ouf.readChar(); if(now<=0||now>n) quitf(_wa,"wrong output on operation %d,found %d,expect in [ 1 , %d ] .score:vov",i,now,n); if(pos=='b') now%=3; if(pos=='a') now%=n; change(now,pos=='b'); } int wz=head; while(wz!=tail){ int nxt=x[wz].nxt; if(x[nxt].val<x[wz].val){ quitf(_wa,"wrong answer"); return 0; } wz=nxt; } if(x[x[tail].pre].val>x[tail].val) quitf(_wa,"worong answer "); else quitf(_ok,"correct answer "); return 0; }

 

未完待续……

相关文章
相关标签/搜索