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

BZOJ 1010 dp 斜率优化

时间:2015-12-20 17:25:15      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:

题意: 给一段数列,要求分成若干段,有一个公式可算每段的花费,求整段数列最小花费。

题意很裸,不难得出状态转移方程:dp[i]=min{dp[j]+(sum[i]-sum[j-1]+i-j-l)^2}(j<i);

但是数据范围很大,o(n^2)过不了,于是就用斜率优化变成n的,就过了。

下面详细讲一下斜率优化:

  斜率优化就是维护一个凸壳,使其严格上凸或下凸,具体情况具体分析,就本题而言设有k<j<i,且i从k转移来的,

  则:dp[k]+(sum[i]-sum[k-1]+i-k-l)^2<=dp[j]+(sum[i]-sum[j-1]+i-j-l)^2,方程变形得到不等式:

  dp[k]+(sum[k]+k+1+l)^2-dp[j]-(sum[j]+j+1+l)^2/(2*(sum[k]+k-sum[j]-j))<=sum[i]+i;

  观察,这个式子左边是一个与k,j有关的斜率表达式,而右边只含有i,所以可用一个单调队列来维护,就降到了n的复杂度。

下面是代码:

技术分享
 1 /**************************************************************
 2     Problem: 1010
 3     User: 201484348
 4     Language: C++
 5     Result: Accepted
 6     Time:120 ms
 7     Memory:5492 kb
 8 ****************************************************************/
 9  
10 #include<cstdio>
11 #include<iostream>
12 using namespace std;
13 typedef long long ll;
14 struct data{
15     ll x,y;
16 }cmp,D[50010];
17 int L,R,N,W;
18 ll C[500010];
19 inline ll jud(data a,data b,data c)
20 {
21     return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
22 }  
23 int main()
24 {
25     scanf("%d%d",&N,&W);
26     for (int i=1;i<=N;i++)
27     {
28         scanf("%lld",&C[i]);
29         C[i]+=C[i-1];
30     }
31     for (int i=1;i<=N;i++)
32     {
33         while (L<R&&D[L].y-2*(i+C[i]-W-1)*D[L].x>=D[L+1].y-2*(i+C[i]-W-1)*D[L+1].x) L++;
34         cmp.x=i+C[i];cmp.y=D[L].y-2*(i+C[i]-W-1)*D[L].x+(i+C[i]-W-1)*(i+C[i]-W-1)+(i+C[i])*(i+C[i]);
35         while (L<R&&jud(D[R-1],D[R],cmp)<=0) R--;
36         D[++R]=cmp;
37     }
38     printf("%lld\n",D[R].y-(N+C[N])*(N+C[N]));
39     return 0;
40 }
View Code

 

BZOJ 1010 dp 斜率优化

标签:

原文地址:http://www.cnblogs.com/nieyunhe/p/5061120.html

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