Description

题库链接

给出 \(n\) 个村庄的横坐标 \(D_i\) 。要求在这 \(n\) 个村庄内最多选择 \(m\) 个作为通讯基站,在村庄 \(i\) 建造通讯基站的代价为 \(C_i\) 。对于村庄 \(i\) ,如果其左右距离超过 \(S_i\) 都没有通讯基站,那么需要额外的 \(W_i\) 的代价。求最小代价。

\(1\leq n\leq 20000,1\leq m\leq 100\)

Solution

记 \(f_{i,j}\) 表示在第 \(i\) 个村庄修建第 \(j\) 个基站的最小费用。

可以处理出一个数组 \(cost_{k,i}\) 表示第 \(i\sim k\) 个村庄之间没有被基站 \(i,k\) 覆盖的村庄所需的额外费用。

那么转移方程 \(f_{i,j} = \min\limits_{k<i} f_{k,j-1}+cost_{k,i}+C_i\) 。转移复杂度为 \(O(n^2m)\) 。

考虑优化。

首先我们可以先把 \(j\) 给滚掉。其次我们注意到每次选择时都是在 \(k\in [1,i)\) 中取一个 \(f_k+cost_{k,i}\) 的最小值。可以用线段树优化查询最小值。

但剩下的就是如何处理 \(cost\) 的更新。

对于一个村庄 \(i\) ,可以二分处理出它所能被覆盖的左右边界为 \(l_i,r_i\),然后在用邻接表记录 \(r\) 值为 \(i\) 的村庄有哪些,在这些村庄之后建立基站就覆盖不到 \(i\) 了。

这样当我们从 \(i\) 推到 \(i + 1\) 时,对于所有 \(r_k=i\) 的村庄若从村庄 \(1\sim l_k-1\) 转移过来则必定要赔偿村庄 \(k\) 的费用,这样就可以用线段树区间加,即在区间 \([1,l_k)\) 加上村庄 \(k\) 的额外费用。

总复杂度为\(O(nmlog_2n)\) 。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 20000, inf = ~0u>>1; int n, m, d[N+5], c[N+5], s[N+5], w[N+5], l[N+5], r[N+5]; long long f[N+5];
vector<int>to[N+5];
struct Segment_tree {
#define lr(o) (o<<1)
#define rr(o) (o<<1|1)
long long sgm[(N<<2)+5], lazy[(N<<2)+5];
void build(int o, int l, int r) {
lazy[o] = 0; int mid = (l+r)>>1;
if (l == r) {sgm[o] = f[l]; return; }
build(lr(o), l, mid); build(rr(o), mid+1, r);
sgm[o] = min(sgm[lr(o)], sgm[rr(o)]);
}
void pushdown(int o) {
sgm[lr(o)] += lazy[o], lazy[lr(o)] += lazy[o];
sgm[rr(o)] += lazy[o], lazy[rr(o)] += lazy[o];
lazy[o] = 0;
}
void update(int o, int l, int r, int a, int b, long long k) {
if (a <= l && r <= b) {sgm[o] += k, lazy[o] += k; return; }
if (lazy[o]) pushdown(o); int mid = (l+r)>>1;
if (a <= mid) update(lr(o), l, mid, a, b, k);
if (b > mid) update(rr(o), mid+1, r, a, b, k);
sgm[o] = min(sgm[lr(o)], sgm[rr(o)]);
}
long long query(int o, int l, int r, int a, int b) {
if (a <= l && r <= b) return sgm[o];
if (lazy[o]) pushdown(o); int mid = (l+r)>>1;
long long c1 = inf, c2 = inf;
if (a <= mid) c1 = query(lr(o), l, mid, a, b);
if (b > mid) c2 = query(rr(o), mid+1, r, a, b);
return min(c1, c2);
}
}T; void work() {
scanf("%d%d", &n, &m);
for (int i = 2; i <= n; i++) scanf("%d", &d[i]);
for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
for (int i = 1; i <= n; i++) scanf("%d", &s[i]);
for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
++m; ++n; d[n] = w[n] = inf;
for (int i = 1; i <= n; i++) {
r[i] = lower_bound(d+1, d+n+1, d[i]+s[i])-d;
l[i] = lower_bound(d+1, d+n+1, d[i]-s[i])-d;
if (d[r[i]]-d[i] > s[i]) --r[i];
to[r[i]].push_back(i);
}
long long tol = 0;
for (int i = 1; i <= n; i++) {
f[i] = c[i]+tol;
for (int j = 0, sz = to[i].size(); j < sz; j++)
tol += w[to[i][j]];
}
long long ans = f[n];
for (int i = 2; i <= m; i++) {
T.build(1, 1, n);
for (int j = 1; j <= n; j++) {
f[j] = (j != 1 ? T.query(1, 1, n, 1, j-1) : 0)+c[j];
for (int k = 0, sz = to[j].size(); k < sz; k++)
if (l[to[j][k]] != 1) T.update(1, 1, n, 1, l[to[j][k]]-1, w[to[j][k]]);
}
ans = min(ans, f[n]);
}
printf("%lld\n", ans);
}
int main() {work(); return 0; }

