您的位置:首页 > 其它

1835: [ZJOI2010]base 基站选址

2016-08-26 22:46 405 查看

1835: [ZJOI2010]base 基站选址

Time Limit: 100 Sec  Memory Limit: 64 MB
Submit: 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 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。

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: