#include<iostream> usingnamespace std; constint N = 1e6 + 10;
int n; int q[N];
voidquick_sort(int q[], int l, int r)//*q也是正确的 { if (l >= r) return; //判断边界,当然l == r也是可以的,看个人习惯
int x = q[(l + r) / 2], i = l - 1, j = r + 1; //取分界点 while (i < j) { do i++ ; while (q[i] < x);//向右找>=x的数 do j-- ; while (q[j] > x);//向左找<=x的数 if (i < j) swap(q[i], q[j]); /*swap函数等效 if (i < j) { int t = q[i]; q[i] = q[j]; q[j] = t; } */ }
#include<iostream> usingnamespace std; constint N = 100010; int n; int q[N], tmp[N];
voidmerge_sort(int q[], int l, int r) { if (l >= r) return; int mid = l + r >> 1; merge_sort(q, l, mid), merge_sort(q, mid + 1, r); int k = 0, i = l, j = mid + 1; while (i <= mid && j <= r) if (q[i] <= q[j]) tmp[k++] = q[i++]; else tmp[k++] = q[j++]; while (i <= mid) tmp[k++] = q[i++]; while (j <= r) tmp[k++] = q[j++]; for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j]; }
intmain() { scanf("%d", &n); for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]); merge_sort(q, 0, n - 1); for (int i = 0; i < n; i ++ ) printf("%d ", q[i]); return0; }
是稳定的
易错点
注意边界i=l而不是i=0
注意函数名的定义sort() 这个函数和 std::sort() 冲突
1.2.2.逆序对个数
int n,a[500010],b[500010]; longlong res;
voidmerge(int l,int r){ if(l>=r) return; int mid=l+r>>1; merge(l,mid); merge(mid+1,r);
// C = 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; } if (t) C.push_back(t); return C; } intmain() { string a, b; vector<int> A, B;
cin >> a >> b; // a = "123456" for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0'); // A = [6, 5, 4, 3, 2, 1] for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');
auto C = add(A, B); // 等价于vector<int> C = add(A, B);
for (int i = C.size() - 1; i >= 0; i -- ) printf("%d", C[i]); return0; }
或者
// C = A + B, A >= 0, B >= 0 vector<int> add(vector<int> &A, vector<int> &B) { if (A.size() < B.size()) returnadd(B, A);
vector<int> C; int t = 0; for (int i = 0; i < A.size(); i ++ ) { t += A[i]; if (i < B.size()) t += B[i]; C.push_back(t % 10); t /= 10; }
if (t) C.push_back(t); return C; }
3.2.高精度减法
#include<iostream> #include<vector>
usingnamespace std;
// 判断是否有 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; }
// C = A - B vector<int> sub(vector<int> &A, vector<int> &B){ vector<int> C; for (int i = 0, t = 0; i < A.size(); i++) { t = A[i] - t; if (i < B.size()) t -= B[i]; C.push_back((t + 10) % 10); if (t < 0) t = 1; else t = 0; } while (C.size() > 1 && C.back() == 0) C.pop_back(); // 如果条件为C.size()>0,虽然实现“形如003pop掉前两个0”的效果但是对于答案是0的情况下就会出错 // C.size()>1则保留至少一个元素(即不会移除全部元素) return C; }
intmain(){ string a, b; vector<int> A, B;
cin >> a >> b; // a = "123456" for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0'); // A = [6, 5, 4, 3, 2, 1] 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--) printf("%d", C[i]); } else { auto C = sub(B, A); printf("-"); for (int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]); } return0; }
或者
// C = A - B, 满足A >= B, A >= 0, B >= 0 vector<int> sub(vector<int> &A, vector<int> &B) { vector<int> C; for (int i = 0, t = 0; i < A.size(); i ++ ) { t = A[i] - t; if (i < B.size()) t -= B[i]; C.push_back((t + 10) % 10); if (t < 0) t = 1; else t = 0; }
// C = A * b, A >= 0, b >= 0, len(A) <= 1e6, b <= 1e6 #include<iostream> #include<vector>
usingnamespace std;
vector<int> mul(vector<int> &A, int b){ vector<int> C;
int t = 0; for (int i = 0; i < A.size() || t; i++) { // 注意t非0则需要继续循环,可能会出现进大于一位数的情况(例如:2*120=240,进位为24) if (i < A.size()) t += A[i] * b; C.push_back(t % 10); t /= 10; }
return C; }
intmain(){ string a; int b; cin >> a >> b;
vector<int> A; for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
auto C = mul(A, b);
for (int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
return0; }
或者
// C = A * b, A >= 0, b >= 0, len(A) <= 1e6, b <= 1e6 vector<int> mul(vector<int> &A, int b) { vector<int> C;
int t = 0; for (int i = 0; i < A.size() || t; i ++ ) { if (i < A.size()) t += A[i] * b; C.push_back(t % 10); t /= 10; }
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C; }
3.4.高精度除法
// A / b = C ... r, A >= 0, b > 0, len(A) <= 1e6, b <= 1e6 #include<iostream> #include<algorithm> #include<vector>
usingnamespace std;
vector<int> div(vector<int> &A, int b, int &r){ vector<int> C; r = 0; for (int i = A.size() - 1; i >= 0; i--) { r = r * 10 + A[i]; C.push_back(r / b); r %= b; } reverse(C.begin(), C.end()); while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; }
intmain(){ string a; int b; cin >> a >> b;
vector<int> A; for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
int r; auto C = div(A, b, r);
for (int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]); cout << endl << r << endl;
return0; }
或者
// A / b = C ... r, A >= 0, b > 0, len(A) <= 1e6, b <= 1e6 vector<int> div(vector<int> &A, int b, int &r) { vector<int> C; r = 0; for (int i = A.size() - 1; i >= 0; i -- ) { r = r * 10 + A[i]; C.push_back(r / b); r %= b; } reverse(C.begin(), C.end()); while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; }
#include<iostream> usingnamespace std; constint N = 100010;
int n, m; int a[N], b[N];
voidinsert(int l, int r, int c) { b[l] += c; b[r + 1] -= c; }
intmain() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]); for (int i = 1; i <= n; i ++ ) insert(i, i, a[i]); // 初始插入,初始化差分矩阵的前缀和
while (m -- ) { int l, r, c; scanf("%d%d%d", &l, &r, &c); insert(l, r, c); }
for (int i = 1; i <= n; i ++ ) b[i] += b[i - 1];
for (int i = 1; i <= n; i ++ ) printf("%d ", b[i]);
for (int i = 0; i < n; i ++ ){ for (int j = 0; j < n; j ++ ){ } }
将上面的朴素算法(时间复杂度为 O(n^2))优化到O(n)
5.1.示例代码
题目:输入一个字符串,请你把每一个单词单独输出并每个单词占单独一行
例如,输入“An apple a day, keeps the doctor away.”,
输出:
An
apple
……
#include<iostream> #include<string.h>
usingnamespace std;
intmain(){ char str[1000]; gets(str); int n = strlen(str);
for (int i = 0; i < n; i++) { int j = i; while (j < n && str[j] != ' ') j++; // 这道题的具体逻辑 for (int k = i; k < j; k++) cout << str[k]; cout << endl; i = j; } return0; }
5.2.示例代码
最长连续不重复子序列
给定一个长度为n的整数序列,请找出最长的不包含重复数字的连续子序列,输出它的长度。
输入格式
第一行包含整数n。
第二行包含n个整数(均在0~100000范围内),表示整数序列。
输出格式
共一行,包含一个整数,表示最长的不包含重复数字的连续子序列的长度。
数据范围:1 ≤ n ≤ 100000
输入样例: 5 1 2 2 3 5
输出样例: 3
#include<iostream> usingnamespace std; constint N = 100010;
int n; int a[N], s[N];
intmain() { cin >> n; for (int i = 0; i < n; i ++ ) cin >> a[i]; int res = 0; for (int i = 0, j = 0; i < n; i ++ ) { s[a[i]] ++ ; while (s[a[i]] > 1) { s[a[j]] -- ; j ++ ; } res = max(res, i - j + 1); } cout << res << endl;
return0; }
6.位运算
6.1.求n的第k位数字:
n >> k & 1
先把第k位移动到最后一位,右移k位
然后只要求得到k位的话,与1做与运算
6.2.返回n的最后一位1
lowbit(n) = n & -n(二进制的负数是原数的补码,也就是取反加一,即`-n=~n+1`)
提取 x 的最低有效位(Least Significant Bit, LSB)中为 1 的那一位
(101000)返回(1000)
6.3.示例代码
二进制中1的个数
给定一个长度为n的数列,请你求出数列中每个数的二进制表示中1的个数。
输入格式
第一行包含整数n。
第二行包含n个整数,表示整个数列。
输出格式
共一行,包含n个整数,其中的第 i 个数表示数列中的第 i 个数的二进制表示中1的个数。
数据范围
1 ≤ n ≤ 100000,
0 ≤ 数列中元素的值 ≤ 10^9
输入样例: 3 1 2 3 4 5
输出样例: 1 1 2 1 2
#include<iostream>
usingnamespace std;
intlowbit(int x){ return x & -x; }
intmain(){ int n; cin >> n; while (n--) { int x; cin >> x;
int res = 0; while (x) x -= lowbit(x), res++; // 每次减去x的最后一位1
// 二分求出x对应的离散化的值 intfind(int x)// 找到第一个大于等于x的位置 { int l = 0, r = alls.size() - 1; while (l < r) { int mid = l + r >> 1; if (alls[mid] >= x) r = mid; else l = mid + 1; } return r + 1; // 映射到1, 2, ...n,不加1的话映射到0,1,2,…… }
7.1.示例代码(前缀和+离散化)
区间和
假定有一个无限长的数轴,数轴上每个坐标上的数都是0。现在,我们首先进行 n 次操作,每次操作将某一位置x上的数加c。近下来,进行 m 次询问,每个询问包含两个整数l和r,你需要求出在区间[l, r]之间的所有数的和。
usingnamespace std; typedef pair<int, int> PII; constint N = 300010; int n, m; int a[N], s[N]; vector<int> alls; vector<PII> add, query;
intfind(int x){ int l = 0, r = alls.size() - 1; while (l < r) { int mid = l + r >> 1; if (alls[mid] >= x) r = mid; else l = mid + 1; } return r + 1; }
intmain(){ cin >> n >> m; for (int i = 0; i < n; i++) { int x, c; cin >> x >> c; add.push_back({x, c}); alls.push_back(x); } for (int i = 0; i < m; i++) { int l, r; cin >> l >> r; query.push_back({l, r});
int st = -2e9, ed = -2e9; for (auto seg: segs) if (ed < seg.first) { if (st != -2e9) res.push_back({st, ed}); st = seg.first, ed = seg.second; } else ed = max(ed, seg.second);
int st = -2e9, ed = -2e9; for (auto seg: segs) if (ed < seg.first) { if (st != -2e9) res.push_back({st, ed}); st = seg.first, ed = seg.second; } else ed = max(ed, seg.second);
if (st != -2e9) res.push_back({st, ed});
segs = res; } intmain(){ cin >> n; for (int i = 0; i < n; i++) { int l, r; cin >> l >> r; segs.push_back({l, r}); } merge(segs); cout << segs.size() << endl; return0; }