HDU 3507 - Print Article - [斜率DP]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3507
One day Zero want to print an article which has N words, and each word i has a cost Ci to be printed. Also, Zero know that print k words in one line will cost
M is a const number.
Now Zero want to know the minimum cost in order to arrange the article perfectly.
Input
There are many test cases. For each test case, There are two numbers N and M in the first line (0 ≤ n ≤ 500000, 0 ≤ M ≤ 1000). Then, there are N numbers in the next 2 to N + 1 lines. Input are terminated by EOF.
Output
A single number, meaning the mininum cost to print the article.
Sample Input
5 5
5
9
5
7
5
Sample Output
230
题意:
假设一篇文章有N个词,每个词有c[i]代表花费;
现在打印文章,打印一行需要花费 M + ( ∑c[i] )2,求怎么打印整篇文章花费最少,为多少。
题解:
假设dp[i]代表输出前i个词的最小费用,那么就有状态转移方程:

sum[i]代表前i个词的c[i]之和;
状态转移方程的意思也很明显,就是枚举选出第i个单词所在的那一行上打印多少个单词最优;
那么如果直接求解的话,O(n2)的时间复杂度对于n=500000的规模是超时的,所以就要使用斜率优化:
那么当我们计算dp[i]时,假设有 1 <= k < j < i,如果有:

就可以说j点比k点更优。
对上式进行变形可得:

我们设

