C++算法板子积累

Hello

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <stack>

using namespace std;
typedef long long ll;

int main() {
cout << "Hello world!" << endl;
return 0;
}

标准库

<algorithm>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
__gcd(a, b)                    // 求两个数的最大公因数
__builtin_popcount(a) // 求 int 的二进制里多少个 1

is_sorted(a, a + n) // 是否升序
is_sorted_until(a, a + n) // 到哪里是升序
sort(a, a + n) // 不稳定排序(默认升序)
sort(a, a + n, greater<int>()) // 降序排序
stable_sort(a, a + n) // 稳定排序
nth_element(a, a + k, a + n) // 将第 k 大元素放到 a[k]
unique(begin, end) // 对有序数组去重,返回末尾地址

max(a, b) // 返回较大值
min(a, b) // 返回较小值
max_element(a, a + n) // 返回最大值位置
min_element(a, a + n) // 返回最小值位置

lower_bound(a, a + n, key) // 返回第一个不小于 key 的元素的位置
upper_bound(a, a + n, key) // 返回第一个大于 key 的元素的位置
binary_search(a, a + n, key) // 二分查找是否存在

is_heap(a, a + n) // 判断是否为大顶堆
is_heap_until(a, a + n) // 到哪里是大顶堆
make_heap(a, a + n) // 区间建堆
push_heap(a, a + n) // 末尾元素入堆并调整,与 push_back() 配合
pop_heap(a, a + n) // 堆顶移到末尾并调整,与 pop_back() 配合
sort_heap(a, a + n) // 升序堆排序

is_permutation() // 两个序列是否互为另一个的排序
next_permutation() // 下一个排序
prev_permutation() // 上一个排序

fill(a, a + n, val) // 批量赋值
reverse(a, a + n) // 数组翻转

<vector>

1
2
3
4
5
6
7
8
9
10
11
12
13
v.at(k)					// 访问 v[k]
v.front() // 首元素
v.back() // 末元素
v.begin() // 首地址(迭代器)
v.end() // 末地址(迭代器)
v.empty() // 是否空
v.size() // 大小
v.max_size() // 最大空间
v.clear() // 清除
v.insert(pos, item) // 在 pos(迭代器) 位置插入 item
v.eraze(pos) // 擦除 pos(迭代器) 位置的元素
v.push_back(item) // 末尾插入
v.pop_back() // 末尾删除

<queue>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*----- queue -----*/
q.front() // 访问队头
q.back() // 访问队尾
q.empty() // 是否空
q.size() // 大小
q.push(item) // item 入队
q.emplace(item) // item 替换队尾
q.pop() // 出队
/*----- priority_queue -----*/
priority_queue<int, vector<int>, greater<int>> pq
pq.top() // 访问队首
pq.empty() // 优先队列是否空
pq.size() // 大小
pq.push(item) // 插入 item
pq.pop() // 出队

<stack>

1
2
3
4
5
6
s.top()					// 访问栈顶
s.empty() // 栈是否空
s.size() // 大小
s.push(item) // item 入栈
s.emplace(item) // item 替换栈顶
s.pop() // 出栈

<set>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*----- set -----*/
s.size() // 大小
s.empty() // 是否空
s.clear() // 清除
s.insert(key) // 插入
s.erase(pos/key) // 删除
s.count(key) // 是否存在
s.find(key) // 查找,成功返回位置,失败返回 s.end()
/*----- multiset -----*/
ms.size() // 大小
ms.empty() // 是否空
ms.clear() // 清除
ms.insert(key) // 插入
ms.erase(pos/key) // 删除
ms.count(key) // 计数
ms.find(key) // 查找,成功返回位置,失败返回 s.end()

<map>

1
2
/*----- map -----*/
/*----- mulmap -----*/

<unordered_set>

1
2
/*----- unordered_set -----*/
/*----- unordered_multiset -----*/

<unordered_map>

1
2
/*----- unordered_map -----*/
/*----- unordered_multimap -----*/

分治

逆序对计数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>

using namespace std;
typedef long long ll;

int temp[200005];

ll solve(int a[], int left, int right);

