bzoj1096: [ZJOI2007]仓库建设

斜率优化dp。

不想写表达式。。。。

s[i]维护前缀p,sx[i]维护前缀p*x。

这样将原dp转移方程转化为了

f[i]=f[j]+(s[i-1]-s[j])x[i]-(sx[i-1]-sx[j])+c[i]。

斜率优化,当i决策时,j>k且j优于k则 x[i]>(f[j]-f[k]+sx[j]-sx[k])/(s[j]-s[k]).

这样就要维护一个下凸包。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1000000 + 10;

long long x[maxn],p[maxn],c[maxn];
int n;
long long s[maxn],sx[maxn],f[maxn];
int q[maxn],l,r;

double slop (int k,int j) {
    return (f[j]-f[k]+sx[j]-sx[k])/(1.0*(s[j]-s[k]));    
}

int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%lld%lld%lld",&x[i],&p[i],&c[i]);
        s[i]=s[i-1]+p[i];    
        sx[i]=sx[i-1]+p[i]*x[i];
    }
    l=0;r=1;
    for(int i=1;i<=n;i++) {
        while(l<r-1 && x[i]>slop(q[l],q[l+1])) l++;
        int t=q[l];
        f[i]=f[t]+(s[i-1]-s[t])*x[i]-(sx[i-1]-sx[t])+c[i];
        while(l<r-1 && slop(q[r-2],q[r-1]) > slop(q[r-1],i) ) r--;
        q[r++]=i;
    }
    printf("%lld
",f[n]);
    return 0;
}
原文地址:https://www.cnblogs.com/invoid/p/5552966.html