当前位置: 首页 > news >正文

P3195 [HNOI2008] 玩具装箱 斜率优化

from DP...

原来一直阻碍我学习斜率优化的是原转移方程推不出来呀。

终于鼓起勇气来学斜率优化了。

问题描述

  • \(n\) 个玩具,每个玩具长度为 \(c_i\)
  • 需要将玩具分成若干组,每组包含连续的玩具
  • 对于一组玩具从 \(i\)\(j\),容器长度 \(x\) 计算为:

    \[x = \sum_{k=i}^{j} c_k + (j - i) \]

    其中 \(j - i\) 是玩具之间的空隙数量
  • 容器的制作成本为 \((x - L)^2\),其中 \(L\) 是给定常数
  • 目标:最小化总成本

原转移方程

定义 \(dp[i]\) 为前 \(i\) 个玩具的最小总成本。最终答案是 \(dp[n]\)

为了计算 \(dp[i]\),考虑最后一组玩具的结束位置,相当于针对每个需计算的 \(dp[i]\) 枚举它最后一个的分组情况。假设最后一组是从 \(j\)\(i\)(其中 \(1 ≤ j ≤ i\)),那么:

  • \(j-1\) 个玩具的最小成本为 \(dp[j-1]\)
  • 最后一组(从 \(j\)\(i\))的成本为 \(cost(j, i)\)

因此:

\[dp[i] = \min_{1 ≤ j ≤ i} \{ dp[j-1] + cost(j, i) \} \]

计算 \(cost(j, i)\)

根据容器长度公式:

\[x = \sum_{k=j}^{i} c_k + (i - j) \]

成本为:

\[cost(j, i) = (x - L)^2 = \left( \sum_{k=j}^{i} c_k + (i - j) - L \right)^2 \]

引入前缀和数组 \(s\),其中 \(s[i] = \sum_{k=1}^{i} c_k\),那么:

\[cost(j, i) = \left( (s[i] - s[j-1]) + (i - j) - L \right)^2 \]

因此,转移方程变为:

\[dp[i] = \min_{1 ≤ j ≤ i} \{ dp[j-1] +\left(s[i] + i - s[j-1] - j - L \right)^2\} \]

斜率优化

化式子

关于原转移方程,将其变为:

\[dp[i] = \min_{0 ≤ j < i} \{ dp[j] +\left(s[i] + i - s[j] - j - (L + 1) \right)^2\} \]

定义新数组 \(t[i] = s[i] + i\),并令 \(C = L+1\),则:

\[dp[i] = \min_{0 ≤ j < i} \{ dp[j] + (t[i] - t[j] - C)^2 \} \]

