BZOJ 1096 [ZJOI2007]仓库建设 - 斜率优化

听说是挺模板的一道题,然而我还是理解了好半天(太菜了233)

数学推演过程在这->http://www.cnblogs.com/ljh2000-jump/p/6015002.html(发照片好麻烦就不发了233)

大概斜率优化的整体过程是这样(针对于单调的那种):
1.写出dp方程;

2.推导当前状态i有关前面节点的式子,得到一个无关于i的类似于斜率形式的多项式。这里需要保证不等式另一端必须是只含i的单调式。

实现方法:

1.判断队列头几项是否满足当前状态的不等式(斜率在队列中不减),若不满足,则head+1必然比head优,于是舍弃;

2.更新dp[i]的值;

3.判断当前点是否可以进入队列,若要满足上凸函数的性质,则不断判断后两项与当前节点是否能组成上凸函数,若不能,则尾节点必定不比当前节点优,可以删去(斜率越大越有差的趋势)。


注意精度,爆了好几次。

代码如下:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
  
using namespace std;
  
const int maxn=1000015;
  
int n;
int x[maxn],c[maxn],p[maxn],q[maxn];
long long f[maxn],sp[maxn],smul[maxn];
  
double getk(int x,int y)
{
    return (double)((f[x]-f[y])+(smul[x]-smul[y]))/(double)(sp[x]-sp[y]);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",x+i,p+i,c+i);
        sp[i]=sp[i-1]+p[i];
        smul[i]=smul[i-1]+(long long)x[i]*p[i];
    }
    int head=1,rear=1;
    for(int i=1;i<=n;i++)
    {
        while(head<rear&&getk(q[head+1],q[head])<x[i])head++;
        f[i]=f[q[head]]+x[i]*(sp[i]-sp[q[head]])-(smul[i]-smul[q[head]])+c[i];
        while(head<rear&&getk(q[rear],q[rear-1])>getk(i,q[rear]))rear--;
        q[++rear]=i;
    }
    printf("%lld",f[n]);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值