Unverified Commit 236efe65 authored by ksyx's avatar ksyx Committed by GitHub
Browse files

Update [Fix Format]

parent 0f9e2f89
Loading
Loading
Loading
Loading
+14 −22
Original line number Diff line number Diff line
@@ -6,13 +6,13 @@

### 各种定义

 `子串` :就是子串[捂脸]
 `子串` :就是子串[捂脸]

 `后缀` :就是从 $i$ 这个位置开始到该字符串的末尾的一个子串
 `后缀` :就是从 $i$ 这个位置开始到该字符串的末尾的一个子串

 `字符串大小比较` : $a$ 和 $b$ 这两个串,从头开始逐个字符按照 ASCII 码进行比较。(按照字典序比较)
 `字符串大小比较`$a$ 和 $b$ 这两个串按照字典序进行比较。

 `后缀数组` : $sa[i]$ 代表该字符串的 $len$ 个后缀中,从 $sa[i]$ 开始的后缀排在为 $i$ 个。 $sa$ 数组记录的是“排第几的哪个后缀”。
 `后缀数组` : $sa[i]$ 代表该字符串的 $len$ 个后缀中,从 $sa[i]$ 开始的后缀排在为 $i$ 个。 $sa$ 数组记录的是“排第几的哪个后缀”。

 `名次数组` : $rank[i]$ 代表从 $i$ 开始的后缀排名为 $rank[i]$ 。 $rank$ 数组记录的是“某个后缀排在第几个”。

@@ -20,7 +20,7 @@

### 最简单的暴力

把所有的后缀拆出来,然后 sort。由于直接比较长度为 n 的字符串的时间复杂度为 $O(n)$ ,所以整体时间复杂度为 $O(n^2 \log n)$ 
把所有的后缀拆出来,然后 sort。由于直接比较长度为 $n$ 的字符串的时间复杂度为 $O(n)$ ,所以整体时间复杂度为 $O(n^2 \log n)$

```cpp
int rank[123], sa[123];
@@ -53,15 +53,9 @@ int main() {

### 倍增法

这个就是一般写后缀数组用的方法
这个就是一般写后缀数组用的方法,复杂度是 $O(n\log n)$,前提是你要先会**基数排序**

复杂度是 $O(n\log n)$ 

前提是你要先会**基数排序**

假设我们有这样一个字符串 `aabaaaab` 

然后我们把所有的后缀列举出来:
假设我们有这样一个字符串 `aabaaaab` ,然后我们把所有的后缀列举出来:

![](images/sa1.png)

@@ -69,19 +63,17 @@ int main() {

![](images/sa2.png)

接着我们以第二个字母为关键字,在首字母有序的基础上进行排序,这个时候,我们把首字母相同的后缀拿出来单看
接着我们以第二个字母为关键字,在首字母有序的基础上进行排序,这个时候,我们把首字母相同的后缀拿出来单看

对于每一组首字母相同的后缀,首字母是对排序没有影响的,所以可以直接按照第二个字母进行基数排序,同样,对于首字母不同的后缀,由于按照首字母排序时,他们的相对大小已经确定,当按照第二个字母排序时,不会出现 `原来 a>b,现在 b>a` 的现象,所以我们可以看成一直在做区域内的排序,这之后变成这样:
对于每一组首字母相同的后缀,首字母是对排序没有影响的,所以可以直接按照第二个字母进行基数排序,同样,对于首字母不同的后缀,由于按照首字母排序时,他们的相对大小已经确定,当按照第二个字母排序时,不会出现 原来 a>b,现在 b>a 的现象,所以我们可以看成一直在做区域内的排序,这之后变成这样:

![](images/sa3.png)

第三字母同理……

这样子我们可以处理这个问题,可是复杂度还是没有到达一个我们可以接受的范围

所以我们引入**倍增**
这样子我们可以处理这个问题,可是复杂度还是没有到达一个我们可以接受的范围,所以我们引入**倍增**

当我们按照每个后缀的前 $2^k$ 个字母进行完排序后,那么我们把后缀的前 $2^{k+1}$ 看做前后两个 $2^k$ , 这样我们就可以把这前后两个 $2^k$ 作为之前说的 `首字母``第二个字母` 了,然后进行上述过程,就可以在 $O(nlogn)$ 的复杂度内处理这个问题了
当我们按照每个后缀的前 $2^k$ 个字母进行完排序后,那么我们把后缀的前 $2^{k+1}$ 看做前后两个 $2^k$ , 这样我们就可以把这前后两个 $2^k$ 作为之前说的首字母第二个字母了,然后进行上述过程,就可以在 $O(nlogn)$ 的复杂度内处理这个问题了

```cpp
#include <bits/stdc++.h>
@@ -132,10 +124,10 @@ int main() {
}
```

代码里 $x[i]$ 就是 $rank[i]$ 
代码里 $x[i]$ 就是 $rank[i]$

 $y[i]$ :假设 $y[i]=a\ ,\  y[i+1]=b$ 那么在原串中 从 $a+2^k$ 开始的 $2^k$ 个字符组成的子串**小于等于**从 $b+2^k$ 开始的 $2^k$ 个字符组成的子串
 $y[i]$:假设 $y[i]=a\ ,\  y[i+1]=b$ 那么在原串中从 $a+2^k$ 开始的 $2^k$ 个字符组成的子串**小于等于**从 $b+2^k$ 开始的 $2^k$ 个字符组成的子串

最好理解这个代码时,每一步都结合这基数排序来考虑
最好理解这个代码时,每一步都结合这基数排序来考虑

### DC3