将雪菜大佬的模板转写为java形式,C++见大佬原文AcWing @yxc
快速幂算法模板
求 m*k%p,时间复杂度 O(logk)
int pow(int m, int k, int p) {
int res = 1 % p;
int t = m;
while (k > 0) {
if ((k & 1) == 1) {
res = res * t % p;
}
t = t * t % p;
k >>= 1;
}
return res;
}
快速排序算法模板
void quick_sort(int q[], int l, int r) {
if (l >= r)
return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j) {
do
i++;
while (q[i] < x);
do
j--;
while (q[j] > x);
if (i < j)
swap(q, i, j);
}
quick_sort(q, l, j);
quick_sort(q, j + 1, r);
}
void swap(int[] q, int i, int j) {
int p;
p = q[i];
q[i] = q[j];
q[j] = p;
}
归并排序算法模板
void merge_sort(int q[], int[] tmp, int l, int r) {
if (l >= r)
return;
int mid = l + r >> 1;
merge_sort(q, tmp, l, mid);
merge_sort(q, tmp, 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];
}
整数二分算法模板
boolean check(int x) {
/* ... */ // 检查x是否满足某种性质
}
// 区间[l, r]被划分成[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; // check()判断mid是否满足性质
else
l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[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;
}
浮点数二分算法模板
boolean check(double x) {
/* ... */ // 检查x是否满足某种性质
}
double bsearch_3(double l, double r) {
final double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求
while (r - l > eps) {
double mid = (l + r) / 2;
if (check(mid))
r = mid;
else
l = mid;
}
return l;
}
高精度算法
具体算法使用了快速傅里叶变换。 JAVA中有大整数类,可以直接使用,这里不做转译。
二维前缀和
S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2,y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
一维差分
给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c
二维差分
给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1,y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c
位运算
求n的第k位数字: n >> k & 1
返回n的最后一位1:lowbit(n) = n & -n
将n的二进制表示中的最低位为1的改为0: n&(n-1)
使n的k位取反:n ^= (1 << k);
将n的k位设置为x:if (x == 0) n &= ~(1 << k); else n |= (1 << k);
双指针算法
for (int i = 0, j = 0; i < n; i ++ )
{
while (j < i && check(i, j)) j ++ ;
// 具体问题的逻辑
}
常见问题分类:
(1) 对于一个序列,用两个指针维护一段区间
(2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作