T1:
首先O(n^3)非常好像,O(n)枚举以i点为最高点,于是问题转化为求
min sigma(hj - (x - |i - j|))其中hj为j位置高度,x为钦定i点的高度,x - |i - j|即为j位置要求高度
首先考场上最后想出做法为:利用分块,提取变量x并设k = x - |i - j|
原式转化为sigma |k - x|,发现讲绝对值函数图像放到坐标系中,则总函数为单峰函数,于是
可以二分x,那么现在问题为如何计算sigam |k - x|,分类讨论k >= x 与 k < x 两种情况,于是
可以利用经典的分块做法:块内排序,在预处理与处理散块时sort维护k的大小关系,查询时
通过lower_bound查询,并通过维护块内前缀和O(1)计算,然而时间复杂度较悬,需要卡常
正解同样是利用分类讨论拆绝对值,首先对于i左右两侧分类讨论去掉|i - j|,然后考虑
拆式子观察一下:|hj - j - (x - i)|,|hj + j - (x + i)|,基本思想为同类归并,于是发现问题结构非常
相似,我们只需要维护两部分即可,做法为在i两侧分别建立两棵权值树状数组(离散化维护)
维护前缀和与前缀数量,查询时直接查询即可,i位置移动时,调整两侧树状数组信息即可
需要注意要卡下界
正解时间复杂度为O(nlog^2n)
接下来给出Windzr的神仙做法,时间复杂度为O(nlogn)
上述两种做法的核心在于通过推式子,观察出单峰函数的性质,在考虑如何维护整体求值
主要是利用下标与数据结构拆绝对值维护式子
Windzr的做法核心在于观察出问题另一关键,即问题要求移动次数最小,那么考虑事实上
移动次数只与基准线上下两侧的方块数有关,而与上下两侧方块高度无关,于是考虑在什么情况下
移动次数最优,显然为上下两侧方块数接近n >> 1时最优,于是同样O(n)枚举i为最高方块位置
设up,down分别为基准线上下两侧方块数,
那么首先卡定下界并Check 此时若down >= up则直接计算答案,否则,根据上述理论
我们设x为基准线还需要向上移动x个方块,那么最优策略显然为:
down + x = up - x,解得:x = up - down >> 1
显然通过预处理的排序,我们可以O(1)计算移动位置,那么现在关键点就在于如何Check与计算答案
同样的做法,利用权值类型数据结构维护前缀和与前缀数量,以此Check与计算
简言之,Windzr做法核心在于观察出题目的性质,将枚举具体最高高度转化为基准线的移动,省略
了三分的log并且常数较小。
T2:
正解高精度小数,并无意义,问题核心在于观察矩阵填数的规律总结出对数级数学式计算
T3:
单调栈原题,转化题意通过李超线段树维护
对于单调不降的部分分通过单调指针维护即可,当i劣于i +1时将i出栈即可
T4:
问题在于对问题观察于思考不足,n点n边,出度为1,显然为内向基环树森林,
朴素做法显然为枚举所有点作为路径端点向前延伸k的长度,时间复杂度为O(n^2)
O(nlogn)做法为通过倍增优化延伸过程,O(n)做法为考虑要覆盖一个点有k种情况
那么枚举所有经过该点的k条路径即可,时间复杂度O(k * n / k) = O(n)