bzoj3156 斜率dp

入门的斜率dp,wa了真的好多发,,,

dp方程为dp[i]=dp[j]+a[i]+(i-j)*(i-j-1)/2;

基本正常思路设i>j>k,假设j比k优

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

化简得dp[j]-dp[k]+(j*j+j)/2-(k*k+k)/2<i*(j-k);

其实就是把j与k化简出来然后把i放在不等式另一边求斜率

得(yj-yk)/(xj-xk)<i;

然后就是斜率dp

 

那么yj-yk/xj-xk<i说明了什么呢?  我们前面是不是假设j的决策比k的决策要好才得到这个表示的? 如果是的话,那么就说明g[j,k]=yj-jk/xj-xk<i代表这j的决策比k的决策要更优。

 

关键的来了:现在从左到右,还是设k<j<i,如果g[i,j]<g[j,k],那么j点便永远不可能成为最优解,可以直接将它踢出我们的最优解集。为什么呢?

我们假设g[i,j]<sum[i],那么就是说i点要比j点优,排除j点。

如果g[i,j]>=sum[i],那么j点此时是比i点要更优,但是同时g[j,k]>g[i,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]<i,那么说明b点比a点更优,a点可以排除,于是a出队。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <set>
 4 #include <iostream>
 5 #include <map>
 6 #include <math.h>
 7 #include <algorithm>
 8 #include <vector>
 9 using namespace std;
10 typedef long long ll;
11 ll  a[1000005],dp[1000005];
12 int q[1000005];
13 ll qujian(int u)
14 {
15     ll i=u;
16     return (i-1)*(i)/2;
17 }
18 ll getup(int i1,int j1)
19 {
20     ll i=i1,j=j1;
21     return (2*dp[j1]+(j*j+j))-(2*dp[i1]+(i*i+i));
22 }
23 ll getdown(int i1,int j1)
24 {
25      ll i=i1,j=j1;
26     return 2*(j-i);
27 }
28 int n;
29 int main()
30 {
31  //   freopen("in.txt","r",stdin);
32 // cout<<"r"<<endl;
33   cin>>n;
34         int i;
35 
36         //  cout<<"r"<<endl;
37         for(i=1; i<=n; i++)
38             scanf("%lld",&a[i]);
39 
40         //cout<<"r"<<endl;
41       //  dp[1]=a[1];
42         int head=0,tail=0;
43         q[tail]=0;
44         for(i=1; i<=n; i++)
45         {
46             while(head<tail&&getup(q[head],q[head+1])<i*getdown(q[head],q[head+1]))
47                 head++;
48             //cout<<"r"<<endl;
49             dp[i]=dp[q[head]]+a[i]+qujian(i-q[head]);
50             while(head<tail&&getup(q[tail-1],q[tail])*getdown(q[tail],i)>getup(q[tail],i)*getdown(q[tail-1],q[tail]))
51                 tail--;
52             q[++tail]=i;
53         }
54         cout<<dp[n]<<endl;
55 
56     
57     return 0;
58 }

 

posted @ 2016-07-08 16:05  十目  阅读(186)  评论(0编辑  收藏  举报