首页 > 其他分享 >从Shopping Plans谈起的一类的经典 kth 问题

从Shopping Plans谈起的一类的经典 kth 问题

时间:2024-09-18 16:13:00浏览次数:6  
标签:trans Shopping Plans val kth 数组 每个 移动 log

一类 kth 相关问题

​ 实际上,这个 trick 以及其拓展在去年 noip 级别的模拟赛已经用到了多次,但是认知仅局限于“用优先队列”解决的一类题目,有时可以直接建立最短路模型。在去年一场 nfls 中甚至因为知道此 trick 而在最后一题狂砍 50 分,今天在 dmy 再遇,故整理其成体系。

T4 控制

有 \(n\) 类装备,每种类型有 \(m_i\) 种,且各有一个魔力值,定义一个方案为每一类选一个;你要求出前 \(k\) 大方案的魔力值总和。

套路题,优秀的暴力是 用优先队列维护,类似搜索,从一个状态向外转移,并加入堆里。为了避免加重,需要加入顺序的约定。

正解比较复杂,但发现本质和 \(dij\) 很像,所以可以转换成图论,建立 \(nm\) 个点,每个第 \(i\) 类的点,向每个第 \(i+1\) 类的点连边。直接可并堆优化 k 短路即可。需要虚拟源点和汇点。

0.模型与思路

给定你一个价值的计算方案,具体又可分为序列上子集和,子区间(超级钢琴),树上连通块。要求输出其第 \(k\) 大的价值,或前 \(k\) 大价值的和。\(k\) 通常在 \(10^5\) 级别,而还有一类 \(k=10^{18}\) 类似的问题通常是使用二分答案解决。

这一类问题有通用思路:

对于目前考虑到的一个状态 \(S\),设 \(trans(S)\) 为 $S $ 的后继状态集合。首先将最优的 \(S\) 放进堆中,重复下列操作 \(k\) 次。

  • 取出堆顶 \(S\),计算 \(S\) 的答案。
  • 将所有 \(trans(S)\) 放入堆里。

可以注意到,如果 \(|trans(S)|\) 是 \(O(1)\) 或者 \(O(\log)\) 的,且都劣于 \(S\),而且需要保证 \(S\) 的状态不重不漏时算法可以在 \(O(n\log n)\) 或者 \(O(n\log ^2 n)\) 的时间复杂度内完成。问题的关键在于构造一个不重不漏的 \(trans(S)\)。

1.Multiset

给定一个可重集 \(S\),求大小为 \(p\) 的第 \(k\) 小子集。

首先排序,最优一定是前 \(p\) 项。先不考虑 \(|trans(S)|\) 大小的限制,先满足不重不漏,因为这样我们至少能得到多项式复杂度的做法。

初始时 \(S_0\) 为排序后的前 \(p\) 个数,考虑以下构造方案:

  • 每次将最右侧未移动点向右移动若干位,但不能跨越已移动点
  • 将其标记为已移动点

容易发现,对于任何一个大小为 \(p\) 的状态,都有且仅有一种操作方案。实际上类似于二进制上逐位确定的方法。

我们可以将转移抽象为树的形式,这样做的问题就在于,节点的儿子实在太多了。

但是只要保证解是逐渐变劣的,那么这棵树的形态是不重要的,那么我们可以用树的兄弟儿子表示法将树三度化,也就是说,每个节点只存它最优的儿子和向右第一个兄弟。

设四元组 \((val,x,y,z)\) 表示权值和为 \(val\),最长未移动前缀为 \(x\),当前移动项为 \(y\),右侧首个已移动项为 \(z\)。

  • \((val,x,y,z)\to (val-v_y+v_{y+1},x,y+1,z)\) 表示最右侧的可移动点向右移动一格,也就是向右第一个兄弟。需要保证 \(y+1<z\)。
  • \((val,x,y,z)\to (val-v_x+v_{x+1},x-1,x+1,y)\) 表示将当前 \(x\) 向右移动一格。也就是最优的儿子。

