题目描述

有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di。需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci。如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就村庄被基站覆盖了。如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi。现在的问题是,选择基站的位置,使得总费用最小。

输入输出格式

输入格式:

输入文件的第一行包含两个整数N,K,含义如上所述。

第二行包含N-1个整数,分别表示D2,D3,…,DN ,这N-1个数是递增的。

第三行包含N个整数,表示C1,C2,…CN。

第四行包含N个整数,表示S1,S2,…,SN。

第五行包含N个整数,表示W1,W2,…,WN。


输出格式:

输出文件中仅包含一个整数,表示最小的总费用。

输入输出样例

输入样例#1:

3 2
1 2
2 3 2
1 1 0
10 20 30
输出样例#1:

4

说明

40%的数据中,N<=500;

100%的数据中,K<=N,K<=100,N<=20,000,Di<=1000000000,Ci<=10000,Si<=1000000000,Wi<=10000。

Solution:

  本题线段树优化dp。

  定义状态$f[i][j]$表示到了$i$村庄建立第$j$个基站的最小费用(不考虑对$i+1\rightarrow n$村庄的影响),则不难得到状态转移方程:$f[i][j]=\min (f[k][j-1]+cost[k][i])+c[i],j-1\leq k<i$,其中$cost[k][i]$表示在$k$村庄和$i$村庄建立基站中间不会被覆盖到的村庄所需补偿费用和。

  对于$cost[k][i]$,我们完全可以预处理出每个村庄建立基站可以覆盖到的边界(二分),然后对补偿费用作前缀和,就能在转移时做到$O(1)$求$cost[k][i]$了,但是这样时间复杂度还是下不去的$O(kn^2)$。

  我们还是预处理出$st[i],ed[i]$分别表示$i$村庄建基站往左最多覆盖到的村庄和往右最多覆盖到的村庄,再用链表建立覆盖关系$ed[i]\rightarrow i$。

  状态转移时,我们可以先滚掉后面一维。然后发现每次村庄右移引起的不会被覆盖的点最多只会比上个位置不会被覆盖的点多$1$,具体来说,当我们由$f[k]$转移到状态$f[i+1]$时,若$ed[p]=i$且$k\in [1,st[p])$则转移时一定会加上覆盖$p$的费用(不在范围内的$k$位置转移的值并没有改变),那么这个区间修改区间最值的转移问题,想到用线段树来优化。

  设当前需要转移的是第$j$个基站,线段树维护$j-1$状态在每个村庄建立基站的最小费用,由某一状态转移到$i$时只需要查询$[j-1,i-1]$的最小值就好了(注意越界问题,至少要有$j-1$个基站),每次转移完就扫一下以$i$点为$ed$的节点$p$,找到$st[p]$,对$[1,st[p]-1]$这段区间的状态整体加上$w[p]$。

  在实现时由于还得知道最后的答案,我们可以在末尾放置一个哨兵村庄,将其设置为必须被选且覆盖不到任何村庄,然后令村庄数$+1$、基站数$+1$,那么每个$f[n]$就是当前状态下的答案了,取每个状态的最小值就好了。

代码:

