【LG2605】[ZJOI2010]基站选址
【LG2605】[ZJOI2010]基站选址
题面
题解
先考虑一下暴力怎么写,设\(f_{i,j}\)表示当前\(dp\)到\(i\),且强制选\(i\),目前共放置\(j\)个的方案数。
那么转移为\(f_{i,j}=\min_{k=1}^{i-1} \{f_{k,j-1}+cost_{k,i}\}+c_i\),其中\(cost_{l,r}\)表示\([l,r]\)只选两端中间的补偿。
其中\(cost\)只需要\(O(\frac {n^3}4)\)预处理就好了,那么复杂度为\(O(\frac {n^3}4+kn^2)\)。
考虑优化这个暴力,此时我们只需要对于\(f_{i,j}\)找到满足条件的最小的\(k\)即可。
而对于一个位置\(i\),它要贡献\(w_i\)当且仅当一段区间内没有建基站,这个可以二分出来。
我们对这些按右端点区间排个序,那么可以知道过了某个位置\(i\),对于右端点在\(i\)的所有区间的左端点\(l\),区间\([1,l-1]\)内的\(f\)转移的花费必然会增加,那么用线段树维护区间取\(\min\)及区间加法即可。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <climits>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (ch != '-' && (ch > '9' || ch < '0')) ch = getchar();
if (ch == '-') w = -1 , ch = getchar();
while (ch >= '0' && ch <= '9') data = (data << 1) + (data << 3) + (ch ^ 48), ch = getchar();
return w * data;
}
#define MAX_N 20005
int N, K;
int D[MAX_N], C[MAX_N], S[MAX_N], W[MAX_N];
int dp[MAX_N];
struct Line {
int l, r;
bool operator < (const Line & rhs) const {
return r < rhs.r;
}
} p[MAX_N];
vector<int> vec[MAX_N];
#define lson (o << 1)
#define rson (o << 1 | 1)
int addv[MAX_N << 2], minv[MAX_N << 2];
void pushup(int o) { minv[o] = min(minv[lson], minv[rson]); }
void puttag(int o, int w) { minv[o] += w, addv[o] += w; }
void pushdown(int o) {
puttag(lson, addv[o]);
puttag(rson, addv[o]);
addv[o] = 0;
}
void build(int o, int l, int r) {
addv[o] = 0;
if (l == r) {
minv[o] = dp[l];
return ;
}
int mid = (l + r) >> 1;
build(lson, l, mid);
build(rson, mid + 1, r);
pushup(o);
}
void modify(int o, int l, int r, int ql, int qr, int w) {
if (ql > qr) return ;
if (ql <= l && r <= qr) {
puttag(o, w);
return ;
}
pushdown(o);
int mid = (l + r) >> 1;
if (ql <= mid) modify(lson, l, mid, ql, qr, w);
if (qr > mid) modify(rson, mid + 1, r, ql, qr, w);
pushup(o);
}
int query(int o, int l, int r, int ql, int qr) {
if (ql > qr) return 0;
if (ql <= l && r <= qr) return minv[o];
pushdown(o);
int mid = (l + r) >> 1, res = INT_MAX;
if (ql <= mid) res = min(res, query(lson, l, mid, ql, qr));
if (qr > mid) res = min(res, query(rson, mid + 1, r, ql, qr));
return res;
}
int main () {
N = gi(), K = gi();
for (int i = 2; i <= N; i++) D[i] = gi();
for (int i = 1; i <= N; i++) C[i] = gi();
for (int i = 1; i <= N; i++) S[i] = gi();
for (int i = 1; i <= N; i++) W[i] = gi();
for (int i = 1, l, r, pos = 1; i <= N; i++) {
l = 1, r = i - 1, pos = i;
while (l <= r) {
int mid = (l + r) >> 1;
if (D[i] - D[mid] <= S[i]) pos = mid, r = mid - 1;
else l = mid + 1;
}
p[i].l = pos;
l = i + 1, r = N, pos = i;
while (l <= r) {
int mid = (l + r) >> 1;
if (D[mid] - D[i] <= S[i]) pos = mid, l = mid + 1;
else r = mid - 1;
}
p[i].r = pos;
}
for (int i = 1; i <= N; i++) vec[p[i].r].push_back(i);
for (int i = 1, tmp = 0; i <= N + 1; i++) {
dp[i] = tmp + C[i];
for (int j = 0; j < vec[i].size(); j++)
tmp += W[vec[i][j]];
}
int ans = dp[N + 1];
for (int i = 1; i <= K; i++) {
build(1, 1, N + 1);
for (int j = 1; j <= N + 1; j++) {
dp[j] = query(1, 1, N + 1, 1, j - 1) + C[j];
for (int k = 0; k < vec[j].size(); ++k) {
modify(1, 1, N + 1, 1, p[vec[j][k]].l - 1, W[vec[j][k]]);
}
}
ans = min(ans, dp[N + 1]);
}
printf("%d\n", ans);
return 0;
}
【LG2605】[ZJOI2010]基站选址的更多相关文章
- BZOJ1835,LG2605 [ZJOI2010]基站选址
题意 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为\(D_i\) 需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为\(C_i\) 如果在距离第i个村 ...
- 【题解】Luogu P2605 [ZJOI2010]基站选址
原题传送门:P2604 [ZJOI2010]基站选址 看一眼题目,变知道这题一定是dp 设f[i][j]表示在第i个村庄修建第j个基站且不考虑i+1~n个村庄的最小费用 可以得出f[i][j] = M ...
- 题解 [ZJOI2010]基站选址
题解 [ZJOI2010]基站选址 题面 解析 首先考虑一个暴力的DP, 设\(f[i][k]\)表示第\(k\)个基站设在第\(i\)个村庄,且不考虑后面的村庄的最小费用. 那么有\(f[i][k] ...
- luogu P2605 [ZJOI2010]基站选址 线段树优化dp
LINK:基站选址 md气死我了l达成1结果一直调 显然一个点只建立一个基站 然后可以从左到右进行dp. \(f_{i,j}\)表示强制在i处建立第j个基站的最小值. 暴力枚举转移 复杂度\(n\cd ...
- [ZJOI2010]基站选址,线段树优化DP
G. base 基站选址 内存限制:128 MiB 时间限制:2000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离 ...
- [ZJOI2010]基站选址
题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范 ...
- bzoj 1835: [ZJOI2010]基站选址
Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...
- BZOJ1835 [ZJOI2010] 基站选址 【动态规划】【线段树】
题目分析: 首先想一个DP方程,令f[m][n]表示当前在前n个村庄选了m个基站,且第m个基站放在n处的最小值,转移可以枚举上一个放基站的村庄,然后计算两个村庄之间的代价. 仔细思考两个基站之间村庄的 ...
- P2605 [ZJOI2010]基站选址
题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范 ...
随机推荐
- Deep Learning专栏--FFM+Recurrent Entity Network的端到端方案
很久没有写总结了,这篇博客仅作为最近的一些尝试内容,记录一些心得.FFM的优势是可以处理高维稀疏样本的特征组合,已经在无数的CTR预估比赛和工业界中广泛应用,此外,其也可以与Deep Networks ...
- Fuck SELinux :rsyslog无法生成log文件,原来是selinux机制搞的鬼!
Fuck SELinux 一万年! 关闭即可.
- 我是如何一步步编码完成万仓网ERP系统的(八)产品库设计 4.品牌类别
https://www.cnblogs.com/smh188/p/11533668.html(我是如何一步步编码完成万仓网ERP系统的(一)系统架构) https://www.cnblogs.com/ ...
- Huawei LiteOS简介
Huawei LiteOS简介 Huawei LiteOS是华为面向物联网领域开发的一个基于实时内核的轻量级操作系统.本项目属于华为物联网操作系统Huawei LiteOS源码,现有基础内核支持任务管 ...
- WPF控件介绍(2)
上一章讲到了布局.这点就有点类似建筑设计.第一步是出图纸.整体的结构.而第二步就是堆砌, 建筑学里面也会有很多描述, 例如砖头,水泥.玻璃.瓷板.而在WPF中, 这一切的基础也就是控件.用于填充结构的 ...
- 代码语法高亮踩坑-原理,问题, PRE元素及htmlentity
语法高亮库基础原理 在研究使用能够在web页面上代码语法高显的解决方案时,发现有很多现成的开源库.比较中意的有prism.js,highlightjs.他们的原理基本上核心就两点: 1. 利用html ...
- C# DataTable 转实体对象
DataTable 转实体对象 /// <summary> /// DataTable通过反射获取单个对象 /// </summary> public static T ToS ...
- FCC-学习笔记 Pig Latin
FCC-学习笔记 Pig Latin 1>最近在学习和练习FCC的题目.这个真的比较的好,推荐给大家. 2>中文版的地址:https://www.freecodecamp.cn/;英文版 ...
- Linux自有服务(2)-Linux从入门到精通第六天(非原创)
文章大纲 一.设置主机名二.chkconfig三.ntp服务四.防火墙服务五.rpm管理(重点)六.cron/crontab计划任务(重点)七.学习资料下载八.参考文章 自有服务,即不需要用户独立 ...
- Vue2.0 新手入门 — 从环境搭建到发布
什么是 Vue Vue 是一个前端框架,特点是数据绑定 比如你改变一个输入框 Input 标签的值,会自动同步更新到页面上其他绑定该输入框的组件的值 组件化 页面上小到一个按钮都可以是一个单独的文件. ...