1835: [ZJOI2010]base 基站选址
2016-08-26 22:46
405 查看
1835: [ZJOI2010]base 基站选址
Time Limit: 100 Sec Memory Limit: 64 MBSubmit: 1188 Solved: 558
[Submit][Status][Discuss]
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 30Sample Input
4Sample Output
40%的数据中,N<=500;100%的数据中,K<=N,K<=100,N<=20,000,Di<=1000000000,Ci<=10000,Si<=1000000000,Wi<=10000。
HINT
Source
Day1[Submit][Status][Discuss]
强烈的dp即视感???
f[i][j]:最后一个基站建在第i个村庄,已经建了j个基站,不考虑i号村庄右端的村庄,最少代价
(为什么不考虑右边呢??转移方便啊。。。)
写出方程f[i][j] = min{f[k][j-1] + cost(k,i)} + c[i]
cost(i,j):在i号和j号建基站,求出区间(i,j)内未被覆盖的基站需要赔偿的总钱数
暴力转移时O(n^2k)的
难点在于如何求出cost函数???
把这个问题拆成两部分思考
区间(i,j)内的村庄何时需要赔偿???
显然,对于村庄k,它与i或者j其中一个距离不超过s[k]的时候他就不用被赔偿
换句话说,我们可以预处理出L[k]R[k],表示对于k,最左边L[k]最右边R[k]有基站时,他不用被赔偿
那么是否赔偿的关键就是取决于L[k]和R[k]了
假设我们从左往右慢慢推状态
对于f[i][j],不考虑i右边的村庄
随着i的右移,之前能够被i覆盖的村庄(R[k]>=i)可能就没办法被i+1覆盖,以及我们要考虑一些新进来的位置
对于第一种情况,总有一个i使得R[k]<i,我们维护一个堆,每次取堆顶看看,如果R[k]<i,那些转移会受影响?我们预处理了L数组,那么L[k]左边的所有状态转移时就都要加上w[k],区间加法??
线段树直接解决,既然用了线段树,区间查询也不是难事,转移就解决了!
第二种情况,,扔堆里呀
线段树开小WA了一发。。。。
#define priority_queue pq #include<iostream> #include<cstdio> #include<queue> #include<vector> #include<bitset> #include<algorithm> #include<cstring> #include<map> #include<stack> #include<set> #include<cmath> #include<ext/pb_ds/priority_queue.hpp> using namespace std; const int maxn = 2E4 + 10; const int T = 8; const int INF = ~0U>>1; struct data{ int posi,Num; data(){} data(int posi,int Num): posi(posi),Num(Num){} bool operator < (const data &b) const { return posi > b.posi; } }; typedef __gnu_pbds::pq<data,less<data>,__gnu_pbds::pairing_heap_tag> Heap; int n,k,dis[maxn],w[maxn],v[maxn],L[maxn],R[maxn], Add[maxn*T],Min[maxn*T],f[maxn][110],pay[maxn]; struct d2{ int posi,Num; d2(){} d2(int posi,int Num): posi(posi),Num(Num){} bool operator < (const d2 &b) const { return posi < b.posi; } }; typedef __gnu_pbds::pq<d2,less<d2>,__gnu_pbds::pairing_heap_tag> Heap2; void pushdown(int o) { if (!Add[o]) return; Min[o] += Add[o]; Add[o<<1] += Add[o]; Add[o<<1|1] += Add[o]; Add[o] = 0; } void maintain(int o) { pushdown(o<<1); pushdown(o<<1|1); Min[o] = min(Min[o<<1],Min[o<<1|1]); } void Insert(int o,int l,int r,int pos,int key) { pushdown(o); maintain(o); if (l == r) { Min[o] += key; return; } int mid = (l + r) >> 1; if (pos <= mid) Insert(o<<1,l,mid,pos,key); else Insert(o<<1|1,mid+1,r,pos,key); Min[o] = min(Min[o<<1],Min[o<<1|1]); } void Modify(int o,int l,int r,int ml,int mr,int key) { if (ml > mr) return; pushdown(o); if (ml <= l && r <= mr) { Add[o] += key; return; } int mid = (l + r) >> 1; if (ml <= mid) Modify(o<<1,l,mid,ml,mr,key); if (mr > mid) Modify(o<<1|1,mid+1,r,ml,mr,key); maintain(o); } int Query(int o,int l,int r,int ql,int qr) { if (ql > qr) return 0; pushdown(o); if (ql <= l && r <= qr) return Min[o]; int ret = ~0U>>1,mid = (l + r) >> 1; if (ql <= mid) ret = Query(o<<1,l,mid,ql,qr); if (qr > mid) ret = min(ret,Query(o<<1|1,mid+1,r,ql,qr)); return ret; } int getint() { char ch = getchar(); int ret = 0; while (ch < '0' || '9' < ch) ch = getchar(); while ('0' <= ch && ch <= '9') ret = ret*10 + ch - '0',ch = getchar(); return ret; } void Clear() { memset(Min,0,sizeof(Min)); memset(Add,0,sizeof(Add)); } int main() { #ifdef DMC freopen("DMC.txt","r",stdin); #endif n = getint(); k = getint(); int Ans = 0; for (int i = 2; i <= n; i++) dis[i] = getint(); for (int i = 1; i <= n; i++) v[i] = getint(); for (int i = 1; i <= n; i++) { int s = getint(); int tmp = dis[i] - s; int pos = lower_bound(dis + 1,dis + n + 1,tmp) - dis; L[i] = pos; tmp = dis[i] + s; pos = lower_bound(dis + 1,dis + n + 1,tmp) - dis; if (dis[pos] > tmp) --pos; R[i] = pos; } for (int i = 1; i <= n; i++) w[i] = getint(),Ans += w[i]; for (int j = 1; j <= k; j++) { Clear(); Heap Q; for (int i = 1; i <= n; i++) { if (i < j) { if (i == j - 1) Insert(1,0,n,i,f[i][j-1]); continue; } while (!Q.empty()) { data K = Q.top(); if (K.posi < i) { if (j == 1) Modify(1,0,n,0,n,w[K.Num]); else Modify(1,0,n,1,L[K.Num] - 1,w[K.Num]); Q.pop(); } else break; } f[i][j] = Query(1,0,n,j-1,i-1) + v[i]; Q.push(data(R[i],i)); Insert(1,0,n,i,f[i][j-1]); } } Heap2 Q; int tot = 0; for (int i = n; i; i--) { while (!Q.empty()) { d2 K = Q.top(); if (K.posi > i) { tot += w[K.Num]; Q.pop(); } else break; } pay[i] = tot; Q.push(d2(L[i],i)); } for (int i = 1; i <= n; i++) for (int j = 1; j <= k; j++) { if (j > i) continue; Ans = min(Ans,f[i][j] + pay[i]); } cout << Ans; return 0; }
相关文章推荐
- 【BZOJ1835】[ZJOI2010]base 基站选址 线段树+DP
- BZOJ1835 [ZJOI2010]base 基站选址
- bzoj 1835: [ZJOI2010]base 基站选址 线段树优化dp
- [BZOJ]1835: [ZJOI2010]base 基站选址 线段树+DP
- 1835: [ZJOI2010]base 基站选址
- BZOJ1835 [ZJOI2010]base 基站选址
- [BZOJ1835][ZJOI2010]base 基站选址
- bzoj 1835: [ZJOI2010]base 基站选址
- BZOJ 1835: [ZJOI2010]base 基站选址(DP,线段树)
- bzoj1835[ZJOI2010]base基站选址
- bzoj1835 [ZJOI2010]base 基站选址(dp+线段树优化)
- bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)
- BZOJ 1835: [ZJOI2010]base 基站选址 [序列DP 线段树]
- bzoj 1835: [ZJOI2010]base 基站选址
- bzoj 1835/luogu P2605 : [ZJOI2010]base 基站选址
- bzoj 1835: [ZJOI2010]base 基站选址(线段树优化dp)
- Bzoj1835:[ZJOI2010]基站选址
- Bzoj1835:[ZJOI2010]基站选址
- bzoj1835[ZJOI2010]基站选址
- [ZJOI 2010]base 基站选址