Print Article

Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 6653    Accepted Submission(s): 2054

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
 
Recommend
zhengfeng   |   We have carefully selected several similar problems for you:  3501 3504 3505 3498 3503 
此题是很基础的斜率优化DP
 题目描述: 给你一些字,你可以选择每次打印一个或者几个字,每次打印的费用是(ci+c(i+1)+c(i+2)+....)^2+m;
c[i]代表每个字的费用;
设dp[i]代表打印前i个字所需的最少费用,dp[i]=min(dp[j]+(sum[i]-sum[j])^2,dp[i]);
由于n的范围是500000,那么25*10^10,肯定会超时;
可以采用斜率优化:

我们首先假设在算 dp[i]时,k<j ,j点比k点优。

也就是

dp[j]+(sum[i]-sum[j])^2+M <= dp[k]+(sum[i]-sum[k])^2+M;

所谓j比k优就是DP方程里面的值更小

对上述方程进行整理很容易得到:

[(dp[j]+sum[j]*sum[j])-(dp[k]+sum[k]*sum[k])] / 2(sum[j]-sum[k]) <=sum[i].

注意整理中要考虑下正负,涉及到不等号的方向。

左边我们发现如果令:yj=dp[j]+sum[j]*sum[j]   xj=2*sum[j]

那么就变成了斜率表达式:(yj-yk)/(xj-xk) <= sum[i];

而且不等式右边是递增的。

所以我们可以看出以下两点:我们令g[k,j]=(yj-yk)/(xj-xk)

第一:如果上面的不等式成立,那就说j比k优,而且随着i的增大上述不等式一定是成立的,也就是对i以后算DP值时,j都比k优。那么k就是可以淘汰的。

如果不成立,那就说明k比j优,但是随着i的增加sum[i]增加,j始终会替换掉k.

第二:如果 k<j<i   而且 g[k,j]>g[j,i] 那么 j 是可以淘汰的。

假设  g[j,i]<sum[i]就是i比j优,那么j没有存在的价值

相反如果 g[j,i]>sum[i] 那么同样有 g[k,j]>sum[i]  那么 k比 j优 那么  j 是可以淘汰

所以这样相当于在维护一个下凸的图形,斜率在逐渐增大。

通过一个队列来维护。

初始化队列:head=0,tail=0;que[tail++]=0;表示tail处不存决策。

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

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

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

3,求解时候,从队头开始,如果已有元素a b c,当i点要求解时,如果g[b,a]<sum[i],那么说明b点比a点更优,a点可以排除,于是a出队。最后dp[i]=getDp(q[head]);

#include <iostream>
#include <cstdio>
#include <string.h>
#include <math.h>
#define maxn 500010
#define LL int
using namespace std; LL sum[maxn],dp[maxn];
int que[maxn];
int head,tail;
int n;
LL m;
int getdp(int i,int j)
{
return dp[j]+m+(sum[i]-sum[j])*(sum[i]-sum[j]);
} int getup(int j,int k) //yj-yk部分
{
return dp[j]+sum[j]*sum[j]-(dp[k]+sum[k]*sum[k]);
}
int getdown(int j,int k)
{
return *(sum[j]-sum[k]);
} void solve()
{
head=;
tail=;
que[tail++]=; //队列里存储的是决策 //tail处不存决策
for(int i=;i<=n;i++)
{
//从头开始找当前状态的最优决策,g[que[head+1],que[head]] < sum[i],说明que[head+1]比que[head]更优,删除que[head]
while(head+ < tail && getup(que[head+],que[head]) <= getdown(que[head+],que[head]) * sum[i] )
head++; //注意写成相乘,不然要考虑除数是否为负数
dp[i]=getdp(i,que[head]); //从尾往前,加入当前状态,如果g[i,que[tail]] < g[que[tail],que[tail-1]] ,可以排除que[tail]
/* while(head+1 <tail && getup(i,que[tail-1]) * getdown(que[tail-1],que[tail-2]) <= getup(que[tail-1],que[tail-2])*getdown(i,que[tail-1])))
{
tail--; //看到为什么RE了吗?笨蛋,括号打错了
}*/
while(head+<tail && getup(i,que[tail-])*getdown(que[tail-],que[tail-])<=getup(que[tail-],que[tail-])*getdown(i,que[tail-]))
tail--;
que[tail++]=i;
}
/*for(int i=1;i<=n;i++)
printf("%.0lf ",dp[i]);*/
printf("%d\n",dp[n]);
}
int main()
{ while(scanf("%d%d",&n,&m)==)
{
// init();
sum[]=;
for(int i=;i<=n;i++)
{
scanf("%d",&sum[i]);
sum[i]+=sum[i-];
}
//for(int i=1;i<=n;i++)
// printf("%lf ",sum[i]);
solve();
}
return ;
}

