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

posted @ 2017-08-06 15:50  Yuhuger  阅读(157)  评论(0编辑  收藏  举报