2018.08.28 洛谷P4360 [CEOI2004]锯木厂选址(斜率优化dp)

传送门
一道斜率优化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]) t o t a l = [ ∑ i = 1 n d i s [ i ] ∗ w [ i ] ] − d i s [ i ] ∗ w [ i ] − d i s [ j ] ∗ ( s u m [ j ] − s u m [ i ] )

然后假设对于两个不同的i取值比较优劣的话就相当于比较斜率,于是可以用斜率优化dp。
代码:

#include
#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(hdq[hd],q[hd+1])>dis[i])++hd;
        ans=min(ans,calc(q[hd],i));
        while(hdq[tl-1],q[tl])q[tl],i))--tl;
        q[++tl]=i;
    }
    cout<return 0;
}

你可能感兴趣的:(#,斜率优化,#,dp)