• BZOJ 1010 [HNOI2008]玩具装箱toy 斜率优化dp


    [HNOI2008]玩具装箱toy

    斜率优化dp:

    好久没有写斜率优化dp都忘记了这个东西到底是怎么回事。

    对于斜率优化dp来说, 我们可以将一个 转移方程转换成 y = k x + b.

    其中要求的东西在b上。

    注意: 现在是给定了一堆点(x,y), 让你在固定k的前提下求出最小/最大的b是多少。

    如果现在是维护最小的b。

    那么我们需要维护出一个下凸壳。

    如果k是递增的话, 我们可以不断的将队头不是最优的(x,y)去掉,留下最优的点作为对头。(讲道理,如果在求最小b的情况下, 这个k应该不会递减,不然就显得特别蠢,23333)。

    如果k是随意的话,我们可以把下凸壳维护出来,然后二分找到最优解。

    题解:

    一开始列的方程应该为 dp[i] = min(dp[j] + (i-j-1 + sum[i] - sum[j] - L)^2)。

    因为n=1e5,所以这个题目不能用n^2去转移。

    可以令A = sum[i] + i, B = sum[j]+j+L+1

    化简前面的式子,可得:dp[j] + B^2 = 2 * A * B + dp[i] - A^2.

    y = dp[j] + B ^ 2, k = 2 * A, x = B, dp[i] - A ^ 2。

    也就是上面说的y = k * x + b了。

    通过维护一个下凸壳,我们可以在o(n)的复杂度内求出答案。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
    #define LL long long
    #define ULL unsigned LL
    #define fi first
    #define se second
    #define pb push_back
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define lch(x) tr[x].son[0]
    #define rch(x) tr[x].son[1]
    #define max3(a,b,c) max(a,max(b,c))
    #define min3(a,b,c) min(a,min(b,c))
    typedef pair<int,int> pll;
    const int inf = 0x3f3f3f3f;
    const int _inf = 0xc0c0c0c0;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL _INF = 0xc0c0c0c0c0c0c0c0;
    const LL mod =  (int)1e9+7;
    const int N = 2e5 + 100;
    int n, L;
    int a[N];
    int sta[N];
    LL sum[N];
    LL dp[N];
    LL calb(int id, int i){
        LL B = sum[id] + id + L + 1;
        LL A = sum[i] + i;
        return dp[id] + B * B - 2 * A * B;
    }
    double slope(int x, int y){
        double x1 = sum[x] + x + L + 1;
        double y1 = dp[x] + x1 * x1;
        double x2 = sum[y] + y + L + 1;
        double y2 = dp[y] + x2 * x2;
        return (y1-y2) / (x1-x2);
    }
    int Ac(){
        scanf("%d%d", &n, &L);
        for(int i = 1; i <= n; ++i){
            scanf("%d", &a[i]);
            sum[i] = sum[i - 1] + a[i];
        }
        int L = 1, R = 1; sta[0] = 0;
        for(int i = 1; i <= n; ++i){
            while(L < R && calb(sta[L], i) > calb(sta[L+1], i)) ++L;
            LL A = sum[i] + i;
            dp[i] = calb(sta[L], i) + A * A;
            while(L < R && slope(i,sta[R]) < slope(sta[R], sta[R-1])) --R;
            sta[++R] = i;
        }
        printf("%lld
    ", dp[n]);
        return 0;
    }
    
    int main(){
        Ac();
        return 0;
    }
    View Code
  • 相关阅读:
    Vue v-if v-for v-bind v-on
    Vue v-bind的使用
    Vue绑定事件
    vue绑定内联样式
    Vue简单使用
    js实现UTC时间转为北京时间,时间戳转为时间
    setTimeOut函数传参数
    直播聊天室,点亮效果,jquery实现
    聊天室自动滚动效果实现
    融云rongCloud聊天室的使用
  • 原文地址:https://www.cnblogs.com/MingSD/p/10855934.html
Copyright © 2020-2023  润新知