int main() {
int n;
int a[200005] = {};
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
cout << solve(a, 0, n - 1);
return 0;
}
ll solve(int a[], int left, int right) {
if (left == right)
return 0;
else {
int mid = (right - left) / 2 + left;
ll s1 = solve(a, left, mid);
ll s2 = solve(a, mid + 1, right);
ll s3 = 0;
int i = left, j = mid + 1, k = 0;
while (i <= mid && j <= right) {
if (a[i] <= a[j]) {
temp[left + k] = a[i];
k++;
i++;
} else {
temp[left + k] = a[j];
s3 += (mid - i + 1);
k++;
j++;
}
}
if (i <= mid)
while (i <= mid) {
temp[k + left] = a[i];
k++;
i++;
}
else
while (j <= right) {
temp[k + left] = a[j];
k++;
j++;
}
for (int l = left; l <= right; l++)
a[l] = temp[l];
return s1 + s2 + s3;
}
}

动态规划

01 背包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <algorithm>

#define ll long long
#define MAX_NUM 1005 //物品数量
#define MAX_CAP 100005 //最大容量
using namespace std;

ll dp[MAX_CAP];
int v[MAX_NUM];
int w[MAX_NUM];

ll backBag(ll Bag[], int *value, int *weight, int num, int cap) {
// dp数组,价值,重量,容量
for(int i = 0; i <= cap; i++)
Bag[i] = 0;
for (int i = 1; i <= num; i++)
for (int j = cap; j >= weight[i]; j--) //倒着dp
Bag[j] = max(Bag[j - weight[i]] + value[i], Bag[j]);
return Bag[cap];
}

int main() {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> v[i] >> w[i];
cout << backBag(dp, v, w, n, k);
return 0;
}

完全背包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <algorithm>

#define ll long long
#define MAX_NUM 10005 //物品数量
#define MAX_CAP 10000005 //最大容量
using namespace std;

ll dp[MAX_CAP];
int v[MAX_NUM];
int w[MAX_NUM];

ll backBag(ll Bag[], int *value, int *weight, int num, int cap) {
// dp数组,价值,重量,容量
for(int i = 0; i <= cap; i++)
Bag[i] = 0;
for (int i = 1; i <= num; i++)
for (int j = weight[i]; j <= cap; j++) //正着dp
Bag[j] = max(Bag[j - weight[i]] + value[i], Bag[j]);
return Bag[cap];
}

int main() {
int n, k;
cin >> k >> n;
for (int i = 1; i <= n; i++)
cin >> w[i] >> v[i];
cout << backBag(dp, v, w, n, k);
return 0;
}

分组背包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <algorithm>

typedef long long ll;

const int MAX = 1005;

struct {
int cnt;
ll ID[MAX];
} group[MAX]; //用一个结构体来存储每一组的物品编号

ll dp[MAX];
ll val[MAX];
ll weight[MAX];

ll group_bag(int cap, int max_group);

using namespace std;

int main() {
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
int n, m;
cin >> m >> n;
int a, b, k, max_group = 0;
for (int i = 1; i <= n; i++) {
cin >> a >> b >> k;
weight[i] = a;
val[i] = b;
group[k].ID[group[k].cnt++] = i;
max_group = max(max_group, k);
}
cout << group_bag(m, max_group);
return 0;
}

ll group_bag(int cap, int max_group) {
for (int i = 0; i <= max_group; i++) // 第一层组循环
for (ll j = cap; j >= 0; j--) // 第二层容量倒着循环
for (int k = 0; k < group[i].cnt; k++) // 第三层组内循环
if (j >= weight[group[i].ID[k]])
dp[j] = max(dp[j],
dp[j - weight[group[i].ID[k]]] + val[group[i].ID[k]]);
return dp[cap];
}

最大子列和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <algorithm>

#define MAX 1000005
#define ll long long
using namespace std;

int a[MAX];

ll maxSubArray(int *array, int n) {
ll Max = -0x3f3f3f3f3f3f3f3f;
ll sum = 0;
for (int i = n - 1; i >= 0; i--) {
if (sum <= 0)
sum = array[i];
else
sum += array[i];
Max = max(sum, Max);
}
return Max;
}

int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
cout << maxSubArray(a, n);
return 0;
}

LCS 最长公共子序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <string>
#define MAX 1005
using namespace std;

struct Tab{
int x, y;
} trac[MAX][MAX];

int lcs[MAX][MAX];

void print_lcs(string str, int i, int j);

int main() {
int k;
cin >> k;
string sa, sb;
cin >> sa >> sb;
int la = (int)sa.length();
int lb = (int)sb.length();
for (int i = 1; i <= la; i++) {
for (int j = 1; j <= lb; j++) {
if (sa[i - 1] == sb[j - 1]) {
lcs[i][j] = lcs[i - 1][j - 1] + 1;
trac[i][j] = {i - 1, j - 1};
} else if (lcs[i - 1][j] >= lcs[i][j - 1]) {
lcs[i][j] = lcs[i - 1][j];
trac[i][j] = {i - 1, j};
} else {
lcs[i][j] = lcs[i][j - 1];
trac[i][j] = {i, j - 1};
}
}
}
if(k == 0)
cout << lcs[la][lb];
else
print_lcs(sa, la, lb);
return 0;
}

