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 }