不难发现,\(x,y\) 的意义相当于于下次操作和这次操作的位置。初始加入 \((sum,p,n+1,n+1)\)。用小根堆维护,时间复杂度 \(O(n\log n)\)。如果拓展至大小在 \([l,r]\) 区间中的子集,那么初始是对每个 \(p\in [l,r]\) 都加入即可。注意这里 \(n+1\) 实际上是 \(\inf\)。

例题:CF1250I。

2.Arrays

\(n\) 个数组,每个数组选一个数,求第 \(k\) 小和。

\(O(n^2\log)\) 的做法即是记录每个数组选到第几个位置。(注意去重:格外记录 \(i\) 表示钦定前 \(i\) 个已经选定了)。

最小的肯定是每个数组选第一个数。套路的,每个数组内部升序排序,设 \((val,x,y)\) 表示当前考虑到第 \(x\) 个数组,第 \(x+1\sim n\) 的数组全部只选第一个元素,第 \(x\) 个数组选第 \(y\) 个元素,这样同样可以保证转移只会变劣不会变优:

  • \((val,x,y)\to (val,x+1,1)\) 表示考虑到下一个数组。
  • \((val,x,y)\to (val-a_{x,y}+a_{x,y+1},x,y+1)\) 表示考虑当前数组的下一个位置。
  • 初始为 \((\sum a_{i,1},1,1)\)。

但是这样会算重,很简单,你在 \(\{2,1,1,1,1\}\) 往下还会转移到 \(\{2,1,1,1,1\}\)。所以我们钦定每次只能向后转移到 \((x+1,2)\)。

那当前数组想取第一个位置怎么办呢?我们只需在每个 \((x,2)\) 新增第三个转移:

  • \((val,x,2)\to (val-a_{x,2}+{a_{x,3},x,3})\)。
  • \((val,x,2)\to (val-a_{x+1,1}+{a_{x+1,2}},x+1,2)\)。
  • \((val,x,2)\to (val-(a_{x,2}-a_{x,1})+(a_{x+1,2}-a_{x+1,1}),x+1,2)\)。

但是注意:我们仍然要保证不断变劣(递增),而 \(-(a_{x,2}-a_{x,1})+(a_{x+1,2}-a_{x+1,1})\) 可能是负数,但是我们只需要数组间按照 \((a_{x,2}-a_{x,1})\) 递增排序即可。有点类似“反悔”的操作。

细节:对于长度为 \(1\) 的数组,我们必须选且不能改变,所以提前算出这些的和,不把他们插进 vector 里即可。

例题:P2541 [USACO16DEC] Robotic Cow Herd P。

与 k 短路的联系:不难发现本题可以直接图论建模,分层图求 k 短路,不过有些小题大做了。

3.Multisets(Shopping Plans)

有 \(n\) 个物品,每个物品有种类 \(a\) 和价格 \(c\)。

对于第 \(j\) 个种类,购买个数必须在 \([x_j,y_j]\) 的限制内。输出价格前 \(k\) 小的方案。

将两者结合起来。外层仍然是 Arrays 的做法,转移到当前数组的下一个位置 \((x,y)\to (x,y+1)\) 就是 Multiset 取到下一个子集。

数组间是按照 \(a_{j,x_{j}+1}-a_{j,x_{j}}\) 排序的。

说起来容易,实现起来或许非常困难。主要在于本题出人意料的特殊情况处理。

4.Tree

求树上第 \(k\) 小连通块点权和。

先考虑包含根的连通块,对有根树求出 dfs 序,建立一张新图:

  • \(i\to i+1\) 表示选择 \(id_i\) 这个点。
  • \(i\to i+siz_i\) 表示跳过 \(i\) 的子树。

然后问题转换为 DAG k 短路。外面再套一层点分治,即可将无根转换为有根。复杂度 \(O(n\log^2)\)。

5.Permutation

雷暴太强大:关于一类求前 k 优解的问题 - Cry_For_theMoon - 博客园 (cnblogs.com)

