跳到主要内容

如何用 Markdown 和 LaTeX 写一篇排版整齐的题解?

提示

本文并非官方文档,而是由用户 StudyingFather 撰写的指南性文章,见末尾 Reference 部分的“本文原文链接”。洛谷官方不对本文的适用性做任何保证。

本文将会对 Markdown 和 LaTeX\LaTeX 的语法进行深入解读,旨在教会阅读本文的读者正确使用 Markdown 和 LaTeX\LaTeX 书写博客或题解。

本文将会通过正反对比的方式,指出一些做法的错误之处,并给出相应的正确做法。

笔者假设将要读本文的读者已经掌握了 Markdown 和 LaTeX\LaTeX 的语法。如果您还不熟悉的话,建议先查阅末尾 Reference 部分的资料。

接下来进入正题。

1 一些基本格式要求

这里是一些非常基本的格式要求,适用于任何格式的文本文档。

  1. 请在每句话的末尾添加句号;
  2. 请正确使用标点符号,注意区分全角符号与半角符号的使用(汉语请使用全角符号,英语请使用半角符号);
  3. 中文与西文字符或公式之间以一个半角空格隔开,但标点符号与西文字符或公式间不要加空格

下面是一些错误示范:

  • 然而即使这样优化后它看上去还是十分辣手(违反 1.1)
  • 众所周知,生存还是死亡,这是个问题.(违反 1.2)
  • 该算法的时间复杂度为O(n2)O(n^2),无法通过n105n \leq 10^5的数据,需要使用Dijkstra的堆优化算法。(违反 1.3)

我们来修正一下:

  • 然而即使这样优化后它看上去还是十分辣手。
  • 众所周知,生存还是死亡,这是个问题。
  • 该算法的时间复杂度为 O(n2)O(n^2),无法通过 n105n \leq 10^5 的数据,需要使用 Dijkstra 的堆优化算法。

2 在正确的地方,用正确的语言

如果你的题解要公开让其他人看到,请顾及他人感受。

以下几点是不提倡的:

  1. 出现不友好的语言(尤其是入门题);
  2. 代码中出现大块的预编译指令;
  3. 分析内容过少(尤其是需要推导的数学题以及模板题);
  4. 啰嗦太多无关的废话。

下面是错误示范。

  • 这是一道大水题!其他的题解咋都写那么烂!(违反 2.1)
  • 这个题目是一个数学题,打表可以发现答案是 a×baba \times b - a - b。(违反 2.3)
  • 先让我吐槽一下背景和数据(中间省略 251251 字)。(违反 2.4)

3 标题的使用

标题是引导文章结构的,不是用来强调的。

因此请不要用标题把字弄的很大,达到强调的目的。

下面是错误示范(为了不破坏文章 TOC,把错误示范用代码块框了起来):

# 这是一道非常水的题!!!
## 我们可以用贪心来解决本题。
# 求管理员审核通过 QAQ

同样的道理,大段的加粗强调也是不合适的。强调的目的是让读者找到重点,如果全是重点,那和没有重点又有什么区别呢?

4 列表的食用方式

4.1 无序列表

Markdown 中的无序列表可以用 *-+ 表示,并且它们都是等价的。

- QAQ
- QwQ
- QvQ

显示的效果是(把前面的 - 换成 *+ 渲染效果一样):

  • QAQ
  • QwQ
  • QvQ

当然,+ 号用的较少,这里不推荐大家使用。

-* 中,因为 * 已经担当了较多的用途(包括加粗,斜体等),为了防止歧义,推荐大家用 - 表示无序列表。

4.2 有序列表

下面的形式描述了一个有序列表:

1. QAQ
2. QwQ
3. QvQ

显示的效果是:

  1. QAQ
  2. QwQ
  3. QvQ

下面也是一种比较推荐的有序列表写法。

1. QAQ
1. QwQ
1. QvQ

它的渲染效果是:

  1. QAQ
  2. QwQ
  3. QvQ

5 代码框

5.1 一般要求

使用代码框时,请标上代码的语言,以正确地渲染代码。

对于非代码部分,语言可以设置为 plain,避免错误地高亮。

5.2 代码可读性要求

人与人之间的代码风格差异还是挺大。不过题解对代码风格的要求并不高,只需要可读性好即可。

对于注释,需要避免注释喧宾夺主

下面是一个典型的注释喧宾夺主的例子(/* */ 注释的部分指出问题所在):

