zoukankan      html  css  js  c++  java
  • P4655 [CEOI2017]Building Bridges 题解

    Link

    P4655 [CEOI2017]Building Bridges

    Solve

    我们很容易能退出转移方程

    [dp[i]=min(dp[i],dp[j]+(H[i]-H[j])ast (H[i]-H[j])+S[i-1]-S[j]) ]

    [dp[i]=dp[j]-2ast H[i]ast H[j]+H[j]ast H[j]+H[i]ast [i]+S[i-1]-S[j] ]

    [(2ast H[i]) * H[j] + (dp[i]-S[i-1]-H[i]ast H[i]) = (dp[j]+H[j]ast H[j]-S[j]) ]

    此时就能发现是斜率优化了。

    但是这里的的k[i]和x都不递增,所以用(CDQ)或者线段树来维护,我用的是(CDQ)来维护

    Code

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #define LD long double
    #define LL long long
    #define Re register int
    #define S2(a) (1ll*(a)*(a))
    using namespace std;
    const LL N=1e5+3,inf=1e18;
    int n,H[N],W[N],Q[N];LL S[N],dp[N];
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    //dp[i]=min(dp[i],dp[j]+(H[i]-H[j])*(H[i]-H[j])+S[i-1]-S[j]);
    //dp[i]=dp[j]-2*H[i]*H[j]+H[j]*H[j]+H[i]*H[i]+S[i-1]-S[j]
    //(2*H[i]) * H[j] + (dp[i]-S[i-1]-H[i]*H[i]) = (dp[j]+H[j]*H[j]-S[j])
    //   k     *  x   +            b             =          y
    #define X(j) (a[j].x)
    #define Y(j) (a[j].y)
    struct QAQ{
        int k,x,id;LL y;
        inline bool operator<(const QAQ &O)const{return x!=O.x?x<O.x:y<O.y;}
    }a[N],b[N];
    inline bool cmp(QAQ A,QAQ B){return A.k<B.k;}
    inline LD slope(Re i,Re j){return X(i)==X(j)?(Y(j)>Y(i)?inf:-inf):(LD)(Y(j)-Y(i))/(X(j)-X(i));}
    inline void CDQ(Re L,Re R){
        if(L==R){Re j=a[L].id;a[L].y=dp[j]+(LL)H[j]*H[j]-S[j];return;}//此时dp[j]必定已经求出来了,直接算计Y(j)即可
        Re mid=L+R>>1,p1=L,p2=mid+1,h=1,t=0;
        for(Re i=L;i<=R;++i)a[i].id<=mid?b[p1++]=a[i]:b[p2++]=a[i];//按照i的大小分到左右两边(两边的k0[i]分别递增)
        for(Re i=L;i<=R;++i)a[i]=b[i];
        CDQ(L,mid);//处理完左边后,左边的X(j)是递增的,此时右边还没处理,所以右边k0[i]是递增的
        for(Re i=L;i<=mid;++i){//把左边的点拿出来维护凸包(使用单调队列)
            while(h<t&&slope(Q[t-1],Q[t])>=slope(Q[t-1],i))--t;
            Q[++t]=i;
        }
        for(Re i=mid+1,j,id;i<=R;++i){//把右边的点拿来决策(依旧是单调队列)
            while(h<t&&slope(Q[h],Q[h+1])<=a[i].k)++h;
            if(h<=t)id=a[i].id,j=Q[h],dp[id]=min(dp[id],a[j].y-(LL)a[i].k*a[j].x+S[id-1]+(LL)H[id]*H[id]);
        }
        CDQ(mid+1,R);//处理完右边后,两边都按照X(j)排好了序
        Re w=L-1;p1=L,p2=mid+1;//把两边按照X(j)从小到大归并起来
        while(p1<=mid&&p2<=R)b[++w]=a[p1]<a[p2]?a[p1++]:a[p2++];
        while(p1<=mid)b[++w]=a[p1++];while(p2<=R)b[++w]=a[p2++];
        for(Re i=L;i<=R;++i)a[i]=b[i];
    }
    int main(){
    	freopen("P4655.in","r",stdin);
    	freopen("P4655.out","w",stdout);
        in(n);
        for(Re i=1;i<=n;++i)in(H[i]);
        for(Re i=1;i<=n;++i)in(W[i]);
        for(Re i=1;i<=n;++i)S[i]=S[i-1]+W[i],dp[i]=inf;
        for(Re i=1;i<=n;++i)a[i].k=(H[i]<<1),a[i].x=H[i],a[i].id=i;
        sort(a+1,a+n+1,cmp);//先按k0[i]排序
        dp[1]=0,CDQ(1,n);//注意左边界上的点要单独求
        printf("%lld
    ",dp[n]);
    }
    
  • 相关阅读:
    9.11 eventbus
    9.10,,,实现new instanceof apply call 高阶函数,偏函数,柯里化
    9.9 promise实现 写完了传到gitee上面了,这里这个不完整
    9.5cors配置代码
    9.5 jsonp 实现
    9.5 http tcp https总结
    9.3 es6 class一部分 and es5 class 发布订阅
    8.30 cookie session token jwt
    8.30vue响应式原理
    warning: LF will be replaced by CRLF in renard-wx/project.config.json. The file will have its original line endings in your working directory
  • 原文地址:https://www.cnblogs.com/martian148/p/14062586.html
Copyright © 2011-2022 走看看