题外话:忙碌了一个学期,结果考试都放到了下个学期。于我个人而言这是没什么影响的,只不过需要提早进行算法竞赛的学习。大二上一直很忙,也没有时间写博客,只能寒假抽个空写个两篇。写这个博客最重要的原因就是方便自己复习之前学过的算法知识,为学更难的算法打下坚实的基础。二来可以督促自己学习,以免荒废了漫长的寒假。
二分模版
//区间被划分为[l,mid]和[mid+1,r]使用
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
//区间被划分为[l,mid-1]和[mid,r]使用
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
上面第一个模板用于寻找左边界,第二个模板用于寻找右边界。使用模板时,先判断本题寻找左边界还是右边界,选取相对应的模板。再思考check函数怎么写,尤其要注意大于等于或者小于等于的问题。
高精度加法模板
#include<iostream>
#include<vector>
#include<string>
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;
cin >> a >> b;
vector<int>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>
using namespace std;
const int N = 1e3 + 10;
int a[N][N];
int 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()
{
int n, m, q;
cin >> n >> m >> q;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> a[i][j];
insert(i, j, i, j, a[i][j]);
}
}
while (q--)
{
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;
}
差分是前缀和的逆运算,差分求前缀和就是原来的数组。代码中最重要的是insert函数,insert函数一方面用于对b数组的初始化,另一方面用于对原数组的修改。想要输出经过q次修改的数组,只需要对b数组求前缀和。
位运算相关
求一个数的二进制表示
#include<iostream>
using namespace std;
int main()
{
int n = 10;
for (int k = 3; k >= 0; k--) cout << (n >> k & 1);
return 0;
}
求二进制数中1的个数
#include<iostream>
using namespace std;
int lowbit(int x) //返回x的最后一位1
{
return x & -x;
}
int main()
{
int x;
cin >> x;
int res = 0;
while (x)
{
x -= lowbit(x);
res++;
}
cout << res << endl;
}
使用lowbit函数可以找到x的最后一位1的位置。