#include<bits/stdc++.h>//万能头文件
/* 这个头文件是万能头文件很重要吗? */
using namespace std;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);//优化cin,cout,险些TLE。
/* 同前。 */
int a[100005],n;
cin>>n; // 输入礼物数。
/* 题目输入格式里已经把输入的每个数字的含义写的很清楚了。 */
for(int i=1;i<=n;i++)//代表n个礼物。
/* 还能是几个礼物? */
{
cin>>a[i];//输入坐标。
/* 同前。 */
a[i]=min(a[i]-1,1000000-a[i]);//取最小值min。
/* 是当读者完全不知道 min 函数吗? */
}
sort(a+1,a+1+n);//排序后取最大值。
/* 同前。 */
cout<<a[n];//将最大值输出。
/* 同前。 */
return 0;//结束。
/* 不是结束还能是啥? */
}
/* 总结:请不要把读者当完全没学过语言的傻子。 */

5.3 长代码片段的处理

有很多情况都会导致长代码的产生。长代码片段对题解的观感会造成不小影响。

对于长代码片段,推荐在正文中只贴出关键部分,而将完整代码置于云剪贴板中。

6 正确使用 LaTeX

进入本文的重点了。

这里希望能教会读者正确使用 LaTeX\LaTeX,规避一些错误用法。

6.1 什么东西该放在公式中?

并不是一切东西都该放在公式中的。滥用公式会导致渲染速度下降,排版混乱等后果。

下面是一个错误示例:

关于 SPFASPFA,它死了。我们应该使用堆优化的 DijkstraDijkstra 算法解决单源非负权最短路问题。

正确的写法是:

关于 SPFA,它死了。我们应该使用堆优化的 Dijkstra 算法解决单源非负权最短路问题。

所以什么东西不该放在公式中呢?

  1. 中文一般不要放在 LaTeX\LaTeX 中。
  2. 算法名,人名等非公式内容一般不要放在 LaTeX\LaTeX 中。
  3. 行内的程序代码(包括程序函数名称,变量类型,完整语句等)应该用行内代码框表示,而不放在公式中。

下面还是一个错误示例:

这是一个错误示例\huge{\text{这是一个错误示例}}

还是那句话,要强调的东西没必要弄得那么大。

即使是要放在公式里的东西,对于使用何种字体仍有要求,下面将会讲到。

6.2 正确使用不同的字体

请使用 Roman 体表示函数和运算。

LaTeX\LaTeX 中已经预先定义了很多常用的函数和运算,我们可以直接使用。

下面是一个错误的例子:

lcm(x,y)=\frac{x \times y}{gcd(x,y)}
lcm(x,y)=x×ygcd(x,y)lcm(x,y)=\frac{x \times y}{gcd(x,y)}

正确的写法应该是这样的:

\operatorname{lcm}(x,y)=\frac{x \times y}{\gcd(x,y)}
lcm(x,y)=x×ygcd(x,y)\operatorname{lcm}(x,y)=\frac{x \times y}{\gcd(x,y)}

又一个错误的例子:

f(x,y)=max(x,y)
f(x,y)=max(x,y)f(x,y)=max(x,y)

正确的写法是这样的:

f(x,y)=\max(x,y)
f(x,y)=max(x,y)f(x,y)=\max(x,y)

简单概括一下:

  1. 对于 gcd\gcdlog\log 这些已经有定义的,请在书写它们的时候在前面直接加一个 \,例如 gcd\gcd 请写成 \gcd
  2. 对于 lcm\operatorname{lcm} 这样没有定义的,请将它包含在 \operatorname{} 中。

接下来特别讲一下 mod 运算符。

mod 运算符有三种,\mod\bmod\pmod,其中较常用的是 \bmod\pmod。下面举例说明它们的区别。

\bmod 一般用来表示模运算操作:

x = a \bmod b
x=amodbx = a \bmod b

\pmod 则一般用于书写同余方程:

3 \equiv 8 \pmod 5
38(mod5)3 \equiv 8 \pmod 5

对于一些字符串常量,使用打字机字体看上去更加美观。

错误的示范:

S=abcdefg
S=abcdefgS=abcdefg

正确的写法:

S=\texttt{abcdefg}
S=abcdefgS=\texttt{abcdefg}

对于非公式内容,应该使用 \text{}

错误的示范:

