【题解】P9499 dp凸优化 复杂度分析
很典但也很妙的题。
首先有一个显然暴力的 dp:从前往后一个一个换,记录目前剩的货币的数量, 目前换完第换完第 种货币,保留了 张,可以赚到多少钱,转移如下:
兑换货币:
在这一步将 张货币用于获取价值,剩下的保留换取更靠后的货币(完全背包):
和值域相关,需要优化,往往要把这种直接放在值域上的东西转化成分段离散的东西来维护,我们把 dp 拍平(滚动数组)观察转移是对 dp 数组进行怎样的操作:
- 在开头放 个 ,整体右移。
- 从后往前,每个位置加上 去更新前一个位置(完全背包)。
- 将数组“放缩 倍”,即只保留 这些项。
这种形态的 dp 往往都不太好维护或是直接优化转移,分析可以发现 dp 值构成了一个上凸包:
- 显然 dp 值是单调递减的,所以在开头插入一段 不影响凸性。
- 从后往前,每个位置加上 去更新前一个位置,等价于与数组 做一个闵可夫斯基和(只不过是差卷积的形态)。
- 放缩 倍后显然不改变凸性:其单减的差分数组上两段等长的区间,靠前那段一定和不会更小。
考虑维护这个上凸包,经典地,维护差分数组的分段函数。
前两种操作是很经典的,第一种操作直接在数组的前面插入一段 ,第二种操作相当于将前面一段斜率小于 的值给弹出,换成斜率为 的段。
第三种操作我们直接暴力完成(当 时):
对于每个原来凸包上的拐点,找到其前后第一个横坐标为 的倍数的点称作特殊点,然后将相邻两个特殊点连起来。
两个中间有拐点的特殊点在缩放后的横坐标差为 ,直接计算斜率,而中间没有拐点的特殊点直接将斜率扩大 倍即可。
下面我们来证明直接暴力完成的复杂度是正确的:
-
首先每次暴力操作会让所有点的坐标至少减半,然后两个凸包拐点的距离也会至少变成除二上取整。
-
虽然每次放缩有可能会使凸包的点数翻倍(每个点前后各取一个),但是这些距离为 的点对在下一次放缩时一定会每组消失至少一个。
所以复杂度为 ,常数不大。
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17970909,谢谢你的阅读或转载!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步