洛谷MYOI月报【7月刊】
duanfeitong
·
2023-07-01 19:43:59
·
个人记录
\Huge\color{orange}\texttt{洛谷MYOI月报 7月刊}
文章作者:@Cyx20110930 @duanfeitong @__immccn123__ @2044_space_elevator
审核:@duanfeitong @SaintRelief @Dream_Creator
技术支持:@L1uTongwei
格式修改:@Dream_Creator
欢迎加入 MYOI出题组!也欢迎向@SaintRelief投递广告(详情见本报最下方)
您也可以在这里阅读本刊:
云剪切板:https://www.luogu.com.cn/paste/hlw6kyz5
\Large\text{卷首语-历史上的七月}
}
七月,是一个充满了激情、热血与奋斗的月份。提起七月,你想起的可能是炎热天气、漫长白天、冰激凌、空调、风扇以及超多的暑假作业……但是,还有一些永远值得记忆的日子,发生在过去的七月。
\large\texttt{7.1}
2023年7月1日,是建党 102 周年。一百余年前,1921年的夏天,一条小船承载着人民的重托、民族的希望,像一盏明灯,冲破黑暗,照亮了中国革命的航向!
同时,2023年7月1日也是香港回归 26 周年。1997年7月1日起,中国在香港成立特别行政区,开始对香港岛、界限街以南的九龙半岛、新界等土地重新行使主权和治权,香港回归祖国怀抱。
\large\texttt{7.4}
1776年7月4日,美利坚合众国成立。
\large\texttt{7.6}
1840年7月6日,第一次鸦片战争开始。拉开了中国近代史的序幕,使中国开始沦为半殖民地半封建社会。
\large\texttt{7.7}
2023年7月7日,是卢沟桥事变(又称“七七事变”)86周年。1937年7月7日,日本开始全面侵华,抗日战争爆发。
\large\texttt{7.13}
2001年7月13日,北京申奥成功,获得了2008年第29届夏季奥林匹克运动会的举办权。
\large\texttt{7.20}
1822年7月20日,遗传学的奠基人、现代遗传学之父格雷戈尔·孟德尔出生于奥地利帝国。
\large\texttt{7.26}
1945年7月26日,《波兹坦公告》发表。
让我们永远地记下这些或神圣或悲哀或伟大的时刻吧!
\Large\text{Introduction to graph theory(图论简介)}
\color{orange}\text{作者:2044\_space\_elevator}\ \ \color{blue}\text{ 审核:duanfeitong、Dream\_Creator}
提示,本文为作者原创,同步发布于codeforces:https://codeforces.com/blog/entry/114946
Overview
Graph is a kind of data struction. It's very useful, it can descripe the relationship of a lot things. In the life, we always see the graph, such as the traffic graph. For instance, this is a graph.
There are 4 nodes in this graph. And there are two edges in this graph. It is a undirected graph.
Of course, we have directed graph too. This is directed graph about my genealogy.
This is a directed graph too.
Now, you know what a graph is, and then, I will introduction how to denote a graph.
Denote a graph
There are two representation methods to denote a graph. One is matrix, and the other one is adjacency table, adjacency table is a little complex. In this article, I only introduction matrix representation method.
Undirected graph
For instance, we denote the graph of picture 1, this the matrix of picture 1:
\begin{bmatrix}
0 & 1 & 0 & 0\\
1 & 0 & 1 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & 0 & 0
\end{bmatrix}
In matrix, if node a and node b are connected, A_{ab},A_{ba}=1 , otherwise A_{ab},A_{ba}=0
In picture 1, there are 2 edges, they are:
1 \operatorname{and} 2
2 \operatorname{and} 3
So:
A_{12},A_{21}=1
A_{23},A_{32}=1
Directed graph
There are new rules for representing directed graphs in matrices:
If a \to b , A_{ab}=1
If b \to a , A_{ba}=1
For instance, we denote the graph of picture 3.
There are 4 edges in picture 3, they are:
1\to 2
2\to 3
3\to 4
2\to 4
So, the matrix of picture 3 like this:
\begin{bmatrix}
0 & 1 & 0 & 0\\
0 & 0 & 1 & 1\\
0 & 0 & 0 & 1\\
0 & 0 & 0 & 0
\end{bmatrix}
Weighted graph
This is a weighted graph.
If node a and b are connected, and there weight is k , this is the representation method of weighted graphs.
If a\to b , A_{ab} = k
If b\to a , A_{ba} = k
Otherwise, A_{ab},A_{ba}=\infty
The matrix of picture 4:
\begin{bmatrix}
\infty & 2 & \infty & \infty\\
\infty & \infty & 5 & 3\\
\infty & \infty & \infty & 6\\
\infty & \infty & \infty & \infty
\end{bmatrix}
Denote by code
Undirected graph
Let's first define a two-dimensional array. For instance, this is the input of picture 3.
4
1 2
2 3
3 4
2 4
It means, there are 4 edges in this graph, 1 and 2 was connected, 2 and 3 was connected, 3 and 4 was connected, 2 and 4 was connected.
This is the code to record the graph:
#include <iostream>
using namespace std;
bool A[10][10];
int n;
int main()
{
cin >> n;
while (n--)
{
int node1, node2;
cin >> node1 >> node2;
A[node1][node2] = 1;
A[node1][node2] = 1;
}
return 0;
}
Directed graph
This is the code of denote directed graph.
#include <iostream>
using namespace std;
bool A[10][10];
int n;
int main()
{
cin >> n;
while (n--)
{
int node1, node2;
cin >> node1 >> node2;
A[node1][node2] = 1;
}
return 0;
}
Weighted graph
This is the code of denote directed graph:
#include <iostream>
using namespace std;
#define oo 123456
int A[10][10];
int n;
int main()
{
// init
cin >> n;
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
A[i][j] = oo;
}
}
while (n--)
{
int node1, node2, weight;
cin >> node1 >> node2 >> weight;
A[node1][node2] = weight;
}
return 0;
}
Search algorithm
There are two kinds of search algorithms graphs: depth first search(dfs) and breadth first search(bfs), dfs is easier than bfs, but dfs is very slow.
In this article, we call the first node of graph "root", such as in picture 4, the "root" is node 1.
Depth first search
You maybe have learnt the backtracking algorithm, this is template code for backtracking:
void backtracking(...)
{
if (Marginal Condition)
{
Save result
return;
}
for (int i = startIndex; i <= n; i++)
{
Record vales
backtracking(...);
Delet vales
}
}
Backtracking is a kind of depth first search. , the dfs of graph is very like backtracking, this is the template code of dfs of graph:
bool vis[N]; // Tag
int n; // node number
void dfs(int node)
{
if (node == n)
{
// output path
return;
}
for (int i = 1; i <= n; i++)
{
if ((A[i][node] == 1 || A[node][i] == 1) && !vis[i])
{
vis[i] = 1;
dfs(i);
vis[i] = 0;
}
}
}
Breadth first search
In fact, breadth first search (bfs) equivalent to level traversal, such as, this is the bfs of picture 3, we set the root node is 1.
We need a queue. First, we put the root node in the queue:
queue:
1
path:
And then, we record node 1, and put all children of node 1 in the queue:
queue:
2
path:
1
Next, we record node 2, and put all children of node 1 in the queue:
queue:
3 4
path:
1 2
Finally, we record node 3 and node 4, put all children of them in the queue:
queue:
path:
1 2 4 3
Node 4 has no children, the children of node 3 has a child (node 4), but it has recorded.
So this is the temple code of bfs:
#include <queue> // We need the queue
int A[N][N];
bool vis[N]; // Has visited?
void bfs()
{
queue<int> path;
path.push(/*root node*/);
vis[/*root node*/] = true;
while (!path.empth())
{
int node = path.front();
/*record node*/
path.pop();
for (int i = 1; i <= N; i++)
{
if ((A[node][i] || A[i][node]) && !vis[i])
{
path.push(i);
vis[i] = true;
}
}
}
}
Summarize
Of course, there are many special graphs, such as: binary trees, red-black trees, cyclic graphs and so on. This article introduces the basic knowledge of graphs.
If this article is helpful to you, please give it a positive review. Thank you!
\Large\textbf{中文版}
这是洛谷英文原文,本文不严格按照原文句式翻译,可能会存在小部分修改的情况。
什么是图?
图是一种数据结构。它可以用来描述不同物体之间的关系。我们可以在任何地方看到图,比如一个城市的交通图。例如,这是一个图:
这幅无向图有 4 个结点,两条边。
既然有无向图,那肯定有有向图,这就是描述我家谱的有向图:
这又是一个有向图:
现在,你知道了什么是图,下面我将介绍如何在计算机里存储一个图。
存储一个图
算法竞赛中,有两种常用的存储图的方式:邻接矩阵法和邻接链表法。本文中,我只介绍如何使用邻接矩阵法。
无向图
例如,使用邻接矩阵法存储图一,我们将得到以下矩阵:
\begin{bmatrix}
0 & 1 & 0 & 0\\
1 & 0 & 1 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & 0 & 0
\end{bmatrix}
矩阵中,如果结点 a 与结点 b 之间存在一条边,则 A_{ab}=1 且 A_{ba}=1 。
图一中有两条边,它们是:
因此:
A_{12},A_{21}=1
A_{23},A_{32}=1
有向图
有向图的描述就更简单了,如果 a 有一条边指向 b ,则 A_{ab}=1 。
现在我们尝试存储图三,图三有四条边,他们是:
1\to 2
2\to 3
3\to 4
2\to 4
所以,图三的矩阵是这样子的:
\begin{bmatrix}
0 & 1 & 0 & 0\\
0 & 0 & 1 & 1\\
0 & 0 & 0 & 1\\
0 & 0 & 0 & 0
\end{bmatrix}
带权图
这是一个带权图:
如果结点 a 与结点 b 之间是相连的,且这条边的权值为 k ,则 A_{ab}=k ,否则 A_{ab}=\infty 。
所以,我们就可以得到了图四的矩阵:
\begin{bmatrix}
\infty & 2 & \infty & \infty\\
\infty & \infty & 5 & 3\\
\infty & \infty & \infty & 6\\
\infty & \infty & \infty & \infty
\end{bmatrix}
使用代码存储图
无向图
我们规定这是图三的输入:
4
1 2
2 3
3 4
2 4
它的意思是:图三有四条边,结点一与结点二相连,结点二与结点三相连,结点三与结点四相连,结点二与结点四相连。
这是存储图的代码:
#include <iostream>
using namespace std;
bool A[10][10];
int n;
int main()
{
cin >> n;
while (n--)
{
int node1, node2;
cin >> node1 >> node2;
A[node1][node2] = 1;
A[node1][node2] = 1;
}
return 0;
}
有向图
有向图不过多赘述了,直接给出代码:
#include <iostream>
using namespace std;
bool A[10][10];
int n;
int main()
{
cin >> n;
while (n--)
{
int node1, node2;
cin >> node1 >> node2;
A[node1][node2] = 1;
}
return 0;
}
带权图
同样直接给出代码:
#include <iostream>
using namespace std;
#define oo 123456
int A[10][10];
int n;
int main()
{
// init
cin >> n;
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
A[i][j] = oo;
}
}
while (n--)
{
int node1, node2, weight;
cin >> node1 >> node2 >> weight;
A[node1][node2] = weight;
}
return 0;
}
搜索算法
图有两种搜索算法:深度优先搜索 (dfs),广度优先搜索 (bfs)。
本文中,我们将第一个要访问的结点称为“根节点”,例如图四中,根节点为 1 。
深度优先搜索
你可能学过回溯算法,这是回溯算法的模板:
void backtracking(...)
{
if (达到边际条件)
{
存储结果
return;
}
for (int i = startIndex; i <= n; i++)
{
记录值
backtracking(...);
撤销值
}
}
回溯就是一种深度优先搜索 ,我们由回溯不难得出 dfs 的代码:
bool vis[N]; // 记录用
int n; // 结点个数
void dfs(int node)
{
if (node == n)
{
// 输出路径
return;
}
for (int i = 1; i <= n; i++)
{
if ((A[i][node] == 1 || A[node][i] == 1) && !vis[i])
{
vis[i] = 1; // 防止重复访问
dfs(i);
vis[i] = 0;
}
}
}
广度优先搜索
实际上,广度优先搜索就是层级遍历,比如,这是图三的 bfs(设根节点为 1 )。
bfs 时需要一个队列。首先,我们将根节点放入队列:
队列:
1
结果:
接着,我们记录结点 1 ,把结点 1 所有的子节点放入队列:
队列:
2
结果:
1
然后,我们记录结点 2 ,把结点 2 所有的子节点放入队列:
队列:
3 4
结果:
1 2
最后,我们记录结点 3,4 ,把所有 3,4 的子节点放入队列
队列:
结果:
1 2 4 3
结点 4 没有子节点,结点三有个子节点,但已经被放入结果了
所以这就是 bfs 的代码:
#include <queue> // 头文件
int A[N][N];
bool vis[N]; // 记录
void bfs()
{
queue<int> path;
path.push(/*根节点*/);
vis[/*根节点*/] = true;
while (!path.empth())
{
int node = path.front();
/*记录结点*/
path.pop();
for (int i = 1; i <= N; i++)
{
if ((A[node][i] || A[i][node]) && !vis[i])
{
path.push(i);
vis[i] = true;
}
}
}
}
总结
当然,还有很多特殊的图,例如二叉树、红黑树、有环图等等,这里只谈及冰山一角。
如果这篇文章对你有用,请你给作者一个赞,谢谢!
\Large\text{快报-洛谷大战开辟第五战场}
duanfeitong}
洛谷MYOI快报!
\textbf{宇宙安全声明:不排除本人神经发作,以下内容仅代表个人观点。}
luogu 大战开辟第五战场!
起因
帖主RyexAwl因为某些原因(大概率是被chen_zhe挂到了知乎上)与chen_zhe展开了对线。
责任
当然,两方都有责任。
帖主由于自身原因,报了洛谷的网校课程却没进省队。
@chen_zhe作为大管理,的确不能随意把别人信息挂到第三方网站上。
这件事很值得我们考究。
事实到底是怎样的
帖主卡在瓶颈期了,辱骂洛谷。
见此页Balor说的话与此页he_____he说的话,都表明虽然@RyexAwl有些过分,但实在不应该侵权。
可根据此页chen_zhe亲自证实后,确有此事。
虽然这样,大部分谷民还是选择站在帖主一边。
@听取MLE声一片
2023-06-09 14:02
简单说一下过程:
昨天晚上在兔群开打,开辟第一战场。
今天中午又在兔群打。
过了一会去 uoj 群打,开辟第二战场。
然后去 LA 群打,开辟第三战场。
接着去 HL1 群打,开辟第四战场。
最后来洛谷讨论区,开辟第五战场。
在第19页帖主的强硬回答更表明事态正在愈发严重。
结果
虽然RyexAwl最后没打赢,但仍有不少人发扬了他的精神,导致这件事发酵的结果正一步步走向不可预测的深渊。
}
\color{orange}\text{作者:\_\_immccn123\_\_}\ \ \color{blue}\text{ 审核:SaintRelief、duanfeitong}
0. 写在前面
本文的每一个章节有一个「推荐阅读」标记,根据读者对不同技术栈、工具的了解程度进行了区分。\small\colorbox{#128e5a}{\color{white}Tool name} 代表「不熟悉/没用过」,\small\colorbox{#3173B3}{\color{white}Tool name} 代表「有一些相关了解,但只会基础操作」,\small\colorbox{orange}{\color{white}Tool name} 代表「非常熟悉」。
示例:
编写 Github Action File
这代表推荐「对 GitHub 有基础了解或者没有了解的读者」阅读此章节。
还有一个标记,\small\colorbox{gray}{\color{white}Magic} ,代表对应操作可能需要科学上网。
本文推荐对于 Web 技术有浅显理解的读者阅读,知道「网页」「静态页面/资源」「相对路径」的相关概念,并对各种环境下的命令行相对熟悉。
重要提示:如果你需要搭建 Hexo 博客,请先完整阅读 一遍文章再开始。 这关系到你每个步骤的选择以及最终成果。
本文的大部分内容主要是针对「喜欢折腾的」(可能是)小白,并应当知晓「仅使用谷歌浏览器上不了谷歌」的事实。部分文段略显啰嗦,但是对于部分内容因为「不适合」新手接触会写得简略一些。
1. 简介
> *如果你对本章节中某些概念不熟悉,例如 WordPress,请跳过。你只需要理解「什么是 Hexo」即可。*
如你所见,Hexo 是一款*静态博客生成器*,可以根据配置文件、博客文章甚至是完整的 HTML 网页根据一套模板生成出对应的静态网页。与市面上大部分的「动态博客」(例如「哔哩哔哩专栏」「洛谷博客」或者「WordPress」)不同,Hexo 在你的本地计算机上运行(而不是在服务器上),没有可视化的网页编辑器,也没有办法「一键发布」。它能做的,只是把你的所有文章转换成一个「静态网站」,你可以将这些网页发布在任何你喜欢的地方。<!-- 待推敲 -->
如果你到这里不能够顺畅理解,那多半是我语言表达的问题。不过没关系,我们继续。阅读到后面,你大概就会明白这一节在说什么。
## 2. 创建你的博客
### 省流
$\small\colorbox{#128e5a}{\color{white}Hexo}$ 及以下
简而言之,一个 Hexo 博客需要以下条件:
1. 一台可以运行 Hexo 的计算机/服务器等
2. 一个地方用于存放你的博客「源代码」和博文
3. 一个可以发布「静态网站」的地方
我会一步一步地带着你走一下这条路。
### 环境准备
$\small\colorbox{#128e5a}{\color{white}Hexo}$ 及以下,$\small\colorbox{#128e5a}{\color{white}Git}$ 及以下,$\small\colorbox{#128e5a}{\color{white}Node.js}$ 及以下
$\small\colorbox{gray}{\color{white}Magic}
首先,你的计算机需要安装有:
Git: https://git-scm.org
Node.js (版本 12 及以上): https://nodejs.org
如果下载很慢或无法访问,请善用搜索引擎查找可以正常访问的安装程序下载链接,或者科学上网。
这两个程序都是在控制台使用的,因此可能 没有图形界面。
此外,非常推荐安装 VSCode 用于博客编辑。
安装 Hexo
**以管理员身份**打开 `cmd` 或 `powershell`(或者你们喜欢的终端程序),执行如下命令:
```sh
npm install -g hexo-cli
```
> 如果卡住或者报错(例如出现 `connection timeout` / `connection reset` 字样),可以尝试更换 `npm` 的下载源:
>
> ```sh
> npm config set registry https://registry.npmmirror.com
> ```
[Hexo 文档 | 安装](https://hexo.io/zh-cn/docs/#%E5%AE%89%E8%A3%85) 提供了更多信息。若需要,可以查阅。不要轻易尝试「进阶安装和使用」部分的内容。
### 初始化 Hexo
$\small\colorbox{#128e5a}{\color{white}Hexo}$ 及以下
任意选择一个目录(比方说,你常用来放代码的目录)。在这个目录下执行命令:
```sh
hexo init <folder>
```
其中 `<folder>` 代表的是新建文件夹的目录名,也就是你的博客「源代码」存放的目录。
> *如果提示找不到 `hexo` 命令,那么请重新开一个 `cmd` 或者终端窗口。*
随后耐心等待处理完成。
> 若提示 `[WARN] git clone failed. Copying data instead`,可以忽略。
### 安装依赖
$\small\colorbox{#128e5a}{\color{white}Hexo}$ 及以下
$\small\colorbox{#128e5a}{\color{white}yarn/npm}$ 及以下
在上一步的 `<folder>` 文件夹内执行命令:
```sh
npm install
```
现在你就有了一个最基本的 hexo 博客。(这还没完!)
现在你的目录结构看起来像这样:
```plain
├── _config.landscape.yml
├── _config.yml
├── .github
├── .gitignore
├── node_modules
├── package.json
├── package-lock.json
├── scaffolds
├── source
└── themes
```
---
#### 关于其他包管理器
$\small\colorbox{#3173B3}{\color{white}Node.js}$ 及以上
如果你安装了其他包管理器(比如 `yarn`),Hexo 将以以下优先级调用包管理器:
1. yarn
2. pnpm
3. npm
另外,请自行将下文提到的 npm 包管理器替换成你自己的包管理器。
---
### 预览站点
$\small\colorbox{#128e5a}{\color{white}Hexo}$ 及以下
现在,在你的 Hexo 源代码文件夹下执行:
```sh
hexo s
```
在浏览器地址栏里输入 `localhost:4000`,就可以看到你现在的站点了!

在控制台里按下 Ctrl+C 停止预览。
有点丑,对不对?
接下来,我会带你一步一步地自定义你的博客。
## 3. 自定义你的博客
### 选择主题
$\small\colorbox{#128e5a}{\color{white}Hexo}$ 及以下
*除非你对 Hexo 和各种网络前端技术有深入了解,否则我非常不建议你手搓主题。*
你可以在 [Hexo | 主题](https://hexo.io/themes/) 选择你喜欢的一个主题。
绝大多数主题都提供了安装方法,但是我还是建议你看一看下面的部分。
一般来说,一个主题的安装方式大致分为三种:
1. 文件夹安装
2. 包管理器安装(部分主题)
3. `git clone` 安装(非常不推荐)
#### 文件夹安装
$99\%$ 的主题都可以通过直接下载主题文件夹安装。
安装方法基本上如下:
1. 下载主题文件夹。

2. 解压主题源码到 `themes` 目录下。

3. 根据需要重命名主题文件夹名称(部分情况下)。
例如,这里的文件夹名称为 `hexo-theme-simpleblock-master`,但是这是一种标准的「项目」命名模式,需要修改成「主题」的命名模式 `simpleblock`。

4. 根据主题文档修改配置文件/拷贝并修改配置文件。
将主题内包含的 `_config.yml` 复制到你的源代码的根目录下,并重命名为 `_config.<主题文件夹名称>.yml`,本例中为 `_config.simpleblock.yml`。
> **关于 `.gitkeep`...**
>
> *看不懂/不知道可以跳过*
>
> `.gitkeep` 是一个在 Git 仓库中常见的文件,它通常被用作一个占位文件,用于保持目录的存在。Git 只会追踪包含文件的目录,对于空目录,Git 不会将其纳入版本控制。为了在 Git 仓库中保留一个空目录,可以在其中添加一个名为 `.gitkeep` 的文件。可以在复制完主题文件夹之后删除这个文件。
部分主题可能会需要安装一部分依赖,一般在主题文档中是以 `cnpm install` / `npm install` / `yarn add` 开头的指令。这时候需要你灵活替换指令了。例如:
```shell
cnpm install hexo-renderer-jade marked jade --save; cnpm install hexo-theme-simpleblock
cp -rf node_modules/hexo-theme-simpleblock themes/simpleblock; rm -r node_modules/hexo-theme-simpleblock
```
此时你应该执行:
```shell
npm install hexo-renderer-jade marked jade --save
```
除此之外,部分主题已经「年久失修」,使用时可能会报错。比方说我用的例子主题。此时建议更换主题。
#### 包管理器安装
有些~~良心的~~有技术力的主题作者会把 ta 的主题打包成 Node.js 里的包(*不用深究*),因此安装主题只需要一行指令的事情。
```shell
npm install <主题作者提供的包名称>
```
比方说主题「Reimu」,提供了详细的安装文档:
> 使用npm
> ```sh
> npm install hexo-theme-reimu --save
> ```
>
> 并修改 `_config.yml` 中的 theme
> ```yaml
> theme: reimu
> ```
做到这一步之后,你需要新建一个 `_config.<主题文件夹名称>.yml`,在本例中为 `_config.reimu.yml`,并在 `_config.reimu.yml` 进行主题的配置。主题配置请参见文档。
#### Git 安装
$\small\colorbox{#128e5a}{\color{white}Git}$ 及以下
这个方法非常需要技术力,不建议使用,即使主题文档写了需要 clone。建议的方法是下载主题的源码(Github 上可以直接点绿色的 Code 下载源代码)。
---
$\small\colorbox{#3173B3}{\color{white}Git}$ 及以上
你需要在项目根目录下编写 `.gitmodules` 文件,格式如下:
```ini
[submodule "<theme-name>"]
path = "themes/<theme-name>"
url = https://github.com/user/repo
```
---
不愿意查阅主题文档的读者可以不用继续了,本文不是针对你们写的。
### 配置 Hexo 和主题
#### 前置知识
$\small\colorbox{#128e5a}{\color{white}Hexo}$ 及以下
「插件」可以通过包管理器(例如 `npm`)安装。部分主题的部分功能需要安装部分插件之后才能启用。一般来说,主题文档会表达例如「需要安装 `hexo-katex` 插件」(仅示例,请自行灵活替换指令内容),这时候你需要执行命令:
```sh
npm install hexo-katex
```
#### Hexo 配置文件介绍
$\small\colorbox{#128e5a}{\color{white}Hexo}$ 及以下
Hexo 的配置文件有两个(一般来说)。第一个 `_config.yml` 是主配置文件,第二个 `_config.<主题名称>.yml` 是主题配置文件,会覆盖主题默认的配置文件以及主配置文件的配置。
##### 配置文件格式简述
$\small\colorbox{#128e5a}{\color{white}YAML}$ 及以下、
推荐阅读的扩展内容
配置文件的格式叫做「YAML」格式,是一种「序列化」格式。YAML 支持列表、字典和标量值等常见的数据结构。列表使用破折号(-)表示,字典使用键值对表示,标量值可以是字符串、数字、布尔值等。YAML 的缩进十分严格,通常使用两个空格作为缩进单位。缩进的层次结构定义了数据的嵌套关系。键值对使用冒号(:)分隔,表示键和值之间的关系。例如 `name: Imken Luo`,跟 Python 中的字典、C++ 中的 map 有几分相似。YAML 的注释以井号(#)开头,可以在数据中添加说明性的注释,不会被解析为数据。还有列表格式,例如:
```yaml
list: [原神, 崩坏, "You are right, but"]
## 等价于
list:
- 原神
- 崩坏
- You are right, but
```
还有其他特性:
```yaml
str: |
这是一个多行的字符串
还可以有第二行
## 等价于
str: "这是一个多行的字符串\n还可以有第二行\n"
```
字符串可以用单引号或者双引号括起来,但是只有用双引号括起来的字符串中的转义字符才会被解析:
```yaml
genshin: "You are right\nbut\n"
# 等价于
genshin: |
You are right
but
# --------
genshin: 'You are right\n but'
# 等价于
genshin: You are right\n but
# 也就是
genshin: "You are right\\n but"
```
多行字符串的列表和键值对:
```yaml
dict_list:
- key1: |
注意这里要多两个缩进,因为是 List 里套了一个 Key
string
- key2: "Genshin Impact"
dict:
key1: |
这里就不需要了
key2: |
区别就在前面的一个 `-`
pure_list:
- |
注意这里也要多一个缩进
- |
上面的竖杠后面不能写东西
```
另外,缩进不可以使用「制表符」;部分编辑器(例如 Code::Blocks、VSCode 的默认配置)会将 Tab 作为 4 个空格,但是有的就不会(例如 记事本、Dev-C++),请查阅编辑器配置。在修改主题和全局配置文件时,请使用两个空格。
YAML 格式的文件一般以 `.yaml` 作为文件扩展名。
#### 编写/修改主配置文件
$\small\colorbox{#128e5a}{\color{white}Hexo}$ 及以下
现在你已经学会了配置文件的格式。
用一个文本编辑器打开 `_config.yml`。
下面是配置文件每一项的说明。部分配置可以留空,留空请使用 `''`(空字符串)。建议对照看完。
```yaml
# Site
## 站点标题,可以来点像 「Prpr 的小天地」啥的中二标题(
title: Imken 的博客
## 副标题,不知道填啥可以留空。
subtitle: '副标题'
## 站点描述。随便填啥,可以填格言/站点介绍/魔怔的产物等。给搜索引擎看的。
description: '听说描述可以写很长但是真的没想到可以写这么长。'
## 站点关键词,给搜索引擎看的。
keywords: ['OI', '原神教程', '生活日常']
## 作者,可以不用写真名。
author: Imken Luo
## 语言,一般写 `zh-CN`/`zh-Hans`。
language: zh-Hans
## 时区,不知道填 `GMT+8`/`UTC+8` 行不行。
timezone: 'Asia/Shanghai'
# URL
## Set your site url here. For example, if you use GitHub Page, set url as 'https://username.github.io/project'
## 你的站点链接,建议看完再填,可以留空。
url: http://example.com
## 文章链接格式。不建议修改。
permalink: :year/:month/:day/:title/
## 永久链接的默认设置,不知道干啥的可以留空。
permalink_defaults:
pretty_urls:
# 让文章的链接看起来像 https://blog.example.com/post-name/index.html
trailing_index: true
# 让文章的链接看起来像 https://blog.example.com/post-name.html
trailing_html: true
# Directory
## 这个部分我非常不建议你修改,如果你是高阶用户,请查阅文档
source_dir: source
public_dir: public
tag_dir: tags
archive_dir: archives
category_dir: categories
code_dir: downloads/code
i18n_dir: :lang
skip_render:
# Writing
## 新文章的文件名格式,文章名为 `博客`,文件就是 `博客.md`。不建议修改。
new_post_name: :title.md
## 默认的布局模板名,不知道干啥的保持默认即可。
default_layout: post
## 标题是否转换为首字母大写。不建议修改。
titlecase: false
external_link:
## 在新标签中打开「外部」链接,即不是指向你本站点的链接。
enable: true
## 对整个网站(site)生效或仅对文章(post)生效
field: site
## 需要排除的域名。主域名和子域名如 www 需分别配置。
exclude: ''
## 把文件名称转换为 (1) 小写或 (2) 大写。不建议修改。
filename_case: 0
## 是否在站点预览/渲染里显示草稿。不建议修改。
render_drafts: false
## 启动 Asset 文件夹,不建议修改。
post_asset_folder: false
## 把链接改为与根目录的相对位址。如果站点 url 的选项让你很迷惑,可以将这一项改成 true.
relative_link: false
## 是否显示未来的文章。不建议修改。
future: true
## 代码高亮(在渲染文章时)
## 我们常用的是 Hignlight.js,即 highlight。
## 如果主题有代码高亮功能,请将下面两大项的 enable 改为 false.
## 或者查阅主题文档。
## enable = 启用,两个选项只能启用一个,同时另一个的配置可以忽略。
highlight:
enable: true
## 行号开关
line_number: true
## 自动检测语言开关,建议修改为 true
auto_detect: false
## 替换 Tab 的内容,一般来说填写一个包含四个空格的字符串。
tab_replace: ' '
## 为了支持行号显示,Hexo 将输出包裹在了 figure 和 table 内部。如果要保持 highlight.js 原来的行为,你需要将 line_number 和 wrap 全部关闭。不建议修改。
wrap: true
## 当 hljs 设置为 true 时,所有代码块的 HTML 输出均会给 class 添加 hljs- 前缀(无论 wrap 是否开启)。不建议修改。
hljs: false
prismjs:
enable: false
## 是否在 Hexo 完成代码高亮(而不是浏览器再加载 Prism.js),不建议修改
preprocess: true
## 行号开关
line_number: true
## 替换 Tab 的内容
tab_replace: ''
## 本节不建议修改。
index_generator:
path: '' # 首页路径,不建议修改
per_page: 10 # 每页显示的文章数量
order_by: -date # 文章排序方式
## 可以不用修改,Hexo 会自动生成标签云和分类云
default_category: uncategorized # 默认分类
category_map: # 分类别名
tag_map: # 标签别名
# Metadata elements
## https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta
meta_generator: true # 是否生成 meta 标签
# Date / Time format
## Hexo uses Moment.js to parse and display date
## You can customize the date format as defined in
## http://momentjs.com/docs/#/displaying/format/
## 如果你不懂下述选项的含义,则不要修改以下配置项。
date_format: YYYY-MM-DD # 日期格式
time_format: HH:mm:ss # 时间格式
## updated_option supports 'mtime', 'date', 'empty'
updated_option: 'mtime' # 更新时间的选择
# Pagination
## Set per_page to 0 to disable pagination
## 如果你不懂下述选项的含义,则不要修改以下配置项。
per_page: 10 # 每页显示的文章数量
pagination_dir: page # 分页目录
# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: landscape # 使用的主题
# Deployment
## Docs: https://hexo.io/docs/one-command-deployment
## 不建议修改,后面会详解。
deploy:
type: '' # 部署类型
```
##### 修改主题
将配置文件的 `theme` 项修改为你的主题文件夹的名称即可。例如,我的主题名称叫 `simplecard`,那么修改为 `simplecard` 即可。
```yaml
# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: simplecard
```
##### 修改主题配置文件
很抱歉,到这里我无法带着你一个一个地跟你解释配置项代表着什么了,也无法一步一步带你走了;这一步只能靠你自己了。具体地,请查阅主题文档。
**善用搜索引擎**来配置评论服务等。参见后面的「杂项」部分。
**记住,一定要仔细阅读主题文档。主题文档一般来说都相对较详细。**
## 3. 开始编写文章
$\small\colorbox{#128e5a}{\color{white}Hexo}$ 及以下
使用命令 `hexo new <文章名>` 创建一篇文章。例如:
```sh
hexo new 「烹饪指南」冰糖炖鸽子
```
这个时候,看到文件夹 `source/_posts/`,会出现一个名叫 `<文章名>` 的文章。例如:
```plain
6月12日 20:42 「烹饪指南」冰糖炖鸽子.md ;; 这个是新增文件
6月 9日 13:24 hello-world.md
```
这个时候,你可以编辑这个新的文件;这就是你的新文章。
观察新的文件,你会发现:
```yaml
---
title: 「烹饪指南」冰糖炖鸽子
date: 2023-06-12 20:42:15
tags:
---
```
给不熟悉的读者解释一下,这一段是 Markdown 的「元信息」(在很多 Markdown 解析器实现上并不会解析这部分内容),使用 YAML 格式(可以参见上文的介绍)。
title 和 date 都还是很好理解的,文章标题和发布时间。tags 是标签,可以传入一个列表:
```yaml
tags:
- OI
- 做饭
- 烹饪
- '有 空格 的标签'
# 或者
tags: [OI, '做饭', '烹饪', '有 空格 的标签']
```
同时你可以加入「分类」的元数据:
```yaml
category: 烹饪指南
```
还可以有子分类(部分主题兼容性不好,出问题了要么换主题,要么不用子分类)。
```yaml
category:
- 烹饪指南
- 炖鸽子
```
建议在书写文章时与元信息之间空一行。
> Tips:你可以保持运行 `hexo s`,这样在编写文章时可以实时在浏览器看到文章在网页的渲染情况。
## 4. 发布你的站点
### 选择一个适合你的静态网站托管服务
下面有教程,可以不用去搜索。
#### 如果你有自己的域名
如果域名没有备案,就只能放在境外的主机上了,比较知名的服务有:
- GitHub Pages(配置最麻烦)
- Vercel
- Netlify
- Cloudflare Pages
其中 Vercel 在境内访问最快,其下依次是 Netlify、Cloudflare Pages 和 GitHub Pages。
如果你选用 GitHub Pages,你需要在 `source` 目录下新建一个空白的 `CNAME` 文件(不是 `CNAME.md` 也不是 `CNAME.txt`),里面填写你的域名。

当然,也可以使用「对象存储 + CDN」,但是配置十分麻烦 ~~(所以没写教程)~~。
#### 如果你没有自己的域名
有几种解决方案:
1. 免费域名
2. 服务商提供的免费子域名(例如 `.github.io`、`.vercel.app`)
免费域名的教程网上都有(关键词 免费域名 Cloudflare),但是需要注意的是,`eu.org` 的域名已经被部分地区的移动网阻断。
静态网站托管服务商(比较知名的有):
- GitHub Pages(配置最麻烦,容易抽风)
- Vercel(域名被阻断)
- Netlify
- Cloudflare Pages(域名被阻断)
推荐 Netlify。
-----
不过,无论你选用何种网站托管服务,都建议把「源代码」存放在 GitHub 上。
### 上传博客的「源代码」
一般情况下,我非常推荐使用「GitHub」来保存你的博客源代码。所以我只写了 GitHub 的详细教程。
用 GitHub 虽然在大陆挺慢的(经常抽风),但是它跟多数「静态网站托管服务」都有很强的兼容性。
#### 注册 GitHub 账号
$\small\colorbox{#128e5a}{\color{white}GitHub}$ 及以下
本段有一定时效性。
你需要有:
- (大概)一点点英文功底
- 一个电子邮箱地址
- 没了
注册链接[在这里](https://github.com/signup)。
很漂亮的注册页面。
第一步是「Enter your email」,输入你的电子邮箱地址。点击右侧的 continue 继续。

下一个是「Create a password」,创建密码。
再下一个是「Enter a username」,输入用户名。如果出现重名会有提示,比如:

下一项:
> Would you like to receive product updates and announcements via email?
>
> Type "y" for yes or "n" for no
问你愿不愿意接收来自 GitHub 的广告啊啥的。打 `n` 就行。
下一项就是接受邮箱验证码。
后面就是一些 GitHub 给你的调查(和广告),尽可能选择免费(且人少)的选项即可。
#### 新建仓库
$\small\colorbox{#128e5a}{\color{white}GitHub}$ 及以下
现在进入到首页,点击右上角加号,点击「New repository」:

输入仓库名。
> 注意:如果你没有自己的域名(并且你希望你的网站托管在 GitHub Pages 上),请将仓库名修改为 `<GitHub用户名>.github.io`,并务必选择「Public」(公开)。

剩下所有选项的保持默认即可,这样可以保留一个完全空的仓库。
点击「Create repository」,创建仓库。
#### 推送仓库
$\small\colorbox{#128e5a}{\color{white}Git}$ 及以下、$\small\colorbox{#128e5a}{\color{white}GitHub}$ 及以下
以下的指令仅供第一次提交使用:
请参阅 [Github配置SSH密钥连接(附相关问题解决)](https://zhuanlan.zhihu.com/p/628727065) 配置 SSH 密钥连接之后,执行以下指令(自行灵活替换)。可能需要科学上网(开启 TUN/TAP 模式)。
```sh
git init
git add .
git commit -m "first commit"
git branch -M main
git remote add origin [email protected] :<用户名>/<仓库名>.git
git push -u origin main
```
#### 部署网站
终于到(几乎)最后一步了。针对不同平台写了几个教程。
你需要选择其中的一个平台。
##### GitHub Pages
$\small\colorbox{#3173B3}{\color{white}GitHub}$ 及以下
在目录 `.github/workflows/` 下新建文件 `deploy.yml`,添加以下内容:
```yaml
name: Auto deploy Hexo site
on:
push:
branches:
- main
jobs:
Build-And-Deploy:
runs-on: ubuntu-latest
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Install dependencies
run: |
npm install
- name: Build Static Pages
run: |
npm run build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
```
同时,在 `source` 文件夹下新建文件 `.nojekyll`。如果 Windows 下新建文件报错的话,请使用命令行在 `source` 目录下执行指令 `echo off > .nojekyll`(或者使用 VSCode 创建)。
如果你使用自定义域名的话,请在 `source` 目录下新建文件 `CNAME`,并将其内容改为你的域名,见上。同时,创建一条 CNAME 记录指向 `<用户名>.github.io`。
随后,推送更改。
```sh
git add .
git commit -m "add github actions"
git push
```
等待两分钟,之后,访问仓库设置(「Setting」栏),在侧边栏点击「Pages」,根据图示修改配置:

接下来,进入 Actions 标签,在左侧菜单选择「Auto deploy Hexo site」,进入**第一项**,点击右上角的「Re-run all jobs」。
(不一定完全是如图示一样)


这个弹窗的「Enable debug logging」可以不用钩。

等待约 $3$ 分钟后,即可访问 `<用户名>.github.io`。
自定义域名可能需要等待一会儿才可以正常访问。
##### Vercel
$\small\colorbox{#128e5a}{\color{white}Vercel}$ 及以下
**如果你没有自己的域名,不要使用 Vercel。**
**Vercel 目前需要手机号验证。不推荐使用。**
##### Netlify
$\small\colorbox{#128e5a}{\color{white}Netlify}$ 及以下
*这里建议你跟着做,因为如果不跟着做你也不知道我在说什么。*
访问 [Netlify 官网](https://netlify.com)。点击右上角「Sign Up」,然后「Continue with GitHub」。
然后认证完成后,它会让你回答一些问题。这个大抵是无所谓的,但是建议选择带 Personal/Hobby 的选项。
最底下「What is the name of your team?」填写团队名,随便填一个用户名就行。
下一页选择「Deploy with GitHub」。认证会弹出一个窗口,其中的一步是「Install Netlify」,你可以选择 Netlify 可以读取你的部分仓库还是全部仓库。
需要说明的是,虽然你可以修改 Netlify 的权限,但是在你不熟悉 GitHub 的情况下,我还是建议你选择「All repositories」,即访问全部仓库。
下一步是「Let’s deploy your project」,选择你刚才创建的仓库即可。

Netlify 会自动识别你项目的类型进行部署。

部署完成。

点击「Get started」,可以看到你现在来到了首页。往下翻,找到「Sites」,点击你刚才部署的网站:

点击「Domain settings」修改自定义域名。


现在,你可以访问你的网站了。
如果你想使用自己的域名,请先添加一条指向你的 Netlify 自定义域名的 CNAME 记录(即 `xxxx.netlify.app`),然后点击「Add a domain」。
输入域名并验证,会提示
> example.com is already registered. If you registered this domain name through a different registrar, select Add subdomain to add it to your site. You can configure Netlify DNS for this domain later.
不要在意,点击「Add domain」/「Add subdomain」就行了。
等待 SSL 证书签发,即可访问你的网站。
##### Cloudflare Pages
$\small\colorbox{#128e5a}{\color{white}Cloudflare}$ 及以下
首先要注册一个 Cloudflare 账号(有了的请跳过),参见 [如何在Cloudflare注册域名?](https://zhuanlan.zhihu.com/p/630040769) 的前两节。
*需要注意的是,右上角可以更改语言。*
点击左侧的「Workers 和 Pages」,进入到一个新页面。选择上方的「Pages」标签。点击「连接到 Git」。

然后点击「连接到 GitHub」。
新页面里,你可以选择 Cloudflare 可以读取你的部分仓库还是全部仓库。
需要说明的是,虽然你可以修改 Cloudflare 的权限,但是在你不熟悉 GitHub 的情况下,我还是建议你选择「All repositories」,即访问全部仓库。
然后选中你刚才创建的仓库。

项目名称填写一个自己喜欢的,稍后可以通过 `<项目名称>.pages.dev` 访问。**需要注意的是,在中国大陆,`.pages.dev` 大概率是被墙的,所以不推荐没有独立域名的读者使用。**
下面是各项配置的值。
- 构建命令:`npm run build`
- 构建输出目录:`public`
与此同时,你需要添加一个环境变量(最下方「环境变量(高级)」) `NODE_VERSION`,值为 `18.16.0`。
点击「保存并部署」。部署完成后点击「继续处理项目」。
如果你想使用自己的域名,你可以在「自定义域」标签添加你自己的域名,并用 CNAME 指向 `<项目名>.pages.dev`。
## 5. Hexo 日常写作
总结来说,Hexo 的「常规」写作流程如下:
1. 配置环境(如果环境已经配置好了的可以跳过)。
2. 克隆仓库:你的博客「源代码」是存储在远端仓库的,因此需要使用 `git clone` 指令从云端拉取仓库,例如执行 `git clone [email protected] :immccn123/Imken-Blog.git`。(灵活替换)
3. 创建文章:使用 `hexo new <文章名>`。
4. 编辑文章。
5. 推送更改:
```sh
git add .
git commit -m "<提交信息,可以随便填写,自己看明白就行>"
git push
```
6. 等待网站自动部署。
## 6. 杂项 / Hexo 进阶
建议在对 Hexo 有一定了解之后再继续。
### KaTeX 支持
部分主题提供了 KaTeX 支持;如果没有的话,参考 <https://wty-yy.space/posts/3849/>。
### 云端写作
[GitPod](https://gitpod.io) 提供了云端的 VSCode 环境,自带 Git、Node.js、npm 等软件,可以方便地在云端进行写作。环境一般是直接配置好了的。你需要对 Linux 系统的终端有一定熟悉。
### 评论系统
部分主题提供了评论系统支持,请查阅主题文档。对于没有提供的(并且你有一定编码水平),可以尝试修改主题。
常用的评论系统有 Gitalk、Giscus、Valine(大陆基本不可行)等。
### 谷歌统计
谷歌提供的网站统计服务,可以看到各个页面指标。具体请搜索。
### Microsoft Clarity
另一个网站统计服务,可以看到用户在网站上的操作。具体请搜索。
可以考虑修改主题。
---
### 广告
##### 欢迎加入 [MYOI出题组](https://www.luogu.com.cn/team/50020#AK-IOI)!
##### 欢迎参加 [MXX解谜赛Round2](https://www.luogu.com.cn/contest/99066)!
### 广告位招租
如果您有个人比赛(如解谜赛)、博客文章、团队等需要宣传的**符合洛谷规定**的广告,欢迎私信@[SaintRelief](https://www.luogu.com.cn/user/746237)投递,价格从关注到RMB不等(面议),欢迎各位投递广告!
---
这就是本期的《洛谷MYOI月报》的全部内容了,我们下期再见!欢迎各位加入[洛谷MYOI月报总部兼编辑部](https://www.luogu.com.cn/team/59480)投稿与参与报刊建设,谢谢!