斜率优化板题 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 ...
随机推荐
- UV数据与风速风向数据转换
package com.qr.util; import java.text.DecimalFormat; /** * //TODO UV数据与风速风向数据转换 */ public class UVAn ...
- Ubuntu 编译安装 qt-opensource 5.9
平台 :Ubuntu 18.04 QT版本 :5.9.1 (open source) g++ : 7.3.0arm-gcc :4.8.1 qt 需要 gcc4.8版本以上 下载解压,进入对应的 ...
- 属性动画 补间动画 帧动画 基本使用案例 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- win7安装镜像注入USB3.0,NVMe驱动
现在的新款主板和笔记本因为原生自带了USB3.0和NVMe,在安装WIN7的时候会出现进入安装界面后不识别USB设备且在硬盘列表中无法读取M.2类型的固态硬盘信息.导致这个现象的原因就是在WIN7安装 ...
- 使用Powershell启用/关闭Windows功能
接上一篇博客,依旧是需要制作安装包,需要开启系统的MSMQ功能.这里就用到了dism.exe DISM全称是Deployment Image Servicing and Management(部署映像 ...
- $(...).wordExport is not a function
参考网址:https://laod.cn/code-audit/jquery-is-not-a-function.html 问题描述: 1.view页面引用的是jquery-1.10.2.min.j ...
- JVM性能优化--Java的垃圾回收机制
一.Java内存结构 1.Java堆(Java Heap) java堆是java虚拟机所管理的内存中最大的一块,是被所有线程共享的一块内存区域,在虚拟机启动时创建.此内存区域的唯一目的就是存放对象实例 ...
- django.db.utils.InternalError: (1060, "Duplicate column name 'user_id'")迁移报错解决方法
django.db.utils.InternalError: (1060, "Duplicate column name 'user_id'")迁移报错解决方法 django.db ...
- poi读取excel的列和删除列
(各自根据具体的poi版本进行相应的替换即可) package com.br.loan.strategy.common.utils; import lombok.extern.slf4j.Slf4j; ...
- 对比分析HashMap、LinkedHashMap、TreeMap
HashMap的原理 :简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象.HashMap 底层采用一个 Entry[] 数组来保存所有的 ...