令 (f_i) 表示在 (i) 工厂建立仓库,(i+1sim n-1) 工厂不建立仓库的最小总费用。对 (p) 做一遍前缀和。
转移直接枚举上一个建立的工厂在哪儿:
[f_i=min{f_j-(p_i-p_j) imes(x_n-x_i)+c_i|j<i}
]
考虑两个决策 (j,k(j<k)),若 (j) 比 (k) 优:
[f_j-(p_i-p_j) imes(x_n-x_i)<f_k-(p_i-p_k) imes(x_n-x_i)
]
[f_j-f_k<(x_n-x_i) imes(p_i-p_j-p_i+p_k)
]
[dfrac{f_k-f_j}{p_k-p_j}>x_i-x_n
]
因为 (x_i-x_n) 随着 (i) 的增大单调递增,所以维护一个下凸壳。
时间复杂度 (Oleft(n ight))。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 1000005
#define Db double
#define Min(x,y)((x)<(y)?x:y)
#define For(i,x,y)for(i=x;i<=(y);i++)
ll p[N],f[N];
int x[N],c[N],que[N];
int read()
{
int A;
bool K;
char C;
C=A=K=0;
while(C<'0'||C>'9')K|=C=='-',C=getchar();
while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
return(K?-A:A);
}
inline Db slope(int j,int k)
{
return Db(f[k]-f[j])/Db(p[k]-p[j]);
}
int main()
{
int n,i,head,tail;
n=read();
For(i,1,n)
{
x[i]=read(),p[i]=read(),c[i]=read();
f[0]-=p[i]*x[i];
p[i]+=p[i-1];
}
f[0]+=p[n]*x[n];
head=tail=1;
For(i,1,n-1)
{
while(head<tail&&slope(que[head],que[head+1])<=x[i]-x[n])head++;
f[i]=f[que[head]]-(p[i]-p[que[head]])*(x[n]-x[i])+c[i];
/*cout<<i<<' '<<f[i]<<' '<<que[head]<<endl;*/
while(head<tail&&slope(que[tail-1],que[tail])>=slope(que[tail],i))tail--;
que[++tail]=i;
}
For(i,1,n-1)f[0]=Min(f[0],f[i]);
cout<<f[0]+c[n];
return 0;
}