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

设状态f(i)表示将前i个玩具装箱后的最小费用,sum(i)表示前i个玩具的长度(c值)和
易得状态转移方程
这里写图片描述
其中 0 < j < i
为了简化式子,记这里写图片描述
将上式代入,开方1
则对于所有可能的这里写图片描述
这里写图片描述
这里写图片描述2
将上式移项后代入,得到这里写图片描述
现在要使b最小,k不变,若固定x,则y越小,b越小,所以维护一个下凸壳。
可以看出x与查询斜率k均单调递增,维护一个有关斜率的单调队列即可。

#include <cstdio>
#define N 50005
using namespace std;
typedef long long LL;
const double INF=1e10;
inline LL sq(LL x) { return x*x; }
struct Point {
    LL x,y;
    Point() {}
    Point(LL _x,LL _y):x(_x),y(_y) {}
    double operator ^ (const Point& rhs) const { //get_slope
        if(x==rhs.x) return y>rhs.y ? -INF : INF;
        return (double)(rhs.y-y)/(rhs.x-x);
    }
}q[N];
int n,l=1,r;
LL L,f[N],sum[N];
LL get_ans(LL k) {
    while(l<r && (q[l]^q[l+1])<k) l++;
    return q[l].y-k*q[l].x;
}
void Insert(Point o) {
    while(l<r && (q[r-1]^q[r])>(q[r-1]^o)) r--;
    q[++r]=o;
    return ;
}
int main() {
    scanf("%d%lld",&n,&L); L++;
    for(int i=1;i<=n;i++) scanf("%lld",sum+i), sum[i]+=sum[i-1]+1;
    //DP
    q[++r]=Point(0,0);
    for(int i=1;i<=n;i++) {
        f[i]=get_ans(2*(sum[i]-L))+sq(sum[i]-L);
        Insert(Point(sum[i],sum[i]*sum[i]+f[i]));
    }

    printf("%lld\n",f[n]);
    return 0;
}

  1. 因为要计算f(i),固定i,有关于i的量均为已知量。将已知量与常量放在一起开方。
  2. 因为要斜率优化,所以将f(i)和常量(已知量)放到b中;有关j与有关i的乘积的项中,将有关i的变量和常量看做斜率k,有关j的变量看做x;其余只含有有关j的量的项看做y
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值