其中:

  • \(t[i] = s[i] + i\)
  • \(s[i]\) 是前缀和(\(s[0] = 0\),所以 \(t[0] = 0\)
  • \(C = L+1\)

首先将平方项展开:

\[dp[i] = \min_{0 ≤ j < i} \{dp[j]+t[i]^2-2t[i]t[j]-2t[i]C+t[j]^2+2t[j]C+C^2\} \]

再合并:

\[dp[i] = \min_{0 ≤ j < i} \{t[i]^2-2t[i]t[j]-2t[i]C+(t[j]+C)^2\} \]

将与 \(j\) 无关的项分离出来:

\[dp[i] = \min_{0 ≤ j < i} \{dp[j]+(t[j]+C)^2-2t[i]t[j]\}+t[i]^2-2t[i]C \]

问题转换

我们定义两个新函数:

  1. \(X(j) = t[j]\)
  2. \(Y(j) = dp[j] + (t[j] + C)^2\)

代入后:

\[dp[i] = \min_{0 \leq j < i} \{ Y(j) - 2t[i]X(j) \} + t[i]^2 - 2t[i]C \]

现在,关键来了!

为什么要这样定义,发现方程中要求 $Y(j) - 2t[i]X(j) $,那么假设 \(Y(j) - 2t[i]X(j)=b\),那么 \(Y(j)=2t[i]X(j)+b\)

\(k\) 设为 \(2t[i]\),发现 \(Y(j)=kX(j)+b\) 不就是一条经过 \((X(j),Y(j))\) 斜率为 \(k\),截距为 \(b\) 的直线吗?

所以 \(Y(j)-kX(j)\) 是什么,就是一条经过 \((X(j),Y(j))\) 斜率为 \(k\) 的直线与 \(y\) 轴的交点(的横坐标)。

所以问题:

\[\min_{0 \leq j < i} \{ Y(j) - 2t[i]X(j) \} \]

就等价于:
对于每个 \(dp[i]\) 找到一个点 \((X(j), Y(j))\),使得斜率为 \(2t[i]\) 的直线经过该点时,在 \(y\) 轴上的截距最小,它对答案的贡献就是这个最小截距。

开始优化

针对每个 \(dp[i]\),要使它候选决策点 \((X(j), Y(j))\) 对他的贡献最小,肯定要使直线的截距更小。但每个 \(i\) 不定,它的斜率 \(k\) 也就是 \(2t[i]\) 也不定,那怎样才能维护出一个正确的最优节点呢?

最优点集

假设一张图上有一些点,我们想让它们在未知斜率的情况下截距最小,那么哪些点可能会是最小的呢?

虽然不知道斜率是多少,但我们知道斜率的正负(\(2t[i]\) 肯定为正),也就是直线成上升趋势,我们发现,如果此时有多个点,未知斜率直线的最小截距,只有可能在经过 A,C,D,E 的直线上产生,也就是最优点不可能是 B 点,因为不管一条斜率为多少(不为负)的直线经过 B 它的截距一定比同斜率经过 A 点的直线大。

所以不在凸包上的一定不会为最优点,而且在凸包上的也不一定为最优点,比如说 A 点和 C 点,在 C 点被算出来之前,A 点是最优点,而在 C 点被算出来以后,A 点将永远不会成为最优点。

而且针对不同斜率,最优点也是不一样的,比如斜率稍大时可能 E 点是最优点,而当斜率稍小时 C 有可能成为最优点。所以这就是为什么说要先维护一个最优点集而不是一个最优点。

那这个点集该怎么维护呢?

发现:对于三个点 \(A = (X_a, Y_a)\), \(B = (X_b, Y_b)\), \(C = (X_c, Y_c)\),如果 \(B\)\(A\)\(C\) 连线的上方,那么 \(B\) 不在凸包上。

数学上,这可以通过斜率来判断:

  • 如果 \(\frac{Y_b - Y_a}{X_b - X_a} \geq \frac{Y_c - Y_b}{X_c - X_b}\),那么 \(B\) 不在凸包上

翻译过来就是,如果 \(AB\) 的斜率大于 \(BC\) 的斜率那么 \(B\) 不在凸包上。

如何维护

当我们计算完 \(dp[i]\) 后,我们得到一个新点 \((X(i), Y(i))\)。我们需要将这个点添加到凸包中。假设我们已经有凸包上的点序列:\(P_1, P_2, ..., P_m\)(按 \(X\) 坐标排序)

当我们添加新点 \(P_{new}\) 时,需要检查最后三个点 \(P_{m-1}, P_m, P_{new}\) 是否满足凸包性质。

判断条件:

  • 如果 \(\text{slope}(P_{m-1}, P_m) \geq \text{slope}(P_m, P_{new})\),那么 \(P_m\) 不在凸包上,应该被移除
  • 反之直接添加即可

$\text{slope}(A,B) $ 表示直线 AB 的斜率。

若移除 \(P_m\) 后,我们需要继续检查 \(P_{m-2}, P_{m-1}, P_{new}\),直到满足凸包性质。

实现起来也相对简单,拿一个数组来存当前凸包上的值,照着上面维护就行了。

	while(End>=1){if(slope(tb[End-1],tb[End])>=slope(tb[End],i))End--;elsebreak ;}tb[++End]=i;

其实为什么是 while(End>=1)还有点不懂。

一个大概的解释是:

既然进来一个点要检查他前两个点,那当 \(End=1\) 意味着要比较 \(tb[0]\)\(tb[1]\)\(i\) 点,这说明原点还有一条连向凸包的边。

所以说,维护出来的凸包将会是一条过原点的曲线,那么上面说的“在 C 点被算出来以后,A 点将永远不会成为最优点”实际上 A 点已经不在凸包上了?线段 AC 将被移除,取而代之的是一条由原点连向 C 点的线段。

但实际上是没有这条线段的,只是为了更改第一个点。

最优点

好了,现在最优点集维护出来了,那怎么找出上面最优的点呢?

二分查找

这是一个通用的写法。

已知当前直线斜率为 \(2t[i]\),如何找到最优点使得截距最小?

如图,当前斜率为 \(k\) 的凸包上的点有四条,肉眼可见蓝色直线的斜率最低,那 D 点是怎么找出来的呢?

对于给定的斜率 \(k\),我们要在凸包上找到那个最优的点 \(j\),使得:

  • \(\text{slope}(j-1, j) < k \leq \text{slope}(j, j+1)\)

也就是当 \(j-1\)\(j\) 的斜率比 \(k\) 小,\(j\)\(j+1\) 的斜率比 \(k\) 大时,\(j\) 为最优点。(应该不难理解)

代码也很清新

    int k=2*t[i];int l=0,r=End;while(l<r){int mid=(l+r)/2;if(slope(tb[mid],tb[mid+1])<k){l=mid+1;}else{r=mid;}}dp[i]=Y(tb[l])-t[i]*2*X(tb[l])+t[i]*t[i]-2*t[i]*C;;

于是玩具装箱的二分版代码就出来了
::::info[代码]

#include<bits/stdc++.h>
using namespace std;
#define N 50005
#define int long longint n,L,C,End;
int c[N],sum[N],dp[N],t[N],tb[N];int X(int i){return t[i];
}int Y(int i){return dp[i]+(t[i]+C)*(t[i]+C);
}float slope(int j,int k){return 1.0*(Y(j)-Y(k))/(1.0*(X(j)-X(k)));
}signed main(){cin>>n>>L;C=L+1;for(int i=1;i<=n;i++){cin>>c[i];sum[i]=sum[i-1]+c[i];t[i]=sum[i]+i;}memset(dp,0x3f3f3f,sizeof(dp));dp[0]=0;for(int i=1;i<=n;i++){int k=2*t[i];int l=0,r=End;while(l<r){int mid=(l+r)/2;if(slope(tb[mid],tb[mid+1])<k){l=mid+1;}else{r=mid;}}dp[i]=Y(tb[l])-t[i]*2*X(tb[l])+t[i]*t[i]-2*t[i]*C;;while(End>=1){if(slope(tb[End-1],tb[End])>=slope(tb[End],i))End--;elsebreak ;}tb[++End]=i;}cout<<dp[n];return 0;
}

::::

二分查找的话,复杂度还有个 \(log\),怎样把 \(log\) 给去掉呢?

单调队列

http://www.jsqmd.com/news/144710/

相关文章:

  • comsol悬浮绝缘子电场计算模型,可以得到绝缘子各个部位电势及电场分布,提供comsol详细...
  • mybatis insert后返回id
  • IRC协议:穿越时光的互联网实时聊天奠基者
  • 专科生必看!9个高效降aigc工具推荐,轻松过审不踩坑
  • Java面试:为何必须在循环中检查等待条件?避坑指南!
  • LuatOS下载不求人:完整流程与高频问题应对策略
  • 课后作业2
  • 2025年12月绵阳米粉/米线加工厂综合比较 - 2025年品牌推荐榜
  • 2025年12月江苏徐州别墅庭院设计、屋顶花园设计、公园绿地设计、市政广场设计、生态园区设计服务商排行榜 - 2025年品牌推荐榜
  • 运用 Python 将 Markdown 转换为 Word、HTML、PDF、PNG 和 JPG
  • 基于Spring Boot和Vue.js的视频点播管理系统设计与实现
  • pg_waldump 和 pg_xlogdump
  • 一个简单想法的实验随笔-胜任能力
  • 高精度光学动作捕捉如何为无人机提供飞行姿态与轨迹真值?——以IROS 2025多篇无人机学习与控制研究为例
  • 让回忆“动”起来:手把手教你制作老照片动态视频
  • 2025最新!自考党必看9个AI论文平台测评与推荐
  • CF1295F Good Contest/[APIO2016] 划艇
  • 郑州家装公司五大推荐:优质装修/别墅装修/老房翻新精选,华埔装饰砸无赦承诺引领行业新风尚 - 深度智识库
  • 基于Spring Boot和Vue.js的房屋出租管理系统设计与实现
  • 2025年12月江苏徐州变压器系列,智能变电站,新能源配套,高低压配电柜,智慧电力系统厂家选择指南 - 2025年品牌推荐榜
  • 2025年门式冲洗装置直销厂家权威推荐榜单:液压水力冲洗门/水力冲洗门/智能控制拍门源头厂家精选 - 品牌推荐官
  • 2025年蠕变持久试验机生产厂家推荐:哪家公司靠谱/国内哪家性价比高/哪个厂家品质好/哪家售后好 - 品牌推荐大师1
  • 上海策划品牌全案公司推荐:4事业部+长期陪跑(案例集) - 品牌排行榜
  • ModelEngine的Aido智能体【娱乐生涯 AI 助手】升级计划——工作流编排精确制导AI应用
  • 哪家上海装修公司口碑最好?21年零投诉实力验证 - 品牌排行榜
  • 告别传统低效!AgentRun 如何用 Serverless + Agent 打造现代化的舆情分析系统?
  • 2025年图书档案标签厂家实力推荐:超高频抗金属标签/耐高温电子标签/rfid标签定制厂家精选 - 品牌推荐官
  • 学长亲荐9个AI论文工具,研究生轻松搞定开题报告!
  • 西门子模拟量处理程序块:滤波峰值,便捷调用报警功能,适用于博图V15及以上版本
  • c# 递归算法