码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ_1010_[HNOI2008]_玩具装箱toy_(斜率优化动态规划+单调队列)

时间:2016-06-11 17:15:09      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:

描述


http://www.lydsy.com/JudgeOnline/problem.php?id=1010

给出\(n\)和\(l\).有\(n\)个玩具,第\(i\)个玩具的长度是\(c[i]\),要求将玩具分成若干段,从\(i\)到\(j\)分为一段的长度为\(x=j-i+\sum_(k=i)^jc[k]\),费用为\((x-l)^2\).求最小费用.

 

分析


用\(dp[i]\)表示前\(i\)个玩具所需的最小费用,则有$$dp[i]=min\{dp[j]+(sum[i]-sum[j]+i-(j+1)-l)^2(1<=j<i)\}$$

其中\(sum[i]\)表示的是\(c[i]\)的前缀和.

为了方便,我们设$$A[i]=sum[i]+i,l=l+1$$

于是原方程久等价于$$dp[i]=min\{dp[j]+(A[i]-A[j]-l)^2(1<=j<i)\}$$

我们设\(j<k<i\)且在计算\(dp[i]\)的时候,决策\(k\)更优.也就是说$$dp[k]+(A[i]-A[k]-l)^2<dp[j]+(A[i]-A[j]-l)^2$$

在纸上写写画画,把式子打开再遍一下形,容易得到$$\frac{[dp[k]+(A[k]+l)^2]-[dp[j]+(A[j]+l)^2]}{2\times{A[k]}-2\times{A[j]}}<A[i]$$

是不是很像$$\frac{Y_k-Y_j}{X_k-X_j}$$的形式?

这玩意儿不就是斜率吗?!我们设它为\(g(k,j)\)

我们可以发现\(A[i]\)是单调递增的,所以所有决策可以转化为二维空间上的点集.

也就是说\(k\)这个点和\(j\)这个点的连线的斜率如果小于\(A[i]\),那么\(k\)这个决策就更优.

那么对于三个决策\(a<b<c\),如果有\(g(c,b)<=g(b,a)\),那么\(b\)决策一定不会被选中.为什么呢?我们来讨论一下(对于任意\(3<i<=n\)):

1.如果\(g(b,a)<A[i]\),那么必有\(g(c,b)<A[i]\),也就是\(c\)最优,选择决策\(c\).

2.如果\(g(b,a)>=A[i]\),那么\(b\)不是最优,最优可能是\(a\)或\(c\).

所以我们在新加入一个点的时候,就可以把它看作\(c\),然后把所有这样的\(b\)都去掉,直到\(g(c,b)>g(b,a)\),所以我们需要处理的斜率是单调递增的.

由于\(A[i]\)是单调递增的,所以对于任意的\(i<n\),如果满足上面的不等式,那么对于任意的\(i‘,i<i<=n\),由于\(A[i‘]>A[i]\),所以上不等式仍然成立,所以\(i‘\)的最优决策的位置一定不比\(i\)的最优决策小.

这样我们就可以用一个单调队列分别维护队首和队尾啦.

 

 

技术分享
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long ll;
 5 const int maxn=50000+5;
 6 ll n,l,front,tail;
 7 ll sum[maxn],A[maxn],dp[maxn],q[maxn];
 8 inline ll pow_(ll x){ return x*x; }
 9 inline ll up(int k,int j){ return dp[k]-dp[j]+pow_(A[k]+l)-pow_(A[j]+l); }
10 inline ll dn(int k,int j){ return 2*(A[k]-A[j]); }
11 int main(){
12     scanf("%lld%lld",&n,&l);
13     l++;
14     for(int i=1;i<=n;i++){
15         ll t; scanf("%lld",&t);
16         sum[i]=sum[i-1]+t;
17         A[i]=sum[i]+i;
18     }
19     front=0,tail=1;
20     for(int i=1;i<=n;i++){
21         while(front+1<tail&&up(q[front+1],q[front])<=A[i]*dn(q[front+1],q[front])) front++;
22         int j=q[front]; dp[i]=dp[j]+pow_(A[i]-A[j]-l);
23         while(front+1<tail&&up(i,q[tail-1])*dn(q[tail-1],q[tail-2])<=up(q[tail-1],q[tail-2])*dn(i,q[tail-1])) tail--;
24         q[tail++]=i;
25     }
26     printf("%lld\n",dp[n]);
27     return 0;
28 }
View Code

 

BZOJ_1010_[HNOI2008]_玩具装箱toy_(斜率优化动态规划+单调队列)

标签:

原文地址:http://www.cnblogs.com/Sunnie69/p/5575464.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!