斜率优化板题 HDU 3507 Print Article
- 题目大意:输出N个数字a[N],输出的时候可以连续的输出,每连续输出一串,它的费用是 “这串数字和的平方加上一个常数M”。n<=500000
- 我们设dp[i]表示输出到i的时候最少的花费,sum[i]表示从a[1]到a[i]的数字和。于是方程就是: dp[i]=dp[j]+M+(sum[i]-sum[j])^2;
- 很显然这个是一个二维的。题目的数字有500000个,不用试了,二维铁定超时了。那我们就来试试斜率优化吧,看看是如何做到从O(n^2)复杂度降到O(n)的。
- 我们假设k<j<i。如果在j的时候决策要比在k的时候决策好,那么也是就是dp[j]+M+(sum[i]−sum[j])2<=dp[k]+M+(sum[i]−sum[k])2dp[j]+M+(sum[i]-sum[j])^2 <= dp[k]+M+(sum[i]-sum[k])^2dp[j]+M+(sum[i]−sum[j])2<=dp[k]+M+(sum[i]−sum[k])2。(因为是最小花费嘛,所以优就是小于)
- 两边移项一下,得到:
(dp[j]+sum[j]2)−(dp[k]+sum[k]2)<=(sum[j]−sum[k])∗2∗sum[i](dp[j]+sum[j]^2)-(dp[k]+sum[k]^2) <= (sum[j]-sum[k])*2*sum[i](dp[j]+sum[j]2)−(dp[k]+sum[k]2)<=(sum[j]−sum[k])∗2∗sum[i]
将(sum[j]−sum[k])(sum[j]-sum[k])(sum[j]−sum[k])除过去,得到:
[(dp[j]+sum[j]2)−(dp[k]+sum[k]2)]/(sum[j]−sum[k])<=2∗sum[i][(dp[j]+sum[j]^2)-(dp[k]+sum[k]^2)]/(sum[j]-sum[k]) <= 2*sum[i][(dp[j]+sum[j]2)−(dp[k]+sum[k]2)]/(sum[j]−sum[k])<=2∗sum[i] - 令xxxi =dp[i]−sum[i]= dp[i]-sum[i]=dp[i]−sum[i]2, yyyi =2∗sum[i]= 2*sum[i]=2∗sum[i].
那么不就是yyyj−y-y−yk/x/x/xj−x-x−xk<=2∗sum[i]<=2*sum[i]<=2∗sum[i]么? 左边是不是斜率的表示?
那么(y(y(yj−y-y−yk)/(x)/(x)/(xj−x-x−xk)<=2∗sum[i])<=2*sum[i])<=2∗sum[i]说明了什么呢?
说明k[j,k]=(yk[j,k]=(yk[j,k]=(yj−y-y−yk)/(x)/(x)/(xj−x-x−xk)<=2∗sum[i])<=2*sum[i])<=2∗sum[i]代表这j的决策比k的决策要更优。 - 关键的来了:若k<j<ik<j<ik<j<i且k[i,j]<k[j,k]k[i,j]<k[j,k]k[i,j]<k[j,k],则j点永远不可能成为最优解,可以直接将它踢出我们的最优解集。为什么呢?
分三种情况讨论:
设当前点为a
1.如果k[i,j]k[i,j]k[i,j]与k[j,k]k[j,k]k[j,k]均小于2∗sum[a]2*sum[a]2∗sum[a],则i比j优,j比k优
2.如果k[i,j]k[i,j]k[i,j]与k[j,k]k[j,k]k[j,k]均大于2∗sum[a]2*sum[a]2∗sum[a],则k比j优,j比i优
3.如果k[i,j]<sum[a]k[i,j]<sum[a]k[i,j]<sum[a]且k[i,j]>2∗sum[a]k[i,j]>2*sum[a]k[i,j]>2∗sum[a],则i比j优,k比j优
不论如何,j都无法成为最佳决策点,所以可以排除j
于是,所有的决策点满足一个下凸包性质 - 接下来看看如何找最优解。 设k<j<ik<j<ik<j<i。
由于我们排除了k[i,j]<k[j,k]k[i,j]<k[j,k]k[i,j]<k[j,k]的情况,所以整个有效点集呈现一种下凸性质,即k[i,j]>k[j,k]k[i,j]>k[j,k]k[i,j]>k[j,k]。
这样,从左到右,斜率之间就是单调递增的了。当我们的最优解取得在j点的时候,那么k点不可能再取得比j点更优的解了,于是k点也可以排除。换句话说,j点之前的点全部不可能再比j点更优了,可以全部从解集中排除。

- 于是对于这题我们对于斜率优化做法可以总结如下:
1.用一个单调队列来维护解集。
2.假设队列中从头到尾已经有元素a b c。那么当d要入队的时候,我们维护队列的下凸性质,即如果k[d,c]<=k[c,b]k[d,c]<=k[c,b]k[d,c]<=k[c,b],那么就将c点删除。直到找到k[d,x]>k[x,y]k[d,x]>k[x,y]k[d,x]>k[x,y]为止,并将d点加入在该位置中。
3.找最佳决策点时,设当前求解状态为i,从队头开始,如果已有元素a b c,当i点要求解时,如果k[b,a]<=2∗sum[i]k[b,a]<=2*sum[i]k[b,a]<=2∗sum[i],那么说明b点比a点更优,a点可以排除,于是a出队,直到第一次遇到k[j,j−1]>2∗sum[i]k[j,j-1]>2*sum[i]k[j,j−1]>2∗sum[i],此时j-1即为最佳决策点。