hdu 3507(DP+斜率优化)的更多相关文章

  1. HDU 3480 DP+斜率优化

    题意:给你n个数字,然后叫你从这些数字中选出m堆,使得每一堆的总和最小,一堆的总和就是这一堆中最大值减去最小值的平方,最后要使得所有堆加起来的总和最小. 思路:对这些数字排序之后,很容易想到DP解法, ...

  2. Print Article hdu 3507 一道斜率优化DP 表示是基础题,但对我来说很难

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

  3. HDU 3480 DP 斜率优化 Division

    把n个数分成m段,每段的值为(MAX - MIN)2,求所能划分得到的最小值. 依然是先从小到大排个序,定义状态d(j, i)表示把前i个数划分成j段,所得到的最小值,则有状态转移方程: d(j, i ...

  4. HDU 3045 DP 斜率优化 Picnic Cows

    题意:将n个数分成若干组,每组数字的个数不少于t个,要把每组的数字减小到这组最小值,求所有数字减少的最小值. 先将这n个数从小到大排个序,可以想到一组里面的数一定是排序后相邻的. 设d(i)表示前i个 ...

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

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

  6. hdu 2829 Lawrence(斜率优化DP)

    题目链接:hdu 2829 Lawrence 题意: 在一条直线型的铁路上,每个站点有各自的权重num[i],每一段铁路(边)的权重(题目上说是战略价值什么的好像)是能经过这条边的所有站点的乘积之和. ...

  7. 【BZOJ-4518】征途 DP + 斜率优化

    4518: [Sdoi2016]征途 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 230  Solved: 156[Submit][Status][ ...

  8. 【BZOJ-3437】小P的牧场 DP + 斜率优化

    3437: 小P的牧场 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 705  Solved: 404[Submit][Status][Discuss ...

  9. 【BZOJ-1010】玩具装箱toy DP + 斜率优化

    1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 8432  Solved: 3338[Submit][St ...

随机推荐

  1. msp430项目编程31

    msp430中项目---无线通信系统31 1.SPI工作原理 2.nrf24l01工作原理 3.代码(显示部分) 4.代码(功能实现) 5.项目总结

  2. Flex里监听mouseDownOutside事件解决弹出窗口点击空白关闭功能

    其实当用户在使用 PopUpManager 打开的某个组件外部单击时,会从该组件分派一个mouseDownOutside事件 监听该事件就能实现点击空白处关闭窗口的功能 this.addEventLi ...

  3. Object_C 定义全局宏的颜色时,报“Expected identifier”的错误

    在定义全局颜色宏的时候,为了整齐把空格删了,写在了同一行里,调用的时候,出错提示“Expected identifier”,如下: 如果宏定义如上那样的话,在调用的时候,会出现如下的问题: 百思不得解 ...

  4. Codechef-BLACKCOM(树形背包dp)

    题意: 给你一棵由 N 个节点构成的树 T.节点按照 1 到 N 编号,每个节点要么是白色,要么是黑色.有 Q 组询问,每组询问形如 (s, b).你需要检查是否存在一个连通子图,其大小恰好是 s,并 ...

  5. Linux内存管理-内核的shmall和shmmax参数(性能调优)(转)

    内核的shmall和shmmax参数 SHMMAX=配置了最大的内存segment的大小:这个设置的比SGA_MAX_SIZE大比较好. SHMMIN=最小的内存segment的大小 SHMMNI=整 ...

  6. SqlSugar最容易使用的ORM

    SqlSugar官网

  7. 地球Gauss_Kruger中央0度经线图

  8. C# 9.0新特性

    CandidateFeaturesForCSharp9 看到标题,是不是认为我把标题写错了?是的,C# 8.0还未正式发布,在官网它的最新版本还是Preview 5,通往C#9的漫长道路却已经开始.前 ...

  9. 【网络】TCP的拥塞控制

    一.拥塞控制的一般原理 拥塞:对网络中某一资源的需求超过了该资源所能提供的可用部分 拥塞控制是防止过多的数据注入到网络,这样可以使网络中的路由器或链路不致过载,拥塞控制是一个全局性的过程. 流量控制往 ...

  10. Linux 下使用 Sar 简介

    Linux 下使用 Sar 简介 提交 我的留言 加载中 已留言 介绍 Sar 最早是实现在 Salaris Unix 系统里,后来移植到了大部分其他的 Unix 系统(如AIX,HP-UX等).Li ...