* Changed heading into h2 (##).
* Deleted heading numbers. (Heading number is generated automatically by mkdocs or latex compiler)
* Deleted trailing colons. (Titles should not end in colons)
* Added monofont style (`code` in markdown) for C++ keywords/function names in titles.
参考书目:信息学奥赛一本通
-## C++ 的 ifstream/ofstream 文件输入输出流
+## C++ 的 `ifstream/ofstream` 文件输入输出流
### 使用方法
**PS** : 用优先队列(小根堆)来维护队首元素最小。
-### code:
+### Code
```cpp
#include <algorithm>
-# 基础部分简介
+基础部分简介
介绍一些基础知识,为之后的进阶内容做铺垫。
两个要素:
-### 1. 最优子结构
+### 最优子结构
具有最优子结构也可能是适合用贪心的方法求解。
- **无权最短路径:**具有最优子结构性质。
- **无权最长(简单)路径:**此问题不具有,是 NPC 的。区别在于,要保证子问题无关,即同一个原问题的一个子问题的解不影响另一个子问题的解。相关:求解一个子问题时用到了某些资源,导致这些资源在求解其他子问题时不可用。
-### 2. 子问题重叠
+### 子问题重叠
子问题空间要足够小,即问题的递归算法会反复地求解相同的子问题,而不是一直生成新的子问题。
说的就是把回路给拆开吧。
-#### 思路一:
+#### 思路一
$dp[i][j]$ 表示 $1 \cdots i$ 和 $1 \cdots j$ 两条路径。
* * *
-## 1. 记忆化搜索是啥
+## 记忆化搜索是啥
好,就以 [洛谷 P1048 采药](https://www.luogu.org/problemnew/show/P1048) 为例,我不会动态规划,只会搜索,我就会直接写一个粗暴的 [DFS](/search/dfs) :
* * *
-## 2. 记忆化搜索与动态规划的关系:
+## 记忆化搜索与动态规划的关系:
有人会问: 记忆化搜索难道不是搜索?
* * *
-## 3. 如何写记忆化搜索
+## 如何写记忆化搜索
-### 方法 I:
+### 方法 I
1. 把这道题的 dp 状态和方程写出来
2. 根据他们写出 dfs 函数
}
```
-### 方法 II:
+### 方法 II
1. 写出这道题的暴搜程序 (最好是 [dfs](/search/dfs) )
2. 将这个 dfs 改成 "无需外部变量" 的 dfs
* * *
-## 4. 记忆化搜索的优缺点
+## 记忆化搜索的优缺点
优点:
* * *
-## 5. 记忆化搜索的注意事项
+## 记忆化搜索的注意事项
- 千万别忘了加记忆化! (别笑, 认真的
- 边界条件要加在检查当前数组值是否为非法数值 (防止越界)
- 数组不要开小了 (逃
-## 6. 模板
+## 模板
```c++
int g[MAXN] ; int f(传入数值) {
讲完了,让我们归纳一下单调队列优化动态规划问题的基本形态:当前状态的所有值可以从上一个状态的某个连续的段的值得到,要对这个连续的段进行 RMQ 操作,相邻状态的段的左右区间满足非降的关系。
-### 几道练习题:
+### 几道练习题
[洛谷 P1886 滑动窗口](https://www.luogu.org/problemnew/show/P1886)
可以用单调队列维护下凸包。
-### 几道练习题:
+### 几道练习题
[洛谷 P4072 \[SDOI2016\] 征途](https://www.luogu.org/problemnew/show/P4072)
因为 $\sum_{i=1}^{n-1}(idx_{i+1,i+1}-idx_{i,i})=idx_{n,n}-idx_{1,1}$ 很显然和 $n$ 同阶,那么它的 $n$ 倍就和 $n^2$ 同阶,时间复杂度是 $O(n^2)$。
-### 一道练习题:
+### 一道练习题
[洛谷 P4767 \[IOI2000\] 邮局](https://www.luogu.org/problemnew/show/P4767)
(建议学习[位运算](/math/bit/)部分的内容)
-### 状压 dp 简介
+### 状压 DP 简介
状压 dp 是动态规划的一种,借由将状态压缩(通常压缩为某整形)以达到节约空间和时间的目的
-# 线段树套平衡树
-
-### 常见用途
+## 常见用途
在算法竞赛中,我们有时需要维护多维度信息。在这种时候,我们经常需要树套树来记录信息。当需要维护前驱,后继,第 $k$ 大,某个数的排名,或者插入删除的时候,我们通常需要使用平衡树来满足我们的需求,即线段树套平衡树。
-### 实现原理
+## 实现原理
我们以**二逼平衡树**为例,来解释实现原理。
操作四,求某区间中某值的前驱:我们对于外层线段树正常操作,对于在某区间中的节点的平衡树,我们返回某值在该平衡树中的前驱,线段树的区间结果合并时,我们取最大值即可。
-### 空间复杂度
+## 空间复杂度
我们每个元素加入 $\log n$ 个平衡树,所以空间复杂度为 $(n + q)\log{n}$。
-### 时间复杂度
+## 时间复杂度
对于 $1,2,4$ 操作,我们考虑我们在外层线段树上进行 $\log{n}$ 次操作,每次操作会在一个内层平衡树树上进行 $\log{n}$ 次操作,所以时间复杂度为 $\log^2{n}$。
对于 $3$ 操作,多一个二分过程,为 $\log^3{n}$。
-### 经典例题
+## 经典例题
[二逼平衡树](https://www.lydsy.com/JudgeOnline/problem.php?id=3196) 外层线段树,内层平衡树。
-### 示例代码
+## 示例代码
平衡树部分代码请参考 Splay 等其他条目。[传送至 Splay 条目](/ds/splay/)
}
```
-### 相关算法
+## 相关算法
面对多维度信息的题目时,如果题目没有要求强制在线,我们还可以考虑 **CDQ 分治**,或者**整体二分**等分治算法,来避免使用高级数据结构,减少代码实现难度。
-# 块状链表
-
[![./images/kuaizhuanglianbiao.png](./images/kuaizhuanglianbiao.png "./images/kuaizhuanglianbiao.png")](./images/kuaizhuanglianbiao.png "./images/kuaizhuanglianbiao.png")
大概就长这样……
-# 并查集
-
并查集是一种树形的数据结构,顾名思义,它用于处理一些不交集的**合并**及**查询**问题。
它支持两种操作:
#define isRoot(x) (ch[f[x]][0] != x && ch[f[x]][1] != x)
```
-### <font color = "red">Access() </font>
+### <code><font color = "red">Access() </font></code>
```cpp
// Access 是 LCT
-## \_\_gnu_pbds :: priority_queue
+## `__gnu_pbds :: priority_queue`
附 :[官方文档地址——复杂度及常数测试](https://gcc.gnu.org/onlinedocs/libstdc++/ext/pb_ds/pq_performance_tests.html#std_mod1)
* * *
-### 对于无旋 Treap 的提示
+## 对于无旋 Treap 的提示
看楼上的 [Treap 词条](/ds/treap/)
**OI 常用的可持久化平衡树** 一般就是 **可持久化无旋转 Treap** 所以推荐首先学习楼上的 **无旋转 Treap**
-### 思想 / 做法
+## 思想 / 做法
我们来看看旋转的 Treap,为什么不能可持久化呢?
因此我们完全可以**参考线段树的可持久化操作**对它进行可持久化。
-### 可持久化操作
+## 可持久化操作
**可持久化**是对**数据结构**的一种操作,即保留历史信息,使得在后面可以调用之前的历史版本.
- 如果某个儿子节点 $Y$ 不用修改信息,那么就把 $X_{a+1}$ 的指针直接指向 $Y_{a}$ ($Y$ 节点的第 $a$ 个版本) 即可。
- 反之,如果要修改 $Y$ ,那么就在**递归到下层**时**新建** $Y_{a+1}$ ($Y$ 节点的第 $a+1$ 个版本) 这个新节点用于**存储新的信息**,同时把 $X_{a+1}$ 的指针指向 $Y_{a+1}$ ($Y$ 节点的第 $a+1$ 个版本)。
-### 可持久化
+## 可持久化
需要的东西:
- build() 建树
-#### Split
+### Split
对于**分裂操作**,每次分裂路径时**新建节点**指向分出来的路径,用 std::pair 存新分裂出来的两棵树的根。
}
```
-#### Merge
+### Merge
int merge(x,y) 返回 merge 出的树的根。
}
```
-### Luogu P3835 可持久化平衡树
+## Luogu P3835 可持久化平衡树
-#### 题目背景
+### 题目背景
本题为题目 **普通平衡树** 的可持久化加强版。
数据已经经过强化
-#### 题目描述
+### 题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):
每个版本的编号即为操作的序号(版本 0 即为初始状态,空树)
-#### 输入格式:
+### 输入格式
第一行为 n,表示操作的个数, 下面 n 行每行有两个数 opt 和 x,opt 表示操作的序号 $(1 \leq x \leq le6)$。
-#### 输出格式:
+### 输出格式
对于操作 3,4,5,6 每行输出一个数,表示对应答案。
-#### 题解简述
+## 题解简述
就是**普通平衡树**一题的可持久化版,操作和该题类似..
只是使用了可持久化的 merge 和 split 操作
-### 推荐的练手题
+## 推荐的练手题
1. luogu P3919 可持久化数组 (模板题)
2. codeforces 702F T-shirt
-### 另外
+## 另外
1. 可持久化平衡树可以用来维护动态凸包,仙人掌等东西,如果读者有兴趣可以阅读相应的 [**计算几何**](/geometry) 知识,再来食用。
-# 线段树套线段树
-
-### 常见用途
+## 常见用途
在算法竞赛中,我们有时需要维护多维度信息。在这种时候,我们经常需要树套树来记录信息。
-### 实现原理
+## 实现原理
我们考虑用树套树如何实现在二维平面上进行单点修改,区域查询。我们考虑外层的线段树,最底层的 $1$ 到 $n$ 个节点的子树,分别代表第 $1$ 到第 $n$ 行的线段树。那么这些底层的节点对应的父节点,就代表其两个子节点的子树所在的一片区域。
-### 空间复杂度
+## 空间复杂度
通常情况下,我们不可能对于外层线段树的每一个结点都建立一颗子线段树,空间需求过大。树套树一般采取动态开点的策略。单次修改,我们会涉及到外层线段树的 $\log{n}$ 个节点,且对于每个节点的子树涉及 $\log{n}$ 个节点,所以单次修改产生的空间最多为 $\log^2{n}$。
-### 时间复杂度
+## 时间复杂度
对于询问操作,我们考虑我们在外层线段树上进行 $\log{n}$ 次操作,每次操作会在一个内层线段树上进行 $\log{n}$ 次操作,所以时间复杂度为 $\log^2{n}$。
修改操作,与询问操作复杂度相同,也为 $\log^2{n}$。
-### 经典例题
+## 经典例题
[陌上花开](https://www.lydsy.com/JudgeOnline/problem.php?id=3262) 将第一维排序处理,然后用树套树维护第二维和第三维。
-### 示例代码
+## 示例代码
第二维查询
}
```
-### 相关算法
+## 相关算法
面对多维度信息的题目时,如果题目没有要求强制在线,我们还可以考虑 **CDQ 分治**,或者**整体二分**等分治算法,来避免使用高级数据结构,减少代码实现难度。
-## 1. 写在前面
+## 写在前面
线段树是个好东西啊 QwQ
OI 中最常用的数据结构之一,不学不行啊 OvO
-## 2. 线段树是什么
+## 线段树是什么
> 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为 $O(\log N)$。而未优化的空间复杂度为 $2N$,因此有时需要离散化让空间压缩。——From 度娘
反正就是一种可以在很短的时间内对某个区间进行操作的数据结构。
-## 3. 线段树有什么用
+## 线段树有什么用
在 $O(\log N)$ 的时间复杂度内实现如:单点修改、区间修改、区间查询(如:区间求和,求区间最大值,求区间最小值……)还有很多……
总之线段树维护的信息,需要满足可加性,且要以可以接受的速度合并信息和修改信息,如果使用标记,标记也要满足可加性(例如取模就不满足可加性,对 $4$ 取模然后对 $3$ 取模,两个操作就不能合并在一起做(事实上某些情况下可以暴力单点取模))
-## 4. 线段树怎么实现
+## 线段树怎么实现
-### (1) 线段树的基本结构与建树
+### 线段树的基本结构与建树
想要建立一棵线段树,不理解它的结构、原理是肯定行不通的。
![](./images/segt5.png)
-### (2) 线段树的区间查询
+### 线段树的区间查询
区间查询,比如求区间 $[l,r]$ 的总和(即 $a[l]+a[l+1]+ \cdots +a[r]$)、求区间最大值 / 最小值…… 还有很多很多…… 怎么做呢?
还是挺短的吧?这里用到的主要思路就是把一个区间拆成左右两个区间,再分别处理左右区间。也是二分的思想。
-### (3) 线段树的区间修改与懒惰标记
+### 线段树的区间修改与懒惰标记
区间修改是个很有趣的东西 o(╯□╰)o…… 你想啊,如果你要修改区间 $[l,r]$,难道把所有包含在区间 [l,r] 中的节点都遍历一次、修改一次?那估计这时间复杂度估计会上天 |(\*′口 \`)。这怎么办呢?我们这里要引用一个叫做 **「懒惰标记」** 的东西。
}
```
-## 5. 一些优化
+## 一些优化
上面的代码为了简单易懂,所以呢我写的比较不优美。
- 最好别像上文那样把所有功能都写一起,比如下放懒惰标记可以写一个专门的函数,从儿子节点更新当前节点也可以写一个专门的函数,等等。
- 标记永久化,如果确定懒惰标记不会在中途被加到超出数据范围,那么就可以将标记永久化,标记永久化可以避免下传标记,可以降低程序常数。在进行询问时要把标记的影响加到答案当中,具体如何处理与题目特性相关,需结合题目来写。标记永久化也是树套树和可持久化数据结构中会用到的一种技巧。
-## 6. 线段树基础题推荐
+## 线段树基础题推荐
-### (1) LUOGU P3372 【模板】线段树 1
+### LUOGU P3372 【模板】线段树 1
[传送门 = ̄ω ̄=](https://www.luogu.org/problem/show?pid=3372)
}
```
-### (2) LUOGU P3373 【模板】线段树 2
+### LUOGU P3373 【模板】线段树 2
[传送门 = ̄ω ̄=](https://www.luogu.org/problem/show?pid=3372)
}
```
-### (3) CODEVS 线段树练习 (这是一个系列)
+### CODEVS 线段树练习 (这是一个系列)
[传送门 = ̄ω ̄=](http://codevs.cn/problem/?q=%E7%BA%BF%E6%AE%B5%E6%A0%91%E7%BB%83%E4%B9%A0)
不保证搜得到。
-### (4) HihoCoder 1078 线段树的区间修改
+### HihoCoder 1078 线段树的区间修改
[传送门 = ̄ω ̄=](https://cn.vjudge.net/problem/HihoCoder-1078)
}
```
-### (5) 2018 Multi-University Training Contest 5 Problem G. Glad You Came
+### 2018 Multi-University Training Contest 5 Problem G. Glad You Came
[传送门](http://acm.hdu.edu.cn/showproblem.php?pid=6356)
-## bitset :
-
-### 介绍 :
+## 介绍
`std :: bitset`是标准库中的一个**固定大小**序列, 其储存的数据只包含`0/1`
#include <bitset> // 包含 bitset 的头文件
```
-#### 运算符 :
+### 运算符
- `operator[]`: 访问其特定的一位
`vector<bool>`只具有前两项
-#### 成员函数 :
+### 成员函数
- `test()`: 它和`vector`中的`at()`的作用是一样的, 和`[]`运算符的区别就是越界检查
- `count()`: 返回`true`的数量
这些`vector<bool>`基本都没有
-### 作用 :
+## 作用
一般来讲, 我们可以用`bitset`优化一些可行性 DP, 或者线筛素数 (`notprime`这种`bool`数组可以用`bitset`开到$10^8$之类的)
// 注意:不可跳过容器参数直接传入比较类
```
-## 成员函数 :
+## 成员函数
1. `top()`: 访问栈顶元素 常数复杂度
2. `empty()`: 检查底层的容器是否为空 常数复杂度
由于 `std::priority_queue` 原生不支持 `modify()` / `join()` / `erase()` 故不做讲解。
-## 示例 :
+## 示例
```cpp
q1.push(1);
-# std :: vector
-
-## 为什么要用 vector
+## 为什么要用 `vector`
作为 OIer ,对程序效率的追求远比对工程级别的稳定性要高得多,而 vector 由于其较静态数组复杂很多的原因,时间效率在大部分情况下都要满慢于静态数组,所以在一般的正常存储数据的时候,我们是不选择 vector 的, 下面给出几个 vector 优秀的特性,在需要用到这些特性的情况下,vector 能给我们带来很大的帮助
-### vector 重写了比较运算符
+### `vector` 重写了比较运算符
vector 以字典序为关键字重载了 6 个比较运算符,这使得我们可以方便的判断两个容器是否相等 (复杂度与容器大小成线性关系)
-### vector 的内存是动态分配的
+### `vector` 的内存是动态分配的
由于其动态分配的特性, 所以在调用内存的常数上在很多情况下是要快于静态数组的。
很多时候我们不能提前开好那么大的空间(eg :预处理 1~n 中所有数的约数)我们知道数据总量在空间允许的级别,但是单份数据还可能非常大,这种时候我们就需要 vector 来保证复杂度。
-### vector 可以用赋值运算符来进行初始化
+### `vector` 可以用赋值运算符来进行初始化
由于 vector 重写了 `=` 运算符,所以我们可以方便的初始化。
-## vector 的构造函数
+## `vector` 的构造函数
参见如下代码
可以利用上述的方法构造一个 vector, 足够我们使用了。
-## vector 元素访问
+## `vector` 元素访问
vector 提供了如下几种方法进行访问元素
使用方法 :`v.data()` 返回指向数组第一个元素的指针。
-## vecort 迭代器
+## `vector` 迭代器
vector 提供了如下几种迭代器
以上列出的迭代器中,含有字符 `c` 的为只读迭代器,你不能通过只读迭代器去修改 vector 中的元素的值。如果一个 vector 本身就是只读的,那么它的一般迭代器和只读迭代器完全等价。只读迭代器自 C++11 开始支持。
-## vector 容量
+## `vector` 容量
vector 有如下几种返回容量的函数
此外,还有 `max_size()`, `reserve()`, `capacity()` 等 OIer 很难用到的函数,不做介绍。
-## vector 修改器
+## `vector` 修改器
- `clear()` 清除所有元素
- `insert()` 支持在某个迭代器位置插入元素、可以插入多个**此操作是与 `pos` 距离末尾长度成线性而非常数的**
- `pop_back()` 删除末尾元素。
- `swap()` 与另一个容器进行交换,此操作是**常数复杂度**而非线性的。
-## vector 特化 `std::vector<bool>`
+## `vector` 特化 `std::vector<bool>`
标准库提供对 bool 的 vector 优化,其空间占用与 bitset 一样,每个 `bool` 只占 1bit,且支持动态内存
我们可以把要研究的图形放在平面直角坐标系或极坐标系下,这样解决问题就会方便很多。
-## 0. 前置技能
+## 前置技能
如并不了解:
请先阅读 [OI Wiki - 数学 - 杂项](/math/misc/)。
-## 1. 图形的记录
+## 图形的记录
-### 1.1. 点
+### 点
在平面直角坐标系下,点用坐标表示,比如点 $(5,2)$,点 $(-1,0)$ 什么的。
在极坐标系下,用极坐标表示即可。记录其极径与极角。
-### 1.2. 向量
+### 向量
由于向量的坐标表示与点相同,所以只需要像点一样存向量即可(当然点不是向量)。
在极坐标系下,与点同理。
-### 1.3. 线
+### 线
-#### 1.3.1. 直线与射线
+#### 直线与射线
一般在解数学题时,我们用解析式表示一条直线。有一般式 $Ax+By+C=0$,还有斜截式 $y=kx+b$,还有截距式 $\frac{x}{a}+\frac{y}{b}=1$…… 用哪种?
因此我们记录的是:直线上一点和直线的方向向量。
-#### 1.3.2. 线段
+#### 线段
线段很好记录:只需要记录左右端点即可。
在极坐标系下,记录线是比较麻烦的,因此大多数直线问题都在平面直角坐标系下解决。
-### 1.4. 多边形
+### 多边形
开数组按一定顺序记录多边形的每个顶点即可。
特殊地,如果矩形的各边均与某坐标轴平行的话,我们只记录左下角和右上角的顶点即可。
-### 1.5. 曲线
+### 曲线
一些特殊曲线,如函数图像等一般记录其解析式。对于圆,直接记录其圆心和半径即可。
-## 2. 基本公式
+## 基本公式
-### 2.1. 正弦定理
+### 正弦定理
在三角形 $\triangle \text{ABC}$ 中,若角 $A,B,C$ 所对边分别为 $a,b,c$,则有:
其中,$R$ 为 $\triangle \text{ABC}$ 的外接圆半径。
-### 2.2. 余弦定理
+### 余弦定理
在三角形 $\triangle \text{ABC}$ 中,若角 $A,B,C$ 所对边分别为 $a,b,c$,则有:
上述公式的证明略。均为人教版高中数学 A 版必修五内容。
-## 3. 基本操作
+## 基本操作
-### 3.1. 判断一个点在直线的哪边
+### 判断一个点在直线的哪边
> 某同学:我能看出来!
可以画一下图,用右手定则感受一下。
-### 3.2. 快速排斥实验与跨立实验
+### 快速排斥实验与跨立实验
> 某同学:捂我嘴干什么我可以 ……%¥\*……%
由于快速排斥实验只需要少量比较而不需要计算,所以先用快速排斥实验判断可以减小一部分常数。
-### 3.3. 判断一点是否在任意多边形内部
+### 判断一点是否在任意多边形内部
> 某同学:我还能 %$#^%\*(%&))
在计算几何中,这个问题被称为 [PIP 问题](https://en.wikipedia.org/wiki/Point_in_polygon),已经有一些成熟的解决方法,下面依次介绍。
-#### 3.3.1. 光线投射算法 _(Ray casting algorithm)_
+#### 光线投射算法 _(Ray casting algorithm)_
在[这里](https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html)可以看到最原始的思路。
在原版代码中,使用的是记录多边形的数组中最后一个点作为射线上一点,这样统计时,如果出现射线过多边形某边或某顶点时,可以规定射线经过的点同在射线一侧,进而做跨立实验即可。
-#### 3.3.2. 回转数算法 _(Winding number algorithm)_
+#### 回转数算法 _(Winding number algorithm)_
回转数是数学上的概念,是平面内闭合曲线逆时针绕过该点的总次数。很容易发现,当回转数等于 $0$ 的时候,点在曲线外部。这个算法同样被称为非零规则 _(Nonzero-rule)_。
如何计算呢?我们把该点与多边形的所有顶点连接起来,计算相邻两边夹角的和。注意这里的夹角是**有方向的**。如果夹角和为 $0$,则这个点在多边形外,否则在多边形内。
-### 3.4. 求两条直线的交点
+### 求两条直线的交点
> 某同学:这还不简单联立方程 #%$&^%)(Y(\*&^UIG))
于是,只需要将点 $P$ 加上 $T\vec a$ 即可得出交点。
-### 3.5. 求任意多边形的周长和面积
+### 求任意多边形的周长和面积
-#### 3.5.1. 求任意多边形的周长
+#### 求任意多边形的周长
直接计算即可,简洁即美德。
-#### 3.5.2. 求任意多边形的面积
+#### 求任意多边形的面积
考虑向量积的模的几何意义,我们可以利用向量积完成。
S=\frac{1}{2}\sum_{i=1}^n |\vec {v_i}\times \overrightarrow{v_{i\bmod n+1}}|
$$
-### 3.6. 圆与直线相关
+### 圆与直线相关
-#### 3.6.1. 求直线与圆的交点
+#### 求直线与圆的交点
首先判断直线与圆的位置关系。如果直线与圆相离则无交点,若相切则可以利用切线求出切点与半径所在直线,之后转化为求两直线交点。
若有两交点,则可以利用勾股定理求出两交点的中点,然后沿直线方向加上半弦长即可。
-#### 3.6.2. 求两圆交点
+#### 求两圆交点
首先我们判断一下两个圆的位置关系,如果外离或内含则无交点,如果相切,可以算出两圆心连线的方向向量,然后利用两圆半径计算出平移距离,最后将圆心沿这个方向向量进行平移即可。
最后还是老套路——沿方向向量方向将圆心平移半径长度。
-### 3.7. 极角序
+### 极角序
!!! 例题
[「JOI Spring Camp 2014 Day4」两个人的星座](https://www.ioi-jp.org/camp/2014/2014-sp-tasks/2014-sp-d4.pdf)
分析一下算法复杂度,我们枚举了一个原点,然后对于每一个原点将剩余点排序后线性统计。于是时间复杂度为 $O(n^2\log n)$。
-## 4. 代码编写注意事项
+## 代码编写注意事项
由于计算几何经常进行 `double` 类型的浮点数计算,因此带来了精度问题和时间问题。
}
```
-### 例题 [P4926 \[1007\] 倍杀测量者](https://www.luogu.org/problemnew/show/P4926)
+### 例题 [P4926 [1007] 倍杀测量者](https://www.luogu.org/problemnew/show/P4926)
不考虑二分等其他的东西,这里只论述差分系统 $\frac{x_i}{x_j}\leq c_k$ 的求解方法。
![](./images/node2.png)
-## 例题 [luogu P4568 \[JLOI2011\] 飞行路线](https://www.luogu.org/problemnew/show/P4568)
+## 例题 [luogu P4568 [JLOI2011] 飞行路线](https://www.luogu.org/problemnew/show/P4568)
题目大意:有 $n$ 个结点, $m$ 条边, $k$ 张旅行券,可以使用一张旅行券使得经过该边的边权除以二向下取整,求从结点 $s$ 到 $t$ 的最短路的长度。
由于树链剖分的思想十分暴力,所以被 OIers 戏称为 **“优雅的暴力”** 。
-## 例题 [luogu P2590 \[ZJOI2008\] 树的统计](https://www.luogu.org/problemnew/show/P2590)
+## 例题 [luogu P2590 [ZJOI2008] 树的统计](https://www.luogu.org/problemnew/show/P2590)
题目大意:对一棵有 $n$ 个节点的静态树,进行三种操作共 $q$ 次:
事实上,这个 DP 就相当于把每个结点拆分成了 $k+1$ 个结点,每个新结点代表使用不同多次免费通行后到达的原图结点。换句话说,就是每个结点 $u_i$ 表示使用 $i$ 次免费通行权限后到达 $u$ 结点。
-### 模板题:[\[JLOI2011\]飞行路线](https://www.luogu.org/problemnew/show/P4568)
+### 模板题:[[JLOI2011]飞行路线](https://www.luogu.org/problemnew/show/P4568)
题意:有一个 $n$ 个点 $m$ 条边的无向图,你可以选择 $k$ 条道路以零代价通行,求 $s$ 到 $t$ 的最小花费。
* * *
-## 0x01 引言
+## 引言
众所周知,尽管现在大部分学校的竞赛练习环境都是构建 XP 等 Windows 系操作系统,但是在 NOI 系列赛中,早已用上了 NOI Linux 这个 Ubuntu 操作系统的阉割版。
![NOI 竞赛的环境要求](./images/WSL2.png)
* * *
-## 0x02 准备
+## 准备
首先,你需要一个最新的 Windows 10 操作系统,这点不必多说。
其次,你需要配置一下开发人员模式环境。
给系统盘留下足够的空间,毕竟装好的 Linux 没法迁移。
这次演示我们会安装 Ubuntu,因为 NOI Linux 正是 Ubuntu 的修改版。
只要学会了方法,你也可照葫芦画瓢,安装 Windows 应用商店中的其他子系统。
-## 0x03 开搞
+
+## 开搞
去 Windows 自带的应用商店,搜索 "Ubuntu",然后选第一个安装。
亦可打开 <https://www.microsoft.com/zh-cn/p/ubuntu/9nblggh4msv6>
???+ warning
![](./images/WSL6.png)
这样之后,一个纯净的 Ubuntu 系统安装完成了!
-## 0x04 基础配置
+## 基础配置
** 以下命令均可直接右键复制粘贴进窗口哦!**
**Tips:Linux 环境下可执行文件可不带扩展名,实现方式看上方命令行 **
-## 0x05 进阶操作
+## 进阶操作
### 安装图形环境,并使用远程桌面连接
运行 `sudo service xrdp restart`,然后去开始菜单,用 `localhost: 你配置的端口 ` 来访问。
![](./images/WSL14.png)
![](./images/WSL15.png)
+
#### 补充:使用 Xming 连接
有网友说,这个可以用 Xming 连接,那我们就来研究一下。
+
##### 客户端:安装 Xterm
我们进入 Ubuntu 环境,安装 xterm:
```bash
sudo apt-get install xterm -y
```
+
##### 服务端:下载 Xming Server
去 <https://sourceforge.net/projects/xming/> 下载最新的 Xming Server,然后一路安装:
![](./images/WSL16.png)
<div align='center'> 达成成就:Windows+Linux 二合一 </div>
感受一下两个版本融合的感觉:
![](./images/WSL21.png)
+
#### 与 Windows 内原硬盘分区交互
硬盘分区作为文件夹在 `/mnt/` 里放着,因此可以直接交互,比如说直接编译个二进制文件,或者往 Ubuntu 里传文件什么的......
具体演示:
![](./images/WSL23.png)
<div align='center'> 这里也可以建立一些 Windows(一般情况下)建不了的文件,例如带点文件夹 </div>
** 乱码是因为我用的预览体验系统……不过用正式版也可以了!**
-## 0x07 FAQ
+
+## FAQ
- 如何在子系统下进行 xxx?
该怎么用怎么用,可以用自带命令行,实在不行参考教程唤醒图形界面。
比如说 vim,在命令行中键入 `man vim`,会给出一份详尽的使用方法。
而且只要别装太多应用,应该还是可以带动的。
- 汉语化时提示不存在?
玄学问题,可以忽略。修了个疏忽导致的错误,可以重上一下试试。
-## 0x08 参考资料
+
+## 参考资料
这里列举了文中提到的链接,以便查阅。
1. [NOIP 标准评测系统及相关问题, smart0326, 2014-05-19, 百度文库](https://wenku.baidu.com/view/8246d96cdd36a32d72758143.html)
9. [Xming X Server for Windows, SourceForge](https://sourceforge.net/projects/xming/)
10. [Sudo, Wikipedia](https://zh.wikipedia.org/wiki/Sudo)
-## 0x09 延伸内容
+## 延伸内容
[Dev on Windows with WSL(在 Windows 上用 WSL 优雅开发)](https://spencerwoo.com/dowww/)
## 大步小步算法
-### 1.0 基础篇
+### 基础篇
大步小步算法英文名:**baby-step gaint-step (BSGS)**.
[BZOJ-2480](http://www.lydsy.com/JudgeOnline/problem.php?id=2480) 是一道模板题(可能是权限题),[BZOJ-3122](http://www.lydsy.com/JudgeOnline/problem.php?id=3122) 是一道略加变化的题,代码可以在 [Steaunk 的博客](https://blog.csdn.net/Steaunk/article/details/78988376) 中看到.
-### 2.0 略微进阶篇
+### 略微进阶篇
求解
[BZOJ-1319](http://www.lydsy.com/JudgeOnline/problem.php?id=1319) 是一道模板题,代码可以在 [Steaunk 的博客](https://blog.csdn.net/Steaunk/article/details/78988376) 中看到.
-### 3.0 扩展篇
+### 扩展篇
上文提到的情况是 $c$ 为素数的情况,如果 $c$ 不是素数呢?
设 $n = p_1^{k_1}p_2^{k_2} \cdots p_s^{k_s}$,其中 $p_i$ 是质数,那么定义 $\varphi(n) = n \times \prod_{i = 1}^s{\frac{p_i - 1}{p_i}}$
-### 欧拉函数的一些神奇性质
+## 欧拉函数的一些神奇性质
- 欧拉函数是积性函数。
- 若 $n = p^k$,其中 $p$ 是质数,那么 $\varphi(n) = p^k - p^{k - 1}$。
(根据定义可知)
-### 如何求欧拉函数值
+## 如何求欧拉函数值
如果只要求一个数的欧拉函数值,那么直接根据定义质因数分解的同时求就好了。
### 消元法及高斯消元法思想
-#### 1.1 消元法说明
+#### 消元法说明
消元法是将方程组中的一方程的未知数用含有另一未知数的代数式表示,并将其带入到另一方程中,这就消去了一未知数,得到一解;或将方程组中的一方程倍乘某个常数加到另外一方程中去,也可达到消去一未知数的母的。消元法主要用于二元一次方程组的求解。
$y = -60$
-#### 1.2 消元法理论的核心
+#### 消元法理论的核心
消元法理论的核心主要如下:
- 一方程乘以数 $k$ 加上另一方程,解不变。
-#### 1.3 高斯消元法思想概念
+#### 高斯消元法思想概念
德国数学家高斯对消元法进行了思考分析,得出了如下结论:
\end{aligned}\right.
$$
-### 第 1 步 增广矩阵行(初等)变换为行最简形
+#### 增广矩阵行(初等)变换为行最简形
所谓增广矩阵,即为方程组系数矩阵 $A$ 与常数列 $b$ 的并生成的新矩阵,即 $(A | b)$,增广矩阵行初等变换化为行最简形,即是利用了高斯消元法的思想理念,省略了变量而用变量的系数位置表示变量,增广矩阵中用竖线隔开了系数矩阵和常数列,代表了等于符号。
化为最简形
-#### 第 2 步 还原线性方程组
+#### 还原线性方程组
$$
\left\{\begin{aligned}
> 所谓的还原线性方程组,即是在行最简形的基础上,将之重新书写为线性方程组的形式,即将行最简形中各位置的系数重新赋予变量,中间的竖线还原为等号。
-#### 第 3 步 求解第一个变量
+#### 求解第一个变量
$$
\left\{\begin{aligned}
> 即是对于所还原的线性方程组而言,将方程组中每个方程的第一个变量,用其他量表达出来。如方程组两方程中的第一个变量 $x_1$ 和 $x_3$
-#### 第 4 步 补充自由未知量
+#### 补充自由未知量
$$
\left\{\begin{aligned}
> 第 3 步中,求解出变量 $x_1$ 和 $x_3$,从而说明了方程剩余的变量 $x_2$ 和 $x_4$ 不受方程组的约束,是自由未知量,可以取任意值,所以需要在第 3 步骤解得基础上进行解得补充,补充的方法为 $x_2 = x_2,x_4 = x_4$,这种解得补充方式符合自由未知量定义,并易于理解,因为是自由未知量而不受约束,所以只能自己等于自己。
-#### 第 5 步 列表示方程组的通解
+#### 列表示方程组的通解
$$
\begin{aligned}
## 如何求逆元
-### 扩展欧几里得法:
+### 扩展欧几里得法
```cpp
void ex_gcd(int a, int b, int& x, int& y) {
扩展欧几里得法和求解 [线性同余方程](/math/linear-equation/) 是一个原理,在这里不展开解释。
-### 快速幂法:
+### 快速幂法
这个要运用 [费马小定理](/math/fermat/):
下面按照从必修到选修的顺序介绍。所有内容均基于人教版高中数学 A 版教科书。
-## 1. 向量
+## 向量
(为人教版高中数学 A 版教科书必修四内容)
>
> ——《膜你抄》
-### 1.1. 定义及相关概念
+### 定义及相关概念
**向量**:既有大小又有方向的量称为向量。
注意到平面向量具有方向性,我们并不能比较两个向量的大小。但是两个向量可以相等。
-### 1.2. 向量的线性运算
+### 向量的线性运算
-#### 1.2.1. 向量的加法与减法
+#### 向量的加法与减法
我们定义了一种量,就希望让它具有运算。向量的运算可以类比数的运算,但是我们从物理学的角度出发研究向量的运算。
我们有时候有两点 $A,B$,想知道 $\vec{AB}$,可以利用减法运算 $\vec{AB}=\vec{OB}-\vec{OA}$ 获得。
-#### 1.2.2. 向量的数乘
+#### 向量的数乘
考虑 $\vec b=\vec a+\vec a+\vec a$,$\vec b$ 等于 3 个 $\vec a$ 相加,我们记为 $\vec b=3\vec a$。
最后,向量的加,减,数乘统称为向量的线性运算。
-### 1.3. 平面向量的基本定理及坐标表示
+### 平面向量的基本定理及坐标表示
-#### 1.3.1. 平面向量基本定理
+#### 平面向量基本定理
平面向量那么多,我们想用尽可能少的量表示出所有平面向量,怎么办呢?
如果基底相互垂直,那么我们在分解的时候就是对向量**正交分解**。
-#### 1.3.2. 平面向量的坐标表示
+#### 平面向量的坐标表示
我们想把平面上的图形都放在平面直角坐标系下研究(这样形的问题就有了数作为依据)。
这样没问题?是的,因为有序实数对 $(x,y)$ 与平面直角坐标系上的点唯一确定,那么我们作 $\vec{OP}=\vec p$,那么终点 $P(x,y)$ 也是唯一确定的。由于我们研究的都是自由向量,可以自由平移起点,这样,在平面直角坐标系里,每一个向量都可以用有序实数对唯一表示。
-#### 1.3.3. 平面向量的坐标运算
+#### 平面向量的坐标运算
由平面向量的线性运算,我们可以推导其坐标运算,主要方法是将坐标全部化为用基底表示,然后利用运算律进行合并,之后表示出运算结果的坐标形式。
证明很简单,~~留作课后作业。~~
-### 1.4. 向量的数量积
+### 向量的数量积
已知两个向量 $\vec a,\vec b$,它们的夹角为 $\theta$,那么:
说到这里,我们就可以用向量解决很多几何问题了。
-### 1.5. 扩展
+### 扩展
-#### 1.5.1. 向量与矩阵
+#### 向量与矩阵
(为人教版高中数学 A 版选修 4-2 内容)
详细内容请参考线性代数。
-#### 1.5.1. 向量积
+#### 向量积
我们定义向量 $\vec a,\vec b$ 的向量积为一个向量,记为 $\vec a\times \vec b$,其模与方向定义如下:
我们有一个不完全的坐标表示:记 $\vec a=(m,n),\vec b=(p,q)$,那么两个向量的向量积的竖坐标为 $mq-np$,我们根据右手法则和竖坐标符号可以推断出 $\vec b$ 相对于 $\vec a$ 的方向,若在逆时针方向竖坐标为正值,反之为负值,简记为**顺负逆正**。
-## 2. 极坐标与极坐标系
+## 极坐标与极坐标系
-### 2.1. 任意角与弧度制
+### 任意角与弧度制
(为人教版高中数学 A 版必修四内容)
可以理解为:给这个角不停加一圈,终边位置不变。
-### 2.2. 极坐标与极坐标系
+### 极坐标与极坐标系
(为人教版高中数学 A 版选修 4-4 内容)
-# CDQ 分治
-
-### 引子
+## 引子
什么是 cdq 分治呢?,其实他是一种思想而不是具体的算法(就和 dp 是一样的),因此 cdq 分治涵盖的范围相当的广泛,由于这样的思路最早是被陈丹琪引入国内的,所以就叫 cdq 分治了
* * *
-## 2 CDQ 分治优化 1D/1D 动态规划的转移
+## CDQ 分治优化 1D/1D 动态规划的转移
所谓 1D/1D 动态规划就是说我们的 dp 数组是 1 维的,转移是$O(n)$的一类 dp 问题,如果条件良好的话我们有些时候可以通过 cdq 分治来把这类问题的时间复杂度由$O(n^2)$降至$O(nlog^2n)$
-## OI 中常用的几类距离 :
+## OI 中常用的几类距离
### 曼哈顿距离
$Dis(A, B) = \sqrt{\sum\limits_{k=1}^n(x_{1k}-x_{2k})^2}$
-### L_m 距离
+### $L_m$ 距离
一般地,我们定义平面上两点 $A(x_1, y_1)$, $B(x_2, y_2)$ 之间的 $L_m$ 距离为
-## 这个板块主要介绍的是一些难以分类的实用算法、实用技巧
+这个板块主要介绍的是一些难以分类的实用算法、实用技巧
如果你是一名想学习一些基础技巧的 OIer / 想掌握这个板块 NOIP 需要掌握的知识,请参阅以下类 :
## 关闭同步 / 解除绑定
-### std::ios::sync_with_stdio(false)
+### `std::ios::sync_with_stdio(false)`
这个函数是一个 “是否兼容 stdio” 的开关,C++ 为了兼容 C,保证程序在使用了 `printf` 和 `std::cout` 的时候不发生混乱,将输出流绑到了一起。
这其实是 C++ 为了兼容而采取的保守措施。我们可以在 IO 之前将 stdio 解除绑定,这样做了之后要注意不要同时混用 `std::cout` 和 `printf` 之类
-### tie
+### `tie`
tie 是将两个 stream 绑定的函数,空参数的话返回当前的输出流指针。
C 标准库是在对字符数组进行操作
-### strlen
+### `strlen`
`int strlen(const char *str)` :返回从 `str[0]` 开始直到 `'\0'` 的字符数。注意,未开启 O2 优化时,该操作写在循环条件中复杂度是 $\Theta(N)$ 的。
-### printf
+### `printf`
`printf("%s", s)`:用 `%s` 来输出一个字符串(字符数组)。
-### scanf
+### `scanf`
`scanf("%s", s)`:用 `%s` 来读入一个字符串(字符数组)。
-### sscanf
+### `sscanf`
`sscanf(const char *__source, const char *__format, ...)`:从字符串`__source`里读取变量,比如`sscanf(str,"%d",&a)`。
-### sprintf
+### `sprintf`
`sprintf(char *__stream, const char *__format, ...)`:将`__format`字符串里的内容输出到`__stream`中,比如`sprintf(str,"%d",i)`。
-### strcmp
+### `strcmp`
`int strcmp(const char *str1, const char *str2)`:按照字典序比较 `str1 str2` 若 `str1` 字典序小返回负值, 一样返回 0 ,大返回正值 请注意,不要简单的认为只有 `0, 1, -1` 三种,在不同平台下的返回值都遵循正负,但并非都是 `0, 1, -1`
-### strcpy
+### `strcpy`
`char *strcpy(char *str, const char *src)` : 把 `src` 中的字符复制到 `str` 中, `str` `src` 均为字符数组头指针, 返回值为 `str` 包含空终止符号 `'\0'` 。
-### strncpy
+### `strncpy`
`char *strncpy(char *str, const char *src, int cnt)` :复制至多 `cnt` 个字符到 `str` 中,若 `src` 终止而数量未达 `cnt` 则写入空字符到 `str` 直至写入总共 `cnt` 个字符。
-### strcat
+### `strcat`
`char *strcat(char *str1, const char *str2)` : 将 `str2` 接到 `str1` 的结尾,用 `*str2` 替换 `str1` 末尾的 `'\0'` 返回 `str1` 。
-### strstr
+### `strstr`
-### strchr
+### `strchr`
-### strrchr
+### `strrchr`
## C++ 标准库
C++ 标准库是在对字符串对象进行操作,同时也提供对字符数组的兼容。
-### std::string
+### `std::string`
- 赋值运算符 `=` 右侧可以是 `const string / string / const char* / char*`。
- 访问运算符 `[cur]` 返回 `cur` 位置的引用。
-## 1. 前言
+## 前言
### 后缀数组和后缀树
`名词数组`: $rank[i]$ 代表第 $i$ 个后缀排名为 $rank[i]$
-## 2. 一些构造方法
+## 一些构造方法
### 最简单的暴力