@[斜率優化]

Description

P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压

缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中. P教授有编号为\(1 .. N\)的\(N\)件玩具,第\(i\)件玩具经过压缩后变成一维长度为\(C_i\).为了方便整理, P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容

器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 $$x = j - i + \sum_{k = i}^{j} C_i$$ 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为\(x\), 其制作费用为\((X-L)^2\). 其中\(L\)是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过\(L\). 但他希望费用最小.

Input

第一行输入两个整数N,L.接下来N行输入\(C_i\). \(1 <= N <= 50000, 1 <= L, C_i <= 10^7\)

Output

输出最小费用

Sample Input

5 4
3
4
2
1
4

Sample Output

1

Solution

典型的斜率優化DP

令\(f[i]\)記錄標號為從\(1\)到\(i\)的玩具全部壓縮好所需要的最小費用, 則可以得到DP递推式$$f[i] = min_{j = 0}^{i - 1}(f[j] + (sum[i] - sum[j] + i - j - 1 - L)^2)$$其中\(sum[i]\)記錄編號從\(1\)到\(i\)的玩具的長度總和.

假設在\(i > j > k\)中, 對於\(i\)有\(j\)比\(k\)優, 則$$f[j] + (sum[i] - sum[j] + i - j - 1 - L)^2 < f[k] + (sum[i] - sum[k] + i - k - 1 - L)^2$$

化簡得到

\[\frac{(f[j] + b[j]^2) - (f[k] + b[k]^2)}{b[j] - b[k]} < 2 * a[i]
\]

其中$$a[i] = sum[i] + 1 - L$$$$b[i] = sum[i] + i$$

*Hint: 化簡有一定技巧. 一般來說, 化簡得到的結果要把含\(i\)的項移至等號右邊, 不含\(i\)的項移至左邊, 以方便後續運算.

可以將這個除法式子理解為所謂的斜率, 記為\(slope(j, k)\)

然後用隊列來維護DP. 具體過程如下:

  1. 對於隊頭的兩個元素, 假如有\(slope(queue[head + 1], queue[head]) > 2 * a[i]\)則說明隊列中第二個元素比第一個優, 隊頭出隊.
  2. 此時可以確保隊頭元素是最優解, 用隊頭元素計算出\(f[i]\)的數值
  3. 在有了\(f[i]\)的值的情況下, 就可以在隊尾進行維護了. 對於隊尾的兩個元素記為\(x, y(x > y)\), 假如有\(slope(x, y) > slope(i, x)\)則說明\(x\)是無用的, 可以出隊. 具體證明如下: (1). 假如\(slope(x, y) > slope(i, x) > 2 * a[i]\), 則雖然有\(x\)比\(i\)優, 但又有\(y\)比\(x\)優, 因此\(x\)可出隊; (2). 假如\(slope(x, y) > slope(i, x) < 2 * a[i]\), 則有\(i\)比\(x\)優, \(x\)可出隊.
  4. 將\(i\)加入隊尾

維護過程結束. 注意每一步的順序, 都是有先後性的, 不要搞反.

然後再說道一個點, 這一題一定要開\(long long\)

感覺現階段推公式的能力還要加強, 這一坨東西我推錯了好多次QAQ

附上代碼

#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;
inline long long read()
{
long long x = 0, flag = 1;
char c;
while(! isdigit(c = getchar()))
if(c == '-')
flag *= - 1;
while(isdigit(c))
x = x * 10 + c - '0', c = getchar();
return x * flag;
}
const long long N = 1 << 16;
long long c[N];
long long sum[N];
long long a[N], b[N];
long long queue[N];
long long f[N];
inline long long sqr(long long x)
{
return x * x;
}
inline long double slope(long long x, long long y)
{
return (long double)((f[x] + sqr(b[x])) - (f[y] + sqr(b[y]))) / (long double)(b[x] - b[y]);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ1010.in", "r", stdin);
freopen("BZOJ1010.out", "w", stdout);
#endif
long long n = read(), l = read();
sum[0] = 0;
a[0] = - 1 - l;
b[0] = 0;
for(long long i = 1; i <= n; i ++)
{
c[i] = read();
sum[i] = c[i] + sum[i - 1];
a[i] = sum[i] + i - 1 - l;
b[i] = sum[i] + i;
}
long long head = 0, tail = 1;
queue[head] = 0;
memset(f, 0, sizeof(f));
for(long long i = 1; i <= n; i ++)
{
while(head + 1 < tail && slope(queue[head + 1], queue[head]) < 2 * (float)a[i])
head ++;
f[i] = f[queue[head]] + sqr(a[i] - b[queue[head]]);
while(head + 1 < tail && slope(queue[tail - 1], queue[tail - 2]) > slope(i, queue[tail - 1]))
tail --;
queue[tail ++] = i;
}
printf("%lld\n", f[n]);
}

順便, 這裡想借這一題, 寫一點關於斜率優化的深層次理解, 主要圍繞隊列的維護方面. 首先是入隊, 為什麼要通過這種方式確定隊尾元素的保留還是彈出? 為什麼在\(slope(i, queue[tail - 1]) > 2 * a[i]\)的情況下仍然要將\(i\)入隊? 主要是出於對後效性的考慮. 對於\(2 * a[i]\)不難看出, 它是隨著\(i\)的增大而遞增的. 因此, 對於一個\(i\), 雖然在當前不一定是最優的, 但在之後可能成為最優解, 因此要入隊. 因此在隊尾出隊的原則, 應該是與當前的\(a[i]\)無關的. 至於在隊頭出隊的原則, 也是在考慮到\(2 * a[i]\)的單調性以及確保無後效性的情況下才出隊的.

