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的方式讀入標準答案文件與選手輸出文件,進行進度比較便可。
實戰樣例:
這道題的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; }
這是一個典型的驗證類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; }
未完待續……