LuoguP2605 基站选址
0x01
设 \(f(i, j)\) 表示第 \(j\) 个基站建在第 \(i\) 个村庄的最小费用,则有
\[f(i, j) = C_i + \min_{1 \leqslant k < i}\{ f(k, j-1) + cost(k, i) \}
\]
其中 \(cost(l, r)\) 表示在 \(l,\ r\) 分别建立基站后补偿 \(l\) 到 \(r\) 所有未被覆盖的村庄的花费.
对每个位置 \(k\) 维护 \(f(k, j) + cost (k, i)\),设为 \(v_{k, j} \ (j > 0)\).
对 \(j = 0\),\(v_{k, j}\) 中的 \(k\) 是无意义的,因此我们只维护一个值 \(v_0\,\).
当枚举到新的 \(i\) 时:
- 计算 \(f(i, j) = C_i + \min\{ v_{k, j-1} \}\).
- 对 \(j > 0\),加入 \(v_{i, j} = f(i, j)\).
- 若存在 \(r_s = i\),对 \(j > 0\),将所有 \(k < l_s\) 的 \(v_{k, j}\) 及 \(v_0\) 增加 \(W_s\,\).
其中 \(l_i\) 和 \(r_i\) 分别表示能覆盖到 \(i\) 的最左和最右的基站,可预处理.
线段树维护,为节约空间,考虑最外层枚举 \(j\),滚动使用线段树.
0x02 Code
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0, f = 1; char c = getchar();
while(isdigit(c)^1) f &= c != 45, c = getchar();
while(isdigit(c)) x = (x<<1) + (x<<3) + (c^48), c = getchar();
return f ? x : -x;
}
const int maxn = 20005;
int d[maxn], c[maxn], s[maxn], w[maxn], l[maxn], r[maxn], f[maxn][105];
vector<int> vec[maxn];
struct SegT {
int tag[maxn<<2], minv[maxn<<2];
SegT() {
memset(minv, 0x3f, sizeof(minv));
}
inline void clear(){
memset(tag, 0, sizeof(tag));
memset(minv, 0x3f, sizeof(minv));
}
inline void pushUp(int p) {
minv[p] = min(minv[p<<1], minv[p<<1|1]);
}
inline void pushDown(int p) {
minv[p<<1] += tag[p], minv[p<<1|1] += tag[p];
tag[p<<1] += tag[p], tag[p<<1|1] += tag[p], tag[p] = 0;
}
void pModify(int p, int l, int r, int x, int k) {
if(l == r) {
minv[p] = k;
return;
}
pushDown(p);
int mid = l + r >> 1;
if(x <= mid) pModify(p<<1, l, mid, x, k);
else pModify(p<<1|1, mid+1, r, x, k);
pushUp(p);
}
void sModify(int p, int l, int r, int x, int y, int k) {
if(x <= l && r <= y) {
minv[p] += k, tag[p] += k;
return;
}
pushDown(p);
int mid = l + r >> 1;
if(x <= mid) sModify(p<<1, l, mid, x, y, k);
if(y > mid) sModify(p<<1|1, mid+1, r, x, y, k);
pushUp(p);
}
int query(int p, int l, int r, int x, int y) {
if(x <= l && r <= y) return minv[p];
pushDown(p);
int mid = l + r >> 1, res = 1e9;
if(x <= mid) res = min(res, query(p<<1, l, mid, x, y));
if(y > mid) res = min(res, query(p<<1|1, mid+1, r, x, y));
return res;
}
}sgt[2];
int main() {
int n = read(), m = read();
for(int i = 2; i <= n; ++i) d[i] = read();
for(int i = 1; i <= n; ++i) c[i] = read();
for(int i = 1; i <= n; ++i) s[i] = read();
for(int i = 1; i <= n; ++i) w[i] = read();
for(int i = 1; i <= n; ++i) {
l[i] = lower_bound(d+1, d+n+1, d[i] - s[i]) - d;
r[i] = upper_bound(d+1, d+n+1, d[i] + s[i]) - d - 1;
assert(l[i] >= 1), assert(r[i] <= n);
vec[r[i]].push_back(i);
}
int v0 = 0, ans = 0;
for(int i = 1; i <= n; ++i) ans += w[i];
for(int i = 1; i <= n; ++i) {
f[i][1] = c[i] + v0;
sgt[1].pModify(1, 1, n, i, f[i][1]);
for(int k : vec[i]) v0 += w[k];
}
for(int j = 2; j <= m; ++j) {
int now = j & 1, las = now ^ 1;
sgt[now].clear();
for(int i = j; i <= n; ++i) {
f[i][j] = c[i] + sgt[las].query(1, 1, n, 1, i-1);
sgt[now].pModify(1, 1, n, i, f[i][j]);
for(int k : vec[i])
if(l[k] > 1) sgt[las].sModify(1, 1, n, 1, l[k]-1, w[k]);
}
ans = min(ans, sgt[las].minv[1]);
}
for(int i = m; i <= n; ++i)
for(int k : vec[i])
if(l[k] > 1) sgt[m & 1].sModify(1, 1, n, 1, l[k]-1, w[k]);
ans = min(ans, sgt[m & 1].minv[1]);
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号