我们使用 MDX——一种 Markdown 的超集,并通过 XDM 编译器处理。它支持 HTML 和 React 组件,因此可以为每个模块添加交互功能和自定义组件。
前置元数据
前置元数据(Frontmatter)位于每个模块开头,由三条短横线包围。它使用 YAML 编写,用于保存模块的“元数据”。
- ID:必填。模块 ID,例如
getting-started或containers。它用于标识模块,因此必须唯一,并且只使用小写字母和短横线。网址会根据它生成。 - 标题(Title):必填。模块标题,例如
Getting Started。 - 作者(Author):必填。模块作者,例如
Unknown。 - 贡献者(Contributors):可选。为模块贡献代码或简短说明的人。
- 描述(Description):必填。模块的简短描述,类似 Codecademy 教学大纲中的描述。描述字段不支持 Markdown 或 LaTeX。
- 前置知识(Prerequisites):可选。学习该模块前需要掌握的内容。如果要引用另一个模块作为前置知识,请填写其模块 ID,系统会自动生成链接。
- 出现频率(Frequency):可选。取 0~4 的整数,其中 0 表示从未出现,4 表示大约每场比赛出现一次。如果不想显示频率,请省略该字段。
- 重定向(Redirects):可选。一组会重定向到当前模块的网址。每当修改模块 ID 或将模块移动到其他组别时,都应添加重定向。
前置元数据示例
--- id: getting-started title: Getting Started description: Welcome to the guide! We'll introduce what programming competitions are and how this guide is organized. author: Nathan Wang order: 1 prerequisites: - Dummy prerequisite - running-cpp redirects: - /silver/bipartite --- # Getting Started ...
模块顺序
content/ordering.ts 文件保存模块顺序。其格式应当不言自明(通过 ID 进行匹配)。
链接到模块
在指南内部链接到另一个模块时,应使用以下格式:
[在此插入文字](/general/practicing)。
不要使用 practicing 这样的相对链接,否则会破坏我们的链接检查器。
目录
系统会根据 Markdown 标题自动生成目录。设置模块格式时请牢记这一点。
MDX 与自定义组件
我们使用 XDM 编译器,它与 MDX v1 有一些区别:
- 完全支持在 JSX 中穿插 Markdown;例如,
<Info>some **markdown**</Info>可以按预期工作。 - 作为上一点的延伸,它完全支持缩进。可以缩进 JSX 标签内嵌套的 Markdown。这也意味着,用四个空格缩进文本不会使其变成代码块;请明确使用三个反引号包围代码块。
<和>需要用反斜杠转义,例如\<。
请注意,JSX 注释({/* ... */})与 Prettier 的配合不佳,因此请改用 HTML 注释。在内部,我们会先将 HTML 注释映射为 JSX 注释,再把 Markdown 交给 XDM。即使暂时无法理解全部细节,也不用担心。
以下组件在每个模块中都可全局使用,无需导入:
<Spoiler><Info><Warning><Optional><Problems><FocusProblem><Resources><Resource><TextTooltip><LanguageSection><CPPSection><JavaSection><PySection><CPPOnly><JavaOnly><PyOnly><IncompleteSection><Asterisk><Quiz>
下面会逐一说明这些组件。
折叠内容
折叠内容是只有用户点击后才会显示的可折叠元素,适合用于编写题目提示或解答。按照约定,模块题解不使用折叠内容。
<Spoiler title="Show Hint"> - Insert hint here </Spoiler>
显示提示
信息块
<Info title="Insert Title Here"> **Markdown is Supported!!** </Info>
在此插入标题
支持 Markdown!
警告块
<Warning title="Insert Title Here"> Fun fact: the title attribute is optional. </Warning>
小知识:title 属性是可选的。
选学内容
<Optional title="Insert Title Here"> Fun fact: the title attribute is optional. </Optional>
小知识:title 属性是可选的。
题目列表
每个模块对应两个文件:一个 .mdx 文件和一个 .problems.json 文件。.problems.json 保存该模块使用的重点题目与题目列表,同时还会被 Algolia 建立索引,用于题目搜索。
.problems.json 文件保存一个对象,其中键是题目列表名称(或重点题目名称),值是 ProblemMetadata 对象数组。对于重点题目,数组长度必须恰好为 1。此外,.problems.json 文件还应包含 MODULE_ID 键,其值为表示模块 ID 的字符串。
关于题目定义的更多信息,请参阅 src/models/problem.ts。
用法示例:
<Problems problems="problems" />
[module].problems.json 应包含键 problems,其值对应一个 ProblemMetadata 数组。
ProblemInfo 和 ProblemMetadata 之间有所区别。[module].problems.json 中保存的是 ProblemMetadata。构建时,内容索引器会将 ProblemMetadata 转换为 ProblemInfo;React 组件在处理题目信息时使用 ProblemInfo。下面的文档介绍内容作者需要编写的 ProblemMetadata。
ProblemMetadata 字段:
uniqueId——题目的唯一 ID。做题进度与此字段关联,因此不要修改它,否则进度会丢失。按照约定,其格式为 [source]-[SlugifiedProblemNameCamelCased]。
- 如果题目名称只有一个单词,该单词使用小写。
- 如果题目来自 USACO 或 CSES,唯一 ID 分别使用
usaco-[USACO URL Number]或cses-[CSES number]。 - 如果题目来自 Codeforces,唯一 ID 使用
cf-[contestNumber][problemLetter];如果来自 CF Gym,则使用cfgym-[gymNumber][problemLetter]。 - 如果题目是带年份的 OI 题目,唯一 ID 使用
[oiName]-[twodigityear]-[slugifiedName]。
以下是一些唯一 ID 示例:
cses-2177 poi-08-blockade apio-18-duathlon dmoj-investment infoarena-xortransform usaco-949 cses-1691 kattis-chineseremainder cfgym-102538F cf-1209H spoj-LexicographicalStringSearch ys-AssociativeArray
唯一 ID 相同的题目,其名称、来源和网址也应完全相同。
name——题目名称,不应包含来源。
示例:
2009 - Beetle Greedy Pie Eaters Zuma 2014 - The Stables of Genghis Khan
source——题目来源。可选值:待补充,请参阅 src/models/problem.ts 中的 contests 和 probSources。
difficulty——题目相对于所在模块的难度。可选值为 Very Easy、Easy、Medium、Hard、Very Hard、Insane。
isStarred——是否将题目标为重点。
tags——题目的标签列表。
solutionMetadata——题解信息。
export type ProblemMetadata = Omit<ProblemInfo, 'solution'> & {
solutionMetadata:
| {
// auto generate problem solution label based off of the given site
// For sites like Codeforces: "Check contest materials, located to the right of the problem statement."
kind: 'autogen-label-from-site';
// The site to generate it from. Sometimes this may differ from the source; for example, Codeforces could be the site while Baltic OI could be the source if Codeforces was hosting a Baltic OI problem.
site: string;
}
| {
// internal solution
kind: 'internal';
}
| {
// URL solution
// Use this for links to PDF solutions, etc
kind: 'link';
url: string;
}
| {
// Competitive Programming Handbook
// Ex: 5.3 or something
kind: 'CPH';
section: string;
}
| {
// USACO solution, generates it based off of the USACO problem ID
// ex. 1113 is mapped to sol_prob1_gold_feb21.html
kind: 'USACO';
usacoId: string;
}
| {
// IOI solution, generates it based off of the year
// ex. Maps year = 2001 to https://ioinformatics.org/page/ioi-2001/27
kind: 'IOI';
year: number;
}
| {
// no solution exists
kind: 'none';
}
| {
// for focus problems, when the solution is presented in the module of the problem
kind: 'in-module';
moduleId: string;
}
| {
kind: 'sketch';
sketch: string;
};
};
题解也使用 MDX 编写,其前置元数据包含四个字段:
--- id: cses-1621 source: CSES title: Distinct Numbers author: Nathan Wang --- ... solution
题解前置元数据中的 ID 必须与题目的唯一 ID 相同。还要确保将所有相关题目的 solutionMetadata 中的 kind 更新为 'internal'。我们假定只要存在站内题解,就应当使用它;因此,如果存在站内题解,但 solutionMetadata 的 kind 未设为 'internal',构建就会报错。添加题解模块介绍了如何添加新题解。
重点题目
将一道题显示为“重点题目”。
<FocusProblem problem="genPermutations" />
[module].problems.json 应包含键 genPermutations,其值对应一个长度为 1 的数组。
资源列表
<Resources>
<Resource
source="Errichto"
title="Video - How to test your solution"
url="https://www.youtube.com/watch?v=JXTVOyQpSGM"
starred
>
using a script to stress test
</Resource>
...
</Resources>
| Resources | |||||
|---|---|---|---|---|---|
| Errichto | 使用脚本进行压力测试 | ||||
根据来源提供的特殊功能:
- 如果来源是一本书,系统会自动将网址设为该书的链接。
- 支持的书籍:
GCP(Guide to Competitive Programming)CPH(Competitive Programming Handbook)PAPS(Principles of Algorithmic Problem Solving)PAPS1(Principles of Algorithmic Problem Solving)CP2(Competitive Programming 2)IUSACO(Darren 的书;会根据用户选择的语言自动设置网址;Python 用户使用 C++ 版本)
- 对于某些来源,系统会自动生成工具提示(列表见此处)。
工具提示
工具提示主要有两类:文本工具提示会在文字下方显示虚线;星号工具提示则渲染一个可悬停查看的星号。
<TextTooltip>
在此填写简短文字<TextTooltip content="Popup text goes here">short text goes here</TextTooltip>
<Asterisk>
<Asterisk>Popup text goes here</Asterisk>
未完成章节
<IncompleteSection> - this list is optional and can be used to specify what is missing - missing 32-bit integer explanation </IncompleteSection>
This section is not complete.
- 此列表可选,可用于说明缺少哪些内容
- 缺少 32 位整数的说明
代码块与代码片段
与普通 Markdown 一样,代码块由三个反引号分隔。此外,我们还支持可折叠代码片段。下面是用法示例:
带标题
// Before
// BeginCodeSnip{Optional Code Snippet Title}
// Code snippet goes here
// You can indent the entire BeginCodeSnip block (including the BeginCodeSnip line) and it will function as expected
// EndCodeSnip
// After
// BeforeCode Snippet: Optional Code Snippet Title (Click to expand)
不带标题:
// BeginCodeSnip{}
// My snippet code goes here
// EndCodeSnip
// My non-snippet code goes here
Code Snippet (Click to expand)// My non-snippet code goes here
Kattio 有一种简写方式,定义在 src/mdx-plugins/rehype-snippets.js 中,通过 CodeSnip{Kattio} 使用。
Kattio
CodeSnip{Kattio} 会被替换为相应缩进的版本(缩进量取决于 CodeSnip 的缩进):
import java.io.*;import java.util.*;public class myClass {Code Snippet: Kattio (Click to expand)public static void main...}
特定语言内容
<LanguageSection> <CPPSection> #### A heading that only appears in C++ ```cpp C++ code here ``` </CPPSection> <JavaSection> #### A heading that only appears in Java ```java Java code here ``` </JavaSection> <PySection /> </LanguageSection>
在上面的示例中,Python 不会渲染任何内容。
如果只想为一种语言渲染内容,使用 CPPOnly、JavaOnly 或 PyOnly 会更加方便:
<CPPOnly> #### A heading that only appears in C++ ```cpp C++ code here ``` </CPPOnly>
C++
只在 C++ 中显示的标题
C++ code here
Java
Python
测验
<Quiz>
<Quiz.Question>
Binary search
<Quiz.Answer>
$O(\log n)$
<Quiz.Explanation>
Almost. Prefer $\mathcal{O}$ over $O$.
</Quiz.Explanation>
</Quiz.Answer>
<Quiz.Answer correct>
$\mathcal{O}(\log n)$
<Quiz.Explanation>
That's correct!
</Quiz.Explanation>
</Quiz.Answer>
<Quiz.Answer>
O(log n)
<Quiz.Explanation>
That's not right. Latex is important...
</Quiz.Explanation>
</Quiz.Answer>
</Quiz.Question>
<Quiz.Question>
```cpp
for (int i = 0; i < 100; i++) {
for (int j = 0; j < m; j++) {
// constant time code here
}
}
```
<Quiz.Answer>
$O(100m)$
<Quiz.Explanation>
That's not correct. Constant factors are ignored.
</Quiz.Explanation>
</Quiz.Answer>
<Quiz.Answer correct>
$O(m)$
<Quiz.Explanation>
That's correct!
</Quiz.Explanation>
</Quiz.Answer>
</Quiz.Question>
</Quiz>
二分查找