参考代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 500005;
int n, m, s, t, dq[MAXN];
int sum[MAXN], f[MAXN];
inline int Getup(int i, int j) { return f[i] + sum[i]*sum[i] - f[j] - sum[j]*sum[j]; } //Yi-Yj
inline int Getdown(int i, int j) { return sum[i] - sum[j]; } //Xi-Xj
int main ()
{
int x;
while(scanf("%d%d", &n, &m) == 2)
{
for(int i = 1; i <= n; i++) scanf("%d", &x), sum[i] = sum[i-1] + x;
f[0] = 0; s = t = 0; dq[t++] = 0;
for(int i = 1; i <= n; i++)
{
while(t-s > 1 && Getup(dq[s+1], dq[s]) <= sum[i] * 2 * Getdown(dq[s+1], dq[s])) s++;
f[i] = f[dq[s]] + (sum[i] - sum[dq[s]]) * (sum[i] - sum[dq[s]]) + m;
while(t-s > 1 && Getup(i, dq[t-1]) * Getdown(dq[t-1], dq[t-2]) <= Getup(dq[t-1], dq[t-2]) * Getdown(i, dq[t-1])) t--;
dq[t++] = i;
}
printf("%d\n", f[n]);
}
}
斜率优化板题 HDU 3507 Print Article的更多相关文章
- hdu 3507 Print Article(斜率优化DP)
题目链接:hdu 3507 Print Article 题意: 每个字有一个值,现在让你分成k段打印,每段打印需要消耗的值用那个公式计算,现在让你求最小值 题解: 设dp[i]表示前i个字符需要消耗的 ...
- HDU 3507 Print Article 斜率优化
Print Article Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)To ...
- HDU 3507 Print Article(DP+斜率优化)
Print Article Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) ...
- DP(斜率优化):HDU 3507 Print Article
Print Article Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)To ...
- HDU 3507 Print Article(斜率优化推导)
$dp$,斜率优化. 第一次做斜率优化的题目,看了一些题解,自己总结一下. 这题是说有$n$个数字,可以切成任意段,每一段的费用是这一段数字的和平方加上$M$.问最小费用是多少. 设$dp[i]$为$ ...
- HDU 3507 Print Article(斜率优化DP)
题目链接 题意 : 一篇文章有n个单词,如果每行打印k个单词,那这行的花费是,问你怎么安排能够得到最小花费,输出最小花费. 思路 : 一开始想的简单了以为是背包,后来才知道是斜率优化DP,然后看了网上 ...
- HDU 3507 Print Article(斜率优化)
显然的斜率优化模型 但是单调队列维护斜率单调性的时候出现了莫名的锅orz 代码 #include <cstdio> #include <algorithm> #include ...
- HDU 3507 [Print Article]DP斜率优化
题目大意 给定一个长度为\(n(n \leqslant 500000)\)的数列,将其分割为连续的若干份,使得 $ \sum ((\sum_{i=j}^kC_i) +M) $ 最小.其中\(C_i\) ...
- HDU 3507 - Print Article - [斜率DP]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3507 Zero has an old printer that doesn't work well s ...
随机推荐
- AJAX调用数据,滚动到底部
最近一个小项目里面,需要使用AJAX去拉取数据,并且直接显示最后一条信息,也就是滚动到底部.实现脚本如下: var scrollHeight = $('.txtBox3').prop("sc ...
- (十)pdf的构成之交叉引用表
交叉引用表(xref) 其中包含对文档中所有对象的引用.交叉引用表的目的是允许随机访问文件中的对象,因此我们不需要读取整个PDF文档来定位特定对象.每个对象由交叉引用表中的一个条目表示.(该表保存 ...
- GridControl单元格编辑验证的方法
本文实例演示了DevExpress实现GridControl单元格编辑验证的方法,比较实用的功能,具体方法如下: 主要功能代码如下: /// <summary> /// 自定义单元格验证 ...
- swift版 二分查找 (折半查找)
二分查找作为一种常见的查找方法,将原本是线性时间提升到了对数时间范围之内,大大缩短了搜索时间,但它有一个前提,就是必须在有序数据中进行查找.废话少说,直接上代码,可复制粘贴直接出结果! import ...
- 【1】volatile关键字解析
volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...
- git设置代理模式,仅为github设置代理
设置代理: 全局代理 git config --global http.proxy 127.0.0.1:1087 局部代理,在github clone 仓库内执行 git config --local ...
- FastJson前置属性过滤器
FastJson前置属性过滤器 /** * <html> * <body> * <P> Copyright 1994 JsonInternational</p ...
- Actions require unique method/path combination for Swagger
原文:Actions require unique method/path combination for Swagger services.AddSwaggerGen (c => { c.Re ...
- [golang]按图片中心旋转后的新图左顶点和原图左顶点的偏移量计算
1 前言 略,作为记录使用 2 代码 /** * @Author: FB * @Description: * @File: RotateSample.go * @Version: 1.0.0 * @D ...
- Python报错:ImportError: cannot import name 'ConnectionRefusedError'
启动了一个flask server,结果报了标题中的错误. ImportError: cannot import name 'ConnectionRefusedError' 解决: pip insta ...