• BZOJ 1835: [ZJOI2010]base 基站选址 [序列DP 线段树]


    1835: [ZJOI2010]base 基站选址

    题目描述

    有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di。需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci。如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了。如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi。现在的问题是,选择基站的位置,使得总费用最小。 输入数据 (base.in) 输入文件的第一行包含两个整数N,K,含义如上所述。 第二行包含N-1个整数,分别表示D2,D3,…,DN ,这N-1个数是递增的。 第三行包含N个整数,表示C1,C2,…CN。 第四行包含N个整数,表示S1,S2,…,SN。 第五行包含N个整数,表示W1,W2,…,WN。

    输入输出格式

    输入格式:

    输入文件的第一行包含两个整数N,K,含义如上所述。

    第二行包含N-1个整数,分别表示D2,D3,…,DN ,这N-1个数是递增的。

    第三行包含N个整数,表示C1,C2,…CN。

    第四行包含N个整数,表示S1,S2,…,SN。

    第五行包含N个整数,表示W1,W2,…,WN。

    输出格式:

    输出文件中仅包含一个整数,表示最小的总费用。

    输入输出样例

    输入样例#1:
    3 2
    1 2
    2 3 2
    1 1 0
    10 20 30
    输出样例#1:
    4

    说明

    40%的数据中,N<=500;

    100%的数据中,K<=N,K<=100,N<=20,000,Di<=1000000000,Ci<=10000,Si<=1000000000,Wi<=10000。


    到洛谷偷了题面

    理解了题解之后还是比较好写的

    显然f[i][j]表示前i个村子建了j个基站且第i个村子建了基站

    f[i][j]=c[i]+min{f[k][j-1]+cost(k,j)}

    cost(k,j)表示k有一个基站,j有一个基站,k..j的补偿代价

    关键就是快速计算这个东西了

    线段树优化,就是用线段树区间min来logn获得转移来的状态中最小值吧

    j这一维显然可以滚掉

    想办法让线段树每个点表示了选这个点作为转移点时的代价

    先把f[][j-1]建树,然后处理cost的问题

    当i-->i+1时,发现左端点不变,右段点右移了,那么哪些刚好最远i位置可以覆盖到的点就可能要补偿了

    所以对于点x,通过二分计算st[x]和ed[x]为x最左和最右到哪,然后用链表记录ed[x]为某个值的点有哪些,

    对于ed[x]=i的点线段树[1,st[x]-1]区间加w[x],因为这些点右面不能被覆盖,左面再不能的话就要补偿了

    复杂度 k*n*logn,区间加n次,区间min也有n次

    注意:

    1.j==1的时候O(n)特判就行了

    2.n++ k++后 d[n]=w[n]=INF c[n]=0,f[n]就是最优解了

    //
    //  main.cpp
    //  bzoj1835
    //
    //  Created by Candy on 2017/1/8.
    //  Copyright © 2017年 Candy. All rights reserved.
    //
    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define lc o<<1
    #define rc o<<1|1
    #define m ((l+r)>>1)
    #define lson o<<1,l,m
    #define rson o<<1|1,m+1,r
    const int N=20005,INF=1e9+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,k,d[N],c[N],s[N],w[N];
    int st[N],ed[N],f[N];
    
    struct edge{
        int v,ne;
    }e[N];
    int h[N],cnt;
    inline void ins(int u,int v){
        cnt++;
        e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
    }
    
    struct node{
        int mn,tag;
    }t[N<<2];
    inline void merge(int o){t[o].mn=min(t[lc].mn,t[rc].mn);}
    inline void paint(int o,int d){
        t[o].tag+=d;
        t[o].mn+=d;
    }
    inline void pushDown(int o){
        if(t[o].tag){
            paint(lc,t[o].tag);
            paint(rc,t[o].tag);
            t[o].tag=0;
        }
    }
    void build(int o,int l,int r){
        t[o].tag=0;
        if(l==r) t[o].mn=f[l];
        else{
            build(lson);
            build(rson);
            merge(o);
        }
    }
    void segAdd(int o,int l,int r,int ql,int qr,int d){
        if(ql>qr) return;
        if(ql<=l&&r<=qr) paint(o,d);
        else{
            pushDown(o);
            if(ql<=m) segAdd(lson,ql,qr,d);
            if(m<qr) segAdd(rson,ql,qr,d);
            merge(o);
        }
    }
    int segQue(int o,int l,int r,int ql,int qr){
        if(ql>qr) return 0;
        if(ql<=l&&r<=qr) return t[o].mn;
        else{
            pushDown(o);
            int mn=INF;
            if(ql<=m) mn=min(mn,segQue(lson,ql,qr));
            if(m<qr) mn=min(mn,segQue(rson,ql,qr));
            return mn;
        }
    }
    
    void dp(){
        int ans=INF,_=0;
        for(int i=1;i<=n;i++){
            f[i]=_+c[i];
            for(int k=h[i];k;k=e[k].ne)
                _+=w[e[k].v];
            //printf("f j1 %d
    ",f[i]);
        }
        
        for(int j=2;j<=k;j++){
            build(1,1,n);
            for(int i=1;i<=n;i++){
                f[i]=segQue(1,1,n,1,i-1)+c[i];
                for(int k=h[i];k;k=e[k].ne){
                    int v=e[k].v;
                    segAdd(1,1,n,1,st[v]-1,w[v]);
                }
            }
            ans=min(ans,f[n]);
        }
        printf("%d",ans);
    }
    int main(int argc, const char * argv[]) {
        n=read();k=read();
        for(int i=2;i<=n;i++) d[i]=read();
        for(int i=1;i<=n;i++) c[i]=read();
        for(int i=1;i<=n;i++) s[i]=read();
        for(int i=1;i<=n;i++) w[i]=read();
        n++;k++;
        d[n]=INF;w[n]=INF;
        for(int i=1;i<=n;i++){
            st[i]=lower_bound(d+1,d+1+n,d[i]-s[i])-d;
            ed[i]=lower_bound(d+1,d+1+n,d[i]+s[i])-d;
            if(d[ed[i]]-d[i]>s[i]) ed[i]--;
            ins(ed[i],i);
            //printf("sted %d %d %d
    ",i,st[i],ed[i]);
        }
        dp();
        return 0;
    }
  • 相关阅读:
    d2admin框架学习
    手机访问本地配置域名下的项目
    laydate 限制结束日期不能大于起始日期
    学习MVC之租房网站(十一)-定时任务和云存储
    学习MVC之租房网站(十)-预约和跟单
    学习MVC之租房网站(九)-房源显示和搜索
    学习MVC之租房网站(八)- 前台注册和登录
    学习MVC之租房网站(七)-房源管理和配图上传
    《程序员修炼之道》笔记(九)
    《程序员修炼之道》笔记(八)
  • 原文地址:https://www.cnblogs.com/candy99/p/6263247.html
Copyright © 2020-2023  润新知