淺談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; }

 

未完待續……

相關文章
相關標籤/搜索