Problem Description
Zero has an old printer that doesn't work well sometimes. As it is antique, he still like to use it to print articles. But it is too old to work for a long time and it will certainly wear and tear, so Zero use a cost to evaluate this degree.
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
 
Author
Xnozero
 
Source

大致题意:要打印一长串词语,每个词语有一个对应的打印费用Ci,要给词语分行,一行的总费用记为,M是给定的常数

要求计算一种分行方案使得总费用最小。

数据规模50万。

分析:首先可以想到枚举上一次断行处,这样可以得到最初的状态转移方程:

,复杂度为O(n^2)。

观察一下数据规模为50万,需要优化。

主要思路是考虑淘汰肯定对最优答案没有贡献的点。

将状态转移方程展开:

(注:公式和图来自BIG YAO学长)

移项可得:

                    

观察到蓝色字体部分只与j有关,绿色字体对给定的i为常量,红色字体部分取最小的时候dp[i]取最小。

将蓝色字体视为y(j),sum[j]视为x(j),问题就转化为对平面上无数个点(x,y),对每一个i,找出一个最优点(x0,y0),使得一条通过该点,斜率为k=2sum[i]的直线的截距最小。

放张图表现一下优化情况:

维护一个队列,即为下凸折线上点的队列,每次寻找最优的j的时候只在队列里的点找。(注意取得最优点的时候相邻的两根折线的斜率对于k=2sum[i]一大一小)

以下具体讨论怎么实现:

i不断向前推进,每次循环做两件事情:

1,找出对于dp[i]最优的上一个断行处j

如果队列上该点i和他后面的那个店形成的斜率小于k=2*sum[i]就头指针+1。

注意由于随i的递增,k=2*sum[i]必然递增,所以出队的点就不需要回来了

2,把i放入队列后就不再需要的点淘汰掉:

一旦出现3个点呈这样,即可淘汰点2,因为:直线经过点4的截距必然小于经过点2的截距,而经过点4的截距必然小于经过点1或点3的截距。

从而经过点2的截距必然小于小1或点3的截距,点2不可能为最优点,可淘汰。

然后把i放入队列(注意sum[i]为严格递增的,所以i个点中最后一个点必然在“外围”,不会被淘汰)

 #include<cstdio>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int MAXN=;
long long int dp[MAXN],q[MAXN],sum[MAXN];
int n,m;
inline long long int getdp(int i,int j)
{
return dp[j]+m+(sum[i]-sum[j])*(sum[i]-sum[j]);
}
inline long long int gety(int x,int y)
{
return dp[x]+sum[x]*sum[x]-dp[y]-sum[y]*sum[y];
}
inline long long int getx(int x,int y)
{
return *sum[x]-*sum[y];
}
int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)==)
{
sum[]=;
rep(i,,n)
{
scanf("%lld",&sum[i]);
sum[i]=sum[i-]+sum[i];
}
dp[]=;
int head,tail;
tail=;
head=;
q[tail]=; //虚拟制造一个点0,若0点最优代表把所有词语分成一行最优
rep(i,,n)
{
while(head+<=tail&&(gety(q[head+],q[head])<=sum[i]*getx(q[head+],q[head]))) head++; //寻找对于i最好的上一次分行的截止点
dp[i]=getdp(i,q[head]);
while(head+<=tail&&gety(i,q[tail])*getx(q[tail],q[tail-])<=gety(q[tail],q[tail-])*getx(i,q[tail])) tail--; //i放入队列后需要淘汰的点
q[++tail]=i; //把i放入队列
}
printf("%lld\n",dp[n]);
}
return ;
}

