首先你要会写一个叫$data.yml$的东西,

这里面记录了这道题的$subtask$计分策略

也告诉了评测姬这道题是提交答案还是$spj$还是交互题

那么,$YAML$语言是啥啊?

别问我,我也不会 本着会用能用就行的原则

给大家讲讲$LOJ$的$special\ jidge$怎么用

$yaml$里基本上的全部语法:

$Structure$通过空格来展示。$Sequence$里的项用$-$来代表,Map里的键值对用$:$分隔.

在$LOJ$我们需要写一份类似这样的$data.yml$文件:

(摘自 LOJ帮助 ,稍有改动)

subtasks:           # 定义subtask
- score: 30 # 这个子任务的分数(注意,所有子任务的总分必须为 100)
type: sum # 子任务类型,可选的值有 sum、min 和 mul.
cases: [1, 2, 3] # 测试点编号可为数字
- score: 30 # 另一个子任务
type: mul        #sum:求和 mul:求积之后折合回100 min:取最小值按百分比折合
cases: ['4', '5', '6'] # 测试点编号也可为字符串
inputFile: 'dat#.in' # 告诉评测姬你测试数据包中的输入文件
outputFile: 'dat#.ans' # 告诉评测姬你测试数据包中的输出文件
# 上述文件名中的 '#' 字符将被替换为测试点编号,eg:dat1.in,dat1.out # Special Judge 可省略
specialJudge:
language: cpp      #语言,这里用简称 
fileName: spj.cpp    #这里是你 答案检查器 的名子,后缀最好要和language一样(没试过不一样行不行)

语言简称:ccppcpp11csharphaskelljavalualuajitnodejspascalpython2python3rubyvalavbnetocam

这里开始举个栗子,$A+B\ problem$ ,$10$个测试点,为$data1.in,data1.out \~ data10.in,data10.out$。

然后

  对于30%的数据,a,b<=100;

  对于另30%的数据,a,b<=1000000;

  对于另40%的数据,a,b<=100000000000000000000000000000000000000000000000000000000000000000;

这时候,你的$data.yml$里就要这样写:

subtasks:
- score: 30
type: sum
cases: [1, 2, 3]
- score: 30
type: mul
cases: [4, 5, 6]
- score: 40
cases: [7, 8, 9, 10] inputFile: 'data#.in'
outputFile: 'data#.out'

然后对于某沙华大佬的那道题,需要有$spj$

subtasks:
- score: 12
type: sum
cases: ['01-14','02-1234','03-1234','04-14','05-1234','06-1234','07-1234','08-1234','09-14','10-1234','11-134','12p-1234','23p-1234']
- score: 15
type: sum
cases: ['02-1234','03-1234','05-1234','06-1234','07-1234','08-1234','10-1234','12p-1234','13-234','14-234','15-234','16-234','17-234','18-234','19-234','20-234','21-234','22-234','23p-1234','24-234','25-234','26-234','27-234','28-234','29-234','30-234','31-234','32-234','33-234','34-234']
- score: 23
type: sum
cases: ['02-1234','03-1234','05-1234','06-1234','07-1234','08-1234','10-1234','11-134','12p-1234','13-234','14-234','15-234','16-234','17-234','18-234','19-234','20-234','21-234','22-234','23p-1234','24-234','25-234','26-234','27-234','28-234','29-234','30-234','31-234','32-234','33-234','34-234','35-34','36-34','37-34','38-34','39-34','40-34','41-34','42-34']
- score: 50
type: sum
cases: ['01-14','02-1234','03-1234','04-14','05-1234','06-1234','07-1234','08-1234','09-14','10-1234','11-134','12p-1234','13-234','14-234','15-234','16-234','17-234','18-234','19-234','20-234','21-234','22-234','23p-1234','24-234','25-234','26-234','27-234','28-234','29-234','30-234','31-234','32-234','33-234','34-234','35-34','36-34','37-34','38-34','39-34','40-34','41-34','42-34','43-4','44-4','45-4','46-4','47-4','48-4','49-4','50-4','51-4','52-4','53-4','54-4','55-4','56-4','57-4','58-4','59-4','60-4','61-4','62-4','63-4','64-4','65-4','66-4'] inputFile: 'demarcation.#.in'
outputFile: 'demarcation.#.sol' specialJudge:
- language: cpp11
fileName: spj_cpp11.cpp
 - language: cpp
   fileName: checker.cpp

(嘤嘤嘤这个数据点编号我也是醉了qwq)

下面开始讲讲怎么写$special\ judge$

只会C++

