目录
1.快速排序
①确定分界点 q[l] q[(l+r)/2] q[r] ★
②调整区间 下标i j 分别从两边遍历
③递归处理左右两段
#include <iostream>
using namespace std;
const int N = 1e6+10;
int n;
int q[N];
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int x = q[l], i = l-1, j = r+1;
while(i < j)
{
do i++; while(q[i] < x);
do j--; while(q[j] > x);
if(i < j) swap(q[i],q[j]);
}
quick_sort(q, l, j);
quick_sort(q, j+1, r);
}
int main()
{
scanf("%d",&n);
for(int i = 0; i < n; i++) scanf("%d",&q[i]);
quick_sort(q, 0, n-1);
for(int i = 0; i < n; i++) printf("%d ",q[i]);
return 0;
}
2.归并排序
①确定分界点 mid = (l+r)/2
②递归排序left right 左右两个数组
③归并排序 合二为一 ★
#include <iostream>
using namespace std;
const int N = 1e6+10;
int n;
int q[N], tmp[N];
void merge_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, k = 0; i <= r; i++, k++) q[i] = tmp[k];
}
int main()
{
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]);
return 0;
}
3.整数二分
① mid = l + r + 1 / 2
x在 l 和 mid 之间 则 r = mid-1 [l, mid - 1];
x在 mid 和 r 之间 则 l = mid [mid, r];
// 区分[l, r]被划分成[l, mid]和[mid + 1, r]时使用
#include <iostream>
using namespace std;
int bsearch_1(int q[], int size, int target)
{
int l = 0, r = size - 1;
while(l < r)
{
int mid = l + r >> 1;
if(q[mid] >= target) r = mid;
else l = mid + 1;
}
if(q[l] != target) return -1;
return l;
}
// 区分[l, r]被划分成[l, mid-1]和[mid, r]时使用
int bsearch_2(int q[], int size, int target)
{
int l = 0, r = size - 1;
while(l < r)
{
int mid = l + r + 1 >> 1;
if(q[mid] <= target) l = mid;
else r = mid - 1;
}
if(q[l] != target) return -1;
return l;
}
4.浮点数二分
double bsearch_f(double q[], int size, double target)
{
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求
int l = 0, r = size - 1;
while (r - l > eps) // 两种写法:此时是用精度控制循环次数,直接控制循环100次也是OK的!
{
int mid = (l + r) / 2;
if (q[mid] >= target) r = mid;
else l = mid + 1;
}
if(q[l] != target) return -1;
return l;
}
5.高精度
高精度整数 比较大的数 A B 10^6位
①大整数存储
②运算
A + B 位数 10^6位
A - B 位数 10^6位
A * a len(A) <=10^6 a <= 10^9
A / a
高精度正整数加法:
#include <iostream>
#include <vector>
using namespace std;
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(1);
return C;
}
int main()
{
string a, b;
vector<int> 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');
auto C = add(A, B);
for(int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
return 0;
}
高精度正整数减法:
#include <iostream>
#include <vector>
using namespace std;
// 判断A是不是大于B
bool cmp(vector<int> &A, vector<int> &B)
{
if(A.size() != B.size()) return A.size() > B.size();
for (int i = 0; i < A.size(); i++)
{
if(A[i] != B[i]) return A[i] > B[i];
}
return true;
}
// 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(); // 去掉前导0 答案为007此情况
return C;
}
int main()
{
string a, b;
vector<int> 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--) printf("%d", C[i]);
}
else
{
auto C = sub(B, A);
printf("-");
for(int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
}
return 0;
}
高精度正整数乘法:
#include <iostream>
#include <vector>
using namespace std;
// C = A * b
vector<int> mul(vector<int> &A, int b)
{
vector<int> C;
int t = 0;
for (int i = 0, t = 0; i < A.size() || t; i++)
{
if(i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
return C;
}
int main()
{
string a;
vector<int> A;
int b;
cin >> a >> b;
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]);
return 0;
}
高精度正整数除法:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// C = A / b 商 C 余数r
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;
}
int main()
{
string a;
vector<int> A;
int b;
cin >> a >> b;
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;
return 0;
}
6.前缀和
数组an a1 a2 ... an
前缀和 Si = a1 + a2 + ... + ai
①如何求
②作用
// 一维数组前缀和的计算
#include <iostream>
using namespace std;
const int N = 100010;
int a[N], s[N];
int n, m;
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++) s[i] = s[i - 1] + a[i]; // 前缀和的初始化
while(m --)
{
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", s[r] - s[l - 1]); // 区间和的计算
}
return 0;
}
// 二位数组矩阵前缀和计算
#include <iostream>
using namespace std;
const int N = 1010;
int n, m, q;
int a[N][N], s[N][N];
int main()
{
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
scanf("%d", &a[i][j]);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];
while(q--)
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
printf("%d\n", s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1]);
}
return 0;
}
7.差分(前缀和的逆运算):
数组 a1 a2 ... an 前缀
构造 b1 b2 ... bn 差分
使得 ai = b1 + b2 + ... + bi
即 b1 = a1 b2 = a2 - a1 b3 = a3 - a2 ... bn = an- an-1
an 是 bn 的前缀和, bn 是 an 的差分
// 一维数组差分
// 输入一个数组和执行数 执行 给序列l~r的每个数加上c
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int a[N], b[N];
void insert(int l, int r, int c)
{
b[l] += c;
b[r+1] -= c;
}
int main()
{
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]);
return 0;
}
// 二维数组差分
// 输入一个二维数组和执行数 执行 给序列x1 y1 ~ x2 y2的每个数加上c
#include <iostream>
using namespace std;
const int N = 1010;
int n, m, t;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c)
{
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
int main()
{
scanf("%d%d%d", &n, &m, &t);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
scanf("%d", &a[i][j]);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
insert(i, j, i, j, a[i][j]);
while(t--)
{
int x1, y1, x2, y2, c;
cin >> x1 >> y1 >> x2 >> y2 >> c;
insert(x1, y1, x2, y2, c);
}
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
b[i][j] += b[i-1][j] + b[i][j-1] -b[i-1][j-1];
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++) cout << b[i][j] << " ";
cout << endl;
}
return 0;
}
8.双指针算法:
例题:输入一个字符串,将里面的每一个单词 各占一行打印出来
#include <iostream>
#include <string.h>
using namespace std;
const int N = 1000;
int main()
{
char str[N];
cin.getline(str,N);
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;
}
return 0;
}
例题:给定一个长度为n的整数序列,请找出最长的不包含重复数字的连续子序列,输出它的长度。
#include <iostream>
using namespace std;
const int N = 100010;
int n, a[N], s[N];
int main()
{
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;
return 0;
}
9.位运算:
n的二进制表示 第k位 是 几
①先把第k位移到最后一位: n >> k
②看个位是几: & 1
n >> k & 1
--------------
lowbit(x) :返回x的最后一位1 是多少 例如 1010 ---> 10, 101000 --->1000
实现 : x & -x = x & (~x + 1)
例: 输入一个数组返回数组中每个元素二进制形式中1的个数
#include <iostream>
using namespace std;
int lowbit(int x)
{
return x & -x;
}
int main()
{
int n;
cin >> n;
while(n --)
{
int x ;
cin >> x;
int res = 0;
while(x) x-= lowbit(x), res++;
cout << res << " ";
}
return 0;
}
10.离散化:
vector <int> alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值进行排序
alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 去除重复元素
// 二分求出x对应的离散化的值
int find(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
}
例题: 输入一个数组长度和操作数,操作:x c 将数组a[x] = c,输入l,r ,输出a[l]+ ...+a[r]的和
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int ,int> PII;
const int N = 300010;
int n, m;
int a[N], s[N];
vector<int> alls;
vector<PII> add, query;
int find(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;
}
int main()
{
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});
alls.push_back(l);
alls.push_back(r);
}
// 去重
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
for(auto item : add) // 插入操作
{
int x = find(item.first);
a[x] += item.second;
}
// 预处理前缀和
for(int i = 1; i <= alls.size(); i ++) s[i] = s[i - 1] + a[i];
// 处理询问
for(auto item : query)
{
int l = find(item.first), r = find(item.second);
cout << s[r] - s[l - 1] << endl;
}
return 0;
}
11.区间和并
例题:输入n 接下来的n行,每行输入两个整数l和r,比如2 4 则表示 2 3 4 这个区间,输出合并后的区间的个数。
①按区间左端点排序;②扫描整个区间,扫描过程中 进行分类合并
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 100010;
void merge(vector<PII> &segs)
{
vector<PII> res;
sort(segs.begin(), segs.end());
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;
}
int n;
vector<PII> segs;
int main()
{
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;
return 0;
}
1296

被折叠的 条评论
为什么被折叠?



