zoukankan      html  css  js  c++  java
  • BZOJ3437 小P的牧场(斜率优化dp)

    题目link:http://www.lydsy.com/JudgeOnline/problem.php?id=3437;

    略略读一下题,发现这题是一道dp

    有一些牧场:

    1 2 3 4 5 6 7 8 9 10

    其中编号大的可以管住编号小的.

    a[i]表示建站费用 b[i]表示养殖奶牛数目

    dp方程大概就出来了

    f[i]=min(f[j]+cost(j+1,i)) (0<j<i);

    可是有些问题需要O(1)计算cost(j+1,i);

    怎么办呢?

    于是我想了一个很不清真的计算方法

    开了两个数组

    形式化的讲:

    sumb[i]=sumb[i-1]+b[i]

    sum[i]=sum[i-1]+sumb[i-1]

    有什么意义呢

    sumb[i]表示b的前缀和

    sum[i]表示如果1到i-1都要由i控制的运输费用;(不计建站费用)

    第一个转移是显然的

    第二个转移是因为可以将运输想象成两部分,先运到i-1,再运到i

    然后就可以O(1)计算cost(j+1,i)了

    cost(j+1,i)=sum[i]-sum[j]-sumb[j]*(i-j)

    这个文字比较难解释,还是看图吧

    矩形的长指i-k

    矩形的宽指b[k]

    (j<k<i)

    则矩形的面积指该点对sum的贡献

    参考

    很显然,现在cost=3号区域的面积

    已知:总面积=sum[i]; 1号区域面积=sum[j]; 2号区域面积=sumb[j]*(i-j);

    所以cost(j+1,i)=sum[i]-sum[j]-sumb[j]*(i-j);

    /-----------------分割线-----------------/

    现在f[i]=min(f[j]+sum[i]-sum[j]-sumb[j]*(i-j)+a[i])

    f[i]=min(f[j]-sum[j]-sumb[j]*(i-j))+sum[i]+a[i];

    开始斜率优化!

    1.去掉min,确认是维护下凸包

    2.f[i]=f[j]-sum[j]-sumb[j]*(i-j)+sum[i]+a[i];

    3.化式子f[i]+i*sumb[j]=f[j]-sum[j]+sumb[j]*j+const(这一坨是跟j无关的常量)

    4.对应     b  +k    x      =y

    然后一切就简单了

    但是这题有坑点,a,b数组要开long long,题中的数据范围是假的

    我因为括号写错了位置,WA一上午,最后只改了一个字符就AC了!QAQ

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000010;
    int n,h,t,q[N];
    long long a[N],b[N],sum[N],sumb[N],f[N];
    inline double X(const int &j){
        return sumb[j];
    }
    inline double Y(const int &j){
        return f[j]-sum[j]+sumb[j]*j;
    }
    inline double Rate(const int i,const int j){
        return (Y(i)-Y(j))/(X(i)-X(j));
    }
    int main(){
        scanf("%d",&n);
        for (int i=1; i<=n; i++) scanf("%lld",&a[i]);
        for (int i=1; i<=n; i++) scanf("%lld",&b[i]);
        for (int i=1; i<=n; i++){
            sumb[i]=sumb[i-1]+b[i];
            sum[i]=sum[i-1]+sumb[i-1];
        }
        for (int i=1; i<=n; i++){
            while (h<t&&Rate(q[h],q[h+1])<i) ++h;
            f[i]=f[q[h]]+sum[i]-sum[q[h]]-sumb[q[h]]*(i-q[h])+a[i];
               while(h<t&&Rate(q[t-1],q[t])>Rate(q[t],q[i])) t--;
            q[++t]=i;
        }
        printf("%lld",f[n]);
    }

    不知道读者明白这题了没有,不明白的话请联系Yuhuger

  • 相关阅读:
    POJ 2154
    POJ 1286
    Polycarp's problems
    Greedy Change
    Goods transportation
    Ugly Problem
    Happy Matt Friends
    Dense Subsequence
    Ray Tracing
    Batch Sort
  • 原文地址:https://www.cnblogs.com/Yuhuger/p/7295009.html
Copyright © 2011-2022 走看看