#include<bits/stdc++.h> usingnamespace std; constint N = 1e5 + 10;
int a[N];
voidquick_sort(int a[], int l, int r) { // l >= r 终止防止无限递归 if (l >= r) return;
// 由于用的是do-while循环,开始时i和j会先移动,因此初始化时i和j要比区间端点更靠外1位 int i = l - 1, j = r + 1, x = a[(l + r)>> 1]; while (i < j) { do{i++;} while(a[i] < x); do{j--;} while(a[j] > x); if (i < j) swap(a[i], a[j]); } // 由于j的循环逻辑,只有遇到a[j] <= x时才会停下,因此 j+1 到 r 全部 >= x,因此递归l到j和j+1到r即可
#include<bits/stdc++.h> usingnamespace std; constint N = 1e5 + 9;
int a[N];
intquick_sort(int a[], int l, int r, int k) { if (l >= r) return a[l]; int i = l - 1, j = r + 1, x = a[l + r >> 1]; while (i < j) { do{i++;} while(a[i] < x); do{j--;} while(a[j] > x); if (i < j) swap(a[i], a[j]); }
// 左半部分区间长度为 j - l + 1 if (j - l + 1 >= k) returnquick_sort(a, l, j, k);
// 如果在右半部分,k 也要对应减少左半部分的长度 returnquick_sort(a, j + 1, r, k - (j - l + 1)); }
intmain() { int n, k; cin >> n >> k; for (int i = 1; i <= n; i++) cin >> a[i]; cout << quick_sort(a, 1, n, k) << '\n'; return0; }
#include<bits/stdc++.h> usingnamespace std; constint N = 1e5 + 9;
int a[N], tmp[N];
voidmerge_sort(int a[], int l, int r) { if (l >= r) return; int mid = l + r >> 1; merge_sort(a, l, mid); merge_sort(a, mid + 1, r); int i = l, j = mid + 1, k = l; while (i <= mid && j <= r) { if (a[i] <= a[j]) tmp[k++] = a[i++]; else tmp[k++] = a[j++]; } while (i <= mid) tmp[k++] = a[i++]; while (j <= r) tmp[k++] = a[j++]; for (int i = l; i <= r; i++) a[i] = tmp[i]; }
intmain() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; merge_sort(a, 1, n); for (int i = 1; i <= n; i++) cout << a[i] << ' '; return0; }
ll merge_sort(int a[], int l, int r) { if (l >= r) return0; int mid = l + r >> 1; // 计算左右两部分单独的逆序对数量 ll res = merge_sort(a, l, mid) + merge_sort(a, mid + 1, r); int i = l, j = mid + 1, k = l;
// 排序+计算横跨两部分的逆序对数量 while (i <= mid && j <= r) { if (a[i] <= a[j]) tmp[k++] = a[i++]; else { tmp[k++] = a[j++]; res += mid - i + 1; } } while (i <= mid) tmp[k++] = a[i++]; while (j <= r) tmp[k++] = a[j++]; for (int i = l; i <= r; i++) a[i] = tmp[i]; return res; }
intmain() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; cout << merge_sort(a, 1, n); return0; }
二分
数的范围
题干
给定一个按照升序排列的长度为 的整数数组,以及 个查询。
对于每个查询,返回一个元素 的起始位置和终止位置(位置从 开始计数)。
如果数组中不存在该元素,则返回 -1 -1。
输入格式
第一行包含整数 和 ,表示数组长度和询问个数。
第二行包含 个整数(均在 范围内),表示完整数组。
接下来 行,每行包含一个整数 ,表示一个询问元素。
输出格式
共 行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回 -1 -1。
数据范围
输入样例:
1 2 3 4 5
6 3 1 2 2 3 3 4 3 4 5
输出样例:
1 2 3
3 4 5 5 -1 -1
思路分析
本题需要找到一个数在有序数组中的起始位置和终止位置,可以使用二分查找来实现。由于二分查找每次只能找到一个位置,因此需要分别进行两次二分查找:一次查找起始位置,一次查找终止位置。记住二分查找的模板即可,临界条件是l + 1 == r,也就是说结束时l和r其中一个会满足临界条件。以if (a[mid] < x) l = mid; else r = mid;为例,每次更新的l都是小于x的,r都是大于等于x的,因此最后结束时l,r相邻,得到l是最大的小于x的数,r是最小的大于等于x的数。
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, q; cin >> n >> q; for (int i = 1; i <= n; i++) cin >> a[i]; while (q--) { int x; cin >> x; int l = 0, r = n + 1; while (l + 1 != r) { int mid = l + r >> 1; if (a[mid] < x) l = mid; else r = mid; } if (a[r] == x) cout << r - 1 << ' '; else cout << -1 << ' '; l = 0, r = n + 1; while (l + 1 != r) { int mid = l + r >> 1; if (a[mid] <= x) l = mid; else r = mid; } if (a[l] == x) cout << l - 1 << endl; else cout << -1 << endl; } }
#include<bits/stdc++.h> usingnamespace std; using ll = longlong; constint N = 1e5 + 9;
vector<int> A, B;
vector<int> add(vector<int> &A, vector<int> &B) { vector<int> C; int t = 0; for (int i = 0; i < A.size() || i < B.size(); i++) { if (i < A.size()) t += A[i]; if (i < B.size()) t += B[i]; C.push_back(t % 10); t /= 10; } while (t) { C.push_back(t % 10); t /= 10; } while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); string a, b; cin >> a >> b; for (int i = a.size() - 1; i >= 0; i--) A.push_back(int(a[i] - '0')); for (int i = b.size() - 1; i >= 0; i--) B.push_back(int(b[i] - '0')); auto C = add(A, B); for (int i = C.size() - 1; i >= 0; i--) cout << C[i]; }
#include<bits/stdc++.h> usingnamespace std; using ll = longlong; constint N = 1e5 + 9;
vector<int> A, B;
boolcmp(vector<int> &A, vector<int> &B) { if (A.size() != B.size()) return A.size() > B.size(); for (int i = A.size() - 1; i >= 0; i--) if (A[i] != B[i]) return A[i] > B[i]; returntrue; }
vector<int> sub(vector<int> &A, vector<int> &B) { vector<int> C; int t = 0; for (int i = 0; i < A.size(); i++) { t += A[i]; if (i < B.size()) t -= B[i]; if (t >= 0) { C.push_back(t); t = 0; } else { C.push_back(t + 10); t = -1; } } while (t) { C.push_back(t % 10); t /= 10; } while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); string a, b; cin >> a >> b; for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0'); for (int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
if (cmp(A, B)) { auto C = sub(A, B); for (int i = C.size() - 1; i >= 0; i--) cout << C[i]; } else { auto C = sub(B, A); cout << '-'; for (int i = C.size() - 1; i >= 0; i--) cout << C[i]; } }
高精度乘法
题干
给定两个非负整数(不含前导 ) 和 ,请你计算 的值。
输入格式
共两行,第一行包含整数 ,第二行包含整数 。
输出格式
共一行,包含 的值。
数据范围
,
输入样例:
1 2
2 3
输出样例:
1
6
思路分析
仿照高精度加法的思路即可,将大整数从低位到高位逐位与小整数相乘,并处理进位。每次将 t % 10 存入结果数组,并将 t / 10 作为进位传递到下一位。
vector<int> mul(vector<int> &A, int &b) { vector<int> C; int t = 0; for (int i = 0; i < A.size(); i++) { t += A[i] * b; C.push_back(t % 10); t /= 10; } while (t) { C.push_back(t % 10); t /= 10; } while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); string a; int b; cin >> a >> b; for (int i = a.size() - 1; i >= 0; i--) A.push_back(int(a[i] - '0')); auto C = mul(A, b); for (int i = C.size() - 1; i >= 0; i--) cout << C[i]; }
高精度除法
题干
给定两个非负整数(不含前导 ) ,请你计算 的商和余数。
输入格式
共两行,第一行包含整数 ,第二行包含整数 。
输出格式
共两行,第一行输出所求的商,第二行输出所求余数。
数据范围
, , 一定不为
输入样例:
1 2
7 2
输出样例:
1 2
3 1
思路分析
与之前的三种计算都不同,除法需要从高位到低位进行计算。我们可以用 t 记录当前的余数,然后从高到低遍历。每次进入到下一位时,将 t 乘以 10 并加上当前位的数字,然后计算当前位的商 t / b 并将其存入结果数组中,最后更新余数 t % b。
#include<bits/stdc++.h> usingnamespace std; constint N = 1e5 + 9;
int a[N]; int prefix[N]; intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) prefix[i] = prefix[i - 1] + a[i]; while (m--) { int l, r; cin >> l >> r; cout << prefix[r] - prefix[l - 1] << '\n'; } }
#include<bits/stdc++.h> usingnamespace std; constint N = 1e5 + 9;
int a[N]; int d[N];
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) d[i] = a[i] - a[i - 1]; while (m--) { int l, r, c; cin >> l >> r >> c; d[l] += c; d[r + 1] -= c; } for (int i = 1; i <= n; i++) { a[i] = a[i - 1] + d[i]; cout << a[i] << ' '; } }
#include<bits/stdc++.h> usingnamespace std; constint N = 1e5 + 9;
int a[N]; int b[N]; int n, m, x;
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m >> x; for (int i = 0; i < n; i++) cin >> a[i]; for (int i = 0; i < m; i++) cin >> b[i]; for (int i = 0, j = m - 1; i < n; i++) { while (a[i] + b[j] > x) j--; if (a[i] + b[j] == x) { cout << i << ' ' << j << '\n'; break; } } }
#include<bits/stdc++.h> usingnamespace std; using ll = longlong; constint N = 1e5 + 9;
int a[N]; int b[N]; int n, m;
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= m; i++) cin >> b[i]; int i = 1, j = 1; while (i <= n && j <= m) { if (a[i] == b[j]) { i++; j++; } else j++; } if (i == n + 1) cout << "Yes" << '\n'; else cout << "No" << '\n'; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; for (int i = 1; i <= n; i++) { int x; cin >> x; int res = 0; while (x) { x -= lowbit(x); res++; } cout << res << ' '; } }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) { int x, c; cin >> x >> c; X.push_back(x); add[i] = {x, c}; } for (int i = 1; i <= m; i++) { int l, r; cin >> l >> r; X.push_back(l), X.push_back(r); que[i] = {l, r}; } sort(X.begin(), X.end()); X.erase(unique(X.begin(), X.end()), X.end()); for (int i = 1; i <= n; i++) p[findx(add[i].first)] += add[i].second; for (int i = 1; i <= X.size(); i++) p[i] += p[i - 1]; for (int i = 1; i <= m; i++) { int l = findx(que[i].first), r = findx(que[i].second); cout << p[r] - p[l - 1] << '\n'; } }