HDU 3507 Print Article(斜率DP优化)

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

2010 ACM-ICPC Multi-University Training Contest(7)——Host by HIT

Recommend

zhengfeng   |   We have carefully selected several similar problems for you:  3506 3501 3504 3505 3498

Statistic | Submit | Discuss | Note







第一道斜率dp,祭

设dp[i]表示输出前i个的最小费用,那么有如下的DP方程:

dp[i]= min{ dp[j]+(sum[i]-sum[j])^2 +M }  0<j<i

其中 sum[i]表示数字的前i项和。

相信都能理解上面的方程。

直接求解上面的方程的话复杂度是O(n^2)

对于500000的规模显然是超时的。下面讲解下如何用斜率优化DP使得复杂度降低一维。

我们首先假设在算 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   而且 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 是可以淘汰的

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

通过一个队列来维护。







 1 #include "bits/stdc++.h"
 2
 3 using namespace std;
 4 typedef long long ll;
 5
 6 ll s[600000],f[600000],q[600000];
 7
 8
 9 ll  slope(ll j, ll k)
10 {
11     return ((f[j]+s[j]*s[j])-(f[k]+s[k]*s[k]));
12
13 }
14 ll down(ll j,ll k)
15 {
16     return (2*s[j]-2*s[k]);
17 }
18
19 ll n,m;
20
21 int main()
22 {
23     while (cin>>n>>m)
24     {
25         for (int i=1;i<=n;i++)
26         {
27             ll x;cin>>x;s[i]=s[i-1]+x;
28         }
29         int L=1,R=1;
30         q[1]=f[0]=0;
31         for (int i=1;i<=n;i++)
32         {
33             while (L<R&&slope(q[L+1],q[L])<=s[i]*down(q[L+1],q[L]))L++;
34             //while (L<R&&slope(q[L],q[L+1])>=s[i]*down(q[L],q[L+1]))L++;
35             int t=q[L];
36             f[i]=f[t]+(ll)pow(s[i]-s[t],2)+m;
37             while(L<R&&slope(q[R],q[R-1])*down(i,q[R])>=down(q[R],q[R-1])*slope(i,q[R]))R--;
38             //while(L<R&&slope(q[R-1],q[R])*down(q[R],i)>=down(q[R-1],q[R])*slope(q[R],i))R--;
39
40             q[++R]=i;
41         }
42         cout<<f[n]<<endl;
43     }
44
45 }

原文地址:https://www.cnblogs.com/zhangbuang/p/10614329.html

时间: 2025-01-06 14:30:28

HDU 3507 Print Article(斜率DP优化)的相关文章

HDU 3507 Print Article (斜率DP)

题意:要输出N个数字a[N],输出的时候可以连续连续的输出,每连续输出一串,它的费用是 "这串数字和的平方加上一个常数M". 析:这个题很容易想到DP方程dp[i] = min{dp[j] + M + (sum[i]-sum[j])^2},但是很明显是O(n^2),TLE是必然的,所以要进行优化. 假设 i > j > k ,并且 j 要比 k 好,那么就是 dp[j] + M + (sum[i]-sum[j])^2 < dp[k] + M + (sum[i]-sum

HDU 3507 Print Article 斜率优化

Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 4810    Accepted Submission(s): 1451 Problem Description Zero has an old printer that doesn't work well sometimes. As it is antique

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

 Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 7960    Accepted Submission(s): 2465 Problem Description Zero has an old printer that doesn't work well sometimes. As it is antiq

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 即 f[j] + s[j]*s[j] = 2*s[i]*s[j] + f[i] - s[i]*s[i] - m 于是维护下凸包即可: 写成 double 的 slp 总是不对,把分母乘到对面就对了... 代码如下: #include<iostream> #include<cstdio>

HDU 3507 Print Article (斜率优化)

HDU 3507 Print Article (斜率优化) ACM 题目地址: HDU 3507 Print Article 题意: 给定一个长度为n的序列,和一个常数m,我们可以将序列分成随意段,每段的权值为sum(arr[i]) + C(x<=i<=y),求一种划分方法使得整个序列的权值最小 分析: from:亟隐's blog f[i]=min(f[k]+(sum(i)-sum(k))^2 )+m = f[k]+sum^2(i)+sum^2(k)-2*sum(i)*sum(k)+m. 也

斜率优化dp简讲 &amp;&amp; HDU 3507 Print Article

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 t

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

Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 8199    Accepted Submission(s): 2549 Problem Description Zero has an old printer that doesn't work well sometimes. As it is antique

HDU 3507 Print Article(斜率优化DP)

题目链接 题意 : 一篇文章有n个单词,如果每行打印k个单词,那这行的花费是,问你怎么安排能够得到最小花费,输出最小花费. 思路 : 一开始想的简单了以为是背包,后来才知道是斜率优化DP,然后看了网上的资料,看得还挺懂的,不过我觉得如果以后真遇到斜率DP,要推起来肯定不简单..... 网上资料1 网上资料2 1 #include <iostream> 2 #include <stdio.h> 3 4 using namespace std; 5 6 int q[500005],dp

HDU 3507 Print Article(斜率优化)

Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 15536    Accepted Submission(s): 4813 Problem Description Zero has an old printer that doesn't work well sometimes. As it is antiqu