void print_lcs(string str, int i, int j){
if(i == 0 || j == 0)
return ;
if(trac[i][j].x == i - 1 && trac[i][j].y == j - 1){
print_lcs(str, i - 1, j - 1);
cout << str[i - 1];
}else if(trac[i][j].x == i - 1 && trac[i][j].y == j)
print_lcs(str, i - 1, j);
else
print_lcs(str, i, j - 1);
}

最小编辑距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <string>
#define MAX 2005
using namespace std;

int min3(int a, int b, int c) {
int m = a;
if (b < m)
m = b;
if (c < m)
return c;
return m;
}
int minDistance(string word1, string word2) {
int dp[2][MAX] = {};
int l1 = word1.length();
int l2 = word2.length();
for (int j = 0; j <= l2; j++)
dp[0][j] = j;
for (int i = 1; i <= l1; i++) {
dp[1][0] = i;
for (int j = 1; j <= l2; j++)
if (word1[i - 1] == word2[j - 1])
dp[1][j] = dp[0][j - 1];
else
dp[1][j] = min3(dp[0][j - 1], dp[0][j], dp[1][j - 1]) + 1;
for (int j = 0; j <= l2; j++)
dp[0][j] = dp[1][j];
}
return dp[0][l2];
}
int main() {
string a;
string b;
cin >> a >> b;
cout << minDistance(a, b);
return 0;
}

最长单调子序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 严格单调递增子列的长度
int lsrsa(const vector<int> &a) {
vector<int> sa;
for (auto x: a) {
if (sa.empty() || x > sa.back())
sa.push_back(x);
else
*lower_bound(sa.begin(), sa.end(), x) = x;
}
return (int) sa.size();
}
// 单调不减子列的长度
int lrsa(const vector<int> &a) {
vector<int> sa;
for (auto x: a) {
if (sa.empty() || x >= sa.back())
sa.push_back(x);
else
*upper_bound(sa.begin(), sa.end(), x) = x;
}
return (int) sa.size();
}

图算法

链式前向星

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Edge{
int to, w, next; //终点,权值,前驱
} e[E_MAX];

int cnt_E = 0;
int head[V_MAX]; //需要先初始化为-1

void intList(int n){
memset(head, -1, sizeof(head));
}

void addEdge(int x, int y, int w){
e[cnt_E].to = y; //保存终点
e[cnt_E].next = head[x]; //添加链接
head[x] = cnt++; //更新表头
}

Dijkstra 最短路(标准版)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <vector>
#include <cstring>

#define V_MAX 100005
#define INF 0x3f3f3f3f3f3f3f3f

using namespace std;
typedef long long ll;

struct Edge {
int to;
ll weight;
};

vector<Edge> e[V_MAX];
ll dis[V_MAX];
bool vis[V_MAX];
int n, m;

void addEdge(int u, int v, ll w);
void dijkstra(int s);

int main() {
int s;
cin >> n >> m >> s;
int x, y;
ll w;
for (int i = 0; i < m; ++i) {
cin >> x >> y >> w;
addEdge(x, y, w);
}
dijkstra(s);
// 最短路保存在 dis 中
for (int i = 1; i <= n; i++) {
if (dis[i] == INF)
cout << -1 << " ";
else
cout << dis[i] << " ";
}
return 0;
}

void addEdge(int u, int v, ll w) {
e[u].push_back({v, w});
}

void dijkstra(int s) {
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0;
for (int i = 1; i <= n; i++) {
int u = 0;
ll mind = INF;
for (int j = 1; j <= n; j++)
if (!vis[j] && dis[j] < mind) {
u = j;
mind = dis[j];
}
vis[u] = true;
for (auto ed: e[u]) {
int v = ed.to;
ll w = ed.weight;
if (dis[v] > dis[u] + w)
dis[v] = dis[u] + w;
}
}
}

