zoukankan      html  css  js  c++  java
  • 基站选址(base.c/cpp/pas)

    基站选址(base.c/cpp/pas)

    题目描述 

     

           有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di。需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci。如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了。如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi。现在的问题是,选择基站的位置,使得总费用最小。

     

     

    输入

     

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

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

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

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

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

     

     

    输出

     

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

     

     

    样例输入

    
    1 2
    2 3 2
    1 1 0
    10 20 30

    样例输出

    4

    提示

     

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

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

     solution

    先列出DP式

    f[i][j]表示当前建到i(i必建),已经建了j个的最小代价

    f[i][j]=f[k][j-1]+cost(k+1,i-1)+c[i];

    效率O(n^3)

    因为j只和j-1有关,我们可以先枚举j,对于每一个j,考虑优化cost(k+1,i-1):

    令l[i]为最左的能覆盖i的基站的位置,r[i]同理

    用线段树存1~i-1  f[k][j-1]+cost(k+1,i-1 ) 的值

    处理完i,将要加入i+1时对于r[x]=i的点显然无法被从右边覆盖,那么将1~l[x]-1加上w[x],

    也就是如果f[i+1]由f[k]转移来,且k<l[x],那么x就不会被覆盖了,cost要加上w[x].

    线段树维护区间加,单点查

    效率O(nlogn)

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<map>
    #include<queue>
    #define maxn 200005
    #define inf 900000000
    using namespace std;
    int n,k,dp[maxn],d[maxn],c[maxn],s[maxn],w[maxn],lm[maxn],rm[maxn];
    int x,tot,head[maxn];
    struct node{
        int nex,v;
    }e[maxn*2];
    struct no
    {
        int l,r,x,bj;
    }tree[maxn*4];
    void lj(int t1,int t2)
    {
        e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
    }
    void get(int k)
    {
        int l=1,r=k;
        x=d[k];
        while(l<r)
        {
            int mid=(l+r)/2;
            if(x-d[mid]<=s[k])r=mid;
            else l=mid+1;
        }
        lm[k]=l;
        l=k,r=n;
        while(l<r)
        {
            int mid=(l+r+1)/2;
            if(d[mid]-x<=s[k])l=mid;
            else r=mid-1;
        }
        rm[k]=l;
        lj(l,k);
    }
    void wh(int k)
    {
        tree[k].x=min(tree[k*2].x,tree[k*2+1].x);
    }
    void build(int k,int L,int R)
    {
        tree[k].l=L,tree[k].r=R;tree[k].bj=0;
        if(L==R){
            tree[k].x=dp[L];
            return;
        }
        int mid=(L+R)/2;
        build(k*2,L,mid);build(k*2+1,mid+1,R);
        wh(k);
    }
    void down(int k)
    {
        if(tree[k].bj>0)
        {
            tree[k*2].bj+=tree[k].bj;tree[k*2+1].bj+=tree[k].bj;
            tree[k*2].x+=tree[k].bj;tree[k*2+1].x+=tree[k].bj;
            tree[k].bj=0;
        }
    }
    int ask(int k,int L,int R)
    {
        if(L>R)return 0;
        down(k);
        if(tree[k].l>=L&&tree[k].r<=R)
        {
            return tree[k].x;
        }
        int mid=(tree[k].l+tree[k].r)/2;
        int u=inf;
        if(L<=mid)u=min(u,ask(k*2,L,R));
        if(R>mid)u=min(u,ask(k*2+1,L,R));
        return u;
    }
    void lian(int k,int L,int R,int v)
    {
        if(L>R)return;
        down(k);
        if(tree[k].l>=L&&tree[k].r<=R)
        {
              
            tree[k].bj+=v;
            tree[k].x+=v;
            return;
        }
        int mid=(tree[k].l+tree[k].r)/2;
        if(L<=mid)lian(k*2,L,R,v);
        if(R>mid)lian(k*2+1,L,R,v);
        wh(k);
    }
    int ss()
    {
        char ch;int v=0;
        while(!isdigit(ch=getchar()));v=v+ch-'0';
        while(isdigit(ch=getchar()))v=(v<<1)+(v<<3)+ch-'0';
        return v;
    }
    int main()
    {
        n=ss();k=ss();
        for(int i=2;i<=n;i++)d[i]=ss();
        for(int i=1;i<=n;i++)c[i]=ss();
        for(int i=1;i<=n;i++)s[i]=ss();
        for(int i=1;i<=n;i++)w[i]=ss();
        n++;d[n]=inf;
        for(int i=1;i<=n;i++)get(i);
          
        int tmp=0;
        for(int i=1;i<=n;i++){
            dp[i]=tmp+c[i];
            int p=head[i];
            while(p!=0)
            {
                tmp+=w[e[p].v];
                p=e[p].nex;
            }
        }
        int ans=dp[n];
        for(int i=2;i<=k+1;i++)
        {
            build(1,1,n);
            for(int j=1;j<=n;j++){
                  
                dp[j]=ask(1,1,j-1)+c[j];
                int p=head[j];
                while(p!=0){
                    lian(1,1,lm[e[p].v]-1,w[e[p].v]);
                    p=e[p].nex;
                }
            }
            ans=min(ans,dp[n]);
        }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    超出宽度...显示
    javascript 浏览器兼容 统计输入字数
    javascript常用工具类
    全局inline-block
    如何设计一套通用消息交互系统
    浅谈.NETfarmwork
    windows 安装gitlab
    阿里云ACP 云计算专业考试分享 2021最新
    Linux将一般用户加入sudo组
    RabbitMQ基础学习
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358887.html
Copyright © 2011-2022 走看看