SCNUOJ 出题指南(助教版)

本文为华南师范大学软件学院在线判题系统 SCNUOJ 出题指南(助教版)。下面的内容糅杂了 RJL 的一些个人观点,故仅供参考。编写本文时参考到了 OI Wiki 的相关内容,对相关内容的作者表示感谢。本文在 CC BY-SA 4.0 下发布。

SCNUOJ 判题原理

对于每道程序设计题目,解题思路和代码实现方式都不是唯一的,一个很简单的例子,输出一行文字 SCNUOJ,在 C++ 下就可以使用下面这些方式:

printf("SCNUOJ\n");
puts("SCNUOJ");
std::cout << "SCNUOJ" << std::endl;
putchar('S');
putchar('C');
putchar('N');
putchar('U');
putchar('O');
putchar('J');
putchar('\n');

怎么判断一份代码是否符合题目要求呢?逐份代码人工审查肯定是不可能的,在线判题系统是通过一系列自动化、标准化的测试衡量一份代码是否正确的。SCNUOJ 有两种判题方式,一种叫文本对比,一种叫 Special Judge。但无论是哪种方式,SCNUOJ 都会先编译学生提供的代码,然后反复运行这个程序,通过一系列事先准备好的测试数据验证程序能否给出期望的输出。

例如学生提交了一份 C++ 代码,SCNUOJ 先把这份代码保存为 Main.cc,接下来就会编译这份代码:

g++ -fno-asm -O2 -Wall -lm --static -std=c++14 -DONLINE_JUDGE -o Main Main.cc

编译时使用的参数在 https://oj.socoding.cn/wiki/index 有说明。

编译结束后会得到一个 Main 可执行文件。由于我们在上传题目的时候提供了若干组测试数据,也就是 1.in1.out 这样的纯文本文件。SCNUOJ 就会利用这些文件测试这个可执行文件,具体来说就是将 *.in 作为标准输入,然后捕获并储存 Main 的标准输出。

形象一点,对于测试点一,SCNUOJ 就相当与在 Linux 系统下执行:

(./Main < 1.in) > outfile.txt

outfile.txt 就是接下来评判代码是否正确的依据。

对于文本比较方式,SCNUOJ 会直接将选手的输出 outfile.txt 和标准答案 *.out 比较。形象一点,对于测试点一, SCNUOJ 就相当于在 Linux 系统下执行:

diff outfile.txt 1.out

形象的比喻罢了,要理解判题机工作原理,请前往 https://github.com/SCNU-SoCoding/scnuoj/tree/master/judge

当然 SCNUOJ 会在进行文本必对时会忽略行末空格和文件末尾的空行。所以下面的程序会判正确:

#include <bits/stdc++.h>

int main()
{
    std::cout << "SCNUOJ  " << std::endl
              << std::endl;
    return 0;
}

但是下面的程序会被判为答案错误(输出无关的提示词):

#include <bits/stdc++.h>

int main()
{
    std::cout << "The answer is: SCNUOJ" << std::endl;
    return 0;
}

这个程序也会被判定为错误(全角字符):

#include <bits/stdc++.h>

int main()
{
    std::cout << "SCNUOJ" << std::endl;
    return 0;
}

对于 Special Judge 方式(简称 SPJ),情况则复杂一些,简单来说就是要求出题人也要编写一个程序,SCNUOJ 同样把这个程序编译成可执行文件,接下来 SCNUOJ 会执行这个文件,并给定三个参数输入文件、用户输出和标程输出:

./spj 1.in outfile.txt 1.out

SCNUOJ 使用这个程序的返回值作为代码是否正确的评判标准。对于下面这些题,我们都会启用 SPJ:

  • 题目最终要求输出一个解决方案,而且这个解决方案可能不唯一。
  • 题目最终要求输出一个浮点数,而且会告诉只要答案和标准答案相差不超过某个较小的数就可以。

我们会在下文说明如何编写 SPJ 程序,你也可以先行查阅 https://oj.socoding.cn/wiki/spj

出题前的准备

抱有认真负责的态度

出题是为了给别人做的,本质上是服务他人,让学生在做题时能有所收获,强化程序设计思维,从而达到课程教学目的;而不是与学生较量,劝退学生,逼迫学生转专业。题目质量不过关,不但会影响学生的做题体验,学生疑问多起来最终也是占用自己的时间。

