位运算
快速幂:
|
|
大数乘法取模(可能溢出):
|
|
lowbit
算法:
|
|
枚举、模拟、递推
递归
二分
二分的实现需要注意细节:
- 对于整数域上的二分,需要注意终止边界、左右区间取舍时的开闭情况,避免遗漏答案造成死循环;
- 对于实数域上的二分,需要注意精度问题。
模版:在单调递增序列中查找 >=x
的数中最小的一个:
|
|
模版:在单调递增序列中查找 <=x
的数中最小的一个:
|
|
模版:实数域二分,保留 k 位小数时:
|
|
模版:求单峰函数极值(三分法):
|
|
例题(贪心,将二分答案转化为判定):
有 N 本书排成一行,已知第 i 本书的厚度是 $A_i$。
把它们连续地分成 M 组,使得 T 最小化,其中 T 表示厚度之和最大的一组的厚度。
注意到这样的一个函数是单调的:
- 以分组数 M 作为定义域,在作为分组方式中,T 最小的一组,其中的 T 作为值域。
排序
排序算法分为三类:
$$O(n^2)$$ 算法: ”选择排序“、”插入排序“、”快速排序“;
$$O(n logn)$$ 算法: ”堆排序“、”归并排序“、”快速排序“;
最优 $$O(n)$$ 算法: ”计数排序“、”基数排序“、”桶排序“;
货仓选址问题:
- 背景:一条数轴上有 N 个商店,需要在数轴上建立一个货仓,是的货仓到每个商店的距离之和最小;
- 解决方案:容易得之,把货仓建在中位数的位置,是满足题意的最优解位置;
均分纸牌问题:
- 背景:有 M 个人排成一排,它们手中分别有
C[1]~C[M]
张纸牌,在每一步操作中,可以让某个人把手中的一张纸牌交给旁边的一个人,求至少需要多少步操作才能让每个人手中的纸牌数量相等; - 解决方案:从第一个人开始分情况递归可以得到公式:$$\displaystyle \sum_{i = 1}^{M}|i * \frac{T}{M} - S[i]|$$,其中 S 表示前缀和;
环形均分纸牌问题:
- 背景:在均分纸牌问题的背景下,第一个人和最后一个人可以交换纸牌;
- 解决方案:
- 假设每个人手中的纸牌减去 $$\displaystyle \frac{T}{M}$$,使得 $$S[M] = 0$$(负数的持有牌数并不会影响结论的讨论);
- 可以证明一定存在一对相邻的人之间没有发生纸牌的交换,枚举这个位置得到:$$\displaystyle \sum_{i = 1}^M |S[i] - S[k]|$$
- 求解上述公式在 k 为变量情况下的最小值,即“货仓选址”问题,对 S[i] 进行排序既得结果;
动态中位数问题:
- 背景:依次输入一个整数序列,每当已经读入的每当已经读入的整数个数为奇数时,输出已经读入的证书构成的序列的中位数;
- 解决方案:可以建立两个二叉堆:一个大根对(
1~M/2
个元素)、一个小根堆(M/2 + 1~M
个元素);
第 k 大数:
- 背景:给定 n 个整数,如何求出第 k 大的数;
- 解决方案:类似快排的思想,选出一个 pivot,每次排序后与 k 进行比较,只需要在一侧继续递归查找;时间复杂度 $$O(n) + O(n/2) + \cdots + 1 = O(n)$$;
求逆序对:
- 背景:对于一个序列 a,如果存在 i>j, a[i]<a[j],则它们称作一对逆序对。求一个给定序列中逆序对数量;
- 解决方案:逆序对可以通过在归并排序的过程中计算,也可以通过数状数组计算。以下是归并的解法:
|
|
奇数码问题(拼图问题):
- 背景:
- 在一个
n*n
的网格中进行,其中 n 为奇数,1 个空格和1~(n-1)*n
个数字,它们恰好不重不漏地分布在n*n
的网格中,空格移动的规则和拼图类似。 - 现在给定两个奇数码游戏的局面 A、B,请判断 A 是否能通过移动得到局面 B;
- 在一个
- 解决方案:上述命题只需要考虑一个充分必要条件:
- 如果按顺序将网格展开序列,AB 两个局面的逆序对奇偶性相同;