一类求解第 k 大问题的做法
这个 idea 本来想出 unrd2t3 的,可惜常数有点大,就弱化成了现在的 unrd2t2。
unrd2t2也有点误判难度了呜呜。我把这题给蒋老师看,蒋老师一两分钟就秒了,而这题场上只有一个还没被叉掉的提交;而蒋老师d2t1做了几十分钟,而这题被过穿了。差点就swap(t1,t2)了!!
结论1.可以 求出 个递增序列的第 大。#
不妨设 个有序序列找前 小的问题是 。
如果 ,那么可以直接对第一个元素做 删掉没用的序列。
如果 ,那么我们只保留每个序列的第一个、第三个、第五个等元素,做一遍 的问题,这样找到的元素都必然是前 小的。但是这样只能找到 个元素,还要往后找 个元素,这个就是 。这样做, 的总规模变成了原来的 。
否则,随机找一个序列,选出它的第一个元素,找到比这个元素小的所有元素(如果要确定性的话,可以考虑找所有序列第一个元素的中位数)。如果在某个时刻发现小的元素超过了 个,那么答案就大于选出元素,可以删掉所有第一个元素比他大的序列了。否则是小了,那么可以把我们找出的元素删掉。
可以发现,上述过程 每次期望都减少了 倍,其中 是常数,所以上述过程是线性的。
结论2. 可以 区间加区间 kth#
首先,以 1/2 的概率保留每一个元素,得到一个新序列 ,观察 序列的 -th,设其为 。
这个是类似随机游走的过程,我们找到的这个元素的 rank 和 的差只有 。
每 个元素分一块,每个块维护块内元素 sort 后的结果。使用分散层叠算法,就可以快速找到每个块有多少个元素 。称所有 的数为“被选中的元素”。
根据结论1,我们就只需要每次找到被选中的元素的前 大并取消选中,然后找到没被选中的元素的前 小并选中。一直做直到边界不变了为止。
如果我们要调整 个元素,这样做的复杂度即为 ,即 。
由于我们还要递归成 n/2 的问题,所以单次操作的复杂度是 ,即 。
结论3. 可以 求出 的 "递增矩阵" 的第 大#
首先调用 unrd2t2,我们发现复杂度瓶颈在于求 个递增数列的第 大。
调用之前的结论1即可。
结论4. 可以 求出 的 "递增矩阵" 的第 大#
容易发现,只有 的位置 才可能成为前 大。
考虑把所有可能成为前 大的元素分到若干个矩形中。分法如下:
首先设 。
我们先切出矩形 。接下来还有需要继续被切分的矩形 和 。以第一个为例。
我们切出 ,。不停地切分下去。
接下来,我们把这些矩形一起做 结论3 的过程。可以发现最后的复杂度是每个矩形的复杂度的加和。一个矩形 (不妨 )贡献的复杂度应为 。
那个 的矩形贡献的复杂度显然是 。
对于剩下的矩形,复杂度为:
综上,这个算法可以做到 (其实可以看到我unrd2t2的标算是对着多个矩阵一起做写的)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话