那么就有:(在计算dp[i]时)j点比k点优 ↔ g(k,j) ≤ sum[i];……………………(1)
j点比k点差 ↔ g(k,j) > sum[i];……………………(2)
(这就像,g(k,j)代表k点与j点的连线斜率,这个斜率小于某个阈值就j更优,否则就k更优)
就不难得到:
①在计算dp[i]时,若有1≤a<b<c<i,只要满足g(a,b) ≥ g(b,c),则b点必然被淘汰. (注意此处的g(a,b) ≥ g(b,c)是必须是要取到等号的)
证明:若g(b,c) ≤ sum[i],由(1)得c点优于b点,选择c点;
若g(b,c) > sum[i],则g(a,b) ≥ g(b,c) > sum[i],由(2)得a点比b点更优,选择a点;
最终,怎么样都选不到b点,故b点必然淘汰。
②若在计算dp[i]时,k点被淘汰,则计算dp[i+1]时,k点必然也被淘汰.
证明:当k点被淘汰,即必然有一点j比k更优,则g(k,j) ≤ sum[i],由于c[i] > 0,则g(k,j) ≤ sum[i] < sum[i+1],即计算dp[i+1]时,j依然比k更优,k依然淘汰。
因此我们可以考虑维护一个斜率的队列来优化整个DP过程:
1、求解dp[i]:
假设队列中的头部依次存在元素a,b,且g(a,b) ≤ sum[i],则b点比a点优,于是a淘汰出队;
重复上述操作,直到队列元素个数小于2或者g(a,b) > sum[i]。
最后dp[i]=getDP(Q[head])。
2、入队点i:
假设队列中的尾部依次存在元素a,b,那么当点c要入队的时候,如果g(a,b) > g(b,c),那么就将b点删除;
重复上述操作,直到队列元素个数小于2,或者找到x,y能满足g(x,y) ≤ g(y,c),将d点加入在该位置中。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=; int n,m,sum[maxn];
int dp[maxn];
int q[maxn],head,tail; //数组模拟队列 int getDP(int i,int j){return dp[j]+(sum[i]-sum[j])*(sum[i]-sum[j])+m;} int gUp(int k,int j){return (dp[j]+sum[j]*sum[j])-(dp[k]+sum[k]*sum[k]);} //g(k,j)的分子部分
int gDown(int k,int j){return *(sum[j]-sum[k]);} //g(k,j)的分母部分 int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
sum[]=;
for(int i=,tmp;i<=n;i++)
{
scanf("%d",&tmp);
sum[i]=sum[i-]+tmp;
} dp[]=;
head=tail=;
q[tail++]=;
for(int i=;i<=n;i++)
{
//计算dp[i]
while(tail-head>= && gUp(q[head],q[head+])<=sum[i]*gDown(q[head],q[head+]))
head++;
dp[i]=getDP(i,q[head]); //入队点i
while(tail-head>= && gUp(q[tail-],q[tail-])*gDown(q[tail-],i)>=gUp(q[tail-],i)*gDown(q[tail-],q[tail-]))
tail--;
q[tail++]=i;
} printf("%d\n",dp[n]);
}
}
有一点需要注意的是,本题中c[i]其实是有可能等于0的,所以不能直接gUp/gDown,而是要把分母gDown乘到其另一边再进行比较。
刚开始头铁,强行用list来模拟本题的队列,写*Q.begin()和*++Q.begin()和*Q.end()和*--Q.end()丑的一B,
强行写完之后,发现因为耗时O(size)的size()方法超时,定义一个_size变量代替之后发现确实还是不如直接数组模拟快,
更严重的是,用list写法并没有简单好看多少,最后还是老老实实数组模拟队列吧……
HDU 3507 - Print Article - [斜率DP]的更多相关文章
- hdu 3507 Print Article(斜率优化DP)
题目链接:hdu 3507 Print Article 题意: 每个字有一个值,现在让你分成k段打印,每段打印需要消耗的值用那个公式计算,现在让你求最小值 题解: 设dp[i]表示前i个字符需要消耗的 ...
- HDU 3507 Print Article(DP+斜率优化)
Print Article Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) ...
- 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
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3507 设 f[i],则 f[i] = f[j] + (s[i]-s[j])*(s[i]-s[j]) + m ...
- 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个单词,如果每行打印k个单词,那这行的花费是,问你怎么安排能够得到最小花费,输出最小花费. 思路 : 一开始想的简单了以为是背包,后来才知道是斜率优化DP,然后看了网上 ...
- ●HDU 3507 Print Article
题链: http://acm.hdu.edu.cn/showproblem.php?pid=3507 题解: 斜率优化DP 一个入门题,就不给题解了,网上的好讲解很多的. 这里就只提一个小问题吧( ...
- HDU 3507 [Print Article]DP斜率优化
题目大意 给定一个长度为\(n(n \leqslant 500000)\)的数列,将其分割为连续的若干份,使得 $ \sum ((\sum_{i=j}^kC_i) +M) $ 最小.其中\(C_i\) ...
- HDU 3507 Print Article(CDQ分治+分治DP)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3507 [题目大意] 将长度为n的数列分段,最小化每段和的平方和. [题解] 根据题目很容易得到dp ...
随机推荐
- iOS开发 frame 与 bounds 的区别与关系 转自隔叶黄莺
frame和bounds是UIView中的两个属性(property). frame指的是:该view在父view坐标系统中的位置和大小.(参照点是父亲的坐标系统) bounds指的是:该view在本 ...
- RESTful状态码说明
https://www.zhihu.com/question/58686782/answer/159603453 常用状态码: 200 请求成功并返回所需资源 400 客户端请求有语法错误 401 未 ...
- HTML开发之(块级标签,行内标签,行内块标签)
显示模式的特性: 主要分为两大类: 块级元素:独占一行,对宽高的属性值生效:如果不给宽度,块级元素就默认为浏览器的宽度,即就是100%宽: 行内元素:可以多个标签存在一行,对宽高属性值不生效,完全靠内 ...
- 【Python】Excel处理
1.包导入 from openpyxl import Workbook from openpyxl import load_workbook from openpyxl.compat import r ...
- mongodb int字段的一个小坑
在使用 php mongodb 搜索时,如果字段类型用 int,则使用 php 搜索时一定要把数值转换成整型来搜索,用字符串类型的数字搜索是没有结果的!!!! $condition = ['membe ...
- Python内置性能分析模块timeit
timeit模块 timeit模块可以用来测试一小段Python代码的执行速度. class timeit.Timer(stmt='pass', setup='pass', timer=<tim ...
- 使用composer进行依赖管理:以guzzle为例
今天突然发现一个不错的php http客户端库guzzle,欣喜不已,跃跃欲试.打开guzzle文档,发现需要composer做依赖管理.之前没有接触过composer,正好以此学习下,也蛮好! 本文 ...
- IOS 通过脚本自动打包工具 webfrogs/xcode_shell
博文转载至 http://www.2cto.com/kf/201506/408346.html ios 开发通过xcode 打包其实效率不是太高,所以就有人,用shell 写了一个,自动打包,发邮件, ...
- 简单mysql类
---恢复内容开始--- class mysql { private $host; private $user; private $pass; private $database; private $ ...
- ldap objectclass
LDAP中,一个条目必须包含一个objectClass属性,且需要赋予至少一个值.每一个值将用作一条LDAP条目进行数据存储的模板:模板中包含了一个条目必须被赋值的属性和可选的属性. obj ...