Dijkstra 最短路(堆优化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>

#define V_MAX 100005
#define INF 0x3f3f3f3f3f3f3f3f

using namespace std;

typedef long long ll;

struct Edge {
int to;
ll w;
};

struct Node {
ll dis;
int u;
bool operator>(const Node &b) const {return dis > b.dis; }
};

vector<Edge> e[V_MAX];

void addEdge(int u, int v, ll w) {
e[u].push_back({v, w});
}

vector<ll> dijkstra(int s) {
priority_queue<Node, vector<Node>, greater<Node>> q;
vector<ll> dis(V_MAX);
fill(dis.begin(), dis.end(), INF);
vector<bool> vis(V_MAX);
dis[s] = 0;
q.push({0, s});
while (!q.empty()){
int u = q.top().u;
q.pop();
if(vis[u])continue;
vis[u] = true;
for (auto ed : e[u]){
int v = ed.to;
ll w = ed.w;
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
q.push({dis[v], v});
}
}
}
return dis;
}

int main() {
int n, m;
int s;
cin >> n >> m >> s;
int x, y, w;
for (int i = 0; i < m; i++) {
cin >> x >> y >> w;
addEdge(x, y, w);
}
vector<ll> dis = dijkstra(s);
for (int i = 1; i <= n; i++) {
cout << dis[i] << " ";
}
return 0;
}

Floyd 最短路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <algorithm>
#include <cstring>
#include <iostream>

#define V_MAX 510 // 结点数
#define INF 0x3f3f3f3f3f3f3f3f

using namespace std;
typedef long long ll;

ll f[V_MAX][V_MAX]; // 邻接矩阵存图

int main() {
int n, m, p;
ll x, y, w;
cin >> n >> m >> p;
for (x = 1; x <= n; x++)
for (y = 1; y <= n; y++)
f[x][y] = INF;
for (int i = 1; i <= n; i++)
f[i][i] = 0;

/*-----初始化部分-----*/

for (int i = 0; i < m; i++) {
cin >> x >> y >> w;
if (w < f[x][y]) // 考虑重边的情况
f[x][y] = w;
}

/*-----读入-----*/

for (int k = 1; k <= n; k++)
for (x = 1; x <= n; x++)
for (y = 1; y <= n; y++)
f[x][y] = min(f[x][y], f[x][k] + f[k][y]);

/*----- Floyd -----*/

for (int i = 0; i < p; i++) {
cin >> x >> y;
if (f[x][y] != INF)
cout << f[x][y] << endl;
else
cout << "-1" << endl;
}

/*-----输出-----*/
return 0;
}

Kruskal 最小生成树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <algorithm>
#include <iostream>

#define V_MAX 300005
#define E_MAX 500005

using namespace std;
typedef long long ll;

struct Edge {
int x, y, w;
bool operator<(const Edge &b) const { return w < b.w; }
} e[E_MAX];

int v[V_MAX];

int Find(int x);
bool isUnion(int x, int y);
void Union(int x, int y); //合并
void makeSet(int n); //初始化并查集

int main() {
int n, m;
cin >> n >> m;
makeSet(n);
for (int i = 0; i < m; i++)
cin >> e[i].x >> e[i].y >> e[i].w;
sort(e, e + m);
int cnt = 0;
ll sum = 0;
for(int i = 0; cnt < n - 1; i++){
if(isUnion(e[i].x, e[i].y))
continue;
cnt++;
sum += e[i].w;
Union(e[i].x, e[i].y);
}
cout << sum;
return 0;
}

void makeSet(int n) {
for (int i = 1; i <= n; i++)
v[i] = i;
}

int Find(int x) {
if (v[x] == x)
return x;
return v[x] = Find(v[x]);
}

bool isUnion(int x, int y) { return Find(x) == Find(y); }
void Union(int x, int y) { v[Find(y)] = Find(x); }

Kahn 拓扑排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>

#define E_MAX 400005
#define V_MAX 100005

using namespace std;

struct Edge { //链式前向星,存边的起点、终点、和前驱
int x, y, next;
} e[E_MAX];

int head[V_MAX]; //下标是起点的表头,存第一个边的编号,初始化为 -1
int id[V_MAX]; //每个点的入度
int cnt; //存储的边数

void addEdge(int x, int y);
bool Kahn(int n);