/*Code by 520 -- 9.25*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int N=;
int n,k,ans,st[N],ed[N];
int d[N],c[N],s[N],w[N],f[N];
int to[N],net[N],h[N],cnt;
int minn[N<<],lazy[N<<]; int gi(){
int a=;char x=getchar();
while(x<''||x>'') x=getchar();
while(x>=''&&x<='') a=(a<<)+(a<<)+(x^),x=getchar();
return a;
} il void add(int u,int v){to[++cnt]=v,net[cnt]=h[u],h[u]=cnt;} il void pushup(int rt){minn[rt]=min(minn[rt<<],minn[rt<<|]);} il void pushdown(int rt){
if(lazy[rt]){
minn[rt<<]+=lazy[rt],minn[rt<<|]+=lazy[rt];
lazy[rt<<]+=lazy[rt],lazy[rt<<|]+=lazy[rt];
lazy[rt]=;
}
} void build(int l,int r,int rt){
lazy[rt]=;
if(l==r) {minn[rt]=f[l];return;}
int m=l+r>>;
build(lson),build(rson);
pushup(rt);
} void update(int x,int L,int R,int l,int r,int rt){
if(L<=l&&R>=r) {minn[rt]+=x,lazy[rt]+=x;return;}
pushdown(rt);
int m=l+r>>;
if(L<=m) update(x,L,R,lson);
if(R>m) update(x,L,R,rson);
pushup(rt);
} int query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r) return minn[rt];
pushdown(rt);
int m=l+r>>,res=0x3f3f3f3f;
if(L<=m) res=min(res,query(L,R,lson));
if(R>m) res=min(res,query(L,R,rson));
return res;
} int main(){
n=gi(),k=gi()+;
For(i,,n) d[i]=gi();
For(i,,n) c[i]=gi();
For(i,,n) s[i]=gi();
For(i,,n) w[i]=gi();
++n,d[n]=w[n]=0x3f3f3f3f;
For(i,,n) {
st[i]=lower_bound(d+,d+n+,d[i]-s[i])-d,
ed[i]=lower_bound(d+,d+n+,d[i]+s[i])-d;
if(d[ed[i]]>d[i]+s[i]) ed[i]--;
add(ed[i],i);
}
int tot=;
For(i,,n) {
f[i]=tot+c[i];
for(RE int p=h[i];p;p=net[p]) tot+=w[to[p]];
}
ans=f[n];
For(i,,k) {
build(,n,);
For(j,,n) {
f[j]=(j>i-?query(i-,j-,,n,):)+c[j];
for(RE int p=h[j];p;p=net[p])
if(st[to[p]]>) update(w[to[p]],,st[to[p]]-,,n,);
}
ans=min(ans,f[n]);
}
cout<<ans;
return ;
}

P2605 [ZJOI2010]基站选址的更多相关文章

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

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

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

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

  3. luogu P2605 [ZJOI2010]基站选址

    luogu 先考虑朴素dp,设\(f_{i,j}\)表示在第\(i\)个村庄放了基站,一共放了\(j\)次,且只考虑前面村庄影响的答案.这里可以把\(j\)放在外面枚举,然后从\(f_{k,j-1}( ...

  4. 洛谷$P2605\ [ZJOI2010]$基站选址 线段树优化$dp$

    正解:线段树优化$dp$ 解题报告: 传送门$QwQ$ 难受阿,,,本来想做考试题的,我还造了个精妙无比的题面,然后今天讲$dp$的时候被讲到了$kk$ 先考虑暴力$dp$?就设$f_{i,j}$表示 ...

  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. [ZJOI2010]基站选址,线段树优化DP

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

  8. 题解 P2605 【[ZJOI2010]基站选址】(From luoguBlog)

    线段树优化dp 数组f[i][j]表示在前i个村庄内,第j个基站建在i处的最小费用 根据交线牛逼法和王鹤松式可得方程 f[i][j]=min(f[k][j−1]+cost(k,i)) cost(k,i ...

  9. [ZJOI2010]基站选址

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

随机推荐

  1. Closure Compiler应用程序使用入门[译]

    Hello World示例 Closure Compiler应用程序是一个Java 命令行工具,用来对JavaScript代码进行压缩.优化和排错.按照下面的步骤,用一个简单的JavaScript程序 ...

  2. 廖雪峰git教程学习笔记

    对git来说,没有消息就是最好的消息 使用 git init 把当前目录变为git仓库 要在仓库里加入文件,先在仓库目录新建这个文件后,比如新建一个文件xiaobai.txt,内容为: 在命令行里输入 ...

  3. 本地使用js或jquery操作cookie在谷歌浏览器chrome中不生效

    一般是在本地调试cookie,无论使用jquery cookie插件还是js原生态cookie方法,在谷歌浏览器chrome中都不生效,这是什么原因? 原因是: chrome不支持js在本地操作coo ...

  4. 《Redis设计与实现》阅读笔记(二)--简单动态字符串

    简单动态字符串 Redis只在一些无需对字符串进行修改的地方使用C字符串,大部分时候使用简单动态字符串(simple dynamic string, SDS),字符串的抽象类型.二进制安全,可以存放任 ...

  5. 学习python,第四篇:Python 3中bytes/string的区别

    原文:http://eli.thegreenplace.net/2012/01/30/the-bytesstr-dichotomy-in-python-3 python 3中最重要的新特性可能就是将文 ...

  6. 企业服务总线ESB

    # 企业服务总线ESB 由中间件技术实现并支持SOA的一组基础架构,支持异构环境中的服务.消息以及基于事件的交互,并且具有适当的服务级别和可管理性. 通过使用ESB,可以在几乎不更改代码的情况下,以一 ...

  7. Netty源码分析第7章(编码器和写数据)---->第2节: MessageToByteEncoder

    Netty源码分析第七章: Netty源码分析 第二节: MessageToByteEncoder 同解码器一样, 编码器中也有一个抽象类叫MessageToByteEncoder, 其中定义了编码器 ...

  8. Sentence | Never underestimate yourself.

    "\(Our\) \(deepest\) \(fear\) \(is\) \(not\) \(that\) \(we\) \(are\) $inadequate. $ \(Our\) \(d ...

  9. 用 requests 模块从 Web 下载文件

    用 requests 模块从 Web 下载文件 requests 模块让你很容易从 Web 下载文件,不必担心一些复杂的问题,诸如网络错误.连接问题和数据压缩.requests 模块不是 Python ...

  10. 我眼中的PD(产品狗)

    以下内容可能引起您的不适(前方高能),请先移步科普: 产品经理为什么会存在? 本猿 -> web程序属 -> 前端开发种,从大森林迁徙到了小草原: 小草原物种稀缺,除了 程序猿,很难见到诸 ...