知识点
XIAOm_YYDS · · 个人记录
前缀和和差分
一维
前缀和:
差分:
关系:逆运算
Ex:异或前缀和和异或差分的关系
例题 #1 求区间和
会发现
例题 #2 语文成绩
在差分数组上给
因此区间
扩展:如果要做异或区间和和区间异或呢?
例题 #3 区间加等差数列
给定一个序列,
考虑区间加等差数列对差分数组的影响。
二维
如果想要求一个二维数组中一个矩阵内的所有数的和呢?
前缀和:表示这个点左上方的所有值的和
差分是什么?
本质上是一种容斥
异或情况下的式子?
重要的点:当你确定了前缀和或差分数组,一定可以还原出原数组吗?
有时想要求出一个数组很难,但是求出差分或者前缀和数组更简单,会用到这个性质。
例题 #4 领地选择
直接求出二维前缀和计算每个矩阵内的和即可。
例题 #5 公路修建
这个就会用到前面所说的思想。
你需要让最终整个数组变成
因此差分后考虑即可。
例题 #6 区间和
还是刚刚的思想,想要确定
但是如果看成确定
如果连一条边,就变成了
例题 #7 特殊训练
首先按照需要的训练次数
然后枚举用了多少次
可以二分这个后缀的位置解决本题。但是更简单也更快的方法是用一个指针去维护这个位置。由于我们在从小到大枚举使用
树上的前缀和和差分
树上的前缀和、差分方式很多,每个都有不同的用处。
第一种:
第二种:
第三种:
一类经典的前缀和问题
有这么一类问题非常经典:在数轴上有若干个点,选择一个点它向所有点的距离和尽量小。
我们不考虑数学上的结论,这是因为这个题可以有很多变式,变式可能就没有结论了。首先选择的点肯定是这些点中的一个,否则一定可以调整过去。那么枚举这个点
这个值可以拆开,会得到一个前缀和的形式。因此给所有
二分和双指针
二分
二分是什么?
单调的东西求分界点。
二分的重要条件是单调,也就是前半部分可以,后半部分不可以。
单调性一般有两种满足方法:
- 排序从而满足单调。
- 存在一个函数
f 关于值域单调。
还存在一种经典的二分:有两个问题,尽量合理地安排它们,也就是让两边尽量接近。
偷懒方法:lower_bound,upper_bound
例题 #1 数数
首先,显然询问和数组顺序无关,因此先给整个数组排序。
然后每次询问就是找到序列中小于等于
例题 #2 A-B 数对
还是和顺序无关,因此可以排序一下。
然后可以枚举
这个数量可以通过二分得到。
例题 #3 Sisyphus
施展魔法总是从大到小施展,这样才能保证西西弗斯亏的距离最大。
当确定了施展魔法的个数时,可以计算出西西弗斯需要走的总距离,因此就可以求出他走完全程所需要的时间。
走的时间显然是关于施展的魔法数单增的,因此可以二分施展多少魔法可以拖他这么久。
例题 #4 区间
最大化最小值和最小化最大值是非常非常经典的二分题模型。
看到这两个条件就要想到二分。
主要是二分完了就变成了一个“所有数都必须大于等于/小于等于“的判定性问题。
这种问题往往是比较容易判断的。
例题 #5 中位数
给出一个两个序列,两个序列均为有序数组,每次有两种操作:
- 单点修改,保证修改后仍然有序
- 给出两个序列中分别一个区间,求出这两个区间内的数拼起来后的中位数
考虑前一半小在两个序列分别占了多少个。
如果二分在第一个序列占了多少个,假设是
这样可以二分出中位数在第一个序列占了多少个数,实现单
例题 #6 Median Pyramid
给出一个
简单版:
二分答案后对中位数的影响是非常大的,会非常好做。
例题 #8 旅行
然后将所有点按
可以二分最后选取的城市在排序后序列中的位置,然后相当于判断后缀之中是否存在距离超过当前二分的权值的点。
这个二分本质上就是找到
怎么判断距离?我们知道
然后对每个情况分别统计后缀最大值即可。
双指针
有时单调问题可以不需要二分来解决,利用上次复杂度分析所分析到的方法。
双指针能解决的问题二分几乎都能解决,但是双指针更快也更好写,本质就是如果二分需要查询到的位置也是单调增加的,那么就可以用双指针解决。
我们可以回忆一下归并排序的过程,最后合并的过程就是一个简单的双指针。
例题 #1 数数
看起来每次查询到的维护并不是单调增加的,怎么应用双指针?
可以给所有查询按照
这样就可以用一个指针去扫这个位置,而不需要枚举了。
例题 #2 A-B 数对
可以重新解决这个问题,可以维护一个指针来表示
维护两个指针,分别表示第一个和最后一个
扩展
*扩展 #1 最大化斜率
最大化最小值的一半方法就是二分。可以二分这个斜率,相当于选出一些点,这些点两两斜率都大于等于这个值。
如果二分的斜率是
*扩展 #2 位运算
有另一种特殊的二分策略,类似于倍增,是从高到低确定答案的每一个位,常用于位运算相关的问题。
从高到低考虑每一位,尝试这一位是否可以为
如果想要尝试这一位是否可以放
基础数据结构
点不进去吧