P4360 [CEOI2004]锯木厂选址

本文介绍了一个基于动态规划解决的CEOI2004锯木厂选址问题,通过枚举锯木厂位置并利用距离后缀和及重量前缀和优化计算过程,实现了高效的算法实现。

P4360 [CEOI2004]锯木厂选址


这™连dp都不是

\(f_i\)表示第二个锯木厂设在\(i\)的最小代价

枚举1号锯木厂

\(f_i=min_{0<=j<i}(\sum_{i=1}^{n}w_id_i-D_jW_j-D_iW_i+D_iW_j)\)

D为距离后缀和,W为重量前缀和

\(f_i=min_{0<=j<i}(D_iW_j-D_jW_j)+\sum_{i=1}^{n}w_id_i-D_iW_i\)

\(X=D_i,K=W_j,B=-D_jW_j\)

CkSA8s.gif

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct line{int k,b;};
double operator *(const line&a,const line&b){return(double)(a.b-b.b)/(b.k-a.k);}
line que[20100];
int w[20100],d[20100];
int s[20100],S[20100];
il int get(line&a,int x){return a.k*x+a.b;}
main(){
#ifdef xzz
    freopen("4360.in","r",stdin);
    freopen("4360.out","w",stdout);
#endif
    int n=gi();
    for(rg int i=1;i<=n;++i)w[i]=gi(),d[i]=gi();
    for(rg int i=n;i;--i)d[i]+=d[i+1];
    for(rg int i=1;i<=n;++i)s[i]=w[i]*d[i];
    for(rg int i=n;i;--i)S[i]=S[i+1]+s[i];
    for(rg int i=1;i<=n;++i)w[i]+=w[i-1];
    int hd=0,tl=0,ans=2e9;
    que[tl++]=(line){0,0};
    for(rg int i=1;i<=n;++i){
        while(tl-hd>1&&get(que[hd],d[i])>get(que[hd+1],d[i]))++hd;
        ans=std::min(ans,get(que[hd],d[i])+S[1]-w[i]*d[i]);
        line x=(line){w[i],-w[i]*d[i]};
        while(tl-hd>1&&x*que[tl-1]>que[tl-1]*que[tl-2])--tl;
        que[tl++]=x;
    }
    printf("%lld\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/xzz_233/p/8779278.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值