BUAA_C++算法板子积累_动态规划、图算法、计算几何、FFT
2022-01-24 00:00
591 查看
Hello
#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>
__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>
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>
/*----- 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>
s.top() // 访问栈顶 s.empty() // 栈是否空 s.size() // 大小 s.push(item) // item 入栈 s.emplace(item) // item 替换栈顶 s.pop() // 出栈
<set>
/*----- 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>
/*----- map -----*/ /*----- mulmap -----*/
<unordered_set>
/*----- unordered_set -----*/ /*----- unordered_multiset -----*/
<unordered_map>
/*----- unordered_map -----*/ /*----- unordered_multimap -----*/
分治
逆序对计数
#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 背包
#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; }
完全背包
#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; }
分组背包
#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]; }
最大子列和
#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 最长公共子序列
#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); }
最小编辑距离
#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; }
最长单调子序列
// 严格单调递增子列的长度 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(); }
图算法
链式前向星
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 最短路(标准版)
#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 最短路(堆优化)
#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 最短路
#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 最小生成树
#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 拓扑排序
#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 最大流
#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; }
二分图匹配
#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; }
计算几何
线段相交计数
#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; 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; } bool intersect(Line l1, Line l2) { int d1 = (l1.q - l1.p) ^ (l2.p - l1.p); int d2 = (l1.q - l1.p) ^ (l2.q - l1.p); int d3 = (l2.q - l2.p) ^ (l1.p - l2.p); int d4 = (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 凸包 + 旋转卡壳
#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
#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
#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 字符串匹配
#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; }
其它
快速幂取余
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; }
快速打质数表
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
相关文章推荐
- HDU5572(2015ACM/ICPC亚洲区上海站A题)_计算几何(积累计算几何的板子)
- SGU315 The Highway Belt【计算几何+动态规划】
- poj1259 The picnic【最大空凸包详解 计算几何+动态规划】
- 【算法学习笔记】52.一道题的三种方法..二分答案、动态规划、计算几何 SJTU OJ 1250 BestSubsequence
- 板子:计算几何
- 【计算几何】Buaacoding1082 AlvinZH的学霸养成记VI
- 蓝桥杯 算法提高 12-1三角形 【计算几何_三角形】【全是板子】
- [计算几何]一些模型的积累
- 计算几何题目积累
- Gym 100952J&&2015 HIAST Collegiate Programming Contest J. Polygons Intersection【计算几何求解两个凸多边形的相交面积板子题】
- 计算几何常用算法【ACM 】
- 【笔记篇】最良心的计算几何学习笔记(六)
- Ural-1084. Goat in the Garden(计算几何)
- bzoj 1043 下落的圆盘(计算几何-圆的周长并)
- [POJ2826]An Easy Problem?!(计算几何-细节/距离)
- POJ 2398 Toy Storage 计算几何(点与直线的关系)
- 计算几何_模板
- 博弈树,动态规划(计算好的子问题存储起来,以后直接取用)
- sgu209:Areas(计算几何)
- Kuangbin 带你飞-基础计算几何专题 题解