$Special\ Judge$ 程序运行时,其目录下会有四个文件 inputuser_outanswercode,分别对应该测试点的输入文件、用户输出、该测试点的输出文件、用户的代码(对于非提交答案题目)。

你可以从这四个文件里读入东西……

$Special\ Judge$ 程序运行完成后,应将该测试点的得分输出到标准输出(stdout)中(范围为 0100,将自动折合为测试点分数),并将提供给用户的额外信息输出到标准错误输出(stderr)中。

然后好像……

LOJ并不支持 $testlib.h$

$mdzz$

(本宝宝内心是拒绝给一个没$testlib.h$的OJ写$spj$的)

既然不支持,由于今天主要讲的是$LOJ$的$spj$写法

那我哭着也要写完吧……

上面说了,我们可以对那4个文件干一些事情

所以我这里只介绍输入输出怎么整,并不介绍运算(因为判断合法性要相对于题而言,并不能概括)

void read(char *fileName)
{
FILE *f = fopen(fileName, "r");
fscanf(f,...,...);
fclose(f);
}

调用这个函数的意思是:

从名为$fileName$的文件里读取一些东西

其中,

$fscanf(  )$里面先要有个$f,$之后就是$scanf$的格式。

之后就是给出正确、错误状态以及得分

void writ(const char s[],int point) {
//给出答案错误以及得分
/*
根据LOJ帮助里说,得分为stdout,详情为stderr
于是就用fprintf()来输出stderr,printf来输出得分
参数中,char数组表示的是详细信息的一个字符串,point是得分
*/
fprintf(stderr, "%s\n", s);
printf("%d\n",point);
exit();
}

然后就基础语法了

放上一波头文件

#include<cstdio>
#include<fstream>
#include<cstdlib>
#include<vector>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;

如果你不会写$data.yml$,但又想要$spj$,你需要在文件里包含一个 spj_***.xxx

其中,$***$为语言简称,$xxx$为任意后缀(强烈安利$.qwq$文件)

下面给出$a+b\ problem$的栗子:

#include<cstdio>
#include<fstream>
#include<cstdlib>
#include<vector>
#include<string>
#include<cctype>
#include<algorithm>
using namespace std;
int std_ans;
int per_out;
void read_ans(char *fileName)//从文件里读入一个数,存到std_ans里
{
FILE *f = fopen(fileName, "r");
fscanf(f,"%d",&std_ans);
fclose(f);
}
void read_out(char *fileName)//从文件里读入一个数,存到per_out里
{
FILE *f = fopen(fileName, "r");
fscanf(f,"%d",&per_out);
fclose(f);
}
void writ(const char s[],int point) {
fprintf(stderr, "%s\n", s);
printf("%d\n",point);
exit();
}
int main()
{
read_out("user_out");//从user_out,用户输出中读取per_out
read_ans("answer");//从 该测试点的输出文件 中读取 std_ans
if(std_ans==per_out) writ("ok the answer is corrit",);//返回正确
else writ("you are wrong",);//返回错误
}

到这里,基础教程就没了,高级的奇技淫巧还在后面……


你有没有发现,如果你要读一堆东西,发现你要写好多$read()$函数……

于是就崩溃了啊。

那怎么办呢?

魔改一下就好啊

int read_int(char *fileName)//从文件里读入一个数,返回这个数的值
{
FILE *f = fopen(fileName, "r");
int now;
fscanf(f,"%d",&now);
fclose(f);
return now;
}

这样我们就少写了好多东西哎

此时的$a+b$少了一个函数:

#include<cstdio>
#include<fstream>
#include<cstdlib>
#include<vector>
#include<string>
#include<cctype>
#include<algorithm>
using namespace std;
int std_ans;
int per_out;
int read_int(char *fileName)
{
FILE *f = fopen(fileName, "r");
int now;
fscanf(f,"%d",&now);
fclose(f);
return now;
}
void writ(const char s[],int point) {
fprintf(stderr, "%s\n", s);
printf("%d\n",point);
exit();
}
int main()
{
per_out=read_int("user_out");
std_ans=read_int("answer");
if(std_ans==per_out) writ("ok the answer is corrit",);
else writ("you are wrong",);
}

哇……这样我们是不是可以类比呢?

没错

char read_char(char *fileName)
{
FILE *f = fopen(fileName, "r");
char now;
fscanf(f,"%c",&now);
fclose(f);
return now;
}

当然,下面这个慎用……

下面这个慎用!!!

前面加 $#include<iostream>$

string resd_string(char *fileName)
{
freopen(fileName,"r",stdin);
string now;
cin>>now;
fclose(stdin);
return now;
}

