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; }