int main() {
int n, m, x, y;
cin >> n >> m;

fill(head + 1, head + 1 + n, -1);

/*----- 初始化 -----*/

for (int i = 0; i < m; i++) {
cin >> x >> y;
addEdge(x, y);
}

/*----- 读入边 -----*/

Kahn(n);
return 0;
}
void addEdge(int x, int y) {
e[cnt].x = x; //起点
e[cnt].y = y; //终点
e[cnt].next = head[x]; //添加
id[y]++;
head[x] = cnt++; //更新表头
}
bool Kahn(int n) {
priority_queue<int> q; //优先队列
for (int i = 1; i <= n; i++) {
if (id[i] == 0)
q.push(i); //把入度为0的点入队
}
vector<int> ans; //数组保存结果
while (!q.empty()) {
int x = q.top(); //出队
q.pop();
ans.push_back(x);
int edge = head[x];
while (edge != -1) {
id[e[edge].y]--; //删除边
if (id[e[edge].y] == 0)
q.push(e[edge].y);
edge = e[edge].next;
}
}
if (ans.size() == n) {
for (int an : ans)
cout << an << " ";
return true;
}

/*----- 无环则输出并返回真 -----*/

return false;
}

Dinic 最大流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int V_MAX = 205;
const int E_MAX = 5005;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;

ll max_stream = 0;
int cnt_E = 0;
int n, m, s, t;

struct Edge {
int to;
int nxt;
ll val;
} e[E_MAX * 2];

int head[V_MAX];
int depth[V_MAX];

void addEdge(int x, int y, int w);
void read();
bool bfs();
ll Dinic();

int main() {
ios::sync_with_stdio(false);
cin >> n >> m >> s >> t;

fill(head + 1, head + 1 + n, -1);

/*----- 读入并初始化 -----*/

read();
cout << Dinic();
return 0;
}
void addEdge(int x, int y, int w) {
e[cnt_E].to = y;
e[cnt_E].val = w;
e[cnt_E].nxt = head[x];
head[x] = cnt_E++;
}
void read() {
int u, v, w;
for (int i = 0; i < m; i++) {
cin >> u >> v >> w;
addEdge(u, v, w);
addEdge(v, u, 0);
}
}
bool bfs() {
memset(depth, 0, sizeof(depth));
depth[s] = 1;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; i > -1; i = e[i].nxt) {
int v = e[i].to;
if (e[i].val && !depth[v]) {
depth[v] = depth[u] + 1;
q.push(v);
}
}
}
if (depth[t] != 0)
return true;
return false;
}

ll dfs(int pos, ll in) {
if (pos == t)
return in;
ll out = 0;
for (int u = head[pos]; u > -1 && in; u = e[u].nxt) {
int v = e[u].to;
if (e[u].val && depth[v] == depth[pos] + 1) {
ll res = dfs(v, min(e[u].val, in));
e[u].val -= res;
e[u ^ 1].val += res;
in -= res;
out += res;
}
}
if (out == 0)
depth[pos] = 0;
return out;
}
ll Dinic() {
while (bfs())
max_stream += dfs(s, LL_INF);
return max_stream;
}

二分图匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;

struct pos {
int x, y;
};

vector<pos> left;
vector<pos> right;

struct augment_path {
// 结点编号从 0 开始
vector<vector<int>> g;
vector<int> pa;
vector<int> pb;
vector<int> vis;
int n, m;
int dfn;
int res;

augment_path(int _n, int _m) : n(_n), m(_m) {
pa = vector<int>(n, -1);
pb = vector<int>(m, -1);
vis = vector<int>(n);
g.resize(n);
res = dfn = 0;
}

void add(int from, int to) {
g[from].push_back(to);
}

bool dfs(int v) {
vis[v] = dfn;
for (int u: g[v])
if (pb[u] == -1) {
pb[u] = v;
pa[v] = u;
return true;
}
for (int u: g[v])
if (vis[pb[u]] != dfn && dfs(pb[u])) {
pa[v] = u;
pb[u] = v;
return true;
}
return false;
}

int solve() {
while (true) {
dfn++;
int cnt = 0;
for (int i = 0; i < n; i++)
if (pa[i] == -1 && dfs(i))
cnt++;
if (cnt == 0)
break;
res += cnt;
}
return res;
}
};

int main() {
int n, m, e;
cin >> n >> m >> e;
augment_path solver(n, m);
int u, v;
for(int i = 0; i < e; i++){
cin >> u >> v;
solver.add(u - 1, v - 1);
}
cout << solver.solve() << endl;
return 0;
}

计算几何

线段相交计数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

struct Point {
int x, y;

Point operator+(const Point &b) const {
return {x + b.x, y + b.y};
}

Point operator-(const Point &b) const {
return {x - b.x, y - b.y};
}

Point operator*(const int &b) const {
return {x * b, y * b};
}

int operator^(const Point &b) const {
return x * b.y - y * b.x;
}
};

