zoukankan      html  css  js  c++  java
  • BZOJ 1010: [HNOI2008]玩具装箱toy

    传送门

    斜率优化DP入门题

    首先有一个很显然的做法

    设 $f[i]$ 表示当前以第 i 个节点作为一段区间的结尾时,从 1 到 i 的最小花费

    然后枚举上一个作为结尾的物品的编号为 j

    那么转移就直接根据题意求就行了

    设长度的前缀和为 $sum$,那么花费就是 $(i-j-1+sum[i]-sum[j]-L)^2$

    那么转移方程为 $f[i]=f[j]+(i-j-1+sum[i]-sum[j]-L)^2$

    那么 $f[i]=f[j]+((i+sum[i])-(j+sum[j]+1+L))^2$

    设 $A[i]=i+sum[i],B[i]=A[i]+1+L$

    那么 $f[i]=f[j]+A[i]^2-2A[i]B[j]+B[j]^2$

    所以 $2A[i]B[j]+(f[i]-A[i]^2)=f[j]+B[j]^2$

    设 $y=f[j]+B[j]^2,k=2A[i],x=B[j],b=(f[i]-A[i]^2)$

    那么上式就变成了 $kx+b=y$ 的样子

    对于同一个 $i$,$k$ 是不变的,$A[i]^2$ 也是不变的,对于同一个 $i$ ,如果确定了直线 $y=kx+b$ 经过的一个点就确定了此直线

    所以如果我们能找到一个点 $(x_j,y_j)$,使得直线 $y=kx+b$ 的截距 $b$ 最小,那么此时的 $f[i]$ 也就取最小值

    对当前每个点 $(x,y)$ 维护一个下凸包,因为显然 $b$ 取最小时直线一定经过的是下凸包上的点,自己画个图就好了

    然后可以发现随着 $i$ 的上升,$k$ 是不降的,所以 $f[i]$ 也是满足单调不降的,所以直接用单调队列维护凸包内的点就好了(这个同样画个图就懂了)

    注意long long 

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    typedef double db;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=5e4+7;
    int n,L,c[N];
    ll sum[N],f[N];
    int q[N],hea,las;
    inline ll a(int x) { return sum[x]+x; }
    inline ll b(int x) { return a(x)+L+1; }
    inline ll X(int x) { return b(x); }
    inline ll Y(int x) { return f[x]+b(x)*b(x); }
    inline db slope(int i,int j) { return (db)(Y(i)-Y(j))/(X(i)-X(j)); }
    int main()
    {
        n=read(); L=read();
        for(int i=1;i<=n;i++) c[i]=read(),sum[i]=sum[i-1]+c[i];
        hea=las=1;
        for(int i=1;i<=n;i++)
        {
            while(hea<las&&slope(q[hea],q[hea+1])<2*a(i)) hea++;
            f[i]=f[q[hea]]+(a(i)-b(q[hea]))*(a(i)-b(q[hea]));
            while(hea<las&&slope(i,q[las-1])<slope(q[las-1],q[las])) las--;
            q[++las]=i;
        }
        cout<<f[n];
        return 0;
    }
  • 相关阅读:
    扩展KMP学习笔记
    【洛谷P5555】秩序魔咒【回文自动机】
    PAM(回文自动机)学习笔记
    形象理解转置原理在FFT中的应用
    NOIP2020考后总结与计划
    CSP2020游记
    JavaScript——面向对象编程
    JavaScript——实现继承的几种方式
    JavaScript闭包
    学习一门新编程语言的6个步骤
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10166561.html
Copyright © 2011-2022 走看看