Краткое руководство по подготовке задач олимпиад по программированию для использования в системе ejudge.
В руководстве будут рассматриваться только задачи для олимпиад по правилам ACM ICPC или аналогичным.
Обычно в ejudge олимпиадная задача состоит из:
statement.xml
)serve.cfg
)Условие задачи хранится в файле statement.xml
. Примерное его содержание:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version="1.0" encoding="utf-8" ?>
<problem
package="ru.codemore.contest"
id="A"
type="standard">
<statement language="ru_RU">
<title>...</title>
<description>
<p>...</p>
</description>
<input_format>
<p>...</p>
</input_format>
<output_format>
<p>...</p>
</output_format>
<notes>
<p>...</p>
</notes>
</statement>
<examples>
<example>
<input>...</input>
<output>...</output>
</example>
</examples>
</problem>
problem
, по документации ejudge, не используются.
Можно записать любые значения, например, в id
номер задачи (A), а в type
- standard
title
, description
, input_format
, output_format
, notes
текст должен быть в формате XHTML
(т.е. корректность тегов строго проверяется).
Любой из этих тегов может отсутствоватьtitle
содержит название задачиdescription
содержит основную часть условия задачиinput_format
содержит подробное описание формата входных данных.
Для параметров должны быть указаны диапазоны значений.
Также здесь рекомендуется обращать внимание участников на разделители параметров
(одиночные пробелы, произвольное количество пробелов, переводы строк и т.п.)output_format
содержит подробное описание формата выходных данныхnotes
содержит примечания к условиюdescription
, input_format
, output_format
, notes
оборачивать в теги <p>
<img src="${getfile}=имя_файла.png"/>
examples
содержит примеры входных и выходных данных.
Каждый пример описывается тегом example
, тег input
содержит пример входных данных,output
- выходных.
Данные в тегах input
и output
будут отображаться с сохранением форматирования, обращайте внимание на лишние пробелыПример statement.xml
реальной задачи:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?xml version="1.0" encoding="utf-8" ?>
<problem
package="ru.pskovedu.contest"
id="rot13"
type="standard">
<statement language="ru_RU">
<title>Шифр ROT13</title>
<description>
<p>
Алгоритм шифрования ROT13 является вариацией шифра Цезаря.
</p>
<blockquote>
Применение алгоритма ROT13 к части текста требует простой замены каждого
буквенного символа на соответствующий ему со сдвигом на 13 позиций в алфавите.
A становится N, B становится O, и т. д. до М, которое становится Z, а затем
последовательно применяются буквы из начала алфавита: N становится A,
O становится B, и так далее до Z, которая становится М. Затронуты лишь те буквы,
которые используются в английском алфавите; цифры, символы, пробелы и все остальные
символы остаются без изменений.
</blockquote>
<a href="https://ru.wikipedia.org/wiki/ROT13">https://ru.wikipedia.org/wiki/ROT13</a>
</description>
<input_format>
<p>
В первой строке дано целое число N (1≤N≤100) - длина строки.
</p>
<p>
Во второй - строка состоящая из N символов - заглавных и строчных латинских букв,
пробелов и знаков препинания ",.!?-" (не включая кавычки), зашифрованная по алгоритму ROT13.
</p>
<p>
Гарантируется, что строка не начинается и не заканчивается пробелом.
</p>
</input_format>
<output_format>
<p>
Расшифрованная строка.
</p>
</output_format>
</statement>
<examples>
<example>
<input>
13
Uryyb, jbeyq!
</input>
<output>Hello, world!</output>
</example>
</examples>
</problem>
Статья в ejudge wiki содержит описания и других тегов, которые можно включить в условие.
Решение задачи, предоставленное жюри.
Должно проходить все тесты, соотвествовать ограничениям по времени и памяти, а также полностью соответствовать правилам олимпиады (если правилами накладываются какие-либо особые граничения).
Также рекомендуется, чтобы решение было написано на языке, разрешенном на олимпиаде.
Пример решения (для задачи, описанной выше):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package rot13;
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
in.nextLine();
String s = in.nextLine();
System.out.println(rot13(s));
}
public static String rot13(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (Character.isAlphabetic(c)) {
if (Character.isUpperCase(c)) {
c = (char)((c - 'A' + 13) % 26 + 'A');
} else {
c = (char)((c - 'a' + 13) % 26 + 'a');
}
}
sb.append(c);
}
return sb.toString();
}
}
Тест - это два текстовых файла, содержащих корректные входные и выходные данные задачи. Рекомендуется, чтобы:
Файлы тестов можно поместить в каталог tests
, файлы входных данных назвать номером теста,
файлы выходных данных - номером теста и расширением .a
(расположение и наименование можно изменить в настройках контеста).
Чекер - программа, проверяющая корректность решения участника, использующая три файла: входные данные, выходные данные жюри, выходные данные участника.
Проверка может закончиться с одним из результатов:
Для написания чекеров обычно используется библиотека testlib,
предоставляющая многие полезные методы.
При использовании библиотеки, нужно ее код (testlib.h
) также включить в файлы задачи.
testlib предоставляет несколько стандартных чекеров, например:
fcmp.cpp
- Lines, doesn’t ignore whitespaceshcmp.cpp
- Single huge integerlcmp.cpp
- Lines, ignore whitespacesncmp.cpp
- Single or more int64, ignores whitespacesrcmp4.cpp
- Single or more double, max any error 1e-4rcmp6.cpp
- Single or more double, max any error 1e-6rcmp9.cpp
- Single or more double, max any error 1e-9wcmp.cpp
- Sequence of tokensyesno.cpp
- Single yes or no, case insensitiveПример чекера для задачи, описанной выше (используется стандартный fcmp.cpp
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "testlib.h"
#include <string>
#include <vector>
#include <sstream>
using namespace std;
int main(int argc, char * argv[])
{
setName("compare files as sequence of lines");
registerTestlibCmd(argc, argv);
std::string strAnswer;
int n = 0;
while (!ans.eof())
{
std::string j = ans.readString();
if (j == "" && ans.eof())
break;
strAnswer = j;
std::string p = ouf.readString();
n++;
if (j != p)
quitf(_wa, "%d%s lines differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), compress(j).c_str(), compress(p).c_str());
}
if (n == 1)
quitf(_ok, "single line: '%s'", compress(strAnswer).c_str());
quitf(_ok, "%d lines", n);
}
Каждой задаче соответствует раздел в настройках контеста (файл serve.cfg
).
Для задания общих настроек для всех задач используются “абстрактные” задачи. Пример настройки такой задачи:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[problem]
abstract
short_name = "PskovGeneric"
use_stdin
use_stdout
use_corr
xml_file = "statement.xml"
test_pat = "%02d"
corr_pat = "%02d.a"
time_limit = 5
real_time_limit = 10
max_vm_size = 256M
max_stack_size = 256M
max_file_size = 256M
check_cmd = "check"
Здесь определены настройки:
PskovGeneric
statement.xml
.a
Далее описываются настройки конкретных задач.
Пример настройки для задачи. описанной выше:
1
2
3
4
5
[problem]
super = PskovGeneric
internal_name = "rot13"
short_name = "B"
long_name = "Шифр ROT13"
Здесь определены настройки:
PskovGeneric
(описанная выше)rot13
(в каталоге с таким именем задача будет хранится на сервере ejudge)B
Шифр ROT13
Статья в ejudge wiki содержит подробное описание настроек контеста.
Задачи удобно готовить в системе polygon. Она поддерживает множество возможностей по организации работы над отдельными задачами и над контестом в целом.
Некоторые полезные возможности:
Существует возможность автоматизированной загрузки задач и контестов из polygon в ejudge. Однако на момент написания руководства условия не импортировались: polygon использует для оформления условий TeX, а ejudge HTML.