mirror of https://github.com/OI-wiki/OI-wiki
refactor(docs): format C++ code in tabs using remark-tabbed and clang-formatter (#5167)
* fix(docs): add indent in tabs for tabbed syntax * chore(docs): format C++ code inside tabs with clang formatter * chore(docs): re-format with previous configpull/5055/head^2
parent
329dacee51
commit
643003dd91
|
@ -18,6 +18,7 @@
|
|||
"remark-math",
|
||||
"remark-math-space",
|
||||
"remark-lint-final-newline",
|
||||
"remark-tabbed",
|
||||
"remark-lint-no-tabs",
|
||||
"remark-clang-format"
|
||||
]
|
||||
|
|
|
@ -252,13 +252,11 @@ while (r - l > eps) {
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
--8<-- "docs/basic/code/binary/binary_1.cpp"
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
--8<-- "docs/basic/code/binary/binary_1.py"
|
||||
```
|
||||
|
|
|
@ -44,7 +44,6 @@ $$
|
|||
$$
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// 假设数组的大小是 n + 1,冒泡排序从数组下标 1 开始
|
||||
void bubble_sort(int *a, int n) {
|
||||
|
@ -64,7 +63,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def bubble_sort(a, n):
|
||||
flag = True
|
||||
|
|
|
@ -30,13 +30,12 @@
|
|||
## 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
const int N = 100010;
|
||||
|
||||
|
||||
int n, w, a[N];
|
||||
vector<int> bucket[N];
|
||||
|
||||
|
||||
void insertion_sort(vector<int>& A) {
|
||||
for (int i = 1; i < A.size(); ++i) {
|
||||
int key = A[i];
|
||||
|
@ -48,7 +47,7 @@
|
|||
A[j + 1] = key;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bucket_sort() {
|
||||
int bucket_size = w / n + 1;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
|
@ -68,13 +67,12 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
N = 100010
|
||||
w = n = 0
|
||||
a = [0] * N
|
||||
bucket = [[] for i in range(N)]
|
||||
|
||||
|
||||
def insertion_sort(A):
|
||||
for i in range(1, len(A)):
|
||||
key = A[i]
|
||||
|
@ -83,7 +81,7 @@
|
|||
A[j + 1] = A[j]
|
||||
j -= 1
|
||||
A[j + 1] = key
|
||||
|
||||
|
||||
def bucket_sort():
|
||||
bucket_size = int(w / n + 1)
|
||||
for i in range(0, n):
|
||||
|
|
|
@ -86,7 +86,6 @@ $f(n)=\omega(g(n))$,当且仅当对于任意给定的正数 $c$,$\exists n_0
|
|||
### `for` 循环
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int n, m;
|
||||
std::cin >> n >> m;
|
||||
|
@ -100,7 +99,6 @@ $f(n)=\omega(g(n))$,当且仅当对于任意给定的正数 $c$,$\exists n_0
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
n = int(input())
|
||||
m = int(input())
|
||||
|
@ -121,7 +119,6 @@ $f(n)=\omega(g(n))$,当且仅当对于任意给定的正数 $c$,$\exists n_0
|
|||
当我们要进行若干次操作时,如何判断这若干次操作是否影响时间复杂度呢?例如:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
const int N = 100000;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
|
@ -130,7 +127,6 @@ $f(n)=\omega(g(n))$,当且仅当对于任意给定的正数 $c$,$\exists n_0
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
N = 100000
|
||||
for i in range(0, N):
|
||||
|
|
|
@ -64,29 +64,27 @@ $$
|
|||
$$
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
const int N = 100010;
|
||||
const int W = 100010;
|
||||
|
||||
|
||||
int n, w, a[N], cnt[W], b[N];
|
||||
|
||||
|
||||
void counting_sort() {
|
||||
memset(cnt, 0, sizeof(cnt));
|
||||
for (int i = 1; i <= n; ++i) ++cnt[a[i]];
|
||||
for (int i = 1; i <= w; ++i) cnt[i] += cnt[i - 1];
|
||||
for (int i = n; i >= 1; --i) b[cnt[a[i]]--] = a[i];
|
||||
memset(cnt, 0, sizeof(cnt));
|
||||
for (int i = 1; i <= n; ++i) ++cnt[a[i]];
|
||||
for (int i = 1; i <= w; ++i) cnt[i] += cnt[i - 1];
|
||||
for (int i = n; i >= 1; --i) b[cnt[a[i]]--] = a[i];
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
N = W = 100010
|
||||
n = w = 0
|
||||
a = b = [0] * N
|
||||
cnt = [0] * W
|
||||
|
||||
|
||||
def counting_sort():
|
||||
for i in range(1, n + 1):
|
||||
cnt[a[i]] += 1
|
||||
|
|
|
@ -37,7 +37,6 @@ int func(传入数值) {
|
|||
1. 结构清晰,可读性强。例如,分别用不同的方法实现 [归并排序](./merge-sort.md):
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// 不使用递归的归并排序算法
|
||||
template <typename T>
|
||||
|
@ -47,6 +46,7 @@ int func(传入数值) {
|
|||
for (int start = 0; start < n - seg; start += seg + seg)
|
||||
merge(a, start, start + seg - 1, std::min(start + seg + seg - 1, n - 1));
|
||||
}
|
||||
```
|
||||
|
||||
// 使用递归的归并排序算法
|
||||
template <typename T>
|
||||
|
@ -60,7 +60,6 @@ int func(传入数值) {
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# 不使用递归的归并排序算法
|
||||
def merge_sort(a):
|
||||
|
|
|
@ -37,15 +37,13 @@ author: Early0v0, frank-xjh, Great-designer, ksyx, qiqistyle, Tiphereth-A , Sais
|
|||
枚举两个数的代码很容易就可以写出来。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (int i = 0; i < n; ++i)
|
||||
for (int j = 0; j < n; ++j)
|
||||
if (a[i] + a[j] == 0) ++ans;
|
||||
for (int j = 0; j < n; ++j)
|
||||
if (a[i] + a[j] == 0) ++ans;
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for i in range(n):
|
||||
for j in range(n):
|
||||
|
@ -58,15 +56,13 @@ author: Early0v0, frank-xjh, Great-designer, ksyx, qiqistyle, Tiphereth-A , Sais
|
|||
不妨要求第一个数要出现在靠前的位置。代码如下:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (int i = 0; i < n; ++i)
|
||||
for (int j = 0; j < i; ++j)
|
||||
if (a[i] + a[j] == 0) ++ans;
|
||||
for (int j = 0; j < i; ++j)
|
||||
if (a[i] + a[j] == 0) ++ans;
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for i in range(n):
|
||||
for j in range(i):
|
||||
|
@ -81,18 +77,16 @@ author: Early0v0, frank-xjh, Great-designer, ksyx, qiqistyle, Tiphereth-A , Sais
|
|||
两个数是否都一定要枚举出来呢?枚举其中一个数之后,题目的条件已经确定了其他的要素(另一个数)的条件,如果能找到一种方法直接判断题目要求的那个数是否存在,就可以省掉枚举后一个数的时间了。较为进阶地,在数据范围允许的情况下,我们可以使用桶[^1]记录遍历过的数。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
bool met[MAXN * 2];
|
||||
memset(met, 0, sizeof(met));
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (met[MAXN - a[i]]) ++ans;
|
||||
met[MAXN + a[i]] = true;
|
||||
if (met[MAXN - a[i]]) ++ans;
|
||||
met[MAXN + a[i]] = true;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
met = [False] * MAXN * 2
|
||||
for i in range(n):
|
||||
|
|
|
@ -103,13 +103,11 @@
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
--8<-- "docs/basic/code/greedy/greedy_1.cpp"
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
--8<-- "docs/basic/code/greedy/greedy_1.py"
|
||||
```
|
||||
|
|
|
@ -45,7 +45,6 @@ iRightChild(i) = 2 * i + 2;
|
|||
## 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void sift_down(int arr[], int start, int end) {
|
||||
// 计算父结点和子结点的下标
|
||||
|
@ -64,7 +63,7 @@ iRightChild(i) = 2 * i + 2;
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void heap_sort(int arr[], int len) {
|
||||
// 从最后一个节点的父节点开始 sift down 以完成堆化 (heapify)
|
||||
for (int i = (len - 1 - 1) / 2; i >= 0; i--) sift_down(arr, i, len - 1);
|
||||
|
@ -77,7 +76,6 @@ iRightChild(i) = 2 * i + 2;
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def sift_down(arr, start, end):
|
||||
# 计算父结点和子结点的下标
|
||||
|
@ -94,7 +92,7 @@ iRightChild(i) = 2 * i + 2;
|
|||
arr[parent], arr[child] = arr[child], arr[parent]
|
||||
parent = child
|
||||
child = int(parent * 2 + 1)
|
||||
|
||||
|
||||
def heap_sort(arr, len):
|
||||
# 从最后一个节点的父节点开始 sift down 以完成堆化 (heapify)
|
||||
i = (len - 1 - 1) / 2
|
||||
|
|
|
@ -40,23 +40,21 @@ $$
|
|||
$$
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
```cpp
|
||||
void insertion_sort(int arr[], int len) {
|
||||
for (int i = 1; i < len; ++i) {
|
||||
int key = arr[i];
|
||||
int j = i - 1;
|
||||
while (j >= 0 && arr[j] > key) {
|
||||
arr[j + 1] = arr[j];
|
||||
j--;
|
||||
}
|
||||
arr[j + 1] = key;
|
||||
for (int i = 1; i < len; ++i) {
|
||||
int key = arr[i];
|
||||
int j = i - 1;
|
||||
while (j >= 0 && arr[j] > key) {
|
||||
arr[j + 1] = arr[j];
|
||||
j--;
|
||||
}
|
||||
arr[j + 1] = key;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def insertion_sort(arr, n):
|
||||
for i in range(1, n):
|
||||
|
@ -79,16 +77,15 @@ $$
|
|||
### 代码实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void insertion_sort(int arr[], int len) {
|
||||
if (len < 2) return;
|
||||
for (int i = 1; i != len; ++i) {
|
||||
int key = arr[i];
|
||||
auto index = upper_bound(arr, arr + i, key) - arr;
|
||||
// 使用 memmove 移动元素,比使用 for 循环速度更快,时间复杂度仍为 O(n)
|
||||
memmove(arr + index + 1, arr + index, (i - index) * sizeof(int));
|
||||
arr[index] = key;
|
||||
}
|
||||
if (len < 2) return;
|
||||
for (int i = 1; i != len; ++i) {
|
||||
int key = arr[i];
|
||||
auto index = upper_bound(arr, arr + i, key) - arr;
|
||||
// 使用 memmove 移动元素,比使用 for 循环速度更快,时间复杂度仍为 O(n)
|
||||
memmove(arr + index + 1, arr + index, (i - index) * sizeof(int));
|
||||
arr[index] = key;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -21,9 +21,7 @@
|
|||
#### 实现
|
||||
|
||||
=== "C/C++"
|
||||
|
||||
=== "数组实现"
|
||||
|
||||
```cpp
|
||||
void merge(const int *a, size_t aLen, const int *b, size_t bLen, int *c) {
|
||||
size_t i = 0, j = 0, k = 0;
|
||||
|
@ -65,7 +63,6 @@
|
|||
也可使用 `<algorithm>` 库的 `merge` 函数,用法与上述指针式写法的相同。
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def merge(a, b):
|
||||
i, j = 0, 0
|
||||
|
@ -99,7 +96,6 @@
|
|||
注意下面的代码所表示的区间分别是 $[l, r)$,$[l, mid)$,$[mid, r)$。
|
||||
|
||||
=== "C/C++"
|
||||
|
||||
```cpp
|
||||
void merge_sort(int *a, int l, int r) {
|
||||
if (r - l <= 1) return;
|
||||
|
@ -115,7 +111,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def merge_sort(a, ll, rr):
|
||||
if rr - ll <= 1:
|
||||
|
@ -150,7 +145,6 @@
|
|||
#### 实现
|
||||
|
||||
=== "C/C++"
|
||||
|
||||
```cpp
|
||||
void merge_sort(int *a, size_t n) {
|
||||
int tmp[1024] = {}; // 请结合实际情况设置 tmp 数组的长度(与 a 相同),或使用
|
||||
|
@ -170,7 +164,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def merge_sort(a):
|
||||
seg = 1
|
||||
|
|
|
@ -29,13 +29,11 @@ C++ 标准库中实现了前缀和函数 [`std::partial_sum`](https://zh.cpprefe
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
--8<-- "docs/basic/code/prefix-sum/prefix-sum_1.cpp"
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
--8<-- "docs/basic/code/prefix-sum/prefix-sum_1.py"
|
||||
```
|
||||
|
@ -77,13 +75,11 @@ C++ 标准库中实现了前缀和函数 [`std::partial_sum`](https://zh.cpprefe
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
--8<-- "docs/basic/code/prefix-sum/prefix-sum_2.cpp"
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
--8<-- "docs/basic/code/prefix-sum/prefix-sum_2.py"
|
||||
```
|
||||
|
|
|
@ -25,14 +25,13 @@
|
|||
第三步中的序列已经分别有序且第一个序列中的数都小于第二个数,所以直接拼接起来就好了。
|
||||
|
||||
=== "C++[^ref2]"
|
||||
|
||||
```cpp
|
||||
struct Range {
|
||||
int start, end;
|
||||
|
||||
|
||||
Range(int s = 0, int e = 0) { start = s, end = e; }
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
void quick_sort(T arr[], const int len) {
|
||||
if (len <= 0) return;
|
||||
|
@ -60,7 +59,6 @@
|
|||
```
|
||||
|
||||
=== "Python[^ref2]"
|
||||
|
||||
```python
|
||||
def quick_sort(alist, first, last):
|
||||
if first >= last:
|
||||
|
@ -176,7 +174,6 @@
|
|||
三路快速排序实现起来非常简单,下面给出了一种三路快排的 C++ 实现。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// 模板的 T 参数表示元素的类型,此类型需要定义小于(<)运算
|
||||
template <typename T>
|
||||
|
@ -206,7 +203,6 @@
|
|||
```
|
||||
|
||||
=== "Python[^ref2]"
|
||||
|
||||
```python
|
||||
def quick_sort(arr, l, r):
|
||||
if l >= r:
|
||||
|
|
|
@ -35,7 +35,6 @@ $$
|
|||
$$
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void selection_sort(int* a, int n) {
|
||||
for (int i = 1; i < n; ++i) {
|
||||
|
@ -51,7 +50,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def selection_sort(a, n):
|
||||
for i in range(1, n):
|
||||
|
|
|
@ -298,7 +298,6 @@ Shell-Sort 执行顺序为:$\text{InsertionSort}(h_{\lfloor \log_2 n\rfloor}),
|
|||
## 实现
|
||||
|
||||
=== "C++[^ref1]"
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
void shell_sort(T array[], int length) {
|
||||
|
@ -318,7 +317,6 @@ Shell-Sort 执行顺序为:$\text{InsertionSort}(h_{\lfloor \log_2 n\rfloor}),
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def shell_sort(array, length):
|
||||
h = 1
|
||||
|
|
|
@ -28,13 +28,11 @@
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
--8<-- "docs/basic/code/simulate/simulate_1.cpp"
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
--8<-- "docs/basic/code/simulate/simulate_1.py"
|
||||
```
|
||||
|
|
|
@ -41,17 +41,16 @@
|
|||
## 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int n, a[maxn], tmp[maxn << 1];
|
||||
|
||||
|
||||
int winner(int pos1, int pos2) {
|
||||
int u = pos1 >= n ? pos1 : tmp[pos1];
|
||||
int v = pos2 >= n ? pos2 : tmp[pos2];
|
||||
if (tmp[u] <= tmp[v]) return u;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
void creat_tree(int &value) {
|
||||
for (int i = 0; i < n; i++) tmp[n + i] = a[i];
|
||||
for (int i = 2 * n - 1; i > 1; i -= 2) {
|
||||
|
@ -62,7 +61,7 @@
|
|||
value = tmp[tmp[1]];
|
||||
tmp[tmp[1]] = INF;
|
||||
}
|
||||
|
||||
|
||||
void recreat(int &value) {
|
||||
int i = tmp[1];
|
||||
while (i > 1) {
|
||||
|
@ -77,7 +76,7 @@
|
|||
value = tmp[tmp[1]];
|
||||
tmp[tmp[1]] = INF;
|
||||
}
|
||||
|
||||
|
||||
void tournament_sort() {
|
||||
int value;
|
||||
creat_tree(value);
|
||||
|
@ -89,19 +88,18 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
n = 0
|
||||
a = [0] * maxn
|
||||
tmp = [0] * maxn * 2
|
||||
|
||||
|
||||
def winner(pos1, pos2):
|
||||
u = pos1 if pos1 >= n else tmp[pos1]
|
||||
v = pos2 if pos2 >= n else tmp[pos2]
|
||||
if tmp[u] <= tmp[v]:
|
||||
return u
|
||||
return v
|
||||
|
||||
|
||||
def creat_tree(value):
|
||||
for i in range(0, n):
|
||||
tmp[n + 1] = a[i]
|
||||
|
@ -111,7 +109,7 @@
|
|||
tmp[k] = winner(i, j)
|
||||
value = tmp[tmp[i]]
|
||||
tmp[tmp[i]] = INF
|
||||
|
||||
|
||||
def recreat(value):
|
||||
i = tmp[1]
|
||||
while i > 1:
|
||||
|
@ -124,7 +122,7 @@
|
|||
i = k
|
||||
value = tmp[tmp[1]]
|
||||
tmp[tmp[1]] = INF
|
||||
|
||||
|
||||
def tournament_sort():
|
||||
value = 0
|
||||
creat_tree(value)
|
||||
|
|
|
@ -124,10 +124,9 @@ int dp() {
|
|||
容易发现该算法的时间复杂度为 $O(n^2)$。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int a[MAXN], d[MAXN];
|
||||
|
||||
|
||||
int dp() {
|
||||
d[1] = 1;
|
||||
int ans = 1;
|
||||
|
@ -144,7 +143,6 @@ int dp() {
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
a = [0] * MAXN
|
||||
d = [0] * MAXN
|
||||
|
@ -177,7 +175,6 @@ int dp() {
|
|||
参考代码如下:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (int i = 0; i < n; ++i) scanf("%d", a + i);
|
||||
memset(dp, 0x1f, sizeof dp);
|
||||
|
@ -190,7 +187,6 @@ int dp() {
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
dp = [0x1f1f1f1f] * MAXN
|
||||
mx = dp[0]
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
## 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (len = 1; len <= n; len++)
|
||||
for (i = 1; i <= 2 * n - 1; i++) {
|
||||
|
@ -55,7 +54,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for len in range(1, n + 1):
|
||||
for i in range(1, 2 * n):
|
||||
|
|
|
@ -42,7 +42,6 @@ $$
|
|||
还有一点需要注意的是,很容易写出这样的 **错误核心代码**:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (int i = 1; i <= n; i++)
|
||||
for (int l = 0; l <= W - w[i]; l++)
|
||||
|
@ -52,7 +51,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for i in range(1, n + 1):
|
||||
for l in range(0, W - w[i] + 1):
|
||||
|
@ -70,15 +68,12 @@ $$
|
|||
因此实际核心代码为
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (int i = 1; i <= n; i++)
|
||||
for (int l = W; l >= w[i]; l--)
|
||||
f[l] = max(f[l], f[l - w[i]] + v[i]);
|
||||
for (int l = W; l >= w[i]; l--) f[l] = max(f[l], f[l - w[i]] + v[i]);
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for i in range(1, n + 1):
|
||||
for l in range(W, w[i] - 1, -1):
|
||||
|
@ -171,7 +166,6 @@ $$
|
|||
|
||||
??? 二进制分组代码
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
index = 0;
|
||||
for (int i = 1; i <= m; i++) {
|
||||
|
@ -189,7 +183,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
index = 0
|
||||
for i in range(1, m + 1):
|
||||
|
@ -248,7 +241,6 @@ for (循环物品种类) {
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (int k = 1; k <= n; k++)
|
||||
for (int i = m; i >= mi; i--) // 对经费进行一层枚举
|
||||
|
@ -257,7 +249,6 @@ for (循环物品种类) {
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for k in range(1, n + 1):
|
||||
for i in range(m, mi - 1, -1): # 对经费进行一层枚举
|
||||
|
@ -277,17 +268,16 @@ for (循环物品种类) {
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (int k = 1; k <= ts; k++) // 循环每一组
|
||||
for (int i = m; i >= 0; i--) // 循环背包容量
|
||||
for (int j = 1; j <= cnt[k]; j++) // 循环该组的每一个物品
|
||||
if (i >= w[t[k][j]]) // 背包容量充足
|
||||
dp[i] = max(dp[i], dp[i - w[t[k][j]]] + c[t[k][j]]); // 像0-1背包一样状态转移
|
||||
for (int k = 1; k <= ts; k++) // 循环每一组
|
||||
for (int i = m; i >= 0; i--) // 循环背包容量
|
||||
for (int j = 1; j <= cnt[k]; j++) // 循环该组的每一个物品
|
||||
if (i >= w[t[k][j]]) // 背包容量充足
|
||||
dp[i] = max(dp[i],
|
||||
dp[i - w[t[k][j]]] + c[t[k][j]]); // 像0-1背包一样状态转移
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for k in range(1, ts + 1): # 循环每一组
|
||||
for i in range(m, -1, -1): # 循环背包容量
|
||||
|
|
|
@ -17,12 +17,11 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int n, t;
|
||||
int tcost[103], mget[103];
|
||||
int ans = 0;
|
||||
|
||||
|
||||
void dfs(int pos, int tleft, int tans) {
|
||||
if (tleft < 0) return;
|
||||
if (pos == n + 1) {
|
||||
|
@ -32,7 +31,7 @@
|
|||
dfs(pos + 1, tleft, tans);
|
||||
dfs(pos + 1, tleft - tcost[pos], tans + mget[pos]);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
cin >> t >> n;
|
||||
for (int i = 1; i <= n; i++) cin >> tcost[i] >> mget[i];
|
||||
|
@ -43,7 +42,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
tcost = [0] * 103
|
||||
mget = [0] * 103
|
||||
|
@ -78,12 +76,11 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int n, t;
|
||||
int tcost[103], mget[103];
|
||||
int mem[103][1003];
|
||||
|
||||
|
||||
int dfs(int pos, int tleft) {
|
||||
if (mem[pos][tleft] != -1)
|
||||
return mem[pos][tleft]; // 已经访问过的状态,直接返回之前记录的值
|
||||
|
@ -94,7 +91,7 @@
|
|||
dfs2 = dfs(pos + 1, tleft - tcost[pos]) + mget[pos]; // 状态转移
|
||||
return mem[pos][tleft] = max(dfs1, dfs2); // 最后将当前状态的值存下来
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
memset(mem, -1, sizeof(mem));
|
||||
cin >> t >> n;
|
||||
|
@ -105,7 +102,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
tcost = [0] * 103
|
||||
mget = [0] * 103
|
||||
|
@ -171,7 +167,6 @@ $dp_{i} = \max\{dp_{j}+1\}\quad (1 \leq j < i \land a_{j}<a_{i})$(最长上升
|
|||
转为
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int dfs(int i) {
|
||||
if (mem[i] != -1) return mem[i];
|
||||
|
@ -180,7 +175,7 @@ $dp_{i} = \max\{dp_{j}+1\}\quad (1 \leq j < i \land a_{j}<a_{i})$(最长上升
|
|||
if (a[j] < a[i]) ret = max(ret, dfs(j) + 1);
|
||||
return mem[i] = ret;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
memset(mem, -1, sizeof(mem));
|
||||
// 读入部分略去
|
||||
|
@ -193,7 +188,6 @@ $dp_{i} = \max\{dp_{j}+1\}\quad (1 \leq j < i \land a_{j}<a_{i})$(最长上升
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def dfs(i):
|
||||
if mem[i] != -1:
|
||||
|
|
|
@ -145,22 +145,20 @@ $$
|
|||
|
||||
???+ note "核心代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (int len = 2; len <= n; ++len) // 枚举区间长度
|
||||
for (int l = 1, r = len; r <= n; ++l, ++r) {
|
||||
for (int l = 1, r = len; r <= n; ++l, ++r) {
|
||||
// 枚举长度为len的所有区间
|
||||
f[l][r] = INF;
|
||||
for (int k = m[l][r - 1]; k <= m[l + 1][r]; ++k)
|
||||
if (f[l][r] > f[l][k] + f[k + 1][r] + w(l, r)) {
|
||||
if (f[l][r] > f[l][k] + f[k + 1][r] + w(l, r)) {
|
||||
f[l][r] = f[l][k] + f[k + 1][r] + w(l, r); // 更新状态值
|
||||
m[l][r] = k; // 更新(最小)最优决策点
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for len in range(2, n + 1): # 枚举区间长度
|
||||
r = len
|
||||
|
@ -263,7 +261,6 @@ $$
|
|||
|
||||
???+ note "代码实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void DP(int l, int r, int k_l, int k_r) {
|
||||
int mid = (l + r) / 2, k = k_l;
|
||||
|
@ -278,7 +275,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def DP(l, r, k_l, k_r):
|
||||
mid = int((l + r) / 2)
|
||||
|
|
|
@ -22,17 +22,15 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
struct dsu {
|
||||
vector<size_t> pa;
|
||||
|
||||
|
||||
explicit dsu(size_t size) : pa(size) { iota(pa.begin(), pa.end(), 0); }
|
||||
};
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
class Dsu:
|
||||
def __init__(self, size):
|
||||
|
@ -47,13 +45,11 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
size_t dsu::find(size_t x) { return pa[x] == x ? x : find(pa[x]); }
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def find(self, x):
|
||||
return x if self.pa[x] == x else self.find(self.pa[x])
|
||||
|
@ -67,13 +63,11 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
size_t dsu::find(size_t x) { return pa[x] == x ? x : pa[x] = find(pa[x]); }
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def find(self, x):
|
||||
if self.pa[x] != x:
|
||||
|
@ -89,13 +83,11 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void dsu::unite(size_t x, size_t y) { pa[find(x)] = find(y); }
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def union(self, x, y):
|
||||
self.pa[self.find(x)] = self.find(y)
|
||||
|
@ -118,15 +110,14 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
struct dsu {
|
||||
vector<size_t> pa, size;
|
||||
|
||||
|
||||
explicit dsu(size_t size_) : pa(size_), size(size_, 1) {
|
||||
iota(pa.begin(), pa.end(), 0);
|
||||
}
|
||||
|
||||
|
||||
void unite(size_t x, size_t y) {
|
||||
x = find(x), y = find(y);
|
||||
if (x == y) return;
|
||||
|
@ -138,13 +129,12 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
class Dsu:
|
||||
def __init__(self, size):
|
||||
self.pa = list(range(size))
|
||||
self.size = [1] * size
|
||||
|
||||
|
||||
def union(self, x, y):
|
||||
x, y = self.find(x), self.find(y)
|
||||
if x == y:
|
||||
|
@ -161,16 +151,15 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
struct dsu {
|
||||
vector<size_t> pa, size;
|
||||
|
||||
|
||||
explicit dsu(size_t size_) : pa(size_ * 2), size(size_ * 2, 1) {
|
||||
iota(pa.begin(), pa.begin() + size_, size_);
|
||||
iota(pa.begin() + size_, pa.end(), size_);
|
||||
}
|
||||
|
||||
|
||||
void erase(size_t x) {
|
||||
--size[find(x)];
|
||||
pa[x] = x;
|
||||
|
@ -179,13 +168,12 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
class Dsu:
|
||||
def __init__(self, size):
|
||||
self.pa = list(range(size, size * 2)) * 2
|
||||
self.size = [1] * size * 2
|
||||
|
||||
|
||||
def erase(self, x):
|
||||
self.size[self.find(x)] -= 1
|
||||
self.pa[x] = x
|
||||
|
@ -197,7 +185,6 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void dsu::move(size_t x, size_t y) {
|
||||
auto fx = find(x), fy = find(y);
|
||||
|
@ -208,7 +195,6 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def move(self, x, y):
|
||||
fx, fy = self.find(x), self.find(y)
|
||||
|
@ -252,13 +238,11 @@ $A(m, n) = \begin{cases}n+1&\text{if }m=0\\A(m-1,1)&\text{if }m>0\text{ and }n=0
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
--8<-- "docs/ds/code/dsu/dsu_1.cpp"
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
--8<-- "docs/ds/code/dsu/dsu_1.py"
|
||||
```
|
||||
|
|
|
@ -115,7 +115,6 @@ $c$ 数组就是用来储存原始数组 $a$ 某段区间的和的,也就是
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int lowbit(int x) {
|
||||
// x 的二进制中,最低位的 1 以及后面所有 0 组成的数。
|
||||
|
@ -128,7 +127,6 @@ $c$ 数组就是用来储存原始数组 $a$ 某段区间的和的,也就是
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def lowbit(x):
|
||||
"""
|
||||
|
@ -171,7 +169,6 @@ $c$ 数组就是用来储存原始数组 $a$ 某段区间的和的,也就是
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int getsum(int x) { // a[1]..a[x]的和
|
||||
int ans = 0;
|
||||
|
@ -184,7 +181,6 @@ $c$ 数组就是用来储存原始数组 $a$ 某段区间的和的,也就是
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def getsum(x): # a[1]..a[x]的和
|
||||
ans = 0
|
||||
|
@ -332,7 +328,6 @@ $c$ 数组就是用来储存原始数组 $a$ 某段区间的和的,也就是
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void add(int x, int k) {
|
||||
while (x <= n) { // 不能越界
|
||||
|
@ -343,7 +338,6 @@ $c$ 数组就是用来储存原始数组 $a$ 某段区间的和的,也就是
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def add(x, k):
|
||||
while x <= n: # 不能越界
|
||||
|
@ -413,12 +407,11 @@ $\sum_{i=1}^r d_i$ 并不能推出 $\sum_{i=1}^r d_i \times i$ 的值,所以
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int t1[MAXN], t2[MAXN], n;
|
||||
|
||||
|
||||
int lowbit(int x) { return x & (-x); }
|
||||
|
||||
|
||||
void add(int k, int v) {
|
||||
int v1 = k * v;
|
||||
while (k <= n) {
|
||||
|
@ -427,7 +420,7 @@ $\sum_{i=1}^r d_i$ 并不能推出 $\sum_{i=1}^r d_i \times i$ 的值,所以
|
|||
k += lowbit(k);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int getsum(int *t, int k) {
|
||||
int ret = 0;
|
||||
while (k) {
|
||||
|
@ -436,42 +429,41 @@ $\sum_{i=1}^r d_i$ 并不能推出 $\sum_{i=1}^r d_i \times i$ 的值,所以
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void add1(int l, int r, int v) {
|
||||
add(l, v), add(r + 1, -v); // 将区间加差分为两个前缀加
|
||||
}
|
||||
|
||||
|
||||
long long getsum1(int l, int r) {
|
||||
return (r + 1ll) * getsum(t1, r) - 1ll * l * getsum(t1, l - 1) -
|
||||
(getsum(t2, r) - getsum(t2, l - 1));
|
||||
(getsum(t2, r) - getsum(t2, l - 1));
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
t1 = [0] * MAXN, t2 = [0] * MAXN; n = 0
|
||||
|
||||
|
||||
def lowbit(x):
|
||||
return x & (-x)
|
||||
|
||||
|
||||
def add(k, v):
|
||||
v1 = k * v
|
||||
while k <= n:
|
||||
t1[k] = t1[k] + v; t2[k] = t2[k] + v1
|
||||
k = k + lowbit(k)
|
||||
|
||||
|
||||
def getsum(t, k):
|
||||
ret = 0
|
||||
while k:
|
||||
ret = ret + t[k]
|
||||
k = k - lowbit(k)
|
||||
return ret
|
||||
|
||||
|
||||
def add1(l, r, v):
|
||||
add(l, v)
|
||||
add(r + 1, -v)
|
||||
|
||||
|
||||
def getsum1(l, r):
|
||||
return (r) * getsum(t1, r) - l * getsum(t1, l - 1) - \
|
||||
(getsum(t2, r) - getsum(t2, l - 1))
|
||||
|
@ -531,34 +523,32 @@ $$
|
|||
|
||||
???+ note "实现"
|
||||
=== "单点加"
|
||||
|
||||
```cpp
|
||||
void add(int x, int y, int v) {
|
||||
for (int i = x; i <= n ;i += lowbit(i)) {
|
||||
for (int j = y; j <= m; j += lowbit(j)) {
|
||||
// 注意这里必须得建循环变量,不能像一维数组一样直接 while (x <= n) 了
|
||||
c[i][j] += v;
|
||||
}
|
||||
for (int i = x; i <= n; i += lowbit(i)) {
|
||||
for (int j = y; j <= m; j += lowbit(j)) {
|
||||
// 注意这里必须得建循环变量,不能像一维数组一样直接 while (x <= n) 了
|
||||
c[i][j] += v;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== "查询子矩阵和"
|
||||
|
||||
```cpp
|
||||
int sum(int x, int y) {
|
||||
int res = 0;
|
||||
for (int i = x; i > 0; i -= lowbit(i)) {
|
||||
for (int j = y; j > 0; j -= lowbit(j)) {
|
||||
res += c[i][j];
|
||||
}
|
||||
for (int j = y; j > 0; j -= lowbit(j)) {
|
||||
res += c[i][j];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int ask(int x1, int y1, int x2, int y2) {
|
||||
// 查询子矩阵和
|
||||
return sum(x2, y2) - sum(x2, y1 - 1) - sum(x1 - 1, y2) + sum(x1 - 1, y1 - 1);
|
||||
// 查询子矩阵和
|
||||
return sum(x2, y2) - sum(x2, y1 - 1) - sum(x1 - 1, y2) + sum(x1 - 1, y1 - 1);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -718,13 +708,12 @@ $$
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// 权值树状数组查询第 k 小
|
||||
int kth(int k) {
|
||||
int sum = 0, x = 0;
|
||||
for (int i = log2(n); ~i; --i) {
|
||||
x += 1 << i; // 尝试扩展
|
||||
x += 1 << i; // 尝试扩展
|
||||
if (x >= n || sum + t[x] >= k) // 如果扩展失败
|
||||
x -= 1 << i;
|
||||
else
|
||||
|
@ -735,7 +724,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# 权值树状数组查询第 k 小
|
||||
def kth(k):
|
||||
|
@ -895,7 +883,6 @@ $i$ 按照 $5 \to 1$ 扫:
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// Θ(n) 建树
|
||||
void init() {
|
||||
|
@ -908,7 +895,6 @@ $i$ 按照 $5 \to 1$ 扫:
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# Θ(n) 建树
|
||||
def init():
|
||||
|
@ -925,7 +911,6 @@ $i$ 按照 $5 \to 1$ 扫:
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// Θ(n) 建树
|
||||
void init() {
|
||||
|
@ -936,7 +921,6 @@ $i$ 按照 $5 \to 1$ 扫:
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# Θ(n) 建树
|
||||
def init():
|
||||
|
@ -950,10 +934,10 @@ $i$ 按照 $5 \to 1$ 扫:
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// 时间戳优化
|
||||
int tag[MAXN], t[MAXN], Tag;
|
||||
```
|
||||
|
||||
void reset() { ++Tag; }
|
||||
|
||||
|
@ -976,7 +960,6 @@ $i$ 按照 $5 \to 1$ 扫:
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# 时间戳优化
|
||||
tag = [0] * MAXN; t = [0] * MAXN; Tag = 0
|
||||
|
|
|
@ -34,31 +34,30 @@ $x = s_0 \cdot 127^0 + s_1 \cdot 127^1 + s_2 \cdot 127^2 + \dots + s_n \cdot 127
|
|||
#### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
const int SIZE = 1000000;
|
||||
const int M = 999997;
|
||||
|
||||
|
||||
struct HashTable {
|
||||
struct Node {
|
||||
int next, value, key;
|
||||
} data[SIZE];
|
||||
|
||||
|
||||
int head[M], size;
|
||||
|
||||
|
||||
int f(int key) { return (key % M + M) % M; }
|
||||
|
||||
|
||||
int get(int key) {
|
||||
for (int p = head[f(key)]; p; p = data[p].next)
|
||||
if (data[p].key == key) return data[p].value;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int modify(int key, int value) {
|
||||
for (int p = head[f(key)]; p; p = data[p].next)
|
||||
if (data[p].key == key) return data[p].value = value;
|
||||
}
|
||||
|
||||
|
||||
int add(int key, int value) {
|
||||
if (get(key) != -1) return -1;
|
||||
data[++size] = (Node){head[f(key)], value, key};
|
||||
|
@ -69,7 +68,6 @@ $x = s_0 \cdot 127^0 + s_1 \cdot 127^1 + s_2 \cdot 127^2 + \dots + s_n \cdot 127
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
M = 999997
|
||||
SIZE = 1000000
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```c++
|
||||
struct Node {
|
||||
int value;
|
||||
|
@ -34,7 +33,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
class Node:
|
||||
def __init__(self, value = None, next = None):
|
||||
|
@ -50,7 +48,6 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```c++
|
||||
struct Node {
|
||||
int value;
|
||||
|
@ -60,7 +57,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
class Node:
|
||||
def __init__(self, value = None, left = None, right = None):
|
||||
|
@ -89,7 +85,6 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```c++
|
||||
void insertNode(int i, Node *p) {
|
||||
Node *node = new Node;
|
||||
|
@ -100,7 +95,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def insertNode(i, p):
|
||||
node = Node()
|
||||
|
@ -131,7 +125,6 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```c++
|
||||
void insertNode(int i, Node *p) {
|
||||
Node *node = new Node;
|
||||
|
@ -148,7 +141,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def insertNode(i, p):
|
||||
node = Node()
|
||||
|
@ -180,7 +172,6 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```c++
|
||||
void insertNode(int i, Node *p) {
|
||||
Node *node = new Node;
|
||||
|
@ -199,7 +190,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def insertNode(i, p):
|
||||
node = Node()
|
||||
|
@ -238,7 +228,6 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```c++
|
||||
void deleteNode(Node *p) {
|
||||
p->value = p->next->value;
|
||||
|
@ -249,7 +238,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def deleteNode(p):
|
||||
p.value = p.next.value
|
||||
|
@ -270,7 +258,6 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```c++
|
||||
void deleteNode(Node *&p) {
|
||||
p->left->right = p->right;
|
||||
|
@ -282,7 +269,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def deleteNode(p):
|
||||
p.left.right = p.right
|
||||
|
|
|
@ -31,7 +31,6 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
此处给出代码实现,可参考注释理解:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void build(int s, int t, int p) {
|
||||
// 对 [s,t] 区间建立线段树,当前根的编号为 p
|
||||
|
@ -49,7 +48,6 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def build(s, t, p):
|
||||
# 对 [s,t] 区间建立线段树,当前根的编号为 p
|
||||
|
@ -87,7 +85,6 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
此处给出代码实现,可参考注释理解:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int getsum(int l, int r, int s, int t, int p) {
|
||||
// [l, r] 为查询区间, [s, t] 为当前节点包含的区间, p 为当前节点的编号
|
||||
|
@ -103,7 +100,6 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def getsum(l, r, s, t, p):
|
||||
# [l, r] 为查询区间, [s, t] 为当前节点包含的区间, p 为当前节点的编号
|
||||
|
@ -156,7 +152,6 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
区间修改(区间加上某个值):
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void update(int l, int r, int c, int s, int t, int p) {
|
||||
// [l, r] 为修改区间, c 为被修改的元素的变化量, [s, t] 为当前节点包含的区间, p
|
||||
|
@ -179,7 +174,6 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def update(l, r, c, s, t, p):
|
||||
# [l, r] 为修改区间, c 为被修改的元素的变化量, [s, t] 为当前节点包含的区间, p
|
||||
|
@ -209,7 +203,6 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
区间查询(区间求和):
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int getsum(int l, int r, int s, int t, int p) {
|
||||
// [l, r] 为查询区间, [s, t] 为当前节点包含的区间, p 为当前节点的编号
|
||||
|
@ -230,7 +223,6 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def getsum(l, r, s, t, p):
|
||||
# [l, r] 为查询区间, [s, t] 为当前节点包含的区间, p为当前节点的编号
|
||||
|
@ -258,7 +250,6 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
如果你是要实现区间修改为某一个值而不是加上某一个值的话,代码如下:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void update(int l, int r, int c, int s, int t, int p) {
|
||||
if (l <= s && t <= r) {
|
||||
|
@ -277,7 +268,7 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
if (r > m) update(l, r, c, m + 1, t, p * 2 + 1);
|
||||
d[p] = d[p * 2] + d[p * 2 + 1];
|
||||
}
|
||||
|
||||
|
||||
int getsum(int l, int r, int s, int t, int p) {
|
||||
if (l <= s && t <= r) return d[p];
|
||||
int m = s + ((t - s) >> 1);
|
||||
|
@ -295,7 +286,6 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def update(l, r, c, s, t, p):
|
||||
if l <= s and t <= r:
|
||||
|
@ -314,7 +304,7 @@ author: Marcythm, Ir1d, Ycrpro, Xeonacid, konnyakuxzy, CJSoft, HeRaNO, ethan-enh
|
|||
if r > m:
|
||||
update(l, r, c, m + 1, t, p * 2 + 1)
|
||||
d[p] = d[p * 2] + d[p * 2 + 1]
|
||||
|
||||
|
||||
def getsum(l, r, s, t, p):
|
||||
if l <= s and t <= r:
|
||||
return d[p]
|
||||
|
|
|
@ -28,10 +28,10 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int st[N];
|
||||
// 这里使用 st[0] (即 *st) 代表栈中元素数量,同时也是栈顶下标
|
||||
```
|
||||
|
||||
// 压栈 :
|
||||
st[++*st] = var1;
|
||||
|
@ -47,10 +47,10 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
st = [0] * N
|
||||
# 这里使用 st[0] 代表栈中元素数量,同时也是栈顶下标
|
||||
```
|
||||
|
||||
# 压栈 :
|
||||
st[st[0] + 1] = var1
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
???+ note "代码实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// stk[] 是整型,存的是下标
|
||||
// p[] 存储向量或点
|
||||
|
@ -52,7 +51,7 @@
|
|||
// 栈内添加第一个元素,且不更新 used,使得 1 在最后封闭凸包时也对单调栈更新
|
||||
for (int i = 2; i <= n; ++i) {
|
||||
while (tp >= 2 // 下一行 * 操作符被重载为叉积
|
||||
&& (p[stk[tp]] - p[stk[tp - 1]]) * (p[i] - p[stk[tp]]) <= 0)
|
||||
&& (p[stk[tp]] - p[stk[tp - 1]]) * (p[i] - p[stk[tp]]) <= 0)
|
||||
used[stk[tp--]] = 0;
|
||||
used[i] = 1; // used 表示在凸壳上
|
||||
stk[++tp] = i;
|
||||
|
@ -72,7 +71,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
stk = [] # 是整型,存的是下标
|
||||
p = [] # 存储向量或点
|
||||
|
|
|
@ -148,11 +148,10 @@ $$
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
|
||||
int main() {
|
||||
int n, x, y, minx = 0x7fffffff, maxx = 0, miny = 0x7fffffff, maxy = 0;
|
||||
scanf("%d", &n);
|
||||
|
@ -167,7 +166,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
minx = 0x7fffffff; maxx = 0; miny = 0x7fffffff; maxy = 0
|
||||
n = int(input())
|
||||
|
@ -319,11 +317,10 @@ $$
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
|
||||
int main() {
|
||||
int n, x, y, a, b, minx = 0x7fffffff, maxx = 0, miny = 0x7fffffff, maxy = 0;
|
||||
scanf("%d", &n);
|
||||
|
@ -339,7 +336,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
minx = 0x7fffffff; maxx = 0; miny = 0x7fffffff; maxy = 0
|
||||
n = int(input())
|
||||
|
|
|
@ -28,19 +28,18 @@
|
|||
|
||||
???+ note "核心代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int sta[N], top; // 将凸包上的节点编号存在栈里,第一个和最后一个节点编号相同
|
||||
bool is[N];
|
||||
|
||||
|
||||
ll pf(ll x) { return x * x; }
|
||||
|
||||
|
||||
ll dis(int p, int q) { return pf(a[p].x - a[q].x) + pf(a[p].y - a[q].y); }
|
||||
|
||||
|
||||
ll sqr(int p, int q, int y) { return abs((a[q] - a[p]) * (a[y] - a[q])); }
|
||||
|
||||
|
||||
ll mx;
|
||||
|
||||
|
||||
void get_longest() { // 求凸包直径
|
||||
int j = 3;
|
||||
if (top < 4) {
|
||||
|
@ -49,7 +48,7 @@
|
|||
}
|
||||
for (int i = 1; i <= top; ++i) {
|
||||
while (sqr(sta[i], sta[i + 1], sta[j]) <=
|
||||
sqr(sta[i], sta[i + 1], sta[j % top + 1]))
|
||||
sqr(sta[i], sta[i + 1], sta[j % top + 1]))
|
||||
j = j % top + 1;
|
||||
mx = max(mx, max(dis(sta[i + 1], sta[j]), dis(sta[i], sta[j])));
|
||||
}
|
||||
|
@ -57,7 +56,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
sta = [0] * N; top = 0 # 将凸包上的节点编号存在栈里,第一个和最后一个节点编号相同
|
||||
def pf(x):
|
||||
|
@ -102,21 +100,20 @@ $$
|
|||
|
||||
???+ note "核心代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void get_biggest() {
|
||||
int j = 3, l = 2, r = 2;
|
||||
double t1, t2, t3, ans = 2e10;
|
||||
for (int i = 1; i <= top; ++i) {
|
||||
while (sqr(sta[i], sta[i + 1], sta[j]) <=
|
||||
sqr(sta[i], sta[i + 1], sta[j % top + 1]))
|
||||
sqr(sta[i], sta[i + 1], sta[j % top + 1]))
|
||||
j = j % top + 1;
|
||||
while (dot(sta[i + 1], sta[r % top + 1], sta[i]) >=
|
||||
dot(sta[i + 1], sta[r], sta[i]))
|
||||
dot(sta[i + 1], sta[r], sta[i]))
|
||||
r = r % top + 1;
|
||||
if (i == 1) l = r;
|
||||
while (dot(sta[i + 1], sta[l % top + 1], sta[i]) <=
|
||||
dot(sta[i + 1], sta[l], sta[i]))
|
||||
dot(sta[i + 1], sta[l], sta[i]))
|
||||
l = l % top + 1;
|
||||
t1 = sqr(sta[i], sta[i + 1], sta[j]);
|
||||
t2 = dot(sta[i + 1], sta[r], sta[i]) + dot(sta[i + 1], sta[l], sta[i]);
|
||||
|
@ -127,7 +124,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def get_biggest():
|
||||
j = 3; l = 2; r = 2
|
||||
|
|
|
@ -28,7 +28,6 @@ DFS 的代码如下:
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void DFS(int p) {
|
||||
visited[p] = true;
|
||||
|
@ -38,7 +37,6 @@ DFS 的代码如下:
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def DFS(p):
|
||||
visited[p] = True
|
||||
|
|
|
@ -18,7 +18,6 @@ BFS 全称是 [Breadth First Search](https://en.wikipedia.org/wiki/Breadth-first
|
|||
下文中 C++ 与 Python 的代码实现是基于链式前向星的存图方式,其实现可参考 [图的存储](./save.md) 页面。
|
||||
|
||||
=== "伪代码"
|
||||
|
||||
```text
|
||||
bfs(s) {
|
||||
q = new queue()
|
||||
|
@ -36,7 +35,6 @@ BFS 全称是 [Breadth First Search](https://en.wikipedia.org/wiki/Breadth-first
|
|||
```
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void bfs(int u) {
|
||||
while (!Q.empty()) Q.pop();
|
||||
|
@ -57,7 +55,7 @@ BFS 全称是 [Breadth First Search](https://en.wikipedia.org/wiki/Breadth-first
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void restore(int x) {
|
||||
vector<int> res;
|
||||
for (int v = x; v != -1; v = p[v]) {
|
||||
|
@ -70,10 +68,9 @@ BFS 全称是 [Breadth First Search](https://en.wikipedia.org/wiki/Breadth-first
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
from queue import Queue
|
||||
|
||||
|
||||
def bfs(u):
|
||||
Q = Queue()
|
||||
Q.put(u)
|
||||
|
@ -90,7 +87,7 @@ BFS 全称是 [Breadth First Search](https://en.wikipedia.org/wiki/Breadth-first
|
|||
d[e[i].to] = d[u] + 1
|
||||
p[e[i].to] = u
|
||||
i = e[i].nxt
|
||||
|
||||
|
||||
def restore(x):
|
||||
res = []
|
||||
v = x
|
||||
|
|
|
@ -85,7 +85,6 @@ author: GitPinkRabbit, Early0v0, Backl1ght, mcendu, ksyx, iamtwz, Xeonacid, kenl
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void Tarjan(int u) {
|
||||
low[u] = dfn[u] = ++dfc; // low 初始化为当前节点 dfn
|
||||
|
@ -100,7 +99,6 @@ author: GitPinkRabbit, Early0v0, Backl1ght, mcendu, ksyx, iamtwz, Xeonacid, kenl
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def Tarjan(u):
|
||||
low[u] = dfn[u] = dfc # low 初始化为当前节点 dfn
|
||||
|
|
|
@ -76,14 +76,13 @@ low[u] = min(low[u], dfn[v]);
|
|||
下面代码实现了求割边,其中,当 `isbridge[x]` 为真时,`(father[x],x)` 为一条割边。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int low[MAXN], dfn[MAXN], dfs_clock;
|
||||
bool isbridge[MAXN];
|
||||
vector<int> G[MAXN];
|
||||
int cnt_bridge;
|
||||
int father[MAXN];
|
||||
|
||||
|
||||
void tarjan(int u, int fa) {
|
||||
father[u] = fa;
|
||||
low[u] = dfn[u] = ++dfs_clock;
|
||||
|
@ -104,14 +103,13 @@ low[u] = min(low[u], dfn[v]);
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
low = [0] * MAXN; dfn = [0] * MAXN; dfs_clock = 0
|
||||
isbridge = [False] * MAXN
|
||||
G = [[0 for i in range(MAXN)] for j in range(MAXN)]
|
||||
cnt_bridge = 0
|
||||
father = [0] * MAXN
|
||||
|
||||
|
||||
def tarjan(u, fa):
|
||||
father[u] = fa
|
||||
low[u] = dfn[u] = dfs_clock
|
||||
|
|
|
@ -39,7 +39,6 @@ DFS 最显著的特征在于其 **递归调用自身**。同时与 BFS 类似,
|
|||
以链式前向星为例:(和上方伪代码每行一一对应)
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void dfs(int u) {
|
||||
vis[u] = 1;
|
||||
|
@ -52,7 +51,6 @@ DFS 最显著的特征在于其 **递归调用自身**。同时与 BFS 类似,
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def dfs(u):
|
||||
vis[u] = True
|
||||
|
|
|
@ -47,7 +47,6 @@ author: Ir1d, Anguei, hsfzLZH1
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
bool Bellman_Ford() {
|
||||
for (int i = 0; i < n; i++) {
|
||||
|
@ -66,7 +65,6 @@ author: Ir1d, Anguei, hsfzLZH1
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def Bellman_Ford():
|
||||
for i in range(0, n):
|
||||
|
|
|
@ -52,10 +52,9 @@
|
|||
下面给出 C++ 的参考实现:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int val[maxn + 1][maxn + 1]; // 原图的邻接矩阵
|
||||
|
||||
|
||||
int floyd(const int &n) {
|
||||
static int dis[maxn + 1][maxn + 1]; // 最短路矩阵
|
||||
for (int i = 1; i <= n; ++i)
|
||||
|
@ -75,10 +74,9 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
val = [[0 for i in range(maxn + 1)] for j in range(maxn + 1)] # 原图的邻接矩阵
|
||||
|
||||
|
||||
def floyd(n):
|
||||
dis = [[0 for i in range(maxn + 1)] for j in range(maxn + 1)] # 最短路矩阵
|
||||
for i in range(1, n + 1):
|
||||
|
|
|
@ -23,11 +23,10 @@ Prüfer 是这样建立的:每次选择一个编号最小的叶结点并删掉
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// 代码摘自原文,结点是从 0 标号的
|
||||
vector<vector<int>> adj;
|
||||
|
||||
|
||||
vector<int> pruefer_code() {
|
||||
int n = adj.size();
|
||||
set<int> leafs;
|
||||
|
@ -37,7 +36,7 @@ Prüfer 是这样建立的:每次选择一个编号最小的叶结点并删掉
|
|||
degree[i] = adj[i].size();
|
||||
if (degree[i] == 1) leafs.insert(i);
|
||||
}
|
||||
|
||||
|
||||
vector<int> code(n - 2);
|
||||
for (int i = 0; i < n - 2; i++) {
|
||||
int leaf = *leafs.begin();
|
||||
|
@ -54,11 +53,10 @@ Prüfer 是这样建立的:每次选择一个编号最小的叶结点并删掉
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# 结点是从 0 标号的
|
||||
adj = [[]]
|
||||
|
||||
|
||||
def pruefer_code():
|
||||
n = len(adj)
|
||||
leafs = set()
|
||||
|
@ -115,30 +113,29 @@ $p$ 是当前编号最小的叶结点,若删除 $p$ 后未产生叶结点,
|
|||
#### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// 从原文摘的代码,同样以 0 为起点
|
||||
vector<vector<int>> adj;
|
||||
vector<int> parent;
|
||||
|
||||
|
||||
void dfs(int v) {
|
||||
for (int u : adj[v]) {
|
||||
if (u != parent[v]) parent[u] = v, dfs(u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vector<int> pruefer_code() {
|
||||
int n = adj.size();
|
||||
parent.resize(n), parent[n - 1] = -1;
|
||||
dfs(n - 1);
|
||||
|
||||
|
||||
int ptr = -1;
|
||||
vector<int> degree(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
degree[i] = adj[i].size();
|
||||
if (degree[i] == 1 && ptr == -1) ptr = i;
|
||||
}
|
||||
|
||||
|
||||
vector<int> code(n - 2);
|
||||
int leaf = ptr;
|
||||
for (int i = 0; i < n - 2; i++) {
|
||||
|
@ -157,23 +154,22 @@ $p$ 是当前编号最小的叶结点,若删除 $p$ 后未产生叶结点,
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# 同样以 0 为起点
|
||||
adj = [[]]
|
||||
parent = [0] * n
|
||||
|
||||
|
||||
def dfs()v:
|
||||
for u in adj[v]:
|
||||
if u != parent[v]:
|
||||
parent[u] = v
|
||||
dfs(u)
|
||||
|
||||
|
||||
def pruefer_code():
|
||||
n = len(adj)
|
||||
parent[n - 1] = -1
|
||||
dfs(n - 1)
|
||||
|
||||
|
||||
ptr = -1
|
||||
degree = [0] * n
|
||||
for i in range(0, n):
|
||||
|
|
|
@ -15,21 +15,20 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct Edge {
|
||||
int u, v;
|
||||
};
|
||||
|
||||
|
||||
int n, m;
|
||||
vector<Edge> e;
|
||||
vector<bool> vis;
|
||||
|
||||
|
||||
bool find_edge(int u, int v) {
|
||||
for (int i = 1; i <= m; ++i) {
|
||||
if (e[i].u == u && e[i].v == v) {
|
||||
|
@ -38,7 +37,7 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void dfs(int u) {
|
||||
if (vis[u]) return;
|
||||
vis[u] = true;
|
||||
|
@ -48,40 +47,39 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
cin >> n >> m;
|
||||
|
||||
|
||||
vis.resize(n + 1, false);
|
||||
e.resize(m + 1);
|
||||
|
||||
|
||||
for (int i = 1; i <= m; ++i) cin >> e[i].u >> e[i].v;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
class Edge:
|
||||
def __init__(self, u = 0, v = 0):
|
||||
self.u = u
|
||||
self.v = v
|
||||
|
||||
|
||||
n, m = map(lambda x:int(x), input().split())
|
||||
|
||||
|
||||
e = [Edge() for _ in range(m)]; vis = [False] * n
|
||||
|
||||
|
||||
for i in range(0, m):
|
||||
e[i].u, e[i].v = map(lambda x:int(x), input().split())
|
||||
|
||||
|
||||
def find_edge(u, v):
|
||||
for i in range(1, m + 1):
|
||||
if e[i].u == u and e[i].v == v:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def dfs(u):
|
||||
if vis[u]:
|
||||
return
|
||||
|
@ -117,19 +115,18 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
int n, m;
|
||||
vector<bool> vis;
|
||||
vector<vector<bool> > adj;
|
||||
|
||||
|
||||
bool find_edge(int u, int v) { return adj[u][v]; }
|
||||
|
||||
|
||||
void dfs(int u) {
|
||||
if (vis[u]) return;
|
||||
vis[u] = true;
|
||||
|
@ -139,6 +136,7 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
int main() {
|
||||
cin >> n >> m;
|
||||
|
@ -157,18 +155,17 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
vis = [False] * (n + 1)
|
||||
adj = [[False] * (n + 1) for _ in range(n + 1)]
|
||||
|
||||
|
||||
for i in range(1, m + 1):
|
||||
u, v = map(lambda x:int(x), input().split())
|
||||
adj[u][v] = True
|
||||
|
||||
|
||||
def find_edge(u, v):
|
||||
return adj[u][v]
|
||||
|
||||
|
||||
def dfs(u):
|
||||
if vis[u]:
|
||||
return
|
||||
|
@ -204,17 +201,16 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
|
||||
??? note "参考代码"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
int n, m;
|
||||
vector<bool> vis;
|
||||
vector<vector<int> > adj;
|
||||
|
||||
|
||||
bool find_edge(int u, int v) {
|
||||
for (int i = 0; i < adj[u].size(); ++i) {
|
||||
if (adj[u][i] == v) {
|
||||
|
@ -223,45 +219,44 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void dfs(int u) {
|
||||
if (vis[u]) return;
|
||||
vis[u] = true;
|
||||
for (int i = 0; i < adj[u].size(); ++i) dfs(adj[u][i]);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
cin >> n >> m;
|
||||
|
||||
|
||||
vis.resize(n + 1, false);
|
||||
adj.resize(n + 1);
|
||||
|
||||
|
||||
for (int i = 1; i <= m; ++i) {
|
||||
int u, v;
|
||||
cin >> u >> v;
|
||||
adj[u].push_back(v);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
vis = [False] * (n + 1)
|
||||
adj = [[] for _ in range(n + 1)]
|
||||
|
||||
|
||||
for i in range(1, m + 1):
|
||||
u, v = map(lambda x:int(x), input().split())
|
||||
adj[u].append(v)
|
||||
|
||||
|
||||
def find_edge(u, v):
|
||||
for i in range(0, len(adj[u])):
|
||||
if adj[u][i] == v:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def dfs(u):
|
||||
if vis[u]:
|
||||
return
|
||||
|
@ -293,7 +288,6 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
本质上是用链表实现的邻接表,核心代码如下:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// head[u] 和 cnt 的初始值都为 -1
|
||||
void add(int u, int v) {
|
||||
|
@ -301,7 +295,7 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
head[u] = cnt; // 起点 u 的第一条边
|
||||
to[cnt] = v; // 当前边的终点
|
||||
}
|
||||
|
||||
|
||||
// 遍历 u 的出边
|
||||
for (int i = head[u]; ~i; i = nxt[i]) { // ~i 表示 i != -1
|
||||
int v = to[i];
|
||||
|
@ -309,7 +303,6 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# head[u] 和 cnt 的初始值都为 -1
|
||||
def add(u, v):
|
||||
|
@ -317,7 +310,7 @@ author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
|
|||
nex[cnt] = head[u] # 当前边的后继
|
||||
head[u] = cnt # 起点 u 的第一条边
|
||||
to[cnt] = v # 当前边的终点
|
||||
|
||||
|
||||
# 遍历 u 的出边
|
||||
i = head[u]
|
||||
while ~i: # ~i 表示 i != -1
|
||||
|
|
|
@ -77,12 +77,11 @@ Tarjan 发明了很多算法和数据结构。不少他发明的算法都以他
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int dfn[N], low[N], dfncnt, s[N], in_stack[N], tp;
|
||||
int scc[N], sc; // 结点 i 所在 SCC 的编号
|
||||
int sz[N]; // 强连通 i 的大小
|
||||
|
||||
|
||||
void tarjan(int u) {
|
||||
low[u] = dfn[u] = ++dfncnt, s[++tp] = u, in_stack[u] = 1;
|
||||
for (int i = h[u]; i; i = e[i].nex) {
|
||||
|
@ -111,7 +110,6 @@ Tarjan 发明了很多算法和数据结构。不少他发明的算法都以他
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
dfn = [0] * N; low = [0] * N; dfncnt = 0; s = [0] * N; in_stack = [0] * N; tp = 0
|
||||
scc = [0] * N; sc = 0 # 结点 i 所在 SCC 的编号
|
||||
|
@ -162,23 +160,22 @@ Kosaraju 算法最早在 1978 年由 S. Rao Kosaraju 在一篇未发表的论文
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// g 是原图,g2 是反图
|
||||
|
||||
|
||||
void dfs1(int u) {
|
||||
vis[u] = true;
|
||||
for (int v : g[u])
|
||||
if (!vis[v]) dfs1(v);
|
||||
s.push_back(u);
|
||||
}
|
||||
|
||||
|
||||
void dfs2(int u) {
|
||||
color[u] = sccCnt;
|
||||
for (int v : g2[u])
|
||||
if (!color[v]) dfs2(v);
|
||||
}
|
||||
|
||||
|
||||
void kosaraju() {
|
||||
sccCnt = 0;
|
||||
for (int i = 1; i <= n; ++i)
|
||||
|
@ -192,7 +189,6 @@ Kosaraju 算法最早在 1978 年由 S. Rao Kosaraju 在一篇未发表的论文
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def dfs1(u):
|
||||
vis[u] = True
|
||||
|
@ -200,13 +196,13 @@ Kosaraju 算法最早在 1978 年由 S. Rao Kosaraju 在一篇未发表的论文
|
|||
if vis[v] == False:
|
||||
dfs1(v)
|
||||
s.append(u)
|
||||
|
||||
|
||||
def dfs2(u):
|
||||
color[u] = sccCnt
|
||||
for v in g2[u]:
|
||||
if color[v] == False:
|
||||
dfs2(v)
|
||||
|
||||
|
||||
def kosaraju(u):
|
||||
sccCnt = 0
|
||||
for i in range(1, n + 1):
|
||||
|
@ -229,7 +225,6 @@ Garbow 算法是 Tarjan 算法的另一种实现,Tarjan 算法是用 dfn 和 l
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int garbow(int u) {
|
||||
stack1[++p1] = u;
|
||||
|
@ -252,7 +247,7 @@ Garbow 算法是 Tarjan 算法的另一种实现,Tarjan 算法是用 dfn 和 l
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void find_scc(int n) {
|
||||
dfs_clock = scc_cnt = 0;
|
||||
p1 = p2 = 0;
|
||||
|
@ -264,7 +259,6 @@ Garbow 算法是 Tarjan 算法的另一种实现,Tarjan 算法是用 dfn 和 l
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def garbow(u):
|
||||
stack1[p1] = u
|
||||
|
@ -286,7 +280,7 @@ Garbow 算法是 Tarjan 算法的另一种实现,Tarjan 算法是用 dfn 和 l
|
|||
while stack1[p1] != u:
|
||||
p1 = p1 - 1
|
||||
sccno[stack1[p1]] = scc_cnt
|
||||
|
||||
|
||||
def find_scc(n):
|
||||
dfs_clock = scc_cnt = 0
|
||||
p1 = p2 = 0
|
||||
|
|
|
@ -50,7 +50,6 @@ author: du33169
|
|||
上面两行都显然是对的,所以说这个做法空间是 $O(N^3)$,我们需要依次增加问题规模($k$ 从 $1$ 到 $n$),判断任意两点在当前问题规模下的最短路。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (k = 1; k <= n; k++) {
|
||||
for (x = 1; x <= n; x++) {
|
||||
|
@ -62,7 +61,6 @@ author: du33169
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for k in range(1, n + 1):
|
||||
for x in range(1, n + 1):
|
||||
|
@ -80,7 +78,6 @@ author: du33169
|
|||
故可以压缩。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (k = 1; k <= n; k++) {
|
||||
for (x = 1; x <= n; x++) {
|
||||
|
@ -92,7 +89,6 @@ author: du33169
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for k in range(1, n + 1):
|
||||
for x in range(1, n + 1):
|
||||
|
@ -164,16 +160,15 @@ Bellman–Ford 算法所做的,就是不断尝试对图上每一条边进行
|
|||
|
||||
??? note "参考实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
struct edge {
|
||||
int v, w;
|
||||
};
|
||||
|
||||
|
||||
vector<edge> e[maxn];
|
||||
int dis[maxn];
|
||||
const int inf = 0x3f3f3f3f;
|
||||
|
||||
|
||||
bool bellmanford(int n, int s) {
|
||||
memset(dis, 63, sizeof(dis));
|
||||
dis[s] = 0;
|
||||
|
@ -201,16 +196,15 @@ Bellman–Ford 算法所做的,就是不断尝试对图上每一条边进行
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
class Edge:
|
||||
def __init__(self, v = 0, w = 0):
|
||||
self.v = v
|
||||
self.w = w
|
||||
|
||||
|
||||
e = [[Edge() for i in range(maxn)] for j in range(maxn)]
|
||||
dis = [0x3f3f3f3f] * maxn
|
||||
|
||||
|
||||
def bellmanford(n, s):
|
||||
dis[s] = 0
|
||||
for i in range(1, n + 1):
|
||||
|
@ -241,16 +235,15 @@ SPFA 也可以用于判断 $s$ 点是否能抵达一个负环,只需记录最
|
|||
|
||||
??? note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
struct edge {
|
||||
int v, w;
|
||||
};
|
||||
|
||||
|
||||
vector<edge> e[maxn];
|
||||
int dis[maxn], cnt[maxn], vis[maxn];
|
||||
queue<int> q;
|
||||
|
||||
|
||||
bool spfa(int n, int s) {
|
||||
memset(dis, 63, sizeof(dis));
|
||||
dis[s] = 0, vis[s] = 1;
|
||||
|
@ -275,17 +268,16 @@ SPFA 也可以用于判断 $s$ 点是否能抵达一个负环,只需记录最
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
from collections import deque
|
||||
class Edge:
|
||||
def __init__(self, v = 0, w = 0):
|
||||
self.v = v
|
||||
self.w = w
|
||||
|
||||
|
||||
e = [[Edge() for i in range(maxn)] for j in range(maxn)]
|
||||
dis = [0x3f3f3f3f] * maxn; cnt = [0] * maxn; vis = [False] * maxn
|
||||
|
||||
|
||||
q = deque()
|
||||
def spfa(n, s):
|
||||
dis[s] = 0
|
||||
|
@ -377,15 +369,14 @@ Dijkstra(/ˈdikstrɑ/或/ˈdɛikstrɑ/)算法由荷兰计算机科学家 E.
|
|||
|
||||
???+ note "暴力实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
struct edge {
|
||||
int v, w;
|
||||
};
|
||||
|
||||
|
||||
vector<edge> e[maxn];
|
||||
int dis[maxn], vis[maxn];
|
||||
|
||||
|
||||
void dijkstra(int n, int s) {
|
||||
memset(dis, 63, sizeof(dis));
|
||||
dis[s] = 0;
|
||||
|
@ -403,7 +394,6 @@ Dijkstra(/ˈdikstrɑ/或/ˈdɛikstrɑ/)算法由荷兰计算机科学家 E.
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
class Edge:
|
||||
def __init(self, v = 0, w = 0):
|
||||
|
@ -429,22 +419,21 @@ Dijkstra(/ˈdikstrɑ/或/ˈdɛikstrɑ/)算法由荷兰计算机科学家 E.
|
|||
|
||||
???+ note "优先队列实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
struct edge {
|
||||
int v, w;
|
||||
};
|
||||
|
||||
|
||||
struct node {
|
||||
int dis, u;
|
||||
|
||||
|
||||
bool operator>(const node& a) const { return dis > a.dis; }
|
||||
};
|
||||
|
||||
|
||||
vector<edge> e[maxn];
|
||||
int dis[maxn], vis[maxn];
|
||||
priority_queue<node, vector<node>, greater<node> > q;
|
||||
|
||||
|
||||
void dijkstra(int n, int s) {
|
||||
memset(dis, 63, sizeof(dis));
|
||||
dis[s] = 0;
|
||||
|
@ -466,7 +455,6 @@ Dijkstra(/ˈdikstrɑ/或/ˈdɛikstrɑ/)算法由荷兰计算机科学家 E.
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def dijkstra(e,s):
|
||||
'''
|
||||
|
|
|
@ -164,33 +164,32 @@ bool toposort() {
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
using Graph = vector<vector<int>>; // 邻接表
|
||||
|
||||
|
||||
struct TopoSort {
|
||||
enum class Status : uint8_t { to_visit, visiting, visited };
|
||||
|
||||
|
||||
const Graph& graph;
|
||||
const int n;
|
||||
vector<Status> status;
|
||||
vector<int> order;
|
||||
vector<int>::reverse_iterator it;
|
||||
|
||||
|
||||
TopoSort(const Graph& graph)
|
||||
: graph(graph),
|
||||
n(graph.size()),
|
||||
status(n, Status::to_visit),
|
||||
order(n),
|
||||
it(order.rbegin()) {}
|
||||
|
||||
|
||||
bool sort() {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (status[i] == Status::to_visit && !dfs(i)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool dfs(const int u) {
|
||||
status[u] = Status::visiting;
|
||||
for (const int v : graph[u]) {
|
||||
|
@ -205,22 +204,21 @@ bool toposort() {
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
from enum import Enum, auto
|
||||
|
||||
|
||||
|
||||
|
||||
class Status(Enum):
|
||||
to_visit = auto()
|
||||
visiting = auto()
|
||||
visited = auto()
|
||||
|
||||
|
||||
|
||||
|
||||
def topo_sort(graph: list[list[int]]) -> list[int] | None:
|
||||
n = len(graph)
|
||||
status = [Status.to_visit] * n
|
||||
order = []
|
||||
|
||||
|
||||
def dfs(u: int) -> bool:
|
||||
status[u] = Status.visiting
|
||||
for v in graph[u]:
|
||||
|
@ -231,11 +229,11 @@ bool toposort() {
|
|||
status[u] = Status.visited
|
||||
order.append(u)
|
||||
return True
|
||||
|
||||
|
||||
for i in range(n):
|
||||
if status[i] == Status.to_visit and not dfs(i):
|
||||
return None
|
||||
|
||||
|
||||
return order[::-1]
|
||||
```
|
||||
|
||||
|
|
|
@ -755,7 +755,6 @@ def fib(n):
|
|||
### 声明常量
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
@ -763,13 +762,12 @@ def fib(n):
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
try: # 引入优先队列模块
|
||||
import Queue as pq #python version < 3.0
|
||||
except ImportError:
|
||||
import queue as pq #python3.*
|
||||
|
||||
|
||||
N = int(1e5 + 5)
|
||||
M = int(2e5 + 5)
|
||||
INF = 0x3f3f3f3f
|
||||
|
@ -778,38 +776,36 @@ def fib(n):
|
|||
### 声明前向星结构体和其它变量
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
struct qxx {
|
||||
int nex, t, v;
|
||||
};
|
||||
|
||||
|
||||
qxx e[M];
|
||||
int h[N], cnt;
|
||||
|
||||
|
||||
void add_path(int f, int t, int v) { e[++cnt] = (qxx){h[f], t, v}, h[f] = cnt; }
|
||||
|
||||
|
||||
typedef pair<int, int> pii;
|
||||
priority_queue<pii, vector<pii>, greater<pii>> q;
|
||||
int dist[N];
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
class qxx: # 前向星类(结构体)
|
||||
def __init__(self):
|
||||
self.nex = 0
|
||||
self.t = 0
|
||||
self.v = 0
|
||||
|
||||
|
||||
e = [qxx() for i in range(M)] # 链表
|
||||
h = [0 for i in range(N)]
|
||||
cnt = 0
|
||||
|
||||
|
||||
dist = [INF for i in range(N)]
|
||||
q = pq.PriorityQueue() # 定义优先队列,默认第一元小根堆
|
||||
|
||||
|
||||
def add_path(f, t, v): # 在前向星中加边
|
||||
# 如果要修改全局变量,要使用 global 来声明
|
||||
global cnt, e, h
|
||||
|
@ -825,7 +821,6 @@ def fib(n):
|
|||
### Dijkstra 算法
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void dijkstra(int s) {
|
||||
memset(dist, 0x3f, sizeof(dist));
|
||||
|
@ -845,15 +840,14 @@ def fib(n):
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def nextedgeid(u): # 生成器,可以用在 for 循环里
|
||||
i = h[u]
|
||||
while i:
|
||||
yield i
|
||||
i = e[i].nex
|
||||
|
||||
|
||||
|
||||
|
||||
def dijkstra(s):
|
||||
dist[s] = 0
|
||||
q.put((0, s))
|
||||
|
@ -873,10 +867,9 @@ def fib(n):
|
|||
### 主函数
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int n, m, s;
|
||||
|
||||
|
||||
int main() {
|
||||
scanf("%d%d%d", &n, &m, &s);
|
||||
for (int i = 1; i <= m; i++) {
|
||||
|
@ -891,7 +884,6 @@ def fib(n):
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
if __name__ == '__main__':
|
||||
# 一行读入多个整数。注意它会把整行都读进来
|
||||
|
@ -899,37 +891,36 @@ def fib(n):
|
|||
for i in range(m):
|
||||
u, v, w = map(int, input().split())
|
||||
add_path(u, v, w)
|
||||
|
||||
|
||||
dijkstra(s)
|
||||
|
||||
|
||||
for i in range(1, n + 1):
|
||||
print(dist[i], end = ' ')
|
||||
|
||||
|
||||
print()
|
||||
```
|
||||
|
||||
### 完整代码
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
const int N = 1e5 + 5, M = 2e5 + 5;
|
||||
|
||||
|
||||
struct qxx {
|
||||
int nex, t, v;
|
||||
};
|
||||
|
||||
|
||||
qxx e[M];
|
||||
int h[N], cnt;
|
||||
|
||||
|
||||
void add_path(int f, int t, int v) { e[++cnt] = (qxx){h[f], t, v}, h[f] = cnt; }
|
||||
|
||||
|
||||
typedef pair<int, int> pii;
|
||||
priority_queue<pii, vector<pii>, greater<pii>> q;
|
||||
int dist[N];
|
||||
|
||||
|
||||
void dijkstra(int s) {
|
||||
memset(dist, 0x3f, sizeof(dist));
|
||||
dist[s] = 0, q.push(make_pair(0, s));
|
||||
|
@ -945,9 +936,9 @@ def fib(n):
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int n, m, s;
|
||||
|
||||
|
||||
int main() {
|
||||
scanf("%d%d%d", &n, &m, &s);
|
||||
for (int i = 1; i <= m; i++) {
|
||||
|
@ -962,30 +953,29 @@ def fib(n):
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
try: # 引入优先队列模块
|
||||
import Queue as pq # python version < 3.0
|
||||
except ImportError:
|
||||
import queue as pq # python3.*
|
||||
|
||||
|
||||
N = int(1e5+5)
|
||||
M = int(2e5+5)
|
||||
INF = 0x3f3f3f3f
|
||||
|
||||
|
||||
class qxx: # 前向星类(结构体)
|
||||
def __init__(self):
|
||||
self.nex = 0
|
||||
self.t = 0
|
||||
self.v = 0
|
||||
|
||||
|
||||
e = [qxx() for i in range(M)] # 链表
|
||||
h = [0 for i in range(N)]
|
||||
cnt = 0
|
||||
|
||||
|
||||
dist = [INF for i in range(N)]
|
||||
q = pq.PriorityQueue() # 定义优先队列,默认第一元小根堆
|
||||
|
||||
|
||||
def add_path(f, t, v): # 在前向星中加边
|
||||
# 如果要修改全局变量,要使用 global 来声名
|
||||
global cnt, e, h
|
||||
|
@ -996,13 +986,13 @@ def fib(n):
|
|||
e[cnt].t = t
|
||||
e[cnt].v = v
|
||||
h[f] = cnt
|
||||
|
||||
|
||||
def nextedgeid(u): # 生成器,可以用在 for 循环里
|
||||
i = h[u]
|
||||
while i:
|
||||
yield i
|
||||
i = e[i].nex
|
||||
|
||||
|
||||
def dijkstra(s):
|
||||
dist[s] = 0
|
||||
q.put((0, s))
|
||||
|
@ -1017,8 +1007,8 @@ def fib(n):
|
|||
continue
|
||||
dist[v] = dist[u[1]]+w
|
||||
q.put((dist[v], v))
|
||||
|
||||
|
||||
|
||||
|
||||
# 如果你直接运行这个python代码(不是模块调用什么的)就执行命令
|
||||
if __name__ == '__main__':
|
||||
# 一行读入多个整数。注意它会把整行都读进来
|
||||
|
@ -1026,14 +1016,14 @@ def fib(n):
|
|||
for i in range(m):
|
||||
u, v, w = map(int, input().split())
|
||||
add_path(u, v, w)
|
||||
|
||||
|
||||
dijkstra(s)
|
||||
|
||||
|
||||
for i in range(1, n + 1):
|
||||
# 两种输出语法都是可以用的
|
||||
print("{}".format(dist[i]), end=' ')
|
||||
# print("%d" % dist[i],end=' ')
|
||||
|
||||
|
||||
print() # 结尾换行
|
||||
```
|
||||
|
||||
|
|
|
@ -61,7 +61,6 @@ $$
|
|||
首先我们可以直接按照上述递归方法实现:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
long long binpow(long long a, long long b) {
|
||||
if (b == 0) return 1;
|
||||
|
@ -74,7 +73,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def binpow(a, b):
|
||||
if b == 0:
|
||||
|
@ -89,7 +87,6 @@ $$
|
|||
第二种实现方法是非递归式的。它在循环的过程中将二进制位为 1 时对应的幂累乘到答案中。尽管两者的理论复杂度是相同的,但第二种在实践过程中的速度是比第一种更快的,因为递归会花费一定的开销。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
long long binpow(long long a, long long b) {
|
||||
long long res = 1;
|
||||
|
@ -103,7 +100,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def binpow(a, b):
|
||||
res = 1
|
||||
|
@ -129,7 +125,6 @@ $$
|
|||
既然我们知道取模的运算不会干涉乘法运算,因此我们只需要在计算的过程中取模即可。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
long long binpow(long long a, long long b, long long m) {
|
||||
a %= m;
|
||||
|
@ -144,7 +139,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def binpow(a, b, m):
|
||||
a = a % m
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
一个数对 $2$ 的非负整数次幂取模,等价于取二进制下一个数的后若干位,等价于和 $mod-1$ 进行与操作。
|
||||
|
||||
=== "C++"
|
||||
|
||||
|
||||
```cpp
|
||||
int modPowerOfTwo(int x, int mod) { return x & (mod - 1); }
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
```python
|
||||
def modPowerOfTwo(x, mod):
|
||||
return x & (mod - 1)
|
||||
|
@ -36,13 +36,13 @@
|
|||
借此可以判断一个数是不是 $2$ 的非负整数次幂。当且仅当 $n$ 的二进制表示只有一个 $1$ 时,$n$ 为 $2$ 的非负整数次幂。
|
||||
|
||||
=== "C++"
|
||||
|
||||
|
||||
```cpp
|
||||
bool isPowerOfTwo(int n) { return n > 0 && (n & (n - 1)) == 0; }
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
```python
|
||||
def isPowerOfTwo(n):
|
||||
return n > 0 and (n & (n - 1)) == 0
|
||||
|
|
|
@ -105,7 +105,7 @@ $$
|
|||
将一个数乘(除) 2 的非负整数次幂:
|
||||
|
||||
=== "C++"
|
||||
|
||||
|
||||
```cpp
|
||||
int mulPowerOfTwo(int n, int m) { // 计算 n*(2^m)
|
||||
return n << m;
|
||||
|
@ -116,7 +116,7 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
```python
|
||||
def mulPowerOfTwo(n, m): # 计算 n*(2^m)
|
||||
return n << m
|
||||
|
@ -132,7 +132,7 @@ $$
|
|||
在某些机器上,效率比 `n > 0 ? n : -n` 高。
|
||||
|
||||
=== "C++"
|
||||
|
||||
|
||||
```cpp
|
||||
int Abs(int n) {
|
||||
return (n ^ (n >> 31)) - (n >> 31);
|
||||
|
@ -144,7 +144,7 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
```python
|
||||
def Abs(n):
|
||||
return (n ^ (n >> 31)) - (n >> 31)
|
||||
|
@ -154,7 +154,7 @@ $$
|
|||
需要计算 n 和 -1 的补码,然后进行异或运算,
|
||||
结果 n 变号并且为 n 的绝对值减 1,再减去 -1 就是绝对值
|
||||
"""
|
||||
|
||||
|
||||
```
|
||||
|
||||
### 取两个数的最大/最小值
|
||||
|
@ -162,7 +162,7 @@ $$
|
|||
在某些机器上,效率比 `a > b ? a : b` 高。
|
||||
|
||||
=== "C++"
|
||||
|
||||
|
||||
```cpp
|
||||
// 如果 a >= b, (a - b) >> 31 为 0,否则为 -1
|
||||
int max(int a, int b) { return (b & ((a - b) >> 31)) | (a & (~(a - b) >> 31)); }
|
||||
|
@ -170,7 +170,7 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
```python
|
||||
# 如果 a >= b, (a - b) >> 31 为 0,否则为 -1
|
||||
def max(a, b):
|
||||
|
@ -182,7 +182,7 @@ $$
|
|||
### 判断两非零数符号是否相同
|
||||
|
||||
=== "C++"
|
||||
|
||||
|
||||
```cpp
|
||||
bool isSameSign(int x, int y) { // 有 0 的情况例外
|
||||
return (x ^ y) >= 0;
|
||||
|
@ -190,7 +190,7 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
```python
|
||||
# 有 0 的情况例外
|
||||
def isSameSign(x, y):
|
||||
|
@ -213,14 +213,14 @@ void swap(int &a, int &b) { a ^= b ^= a ^= b; }
|
|||
获取一个数二进制的某一位:
|
||||
|
||||
=== "C++"
|
||||
|
||||
|
||||
```cpp
|
||||
// 获取 a 的第 b 位,最低位编号为 0
|
||||
int getBit(int a, int b) { return (a >> b) & 1; }
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
```python
|
||||
# 获取 a 的第 b 位,最低位编号为 0
|
||||
def getBit(a, b):
|
||||
|
@ -230,14 +230,14 @@ void swap(int &a, int &b) { a ^= b ^= a ^= b; }
|
|||
将一个数二进制的某一位设置为 $0$:
|
||||
|
||||
=== "C++"
|
||||
|
||||
|
||||
```cpp
|
||||
// 将 a 的第 b 位设置为 0 ,最低位编号为 0
|
||||
int unsetBit(int a, int b) { return a & ~(1 << b); }
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
```python
|
||||
# 将 a 的第 b 位设置为 0 ,最低位编号为 0
|
||||
def unsetBit(a, b):
|
||||
|
@ -247,14 +247,14 @@ void swap(int &a, int &b) { a ^= b ^= a ^= b; }
|
|||
将一个数二进制的某一位设置为 $1$:
|
||||
|
||||
=== "C++"
|
||||
|
||||
|
||||
```cpp
|
||||
// 将 a 的第 b 位设置为 1 ,最低位编号为 0
|
||||
int setBit(int a, int b) { return a | (1 << b); }
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
```python
|
||||
# 将 a 的第 b 位设置为 1 ,最低位编号为 0
|
||||
def setBit(a, b):
|
||||
|
@ -264,14 +264,14 @@ void swap(int &a, int &b) { a ^= b ^= a ^= b; }
|
|||
将一个数二进制的某一位取反:
|
||||
|
||||
=== "C++"
|
||||
|
||||
|
||||
```cpp
|
||||
// 将 a 的第 b 位取反 ,最低位编号为 0
|
||||
int flapBit(int a, int b) { return a ^ (1 << b); }
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
```python
|
||||
# 将 a 的第 b 位取反 ,最低位编号为 0
|
||||
def flapBit(a, b):
|
||||
|
|
|
@ -73,11 +73,10 @@ $$
|
|||
|
||||
??? note "参考实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
const int maxn = 2000 + 5;
|
||||
int bell[maxn][maxn];
|
||||
|
||||
|
||||
void f(int n) {
|
||||
bell[0][0] = 1;
|
||||
for (int i = 1; i <= n; i++) {
|
||||
|
@ -89,7 +88,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
maxn = 2000 + 5
|
||||
bell = [[0 for i in range(maxn + 1)] for j in range(maxn + 1)]
|
||||
|
|
|
@ -47,13 +47,12 @@ $$
|
|||
题目大意:入栈顺序为 $1,2,\ldots ,n$,求所有可能的出栈顺序的总数。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
int n;
|
||||
long long f[25];
|
||||
|
||||
|
||||
int main() {
|
||||
f[0] = 1;
|
||||
cin >> n;
|
||||
|
@ -65,7 +64,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
f = [0] * 25
|
||||
f[0] = 1
|
||||
|
|
|
@ -69,7 +69,6 @@ $$
|
|||
## 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int eulerianNumber(int n, int m) {
|
||||
if (m >= n || n == 0) return 0;
|
||||
|
@ -80,7 +79,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def eulerianNumber(n, m):
|
||||
if m >= n or n == 0:
|
||||
|
|
|
@ -184,20 +184,18 @@ $$
|
|||
由此,$\frac{p_k}{q_k} = [a_0; a_1, \dots, a_k]$ 的 $\gcd(p_k, q_k) = 1$。因此,渐进分数总是不可约的。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
auto fraction(int p, int q) {
|
||||
vector<int> a;
|
||||
while(q) {
|
||||
a.push_back(p / q);
|
||||
tie(p, q) = make_pair(q, p % q);
|
||||
}
|
||||
return a;
|
||||
vector<int> a;
|
||||
while (q) {
|
||||
a.push_back(p / q);
|
||||
tie(p, q) = make_pair(q, p % q);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```py
|
||||
def fraction(p, q):
|
||||
a = []
|
||||
|
@ -449,21 +447,19 @@ $$
|
|||
把渐进分数计算为一对序列 $p_{-2}, p_{-1}, p_0, p_1, \dots, p_k$ 和 $q_{-2}, q_{-1}, q_0, q_1, \dots, q_k$:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
auto convergents(vector<int> a) {
|
||||
vector<int> p = {0, 1};
|
||||
vector<int> q = {1, 0};
|
||||
for(auto it: a) {
|
||||
p.push_back(p[p.size() - 1] * it + p[p.size() - 2]);
|
||||
q.push_back(q[q.size() - 1] * it + q[q.size() - 2]);
|
||||
}
|
||||
return make_pair(p, q);
|
||||
vector<int> p = {0, 1};
|
||||
vector<int> q = {1, 0};
|
||||
for (auto it : a) {
|
||||
p.push_back(p[p.size() - 1] * it + p[p.size() - 2]);
|
||||
q.push_back(q[q.size() - 1] * it + q[q.size() - 2]);
|
||||
}
|
||||
return make_pair(p, q);
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```py
|
||||
def convergents(a):
|
||||
p = [0, 1]
|
||||
|
@ -622,8 +618,8 @@ $$
|
|||
$$
|
||||
|
||||
其中 $g = \gcd(A, B)$。如果 $C$ 可被 $g$ 整除,则解为 $x = (-1)^{k-1}\frac{C}{g} q_{k-1}$ 和 $y = (-1)^{k}\frac{C}{g} p_{k-1}$。
|
||||
=== "Python"
|
||||
|
||||
=== "Python"
|
||||
```py
|
||||
# return (x, y) such that Ax+By=C
|
||||
# assumes that such (x, y) exists
|
||||
|
@ -770,18 +766,20 @@ $$
|
|||
并且 $t < a_i$ 成立,因为已经耗尽了从 $i+2$ 获得的半收敛,因此 $x + q_{i-1} + a_i q_i = x+q_{i+1}$ 大于 $N$。
|
||||
|
||||
现在,可以将 $(\Delta x; \Delta y)$ 添加到 $(x;y)$ 中 $k = \lfloor \frac{N-x}{\Delta x} \rfloor$ 次,然后再超过 $N$,之后将尝试下一个中间分数。
|
||||
=== "C++"
|
||||
|
||||
=== "C++"
|
||||
```cpp
|
||||
// returns [ah, ph, qh] such that points r[i]=(ph[i], qh[i]) constitute upper convex hull
|
||||
// of lattice points on 0 <= x <= N and 0 <= y <= r * x, where r = [a0; a1, a2, ...]
|
||||
// and there are ah[i]-1 integer points on the segment between r[i] and r[i+1]
|
||||
// returns [ah, ph, qh] such that points r[i]=(ph[i], qh[i]) constitute upper
|
||||
// convex hull of lattice points on 0 <= x <= N and 0 <= y <= r * x, where r =
|
||||
// [a0; a1, a2, ...] and there are ah[i]-1 integer points on the segment between
|
||||
// r[i] and r[i+1]
|
||||
auto hull(auto a, int N) {
|
||||
auto [p, q] = convergents(a);
|
||||
int t = N / q.back();
|
||||
vector ah = {t};
|
||||
vector ph = {0, t*p.back()};
|
||||
vector qh = {0, t*q.back()};
|
||||
auto [p, q] = convergents(a);
|
||||
int t = N / q.back();
|
||||
vector ah = {t};
|
||||
vector ph = {0, t * p.back()};
|
||||
vector qh = {0, t * q.back()};
|
||||
```
|
||||
|
||||
for(int i = q.size() - 1; i >= 0; i--) {
|
||||
if(i % 2) {
|
||||
|
@ -801,7 +799,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```py
|
||||
# returns [ah, ph, qh] such that points r[i]=(ph[i], qh[i]) constitute upper convex hull
|
||||
# of lattice points on 0 <= x <= N and 0 <= y <= r * x, where r = [a0; a1, a2, ...]
|
||||
|
@ -837,8 +834,8 @@ $$
|
|||
为了更一般地对待它,编写一个函数,该函数在 $0 \leq x \leq N$ 和 $y = \lfloor \frac{Ax+B}{C} \rfloor$ 上找到最佳点。
|
||||
|
||||
这个问题的核心解决方案思想基本上重复了前面的问题,但不是使用下中间分数来偏离直线,而是使用上中间分数来接近直线,而不跨越直线,也不违反 $x \leq N$。不幸的是,与前一个问题不同,您需要确保在靠近 $y=\frac{Ax+B}{C}$ 线时不会越过该线,因此在计算中间分数的系数 $t$ 时应牢记这一点。
|
||||
=== "Python"
|
||||
|
||||
=== "Python"
|
||||
```py
|
||||
# (x, y) such that y = (A*x+B) // C,
|
||||
# Cy - Ax is max and 0 <= x <= N.
|
||||
|
@ -864,6 +861,7 @@ $$
|
|||
qh.append(qh[-1] + k*dq)
|
||||
ph.append(ph[-1] + k*dp)
|
||||
return qh[-1], ph[-1]
|
||||
```
|
||||
|
||||
def solve(A, B, N):
|
||||
x, y = closest(A, N % A, B, N // A)
|
||||
|
@ -878,13 +876,14 @@ $$
|
|||
此和等于格点 $(x;y)$ 的数量,使得 $1 \leq x \leq N$ 和 $1 \leq y \leq \mathrm{e}x$。
|
||||
|
||||
在构造了 $y=\mathrm{e}x$ 以下的点的凸包之后,可以使用 Pick 定理计算这个数:
|
||||
=== "C++"
|
||||
|
||||
=== "C++"
|
||||
```cpp
|
||||
// sum floor(k * x) for k in [1, N] and x = [a0; a1, a2, ...]
|
||||
int sum_floor(auto a, int N) {
|
||||
N++;
|
||||
auto [ah, ph, qh] = hull(a, N);
|
||||
N++;
|
||||
auto [ah, ph, qh] = hull(a, N);
|
||||
```
|
||||
|
||||
// The number of lattice points within a vertical right trapezoid
|
||||
// on points (0; 0) - (0; y1) - (dx; y2) - (dx; 0) that has
|
||||
|
@ -904,12 +903,12 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```py
|
||||
# sum floor(k * x) for k in [1, N] and x = [a0; a1, a2, ...]
|
||||
def sum_floor(a, N):
|
||||
N += 1
|
||||
ah, ph, qh = hull(a, N)
|
||||
```
|
||||
|
||||
# The number of lattice points within a vertical right trapezoid
|
||||
# on points (0; 0) - (0; y1) - (dx; y2) - (dx; 0) that has
|
||||
|
@ -937,20 +936,19 @@ $$
|
|||
$$
|
||||
|
||||
然而,将 $x$ 从 $1$ 到 $N$ 的 $\lfloor rx \rfloor$ 相加,是我们能够从上一个问题中得出的结果。
|
||||
=== "C++"
|
||||
|
||||
=== "C++"
|
||||
```cpp
|
||||
void solve(int p, int q, int N) {
|
||||
cout << p * N * (N + 1) / 2 - q * sum_floor(fraction(p, q), N) << "\n";
|
||||
cout << p * N * (N + 1) / 2 - q * sum_floor(fraction(p, q), N) << "\n";
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```py
|
||||
def solve(p, q, N):
|
||||
return p * N * (N + 1) // 2 - q * sum_floor(fraction(p, q), N)
|
||||
```
|
||||
```
|
||||
|
||||
### [Library Checker - Sum of Floor of Linear](https://judge.yosupo.jp/problem/sum_of_floor_of_linear)
|
||||
|
||||
|
@ -966,8 +964,8 @@ $$
|
|||
现在应该注意到,一旦到达了离直线最近的点,就可以假设直线实际上通过了最近的点。因为在实际直线和稍微向下移动以通过最近点的直线之间,$[0, N-1]$ 上没有其他格点。
|
||||
|
||||
也就是说,要在 $[0, N-1]$ 上的线 $y=\frac{Ax+B}{M}$ 下方构造全凸包,可以将其构造到与 $[0, N-1]$ 的线最近的点,然后继续,就像该线通过该点一样,重用用于构造 $B=0$ 的凸包的算法:
|
||||
=== "Python"
|
||||
|
||||
=== "Python"
|
||||
```py
|
||||
# hull of lattice (x, y) such that C*y <= A*x+B
|
||||
def hull(A, B, C, N):
|
||||
|
@ -978,6 +976,7 @@ $$
|
|||
ah = []
|
||||
ph = [B // C]
|
||||
qh = [0]
|
||||
```
|
||||
|
||||
def insert(dq, dp):
|
||||
k = (N - qh[-1]) // dq
|
||||
|
@ -1031,8 +1030,8 @@ $$
|
|||
由于 $m$ 是常量,可以除以它,并进一步将其重新表述为求解 $q$,这样 $1 \leq q \leq 10^9$ 和 $\frac{r}{m} q - k \geq 0$ 是可能的最小值。
|
||||
|
||||
就连分数而言,这意味着 $\frac{k}{q}$ 是 $\frac{r}{m}$ 的最佳丢番图近似值,并且仅检查 $\frac{r}{m}$ 的下中间分数就足够了。
|
||||
=== "Python"
|
||||
|
||||
=== "Python"
|
||||
```py
|
||||
# find Q that minimizes Q*r mod m for 1 <= k <= n < m
|
||||
def mod_min(r, n, m):
|
||||
|
|
|
@ -37,7 +37,6 @@ $$
|
|||
## 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
LL CRT(int k, LL* a, LL* r) {
|
||||
LL n = 1, ans = 0;
|
||||
|
@ -52,7 +51,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def CRT(k, a, r):
|
||||
n = 1; ans = 0
|
||||
|
@ -157,7 +155,6 @@ $$
|
|||
|
||||
??? note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (int i = 0; i < k; ++i) {
|
||||
x[i] = a[i];
|
||||
|
@ -170,7 +167,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for i in range(0, k):
|
||||
x[i] = a[i]
|
||||
|
|
|
@ -115,30 +115,27 @@ $$
|
|||
求 $S_1(n)= \sum_{i=1}^{n} \mu(i)$ 和 $S_2(n)= \sum_{i=1}^{n} \varphi(i)$ 的值,$1\leq n<2^{31}$.
|
||||
|
||||
=== "莫比乌斯函数前缀和"
|
||||
|
||||
我们知道:
|
||||
|
||||
|
||||
$$
|
||||
\epsilon = [n=1] = \mu * 1 = \sum_{d \mid n} \mu(d)
|
||||
$$
|
||||
|
||||
|
||||
$$
|
||||
\begin{aligned}
|
||||
S_1(n) & =\sum_{i=1}^n \epsilon (i)-\sum_{i=2}^n S_1 \left(\left\lfloor \frac n i \right\rfloor\right) \\
|
||||
& = 1-\sum_{i=2}^n S_1\left(\left\lfloor \frac n i \right\rfloor\right)
|
||||
\end{aligned}
|
||||
$$
|
||||
|
||||
|
||||
时间复杂度的推导见 [时间复杂度](#时间复杂度) 一节。
|
||||
|
||||
对于较大的值,需要用 `map` / `unordered_map` 存下其对应的值,方便以后使用时直接使用之前计算的结果。
|
||||
|
||||
对于较大的值,需要用 `map`/`unordered_map` 存下其对应的值,方便以后使用时直接使用之前计算的结果。
|
||||
|
||||
=== "欧拉函数前缀和"
|
||||
|
||||
当然也可以用杜教筛求出 $\varphi (x)$ 的前缀和,但是更好的方法是应用莫比乌斯反演。
|
||||
|
||||
|
||||
=== "莫比乌斯反演"
|
||||
|
||||
$$
|
||||
\begin{aligned}
|
||||
\sum_{i=1}^n \sum_{j=1}^n [\gcd(i,j)=1] & =\sum_{i=1}^n \sum_{j=1}^n \sum_{d \mid i,d \mid j} \mu(d) \\
|
||||
|
@ -149,13 +146,13 @@ $$
|
|||
由于题目所求的是 $\sum_{i=1}^n \sum_{j=1}^i [\gcd(i,j)=1]$, 所以我们排除掉 $i=1,j=1$ 的情况,并将结果除以 $2$ 即可。
|
||||
|
||||
观察到,只需求出莫比乌斯函数的前缀和,就可以快速计算出欧拉函数的前缀和了。时间复杂度 $O\left(n^{\frac 2 3}\right)$.
|
||||
|
||||
=== "杜教筛"
|
||||
|
||||
|
||||
== "杜教筛"
|
||||
|
||||
求 $S(n)=\sum_{i=1}^n\varphi(i)$.
|
||||
|
||||
|
||||
同样的,$\varphi * 1=\operatorname{id}$, 从而:
|
||||
|
||||
|
||||
$$
|
||||
\begin{aligned}
|
||||
S(n) & =\sum_{i=1}^n i - \sum_{i=2}^n S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) \\
|
||||
|
|
|
@ -54,9 +54,9 @@ author: iamtwz, Chrogeek, Enter-tainer, StudyingFather, aofall, CCXXXI, Coelacan
|
|||
如果只要求一个数的欧拉函数值,那么直接根据定义质因数分解的同时求就好了。这个过程可以用 [Pollard Rho](./pollard-rho.md) 算法优化。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
#include <cmath>
|
||||
|
||||
int euler_phi(int n) {
|
||||
int m = int(sqrt(n + 0.5));
|
||||
int ans = n;
|
||||
|
@ -71,7 +71,6 @@ author: iamtwz, Chrogeek, Enter-tainer, StudyingFather, aofall, CCXXXI, Coelacan
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
import math
|
||||
def euler_phi(n):
|
||||
|
@ -90,9 +89,9 @@ author: iamtwz, Chrogeek, Enter-tainer, StudyingFather, aofall, CCXXXI, Coelacan
|
|||
注:如果将上面的程序改成如下形式,会提升一点效率:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
#include <cmath>
|
||||
|
||||
int euler_phi(int n) {
|
||||
int ans = n;
|
||||
for (int i = 2; i * i <= n; i++)
|
||||
|
@ -106,7 +105,6 @@ author: iamtwz, Chrogeek, Enter-tainer, StudyingFather, aofall, CCXXXI, Coelacan
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
import math
|
||||
def euler_phi(n):
|
||||
|
|
|
@ -41,27 +41,25 @@
|
|||
#### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// Version 1
|
||||
int gcd(int a, int b) {
|
||||
if (b == 0) return a;
|
||||
return gcd(b, a % b);
|
||||
}
|
||||
|
||||
|
||||
// Version 2
|
||||
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java
|
||||
// Version 1
|
||||
public int gcd(int a, int b) {
|
||||
if (b == 0) return a;
|
||||
return gcd(b, a % b);
|
||||
}
|
||||
|
||||
|
||||
// Version 2
|
||||
public int gcd(int a, int b) {
|
||||
return b == 0 ? a : gcd(b, a % b);
|
||||
|
@ -69,7 +67,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def gcd(a, b):
|
||||
if b == 0:
|
||||
|
@ -82,7 +79,6 @@
|
|||
根据上述递归求法,我们也可以写出一个迭代求法:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int gcd(int a, int b) {
|
||||
while (b != 0) {
|
||||
|
@ -95,7 +91,6 @@
|
|||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java
|
||||
public int gcd(int a, int b) {
|
||||
while(b != 0) {
|
||||
|
@ -108,7 +103,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def gcd(a, b):
|
||||
while b != 0:
|
||||
|
@ -269,7 +263,6 @@ $ax_1+by_1=ay_2+bx_2-\lfloor\frac{a}{b}\rfloor\times by_2=ay_2+b(x_2-\lfloor\fra
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int Exgcd(int a, int b, int &x, int &y) {
|
||||
if (!b) {
|
||||
|
@ -286,7 +279,6 @@ $ax_1+by_1=ay_2+bx_2-\lfloor\frac{a}{b}\rfloor\times by_2=ay_2+b(x_2-\lfloor\fra
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def Exgcd(a, b):
|
||||
if b == 0:
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void exgcd(int a, int b, int& x, int& y) {
|
||||
if (b == 0) {
|
||||
|
@ -23,7 +22,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def exgcd(a, b):
|
||||
if b == 0:
|
||||
|
@ -52,7 +50,6 @@
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int qpow(long long a, int b) {
|
||||
int ans = 1;
|
||||
|
@ -66,7 +63,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def qpow(a, b):
|
||||
ans = 1
|
||||
|
@ -117,7 +113,6 @@ $$
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
inv[1] = 1;
|
||||
for (int i = 2; i <= n; ++i) {
|
||||
|
@ -126,7 +121,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
inv[1] = 1
|
||||
for i in range(2, n + 1):
|
||||
|
@ -159,7 +153,6 @@ $$
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
s[0] = 1;
|
||||
for (int i = 1; i <= n; ++i) s[i] = s[i - 1] * a[i] % p;
|
||||
|
@ -170,7 +163,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
s[0] = 1
|
||||
for i in range(1, n + 1):
|
||||
|
|
|
@ -92,7 +92,6 @@ $$
|
|||
|
||||
???+ note "代码实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int ex_gcd(int a, int b, int& x, int& y) {
|
||||
if (b == 0) {
|
||||
|
@ -106,7 +105,7 @@ $$
|
|||
y = temp - a / b * y;
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
bool liEu(int a, int b, int c, int& x, int& y) {
|
||||
int d = ex_gcd(a, b, x, y);
|
||||
if (c % d != 0) return 0;
|
||||
|
@ -118,7 +117,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def ex_gcd(a, b ,x, y):
|
||||
if b == 0:
|
||||
|
@ -129,7 +127,7 @@ $$
|
|||
x = y
|
||||
y = temp - a // b * y
|
||||
return d
|
||||
|
||||
|
||||
def liEu(a, b, c, x, y):
|
||||
d = ex_gcd(a, b, x, y)
|
||||
if c % d != 0:
|
||||
|
|
|
@ -18,7 +18,6 @@ $$
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
long long Lucas(long long n, long long m, long long p) {
|
||||
if (m == 0) return 1;
|
||||
|
@ -27,7 +26,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def Lucas(n, m, p):
|
||||
if m == 0:
|
||||
|
|
|
@ -69,7 +69,6 @@ $$
|
|||
|
||||
???+ note "线性筛实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void getMu() {
|
||||
mu[1] = 1;
|
||||
|
@ -88,7 +87,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def getMu():
|
||||
mu[1] = 1
|
||||
|
|
|
@ -208,8 +208,8 @@ $$
|
|||
这种表示法的优点在于,如果将 $x_{k+1}, y_{k+1}, z_{k+1}$ 减去它们的最大公约数,结果将是唯一的。因此,可以使用它来检查当前状态是否已经重复,以及检查具有此状态的上一个索引的位置。
|
||||
|
||||
下面是计算 $\alpha = \sqrt n$ 的连分数表示的代码:
|
||||
=== "Python"
|
||||
|
||||
=== "Python"
|
||||
```py
|
||||
# compute the continued fraction of sqrt(n)
|
||||
def sqrt(n):
|
||||
|
@ -222,7 +222,7 @@ $$
|
|||
x, y, z = z*t, -z*y, t**2 - n*x**2
|
||||
g = math.gcd(x, math.gcd(y, z))
|
||||
return x // g, y // g, z // g
|
||||
|
||||
|
||||
used = dict()
|
||||
for i in range(n):
|
||||
used[x, y, z] = i
|
||||
|
@ -375,36 +375,36 @@ $$
|
|||
|
||||
??? "解答"
|
||||
在计算完 $\sqrt x$ 的周期后,可以使用连分数表示引起的线性分数变换上的二进制幂来计算 $a_k$。要查找结果转换,请将大小为 $T$ 的周期压缩为单个转换,并将其重复 $\lfloor \frac{k-1}{T}\rfloor$ 次,然后手动将其与其余转换组合。
|
||||
=== "Python"
|
||||
|
||||
=== "Python"
|
||||
```py
|
||||
x, k = map(int, input().split())
|
||||
|
||||
|
||||
mod = 10**9+7
|
||||
|
||||
|
||||
# compose (A[0]*x + A[1]) / (A[2]*x + A[3]) and (B[0]*x + B[1]) / (B[2]*x + B[3])
|
||||
def combine(A, B):
|
||||
return [t % mod for t in [A[0]*B[0]+A[1]*B[2], A[0]*B[1]+A[1]*B[3], A[2]*B[0]+A[3]*B[2], A[2]*B[1]+A[3]*B[3]]]
|
||||
|
||||
|
||||
A = [1, 0, 0, 1] # (x + 0) / (0*x + 1) = x
|
||||
|
||||
|
||||
a = sqrt(x)
|
||||
|
||||
|
||||
T = len(a) - 1 # period of a
|
||||
|
||||
|
||||
# apply ak + 1/x = (ak*x+1)/(1x+0) to (Ax + B) / (Cx + D)
|
||||
for i in reversed(range(1, len(a))):
|
||||
A = combine([a[i], 1, 1, 0], A)
|
||||
|
||||
|
||||
def bpow(A, n):
|
||||
return [1, 0, 0, 1] if not n else combine(A, bpow(A, n-1)) if n % 2 else bpow(combine(A, A), n // 2)
|
||||
|
||||
|
||||
C = (0, 1, 0, 0) # = 1 / 0
|
||||
while k % T:
|
||||
i = k % T
|
||||
C = combine([a[i], 1, 1, 0], C)
|
||||
k -= 1
|
||||
|
||||
|
||||
C = combine(bpow(A, k // T), C)
|
||||
C = combine([a[0], 1, 1, 0], C)
|
||||
print(str(C[1]) + '/' + str(C[3]))
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
最简单的算法即为从 $[2, \sqrt N]$ 进行遍历。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> breakdown(int N) {
|
||||
vector<int> result;
|
||||
|
@ -29,7 +28,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def breakdown(N):
|
||||
result = []
|
||||
|
@ -158,7 +156,6 @@ $$
|
|||
|
||||
??? note "基于 Floyd 判环的 Pollard-Rho 算法"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
ll Pollard_Rho(ll N) {
|
||||
ll c = rand() % (N - 1) + 1;
|
||||
|
@ -175,7 +172,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
import random
|
||||
def Pollard_Rho(N):
|
||||
|
@ -201,7 +197,6 @@ $$
|
|||
|
||||
??? note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
ll Pollard_Rho(ll x) {
|
||||
ll t = 0;
|
||||
|
@ -229,7 +224,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
from random import randint
|
||||
from math import gcd
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
暴力做法自然可以枚举从小到大的每个数看是否能整除
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
bool isPrime(a) {
|
||||
if (a < 2) return 0;
|
||||
|
@ -22,7 +21,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def isPrime(a):
|
||||
if a < 2:
|
||||
|
@ -42,7 +40,6 @@
|
|||
由于 $1$ 肯定是约数,所以不检验它。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
bool isPrime(a) {
|
||||
if (a < 2) return 0;
|
||||
|
@ -53,7 +50,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def isPrime(a):
|
||||
if a < 2:
|
||||
|
@ -88,7 +84,6 @@
|
|||
##### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
bool millerRabin(int n) {
|
||||
if (n < 3) return n == 2;
|
||||
|
@ -103,7 +98,6 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def millerRabin(n):
|
||||
if n < 3:
|
||||
|
@ -248,7 +242,6 @@ Carmichael 数有如下性质:
|
|||
这样得到了较正确的 Miller Rabin:(来自 fjzzq2002)
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
bool millerRabin(int n) {
|
||||
if (n < 3 || n % 2 == 0) return n == 2;
|
||||
|
@ -261,7 +254,7 @@ Carmichael 数有如下性质:
|
|||
if (v == 1) continue;
|
||||
int s;
|
||||
for (s = 0; s < t; ++s) {
|
||||
if (v == n - 1) break; // 得到平凡平方根 n-1,通过此轮测试
|
||||
if (v == n - 1) break; // 得到平凡平方根 n-1,通过此轮测试
|
||||
v = (long long)v * v % n;
|
||||
}
|
||||
// 如果找到了非平凡平方根,则会由于无法提前 break; 而运行到 s == t
|
||||
|
@ -273,7 +266,6 @@ Carmichael 数有如下性质:
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def millerRabin(n):
|
||||
if n < 3 or n % 2 == 0:
|
||||
|
|
|
@ -19,9 +19,9 @@ author: inkydragon, TravorLZH, YOYO-UIAT, wood3, shuzhouliu, Mr-Python-in-China
|
|||
#### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
bool is_prime[N];
|
||||
|
||||
int Eratosthenes(int n) {
|
||||
int p = 0;
|
||||
for (int i = 0; i <= n; ++i) is_prime[i] = 1;
|
||||
|
@ -41,7 +41,6 @@ author: inkydragon, TravorLZH, YOYO-UIAT, wood3, shuzhouliu, Mr-Python-in-China
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def Eratosthenes(n):
|
||||
p = 0
|
||||
|
@ -99,9 +98,9 @@ author: inkydragon, TravorLZH, YOYO-UIAT, wood3, shuzhouliu, Mr-Python-in-China
|
|||
显然,要找到直到 $n$ 为止的所有素数,仅对不超过 $\sqrt n$ 的素数进行筛选就足够了。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
bool is_prime[N];
|
||||
|
||||
int Eratosthenes(int n) {
|
||||
int p = 0;
|
||||
for (int i = 0; i <= n; ++i) is_prime[i] = 1;
|
||||
|
@ -110,8 +109,7 @@ author: inkydragon, TravorLZH, YOYO-UIAT, wood3, shuzhouliu, Mr-Python-in-China
|
|||
for (int i = 2; i * i <= n; ++i) {
|
||||
if (is_prime[i]) {
|
||||
prime[p++] = i;
|
||||
for (int j = i * i; j <= n; j += i)
|
||||
is_prime[j] = 0;
|
||||
for (int j = i * i; j <= n; j += i) is_prime[j] = 0;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
|
@ -119,7 +117,6 @@ author: inkydragon, TravorLZH, YOYO-UIAT, wood3, shuzhouliu, Mr-Python-in-China
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def Eratosthenes(n):
|
||||
p = 0
|
||||
|
@ -212,7 +209,6 @@ author: inkydragon, TravorLZH, YOYO-UIAT, wood3, shuzhouliu, Mr-Python-in-China
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void init(int n) {
|
||||
for (int i = 2; i <= n; ++i) {
|
||||
|
@ -236,7 +232,6 @@ author: inkydragon, TravorLZH, YOYO-UIAT, wood3, shuzhouliu, Mr-Python-in-China
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def init(n):
|
||||
for i in range(2, n + 1):
|
||||
|
@ -291,7 +286,6 @@ $$
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void pre() {
|
||||
for (int i = 1; i <= 5000000; i++) {
|
||||
|
@ -319,7 +313,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def pre():
|
||||
cnt = 0
|
||||
|
@ -360,7 +353,6 @@ $$
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void pre() {
|
||||
mu[1] = 1;
|
||||
|
@ -380,7 +372,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def pre():
|
||||
mu[1] = 1
|
||||
|
@ -421,7 +412,6 @@ $$
|
|||
3. 当 $p,q$ 互质时,$\textit{num}_i \gets 1,\textit{d}_i \gets \textit{d}_q \times (\textit{num}_i+1)$。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void pre() {
|
||||
d[1] = 1;
|
||||
|
@ -443,7 +433,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def pre():
|
||||
d[1] = 1
|
||||
|
@ -470,7 +459,6 @@ $f_i$ 表示 $i$ 的约数和,$g_i$ 表示 $i$ 的最小质因子的 $p^0+p^1+
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void pre() {
|
||||
g[1] = f[1] = 1;
|
||||
|
@ -492,7 +480,6 @@ $f_i$ 表示 $i$ 的约数和,$g_i$ 表示 $i$ 的最小质因子的 $p^0+p^1+
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def pre():
|
||||
g[1] = f[1] = 1
|
||||
|
|
|
@ -112,7 +112,6 @@ $$
|
|||
构建实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void build(int a = 0, int b = 1, int c = 1, int d = 0, int level = 1) {
|
||||
int x = a + c, y = b + d;
|
||||
|
@ -124,7 +123,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def build(a = 1, b = 1, c = 1, d = 0, level = 1):
|
||||
x = a + c; y = b + d
|
||||
|
@ -137,7 +135,6 @@ $$
|
|||
查询实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
string find(int x, int y, int a = 0, int b = 1, int c = 1, int d = 0) {
|
||||
int m = a + c, n = b + d;
|
||||
|
@ -150,7 +147,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def find(x, y, a = 0, b = 1, c = 1, d = 0):
|
||||
m = a + c; n = b + d
|
||||
|
|
|
@ -67,10 +67,9 @@ $$
|
|||
#### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
const int N = 1000 * 1000;
|
||||
|
||||
|
||||
double simpson_integration(double a, double b) {
|
||||
double h = (b - a) / N;
|
||||
double s = f(a) + f(b);
|
||||
|
@ -84,10 +83,9 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
N = 1000 * 1000
|
||||
|
||||
|
||||
def simpson_integration(a, b):
|
||||
h = (b - a) / N
|
||||
s = f(a) + f(b)
|
||||
|
@ -120,29 +118,27 @@ $$
|
|||
参考代码如下:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
double simpson(double l, double r) {
|
||||
double mid = (l + r) / 2;
|
||||
return (r - l) * (f(l) + 4 * f(mid) + f(r)) / 6; // 辛普森公式
|
||||
}
|
||||
|
||||
|
||||
double asr(double l, double r, double eps, double ans, int step) {
|
||||
double mid = (l + r) / 2;
|
||||
double fl = simpson(l, mid), fr = simpson(mid, r);
|
||||
if (abs(fl + fr - ans) <= 15 * eps && step < 0)
|
||||
return fl + fr + (fl + fr - ans) / 15; // 足够相似的话就直接返回
|
||||
return asr(l, mid, eps / 2, fl, step - 1) +
|
||||
asr(mid, r, eps / 2, fr, step - 1); // 否则分割成两段递归求解
|
||||
asr(mid, r, eps / 2, fr, step - 1); // 否则分割成两段递归求解
|
||||
}
|
||||
|
||||
|
||||
double calc(double l, double r, double eps) {
|
||||
return asr(l, r, eps, simpson(l, r), 12);
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def simpson(l, r):
|
||||
mid = (l + r) / 2
|
||||
|
|
|
@ -43,7 +43,6 @@ $$
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
double sqrt_newton(double n) {
|
||||
const double eps = 1E-15;
|
||||
|
@ -58,7 +57,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def sqrt_newton(n):
|
||||
eps = 1e-15
|
||||
|
@ -78,7 +76,6 @@ $$
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int isqrt_newton(int n) {
|
||||
int x = 1;
|
||||
|
@ -94,7 +91,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def isqrt_newton(n):
|
||||
x = 1
|
||||
|
|
|
@ -273,59 +273,57 @@ $$
|
|||
#### 普通方法
|
||||
|
||||
=== "多项式对数函数"
|
||||
|
||||
首先,对于多项式 $f(x)$,若 $\ln{f(x)}$ 存在,则由其 [定义](./intro.md#复合),其必须满足:
|
||||
|
||||
|
||||
$$
|
||||
[x^{0}]f(x)=1
|
||||
$$
|
||||
|
||||
|
||||
对 $\ln{f(x)}$ 求导再积分,可得:
|
||||
|
||||
|
||||
$$
|
||||
\begin{aligned}
|
||||
\frac{\mathrm{d} \ln{f(x)}}{\mathrm{d} x} & \equiv \frac{f'(x)}{f(x)} & \pmod{x^{n}} \\
|
||||
\ln{f(x)} & \equiv \int \mathrm{d} \ln{x} \equiv \int\frac{f'(x)}{f(x)} \mathrm{d} x & \pmod{x^{n}}
|
||||
\end{aligned}
|
||||
$$
|
||||
|
||||
|
||||
多项式的求导,积分时间复杂度为 $O(n)$,求逆时间复杂度为 $O(n\log{n})$,故多项式求 $\ln$ 时间复杂度 $O(n\log{n})$。
|
||||
|
||||
=== "多项式指数函数"
|
||||
|
||||
首先,对于多项式 $f(x)$,若 $\exp{f(x)}$ 存在,则其必须满足:
|
||||
|
||||
|
||||
$$
|
||||
[x^{0}]f(x)=0
|
||||
$$
|
||||
|
||||
|
||||
否则 $\exp{f(x)}$ 的常数项不收敛。
|
||||
|
||||
|
||||
对 $\exp{f(x)}$ 求导,可得:
|
||||
|
||||
|
||||
$$
|
||||
\frac{\mathrm{d} \exp{f(x)}}{\mathrm{d} x} \equiv \exp{f(x)}f'(x)\pmod{x^{n}}
|
||||
$$
|
||||
|
||||
|
||||
比较两边系数可得:
|
||||
|
||||
|
||||
$$
|
||||
[x^{n-1}]\frac{\mathrm{d} \exp{f(x)}}{\mathrm{d} x} = \sum_{i = 0}^{n - 1} \left([x^{i}]\exp{f(x)}\right) \left([x^{n-i-1}]f'(x)\right)
|
||||
$$
|
||||
|
||||
|
||||
$$
|
||||
n[x^{n}]\exp{f(x)} = \sum_{i = 0}^{n} \left([x^{i}]\exp{f(x)}\right) \left((n - i + 1)[x^{n - i}]f(x)\right)
|
||||
$$
|
||||
|
||||
|
||||
又 $[x^{0}]f(x)=0$,则:
|
||||
|
||||
|
||||
$$
|
||||
n[x^{n}]\exp{f(x)} = \sum_{i = 0}^{n - 1} \left([x^{i}]\exp{f(x)}\right) \left((n - i + 1)[x^{n - i}]f(x)\right)
|
||||
$$
|
||||
|
||||
|
||||
使用分治 FFT 即可解决。
|
||||
|
||||
**时间复杂度** $O(n\log^{2}{n})$。
|
||||
|
||||
**时间复杂度** $O(n\log^{2}{n})$。
|
||||
|
||||
#### Newton's Method
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ DFS 为图论中的概念,详见 [DFS(图论)](../graph/dfs.md) 页面。
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
for (int i = 1; i <= n; ++i)
|
||||
for (int j = i; j <= n; ++j)
|
||||
|
@ -24,7 +23,6 @@ DFS 为图论中的概念,详见 [DFS(图论)](../graph/dfs.md) 页面。
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
for i in range(1, n + 1):
|
||||
for j in range(i, n + 1):
|
||||
|
@ -34,7 +32,6 @@ DFS 为图论中的概念,详见 [DFS(图论)](../graph/dfs.md) 页面。
|
|||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```Java
|
||||
for (int i = 1; i < n + 1; i++) {
|
||||
for (int j = i; j < n + 1; j++) {
|
||||
|
@ -65,10 +62,9 @@ DFS 为图论中的概念,详见 [DFS(图论)](../graph/dfs.md) 页面。
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int m, arr[103]; // arr 用于记录方案
|
||||
|
||||
|
||||
void dfs(int n, int i, int a) {
|
||||
if (n == 0) {
|
||||
for (int j = 1; j <= i - 1; ++j) printf("%d ", arr[j]);
|
||||
|
@ -81,17 +77,16 @@ DFS 为图论中的概念,详见 [DFS(图论)](../graph/dfs.md) 页面。
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 主函数
|
||||
scanf("%d%d", &n, &m);
|
||||
dfs(n, 1, 1);
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
arr = [0] * 103 # arr 用于记录方案
|
||||
|
||||
|
||||
def dfs(n, i, a):
|
||||
if n == 0:
|
||||
print(arr[1:i])
|
||||
|
@ -99,17 +94,16 @@ DFS 为图论中的概念,详见 [DFS(图论)](../graph/dfs.md) 页面。
|
|||
for j in range(a, n + 1):
|
||||
arr[i] = j
|
||||
dfs(n - j, i + 1, j) # 请仔细思考该行含义。
|
||||
|
||||
|
||||
# 主函数
|
||||
n, m = map(int, input().split())
|
||||
dfs(n, 1, 1)
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```Java
|
||||
static int m;
|
||||
|
||||
|
||||
// arr 用于记录方案
|
||||
static int[] arr = new int[103];
|
||||
|
||||
|
|
|
@ -80,7 +80,6 @@ AC 自动机在做匹配时,同一位上可匹配多个模式串。
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
void build() {
|
||||
for (int i = 0; i < 26; i++)
|
||||
|
@ -99,7 +98,6 @@ AC 自动机在做匹配时,同一位上可匹配多个模式串。
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def build():
|
||||
for i in range(0, 26):
|
||||
|
@ -163,7 +161,6 @@ AC 自动机在做匹配时,同一位上可匹配多个模式串。
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int query(char *t) {
|
||||
int u = 0, res = 0;
|
||||
|
@ -178,7 +175,6 @@ AC 自动机在做匹配时,同一位上可匹配多个模式串。
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def query(t):
|
||||
u, res = 0, 0
|
||||
|
|
|
@ -54,15 +54,14 @@ Hash 的核心思想在于,将输入映射到一个值域较小、可以方便
|
|||
参考代码:(效率低下的版本,实际使用时一般不会这么写)
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
using std::string;
|
||||
|
||||
|
||||
const int M = 1e9 + 7;
|
||||
const int B = 233;
|
||||
|
||||
|
||||
typedef long long ll;
|
||||
|
||||
|
||||
int get_hash(const string& s) {
|
||||
int res = 0;
|
||||
for (int i = 0; i < s.size(); ++i) {
|
||||
|
@ -70,24 +69,23 @@ Hash 的核心思想在于,将输入映射到一个值域较小、可以方便
|
|||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool cmp(const string& s, const string& t) {
|
||||
return get_hash(s) == get_hash(t);
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
M = int(1e9 + 7)
|
||||
B = 233
|
||||
|
||||
|
||||
def get_hash(s):
|
||||
res = 0
|
||||
for char in s:
|
||||
res = (res * B + ord(char)) % M
|
||||
return res
|
||||
|
||||
|
||||
def cmp(s, t):
|
||||
return get_hash(s) == get_hash(t)
|
||||
```
|
||||
|
|
|
@ -60,7 +60,6 @@ $\pi[6]=0$,因为 `abcabcd` 无相等的真前缀和真后缀
|
|||
具体实现如下:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> prefix_function(string s) {
|
||||
int n = (int)s.length();
|
||||
|
@ -76,7 +75,6 @@ $\pi[6]=0$,因为 `abcabcd` 无相等的真前缀和真后缀
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def prefix_function(s):
|
||||
n = len(s)
|
||||
|
@ -113,7 +111,6 @@ $$
|
|||
此时的改进的算法为:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> prefix_function(string s) {
|
||||
int n = (int)s.length();
|
||||
|
@ -129,7 +126,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def prefix_function(s):
|
||||
n = len(s)
|
||||
|
@ -180,7 +176,6 @@ $$
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> prefix_function(string s) {
|
||||
int n = (int)s.length();
|
||||
|
@ -196,7 +191,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def prefix_function(s):
|
||||
n = len(s)
|
||||
|
@ -237,7 +231,6 @@ $$
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> find_occurrences(string text, string pattern) {
|
||||
string cur = pattern + '#' + text;
|
||||
|
@ -245,15 +238,13 @@ $$
|
|||
vector<int> v;
|
||||
vector<int> lps = prefix_function(cur);
|
||||
for (int i = sz2 + 1; i <= sz1 + sz2; i++) {
|
||||
if (lps[i] == sz2)
|
||||
v.push_back(i - 2 * sz2);
|
||||
if (lps[i] == sz2) v.push_back(i - 2 * sz2);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def find_occurrences(t, s):
|
||||
cur = s + '#' + t
|
||||
|
@ -286,7 +277,6 @@ $$
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> ans(n + 1);
|
||||
for (int i = 0; i < n; i++) ans[pi[i]]++;
|
||||
|
@ -295,7 +285,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
ans = [0] * (n + 1)
|
||||
for i in range(0, n):
|
||||
|
|
|
@ -33,7 +33,6 @@ Duval 算法运用了贪心的思想。算法过程中我们把串 $s$ 分成三
|
|||
下面的代码返回串 $s$ 的 Lyndon 分解方案。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// duval_algorithm
|
||||
vector<string> duval(string const& s) {
|
||||
|
@ -58,7 +57,6 @@ Duval 算法运用了贪心的思想。算法过程中我们把串 $s$ 分成三
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# duval_algorithm
|
||||
def duval(s):
|
||||
|
@ -93,7 +91,6 @@ Duval 算法运用了贪心的思想。算法过程中我们把串 $s$ 分成三
|
|||
于是我们在分解的过程中记录每一次的近似 Lyndon 串的开头即可。
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
// smallest_cyclic_string
|
||||
string min_cyclic_string(string s) {
|
||||
|
@ -117,7 +114,6 @@ Duval 算法运用了贪心的思想。算法过程中我们把串 $s$ 分成三
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# smallest_cyclic_string
|
||||
def min_cyclic_string(s):
|
||||
|
|
|
@ -42,7 +42,6 @@ $$
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> d1(n), d2(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
|
@ -50,17 +49,16 @@ $$
|
|||
while (0 <= i - d1[i] && i + d1[i] < n && s[i - d1[i]] == s[i + d1[i]]) {
|
||||
d1[i]++;
|
||||
}
|
||||
|
||||
|
||||
d2[i] = 0;
|
||||
while (0 <= i - d2[i] - 1 && i + d2[i] < n &&
|
||||
s[i - d2[i] - 1] == s[i + d2[i]]) {
|
||||
s[i - d2[i] - 1] == s[i + d2[i]]) {
|
||||
d2[i]++;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
d1 = [0] * n
|
||||
d2 = [0] * n
|
||||
|
@ -151,7 +149,6 @@ Manacher 算法的另一部分显然也是线性的,因此总复杂度为 $O(n
|
|||
为了计算 $d_1[]$,我们有以下代码:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> d1(n);
|
||||
for (int i = 0, l = 0, r = -1; i < n; i++) {
|
||||
|
@ -168,7 +165,6 @@ Manacher 算法的另一部分显然也是线性的,因此总复杂度为 $O(n
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
d1 = [0] * n
|
||||
l, r = 0, -1
|
||||
|
@ -186,7 +182,6 @@ Manacher 算法的另一部分显然也是线性的,因此总复杂度为 $O(n
|
|||
计算 $d_2[]$ 的代码十分类似,但是在算术表达式上有些许不同:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> d2(n);
|
||||
for (int i = 0, l = 0, r = -1; i < n; i++) {
|
||||
|
@ -203,7 +198,6 @@ Manacher 算法的另一部分显然也是线性的,因此总复杂度为 $O(n
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
d2 = [0] * n
|
||||
l, r = 0, -1
|
||||
|
|
|
@ -21,14 +21,13 @@
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
/*
|
||||
* s:待匹配的主串
|
||||
* t:模式串
|
||||
* n:主串的长度
|
||||
* m:模式串的长度
|
||||
*/
|
||||
* s:待匹配的主串
|
||||
* t:模式串
|
||||
* n:主串的长度
|
||||
* m:模式串的长度
|
||||
*/
|
||||
std::vector<int> match(char *s, char *t, int n, int m) {
|
||||
std::vector<int> ans;
|
||||
int i, j;
|
||||
|
@ -43,12 +42,11 @@
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def match(s, t, n, m):
|
||||
if m < 1:
|
||||
return []
|
||||
|
||||
|
||||
ans = []
|
||||
for i in range(0, n - m + 1):
|
||||
for j in range(0, m):
|
||||
|
|
|
@ -25,7 +25,6 @@ $$
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int k = 0, i = 0, j = 1;
|
||||
while (k < n && i < n && j < n) {
|
||||
|
@ -44,7 +43,6 @@ $$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
k, i, j = 0, 0, 1
|
||||
while k < n and i < n and j < n:
|
||||
|
@ -99,7 +97,6 @@ $O(n)$
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
int k = 0, i = 0, j = 1;
|
||||
while (k < n && i < n && j < n) {
|
||||
|
@ -115,7 +112,6 @@ $O(n)$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
k, i, j = 0, 0, 1
|
||||
while k < n and i < n and j < n:
|
||||
|
|
|
@ -19,12 +19,11 @@ trie 的结构非常好懂,我们用 $\delta(u,c)$ 表示结点 $u$ 的 $c$
|
|||
放一个结构体封装的模板:
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
struct trie {
|
||||
int nex[100000][26], cnt;
|
||||
bool exist[100000]; // 该结点结尾的字符串是否存在
|
||||
|
||||
|
||||
void insert(char *s, int l) { // 插入字符串
|
||||
int p = 0;
|
||||
for (int i = 0; i < l; i++) {
|
||||
|
@ -34,7 +33,7 @@ trie 的结构非常好懂,我们用 $\delta(u,c)$ 表示结点 $u$ 的 $c$
|
|||
}
|
||||
exist[p] = 1;
|
||||
}
|
||||
|
||||
|
||||
bool find(char *s, int l) { // 查找字符串
|
||||
int p = 0;
|
||||
for (int i = 0; i < l; i++) {
|
||||
|
@ -48,14 +47,13 @@ trie 的结构非常好懂,我们用 $\delta(u,c)$ 表示结点 $u$ 的 $c$
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
class trie:
|
||||
def __init__(self):
|
||||
self.nex = [[0 for i in range(26)] for j in range(100000)]
|
||||
self.cnt = 0
|
||||
self.exist = [False] * 100000 # 该结点结尾的字符串是否存在
|
||||
|
||||
|
||||
def insert(self, s): # 插入字符串
|
||||
p = 0
|
||||
for i in s:
|
||||
|
@ -65,7 +63,7 @@ trie 的结构非常好懂,我们用 $\delta(u,c)$ 表示结点 $u$ 的 $c$
|
|||
self.nex[p][c] = self.cnt # 如果没有,就添加结点
|
||||
p = self.nex[p][c]
|
||||
self.exist[p] = True
|
||||
|
||||
|
||||
def find(self, s): # 查找字符串
|
||||
p = 0
|
||||
for i in s:
|
||||
|
|
|
@ -24,7 +24,6 @@ Z 函数的朴素算法复杂度为 $O(n^2)$:
|
|||
|
||||
???+ note "实现"
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> z_function_trivial(string s) {
|
||||
int n = (int)s.length();
|
||||
|
@ -36,7 +35,6 @@ Z 函数的朴素算法复杂度为 $O(n^2)$:
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def z_function_trivial(s):
|
||||
n = len(s)
|
||||
|
@ -70,7 +68,6 @@ Z 函数的朴素算法复杂度为 $O(n^2)$:
|
|||
### 实现
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp
|
||||
vector<int> z_function(string s) {
|
||||
int n = (int)s.length();
|
||||
|
@ -89,7 +86,6 @@ Z 函数的朴素算法复杂度为 $O(n^2)$:
|
|||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
def z_function(s):
|
||||
n = len(s)
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
"patch-package": "^6.5.1",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"remark": "^14.0.2",
|
||||
"remark-clang-format": "^2.3.2",
|
||||
"remark-clang-format": "2.3.2",
|
||||
"remark-cli": "^10.0.1",
|
||||
"remark-copywriting-correct": "0.6.0",
|
||||
"remark-details": "^4.1.1",
|
||||
|
@ -55,6 +55,7 @@
|
|||
"remark-parse": "^10.0.1",
|
||||
"remark-preset-lint-markdown-style-guide": "^5.1.2",
|
||||
"remark-stringify": "^10.0.2",
|
||||
"remark-tabbed": "OI-wiki/remark-tabbed#pre-release",
|
||||
"ts-node": "^10.8.2",
|
||||
"unified": "^10.1.2",
|
||||
"unist-util-visit": "^4.1.0",
|
||||
|
|
Loading…
Reference in New Issue