f(a) = \begin{cases}
1 ,& a \in prime\\
0 ,& otherwise.
\end{cases}
f(a)={1,aprime0,otherwise.f(a) = \begin{cases} 1 ,& a \in prime\\ 0 ,& otherwise. \end{cases}

正确的写法:

f(a) = \begin{cases}
1 ,& a \in \text{prime}\\
0 ,& \text{otherwise.}
\end{cases}
f(a)={1,aprime0,otherwise.f(a) = \begin{cases} 1 ,& a \in \text{prime}\\ 0 ,& \text{otherwise.} \end{cases}

6.3 行间公式

对于 \sum \prod 等巨运算符,放在行内公式会显得比较紧凑。

像这样:i=1nai\sum_{i=1}^n a_i

必要的场合请使用行间公式,这样这些巨运算符就不会显得太小,观感也会好不少。

i=1nai\sum_{i=1}^n a_i

6.4 公式不是写代码的地方

我们写的是非常正规的数学公式,因此不要在非代码区域使用任何程序设计语言的表示方式

下面是一些错误示范:

a=x\%p
x++
a==b
a <= b
a<<1
5e7
a=x%pa=x\%p
x++x++
a==ba==b
a<=ba <= b
a<<1a<<1
5e75e7

正确的写法是这样的:

a=x \bmod p
x \gets x+1
a=b
a \leq b
a \times 2
5 \times 10^7
a=xmodpa=x \bmod p
xx+1x \gets x+1
a=ba=b
aba \leq b
a×2a \times 2
5×1075 \times 10^7

注:xx+1x \gets x+1 表示将 x+1x+1 的值赋给 xx(其实等号也可以表示赋值的含义,不过在这个场景下这种写法更加严谨)。

这里附一些常用符号的表示方法,以供参考:

  • 小于等于号 aba \leq b\le\leq
  • 大于等于号 aba \geq b\ge\geq
  • 另一种格式的小于等于号 aba \leqslant b\leqslant
  • 另一种格式的大于等于号 aba \geqslant b\geqslant
  • 横向省略号(居于排版基线的位置){1,2,,n}\{1, 2, \ldots, n \}\ldots
  • 横向省略号(居于排版基线与顶线中间)1+2++n1 + 2 + \cdots + n\cdots
  • 叉乘 a×ba \times b\times
  • 点乘 aba \cdot b\cdot
  • 整除 aba \mid b\mid

更多资料可以在文末的 Reference 部分找到。

6.5 数组的表示

在题解中常常要写到数组,怎样表示比较优美呢?

我们推荐使用多元函数的形式表示数组。例如:f[i][j] 表示成 f(i,j)f(i,j)

当然用下标的形式也是不错的选择。像上面的例子可以表示为 fi,jf_{i,j}

6.6 分数

一般情况下,用 \frac{x}{y} 表示分数 xy\frac{x}{y}

但是行内这个分数实在是太小了。

这种情况下我们更建议使用 \dfrac{x}{y} 表示分数 xy\dfrac{x}{y}

(你会发现这个就大不少了)

6.7 特殊符号

不要使用输入法的插入特殊符号功能来插入我们下面要说的特殊符号。

下面是一些特殊符号在 LaTeX\LaTeX 的表示方法。

  • 欧拉函数 φ\varphi\varphi(注意不是 \phi);
  • 黄金分割数 ϕ\phi\phi
  • 圆的直径 Φ\Phi\Phi
  • 莫比乌斯函数 μ\mu\mu
  • 圆周率 π\pi\pi
  • 空集 \varnothing\varnothing(注意不是 \emptyset)。

更多资料可以在文末 Reference 部分找到。

7 外部链接

在一篇题解中,有一些相关知识并不是题解内容的重点,但又属于理解题解所需的必不可少的内容。虽然在大多数情况下可以假设读者已经了解了相关知识,但在某些特殊情况下,还是需要给出一些外部链接,方便阅读该题解的同学学习。

例如,在 NOIp2001 一元三次方程求解 的题解区中,有好几篇题解都提及了盛金公式,却并没有对其进行任何解释,也没有给出外部链接。这很容易让阅读该题解的人感到疑惑。

后记

网上关于 Markdown 和 LaTeX 的资料其实并不少(在 Reference 部分已经列出),那为什么还要有这篇文章呢?

本文大多数常见的错误例子都是笔者在题解审核时经常遇到的。举这些错误例子也是希望各位读者引以为戒,在未来的博客撰写中严格遵守格式规范,使题解的排版更加美观。

Reference