有 N 个村庄坐落在一条直线上,第 i(i>1) 个村庄距离第 1 个村庄的距离为 ,需要在这些村庄中建立不超过 K 个通讯基站,在第 i 个村庄建立基站的费用为
。如果在距离第 i 个村庄不超过
的范围内建立了一个通讯基站,那么就村庄被基站覆盖了。
如果第 i 个村庄没有被覆盖,则需要向他们补偿,费用为 i。现在的问题是,选择基站的位置,使得总费用最小。
#include <cstdio>
#include <algorithm>
#include <vector>
typedef long long LL;
const int N = 20010;
const LL INF = 0x3f3f3f3f3f3f3f3f;
LL d[N], s[N], f[N][210], c[N], w[N];
int n, first[N], last[N], Time;
std::vector<int> v[N];
LL small[N << 2], tag[N << 2];
inline void pushup(int o) {
small[o] = std::min(small[o << 1], small[o << 1 | 1]);
return;
}
inline void pushdown(int o) {
if(tag[o]) {
int ls = o << 1;
int rs = ls | 1;
tag[ls] += tag[o];
tag[rs] += tag[o];
small[ls] += tag[o];
small[rs] += tag[o];
tag[o] = 0;
}
return;
}
void add(int L, int R, LL v, int l, int r, int o) {
if(L <= l && r <= R) {
tag[o] += v;
small[o] += v;
return;
}
int mid = (l + r) >> 1;
pushdown(o);
if(L <= mid) {
add(L, R, v, l, mid, o << 1);
}
if(mid < R) {
add(L, R, v, mid + 1, r, o << 1 | 1);
}
pushup(o);
return;
}
LL ask(int L, int R, int l, int r, int o) {
if(L <= l && r <= R) {
return small[o];
}
int mid = (l + r) >> 1;
pushdown(o);
LL ans = INF;
if(L <= mid) {
ans = std::min(ans, ask(L, R, l, mid, o << 1));
}
if(mid < R) {
ans = std::min(ans, ask(L, R, mid + 1, r, o << 1 | 1));
}
return ans;
}
void clear(int l, int r, int o) {
tag[o] = 0;
if(l == r) {
small[o] = f[r - 1][Time - 1];
return;
}
int mid = (l + r) >> 1;
clear(l, mid, o << 1);
clear(mid + 1, r, o << 1 | 1);
pushup(o);
return;
}
int main() {
int k;
LL ans = 0;
scanf("%d%d", &n, &k);
for(int i = 2; i <= n; i++) {
scanf("%lld", &d[i]);
}
for(int i = 1; i <= n; i++) {
scanf("%lld", &c[i]);
}
for(int i = 1; i <= n; i++) {
scanf("%lld", &s[i]);
}
for(int i = 1; i <= n; i++) {
scanf("%lld", &w[i]);
ans += w[i];
f[i][0] = f[i - 1][0] + w[i];
}
for(int i = 1; i <= n; i++) { // prework
int l = 1, r = i;
while(l < r) {
int mid = (l + r) >> 1;
if(d[mid] >= d[i] - s[i]) {
r = mid;
}
else {
l = mid + 1;
}
}
first[i] = r;
l = i;
r = n;
while(l < r) {
int mid = (l + r + 1) >> 1;
if(d[mid] <= d[i] + s[i]) {
l = mid;
}
else {
r = mid - 1;
}
}
last[i] = r;
v[r].push_back(i);
}
for(int i = 1; i <= n + 1; i++) {
f[i][0] = INF;
}
for(int j = 1; j <= k + 1; j++) {
Time = j;
clear(1, n + 1, 1);
for(int i = 0; i <= n + 1; i++) {
// ask f[i][j]
if(i >= j) {
f[i][j] = ask(1, i, 1, n + 1, 1) + c[i];
}
else {
f[i][j] = INF;
}
// insert
for(int p = 0; p < v[i].size(); p++) {
add(1, first[v[i][p]], w[v[i][p]], 1, n + 1, 1);
}
}
if(j > 1) {
ans = std::min(ans, f[n + 1][j]);
}
}
printf("%lld", ans);
return 0;
}