bzoj2006
转移自老blog
n<5e5 20s
然后来优化它,我们观察取出前k大的方法,是一个一个取出来的,这就说明了,一次只取出了一个,这就是突破点于是我们这样来做,我们对每一种区间按终点分类,显然可能取出来的,一定是以当前终点为终点的所有区间中最大的那一个,那我们就维护数列f[]
f[i]代表以i为终点的所有可取且未取区间中区间和最大的那一个,于是我们这样来查询,每次取出f数组的最大值,然后更新f数组,如何更新呢?我们再多记录一个信息,记录当前的f[i]是原先所有以i为终点的所有选择中的第几大,假设现在这个是第k大,当我们取出来之后,只要更新f[i]即可,更新可选择的第k+1大
我们来加速这个过程,发现f可以用堆来维护,用一个三元组: <EndAt,val,kth>分别代表该区间以EndAt为结尾,区间和为val,此区间是所有以EndAt为终点的可选区间的第kth大,此三元祖按照val建堆即可。
bzoj2006
链接
题意
给一个长为n的序列,输入一个询问k,l,r,从中选出k个长度介于[l,r]中的不同的区间,最大化 k个子段和 的和,n<5e5 20s
题解
先想一个暴力算法,我们把所有长度介于[l,r]的子段的和都求出来,放进一个堆,然后取出前k大然后来优化它,我们观察取出前k大的方法,是一个一个取出来的,这就说明了,一次只取出了一个,这就是突破点于是我们这样来做,我们对每一种区间按终点分类,显然可能取出来的,一定是以当前终点为终点的所有区间中最大的那一个,那我们就维护数列f[]
f[i]代表以i为终点的所有可取且未取区间中区间和最大的那一个,于是我们这样来查询,每次取出f数组的最大值,然后更新f数组,如何更新呢?我们再多记录一个信息,记录当前的f[i]是原先所有以i为终点的所有选择中的第几大,假设现在这个是第k大,当我们取出来之后,只要更新f[i]即可,更新可选择的第k+1大
我们来加速这个过程,发现f可以用堆来维护,用一个三元组: <EndAt,val,kth>分别代表该区间以EndAt为结尾,区间和为val,此区间是所有以EndAt为终点的可选区间的第kth大,此三元祖按照val建堆即可。