差分:蓝桥杯2022省赛重新排序
差分:蓝桥杯2022省赛重新排序
前言
这是一道蓝桥杯2022省赛原题,其差分思想和实现的思路比较灵活,值得尝试和学习。
题目
给定一个数组 A和一些查询 Li,Ri, 求数组中第 Li 至第 Ri 个元素之和。
小蓝觉得这个问题很无聊, 于是他想重新排列一下数组, 使得最终每个查 询结果的和尽可能地大。小蓝想知道相比原数组, 所有查询结果的总和最多可 以增加多少?
输入格式
输入第一行包含一个整数 n。
第二行包含 n 个整数 A1,A2,⋯,An, 相邻两个整数之间用一个空格分隔。
第三行包含一个整数 m 表示查询的数目。
接下来 m 行, 每行包含两个整数 Li、Ri, 相邻两个整数之间用一个空格分 隔。
输出格式
输出一行包含一个整数表示答案。
样例输入
1 | 5 |
样例输出
1 | 4 |
样例说明
原来的和为 6+14=20, 重新排列为 (1,4,5,2,3) 后和为 10+14=24, 增加了 4。
官方题解
题目希望所有查询之和经过重新排序后增加最多,因此考虑先计算出当前的查询之和,以及排序后最大的查询之和。
由于给定查询区间,因此排序前和排序后询问的区间是一样的,那么可以利用 m 个查询区间计算出每个位置 j 的累计查询次数 s[j],最终查询总和为
$$
\sum_{j=1}^{n} A_j \cdot s[j]
$$
每次查询区间 [Li,Ri],相当于区间 [Li,Ri] 中的每个数字查询次数 +1+1。为了统计每个数字的查询次数,需要实现区间加法,可以使用线段树、树状数组、差分数组来得到数组 ss 的值。
此处使用差分数组的做法实现区间更新:
- 在区间 [Li,Ri] 上 +1+1,只需要在差分数组 b[Li]++,b[Ri]−−。
- 最终
$$
s[j] = \sum_{i=1}^{j} b[i]
$$
此时最开始的查询之和相当于统计每个数字的查询次数:
$$
\sum_{j=1}^{n} A_j s[j]
$$
需要对数组 A 进行排序,使得新的 sum 最大。利用贪心的思想可以得出结论:查询次数越多,数值一定越大。这样才能保证和最大。
因此对 A 数组从小到大排序,而 s 数组也从小到大排序,使得A中最小的对应 s 中最小的,A 中最大的对应 s 中最大的,此时可以保证和最大。
个人反思
这题涉及了差分和贪心算法,有以下几个难点要注意:
- 要把区间维护转换为对数组的单个点的维护,这样就可以直接用数组进行计算,就方便很多。
- 题目中的查询次数区间的维护操作对应了差分算法,差分计算完后还要记得计算前缀和得到查询次数原数组。
- 在思考怎么把最大的数对应到查询次数最大的点时,不仅可以把数字排序再通过查询次数的优先级对应上原数组,还可以直接把原数组的查询区间也给排序了,反正是一一对应的关系,不会影响结果。总结就是数据和位置都可以排序,不要被困于模拟操作的局限当中,位置也是可以排序的。
- 本题的边界问题也是个坑,注意写代码时一定要全部一遍考虑好,不然后期debug很麻烦。
AC_Code
1 |
|