标签:trans,Shopping,Plans,val,kth,数组,每个,移动,log
From: https://www.cnblogs.com/AK-IOI/p/18418766

相关文章

  • A Walkthrough Using Acquire and Release Fences
    We’lltaketheexamplefrommypreviouspostandmodifyittouseC++11’sstandaloneacquireandreleasefences.Here’stheSendTestMessagefunction.Theatomicwriteisnowrelaxed,andareleasefencehasbeenplacedimmediatelybeforeit.voidSen......
  • HACKTHEBOX——Brainfuck
    靶机详情靶机地址:10.10.10.17攻击地址:10.10.16.3端口服务扫描首先依旧要确定攻击主机能否Ping通靶机使用nmap或者其他工具扫描目标开放了哪些端口与服务渗透过程从上图可以看到目标开放了135、139、445端口,开放了Smb服务,这个服务有个大名鼎鼎的漏洞就是永恒之......
  • HACKTHEBOX——Lame
    靶机详情靶机地址:10.10.10.3攻击地址:10.10.14.10端口服务扫描先确认kali是否与靶机互通接下来使用nmap或者其他工具扫描一下靶机开放了哪些端口以及服务渗透过程根据htb中的flag提示完成前两个任务第三个任务提示VSFTPd2.3.4存在一个著名的后门,尝试使用ms......
  • 学习笔记(?):一类查询 kth 的整体二分 trick
    问题大概就是有若干次修改(也有可能没有)和若干次查询,查询形如查某个范围的kth。做法是,把可能成为答案的候选集合按照权值大小排序。询问集合可以不用管顺序。然后开始二分。我们令solve(l,r,L,R)表示第\(l\)到\(r\)个询问的kth一定在候选序列的第\(L\)到\(R\)个数。......
  • kworker和kthread
    kworker和kthread都是Linux内核中的组件,它们在内核中扮演着不同的角色,但也有着一定的联系。kworker定义与功能:定义:kworker是Linux内核中的一个工作线程,用于异步处理工作队列(workqueue)中的任务。这些任务包括但不限于处理硬件中断、文件系统事件、管理系统内存等。功能:kworker......
  • [LeetCode] 2053. Kth Distinct String in an Array
    Adistinctstringisastringthatispresentonlyonceinanarray.Givenanarrayofstringsarr,andanintegerk,returnthekthdistinctstringpresentinarr.Iftherearefewerthankdistinctstrings,returnanemptystring"".Notethat......
  • Solution - Atcoder AGC022D Shopping
    考虑到不管怎么走,都是\(0\)最后又绕回\(0\),于是答案肯定是\(2L\)的倍数。那么考虑\(\frac{\operatorname{ans}}{2L}\)即可。那么对于\(t_i\),可以先让答案加上\(\lfloor\frac{t_i}{2L}\rfloor\),同时令\(t_i\leftarrowt_i\bmod2L\)。原因就是考虑到这被去除掉的\(2......
  • Hackthebox bagel.dll 代码审计
    利用ilspy将bagel.dll打开关于此目录有可以说的内容目录解析最上方的bagel是组装名字(assemblename)bagel_server是命令空间(namespace)下一级分支是类如File,Base,Handler,Orders等(class)反序列化导致的命令执行漏洞代码审计思路 首先看主程序Bagel1.通过明显的英语翻......
  • HackTheBox(黑客盒子)基础模块速通Responder篇
    前言  还是速通,直接给大家上解题思路。这台靶机侧重使用responder工具通过黑化kali获取hash。靶机提供准备目标靶机网络连通题目已披露的漏洞环境实战攻击任务一unika.htb任务二直接上nmap扫服务,试试看能否爆出来。nmap-sV-T410.129.253.226可以看......
  • Fallout Walkthrough
    TheNearlyUltimateFalloutGuideVersion1.1WrittenandcodedbyPerJornerThemainthingyouwillfindinFO1isthereislessofeverything.Ofcourse,itshouldcomeasnosurprisethatthefirstgameintheserieswouldbesmallerthanthesequel.......