缩进使用长度为 4 的 Tab,一个长度为 4 的 Tab 记作一个单位的缩进。同一个代码块的缩进必须统一。
大括号不换行,左大括号{与右圆括号)或函数名之间有空格。一般地,右大括号的缩进与上一级代码块 (含左大括号的行) 相同,中间的代码块向前缩进一个单位。例:
struct fy {
int id, age;
void ak(int score) {
std::cout << "ckr ak zjoi2019 !" << std::endl;
return;
}
};
特殊地,如果该函数 (过程/结构体) 比较短,则服从 "单行代码块" 格式:
该格式中,左大括号前依然有空格,函数等在一行内完成,右大括号紧随其后。例:
inline void up(int &x, const int y) {x < y ? x = y : 0;}
struct pr {int x, y;} p[100];
struct/class等声明完毕后,如果大括号后为分号,则紧随其后;如果为变量,则中间以一个空格分割。(例子见上两例)
左圆括号(前,如果是函数等非关键字 (不管是声明还是调用),中间不加空格,如果为 if/for/while 等关键字,中间以一个空格分割。例:
sort(a, a + n);
for (i = 0; i < n; ++i)
if (a[i] % 3)
fy_get(a[i]);
do后如果有大括号,则它们之间以一个空格分割,其后的while前也有空格。(例子略)
单目运算符与操作数之间一律不添加空格。如:!x,-y,++i。
一般的双目和三目运算符 (不包括中括号运算符),以及构造函数中的单冒号,运算符的两侧均要添加空格,如:a + 1,p[x] == x ? x : (p[x] = ancestor(p[x])) 等。
当然,代表成员关系的双目运算符 (::, ., ->) 两侧不添加空格,如:std::sort,b.first,it->second。
特殊地,逗号运算符的左侧不能有空格,右边则必须有空格。
当一行有用分号隔开的多个语句时 (包括 for 循环的三个条件,甚至空的 for 循环),分号前不加空格,分号后必须加空格。例:
x[id].v += v; x[id].sum += v * L;
for (; ; ) {
for (j = 0; j < n; ++j)
if (test(j))
break;
++round;
}
下列情况下必须以一个空行隔开:
下列情况下推荐以一个空行隔开:
如果是行末注释,则注释与该行最后一个可见字符 (通常是大括号或分号) 之间用空格隔开。
模数一律使用const,例:
typedef long long ll;
const ll mod = 998244353, root = 31;表示数组大小的常量可以使用#define,也可以使用 const,但是如果有多个namespace 都需要定义数组时,则必须使用const,并采取如下方案:
const int N = 100005;
namespace fy {
const int N = ::N << 1, M = ::N * 5;
...
}
namespace sorting {
const int N = ::N * 3;
...
}
表示数组大小的常量,往往要略大于数据规模,如 $10^5 + 5, 2 \times 10^7 + 5$ 等。
全局变量必须代表着全局的意义,比如题目规模 n 或跟题目密切相关的主数组 a[i]。
循环下标 i,j 等一律定义成局部变量,并且如果频繁使用,则尽量在该过程开头写int i, j;等,如果使用次数较少,可以在 for 循环中即时定义。
类型定义一律使用 typedef,允许使用 using,极不推荐使用 #define。
定义变量的行必须为新行,即不能在一个常规语句 (包括定义变量语句) 后又跟一个变量声明语句。即,下面的情形是禁止的:
fy[2] += fy[1]; int i, j;
for (i = 0; i < fy[2]; ++i) j += fy[1];
一行内不能定义太多 (10 个以上) 变量,否则会显得凌乱,更不能一行把所有 int 型变量定义完 (除非就四五个)。例:
int V, E, Es;
int first[N], next[M]; // adj
int cnt = 0, id[N], low[N]; // tarjan
int stc = 0, sta[N], in_stack[N]; // stack
int scc = 0, bel[N], top[N]; // shrink
int deg[N], size[N], que[N]; // toposort
int f[N], g[N], hash[N]; // dp
int ans, Count;
如果代码较长,且有比较多的子块时,推荐使用多个 namespace 来避免变量冲突,如 Tree::cnt, Graph::cnt, SA::cnt。极不推荐使用诸如 cnt1, cnt2, first1, first2, cnt, Cnt 等命名方法。
运行时间在 $O(1)$ 的单行函数尽量加 inline。
外部比较器一律使用 (const T x, const T y) 型传值。
合理选用乘法和左移,除法和右移,模和按位与。下面是不明文规定的规则:当不开 -O2 时用位运算,开 -O2 时用乘除法,特殊地,(不管有没有 -O2) 模尽量改成按位与。
如果乘除模的参数非 $2$ 的幂次,一律使用乘、除、模,不使用自己手工移位,编译器的优化一定比你手工的强。特殊地,IO 优化中关于十进制的运算一律使用 * 10 和 / 10。
在明确运算符的优先级情况下,可以不加括号,否则推荐加括号 (比如 &, |, ^ 三个运算符)。
特别地,赋值运算符 = 和三目运算符 ? : 的优先级不确定 (都可能比对方高),此时一律加括号。(可以参考上面的并查集例子)
当前置和后置的自增运算符都能使用时,推荐使用前置的。尤其是 STL 的 iterator,更要如此。(如果开了 -O2,可能关系不大)
sizeof 运算符后如果后面为变量或数组,则不加括号。
转 long long 尽量使用 (ll)x * y 而不是 1ll * x * y,特殊地,如果还要乘一个系数 $2$ 等,可以使用 2ll * x * y。(转 double 类似)
尽量不使用 using namespace std;,这点极其重要,可以避免莫名其妙的变量冲突导致 Compile Error,需要使用的 STL 标准库中的内容在前面加 std::。频繁使用的函数 (如排序),可以在前面加 using std::sort;。
if 和 else 不能位于同一行,else 之前必须换行。但是如果前面或后面是花括号,则在同一行。例:
if (i % p[j]) ++a;
else ++b;
if (a + b == 100) {
std::cout << "ok\n";
} else {
std::cout << "failed\n";
}
如果一个 if - else 语句里面的操作比较短可以被三目运算符优化掉,尽量去手动优化,因为 if 的误判惩罚很高。比如,上例的两个语句可以改成:
i % p[j] ? ++a : ++b;
std::cout << (a + b == 100 ? "ok\n" : "failed\n");
循环上限尽量不使用函数型,比如 vec.size(),尽量替换成下列两种方案之一:
for (i = (int)vec.size() - 1; i >= 0; --i)
// do something;
for (n = (int)vec.size(), i = 0; i < n; ++i)
// do something;
所有预编译指令 # 均位于程序开头 (有特例);类型声明、常量定义紧随其后;接着是全局变量定义;所有全局变量定义完毕后才是定义所有的函数。
这其中每两个部分之间均用空行分隔。
小于等于,大于等于一律使用 \leq, \geq。
空集一律使用 \varnothing,不使用 \emptyset。
所有运算符 (不论单目还是双目) 与操作数之间必须以空格隔开,例:$1 \leq i < j \leq n$。
行内公式中,分数和二项式系数尽量使用 \dfrac 和 \dbinom。行内的和式、乘积式均要添加 \limits。
如果行内公式不提供可视版本 (如 Stirling 数),则需在前面手动添加 \displaystyle。
按位与、或、异或、非分别使用 \mathbin{\&}, \mid, \oplus, \neg,效果:$a \mathbin{\&} b, a \mid b, a \oplus b, \neg a$。
逻辑与、或、异或、非分别使用 \wedge, \vee, \oplus (或 \veebar), \neg (或 !),效果 $a \wedge b, a \vee b, a \oplus b (a \veebar b), \neg a (! a)$。
标准数学函数必须使用正体,如 \log, \sin, \gcd 等。
如果库里面没有,则需使用 \mathrm 或 \operatorname 使之变为正体。
微分算子 $\mathrm dx$ 的 d 和虚数单位 $\mathrm i$ 使用正体。
若字母表示变量,则使用斜体,若字母表示物理单位等,则使用正体。例:$m = 30 \mathrm{kg} + m_0$,效果:$m = 30 \mathrm {kg} + m_0$。
当有多个不等式,每个不等式有多个变量时 (尤其是限制与约定部分),变量之间用逗号隔开,不等式之间用分号隔开。例:
$1 \leq n, m \leq 10^5; a_i, b_i \leq 10^9; a_i \neq b_i$,效果:$1 \leq n, m \leq 10^5; a_i, b_i \leq 10^9; a_i \neq b_i$。
中文和英文、公式之间必须以一个空格隔开,但是和中文的标点之间不能有空格。例:
fy 最可爱啦,她要 AK! 给定 $n$ 个数 $a_1, a_2, \cdots, a_n$。
超链接的两侧可以加空格,但是如果不加空格,则必须按照中西文遵守第 1 条规则。
<code> 标签两侧可以不加空格,但是推荐加空格。
数字与单位之间尽量不加空格。
自闭合 (self-closing) 标签必须在后面添加 " />" 三个字符,例:<br />, <img src="fy.jpg" alt="fy" />。
<img> 标签必须添加 alt 属性。
超链接 <a> 标签尽量添加 target="_blank" 选项。
加粗、斜体、下划线、删除线尽量使用 <strong>, <em>, <ins>, <del> 标签。
其它字体属性 (如颜色) 尽量使用 CSS,如 <font color="red"> 尽量改为 <span style="color: red">。
类似地,图片的宽度尽量从 <img width="800px"> 改为 <img style="width: 800px">。
较为生僻的缩写必须在每一处使用 <abbr> 标签展示全名,例:<abbr title="Euler Tour Tree, 欧拉环游树">ETT</abbr>,效果:ETT。