O(n^2)dp方程:f[i]=min(f[j]+(P[i]-P[j])*x[i]-G[i]+G[j]+c[i])(0<j<i)
P[i]表示p[i]的前缀和,G[i]表式p[i]*c[i]的前缀和,f[i]表示i处建仓库且i之前的所有工厂的产品都安顿的最小代价
我们可以发现该方程可以用斜率优化
斜率K(k,j)=(f[j]-f[k]+G[j]-G[k])/(P[j]-P[k])
ac代码
#include<bits/stdc++.h> #define maxn 1000005 #define ll long long using namespace std; ll P[maxn],G[maxn],f[maxn],c[maxn],x[maxn]; int q[maxn]; int n; int read() { int x=0,f=1,c;while(!isdigit(c=getchar()))if(c=='-')f=-1; while(x=x*10+c-'0',isdigit(c=getchar())); return x*f; } double K(int k,int j) { return (double)(f[j]-f[k]+G[j]-G[k])/(P[j]-P[k]); } int main() { n=read(); for(int i=1;i<=n;i++) { x[i]=read();int p=read();c[i]=read(); G[i]=G[i-1]+p*x[i]; P[i]=P[i-1]+p; } int l=0,r=0; for(int i=1;i<=n;i++) { while(l<r&&K(q[l],q[l+1])<x[i])l++; int t=q[l]; //printf("%d %d %d %d\n",l,r,q[l],q[r]); f[i]=f[t]+(P[i]-P[t])*x[i]-G[i]+G[t]+c[i]; while(l<r&&K(q[r-1],q[r])>K(q[r],i))r--; q[++r]=i; //printf("%d %d %d %d\n",l,r,q[l],q[r]); } printf("%lld\n",f[n]); return 0; }