[ZJOI 2010]base 基站选址的更多相关文章

  1. BZOJ 1835: [ZJOI2010]base 基站选址 [序列DP 线段树]

    1835: [ZJOI2010]base 基站选址 题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立 ...

  2. 【BZOJ1835】[ZJOI2010]base 基站选址 线段树+DP

    [BZOJ1835][ZJOI2010]base 基站选址 Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯 ...

  3. bzoj1835[ZJOI2010]base基站选址

    据说正解是什么线段树优化DP,但是作为脑子有坑选手,我们需要5k的做法: 主席树+决策单调性..... F[m][i]表示已经放置了m个基站,第m个基站放置在第i个村庄,第i个村庄及之前的村庄的总最少 ...

  4. bzoj 1835: [ZJOI2010]base 基站选址

    Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...

  5. BZOJ1835: [ZJOI2010]base 基站选址【线段树优化DP】

    Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...

  6. BZOJ1835: [ZJOI2010]base 基站选址(线段树优化Dp)

    Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...

  7. bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1835 [题意] 有n个村庄,每个村庄位于d[i],要求建立不多于k个基站,在第i个村庄 ...

  8. bzoj 1835 base 基站选址 - 动态规划 - 线段树

    题目传送门 需要高级权限的传送门 题目大意 有$n$个村庄坐落在一条直线上,第$i \ \ \ (i>1)$个村庄距离第$1$个村庄的距离为$D_i$.需要在这些村庄中建立不超过$K$个通讯基站 ...

  9. BZOJ 1835 [ZJOI2010]base 基站选址:线段树优化dp

    传送门 题意 有 $ n $ 个村庄在一排直线上,现在要建造不超过 $ K $ 个通讯基站,基站只能造在村庄处. 第 $ i $ 个村庄距离第 $ 1 $ 个村庄的距离为 $ D_i $ .在此建造基 ...

随机推荐

  1. 第 8 章 IO库

    第 8 章 IO库 标签: C++Primer 学习记录 IO库 第 8 章 IO库 8.1 IO类 8.2 文件输入输出 8.1 string流 8.1 IO类 IO对象无拷贝或赋值,因此不能将形参 ...

  2. 分区表SQL调优/优化(Tuning)时容易“被欺骗”的场景之一

    近几天没有用户找到,除了看看书,就是上网浏览点东西,好不惬意.可惜好景不长,正在享受悠闲惬意的日子时,一个用户的工作人员QQ找到我,说他们在统计一些数据,但一个SQL特别慢,或者说就从来没出过数据,我 ...

  3. Java之排序

    1.插入排序 假设第一个数已经是排好序的,把第二个根据大小关系插到第一个前面或维持不动,把第三个根据前面两个的大小关系插到对应位置,依次往后. public class InsertSort { pu ...

  4. 关于Mac OS 使用GIT的引导

    1. 下载Git installer 链接地址:https://ncu.dl.sourceforge.net/project/git-osx-installer/git-2.14.1-intel-un ...

  5. 2018C程序设计—第0次作业

    1.翻阅邹欣老师博客关于师生关系博客,并回答下列问题,每个问题的答案不少于500字 1)最理想的师生关系是健身教练和学员的关系,在这种师生关系中你期望获得来自老师的哪些帮助? 答:正如邹欣老师博客里所 ...

  6. 在django模板中添加jquery

    路径 /project_name /app_name /templates /index.html /project_name setting.py /static /js jquery.js 导入方 ...

  7. 大神都在看的RxSwift 的完全入坑手册

    大神都在看的RxSwift 的完全入坑手册 2015-09-24 18:25 CallMeWhy callmewhy 字号:T | T 我主要是通过项目里的 Rx.playground 进行学习和了解 ...

  8. 纯CSS垂直居中的四种解决方案

    总结了几种解决方法 但也不是说除了我说的就没有其他方法了 第一个.利用flex布局 代码: 效果: 第二个.利用transform 的 translate属性 代码: 效果: 第三个.使用伪类::af ...

  9. ORA-00379 缓冲池 DEFAULT 中无法提供 32K 块大小的空闲缓冲区

    (一)问题 今天在使用Pl/sql developer查看表空间大小的时候,报错误:ORA-00379 缓冲池 DEFAULT 中无法提供 32K 块大小的空闲缓冲区,具体如下图: SQL> s ...

  10. 第二章 初识JSP

    第二章   初识JSP 一.JSP简述 1.是JSP JSP是指在HTML中嵌入Java脚本语言.全称(Java Server Pages) 当用户通过浏览器访问Web应用时,使用JSP容器对请求的J ...