自己先尝试动手做题

如果没有接触 OI/ACM 或任何程序设计竞赛,在可能的前提下,在 Codeforces 注册一个账号并尝试完成上面的程序设计题目(不需要是难题,题目 Rating 值小于 1000 的就行,基本就是面向大一新生 AK 杯的那种难度)。Codeforces 是目前最为出名的在线判题系统,题目的上传有着非常严格的把关,近五年的题目在题面排版、数据、输入输出表述方式上是无懈可击的,在做题的过程中可以感受一下。出题思路也非常值得参考。

题目准备

造题系统

SCNUOJ 目前有两套造题系统,Polygon System(对所有人开放)和管理员后台自带的造题系统(对管理员和助教开放)。所有题目都需要在这两套造题系统中准备。 两者各有优缺点,使用起来都非常容易上手,大家目前可以根据自己的需要进行选择,我们会在后期逐步合并两个造题系统的功能。

下面是 Polygon System 提供的一些特性:

  • 支持上传标程代码后利用标程代码自动生成测试数据的 *.out 文件。

在 Polygon System 造的题目需要先同步到管理员后台自带的造题系统才能在 SCNUOJ 中使用。同步方式就是访问 https://oj.socoding.cn/admin/problem/create-from-polygon 并输入 Polygon System 的题目 ID。

下面是管理员后台自带的造题系统提供的一些特性:

  • 支持 Special Judge 题目的验题。

