• 题目大意:输出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&lt;=dp[k]+M+(sum[i]−sum[k])2dp[j]+M+(sum[i]-sum[j])^2 &lt;= 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)&lt;=(sum[j]−sum[k])∗2∗sum[i](dp[j]+sum[j]^2)-(dp[k]+sum[k]^2) &lt;= (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])&lt;=2∗sum[i][(dp[j]+sum[j]^2)-(dp[k]+sum[k]^2)]/(sum[j]-sum[k]) &lt;= 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&lt;=2∗sum[i]&lt;=2*sum[i]<=2∗sum[i]么? 左边是不是斜率的表示?

    那么(y(y(yj−y-y−yk)/(x)/(x)/(xj−x-x−xk)&lt;=2∗sum[i])&lt;=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)&lt;=2∗sum[i])&lt;=2*sum[i])<=2∗sum[i]代表这j的决策比k的决策要更优。
  • 关键的来了:若k&lt;j&lt;ik&lt;j&lt;ik<j<i且k[i,j]&lt;k[j,k]k[i,j]&lt;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]&lt;sum[a]k[i,j]&lt;sum[a]k[i,j]<sum[a]且k[i,j]&gt;2∗sum[a]k[i,j]&gt;2*sum[a]k[i,j]>2∗sum[a],则i比j优,k比j优

    不论如何,j都无法成为最佳决策点,所以可以排除j

    于是,所有的决策点满足一个下凸包性质
  • 接下来看看如何找最优解。 设k&lt;j&lt;ik&lt;j&lt;ik<j<i。

    由于我们排除了k[i,j]&lt;k[j,k]k[i,j]&lt;k[j,k]k[i,j]<k[j,k]的情况,所以整个有效点集呈现一种下凸性质,即k[i,j]&gt;k[j,k]k[i,j]&gt;k[j,k]k[i,j]>k[j,k]。

    这样,从左到右,斜率之间就是单调递增的了。当我们的最优解取得在j点的时候,那么k点不可能再取得比j点更优的解了,于是k点也可以排除。换句话说,j点之前的点全部不可能再比j点更优了,可以全部从解集中排除。

  • 于是对于这题我们对于斜率优化做法可以总结如下:

    1.用一个单调队列来维护解集。

    2.假设队列中从头到尾已经有元素a b c。那么当d要入队的时候,我们维护队列的下凸性质,即如果k[d,c]&lt;=k[c,b]k[d,c]&lt;=k[c,b]k[d,c]<=k[c,b],那么就将c点删除。直到找到k[d,x]&gt;k[x,y]k[d,x]&gt;k[x,y]k[d,x]>k[x,y]为止,并将d点加入在该位置中。

    3.找最佳决策点时,设当前求解状态为i,从队头开始,如果已有元素a b c,当i点要求解时,如果k[b,a]&lt;=2∗sum[i]k[b,a]&lt;=2*sum[i]k[b,a]<=2∗sum[i],那么说明b点比a点更优,a点可以排除,于是a出队,直到第一次遇到k[j,j−1]&gt;2∗sum[i]k[j,j-1]&gt;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的更多相关文章

  1. hdu 3507 Print Article(斜率优化DP)

    题目链接:hdu 3507 Print Article 题意: 每个字有一个值,现在让你分成k段打印,每段打印需要消耗的值用那个公式计算,现在让你求最小值 题解: 设dp[i]表示前i个字符需要消耗的 ...

  2. HDU 3507 Print Article 斜率优化

    Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)To ...

  3. HDU 3507 Print Article(DP+斜率优化)

     Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) ...

  4. DP(斜率优化):HDU 3507 Print Article

    Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)To ...

  5. HDU 3507 Print Article(斜率优化推导)

    $dp$,斜率优化. 第一次做斜率优化的题目,看了一些题解,自己总结一下. 这题是说有$n$个数字,可以切成任意段,每一段的费用是这一段数字的和平方加上$M$.问最小费用是多少. 设$dp[i]$为$ ...

  6. HDU 3507 Print Article(斜率优化DP)

    题目链接 题意 : 一篇文章有n个单词,如果每行打印k个单词,那这行的花费是,问你怎么安排能够得到最小花费,输出最小花费. 思路 : 一开始想的简单了以为是背包,后来才知道是斜率优化DP,然后看了网上 ...

  7. HDU 3507 Print Article(斜率优化)

    显然的斜率优化模型 但是单调队列维护斜率单调性的时候出现了莫名的锅orz 代码 #include <cstdio> #include <algorithm> #include ...

  8. HDU 3507 [Print Article]DP斜率优化

    题目大意 给定一个长度为\(n(n \leqslant 500000)\)的数列,将其分割为连续的若干份,使得 $ \sum ((\sum_{i=j}^kC_i) +M) $ 最小.其中\(C_i\) ...

  9. 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 ...

随机推荐

  1. 在CAD中插入谷歌地球卫星地图

    本文主要介绍如何在CAD中插入谷歌地球卫星地图,作为参照光栅图像.谷歌地球卫星地图使用“迈高图-地图数据下载器”(以下简称:迈高图)下载.迈高图会给出相关插入参数(插入点和缩放比例),保证插入卫星地图 ...

  2. 【Python爬虫案例学习】python爬取淘宝里的手机报价并以价格排序

    第一步: 先分析这个url,"?"后面的都是它的关键字,requests中get函数的关键字的参数是params,post函数的关键字参数是data, 关键字用字典的形式传进去,这 ...

  3. C语言 小球撞击反弹

    计算法(略) #include <stdio.h> #include <stdlib.h> int main() { int x, y, a, resu; scanf(&quo ...

  4. 部署.Net Core APi+Vue 到 linux centos 服务器(一)

    部署.Net Core APi+Vue 到 linux centos 服务器(一) 前言:项目采用的是 .net core 作为接口,vue作为前端. 此时需要把整个项目架设到linux centos ...

  5. The four Day 给出一个平衡字符串,将它分割成尽可能多的平衡字符串

    """ 在一个「平衡字符串」中,'L' 和 'R' 字符的数量是相同的. 给出一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串. 返回可以通过分割得到的平衡字符串的 ...

  6. ElasticSearch 429 Too Many Requests circuit_breaking_exception

    错误提示 { "statusCode": 429, "error": "Too Many Requests", "message& ...

  7. windows操作系统更改 <远程桌面> 端口号

    windows远程桌面连接默认使用的是3389端口,为了避免被他人扫描从而暴力破解远程服务器或者病毒入侵.可以将默认端口修改为其它端口,如8888,11111等.最好修改为10000以后的端口,这样可 ...

  8. c# 更新web.config

    /// <summary> /// 添加和更新配置文件web.config的appSettings,缺点是会删除注释 /// </summary> /// <param ...

  9. Go内存分配器可视化指南【译】【精】

    当我第一次开始尝试理解 Go 语言的内存分配器时,整个过程让我抓狂.一切看起来都像一个神秘的黑盒子.因为几乎所有技术魔法(technical wizardry)都隐藏在抽象之下,所以你需要一层一层的剥 ...

  10. 1 matplotlib绘制折线图

    from matplotlib import pyplot as plt #设置图形大小 plt.figure(figsize=(20,8),dpi=80) plt.plot(x,y,color=&q ...