【HNOI2008】玩具装箱TOY & 斜率优化学习笔记
题目
P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为 \(1\cdots N\) 的 \(N\) 件玩具,第 \(i\) 件玩具经过压缩后变成一维长度为 \(C_i\) .为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第 \(i\) 件玩具到第 \(j\) 个玩具放到一个容器中,那么容器的长度将为 \(x=j-i+\sum\limits_{k=i}^{j}C_k\) 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为 \(x\) ,其制作费用为 \((x-L)^2\) .其中 \(L\) 是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过 \(L\) 。但他希望费用最小.
\(0\le n \le 5\times 10^4\)
分析
设 \(f_i\) 代表前 \(i\) 个玩具的最小费用。
显然有:
\]
其中,\(S_{i} = \sum_{j=0}^i C_j\).
使用换元法,将只与 \(i\) 或 \(j\) 有关的项提取出来。(常数项无所谓)
设 \(A_i = i + S_i\), \(B_i = A_i + L + 1\).
则有:
\]
对于决策 \(j\) ,设:
\]
最优的 \(j\) 就是使 \(b\) 最小的 \(j\).
移项得:
\]
发现这个式子非常眼熟,设 \(k = 2A_i, y = f_j + B_j^2, x = B_j\).
就变成了直线的解析式:\(y = kx + b\)
而这个式子中,对于所有的决策,斜率 \(k\) 都是常量,我们需要找到一个 \(j\) 使得截距最小。
对于每一个决策 \(j\) 都给出了一个点 \(P_j(B_j, f_j + B_j^2)\),问题就转换成了:已知若干个点和斜率(\(k>0\)),求过这些点之中一个且斜率为给定值的直线中截距最小的一个。
考虑这样一条不断向上移动的直线,当它不断上移时截距越来越大,直到它碰到第一个点为止,这个点就是使截距最小的点。
引理:候选决策连线段的斜率必然递增
证明:\(j\) 要是 \(i\) 时最优决策,它必须满足:
\]
即:
2A_i(B_j + B_k) & < f_k + B_k^2 - f_j - B^2_j \\
2A_i & < \frac{f_k + B_k^2 - (f_j + B^2_j)}{B_j + B_k}
\end{align*}
\]
我们发现,这就是 \(P_jP_i\) 的斜率 \(> 2A_i\).
而 \(2A_i\) 就是我们不断上移的直线的斜率 \(k\).
所以,若 \(B\) 可能是最优决策点,则另外一个可能的最优决策点 \(C\) 必然在直线 \(y = kx + b\) 的左侧而非右侧。
所以,最优解一定在决策的下凸壳上。
我们可以轻易的证明 \(A_i\) 单调递增。
考虑使用一个单调队列维护第一个使得斜率 \(>A_i\) 的点,然后就结束了。
不过,有时候 \(A_i\) 没有单调递增,那就需要Cdq或者平衡树维护了,那就是下篇的事了。
代码
#include <bits/stdc++.h>
typedef long long ll;
const double eps = 1e-7;
const int kMaxN = 5e5 + 5;
ll S[kMaxN], f[kMaxN], C[kMaxN], n, L;
std::deque<int> que;
ll A(int i) {return i + S[i];}
ll B(int i) {return A(i) + L + 1;}
ll PointX(int i) {return B(i);}
ll PointY(int i) {return f[i] + B(i) * B(i);}
double Slope(int i, int j) {
return (PointY(i) - PointY(j)) / (double)(PointX(i) - PointX(j));
}
int main() {
scanf("%lld%lld", &n, &L);
for(int i = 1; i <= n; i++) {
scanf("%lld", C + i);
S[i] = S[i - 1] + C[i];
}
f[0] = 0;
que.push_back(0);
for(int i = 1; i <= n; i++) {
while(que.size() > 1 && Slope(que.front(), que[1]) < 2 * A(i))
que.pop_front();
int tmp = que.front();
f[i] = f[tmp] + (A(i) - B(tmp)) * (A(i) - B(tmp));
while(
que.size() > 1 &&
Slope(que.back(), i) < Slope(que.back(), que[que.size() - 2])
)
que.pop_back();
que.push_back(i);
}
printf("%lld", f[n]);
return 0;
}
【HNOI2008】玩具装箱TOY & 斜率优化学习笔记的更多相关文章
- BZOJ 1010: [HNOI2008]玩具装箱toy 斜率优化DP
1010: [HNOI2008]玩具装箱toy Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再 ...
- bzoj1010[HNOI2008]玩具装箱toy 斜率优化dp
1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 11893 Solved: 5061[Submit][S ...
- Bzoj 1010: [HNOI2008]玩具装箱toy(斜率优化)
1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec Memory Limit: 162 MB Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定 ...
- 【bzoj1010】[HNOI2008]玩具装箱toy 斜率优化dp
题目描述 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具, ...
- [luogu3195 HNOI2008] 玩具装箱TOY (斜率优化dp)
题目描述 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具, ...
- P3195 [HNOI2008]玩具装箱TOY 斜率优化dp
传送门:https://www.luogu.org/problem/P3195 题目描述 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任 ...
- 洛谷P3195 [HNOI2008]玩具装箱TOY——斜率优化DP
题目:https://www.luogu.org/problemnew/show/P3195 第一次用斜率优化...其实还是有点云里雾里的: 网上的题解都很详细,我的理解就是通过把式子变形,假定一个最 ...
- 洛谷P3195 [HNOI2008]玩具装箱TOY 斜率优化
Code: #include<cstdio> #include<algorithm> using namespace std; const int maxn = 100000 ...
- bzoj1010: [HNOI2008]玩具装箱toy——斜率优化
方程 $\Large f(i)=min(f(j)+(s(i)-s(j)-1-L)^2)$ 其中$s(i)$为i的前缀和再加上$i$ 对于某个$i$若$j$比$k$优,则 $\large f(j)+(s ...
随机推荐
- org.slf4j.impl.Log4jLoggerAdapter cannot be cast to ch.qos.logback.classic.Logger
https://stackoverflow.com/questions/31433246/classcastexception-org-slf4j-impl-log4jloggeradapter-ca ...
- 一、安装 IntelliJ IDEA
首先,双击打开 IntelliJ IDEA 的快捷方式: 在此,需要说明: 如果咱们的电脑曾经安装过 IntelliJ IDEA,并且你在卸载 IntelliJ IDEA 的时候没有删除其配置文件目录 ...
- OpenMP使用体验报告(概述)
(本文原创,首次使用OpenMP,将使用体会记录下来供学习) OpenMP是啥玩意??? 多核多线程处理器的出现,让并行计算成为可能.在此之前,单核处理器并不能并行计算,这是很显然的,只有一个核心只能 ...
- 通过ajax给后台提交数据时,radio性别数据的获取
通过ajax向后台异步发送数据,经常我们会遇到个人信息额提交,一般我们采用FormData来装数据.在装性别值得时候,我们会有两个radio框,获取radio值得方法如下: 一般情况下,一个radio ...
- Navicat Premium 连接Oracle 数据库之配置
Navicat Premium连接Oracle 数据库之配置 1.Oracle数据库服务器下载 Oracle官方网站下载数据库最新版本:http://www.oracle.com/technetwor ...
- oracle-sql脚本导出EXCEL数据
在数据库中,经常有业务人员提出需求导出数据库中的业务数据,而且是每天.每周或每月定时导出.为了方便,可将sql查询的脚本 通过下面脚本来导出EXCEL数据. 1.将查询sql脚本(AAA.sql)放到 ...
- 02-第一个iOS程序-开发步骤
打开Xcode 选择项目模板 Single View Application是最适合初学者的模板 设置项目属性 运行程序 不管怎样,先运行第一个iOS程序看看效果先(用快捷键Command + R 也 ...
- 【ospf-stub区域配置】
根据项目需求搭建好如下拓扑图 配置rt1的环回口地址及g0/0/0和g0/0/1的ip地址 配rt1的ospf 配置rt2的环回口地址和g0/0/0和g0/0/1 配置rt2的ospf 配置rt3的环 ...
- 部署node api的二三事
当接到node开发node api的时候,我就想用docker来部署,众所周知,node的版本更新迭代很快.很多以前需要babel后才能采用的方法正在不断被node 原生的支持.如果随便更换生产服务器 ...
- 微信程序跳转到页面底部 scroll-view
wx.createSelectorQuery().select('#j_page').boundingClientRect(function (rect) { wx.pageScrollTo({ sc ...