斜率优化DP P4360【锯木厂选址】

分析:

用sumw[i]记录∑ij=1w[j]∑j=1iw[j]维护前缀和

用sumd[i]记录∑i−1j=1d[j]∑j=1i−1d[j]维护前缀和

Cost[i]表示将第一个锯木厂建在i的位置时,1~i第一段的木材运到i的费用:

Cost[i]=Cost[i-1]+sumw[i-1]*d[i-1]

接着就可以用列出状态转移方程,设f[i]表示第二个锯木厂建在i时的费用

f[i]=min{ Cost[j]- sumw[j] (sumd[i]-sumd[j])- sumw[i] (sumd[n+1]-sumd[i]) }

令 y=sumw[j]*sumd[j] ,x=sumw[j] ,k=sumd[i]

维护下凸包,斜率优化乱搞即可。

下面是本蒟蒻的代码:

#include<bits/stdc++.h>
#define INF 0x7ffffffffff
using namespace std;
long long n,sumw[50005],sumd[50005],w[50005],d[50005],c[50005],q[50005],f[50005],ans=INF;
long double find(long long j,long long k){//计算斜率
    return (double)(sumw[k]*sumd[k]-sumw[j]*sumd[j])/(sumw[k]-sumw[j]);
}
int main() {
    scanf("%lld",&n);
    for(long long i=1;i<=n;i++)scanf("%lld%lld",&w[i],&d[i]);
    for(long long i=1;i<=n+1;i++) {
        sumw[i]=sumw[i-1]+w[i];//求出w的前缀和
        sumd[i]=sumd[i-1]+d[i-1];//求出d的前缀和
        c[i]=c[i-1]+sumw[i-1]*d[i-1];//c[i]表示把第一个锯木厂设在i,第一段木材运到i的总费用
    }
    long long l=1,r=1;
    q[1]=1;f[1]=0;
    for(long long i=2;i<=n;i++) {
        while(l<r&&find(q[l],q[l+1])<=sumd[i])l++;//维护队首(删除非最优决策)
        f[i]=sumw[q[l]]*sumd[q[l]]-sumd[i]*sumw[q[l]]+c[n+1]-sumw[i]*(sumd[n+1]-sumd[i]);
        while(l<r&&find(q[r-1],q[r])>=find(q[r],i))r--;//维护队尾(维护下凸包性质)
        q[++r]=i;//入队
        ans=min(ans,f[i]);
    }
    printf("%lld",ans);
    return 0;
}

小提示:不开long long 见祖宗

全部评论

相关推荐

粗心的雪碧不放弃:纯学历问题,我这几个月也是一直优化自己的简历,后来发现优化到我自己都觉得牛逼的时候,发现面试数量也没有提升,真就纯学历问题
点赞 评论 收藏
分享
gcniz:一天写两千行你闹呢
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务