[ZJOI2010]基站选址
题目描述
有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。
输出格式:输出文件中仅包含一个整数,表示最小的总费用。
输入输出样例
说明
40%的数据中,N<=500;
100%的数据中,K<=N,K<=100,N<=20,000,Di<=1000000000,Ci<=10000,Si<=1000000000,Wi<=10000。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long lol; struct Node { int next,to; } edge[20005]; int head[20005],num; lol Min[81005],f[20005]; lol lazy[81005]; int n,k,d[20005],c[20005],l[20005],w[20005]; int st[20005],ed[20005],inf=1e15; lol ans,now; void add(int u,int v) { num++; edge[num].next=head[u]; head[u]=num; edge[num].to=v; } void build(int rt,int l,int r) { lazy[rt]=0; if (l==r) { Min[rt]=f[l]; return; } int mid=(l+r)/2; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); Min[rt]=min(Min[rt<<1],Min[rt<<1|1]); } void pushdown(int rt) { if (lazy[rt]) { lazy[rt<<1]+=lazy[rt]; lazy[rt<<1|1]+=lazy[rt]; Min[rt<<1]+=lazy[rt]; Min[rt<<1|1]+=lazy[rt]; lazy[rt]=0; } } void update(int rt,int l,int r,int L,int R,lol d) { if (l>=L&&r<=R) { Min[rt]+=d; lazy[rt]+=d; return; } int mid=(l+r)/2; pushdown(rt); if (L<=mid) update(rt<<1,l,mid,L,R,d); if (R>mid) update(rt<<1|1,mid+1,r,L,R,d); Min[rt]=min(Min[rt<<1],Min[rt<<1|1]); } lol query(int rt,int l,int r,int L,int R) { if (l>=L&&r<=R) { return Min[rt]; } int mid=(l+r)/2; lol s=2e15; pushdown(rt); if (L<=mid) s=min(s,query(rt<<1,l,mid,L,R)); if (R>mid) s=min(s,query(rt<<1|1,mid+1,r,L,R)); Min[rt]=min(Min[rt<<1],Min[rt<<1|1]); return s; } int main() { int i,j,p; cin>>n>>k; for (i=2; i<=n; i++) scanf("%d",&d[i]); for (i=1; i<=n; i++) scanf("%d",&c[i]); for (i=1; i<=n; i++) scanf("%d",&l[i]); for (i=1; i<=n; i++) scanf("%d",&w[i]); ++n; ++k; w[n]=inf; d[n]=inf; for (i=1; i<=n; i++) { st[i]=lower_bound(d+1,d+n+1,d[i]-l[i])-d; ed[i]=lower_bound(d+1,d+n+1,d[i]+l[i])-d; if (d[ed[i]]>d[i]+l[i]) ed[i]--; add(ed[i],i); } ans=2e15; for (i=1; i<=n; i++) { f[i]=now+c[i]; for (j=head[i]; j; j=edge[j].next) { int v=edge[j].to; now+=w[v]; } } ans=min(ans,f[n]); for (i=2; i<=k; i++) { build(1,1,n); for (j=1; j<=n; j++) { if (j>1) f[j]=query(1,1,n,1,j-1)+c[j]; else f[j]=c[j]; for (p=head[j]; p; p=edge[p].next) { int v=edge[p].to; if (st[v]>1) update(1,1,n,1,st[v]-1,w[v]); } } ans=min(ans,f[n]); } cout<<ans; }