• 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 }
  • 相关阅读:
    Post和Get的区别(兼谈页面间传值的方式)
    ClickOnce部署Winform程序的方方面面
    TSQL查询进阶深入浅出视图
    一个java volatile测试揭开的陷阱
    java volatile的一个验证反例
    [Swing扩展组件分享]为JTable添加选择列(CheckBox)的包装类
    JTextField限制输入长度的完美解决方案
    swing程序的关闭机制看好你的swing.Timer,别让它成为程序不能退出的原凶
    举例理解单元测试
    打印出txt中出现频率最高的十个词——软件工程个人项目C语言
  • 原文地址:https://www.cnblogs.com/shimu/p/5653731.html
Copyright © 2020-2023  润新知