• hdu3570, 超级简单的斜率优化dp


    dp[i] = dp[j] + (a[i] - a[j])^2 + m;
    展开得 dp[i] = min{dp[j] + a[i]^2 + a[j]^2 - 2*a[i]*a[j] + m}
    其中a[i]^2 是与i相关的变量, 而m是常量,所以可以从表达式中抽离出来
    所以只要求 dp[i] = min{dp[j] + a[j]^2 + 2*a[i]*a[j]} 即可,
    设k = a[i] ,  x = 2*a[j], y = dp[j] + a[j]^2,G = dp[i]
    那么就是G = -kx + y,
    为了得到dp[i]的最小值, 那么需要枚举j,那么相当于二维的坐标系上有很多个点,
    然后有一条斜率为-k的直线从y轴下方无限远处慢慢向上平移, 直到经过坐标系上的一个点,
    那么此时与y轴的截距G是最小的,


    我们只要维护一个凸包就行了。

    设红线的斜率为k,直线ab的斜率为kab,
    如果k<kab, 那么点a就是最优的,因为如果要经过点a之后的点,就必须把红线往上平移
    如果k>kab, 那么点a不是最优的,因为如果要经过点b,是把红线往下移,也就是说点a是可以舍弃的,因为k=a[i],
    而a[i]是递增不减的,所以说点a是当前可舍弃,以后也可舍弃的
    至于k==kab, 那么点a也是可舍弃的


    为什么不在凸包上的点就不可能成为最优点呢?


    因为t不在凸包上,所以ktb <  kat
    如果t可以成为最优的,那么就是说存在一条斜率为k的直线
    使得k>=kat且 k<ktb,  然而ktb < kat, 所以这是不可能发生的事情,所以舍弃掉

    所以我们就是维护一个凸包就行啦。

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <math.h>
     4 #include <iostream>
     5 #include <algorithm>
     6 #include <vector>
     7 #include <queue>
     8 #include <stack>
     9 #include <functional>
    10 #include <map>
    11 #include <set>
    12 using namespace std;
    13 typedef long long LL;
    14 const int INF = 1<<30;
    15 /*
    16  * */
    17 const int N = 500000 + 10;
    18 int a[N];
    19 int dp[N];
    20 int q[N],head,tail;
    21 int n,m;
    22 int getUp(int k1, int k2)
    23 {
    24     return (dp[k1]+a[k1]*a[k1]) - (dp[k2]+a[k2]*a[k2]);
    25 }
    26 int getDown(int k1, int k2)
    27 {
    28     return  a[k1] -  a[k2];
    29 }
    30 int getDp(int i, int k)
    31 {
    32     return dp[k] + (a[i] - a[k]) * (a[i] - a[k]) + m;
    33 }
    34 int main()
    35 {
    36     //freopen("/Users/whoami/in.txt","r",stdin);
    37     while(scanf("%d%d",&n,&m)!=EOF)
    38     {
    39         memset(dp,0,sizeof(dp));
    40         for(int i=1;i<=n;++i)
    41         {
    42             scanf("%d",&a[i]);
    43             a[i] += a[i-1];
    44         }
    45         head = tail = 0;
    46         q[tail++] = 0;
    47         for(int i=1;i<=n;++i)
    48         {
    49             /*
    50                 while(head+1<tail && getDp(i,q[head])<=getDp(i,q[head+1]))
    51                 head++;
    52             */
    53             //得到最优值
    54             while(head+1<tail && getUp(q[head+1], q[head])<=2 * a[i] * getDown(q[head+1], q[head]))
    55                 head++;
    56             dp[i] = getDp(i,q[head]);
    57             //维护下凸包,
    58             while(head+1<tail &&  getUp(q[tail-1],q[tail-2])*getDown(i,q[tail-1]) >= getUp(i,q[tail-1])*getDown(q[tail-1],q[tail-2]))
    59                 tail--;
    60             q[tail++] = i;
    61 
    62         }
    63         printf("%d
    ",dp[n]);
    64     }
    65     return 0;
    66 }
    View Code
  • 相关阅读:
    关于service相关知识的认识
    如何在service实现弹出对话框
    NDK编程jni学习入门,声明native方法,使其作为java与c的交互接口
    js事件
    es6箭头函数
    es6展开运算符
    es6 解构赋值
    js 函数的this指向
    js函数作用域
    js 预解析以及变量的提升
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4949303.html
Copyright © 2020-2023  润新知