题目
思路
设(dis[i])表示i到山脚的距离,(sum[i])表示前i个木材的重量和,(tot)为不建锯木厂的代价
假设分别建在(i,j)位置((i<j)),那么有(ans=min(tot−dis[j]∗sum[j]−dis[i]∗(sum[i]−sum[j])))
化简得:(frac{dis[j]*sum[j]-dis[k]*sum[k]}{sum[j]-sum[k]} > dis[i])
维护上凸壳即可
Code
#include<bits/stdc++.h>
#define N 20005
using namespace std;
int n,w[N],d[N],dis[N],sum[N],tot;
int q[N],l=1,r=0,ans=2000000001;
template <class T>
void read(T &x)
{
char c;int sign=1;
while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}
double k(int x,int y) {return ((double)dis[x]*sum[x]-(double)dis[y]*sum[y])/(sum[x]-sum[y]);}
int main()
{
read(n);
for(int i=1;i<=n;++i) read(w[i]),read(d[i]);
for(int i=1;i<=n;++i) sum[i]=sum[i-1]+w[i];
for(int i=n;i>=1;--i) dis[i]=dis[i+1]+d[i];
for(int i=n;i;--i) tot+=dis[i]*(sum[i]-sum[i-1]);
for(int i=1;i<=n;++i)
{
while(l<r && k(q[l],q[l+1])>dis[i]) ++l;
ans=min(ans,tot-dis[q[l]]*sum[q[l]]-dis[i]*(sum[i]-sum[q[l]]));
while(l<r && k(i,q[r-1])<k(i,q[r])) --r;
q[++r]=i;
}
cout<<ans<<endl;
return 0;
}