像潮落潮涌,送我奔向自由。|

寂静的海底

园龄:3年2个月粉丝:59关注:15

【题解】P9499 dp凸优化 复杂度分析

很典但也很妙的题。

首先有一个显然暴力的 dp:从前往后一个一个换,记录目前剩的货币的数量,fi,j 目前换完第换完第 i 种货币,保留了 j 张,可以赚到多少钱,转移如下:

兑换货币:

fi,jxi1+ci=fi1,j

在这一步将 k 张货币用于获取价值,剩下的保留换取更靠后的货币(完全背包):

fi,j=max0kj{fi,j+k+kv}

和值域相关,需要优化,往往要把这种直接放在值域上的东西转化成分段离散的东西来维护,我们把 dp 拍平(滚动数组)观察转移是对 dp 数组进行怎样的操作:

  • 在开头放 c0,整体右移。
  • 从后往前,每个位置加上 v 去更新前一个位置(完全背包)。
  • 将数组“放缩 x 倍”,即只保留 x,2x,,kx 这些项。

这种形态的 dp 往往都不太好维护或是直接优化转移,分析可以发现 dp 值构成了一个上凸包:

  • 显然 dp 值是单调递减的,所以在开头插入一段 0 不影响凸性。
  • 从后往前,每个位置加上 v 去更新前一个位置,等价于与数组 {0,v,2v,....,kv} 做一个闵可夫斯基和(只不过是差卷积的形态)。
  • 放缩 x 倍后显然不改变凸性:其单减的差分数组上两段等长的区间,靠前那段一定和不会更小。

考虑维护这个上凸包,经典地,维护差分数组的分段函数。

前两种操作是很经典的,第一种操作直接在数组的前面插入一段 0,第二种操作相当于将前面一段斜率小于 v 的值给弹出,换成斜率为 v 的段。

第三种操作我们直接暴力完成(当 x>1 时):

对于每个原来凸包上的拐点,找到其前后第一个横坐标为 x 的倍数的点称作特殊点,然后将相邻两个特殊点连起来。

两个中间有拐点的特殊点在缩放后的横坐标差为 1,直接计算斜率,而中间没有拐点的特殊点直接将斜率扩大 x 倍即可。

下面我们来证明直接暴力完成的复杂度是正确的:

  • 首先每次暴力操作会让所有点的坐标至少减半,然后两个凸包拐点的距离也会至少变成除二上取整。

  • 虽然每次放缩有可能会使凸包的点数翻倍(每个点前后各取一个),但是这些距离为 1 的点对在下一次放缩时一定会每组消失至少一个。

所以复杂度为 O(nlogci),常数不大。

posted @   寂静的海底  阅读(34)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起