这样是好写了……但是别忘了

$checker.cpp$运行也是有时间限制的啊啊啊、

所以……

你读一个数运行一次$fopen,fclose$可能会崩

所以你可以写一个指定从某文件读取$int,char$的函数。

这里我就不写了$qwq$


哇啊啊啊神tm LOJ支持$testlib.h$

那么就来讲讲$testlib.h$怎么用吧

首先我们需要有这个$testlib.h$

下载地址:戳这里

然后呢,我们需要的是

使用自定义校验器,请在problem.conf中去掉use_builtin_checker那一行。

(其实没什么用)

开始介绍$testlib.h$中的语法

首先必要的几个东西:

#include "testlib.h"
int main(int argc,char *argv[])
{
registerTestlibCmd(argc, argv);
/*
your main function
*/
return ;
}

第四行那句话是必须要加的,所谓的初始化$qwq$

不过,偷偷的告诉你,$testlib.h$里面包含的头文件:

#define random __random_deprecated
#include <stdlib.h>
#include <cstdlib>
#include <climits>
#include <algorithm>
#undef random #include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <sstream>
#include <fstream>
#include <cstring>
#include <limits>
#include <stdarg.h>
#include <fcntl.h>

所以基本上不用$#include$其他的东东。

之后,支持testlib.h$,就不用管之前的选手答案等东西的文件名了

$testlib.h$里面自带的文件名有这几个:

  • inf : 输入数据
  • ouf : 选手输出
  • ans : 标准输出

所以我们调用的话,直接$inf.***$ $ouf.***$ $ans.**$ 就好

下面说语法:

首先是读取

读取方法:

char readChar()

读入一个char。

char readChar(char c)

和上面一样,但是只能读到一个特定字母c

char readSpace()

读取一个空格同 readChar(' ').

string readToken()

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

long long readLong()

读入一个$long\ long$

long long readLong(long long L, long long R)

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

int readInt()

读入一个$int$

int readInt(int L, int R),

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

double readReal()

读入一个实数

double readReal(double L, double R),

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

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

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

string readString(),

string readLine()

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

void readEoln()

读入一个换行符

void readEof()

读入一个$eof$

int eof()

然后怎么调用这些呢?

我们从想要的文件里读入一个想要的类型的变量

就用$###.***$其中,$###$是文件名(上述三个),$***$是函数名(刚刚说的一堆)

举个例子,我们要从选手输出文件读取一个$int$

这么写就行了

int per_out=ouf.readInt();

这样就会从选手文件里读入一个$int$存到$per_out$里。

然后就是给出得分和答案

和$fprintf$不是一般的像,

这里用到的叫$qutif$和$quitp$函数,最少支持1个参数,最多……呵呵

格式:

$quitf(***,string,...)$

首先第一个参数是必须有的

$quitf$可选的值为:

.    \ok  //满分
. \wa //Wown answer ,0分
. double变量 //给选手a*100的分 (0<=a<=1)
. ceil(100.0*p/a)/ //给选手p分

中的$1,2$

$quitp$的第一个参数可以填3$,4$

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

给出AC

quitf(\_wa, "The answer is wrong");

给出WA

quitp(0.5,"Partially Correct");

给出$50\%$的分

quitp(ceil(100.0 * p / a) / 100, "QAQ");

这将会给选手p分。

之后那个字符串就是要显示的详情,里面遵循$printf$语法,就是支持 $\%d$等东西

然后后面跟着几个要显示的内容

这里口糊不太清楚,直接上代码

$a+b$的$spj$就可以这么写:

ps:这个直接从简介里抄了一份,请见谅

#include "testlib.h"
int main(int argc, char* argv[])
{
registerTestlibCmd(argc, argv);
int pans,jans;
pans=ouf.readInt();
jans=ans.readInt();
if (pans == jans)
quitf(_ok, "Correct. the answer is: %d \n QAQ " , jans);
else
quitf(_wa, "WA! expect=%d recieve=%d", jans, pans);
}

之后,多看几份$spj$就能自己写一个不错的$spj$了

然后呢……

下面奉上一份某沙华大佬的$spj$

额……某沙华大佬表示已经没题了

不,是沙华不会写QWQ

(强烈吐槽一句:LOJ的压榨翻译组的人力工作qwq)

