for (int i = 0; i < n; i++)
for (int j = 1; j < n - i; j++)
if (a[j - 1] > a[j]) swap(a[j - 1], a[j]);
for (int i = 0; i < n - 1; i++) {
int loc = i;
for (int j = i + 1; j < n; j++) if (a[j] < a[loc]) loc = j;
swap(a[loc], a[i]);
}
for (int i = 1; i < n; i++)
for (int j = i - 1; j >= 0 && a[j] > a[j + 1]; j--)
swap(a[j], a[j + 1]);
- 确定分界点 x(a[l], a[r], a[mid], 随机)
- 调整区间(左边所有数 <= x,右边所有数 >= x)
- 浪费额外空间
- 开两个额外数组 b, c
- 扫描区间,对于 a[i] <= x,放进 b。a[i] >= x,放进 c
- 然后把 b 放进 a,再把 c 放进 a
- 优雅做法
- 两个指针 i,j,分别从两端开始,往中间走
- 如果 a[i] <= x i++,直到 a[i] >= x,i 停止(错位,应该放右边)
- 如果 a[j] >= x j--,知道 a[j] <= x,j 停止(错位,应该放左边)
- swap(a[i], a[j])
- 浪费额外空间
- 递归处理左右两段
void quick_sort(int a[], int l, int r) {
if (l >= r) return;
int x = a[l + (rand() % (r - l + 1))];
int i = l - 1, j = 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]);
}
quick_sort(a, l, j);
quick_sort(a, j + 1, r);
}
- 模板里为什么不写 quick_sort(a, l, i)
- 因为 i 出来的时候,指向的是一个 >= x 的数,所以得写
- quick_sort(a, l, i - 1)
- quick_sort(a, i, r)
- x 不能取 a[l],会死循环
- 1 2,i = 1,j = 0
- quick_sort(a, 0, -1); quick_sort(a, 0, 1);
- 因为 i 出来的时候,指向的是一个 >= x 的数,所以得写
- 确定分界点 mid = (l + r) / 2
- 递归排序左边和右边
- 归并(合二为一)
- 两个指针 i j,只想两个序列的开头
- 两个指针 较小值放进 第二个数组,指针往后移
- 把序列剩下的部分放进第二个数组
void merge_sort(int a[], int l, int r, int c[]) {
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(a, l, mid, c), merge_sort(a, mid + 1, r, c);
int i = l, j = mid + 1;
for (int k = l; k <= r; k++)
if (j > r || i <= mid && a[i] <= a[j]) c[k] = a[i++];
else c[k] = a[j++];
for (int k = l; k <= r; k++) a[k] = c[k];
}
在区间内,左半边不满足,右半边满足,寻找边界点。
- 寻找左边的右端点
- mid = l + r + 1 >> 1
- check(mid)
- true: l = mid
- false: r = mid - 1
- 寻找右边的左端点
- mid = l + r >> 1
- check(mid)
- true: r = mid
- false: l = mid + 1
int bsearch_1(int l, int r) {
while (l < r) {
int m = l + r + 1 >> 1;
if (check(m)) l = m;
else r = m - 1;
}
return l;
}
int bsearch_2(int l, int r) {
while (l < r) {
int m = l + r >> 1;
if (check(m)) r = m;
else l = m + 1;
}
return l;
}
- mid = (l + r) / 2;
- check(mid)
- true: l = mid
- false: r = mid
double bsearch_1(double l, double r) {
while (r - l > 1e-8) {
double m = (l + r) / 2;
if (check(m)) l = m;
else r = m;
}
return l;
}
double bsearch_2(double l, int double r) {
for (int i = 0; i < 100; i++) {
double m = (l + r) / 2;
if (check(m)) l = m;
else r = m;
}
return l;
}
模拟竖式
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;
}
- 比较两个数A,B的大小,让大的减去小的
- 做减法
- 去除前导0
bool cmp (const vector<int> & A, const 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];
return true;
}
vector<int> sub(const vector<int> & A, const vector<int> & B) {
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || i < B.size(); i++) {
t += A[i];
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();
return C;
}
- t += A[i] * b
- 把 t % 10,即最低位的结果放进答案
- t /= 10,t 舍弃最低位
- 最后需要去除前导0
vector<int> mul(const 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;
}
- 每次从最大位开始,取一个,整除 b
- 结果放进答案,余数再对 b 取余
- 最后把结果反过来,因为我们的存储格式应该是低位在前
- 去前导0
vector<int> div(const 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;
}
利用大数和大数的加法,以及大数和小数的乘法,组合出来
vector<int> mul(const vector<int> & A, const vector<int> & B) {
vector<int> ans = vector<int>(1, 0); // 初始化只有一位,为0
for (int i = B.size() - 1; i >= 0; i--) {
ans = mul(ans, 10); // 往左移一位
ans = add(ans, mul(A, B[i]));
}
return ans;
}
![](http://latex.codecogs.com/gif.latex?123\ mod\ 7\ %3D(1\times10^2 + 2\times10^1 + 3\times10^0)\ mod\ 7\%3D(1\times10^2\ mod\ 7 + 2\times10^1\ mod\ 7 + 3\times10^0\ mod\ 7)\ mod\ 7)
int mod(const vector<int> & A, int p) {
int ans = 0;
for (int i = A.size() - 1; i >= 0; i--) ans = (ans * 10 + A[i]) % p;
return ans;
}
#include <iostream>
#define fir(i, a, b) for (int i = a; i <= b; i++)
using namespace std;
const int N = 1e5 + 10;
int sum[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n, m;
cin >> n >> m;
fir(i, 1, n) cin >> sum[i], sum[i] += sum[i - 1];
while (m--) {
int a, b;
cin >> a >> b;
cout << sum[b] - sum[a - 1] << endl;
}
}
#include <iostream>
#define fir(i,a,b) for (int i = a; i <= b; i++)
using namespace std;
const int N = 1000 + 5;
int sum[N][N];
int main() {
int n, m, q;
scanf("%d%d%d", &n, &m, &q);
fir(i, 1, n) fir(j, 1, m) {
scanf("%d", &sum[i][j]);
sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
}
while (q--) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
cout << sum[x2][y2] - sum[x2][y1 -1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1] << endl;
}
}
![](http://latex.codecogs.com/gif.latex?{a_1, a_2, \dots, a_n})
![](http://latex.codecogs.com/gif.latex?{b_1, b_2, \dots, b_n})
构造 b数组,使得 是 ![](http://latex.codecogs.com/gif.latex?b_1 + b_2 + \dots + b_i) 即前缀和
即 前缀和 与 差分 互为逆运算
区间修改变单点修改
差分数组我们可以不用管他的构造,默认全是 0,然后我们往里“插入”数,即让区间长度为1的区间,加上某个数。
#include <iostream>
#define fir(i,a,b) for (int i = a; i <= b; i++)
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
void insert(int l, int r, int c) {
b[l] += c;
b[r + 1] -= c;
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
fir(i, 1, n) scanf("%d", &a[i]);
fir(i, 1, n) insert(i, i, a[i]);
while (m--) {
int l, r, c;
scanf("%d%d%d", &l, &r, &c);
insert(l, r, c);
}
fir(i, 1, n) a[i] = b[i] + a[i - 1];
fir(i, 1, n) printf("%d ", a[i]);
}
#include <iostream>
#define fir(i, a, b) for (int i = a; i <= b; i++)
#define fri(i, b, a) for (int i = b; i >= a; i--) // 简写循环,可以少敲几下键盘
using namespace std;
const int N = 1e3 + 10;
int a[N][N];
void insert(int x1, int y1, int x2, int y2, int c) {
a[x1][y1] += c;
a[x1][y2 + 1] -= c;
a[x2 + 1][y1] -= c;
a[x2 + 1][y2 + 1] += c;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n, m, q;
int x1, y1, x2, y2, c;
cin >> n >> m >> q;
fir (i, 1, n) fir (j, 1, m) {
cin >> c;
insert(i, j, i, j, c);
}
while (q--) {
cin >> x1 >> y1 >> x2 >> y2 >> c;
insert(x1, y1, x2, y2, c);
}
fir (i, 1, n) {
fir (j, 1, m) {
a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
cout << a[i][j] << " ";
}
cout << endl;
}
}
本来需要两个指针,枚举全部状态,但利用某种单调性,可以使复杂度讲到
没有啥模板,只是一种思想,要看具体题目的
-
求整数 n 的二进制表示中,第 k 位
-
把第 k 位移到最低位
-
看最低位是几
int get_k(int n, int k) { return (n >> k) & 1; }
-
-
lowbit,返回最低位的1
int lowbit(int n) { return n & -n; }
数据范围很大,但数据量很小,比较稀疏
sort(a.begin(), a.end());
a.erase(unique(a.begin(), a.end()), a.end());
贪心
- 按左端点排序
- 贪心维护一个区间,有下列三种情况
- 包含,那么当前区间不动
- 相交,区间右端点更新
- 不相交,ans++,当前区间更新为不相交的那个区间
#include <iostream>
#include <algorithm>
#define fir(i, a, b) for (int i = a; i <= b; i++)
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
PII a[N];
int main() {
int n;
cin >> n;
fir(i, 0, n - 1)
cin >> a[i].first >> a[i].second;
sort(a, a + n, less<PII>());
int ans = 1;
int l = a[0].first, r = a[0].second;
fir(i, 1, n - 1)
if (a[i].first > r) ans++, l = a[i].first, r = a[i].second;
else r = max(r, a[i].second);
cout << ans << endl;
}