bzoj 1096 斜率优化DP

  首先比较容易的看出来是DP,w[i]为前i个工厂的最小费用,那么w[i]=min(w[j-1]+cost(j,i))+c[i],但是这样是不work的,复杂度上明显过不去,这样我们考虑优化DP。

  设A[i]=Σp[j](0<j<=i),B[i]=Σp[j]*x[j](0<j<=i),那么我们就可以表示cost(j,i)了。

  cost(j,i)=Σ(x[i]-x[k])*p[k]

      =Σx[i]*p[k]-Σx[k]*p[k]

      =x[i]*(A[i]-A[j-1])-(B[i]-B[j-1])

      =x[i]*A[i]-x[i]*A[j-1]-B[i]+B[j-1]

  对于这个式子我们考虑斜率优化,假设j>k且决策j优于决策k。

  那么有w[j-1]-x[i]*A[j-1]+B[j-1]<w[k-1]-x[i]*B[k-1]+B[k-1]

  那么((w[j-1]+B[j-1])-(w[k-1]+B[k-1]))/(A[j-1]-B[k-1])<x[i]

  这样就是标准的斜率优化了,维护一个上凸壳就行了。

/**************************************************************
    Problem: 1096
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:2648 ms
    Memory:55492 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#define maxn 1000010
#define LL long long
 
using namespace std;
 
int n;
LL a[maxn],c[maxn],x[maxn],que[maxn];
LL A[maxn],B[maxn],w[maxn];
 
double k(int k,int j)
{
    double kk;
    kk=(((w[j-1]+B[j-1])-(w[k-1]+B[k-1]))/(A[j-1]-A[k-1]));
    return kk;
}
 
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%lld%lld%lld",&x[i],&a[i],&c[i]);
    for (int i=1;i<=n;i++) A[i]=A[i-1]+a[i],B[i]=B[i-1]+a[i]*x[i];
    int h=1,t=0;
    for (int i=1;i<=n;i++)
    {   
        for (;(h<t)&&(k(que[t-1],i)<k(que[t-1],que[t]));t--);
        que[++t]=i;
        for (;(h<t)&&(k(que[h],que[h+1])<x[i]);h++);
        int cur=que[h];
        w[i]=w[cur-1]+x[i]*A[i]-x[i]*A[cur-1]-B[i]+B[cur-1]+c[i];
        //printf("%d %d\n",h,t);
    }
    printf("%lld\n",w[n]);
    return 0;
}
 

 

posted on 2014-02-17 08:22  BLADEVIL  阅读(344)  评论(0编辑  收藏  举报