struct Line {
Point p;
Point q;
};

vector<Line> lines;

int sgn(int x);

bool intersect(Line l1, Line l2);

bool onSegment(Point point, Line line);

int main() {
int n, cnt = 0;
cin >> n;
int x1, y1, x2, y2;
for (int i = 0; i < n; i++) {
cin >> x1 >> y1 >> x2 >> y2;
lines.push_back({{x1, y1},
{x2, y2}});
}
for (int i = 0; i < n; i++)
for (int j = 0; j < i; j++)
if (intersect(lines[i], lines[j]))
cnt++;
cout << cnt;
return 0;
}

int sgn(int x) {
if (x < 0) return -1;
if (x > 0) return 1;
return 0;
}

bool intersect(Line l1, Line l2) {
int d1 = sgn((l1.q - l1.p) ^ (l2.p - l1.p));
int d2 = sgn((l1.q - l1.p) ^ (l2.q - l1.p));
int d3 = sgn((l2.q - l2.p) ^ (l1.p - l2.p));
int d4 = sgn((l2.q - l2.p) ^ (l1.q - l2.p));
if (d1 * d2 < 0 && d3 * d4 < 0)
return true;
if (d1 == 0 && onSegment(l2.p, l1))
return true;
if (d2 == 0 && onSegment(l2.q, l1))
return true;
if (d3 == 0 && onSegment(l1.p, l2))
return true;
if (d4 == 0 && onSegment(l1.q, l2))
return true;
return false;
}

bool onSegment(Point point, Line line) {
if (point.x >= min(line.p.x, line.q.x) &&
point.x <= max(line.p.x, line.q.x) &&
point.y >= min(line.p.y, line.q.y) &&
point.y <= max(line.p.y, line.q.y))
return true;
return false;
}

Graham 凸包 + 旋转卡壳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>

using namespace std;

const int MAX = 200005;
const double eps = 1e-7;

struct Point {
double x, y;

Point operator+(const Point &b) const {
return {x + b.x, y + b.y};
}

Point operator-(const Point &b) const {
return {x - b.x, y - b.y};
}

double operator^(const Point &b) const {
return x * b.y - y * b.x;
}

bool operator<(const Point &b) const {
if (x != b.x)
return x < b.x;
return y < b.y;
}
};

Point p[MAX];
Point s[MAX];
int top;

void selMin(int n);
int cmp(Point a, Point b);
bool equal(double a, double b);
double dis(Point a, Point b);
void graham(int n);
double s_sqr(Point a, Point b, Point c);
double diameter();

int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> p[i].x >> p[i].y;
selMin(n);
sort(p + 1, p + n, cmp);
graham(n);
printf("%.6f", sqrt(diameter())) ;
return 0;
}

void selMin(int n) {
Point Min = p[0];
int IDMin = 0;
for (int i = 0; i < n; i++)
if (p[i] < Min) {
Min = p[i];
IDMin = i;
}
swap(p[0], p[IDMin]);
}

int cmp(Point a, Point b) {
double x = (a - p[0]) ^ (b - p[0]);
if (x > 0)
return 1;
if (equal(x, 0) && (dis(a, p[0]) < dis(b, p[0])))
return 1;
return 0;
}

double dis(Point a, Point b) {
double x = a.x - b.x;
double y = a.y - b.y;
return x * x + y * y;
}

void graham(int n) {
top = 1;
s[0] = p[0];
s[1] = p[1];
for (int i = 2; i < n; i++) {
while (top > 1 && ((p[i] - s[top]) ^ (s[top - 1] - s[top])) <= 0)
top--;
s[++top] = p[i];
}
}

double s_sqr(Point a, Point b, Point c) {
return fabs((a - b) ^ (c - b));
}

double diameter() {
double diam = 0;
int j = 2;
s[++top] = s[0];
if (top < 3)
return dis(s[0], s[1]);
for (int i = 0; i < top - 1; i++) {
while (s_sqr(s[i], s[i + 1], s[j]) <
s_sqr(s[i], s[i + 1], s[(j + 1) % top]))
j = (j + 1) % top;
diam = max(diam, max(dis(s[i], s[j]), dis(s[i + 1], s[j])));
}
return diam;
}
bool equal(double a, double b){
return fabs(a - b) < eps;
}

其他算法

多项式乘法-FFT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
#include <vector>
#include <cmath>

const double Pi = acos(-1);
const int MAX = 4000005;
using namespace std;
typedef long long ll;

