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;

}

 

 

你可能感兴趣的:(ZOJ)