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 config
pull/5055/head^2
Shaoyu Wang 2023-10-04 21:50:08 +08:00 committed by GitHub
parent 329dacee51
commit 643003dd91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 905 additions and 1256 deletions

View File

@ -18,6 +18,7 @@
"remark-math",
"remark-math-space",
"remark-lint-final-newline",
"remark-tabbed",
"remark-lint-no-tabs",
"remark-clang-format"
]

View File

@ -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"
```

View File

@ -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

View File

@ -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):

View File

@ -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):

View File

@ -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

View File

@ -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):

View File

@ -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):

View File

@ -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"
```

View File

@ -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

View File

@ -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;
}
}
```

View File

@ -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

View File

@ -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"
```

View File

@ -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:

View File

@ -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):

View File

@ -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

View File

@ -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"
```

View File

@ -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)

View File

@ -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]

View File

@ -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):

View File

@ -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): # 循环背包容量

View File

@ -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:

View File

@ -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)

View File

@ -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"
```

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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

View File

@ -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 = [] # 存储向量或点

View File

@ -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())

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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 @@ BellmanFord 算法所做的,就是不断尝试对图上每一条边进行
??? 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 @@ BellmanFord 算法所做的,就是不断尝试对图上每一条边进行
```
=== "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):
'''

View File

@ -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]
```

View File

@ -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() # 结尾换行
```

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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)]

View File

@ -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

View File

@ -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:

View File

@ -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):

View File

@ -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]

View File

@ -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) \\

View File

@ -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):

View File

@ -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:

View File

@ -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):

View File

@ -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:

View File

@ -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:

View File

@ -69,7 +69,6 @@ $$
???+ note "线性筛实现"
=== "C++"
```cpp
void getMu() {
mu[1] = 1;
@ -88,7 +87,6 @@ $$
```
=== "Python"
```python
def getMu():
mu[1] = 1

View File

@ -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]))

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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)
```

View File

@ -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):

View File

@ -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):

View File

@ -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

View File

@ -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):

View File

@ -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:

View File

@ -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:

View File

@ -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)

3
package.json vendored
View File

@ -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",

1077
yarn.lock

File diff suppressed because it is too large Load Diff