如何给LOJ补全special judge的更多相关文章

  1. [LeetCode] Design Search Autocomplete System 设计搜索自动补全系统

    Design a search autocomplete system for a search engine. Users may input a sentence (at least one wo ...

  2. Mac OS终端中设置颜色高亮和自动补全

    已测试通过,原文:http://blog.csdn.net/songjinshi/article/details/8945809 一.颜色高亮显示 针对terminal采用bash模式: 编辑 ~/. ...

  3. 【bzoj2764】[JLOI2011]基因补全 dp+高精度

    题目描述 在生物课中我们学过,碱基组成了DNA(脱氧核糖核酸),他们分别可以用大写字母A,C,T,G表示,其中A总与T配对,C总与G配对.两个碱基序列能相互匹配,当且仅当它们等长,并且任意相同位置的碱 ...

  4. [LeetCode] 642. Design Search Autocomplete System 设计搜索自动补全系统

    Design a search autocomplete system for a search engine. Users may input a sentence (at least one wo ...

  5. Docker Compose的安装及命令补全

    安装Compose Compose的安装有多种方式,例如通过shell安装.通过pip安装.以及将compose作为容器安装等等.本文讲解通过shell安装的方式.其他安装方式如有兴趣,可以查看Doc ...

  6. Oracle补全日志(Supplemental logging)

    Oracle补全日志(Supplemental logging)特性因其作用的不同可分为以下几种:最小(Minimal),支持所有字段(all),支持主键(primary key),支持唯一键(uni ...

  7. python 添加tab补全

    在平时查看Python方法用到tab补全还是很方便的. 1. mac 平台 配置如下: mac是类Unix平台,需要在添加一条配置内容到bash_profile 中(默认是没有这个文件,可以新建一个放 ...

  8. 记录一次bug解决过程:else未补全导致数据泄露和代码优化

    一.总结 快捷键ctrl + alt + 四个方向键 --> 倒置屏幕 未补全else逻辑,倒置查询数据泄露 空指针是最容易犯的错误,数据的空指针,可以普遍采用三目运算符来解决 SVN冲突解决关 ...

  9. jQuery 邮箱下拉列表自动补全

    综述 我想大家一定见到过,在某个网站填写邮箱的时候,还没有填写完,就会出现一系列下拉列表,帮你自动补全邮箱的功能.现在我们就用jQuery来实现一下. 博主原创代码,如有代码写的不完善的地方还望大家多 ...

随机推荐

  1. 4 MySQL--表(增删改查)

    1.表的介绍 表相当于文件,表中的一条记录就相当于文件的一行内容,不同的是,表中的一条记录有对应的标题,称为表的字段 id,name,qq,age称为字段,其余的,一行内容称为一条记录 2.创建表: ...

  2. 迷你MVVM框架 avalonjs 0.91发布

    本版本修了一些BUG与不合理的地方,感谢感谢ztz, 民工精髓, 姚立, qiangtou等人指正. 处理AMD加载 旧式IE下移除script节点内存泄漏的问题 fix firefox 全系列vis ...

  3. js中改变文档的层次结构(创建元素节点,添加结点,插入子节点,取代子节点,删除子节点)

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  4. 网页设计编辑利器——jQuery EasyUI所学整理(待编辑)

    1, Messager弹窗信息 方法: $.messager.alert(...), 在网页中间弹出一个窗口 $.messager.confirm(...) 弹出一个确认窗口, 有确定和取消两个按钮, ...

  5. 把CString转化为char*

    转:http://blog.sina.com.cn/s/blog_58e19ae7010003jt.html 正确方法:CString m_Head:char *codefile;codefile=( ...

  6. Python id() 函数

    Python id() 函数  Python 内置函数 描述 id() 函数用于获取对象的内存地址. 语法 id 语法: id([object]) 参数说明: object -- 对象. 返回值 返回 ...

  7. SQLSERVER的四个系统数据库

    (1)Master数据库是SQL Server系统最重要的数据库,它记录了SQL Server系统的所有系统信息.这些系统信息包括所有的登录信息.系统设置信息.SQL Server的初始化信息和其他系 ...

  8. Qt的安装和使用中的常见问题(简略版)

    对于喜欢研究细节的朋友,可参考Qt的安装和使用中的常见问题(详细版). 目录 1.引入 2.Qt简介 3.Qt版本 3.1 查看安装的Qt版本 3.2 查看当前项目使用的Qt版本 3.3 查看当前项目 ...

  9. mysql索引原理及用法

    MySQL索引原理及慢查询优化 Mysql explain用法和性能分析 MySQL 索引优化全攻略 1.索引作用 在索引列上,除了上面提到的有序查找之外,数据库利用各种各样的快速定位技术,能够大大提 ...

  10. Ansible常用模块命令

    Ansible常用模块命令 一.安装ansible yum install epel-release yum install ansible 二.配置文件配置 vi /etc/ansible/ansi ...