struct Complex {
double x, y;

Complex operator+(const Complex &b) const {
return {x + b.x, y + b.y};
}

Complex operator-(const Complex &b) const {
return {x - b.x, y - b.y};
}

Complex operator*(const Complex &b) const {
return {x * b.x - y * b.y, x * b.y + y * b.x};
}
} f[MAX], p[MAX], sav[MAX];
void dft(Complex *f, int len);

void idft(Complex *f, int len);

int main() {
int n, m;
cin >> n >> m;
for (int i = 0; i <= n; i++)
cin >> f[i].x;
for (int i = 0; i <= m; i++)
cin >> p[i].x;
for (m += n, n = 1; n <= m; n <<= 1);
dft(f, n);
dft(p, n);
for (int i = 0; i < n; i++)
f[i] = f[i] * p[i];
idft(f, n);
for (int i = 0; i <= m; i++)
cout << (int) (f[i].x / n + 0.49) << " ";
return 0;
}

void dft(Complex *f, int len) {
if (len == 1)
return;
Complex *fl = f, *fr = f + len / 2;
for (int k = 0; k < len; k++)
sav[k] = f[k];
for (int k = 0; k < len / 2; k++) {
fl[k] = sav[k << 1];
fr[k] = sav[k << 1 | 1];
}
dft(fl, len / 2);
dft(fr, len / 2);
Complex tG = {cos(2 * Pi / len), sin(2 * Pi / len)};
Complex buf = {1, 0};
for (int k = 0; k < len / 2; k++) {
sav[k] = fl[k] + buf * fr[k];
sav[k + len / 2] = fl[k] - buf * fr[k];
buf = buf * tG;
}
for (int k = 0; k < len; k++)
f[k] = sav[k];
}

void idft(Complex *f, int len) {
if (len == 1)
return;
Complex *fl = f, *fr = f + len / 2;
for (int k = 0; k < len; k++)
sav[k] = f[k];
for (int k = 0; k < len / 2; k++) {
fl[k] = sav[k << 1];
fr[k] = sav[k << 1 | 1];
}
idft(fl, len / 2);
idft(fr, len / 2);
Complex tG = {cos(2 * Pi / len), -sin(2 * Pi / len)};
Complex buf = {1, 0};
for (int k = 0; k < len / 2; k++) {
sav[k] = fl[k] + buf * fr[k];
sav[k + len / 2] = fl[k] - buf * fr[k];
buf = buf * tG;
}
for (int k = 0; k < len; k++)
f[k] = sav[k];
}

高精度乘法-FFT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <iostream>
#include <cmath>
#include <cstring>

const double Pi = acos(-1);
const int MAX = 4000005;
using namespace std;
typedef long long ll;

struct Complex {
double x, y;

Complex operator+(const Complex &b) const {
return {x + b.x, y + b.y};
}

Complex operator-(const Complex &b) const {
return {x - b.x, y - b.y};
}

Complex operator*(const Complex &b) const {
return {x * b.x - y * b.y, x * b.y + y * b.x};
}
} f[MAX], p[MAX], sav[MAX];

ll ans[MAX];
void dft(Complex *f, int len);

void idft(Complex *f, int len);

int main() {
char a[MAX], b[MAX];
scanf("%s%s", a, b);
int n = strlen(a);
int m = strlen(b);
for(int i = 0; i < n; i++)
f[i].x = a[n - i - 1] - '0';
for(int i = 0; i < m; i++)
p[i].x = b[m - i - 1] - '0';
for (m += n, n = 1; n <= m; n <<= 1);
dft(f, n);
dft(p, n);
for (int i = 0; i < n; i++)
f[i] = f[i] * p[i];
idft(f, n);
for (int i = 0; i <= m; i++)
ans[i] = (ll) (f[i].x / n + 0.49);
for(int i = 0; i < MAX; i++){
ans[i + 1] += (ans[i] / 10);
ans[i] %= 10;
}
int t = MAX - 1;
while (ans[t] == 0)
t--;
while (t >= 0)
cout << ans[t--];
cout << endl;
return 0;
}

void dft(Complex *f, int len) {
if (len == 1)
return;
Complex *fl = f, *fr = f + len / 2;
for (int k = 0; k < len; k++)
sav[k] = f[k];
for (int k = 0; k < len / 2; k++) {
fl[k] = sav[k << 1];
fr[k] = sav[k << 1 | 1];
}
dft(fl, len / 2);
dft(fr, len / 2);
Complex tG = {cos(2 * Pi / len), sin(2 * Pi / len)};
Complex buf = {1, 0};
for (int k = 0; k < len / 2; k++) {
sav[k] = fl[k] + buf * fr[k];
sav[k + len / 2] = fl[k] - buf * fr[k];
buf = buf * tG;
}
for (int k = 0; k < len; k++)
f[k] = sav[k];
}

