BZOJ 1010: [HNOI2008]玩具装箱toy(斜率优化dp)

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

题意:

 

思路:

容易得到朴素的递归方程:$dp(i)=min(dp(i),dp(k)+(i-k-1+sum[i]-sum[k]-l)^{2})$,$sum[i]$表示前i个玩具的$c_{i}$之和。$f(k)$表示前k个玩具的最小费用。

如果设$f(i)=sum[i]+i$,那么上式就可以改写为$dp(i)=min(dp(i),dp(k)+(f(i)-f(k)-l-1)^{2})$。

所以这道题目是很明显的斜率优化dp。

 

如果k决策比j决策更优的话,那么(c=l+1)

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8 #include<queue>
 9 #include<cmath>
10 #include<map>
11 #include<set>
12 using namespace std;
13 typedef long long ll;
14 typedef pair<int,ll> pll;
15 const int INF = 0x3f3f3f3f;
16 const int maxn=50000+5;
17 
18 ll n, l;
19 ll c[maxn];
20 ll dp[maxn];
21 ll sum[maxn];
22 ll Q[maxn];
23 
24 ll dy(ll k, ll j)
25 {
26     return dp[k]+(sum[k]+l)*(sum[k]+l)-dp[j]-(sum[j]+l)*(sum[j]+l);
27 }
28 
29 ll dx(ll k, ll j)
30 {
31     return 2*(sum[k]-sum[j]);
32 }
33 
34 int main()
35 {
36     //freopen("in.txt","r",stdin);
37     while(~scanf("%lld%lld",&n,&l))
38     {
39         l+=1;
40         sum[0]=0;
41         for(int i=1;i<=n;i++)
42         {
43             scanf("%I64d",&c[i]);
44             sum[i]=sum[i-1]+c[i];
45         }
46         for(int i=1;i<=n;i++)  sum[i]+=i;
47         Q[1]=0;
48         int frt=1,rear=1;
49         for(int i=1;i<=n;i++)
50         {
51             while(frt<rear && dy(Q[frt+1],Q[frt])<=sum[i]*dx(Q[frt+1],Q[frt]))   frt++;
52             int tmp=Q[frt];
53             dp[i]=dp[tmp]+(sum[i]-sum[tmp]-l)*(sum[i]-sum[tmp]-l);
54             while(frt<rear && dy(Q[rear],Q[rear-1])*dx(i,Q[rear])>=dy(i,Q[rear])*dx(Q[rear],Q[rear-1]))  rear--;
55             Q[++rear]=i;
56         }
57         printf("%lld\n",dp[n]);
58     }
59     return 0;
60 }
posted @ 2017-08-09 21:12  Kayden_Cheung  阅读(186)  评论(0编辑  收藏  举报
//目录