题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1096
设 f[i] 为 i 作为最后一个仓库时前 i 个工厂的答案,最后的答案当然是 f[n];
f[i] = min{ f[j] + ∑(j+1<=k<=i)p[k]*(x[i]-x[k]) + c[i] } , 1<=j<i
令 s[i] = ∑(1<=j<=i)p[j],t[i] = ∑(1<=j<=i)p[j]*x[j]
则 f[i] = min{ f[j] + x[i]*(s[i]-s[j]) - (t[i]-t[j]) + c[i] }
移项,得到 f[j] + t[j] = x[i]*s[j] - x[i]*s[i] + t[i] - c[i] + f[i]
x[i] 单增,s[j] 单增,可以看出是要维护一个下凸包。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef double db; typedef long long ll; int const xn=1e6+5; int n,x[xn],p[xn],c[xn],q[xn]; ll s[xn],t[xn],f[xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } db y(int i){return f[i]+t[i];} db slp(int a,int b){return (y(b)-y(a))/(s[b]-s[a]);} int main() { n=rd(); for(int i=1;i<=n;i++) { x[i]=rd(),p[i]=rd(),c[i]=rd(); s[i]=s[i-1]+p[i]; t[i]=t[i-1]+(ll)p[i]*x[i]; } int hd=0,tl=0; for(int i=1;i<=n;i++) { while(hd<tl&&slp(q[hd],q[hd+1])<x[i])hd++; f[i]=f[q[hd]]+(ll)x[i]*(s[i]-s[q[hd]])-t[i]+t[q[hd]]+c[i]; while(hd<tl&&slp(q[tl-1],q[tl])>slp(q[tl-1],i))tl--; q[++tl]=i; } printf("%lld\n",f[n]); return 0; }