P4360 [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)

// 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
",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/xzz_233/p/8779278.html