void idft(Complex *f, int len) {
if (len == 1)
return;
Complex *fl = f, *fr = f + len / 2;
for (int k = 0; k < len; k++)
sav[k] = f[k];
for (int k = 0; k < len / 2; k++) {
fl[k] = sav[k << 1];
fr[k] = sav[k << 1 | 1];
}
idft(fl, len / 2);
idft(fr, len / 2);
Complex tG = {cos(2 * Pi / len), -sin(2 * Pi / len)};
Complex buf = {1, 0};
for (int k = 0; k < len / 2; k++) {
sav[k] = fl[k] + buf * fr[k];
sav[k + len / 2] = fl[k] - buf * fr[k];
buf = buf * tG;
}
for (int k = 0; k < len; k++)
f[k] = sav[k];
}

KMP 字符串匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <vector>
#include <string>

using namespace std;

vector<int> prefix(string str);

int main(){
string text;
string key;
cin >> text;
cin >> key;
int kl = key.length();
vector<int> kmp = prefix(key);
int k = 0;
for(int i = 0; i < text.length(); i++){
while (k && key[k] != text[i])
k = kmp[k - 1];
if(text[i] == key[k])
k++;
if(k == kl)
cout << i - k + 2 << endl;
}
for(auto x: kmp)
cout << x << " ";
return 0;
}
vector<int> prefix(string str){
int l = (int) str.length();
vector<int> pre(l);
for(int i = 1; i < l; i++){
int j = pre[i - 1];
while (j && str[j] != str[i])
j = pre[j - 1];
if(str[j] == str[i])
j++;
pre[i] = j;
}
return pre;
}

其它

快速幂取余

1
2
3
4
5
6
7
8
9
10
ll fast_pow_mod(ll a, ll b, ll m){
a %= m;
ll res = 1;
while (b > 0) {
if (b & 1) res = res * a % m;
a = a * a % m;
b >>= 1;
}
return res;
}

快速打质数表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
vector<int> generate_prime_list(int n) {
if (n <= 2)
return vector<int>{2};
if (n <= 3)
return vector<int>{2, 3};
if (n <= 5)
return vector<int>{2, 3, 5};
vector<int> prime_list = {2, 3, 5};
int i = 1;
int x;
while (true) {
x = 6 * i + 1;
if (x > n)
break;
if (is_prime(x, prime_list))
prime_list.push_back(x);
x = 6 * i + 5;
if (x > n)
break;
if (is_prime(x, prime_list))
prime_list.push_back(x);
i++;
}
return prime_list;
}

bool is_prime(int x, const vector<int> &prime_list) {
for(auto u: prime_list){
if(x % u == 0)
return false;
if(u * u > x)
return true;
}
return false;
}

鸣谢

  • 首先感谢能看到这里的读者,若您能从本篇文章获得或多或少的帮助都将是作者的荣幸
  • 还要感谢我的算法老师黄坚、罗川老师,他们生动的课堂让我在疲惫的早八仍然能保持良好的睡眠质量,为我的算法练习养精蓄锐
  • 另外感谢拼命捞我的宋友老师、Marvolo助教和Matrix53助教,在他们的帮助下我才能取得大学以来首个满分
  • 感谢所有负责出题、讲题的算法助教,在他们的帮助下我的代码水平才能在练习和学习中提高
  • 感谢教我过做题的xjc、pyy、wyq同学,简单的一句话便能点醒我的思路
  • 感谢所有我看过的教程博客:
    • https://www.runoob.com/cplusplus/cpp-tutorial.html
    • https://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5
    • https://oi-wiki.org/
    • https://www.luogu.com.cn/blog/hkr04/wang-lao-liu-dinic
    • https://blog.csdn.net/sugarbliss/article/details/86495945
    • https://www.cnblogs.com/LiGuanlin1124/category/1399603.html
    • https://www.luogu.com.cn/blog/command-block/fft-xue-xi-bi-ji
    • https://www.luogu.com.cn/problem/solution/P3375
    • https://www.luogu.com.cn/problem/solution/P1226

C++算法板子积累
https://onlyar.site/2022/01/24/Cpp-template/
作者
Only(AR)
发布于
2022年1月24日
许可协议