一种求第 k 小方案的神奇做法

同样适用于前 k 大

肯定对于每一个方案 xx 都会有一个 val(x)val(x) 表示这种方案的权值。

我们定义对于一个集合的 valval 是 val(S)=min⁡x∈S{val(S)}val(S)=\min\limits_{x\in S}\{val(S)\},首先需要找到一个集合 SS 使得 val(S)val(S) 是最小的权值,对 SS 定义一个 trans(S)trans(S) 表示 SS 能变换到的集合的集合,一般这个 transtrans 是一个固定的变换方法,这里需要满足 T∈trans(S),val(T)≥val(S)T \in trans(S) ,val(T) \ge val(S) 并且对于任意一个不是权值最小的方案 TT 都存在且一个 SS 使得 T∈trans(S)T \in trans(S),这样能保证我们拓展到的集合权值是逐渐递增的。

考虑我们如何维护这个东西,我们用一个堆维护当前的已经被拓展到的方案,取出 valval 最小的方案 SS,然后将 trans(S)trans(S) 中没有加进过堆的集合全部加入堆中,将 SS 弹出堆,重复操作,不难发现我们第 ii 弹出堆的元素一定是第 ii 小,因为根据上面 transtrans 的定义是一定能变换到所有方案的,并且从最小方案到当前方案的路径上 valval 是递增的,我们这样拓展 kk 次一定能找到第 kk 小的元素,我们设 szsz 表示 transtrans 集合的大小,dsds 表示从集合中找到最大值的复杂度,判断集合是否加进过堆的复杂度是 O(chk)O(chk),这样时间复杂度是 O(k⋅sz⋅ds⋅(chk+log⁡(k⋅sz)))O(k\cdot sz\cdot ds\cdot (chk+\log(k\cdot sz))),非常优秀。

题目:

P2048 [NOI2010] 超级钢琴

题意:给你一个长度为 nn 序列 AA,求前 kk 大的长度属于 [l,r][l,r] 的区间 aia_i 和。

n,k≤5×105,−1000≤ai≤1000n,k \le 5 \times 10^5,-1000 \le a_i \le 1000。

发现区间不好做,先做前缀和转换成 max⁡(ar−al)\max(a_r-a_l),发现对于每一个左端点 xx 都有一个 [l,r][l,r] 表示右端点能在的位置,我们用堆维护五元组 S={x,l,r,val,pos}S=\left\{x,l,r,val,pos\right\} 表示左端点是 xx ,右端点选的区间是 [l,r][l,r] ,当右端点选 pospos 时是最优的,权值为 valval ,不难发现 trans(S)={{x,l,pos−1,vall,pos−1,posl,pos−1},{x,pos+1,r,valpos+1,r,pospos+1,r}}trans(S)=\left\{\left\{x,l,pos-1,val_{l,pos-1},pos_{l,pos-1}\right\},\left\{x,pos+1,r,val_{pos+1,r},pos_{pos+1,r}\right\}\right\},发现 pospos 肯定是 [l,r][l,r] 中 aia_i 最大的 ii ,这个可以直接用 stst 表维护,valval 也就很好算了,这里 sz=2,ds=O(log⁡n)sz=2,ds=O(\log n),不会有重复集合加入堆,所以时间复杂度 O(klog⁡klog⁡n)O(k \log k\log n)。

异或粽子和上面那道题基本一样,就不详细说了。

P6230 [BalticOI 2019 Day2]奥运会

题意:有 nn 个人,kk 个比赛,第 ii 个人在第 jj 场比赛中的得分是 ai,ja_{i,j} 现在一支队伍要选 kk 个人,这支队伍每一场比赛的得分为得分最高的那个人的得分,这支队伍的得分为所有比赛的得分的和,现在问你得分第 CC 大的队伍的得分

n≤500,k≤6,C≤2000n\le500,k \le6,C\le2000

蒟蒻瞎想的做法:link

洛谷题解做法:

首先这个数据范围非常小,所以我们设的一些东西可以非常暴力。

P6646 [CCO2020] Shopping Plans

非常牛逼的一道题!

分成几部分来考虑这道题

Part1

ai=1,x=ya_i=1,x=y

这个还是比较简单的,首先最小值肯定是选前 xx 个,然后考虑怎么设计 transtrans,


一种求第 k 小方案的神奇做法
http://lnyxqwq.github.io/2023/08/15/一种求第 k 小方案的神奇做法/
作者
lnyx
发布于
2023年8月15日
许可协议