hdu 3507 斜率dp

不好理解,先多做几个再看

此题是很基础的斜率DP的入门题。

题意很清楚,就是输出序列a[n],每连续输出的费用是连续输出的数字和的平方加上常数M

让我们求这个费用的最小值。

设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,用一个单调队列来维护解集。

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])。

 1 /*
 2 HDU 3507
 3
 4 */
 5
 6 #include<stdio.h>
 7 #include<iostream>
 8 #include<string.h>
 9 #include<queue>
10 using namespace std;
11 const int MAXN=500010;
12
13 int dp[MAXN];
14 int q[MAXN];//队列
15 int sum[MAXN];
16
17 int head,tail,n,m;
18 // dp[i]= min{ dp[j]+M+(sum[i]-sum[j])^2 };
19 int getDP(int i,int j)
20 {
21     return dp[j]+m+(sum[i]-sum[j])*(sum[i]-sum[j]);
22 }
23
24 int getUP(int j,int k) //yj-yk部分
25 {
26     return dp[j]+sum[j]*sum[j]-(dp[k]+sum[k]*sum[k]);
27 }
28 int getDOWN(int j,int  k)
29 {
30     return 2*(sum[j]-sum[k]);
31 }
32
33 int main()
34 {
35   //  freopen("in.txt","r",stdin);
36   //  freopen("out.txt","w",stdout);
37     while(scanf("%d%d",&n,&m)==2)
38     {
39         for(int i=1;i<=n;i++)
40            scanf("%d",&sum[i]);
41         sum[0]=dp[0]=0;
42         for(int i=1;i<=n;i++)
43            sum[i]+=sum[i-1];
44         head=tail=0;
45         q[tail++]=0;
46         for(int i=1;i<=n;i++)
47         {
48             //把斜率转成相乘,注意顺序,否则不等号方向会改变的
49             while(head+1<tail &&  getUP(q[head+1],q[head])<=sum[i]*getDOWN(q[head+1],q[head]))
50                head++;
51             dp[i]=getDP(i,q[head]);
52             while(head+1<tail && getUP(i,q[tail-1])*getDOWN(q[tail-1],q[tail-2])<=getUP(q[tail-1],q[tail-2])*getDOWN(i,q[tail-1]))
53                     tail--;
54             q[tail++]=i;
55         }
56         printf("%d\n",dp[n]);
57     }
58     return 0;
59 }
时间: 2024-10-11 22:59:21

hdu 3507 斜率dp的相关文章

HDU 3507(斜率优化dp

题目:每次选取连续的若干数字的代价 要求选取虽有数字的最小代价. 思路:基础斜率dp题,题解见http://www.cnblogs.com/kuangbin/archive/2012/08/26/2657650.html /* * @author: Cwind */ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include &

HDU 3507斜率优化dp

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

hdu 3507 斜率优化

我的第一道斜率优化. 就这道题而言,写出原始的方程: dp[i] = min{ dp[j] + (sum[i]-sum[j])2  + M | j in [0,i) } O(n^2)的复杂度肯定超时,要么优化转移,要么重写方程. 斜率优化的思想就是减少不必要的枚举(即不枚举肯定不会成为决策点的j). 我们考虑两个位置p<q<i “选择q比选择p优” 当且仅当 dp[q]+(sum[i]-sum[q])2+M < dp[p]+(sum[i]-sum[p])2+M 化简右边即: [ (dp[

HDU 3480 斜率dp

Division Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 999999/400000 K (Java/Others)Total Submission(s): 5053    Accepted Submission(s): 1980 Problem Description Little D is really interested in the theorem of sets recently. There’s a prob

Lawrence HDU - 2829 斜率dp

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAX = 1000+10; //dp[i][j]:把前 i 个数分成 j 段后能得到的序列的最小权值和 //dp[i][j] = min( dp[k][j-1] + cost[i] - cost[k] - sum[k] *(sum[i] - sum[

斜率优化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

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

Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 4990    Accepted Submission(s): 1509 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(斜率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 t