zoukankan      html  css  js  c++  java
  • BZOJ-1010&洛谷P3195玩具装箱toy-【HNOI2008】斜率优化DP+单调队列

    Time Limit: 1 Sec  Memory Limit: 162 MB

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1010

    洛谷:https://www.luogu.com.cn/problem/P3195

    Description

      P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压
    缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具经过
    压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容
    器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一
    个容器中,那么容器的长度将为 $x=j-i+sum_{k=i}^{j}C_{k}$ 制作容器的费用与容器的长度有关,根据教授研究,
    如果容器长度为x,其制作费用为$(X-L)^{2}$.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容
    器,甚至超过L。但他希望费用最小.

    Input

      第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7

    Output

      输出最小费用

    Sample Input

    5 4
    3
    4
    2
    1
    4

    Sample Output

    1

    emmm,我连DP都不会。。。突然让我写个斜率优化DP。。。
    这个DP的式子不是很难得出来,当然对于我这种蒟蒻就很难了。设dp[i]为有i个玩具时的最优解,那么可得:
    $dp[i]=min(dp[i],dp[j]+(i-j+sum[i]-sum[j]-L-1)^{2}$
    即第i个最优解是由第j个最优解转移过来的,那么我们枚举j就完事了:
    memset(dp,0x7f,sizeof dp);
    dp[0]=0;
    for (int i=1; i<=n; i++)
        for (int j=0; j<i; j++){
            dp[i]=min(dp[i],dp[j]+pow(sum[i]+i-sum[j]-j-m-1));
        }

    而很显然,这是个$O(n^{2})$复杂度的算法。。。会T掉。加了$O_{2}$优化后在洛谷能得60分。而没有优化只有20分。。。

    那么我们就需要将它优化成$O(nlogn)$或者$O(n)$的复杂度。

    斜率优化的式子的一般是这样的:$dp[i]=a[i] imes b[j]+c[i]+d[j]$

    至于这里的$dp[i]=dp[j]+(sum[i]+i-sum[j]-j-L-1)^{2}$  我们令$a[i]=sum[i]+i,b[i]=sum[i]+i+L+1$

    则展开式子得:$dp[i]=dp[j]+a[i]^{2}+b[j]^{2}-2a[i]b[j]$ 那么可以知道的是j是在不断变动的,而i是固定的,那么我们可设b[j]为x,则式子可化为:

    $dp[j]+b[j]^{2}=2a[i]b[j]-a[i]^{2}+dp[i]$即$Y=2a[i]X+B$

    其中B包含dp[i],那么我们只要求Y在斜率为$2a[i]$下的最小截距就OK了,又$a[i]=sum[i]+i$为递增的,那么也就是说最优解的图形会构成一个下凸包的形状,

    而显然,凸包中相邻两点的斜率是单调递增的,$2 imes a[i]$也是单调递增的,那么最优的点$P_{j}$即为第一个斜率$k(P_{j},P_{j+1})>2a[i]$的点。我们用单调队列维护这个凸包即最优点,设head和tail:
    1.$while (k(q_{head},q_{head+1})<2a[i])  head++$
    2.此时q[head]这个点为最优点,可直接算出dp[i]
    3.$while (k(q_{tail-1},q_{tail})>k(q_{tail-1},i)) tail-- $ !维护凸包,新加入的点和tail-1的点构成的斜率必须小于tail和tail-1的斜率,这样才能构成下凸包:

    如图所示,红色为新的点。

    4.在队尾插入点$P_{i}$
     
    更多更详细的斜率优化问题戳这里:https://www.cnblogs.com/Xing-Ling/p/11210179.html 
     
    以下是AC代码: 
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    typedef long long ll;
    const int mac=5e4+10;
    int m;
    
    ll dp[mac],q[mac],sum[mac];
    
    ll X(ll x) {return sum[x];}
    
    ll Y(ll x) {return dp[x]+(sum[x]+m)*(sum[x]+m);}
    
    long double slope(ll a,ll b)
    {
        return (long double)((Y(a)-Y(b))/(X(a)-X(b)));
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        int n;
        scanf ("%d%d",&n,&m);
        for (int i=1; i<=n; i++){
            int x;
            scanf("%d",&x);
            sum[i]=sum[i-1]+x+1;
        }
        m++;
        int head=1,tail=0;
        q[++tail]=0;
        for (int i=1; i<=n; i++){
            while (head<tail && slope(q[head],q[head+1])<=2*sum[i])
                ++head;
            int j=q[head];
            dp[i]=dp[j]+(sum[i]-sum[j]-m)*(sum[i]-sum[j]-m);
            while (head<tail && slope(q[tail-1],q[tail])>=slope(q[tail-1],i))
                tail--;
            q[++tail]=i;
        }
        printf("%lld
    ",dp[n]);
        return 0;
    }
     
     
     
     
    路漫漫兮
  • 相关阅读:
    vue, 同一个页面有多处地方需要上传图片
    单张图片上传,vue
    replace 替换只会替换找到的第一个字符
    vue ant design table中rowSelection属性的应用
    一般做页面时需要注意的事项
    vue 为form 表单赋值 获取form表单的值
    vue 父子组件中的传值
    vue 页面跳组件,实现点击浏览器自带返回箭头,返回到上一个页面,而不是返回道上个路由
    vue ant design a-table 的分页
    初建vuex项目
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/12205258.html
Copyright © 2011-2022 走看看