在完成造题(如果在 Polygon System 完成造题后要先完成同步)之后,即可直接在小组作业或比赛中添加造好的题目。如果你希望将题目添加到公共题库(特指 https://oj.socoding.cn/problem/index 能看到的题目)或者添加到公共比赛(特指 https://oj.socoding.cn/contest/index 能看到的比赛),请联系任意任一香农先修班负责人。

Polygon System 使用流程

造题:

  • https://oj.socoding.cn/ 注册一个账户并登录。
  • 顶部导航栏 - 后台 - 侧栏 - Polygon System。
  • 创建题目。
  • 填写标题 - 创建。
  • 编辑 - 填写上面的栏目(下文有指导)- 保存。
  • 解决方案 - 上传解决方案 - 保存。
  • (如果启用了 Special Judge)Special Judge - 填写特判程序 - 保存。
  • 测试数据 - 只需要上传输入文件,即 *.in - 开始上传 - 运行 - 等候输出文件自动生成。

同步到管理员后台自带的造题系统:

  • 顶部导航栏 - 后台 - 侧栏 - 问题。
  • Polygon 题目。
  • 填写 Polygon 题目 ID - 提交。
  • 从问题列表找到自己的题目,点击进入。
  • (可选)编辑 - 补充来源 - 保存。
  • (如果启用了 Special Judge)SPJ - 提交。

Polygon System 不会编译你上传的 SPJ 程序,但是管理员后台自带的造题系统在点击 SPJ 栏目的提交按钮后会编译你提供的 SPJ 程序并保存,判题时会直接使用这个编译好的程序。所以一定要到管理员后台自带的造题系统手动点一下提交。否则学生的代码将无法被正常评判。

更新题目:

  • 顶部导航栏 - 后台 - 侧栏 - Polygon System。
  • 从问题列表找到自己的题目,点击进入。
  • 参考造题一节更新题目并保存。
  • 顶部导航栏 - 后台 - 侧栏 - 问题。
  • Polygon 题目。
  • 填写 Polygon 题目 ID - 提交。
  • 从问题列表找到自己的题目,点击进入。
  • (如果启用了 Special Judge)SPJ - 提交。

事实上就是重新导入这道题目,但公共题库的题目无需删除,重新导入会自动覆盖管理员后台自带造题系统对应的题目。对于在 Polygon System 创建的题目,尽量在 Polygon System 编辑题目后重新导入,而不是在管理员后台自带的造题系统直接编辑。后续版本的 SCNUOJ 会添加合适的逻辑减少操作量。

Polygon System 不支持 Special Judge 题目的验题,这意味着 Polygon System 只可以对文本比较型题目作验题,而管理员后台自带造题系统可以对两类题目做验题,后面会介绍如何在管理员后台自带造题系统验题。

如果你的题目为 Special Judge 评测方式,无论是否改动特判程序,都请重新编译该程序。

管理员后台自带的造题系统使用流程

造题或更新题目:

  • https://oj.socoding.cn/ 注册一个账户并登录。
  • 顶部导航栏 - 后台 - 侧栏 - 问题。
  • 创建题目(或找到自己的题目,点击进入)。
  • 填写上面的栏目(下文有指导)- 保存。
  • 测试数据 - 输入文件和输出文件都要上传,即 *.in 和对应的 *.out 文件 - 开始上传。
  • (如果启用了 Special Judge)SPJ - 填写特判程序 - 保存。

验题:

  • 顶部导航栏 - 后台 - 侧栏 - 问题。
  • 从问题列表找到自己的题目,点击进入。
  • 验题 - 提交一份代码。

在将题目添加至小组作业(方法见下文)前要完成验题。

出题思路

在 SCNUOJ 上布置的题目,主要目的应当是培养程序设计思维,让学生在见到程序设计类题目时可以有具体的实现想法,能将题面转化为逻辑化的程序语言,次之才是语法学习:例如题目是读入两个数后比较它们的大小,学生应该能马上意识到要声明两个变量,将读入的数字保存到变量,用分支语句比较两个变量的值,输出结果;鼓励在满足时空要求的前提下让学生做到一题多解,除非是希望学生刻意学习、刻意练习,非必要情况下不应当在语法上做过多限制,例如只能利用指针进行某个操作、必须声明一个什么函数等等。

题目可以来源课本和其它在线判题系统,也可以自己原创。特别地,对于《C 语言程序设计》课本原题,这些题目往往不是专门为 OJ 设计的,移植到 SCNUOJ 之前可能需要做一定的修改,详见下面章节的介绍;对于原创题,注意题目中不应过多涉及到其它学科的知识,如果涉及应当给予详细的解释,不应使其它学科的知识作为解题的重大障碍;思维难度应占主要部分,避免强行拼凑多个题目、条件或知识点而达到降低 AC 人数的目的。

题目描述

简而言之,题目描述需要清晰易懂。题面中的每个可能不被理解的定义都应得到解释,不应凭空冒出未加定义的概念。题面中涉及到的每个概念应当使用单一的词汇来描述。例如:不应一会儿说费用,一会儿说代价。不应不加说明地使用与原义、常见义不同的词汇。例如:不应不加说明地用路径代指一条。顺着读题目描述应当能看懂每一句话,并理解题目的任务与要求。避免看完题目和输入输出要求还是不懂要根据样例来猜题意。如果题目描述中包含题目背景,题目背景应当尽量简短

如果你有给题目描述添加图片的需求,请联系任一香农负责人。

下面给出一个例子供参考(2020 年软件学院 AK 杯程序设计竞赛):


一鸣师姐作为一名程序员,最期望的事情就是写出的代码编译过后显示 0 error(s), 0 warning(s)。她讨厌 errorwarning 到了极点,以至于她不想任何文本出现 errorwarning 这两个字符串。

现在一鸣有多个只含小写字母的字符串,对于每个字符串,请你帮他判断是否存在一个非负整数 x将字符串中每一个字符加上 x,得到的字符串中不含有 errorwarning

我们认为,如果某一个小写字母是字母表中的第 i 个字母,给这个字符加上非负整数 x 之后,应该得到一个新的小写字母,这个新的小写字母恰好是字母表中的第 (i+x-1) \ \% \ 26 +1 个字母, \% 指代取模运算,举个例子:

  • 对于字符串 ogilow,如果给字符串中每个字符加上 3 ,结果为 rjlorz
  • 字符串 ahz,如果给字符串中每个字符加上 7 ,结果为 hog
  • 字符串 dogaz,如果给字符串中每个字符加上 28 ,结果为 fqicb

安娜 • 璃莹殇 • 安洁莉娜 • 爱丽丝 • 樱雪羽晗灵 • 血丽魑 • J • Q • 安塔利亚 • 伤梦薰魅 • 海瑟薇 • 蔷薇玫瑰雪 • 芳羽灵邪 • 凡多姆海威恩 • 音 • 夏影 • 紫蝶 • 丽馨 • 蕾琦洛 • 凤 • 颜鸢 • 希洛 • 玖楠 • 雨烟 • 叶洛莉兰 • 晚凝羽沙 • 一鸣师姐作为一名程序员,最期望的事情就是写出的代码编译过后显示 0 error(s), 0 warning(s)。安娜 • 璃莹殇 • 安洁莉娜 • 爱丽丝 • 樱雪羽晗灵 • 血丽魑 • J • Q • 安塔利亚 • 伤梦薰魅 • 海瑟薇 • 蔷薇玫瑰雪 • 芳羽灵邪 • 凡多姆海威恩 • 音 • 夏影 • 紫蝶 • 丽馨 • 蕾琦洛 • 凤 • 颜鸢 • 希洛 • 玖楠 • 雨烟 • 叶洛莉兰 • 晚凝羽沙 • 一鸣师姐讨厌 errorwarning 到了极点,以至于她不想任何文本出现 errorwarning 这两个字符串。

给你一个字符串,给字符串每个字符加一个数,安娜 • 璃莹殇 • 安洁莉娜 • 爱丽丝 • 樱雪羽晗灵 • 血丽魑 • J • Q • 安塔利亚 • 伤梦薰魅 • 海瑟薇 • 蔷薇玫瑰雪 • 芳羽灵邪 • 凡多姆海威恩 • 音 • 夏影 • 紫蝶 • 丽馨 • 蕾琦洛 • 凤 • 颜鸢 • 希洛 • 玖楠 • 雨烟 • 叶洛莉兰 • 晚凝羽沙 • 一鸣师姐想知道能不能让字符串中没有 errorwarning


人名能不能不要这么玛丽苏?啥叫给字符加一个数?

编写题目描述应该使用 Markdown 排版,网上有大量 Markdown 相关的教程,通常情况下你可以使用自带的编辑完成加粗倾斜、添加代码块等操作,同时从编辑器右侧的预览框中看到排版效果。但是由于实际渲染和编辑器自带的渲染不一致,不保证即见即所得。下面通过一个例子说明,假设我希望渲染完是下面的内容:


有着女装 Buff 加成,一鸣师姐写起作业来也是贼快贼快的啦!

一天,一鸣师姐遇到了这样一道题:对于正整数 n ,定义 s(n) 的值是数位和恰好为 n 的最小正整数,如 s(10)=19 。现在给定 n ,请你求出 s(n) 的值。

一鸣师姐一下子就写出来了,聪明的你又能否做到呢?


对应的正确 Markdown 源文本是:

有着女装 Buff 加成,一鸣师姐写起作业来也是贼快贼快的啦!

一天,一鸣师姐遇到了这样一道题:对于正整数 $n$ ,定义 $s(n)$ 的值是**数位和**恰好为 $n$ 的最小正整数,如 $s(10)=19$ 。现在给定 $n$ ,请你求出 $s(n)$ 的值。

一鸣师姐一下子就写出来了,聪明的你又能否做到呢?

两个自然段之间必须添加一个空行,公式两边使用 $$ 括起来。

有关如何使用 LaTeX 写公式请上网搜索,也有大量在线 LaTeX 公式编辑器可供使用(例如 https://latex.91maths.com/ )。

此外还有一些排版规范需要遵守,例如上面例子中变量必须使用公式,英文字母、公式或数字与汉字之间必须添加空格, 具体请阅读 https://oj.socoding.cn/wiki/problem 。这很大程度上会影响学生的读题和做题体验。

下面是一些正确的例子:

我的 SCNUOJ 账户名是 bobby285271,SCNUOJ 目前有 700 个注册账户, n 一定大于 n-1 。字符串 abcabcdef 的字串。

我的 SCNUOJ 账户名是 bobby285271,SCNUOJ 目前有 $700$ 个注册账户, $n$ 一定大于 $n-1$ 。字符串 `abc` 是 `abcdef` 的字串。

错误的例子:

我的ScNuOj用户名是bobby285 2 71,SCNUOJ目前有7百个注册用户,N一定>n-1。字符串"abc”是’abcdef“”的字串。

要是真有人这么写我直接裂开。

我的SCNUOJ用户名是bobby285271,SCNUOJ目前有700个注册用户,n一定大于n-1。字符串"abc"是"abcdef"的字串。

其实还可以接受,空格要加的尽可能加吧,LaTeX 该上还是要上。

输入输出格式

输入输出格式必须清晰、完整,无二义性。

请按照下面的模版编写输入格式要求:

输入只有一行,包含两个用空格间隔的整数 a,b \ (1 \leq a,b \leq 10^9) ,含义如题目描述所示。

输入只有一行,包含两个用空格间隔的整数 $a,b \ (1 \leq a,b \leq 10^9)$ ,含义如题目描述所示。

注意字母 b 和左括号之间有一个空格。数据范围必须紧接变量后面给出,必须给出明确的数字范围,不能简单地说 a,b 是整型数据或在整型范围内。数据范围中应当使用小于等于号,而不是小于号。非显然情况下,上界和下界必须同时提供。大数需要使用科学计数法,例如 10^9 ,不能写成 1000000000 ,不能写成 1e9

输入包含两行。

第一行包含一个整数 n \ (1 \leq n \leq 2 \cdot 10^5) ,表示序列的长度。

第二行包含 n 个用空格间隔的整数 a_1,a_2,a_3,\cdots,a_n \ (1 \leq a_i \leq 10^9) ,表示序列。

输入包含两行。

第一行包含一个整数 $n \ (1 \leq n \leq 2 \cdot 10^5)$ ,表示序列的长度。

第二行包含 $n$ 个用空格间隔的整数 $a_1,a_2,a_3,\cdots,a_n \ (1 \leq a_i \leq 10^9)$ ,表示序列。

下标要从 1 开始。数与数之间用空格间隔而不是逗号或其它符号。

输入包含若干行。

第一行包含一个整数 n \ (1 \leq n \leq 2 \cdot 10^5) ,表示字符串的个数。

接下来 n 行每行包含一个由小写英文字母组成的字符串 s_i ,保证字符串长度 |s_i| \leq 10^5

输入包含若干行。

第一行包含一个整数 $n \ (1 \leq n \leq 2 \cdot 10^5)$ ,表示字符串的个数。

接下来 $n$ 行每行包含一个由小写英文字母组成的字符串 $s_i$ ,保证字符串长度 $|s_i| \leq 10^5$ 。

输入的字符串包含什么字符需要标明。但无论如何,整个输入文件中不应包含除了英文字母、数字、空格、换行符 \n~!@#$%^&*()_+-={}|[]\:";'<>?,./ 之外的其它的任何字符,特别是制表符、全角标点和中日韩文字。

输入包含多组测试用例。

输入的第一行包含一个整数 T \ (1 \leq T \leq 10^4) ,代表你需要处理 T 组测试用例。

每组用例输入包含两行,其中:

第一行包含一个整数 n \ (1 \leq n \leq 10^5) ,表示序列的长度。

第二行包含 n 个用空格间隔的整数 a_1,a_2,a_3,...,a_n \ (0 \leq a_i \leq 10^9) ,表示序列。

输入数据保证 n 的和小于等于 2 \cdot 10^5 ,即 \sum{n} \leq 2 \cdot 10^5

输入包含多组测试用例。

输入的第一行包含一个整数 $T \ (1 \leq T \leq 10^4)$ ,代表你需要处理 $T$ 组测试用例。

每组用例输入包含两行,其中:

第一行包含一个整数 $n \ (1 \leq n \leq 10^5)$ ,表示序列的长度。

第二行包含 $n$ 个用空格间隔的整数 $a_1,a_2,a_3,...,a_n \ (0 \leq a_i \leq 10^9)$ ,表示序列。

输入数据保证 $n$ 的和小于等于 $2 \cdot 10^5$ ,即 $\sum{n} \leq 2 \cdot 10^5$ 。

在多组数据下,如果数据量最大值乘以测试用例数得到的值过大,需要对总数据量作额外的约定。

确定数据范围时,你需要保证标程可以通过满足题面所述数据范围的任何一组数据。

请按照下面的模版编写输出格式要求:

输出一个整数,表示答案。

输出一个整数,表示答案。

输出一个实数,表示答案。

你的答案将被判定为正确当且仅当你的答案和标准答案误差小于等于 0.01

具体而言,假设你的答案为 a ,标准答案为 b ,只有 |a-b| \leq 0.01 你的答案才会被判为正确。

输出一个实数,表示答案。

你的答案将被判定为正确当且仅当你的答案和标准答案误差小于等于 $0.01$ 。

具体而言,假设你的答案为 $a$ ,标准答案为 $b$ ,只有 $|a-b| \leq 0.01$ 你的答案才会被判为正确。

输出小数必须开启 Special Judge 评测并给明精度要求,除非考察的是高精度除法。

输出一行,包含 n 个用空格间隔的整数,表示你构造的一组方案。

如果有多组答案,输出任意一组。

输出一行,包含 $n$ 个用空格间隔的整数,表示你构造的一组方案。

如果有多组答案,输出任意一组。

通解可能是唯一的,但只要对于任一测试点有多个可以满足题意的答案就必须写 Special Judge。

和输入文件一个道理,整个输出文件中不应包含除了英文字母、数字、空格、换行符 \n~!@#$%^&*()_+-={}|[]\:";'<>?,./ 之外的其它的任何字符,特别是制表符、全角标点和中日韩文字。

除非是希望刻意考察输入输出格式,否则尽可能避免卡输出。要求数字与数字之间用一个空格间隔就行,尽可能避免要求行与行的数字对齐(我当然知道格式控制符怎么用),避免让学生对着样例数空格数量

样例

样例应当有一定的强度,能够查出一些简单的错误。读错题意的人应当能够通过样例发现自己读错了题意。有多种操作的题,每种操作都应在样例中出现有多种输出的题,每种输出都应在样例中出现(例外是实际上不可能无解,但要求判断是否有解的题目)。

提示

在必要的情况下,对样例进行解释说明,无论这个样例对于你来说有多显然。特别是题目描述你自己都无法表述清楚的那种题。

数据

严格按照自己所写的输入输出格式要求准备数据,由于 DOS 与 UNIX 文件换行符不一致的原因,有条件的话就直接在 Linux 下造数据(或者你知道如何转换文件也可)。下面是一些注意事项:

  • 输入文件的后缀为 in,例如 1.in;输出文件后缀为 out,例如 1.out
  • 由于目前 OJ 的问题,如果题目无输入要求,为了正确生成输出文件,需要包含至少一个非空的输入文件(文件内容就敲一个空格,不要敲其它东西)。
  • 有输入要求题目的输入文件和所有题目的输出文件文件末尾最多只能有一个空行
  • 有输入要求题目的输入文件和所有题目的输出文件每行末尾都不应该有任何数量的空格
  • 必须包括各种各样的数据,而且应该有各种各样的达到最小数据范围的数据和达到最大数据范围的数据。
  • 测试数据不应完全依赖于程序随机生成,最好人为考虑各种不同的情况,针对各种情况出数据,确保暴力、假算法、看错题意看漏题意写出来的程序无法通过。

https://oj.socoding.cn/wiki/problem 提供了一些补充信息。

关于如何快速生成输入数据,可以参考上面链接中提供的示例,下面额外补充一例:

输入包含两行。

第一行包含一个整数 n \ (1 \leq n \leq 10^4) ,表示序列的长度。

第二行包含 n 个用空格间隔的整数 a_1,a_2,a_3,\cdots,a_n \ (1 \leq a_i \leq 10^4) ,表示序列。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    srand((unsigned)time(NULL));
    for (int test = 1; test <= 50; test++)
    {
        char name[100];
        sprintf(name, "%d.in", test);
        FILE *fp = fopen(name, "w");
        int a = rand() % 10000 + 1;
        fprintf(fp, "%d\n", a);
        a--;
        while (a--)
        {
            int c = rand() % 10000 + 1;
            fprintf(fp, "%d ", c);
        }
        int c = rand() % 10000 + 1;
        fprintf(fp, "%d\n", c);
        fclose(fp);
    }
    return 0;
}

关于如何生成输出数据,你可以先写一个解答程序直接批量生成(Polygon System 可以帮助你完成批量生成的工作),也可以人工制作。要注意的是如果你通过解答程序批量生成必须要做到输出文件末尾最多只能有一个空行,每行末尾都不应该有任何数量的空格。

例如题目要你在一行内输出 n 个用空格间隔的数,学生可以这样写:

for (int i = 1; i <= n; i++)
{
    std::cout << a[i] << ' ';
}

由于在评判时会忽略行末空格,这样写是可以的。

但是你的标程必须这样写:

for (int i = 1; i < n; i++)
{
    std::cout << a[i] << ' ';
}
std::cout << a[n];

Special Judge

Special Judge 是当一道题有多组解时,用来判断答案合法性的程序。

请参考 https://oj.socoding.cn/wiki/spj 提供的用法,学习如何使用 Testlib 并完成 Special Judge 的编写。

即使旧版 OJ 的 Special Judge 编写规则依然适用于新 OJ,但为了避免 Judgment Failed,在新 OJ 必须使用 Testlib。

请尽可能避免使用 while (!ans.eof()) 的用法,除非你的输出数据文件足够规范,即行末没有任何空行。

由于用户输出多余内容或者过少内容均会被 Testlib 判为答案错误,如果输出要求用户输出 n 个实数,那么在判定一份正确的输出时应当恰好调用 nouf.readDouble(),不能说因为读取第 1 个数就已经知道这份输出一定正确就提前 quitf()。当然对于错误的用户输出可以随时 quitf()

有关如何判断浮点数,还请继续看 https://oj.socoding.cn/wiki/spj ,页面底部有例子。

对于答案不唯一的 SPJ 写法,下面以 https://oj.socoding.cn/p/1094 这道题为例:

首先你要判断用户输出的 YESNO 是不是对的,接下来要看输出的序列是不是一个排列,接下来还要从输入文件读入 n 个括号字符串,按照序列给定的顺序组合起来,判断能不能生成一个合法的括号序列。

#include "testlib.h"

using namespace std;

int b[11000], c[11000];

int main(int argc, char *argv[])
{
	registerTestlibCmd(argc, argv);
	int n = inf.readInt();
	vector<string> a(n);
	for (int i = 0; i < n; i++)
	{
		a[i] = inf.readToken();
	}
	string ansans1 = ouf.readToken();
	string ansans2 = ans.readToken();
	if (ansans1 != ansans2)
	{
		quitf(_wa, "wa (1)");
		return 1;
	}
	if (ansans1 == "NO")
	{
		quitf(_ok, "ok, the answer is NO");
		return 0;
	}
	string cmp = "";
	for (int i = 0; i < n; i++)
	{
		b[i] = ouf.readInt();
		b[i]--;
		c[i] = b[i];
	}
	sort(c, c + n);
	for (int i = 0; i < n; i++)
	{
		if (c[i] != i)
		{
			quitf(_wa, "wa (2)");
		}
	}
	for (int i = 0; i < n; i++)
	{
		cmp += a[b[i]];
	}
	int cnt = 0;
	for (int i = 0; i < cmp.size(); i++)
	{
		if (cmp[i] == '(')
		{
			cnt++;
		}
		else if (cmp[i] == ')')
		{
			cnt--;
		}
		else
		{
			quitf(_fail, "not a valid string");
			return 1;
		}
		if (cnt < 0)
		{
			quitf(_wa, "wa (3)");
			return 1;
		}
	}
	if (cnt == 0)
	{
		quitf(_ok, "ok, the answer is YES, valid permutation");
		return 0;
	}
	else
	{
		quitf(_wa, "wa (4)");
		return 1;
	}
}

quitf() 中可以填写答案正确或错误的原因,自己能看懂就行。如果自己的 SPJ 写得有问题(即验题的时候发现评判结果不符合预期)可以利用这个进行调试。

发布题目

在完成造题(如果在 Polygon System 完成造题后要先完成同步)之后,即可直接在小组作业或比赛中添加造好的题目。

  • 顶部导航栏 - 后台 - 侧栏 - 问题。
  • 找到自己的题目,记下题号。
  • 顶部导航栏 - 小组 - 找到自己管理的小组。
  • 作业 - 创建。
  • 填写作业信息 - 提交。
  • 进入你刚刚创建的比赛 - 设置。
  • 问题列表 - 添加问题 - 填入题号。

有关赛制的选择,请查看 https://oj.socoding.cn/wiki/contest 。通常是作业赛制(允许学生看测试点)和 ICPC 赛制(不允许看数据)二选一,如果需要用到其它赛制,请先联系任一香农先修班负责人重启判题机并为 OJ 开启 OI 模式。

要统计学生完成情况,直接保存公共榜单即可,公共榜单现已默认显示学生填写的学号。

2赞
粤 ICP 备 2020080455 号