传送门 一道斜率优化dp入门题。
是这样的没错。。。
我们用dis[i]表示i到第三个锯木厂的距离,sum[i]表示前i棵树的总重量,w[i]为第i棵树的重量,于是发现如果令第一个锯木厂地址为i,第二个地址为j,则有
total=[∑ni=1dis[i]∗w[i]]−dis[i]∗w[i]−dis[j]∗(sum[j]−sum[i])total=[∑i=1ndis[i]∗w[i]]−dis[i]∗w[i]−dis[j]∗(sum[j]−sum[i])。
然后假设对于两个不同的i取值比较优劣的话就相当于比较斜率,于是可以用斜率优化dp。
代码:
#include<bits/stdc++.h>
#define N 30005
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,ans=2e9,tot,sum[N],dis[N],w[N],q[N],hd,tl;
inline double slope(int a,int b){return 1.0*(dis[a]*sum[a]-dis[b]*sum[b])/(sum[a]-sum[b]);}
inline int calc(int a,int b){return tot-dis[a]*sum[a]-dis[b]*(sum[b]-sum[a]);}
int main(){
n=read();
for(int i=1;i<=n;++i)w[i]=read(),dis[i]=read();
for(int i=n-1;i;--i)dis[i]+=dis[i+1];
for(int i=1;i<=n;++i)sum[i]=sum[i-1]+w[i],tot+=w[i]*dis[i];
for(int i=1;i<=n;++i){
while(hd<tl&&slope(q[hd],q[hd+1])>dis[i])++hd;
ans=min(ans,calc(q[hd],i));
while(hd<tl&&slope(q[tl-1],q[tl])<slope(q[tl],i))--tl;
q[++tl]=i;
}
cout<<ans;
return 0;
}