您的位置:首页 > 其它

HDU 3507:Print Article(斜率DP)

2016-11-17 01:05 405 查看


Print Article

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

Total Submission(s): 10556    Accepted Submission(s): 3227


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

问题概述:一个数列n,你要从左到右输出这个序列中的每一个数,每次连续输出都要消耗连续输出的数字和的平方

加上常数M,问如何输出才能使总消耗最小

http://www.cnblogs.com/kuangbin/archive/2012/08/26/2657650.html

思路:

设dp[i]为前i个数的最小花费,那么有dp[i] = min(dp[j]+(sum[i]-sum[j])²+m)(0<j<i)

可这样循环是n²的,那我们假设k<j<i,从j+1点做起始点比从k+1点做起始点更优,则有公式

dp[j]+(sum[i]-sum[j])²<=dp[k]+(sum[i]-sum[k])²,移项得

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

那么就得到了斜率表达式g[k,j]=Gp[k,j]/Gd[k,j],如果g[k,j]<=sum[i],则从j+1点做起始点比从k+1点做起始点更优

除此之外,易得如果g[k,j]>=g[j,i]那么j可淘汰。②

这样下来,可以确定一个j点,他前面所有的点都不可能比它更优(sum[i]递增),但是后面的怎么办?很显然
此时j点比j+1点优,如果j+1点比j+2点优,那么就没有什么可说的,但如果j+1点没有j+2点优,那么当j+2点入队时,

j+1点就会通过式②被淘汰!这样j点一定是对于当前i点最优的!

那么只要维护一个队列就好,如果当前队尾的两个位置k,j满足g[k,j]<=sum[i],则可以将队尾k弹出,

如果当前队头的两个位置k,j满足g[k,j]>=g[j,i],则可以将队头j弹出,i表示当前遍历到第i个数

#include<stdio.h>
#include<algorithm>
using namespace std;
int m, sum[500005], q[500005], dp[500005];
int Getup(int x, int y)
{
return dp[y]+sum[y]*sum[y]-dp[x]-sum[x]*sum[x];
}
int Getdown(int x, int y)
{
return 2*(sum[y]-sum[x]);
}
int main(void)
{
int n, i, b, e;
while(scanf("%d%d", &n, &m)!=EOF)
{
sum[0] = dp[0] = 0;
for(i=1;i<=n;i++)
{
scanf("%d", &sum[i]);
sum[i] += sum[i-1];
}
b = e = 0;
q[e++] = 0;
for(i=1;i<=n;i++)
{
while(b+1<e && Getup(q[b], q[b+1])<=sum[i]*Getdown(q[b], q[b+1]))  b++;
dp[i] = dp[q[b]]+(sum[i]-sum[q[b]])*(sum[i]-sum[q[b]])+m;
while(b+1<e && Getup(q[e-1], i)*Getdown(q[e-2], q[e-1])<=Getup(q[e-2], q[e-1])*Getdown(q[e-1], i))  e--;
q[e++] = i;
}
printf("%d\n", dp
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: