zoukankan      html  css  js  c++  java
  • bzoj1835 [ZJOI2010] 基站选址

    Description

    有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。

    Input

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

    Output

    3 2 1 2 2 3 2 1 1 0 10 20 30

    Sample Input

    4

    Sample Output

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

    正解:$dp$+线段树优化。

    设$f[p][i]$表示用$p$个基站,且第$p$个基站在$i$的最小费用,则$f[p][i]=min(f[p-1][j]+cost[j+1][i])$。考虑如何求出$cost[j+1][i]$。

    对于每一个村庄,求出它能覆盖的左界和右界,并把村庄按照右界排序。我们递推到$f[p][i]$的时候,发现右端点小于$i$的村庄都是$i$基站不能覆盖的,那么我们在线段树$[1,l-1]$中加入这些点的$w[i]$。

    同时我们把所有的$f[p-1][j]$都加入线段树中,那么求$f[p][i]$就直接在线段树中查询区间最小值就行了。最后我们再把$i$以后不能被覆盖的村庄加入答案中就行了。

      1 //It is made by wfj_2048~
      2 #include <algorithm>
      3 #include <iostream>
      4 #include <complex>
      5 #include <cstring>
      6 #include <cstdlib>
      7 #include <cstdio>
      8 #include <vector>
      9 #include <cmath>
     10 #include <queue>
     11 #include <stack>
     12 #include <map>
     13 #include <set>
     14 #define inf (1LL<<60)
     15 #define N (100010)
     16 #define ls (x<<1)
     17 #define rs (x<<1|1)
     18 #define il inline
     19 #define RG register
     20 #define ll long long
     21 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
     22 
     23 using namespace std;
     24 
     25 struct data{ ll i,l,r; }a[N],b[N];
     26 
     27 ll f[110][20010],lazy[4*N],sum[4*N],d[N],c[N],s[N],w[N],n,k,ans;
     28 
     29 il ll gi(){
     30     RG ll x=0,q=1; RG char ch=getchar();
     31     while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
     32     if (ch=='-') q=-1,ch=getchar();
     33     while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
     34     return q*x;
     35 }
     36 
     37 il ll cmpr(const data &a,const data &b){ return a.r<b.r; }
     38 
     39 il ll findl(RG ll i){
     40     RG ll l=1,r=i,mid,ans;
     41     while (l<=r){
     42     mid=(l+r)>>1;
     43     if (d[i]-d[mid]<=s[i]) ans=mid,r=mid-1;
     44     else l=mid+1;
     45     }
     46     return ans;
     47 }
     48 
     49 il ll findr(RG ll i){
     50     RG ll l=i,r=n,mid,ans;
     51     while (l<=r){
     52     mid=(l+r)>>1;
     53     if (d[mid]-d[i]<=s[i]) ans=mid,l=mid+1;
     54     else r=mid-1;
     55     }
     56     return ans;
     57 }
     58 
     59 il void pushdown(RG ll x){
     60     sum[ls]+=lazy[x],sum[rs]+=lazy[x];
     61     lazy[ls]+=lazy[x],lazy[rs]+=lazy[x],lazy[x]=0; return;
     62 }
     63 
     64 il void build(RG ll x,RG ll l,RG ll r){
     65     lazy[x]=0; if (l==r){ sum[x]=0; return; }
     66     RG ll mid=(l+r)>>1;
     67     build(ls,l,mid),build(rs,mid+1,r);
     68     sum[x]=min(sum[ls],sum[rs]); return;
     69 }
     70 
     71 il void update(RG ll x,RG ll l,RG ll r,RG ll xl,RG ll xr,RG ll v){
     72     if (xl<=l && r<=xr){ sum[x]+=v,lazy[x]+=v; return; }
     73     if (lazy[x]) pushdown(x); RG ll mid=(l+r)>>1;
     74     if (xr<=mid) update(ls,l,mid,xl,xr,v);
     75     else if (xl>mid) update(rs,mid+1,r,xl,xr,v);
     76     else update(ls,l,mid,xl,mid,v),update(rs,mid+1,r,mid+1,xr,v);
     77     sum[x]=min(sum[ls],sum[rs]); return;
     78 }
     79 
     80 il ll query(RG ll x,RG ll l,RG ll r,RG ll xl,RG ll xr){
     81     if (xl<=l && r<=xr) return sum[x];
     82     if (lazy[x]) pushdown(x); RG ll mid=(l+r)>>1;
     83     if (xr<=mid) return query(ls,l,mid,xl,xr);
     84     else if (xl>mid) return query(rs,mid+1,r,xl,xr);
     85     else return min(query(ls,l,mid,xl,mid),query(rs,mid+1,r,mid+1,xr));
     86 }
     87 
     88 il void work(){
     89     n=gi(),k=gi();
     90     for (RG ll i=2;i<=n;++i) d[i]=gi();
     91     for (RG ll i=1;i<=n;++i) c[i]=gi();
     92     for (RG ll i=1;i<=n;++i) s[i]=gi();
     93     for (RG ll i=1;i<=n;++i) w[i]=gi();
     94     for (RG ll i=1;i<=n;++i){
     95     a[i].i=i,a[i].l=findl(i),a[i].r=findr(i);
     96     b[i].i=i,b[i].l=a[i].l,b[i].r=a[i].r;
     97     }
     98     sort(a+1,a+n+1,cmpr);
     99     for (RG ll i=1;i<=n;++i){
    100     f[1][i]=c[i]+query(1,1,n,i,i);
    101     if (b[i].r<n) update(1,1,n,b[i].r+1,n,w[i]);
    102     }
    103     for (RG ll p=2,top;p<=k;++p){
    104     top=1,build(1,1,n);
    105     for (RG ll i=p-1;i<=n;++i) update(1,1,n,i,i,f[p-1][i]);
    106     for (RG ll i=p;i<=n;++i){
    107         for (;top<=n && a[top].r<i;++top)
    108         if (a[top].l>1) update(1,1,n,1,a[top].l-1,w[a[top].i]);
    109         f[p][i]=c[i]+query(1,1,n,p-1,i-1);
    110     }
    111     }
    112     ans=inf;
    113     for (RG ll p=k;p;--p){
    114     build(1,1,n);
    115     for (RG ll i=n;i>=p;--i){
    116         f[p][i]+=query(1,1,n,i,i),ans=min(ans,f[p][i]);
    117         if (b[i].l>1) update(1,1,n,1,b[i].l-1,w[i]);
    118     }
    119     }
    120     printf("%lld
    ",ans); return;
    121 }
    122 
    123 int main(){
    124     File("base");
    125     work();
    126     return 0;
    127 }
  • 相关阅读:
    面向对象基本原则
    策略模式
    简单工厂模式
    高内聚、低耦合
    UML在代码中的展现
    使用commons-csv简单读写CSV文件
    java反射机制
    SrpingDruid数据源加密数据库密码
    markdown学习经验
    Vue.js学习笔记
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7147791.html
Copyright © 2011-2022 走看看