另外一點就是關於判斷一道題是否可以進行斜率优化. 這主要取決於等式右邊的斜率是否滿足單調性. 雖然說從隊尾出隊的元素與斜率無關, 但是隊頭出隊的元素是需要依賴於斜率的單調性的. 因此斜率是否滿足單調性可以作為一題是否可以採用 常規 的斜率优化的判斷依據.(假如不滿足, 還可以採用特殊的方法優化DP)

BZOJ1010玩具裝箱Toy的更多相关文章

  1. [BZOJ1010]玩具装箱toy(斜率优化)

    Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1... ...

  2. BZOJ-1010 玩具装箱toy (斜率优化)

    题目大意:将n个数分成若干组,并且每组的数在原数组中应是连续的,每组会产生的代价为sum(i)-sum(j)+i-j-1-m,m为已知的常数.求最小代价. 题目分析:定义dp(i)表示将前 i 个元素 ...

  3. [NOIP2016day1T1] 玩具迷題(toy)

    题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业. 有一天, 这些玩具小人把小南的眼镜藏了起来. 小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外.如下图: 这时singer告诉 ...

  4. bzoj1010 玩具装箱

    玩具装箱 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具, ...

  5. Noip2016day1 玩具迷题toy

    题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业. 有一天, 这些玩具小人把小南的眼镜藏了起来. 小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外.如下图: 这时singer告诉 ...

  6. BZOJ1010玩具装箱 - 斜率优化dp

    传送门 题目分析: 设\(f[i]\)表示装前i个玩具的花费. 列出转移方程:\[f[i] = max\{f[j] + ((i - (j + 1)) + sum[i] - sum[j] - L))^2 ...

  7. luogu3195/bzoj1010 玩具装箱(斜率优化dp)

    推出来式子然后斜率优化水过去就完事了 #include<cstdio> #include<cstring> #include<algorithm> #include ...

  8. P3195 [HNOI2008] 玩具装箱(斜率优化DP)

    题目链接 设\(d[i]\)为将前 \(i\) 个玩具装入箱中所需得最小费用 容易得到动态转移方程: \[d[i] = min(d[j] + (s[i]-s[j]+i-j-1-L)^2), (j< ...

  9. HNOI2008题目总结

    呜呼..NOI前一个月正式开始切BZOJ了……以后的题解可能不会像之前的零散风格了,一套题我会集中起来发,遇到一些需要展开总结的东西我会另开文章详细介绍. 用了一天的时间把HNOI2008这套题切了… ...

随机推荐

  1. 转:跟我一起写Makefile (PDF重制版)

    原文地址:http://seisman.info/how-to-write-makefile.html 其它一些问题  不妨看一下:http://blog.csdn.net/huyansoft/art ...

  2. oracle如何保证读一致性 第一弹

    oracle保证读一致性原理   1:undo segment的概念                   当数据库进行修改的时候,需要把保存到以前的old的数据保存到一个地方,然后进行修改,用于保存o ...

  3. POJ:1185-炮兵阵地(状压dp入门)

    炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组 ...

  4. Linux学习-循环执行的例行性工作排程

    循环执行的例行性工作排程则是由 cron (crond) 这个系统服务来控制的.Linux 系统上面原本就有非常多的例行性工作,因此这个系统服务是默认启动的. 另外, 由于使用者自己也可以进行例行性工 ...

  5. HDU 5527 Too Rich 贪心

    题意: 有\(10\)种面值为\(1, 5, 10, 20, 50, 100, 200, 500, 1000, 2000\)的纸币,现在你要选最多的数量凑成\(p\)块钱. 分析: 同样分析问题的反面 ...

  6. Scala学习-01-变量与类型

    Scala运行在jvm之上,可以调用Java类库和与Java框架交互,并将面向对象与面向函数结合在一起. 特点: 1 保留了静态类型检查.安全保障高. 2 函数式编程,更加灵活. 3 运行于jvm之上 ...

  7. Selenium WebDriver的多浏览器测试

    1. IE浏览器,需要配合下载IEDriverSever.exe的驱动程序,目前selenium支持IE9以上. (驱动程序下载链接:https://pan.baidu.com/s/1YpaUsIs1 ...

  8. python之路 --- python模块初认识&数据类型

    一.模块初识 首先,文件名不能和导入的模块名称一样.因为系统默认先从当前文件寻找模块名,如果文件名和导入的模块名称一样的话,就相当于自己调用自己,会找不到相应的方法的. sys模块 sys.path  ...

  9. javascript学习笔记 - 引用类型 Function

    五 Function类型 每个函数都时Function类型的实例.函数也是对象. 声明函数: function func_name () {} //javascript解析器会在程序执行时率先读取函数 ...

  10. c/c++内存泄露的检测方法

    此文内容摘自 https://zhuanlan.zhihu.com/p/22664202 作为   从零开始的 JSON 库教程(三):解析字符串解答篇  的笔记 1A. Windows 下的内存泄漏 ...