斜率DP hdu 3507的更多相关文章

  1. hdu 3507 斜率dp

    不好理解,先多做几个再看 此题是很基础的斜率DP的入门题. 题意很清楚,就是输出序列a[n],每连续输出的费用是连续输出的数字和的平方加上常数M 让我们求这个费用的最小值. 设dp[i]表示输出前i个 ...

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

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

  3. 斜率dp A - Print Article HDU - 3507

    A - Print Article HDU - 3507 今天刚刚学习了一下斜率dp,感觉还ok,主要就是要推这个斜率,然后利用数据结构来优化. 推荐两篇写的比较好的博客,https://www.cn ...

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

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

  5. HDU 3507 单调队列 斜率优化

    斜率优化的模板题 给出n个数以及M,你可以将这些数划分成几个区间,每个区间的值是里面数的和的平方+M,问所有区间值总和最小是多少. 如果不考虑平方,那么我们显然可以使用队列维护单调性,优化DP的线性方 ...

  6. B - Lawrence HDU - 2829 斜率dp dp转移方程不好写

    B - Lawrence HDU - 2829 这个题目我觉得很难,难在这个dp方程不会写. 看了网上的题解,看了很久才理解这个dp转移方程 dp[i][j] 表示前面1~j 位并且以 j 结尾分成了 ...

  7. HDU 3480 - Division - [斜率DP]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3480 Time Limit: 10000/5000 MS (Java/Others) Memory L ...

  8. HDU 2829 - Lawrence - [斜率DP]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2829 T. E. Lawrence was a controversial figure during ...

  9. HDU 2993 - MAX Average Problem - [斜率DP]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2993 Consider a simple sequence which only contains p ...

随机推荐

  1. java定时任务的实现方式

    在本文里,我会给大家介绍2种不同的实现方法:1.普通thread实现2.ScheduledExecutorService实现 一:实现普通的thread: 首先是创建thread然后就是一直让whil ...

  2. Java 9 揭秘(13. Collection API 更新)

    Tips 做一个终身学习的人. 在本章中,主要介绍以下内容: 在JDK 9之前如何创建了不可变的list,set和map以及使用它们的问题. 如何使用JDK 9中的List接口的of()静态工厂方法创 ...

  3. Java字符串格式化记录

    最近打log的时候用到了字符串的格式化. Java中String格式化和C语言的很类似.把情况都列出来,以后好查询. public static void main(String[] args) { ...

  4. Python判断文件是否存在的三种方法

    通常在读写文件之前,需要判断文件或目录是否存在,不然某些处理方法可能会使程序出错.所以最好在做任何操作之前,先判断文件是否存在. 这里将介绍三种判断文件或文件夹是否存在的方法,分别使用os模块.Try ...

  5. LINUX下的远端主机登入 校园网络注册 网络数据包转发和捕获

    第一部分:LINUX 下的远端主机登入和校园网注册 校园网内目的主机远程管理登入程序 本程序为校园网内远程登入,管理功能,该程序分服务器端和客户端两部分:服务器端为remote_server_udp. ...

  6. phpstudy连接SQL Server 2008数据库 以及 php使用sql server出现乱码解决方式

    开始也尝试自己配置php安装环境,找到一个详细的百度经验http://jingyan.baidu.com/article/154b46315242b328ca8f4101.html,前面有问题也一一去 ...

  7. Python学习——(1)Centos安装Flask

    一.环境 [root@localhost myproject]# cat /proc/version centos6.5 Linux version 2.6.32-642.11.1.el6.i686 ...

  8. ffmpeg编解码视频导致噪声增大的一种解决方法

    一.前言 ffmpeg在视音频编解码领域算是一个比较成熟的解决方案了.公司的一款视频编辑软件正是基于ffmpeg做了二次封装,并在此基础上进行音视频的编解码处理.然而,在观察编码后的视频质量时,发现图 ...

  9. Open-Falcon第三步安装Agent (小米开源互联网企业级监控系统)

    安装Agent 每台机器上,都需要部署agent,agent会自动采集预先定义的各种采集项,每隔60秒,push到transfer. cd $WORKSPACE/agent/ mv cfg.examp ...

  10. python实战第一天-环境的安装

    操作系统 Ubuntu 15.10 IDE & editor JetBrains PyCharm 5.0.2 ipython3 Python版本 python-3.4.3 安装Python s ...