zoukankan      html  css  js  c++  java
  • [HNOI2008]玩具装箱TOY(斜率优化)

    题目链接
    题意:有编号为(1cdots N)的N件玩具,第 i 件玩具经过压缩后变成一维长度为 (C_i)​ 。要求在一个容器中的玩具编号是连续的,同时如果将第 i 件玩具到第 j 个玩具放到一个容器中,那么容器的长度将为 (x=j-i+sumlimits_{k=i}^{j}C_k)。​如果容器长度为 x ,其制作费用为 ((X-L)^2) .其中 L 是一个常量。容器数目长度不限。求最小费用。
    (1 le N le 50000,1 le L,Ci le 10^7)

    这道题是斜率优化的经典题了qvq
    当然dp顺序肯定是从前到后了
    分析一下答案式
    用f(j)来更新f(i)

    [X - L = i-(j + 1)+sumlimits_{k=j + 1}^{i}C_k - L= sum[i] + i - sum[j] - j - L - 1 ]

    (a[i] = sum[i] + i, b[i] = sum[i] + i + 1 + L)

    [f[i] = f[j] + (X - L)^2 = f(j) + (a[i] - b[j]) ^ 2 ]

    这里面 随j改变的量是(b[j], b[j]^2)(f[j])
    所以移项得 (2⋅a[i]⋅b[j]+f[i]−a[i]^2=f[j]+b[j]^2)
    将b[j]看作x,(f[j]+b[j]^2)看作y,这个式子就可以看作一条斜率为(2a[i])的直线
    f[i]即当上述直线过点(P(b[j],f[j]+b[j]^2))时,直线在y轴的截距加(a[i]^2)
    而题目即为找这个截距的最小值
    由于sum[i]随i递增 所以a[i],b[i]都递增
    所以点(1 cdots i-1)是从左到右排列的
    用单调栈维护一下凸包
    像做线性规划一样做一个切线就行了
    也就是二分斜率((P_j,P_{j+1}​) < 2a[i])
    update:貌似不用二分
    因为a[i]递增要查询的斜率也递增
    那单调队列维护就行了qvq

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int N = 1e5 + 5;
    const int K = 2e5;
    int n, L;
    double sum[N], f[N];
    int que[N], head, tail;
    inline double a(int x){return sum[x]+x;}
    inline double b(int x){return sum[x]+x+1+L;}
    inline double X(int x){return b(x);}
    inline double Y(int x){return f[x]+b(x)*b(x);}//注意这里不可以用define qvq 
    //a[i] = sum[i] + i, b[i] = sum[i] + i + 1 + L
    //P(b[j],f[j]+b[j]^2)
    inline double slope(int x, int y){
     return (Y(y) - Y(x)) / (X(y) - X(x));
    }
    int main() {
     scanf("%d%d", &n, &L);
     for(int i = 1; i <= n; ++i){
      scanf("%lf", &sum[i]);
      sum[i] += sum[i - 1];
     }
     head = tail = 1;
     for(int i = 1; i <= n; ++i){
      while(head < tail && slope(que[head], que[head + 1]) < 2 * a(i)) ++head;
      f[i] = f[que[head]] + (a(i) - b(que[head])) * (a(i) - b(que[head]));
      //printf("b %lld
    ", (long long)(a(i) - b(que[head])));
      while(head < tail && slope(que[tail - 1], que[tail]) > slope(que[tail - 1], i)) --tail;
      que[++tail] = i;
     }
     printf("%lld", (long long)f[n]);
     return 0;
    }
    
  • 相关阅读:
    c++ 反汇编 除法优化
    python3 循环位移动
    Reverse 高校网络信息安全运维挑战赛
    2019_西湖论剑_预选赛 testre
    《C++反汇编与逆向分析技术揭秘》--算术运算和赋值
    《C++反汇编与逆向分析技术揭秘》--认识启动函数,找到用户入口
    《C++反汇编与逆向分析技术揭秘》--数据类型
    D8016 “/ZI”和“/Gy-”命令行选项不兼容
    逆向学习书籍分享
    获得PyInstaller打包exe的py源码
  • 原文地址:https://www.cnblogs.com/hjmmm/p/10448468.html
Copyright © 2011-2022 走看看