• P2605 [ZJOI2010]基站选址


    题目

    P2605 [ZJOI2010]基站选址

    简化题目:1~n个村庄,每个村庄有范围,要求范围内有村庄被选(不超过(k)个),否则被罚款,选村庄有一定花费,求最小总花费

    做法

    朴素
    (dp_{i,j})(j)个被选的村庄为(i)的最小花费:(dp_{i,k}=min{dp_{j,k-1}+cost_{i,j}}+w_i)

    枚举(k)(准备选第(k)个),(i)(具体选(i)),(j)(上一个被选的),显然(cost_{i,j})预处理(O(n^2)),枚举方程(O(n^2k))

    时间复杂度度估为(O(n^2k))

    优化
    习惯地,只出现(k)(k-1),倒序枚举(j)(dp_{i}=min{dp_{j}+cost_{i,j}}+w_i),还只是优化了点空间而已

    最外层(k)其实差不多可以不管了((k<=100)),主要是优化刚才的这个方程

    无后效性,顺序也显然((j<i)),考虑这部分(min{dp_{j}+cost_{i,j}}),最值有关的((BIT)/线段树,单调队列,斜率优化......)

    有哪些相同的部分可以利用呢?

    假设这次是选(x),上一次选(i),那(i)前面的我们暂时不管,因为之前已经计算过了,我们只用考虑(i)~(k)中间的赔款

    对于上一次选的位置(i)(j),如果(i<j),上一个选(i)的赔款肯定包括了(longrightarrow)上一个选(j)的赔款

    理解:(i)~(x)(j)~(x)中间的空区比较多

    已经接近了我们的最终思路,假设我们这次在做第(k)个选(i),设以(i)为右端点的村庄为(x),其左端点为(L),那我们

    (1)~(L-1)都加上(pay_{x})村庄(x)的赔款:选(1)~(L-1)的村庄就不符合(x)

    诶!!区间查询最小值及位置,区间修改好像线段树做会比较简单

    至此,我们已经得到了最终解法:最外层枚举(k)(选第k个),第二层枚举选(i)(选第i个村庄),然后线段树维护选每个点的赔款及区间最小值

    My complete code

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef int LL;
    const LL maxn=20000+9,inf=0x3f3f3f3f;
    inline LL Read(){
        LL x(0),f(1); char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-') f=-1;c=getchar();
        }
        while(c>='0'&&c<='9')
            x=(x<<3)+(x<<1)+c-'0',c=getchar();
        return x*f;
    }
    struct node{
        LL mn,mni,lazy;
        LL son[2];
    }T[maxn<<2];
    LL n,ans,nod,K,root;
    LL d[maxn],s[maxn],bad[maxn],pay[maxn],dp[maxn],st[maxn],ed[maxn];
    vector<LL> belong[maxn];
    inline void Update(LL now,LL s1,LL s2){
        if(T[s1].mn<T[s2].mn)
            T[now].mn=T[s1].mn,
            T[now].mni=T[s1].mni;
        else
            T[now].mn=T[s2].mn,
            T[now].mni=T[s2].mni;
    }
    void Build(LL &now,LL l,LL r){
        if(!now)
            now=++nod;
        T[now].mn=T[now].mni=T[now].lazy=0;
        if(l==r){
            T[now].mn=dp[l],
            T[now].mni=l;
            return;
        }
        LL mid(l+r>>1);
        Build(T[now].son[0],l,mid),
        Build(T[now].son[1],mid+1,r);
        Update(now,T[now].son[0],T[now].son[1]);
    }
    inline void Pushdown(LL now,LL s1,LL s2){
        LL val(T[now].lazy);
        T[now].lazy=0;
        if(!val)
            return;
        T[s1].lazy+=val,T[s2].lazy+=val,
        T[s1].mn+=val,T[s2].mn+=val;
    }
    LL Query(LL now,LL l,LL r,LL lt,LL rt){
        if(lt>rt)
            return inf;
        if(lt<=l&&rt>=r)
            return T[now].mn;
        Pushdown(now,T[now].son[0],T[now].son[1]);
        LL mid(l+r>>1),ret=inf;
        if(lt<=mid)
            ret=min(ret,Query(T[now].son[0],l,mid,lt,rt));
        if(rt>mid)
            ret=min(ret,Query(T[now].son[1],mid+1,r,lt,rt));
        return ret;
    }
    inline void Change(LL now,LL l,LL r,LL lt,LL rt,LL val){
        if(lt>rt)
            return;
        if(lt<=l&&rt>=r){
            T[now].mn+=val,
            T[now].lazy+=val;
            return;
        }
        Pushdown(now,T[now].son[0],T[now].son[1]);
        LL mid(l+r>>1);
        if(lt<=mid)
            Change(T[now].son[0],l,mid,lt,rt,val);
        if(rt>mid)
            Change(T[now].son[1],mid+1,r,lt,rt,val);
        Update(now,T[now].son[0],T[now].son[1]);
    }
    int main(){
        n=Read(),K=Read();
        for(LL i=2;i<=n;++i)
            d[i]=Read();
        for(LL i=1;i<=n;++i)
            pay[i]=Read();
        for(LL i=1;i<=n;++i)
            s[i]=Read();
        for(LL i=1;i<=n;++i)
            bad[i]=Read();
        d[++n]=inf;
        for(LL 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];
            belong[ed[i]].push_back(i);
        }
        LL sum(0);
        for(LL i=1;i<=n;++i){
            dp[i]=sum+pay[i];
            for(LL j=0,size=belong[i].size();j<size;++j)
                sum+=bad[belong[i][j]];
        }
        ans=dp[n];
        ++K;
        for(LL k=2;k<=K;++k){
            Build(root,1,n);
            for(LL i=1;i<=n;++i){
                dp[i]=Query(root,1,n,1,i-1)+pay[i];
                for(LL j=0,size=belong[i].size();j<size;++j){
                    LL x(belong[i][j]);
                    Change(root,1,n,1,st[x]-1,bad[x]);
                }
            }
            ans=min(ans,dp[n]);
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    JVM调优-Java中的对象
    Spring MVC如何接收浏览器传递来的请求参数--request--形参--实体类封装
    Navicat for MySQL 64位破解版
    Idea详细配置
    数据库--悲观锁【收藏,待尝试】
    性能问题分析
    java 反射机制之 getDeclaredMethod()获取方法,然后invoke执行实例对应的方法
    Mysql show indexes 查看索引状态
    基于(Redis | Memcache)实现分布式互斥锁
    彻底解决每次打开visio都提示windows正在配置visio的问题
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10274063.html
Copyright © 2020-2023  润新知