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

题解:

这题非常的有意思,完全虐翻了我,开始写的是没有优化的DP,T到40,原来正解就是这个DP的优化,原DP中,定义的是 f[i][j] 表示第j个站安放在i这个位置的最小费用,这里并没有考虑后面的基站,所以我们要新建一个点,且这个点距离很远,费用为0,这样就可以完美的合并答案到这个点上面了,然后转移就是 f[i][j]=f[k][j-1]+c[k][i] ,c[k][i]表示k-i间覆盖不到的点的w总和.

考虑优化:

难点在于求出c[k][i]这个东西,我们就考虑消掉这个东西,再思考会发现,j这一维是可以滚动的,我们就可以考虑用线段树维护f[k][j-1],然后就是维护c这个东西,我们设st[i]为i左边能覆盖到i的最远点,同理ed[i]为右边最远点,那么如果扫到了i,那么ed在i上面的点,并且如果转移是从st-1转移来的,那么这个点就覆盖不到,就要在线段树[1,st[i]-1]的位置加上w[i],这样k的位置就变成了f[k]+w[i]了,所以转移就是查询线段树[1,i-1]中的最小值

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
#define ls (node<<1)
#define rs (node<<1|1)
using namespace std;
typedef long long ll;
const int N=20005,M=105,inf=2e8;
int gi(){
int str=0;char ch=getchar();
while(ch>'9' || ch<'0')ch=getchar();
while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
return str;
}
int n,m;int f[N],c[N],w[N],st[N],ed[N],Tree[N<<2],mark[N<<2];ll d[N],s[N];
int midl(int sta,ll x){
int l=1,r=n,mid,ret=sta;
while(l<=r){
mid=(l+r)>>1;
if(d[mid]>=x)ret=mid,r=mid-1;
else l=mid+1;
}
return ret;
}
int midr(int sta,ll x){
int l=1,r=n,mid,ret=sta;
while(l<=r){
mid=(l+r)>>1;
if(d[mid]<=x)ret=mid,l=mid+1;
else r=mid-1;
}
return ret;
}
int head[N],to[N],num=0,nxt[N];
void addedge(int x,int y){
nxt[++num]=head[x];to[num]=y;head[x]=num;
}
void upd(int node){
Tree[node]=Min(Tree[ls],Tree[rs]);
}
void build(int l,int r,int node){
mark[node]=0;
if(l==r){
Tree[node]=f[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,ls);build(mid+1,r,rs);
upd(node);
}
void pushdown(int node){
if(!mark[node])return ;
int k=mark[node];
Tree[ls]+=k;Tree[rs]+=k;
mark[ls]+=k;mark[rs]+=k;
mark[node]=0;
}
void updata(int l,int r,int node,int sa,int se,int to){
if(l>se || r<sa)return ;
if(sa<=l && r<=se){
Tree[node]+=to;mark[node]+=to;
return ;
}
pushdown(node);
int mid=(l+r)>>1;
updata(l,mid,ls,sa,se,to);updata(mid+1,r,rs,sa,se,to);
upd(node);
}
int query(int l,int r,int node,int sa,int se){
if(l>se || r<sa)return inf;
if(sa<=l && r<=se)return Tree[node];
pushdown(node);
int mid=(l+r)>>1;
int q1=query(l,mid,ls,sa,se),q2=query(mid+1,r,rs,sa,se);
upd(node);
return Min(q1,q2);
}
void work()
{
n=gi();m=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();
n++;d[n]=2e12;
for(int i=1;i<=n;i++){
st[i]=midl(i,d[i]-s[i]);ed[i]=midr(i,d[i]+s[i]);
addedge(ed[i],i);
}
ll tot=0;
for(int i=1;i<=n;i++){
f[i]=tot+c[i];
for(int j=head[i];j;j=nxt[j]){
tot+=w[to[j]];
}
}
ll ans=f[n];
for(int j=2;j<=m+1;j++){
build(1,n,1);
for(int i=1;i<=n;i++){
if(i>1)f[i]=query(1,n,1,1,i-1)+c[i];
for(int k=head[i];k;k=nxt[k]){
int u=to[k];
if(st[u]>1)updata(1,n,1,1,st[u]-1,w[u]);
}
}
ans=Min(ans,f[n]);
}
printf("%lld\n",ans);
} int main()
{
freopen("base.in","r",stdin);
freopen("base.out","w",stdout);
work();
return 0;
}

bzoj 1835: [ZJOI2010]基站选址的更多相关文章

  1. BZOJ 1835 [ZJOI2010]基站选址 (线段树优化DP)

    题目大意:略 洛谷题面传送门 BZOJ题面传送门 注意题目的描述,是村庄在一个范围内去覆盖基站,而不是基站覆盖村庄,别理解错了 定义$f[i][k]$表示只考虑前i个村庄,一共建了$k$个基站,最后一 ...

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

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

  3. bzoj[1835][ZJOI2010]base 基地选址

    bzoj[1835][ZJOI2010]base 基地选址 标签: 线段树 DP 题目链接 题解 这个暴力DP的话应该很容易看出来. dp[i][j]表示造了i个通讯站,并且j是第i个的最小费用. \ ...

  4. 【题解】Luogu P2605 [ZJOI2010]基站选址

    原题传送门:P2604 [ZJOI2010]基站选址 看一眼题目,变知道这题一定是dp 设f[i][j]表示在第i个村庄修建第j个基站且不考虑i+1~n个村庄的最小费用 可以得出f[i][j] = M ...

  5. 【LG2605】[ZJOI2010]基站选址

    [LG2605][ZJOI2010]基站选址 题面 洛谷 题解 先考虑一下暴力怎么写,设\(f_{i,j}\)表示当前\(dp\)到\(i\),且强制选\(i\),目前共放置\(j\)个的方案数. 那 ...

  6. 题解 [ZJOI2010]基站选址

    题解 [ZJOI2010]基站选址 题面 解析 首先考虑一个暴力的DP, 设\(f[i][k]\)表示第\(k\)个基站设在第\(i\)个村庄,且不考虑后面的村庄的最小费用. 那么有\(f[i][k] ...

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

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

  8. luogu P2605 [ZJOI2010]基站选址 线段树优化dp

    LINK:基站选址 md气死我了l达成1结果一直调 显然一个点只建立一个基站 然后可以从左到右进行dp. \(f_{i,j}\)表示强制在i处建立第j个基站的最小值. 暴力枚举转移 复杂度\(n\cd ...

  9. [ZJOI2010]基站选址,线段树优化DP

    G. base 基站选址 内存限制:128 MiB 时间限制:2000 ms 标准输入输出 题目类型:传统 评测方式:文本比较   题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离 ...

随机推荐

  1. python网络爬虫,知识储备,简单爬虫的必知必会,【核心】

    知识储备,简单爬虫的必知必会,[核心] 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到桌 ...

  2. ruby:TypeError: 对象不支持此属性或方法

    解决办法. 1.下载对应版本 下载node.js,根据ruby版本决定下载32还是x64,我的ruby版本x64 https://npm.taobao.org/mirrors/node/v8.9.3/ ...

  3. javascript 腾讯ABS云平台面试题及面试经历

    既然说到面试前端肯定是Javascript各种问,只好各种答. 面试题肯定离不了,最近热门的Vue.js,React.js,Angular.js,Gulp,Webpack还有各种Js问题,还有令人头痛 ...

  4. React 深入系列1:React 中的元素、组件、实例和节点

    文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助大家加深对React的理解,以及在项目中 ...

  5. BizTalk Server 2010高可用方案

    BizTalk Server 2010高可用方案 本文介绍了 Microsoft BizTalk Server 中通过对主机的各层进行扩展提供高可用性的方案. 分隔各个区域的功能分为不同的主机和中的层 ...

  6. Docker Mysql主从同步配置搭建

    Docker Mysql主从同步配置搭建 建立目录 在虚拟机中建立目录,例如路径/home/mysql/master/data,目录结构如下: Linux中 新建文件夹命令:mkdir 文件夹名 返回 ...

  7. Linux CentOS7.0 (03)安装验证 docker

    一.安装docker 1.升级 Linux 的软件包和内核 sudo yum update 2.安装 docker (1) sudo yum install docker  (2).验证docker安 ...

  8. GIT入门笔记(13)- GUI GIT

  9. EasyUI中datagrid的基本用法

    EasyUI中datagrid是最常用的一个控件了,现在整理一下datagrid的基本语法,先展示下页面效果吧,如下图

  10. word2vec初探(用python简单实现)

    为什么要用这个? 因为看论文和博客的时候很常见,不论是干嘛的,既然这么火,不妨试试. 如何安装 从网上爬数据下来 对数据进行过滤.分词 用word2vec进行近义词查找等操作 完整的工程传到了我的gi ...