zoukankan      html  css  js  c++  java
  • 斜率优化

    斜率优化

    2 种方法

    比如这个式子: (from [HNOI2008]玩具装箱TOY)

    [f[i] = min{ f[j] + (sum[i] + i - sum[j] - j - L - 1) ^ 2 } ]

    大概有两种方法:

    1. 考虑 (i, j) 的关系, 将分别只和 (i, j) 有关的式子分开,
      整理成为 (y = kx + b) 的形式, 要求其中 (b) 为和 (f[i]) 有关的式子, (y) 是和 (f[j]) 有关的式子, (x)(j) 有关, (k)(i) 有关
      这样一个 (j) 就成了一个坐标 ((x, y)), 本题中取 (min), 就转化成了在和 (i) 有关的斜率 (k) 下取最小的 (b) 即截距
    2. 考虑 (i) 的两个子状态 (j, k), 他们谁更优, 这里假定 (j > k), (j)(k) 更优的情况
      然后将 (j, k) 分别带入 (f[i]) 的递推式中, 同样将仅与 (j, k) 有关的式子分开, 整理为 (frac{y_j - y_k}{x_j - x_k} < k)
      其中 (y) 是包含 (f) 的, (x) 不包含, (k) 则是仅与 (i) 有关, 取 (min) 就用 (<), 反之亦然

    以上都是基本的转化, 现在考虑两种方法分别如何求最优值

    首先都是要画图, 然后就会发现两种方法是极其类似的,

    1. 假设有 3 个可以取的点组成 上凸折线, 由线性规划的方法容易得到, 用任何斜率取切, 中间那个上凸点都切不到, 会被另外两个点卡住
      显然, 不管斜率如何, 都只需要留下下凸包的点
    2. 任然用这三个点, 首先左边两点的斜率 > 右边, 然后枚举一下现在的斜率与这两个的关系, 可以得到 3 中情况, 可以发现中间点都不用取
      得到了同样的结论

    于是, 对于每个 (i), 可以在 ([1, i - 1]) 这些点组成的凸包上的点取值, 用 (i) 的斜率一个一个比过去即可,
    例如本题中保留下凸包, 对于两种方法, 都是找到第一个大于当前斜率的点

    不难想到可以用二分来查找

    然而, 许多题都满足 (i) 的斜率有单调性, 比如这题, 两种方法中斜率都是 (2(sum[i] + i)), 其中两个变量都是单增的, 所以单增
    于是, 凸包中也是斜率不断增的, 对于每个 (i) , 把从凸包起点开始不断删(即上面的暴力过程), 直到大于当前斜率, 显然这样复杂度是线性的

    接下来用本题具体演示一下

    第一种:

    (A[j] = (sum[j] + j + L + 1))

    [f[j] + A[j] ^ 2 = 2 cdot (sum[i] + i) cdot A[j] + f[i] - (sum[i] + i) ^ 2 ]

    第二种:

    (A[j] = (sum[j] + j + L + 1))

    [frac{(f[j] + A[j] ^ 2) - (f[k] + A[k] ^ 2)}{a[j] - a[k]} le 2 cdot (sum[i] + i) ]

    代码是一样的

    
    int n;
    
    const int MAXN = 5e4 + 10;
    
    LL L, sum[MAXN], a[MAXN], f[MAXN];
    
    struct Node
    {
        LL x, y;
    } q[MAXN];
    int h, t;
    
    /*
    0815
     */
    int main()
    {
        n = in();
        L = in();
        for (int i = 1; i <= n; ++ i) 
        {
    	sum[i] = sum[i - 1] + in();
    	a[i] = (sum[i] + i + L + 1);
        }
        a[0] = L + 1;
        f[0] = 0;
        h = t = 1;
        q[1].x = a[0], q[1].y = a[0] * a[0];
        for (int i = 1; i <= n; ++ i)
        {
    	while (h < t && (q[h + 1].y - q[h].y) <= 2 * (sum[i] + i) * (q[h + 1].x - q[h].x)) ++ h;
    	f[i] = q[h].y - 2 * (sum[i] + i) * q[h].x + (sum[i] + i) * (sum[i] + i);
    	Node now = (Node) { a[i], f[i] + a[i] * a[i] };
    	while (h < t && (now.y - q[t].y) * (q[t].x - q[t - 1].x) <= (q[t].y - q[t - 1].y) * (now.x - q[t].x)) -- t;
    	q[++ t] = now;
        }
        printf("%lld
    ", f[n]);
        return 0;
    }
    
    
  • 相关阅读:
    解决DataGridView绑定List后不能排序的问题
    最新的皮肤下载
    我收录的名言
    HttpRequest访问Https带有证书并使用WSDL文档生成代理类方案(2)
    最新的Functions 类
    华兴软通短信接口简单使用WebServices版
    最新的SqlHelper 类
    闲来没事写个记事本玩玩!!!
    "基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系"证书验证失败的解决过程(3)
    FCK配置
  • 原文地址:https://www.cnblogs.com/Kuonji/p/11865015.html
Copyright © 2011-2022 走看看