原题传送门

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

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

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

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

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

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

Output

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

Sample Input

3 2

1 2

2 3 2

1 1 0

10 20 30

Sample Output

4

Hint

40%的数据中,\(N \leq 500\);

100%的数据中,\(K \leq N,K \leq 100 , N \leq 20000 , Di \leq 10^{9} , Ci \leq 10000,Si \leq 10^9,Wi \leq 10000\) 。

Solution

对于 40%的数据,显然,这是一个简单的 dp,定义 \(f_{i,j}\) 表示将第 i 个星球选为第 j 个基站且不考虑之后的星球的费用,显然可以很容易的得到 dp 方程:$f_{i,j} = min(f_{k,j-1} + cost(k,i))+c_{i} $ ;

上文中 $ Cost(i,j) = \Sigma_{k} w_{k} ( d_{i} < d_{k} - s_{k} \wedge d_{k} > d_{j} + s_{k} ) $ 表示 i~j 之间没有被覆盖到的星球的花费之和。暴力计算 cost 函数的时间复杂度为 O(n),故总时间复杂度为\(O(kn^2)\) .

对于 100%的数据,考虑进行优化,首先发现,第 j 层的状态只与上一层有关,故考虑压内存,j接下来,我们发现,大量的时间花费计算在 cost 函数上,容易发现,对于一个星球 i,它可以被覆盖的范围一定是一个区间,考虑记录这个区间的左右端点,接下来考虑它没被覆盖的贡献,容易发现,当你选择区间右端点(不含)之后作为即将建立的基站时,若是从左端点(不含)之前的星球所转移过来的,就需要花费该星球的未覆盖费,由于这是一个区间问题,而状态的转移\(min(f_{j} + cost(j,i))\)也同样是区间内的,因此考虑利用线段树维护\(min(f_{j} + cost(j,i))\)加速 DP,滚动利用线段树,在推导完第 i 个星球之后,将右端点为 i 的星球的\(w_{j}\)在线段树上累加到该星球左端点(不含)之前的星球即可,这样处理好细节之后就可以通过此题,时间复杂度为\(O(kn \log_{2} n)\),空间复杂度为O(n).

Code

#include <stdio.h>
#define R register
#define mid (l+r>>1)
#define MN 20005
#define MM (1<<16)
#define inf 0x3f3f3f3f
inline int read(){
R int x; R bool f; R char c;
for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
return f?-x:x;
}
int d[MN],T[MM],mark[MM],r[MN],c[MN],w[MN],st[MN],ed[MN],n,k,lk[MN],nxt[MN],head[MN],cnt,f[MN],ans=inf;
inline int min(int a,int b) {return a<b?a:b;}
inline void ins(int x,int y){lk[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;}
inline int find(int x){
R int l=1,r=n;
while(l<r)
if (d[mid]<x) l=mid+1;
else r=mid;
return l;
}
inline void build(int k,int l,int r){
if (l==r){
T[k]=f[l];
return;
}build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
T[k]=min(T[k<<1],T[k<<1|1]);mark[k]=0;
}
inline void pushdown(int k){
if (!mark[k]) return;
T[k<<1]+=mark[k],T[k<<1|1]+=mark[k];
mark[k<<1]+=mark[k],mark[k<<1|1]+=mark[k];
mark[k]=0;
}
inline void update(int l,int r,int a,int b,int k,int ad){
if (l>=a&&r<=b){
T[k]+=ad;
mark[k]+=ad;
return;
}pushdown(k);
if (a<=mid) update(l,mid,a,b,k<<1,ad);
if (b>mid) update(mid+1,r,a,b,k<<1|1,ad);
T[k]=min(T[k<<1],T[k<<1|1]);
}
inline int query(int l,int r,int a,int b,int k){
if (l==a&&r==b) return T[k];pushdown(k);
if (b<=mid) return query(l,mid,a,b,k<<1);
if (a>mid) return query(mid+1,r,a,b,k<<1|1);
return min(query(l,mid,a,mid,k<<1),query(mid+1,r,mid+1,b,k<<1|1));
}
int main(){
n=read(),k=read();
for (R int i=2; i<=n; ++i) d[i]=read();
for (R int i=1; i<=n; ++i) c[i]=read();
for (R int i=1; i<=n; ++i) r[i]=read();
for (R int i=1; i<=n; ++i) w[i]=read();
d[++n]=inf;++k;
for (R int i=1; i<=n; ++i){
st[i]=find(d[i]-r[i]),ed[i]=find(d[i]+r[i]);
if (d[ed[i]]>r[i]+d[i]) --ed[i];
ins(ed[i],i);
}
for (R int i=1,sum=0; i<=n; ++i){
f[i]=sum+c[i];
for (R int j=head[i]; j; j=nxt[j])
sum+=w[lk[j]];
}
for (R int i=2; i<=k; ++i){
build(1,1,n);
for (R int j=1; j<=n; ++j){
if (j>=i)
f[j]=query(1,n,1,j-1,1)+c[j];
else f[j]=inf;
for (R int l=head[j]; l; l=nxt[l])
if (st[lk[l]]>1)
update(1,n,1,st[lk[l]]-1,1,w[lk[l]]);
}
}
printf("%d\n",f[n]);
return 0;
}

【BZOJ1835】【ZJOI2010】基站选址的更多相关文章

  1. BZOJ1835 [ZJOI2010] 基站选址 【动态规划】【线段树】

    题目分析: 首先想一个DP方程,令f[m][n]表示当前在前n个村庄选了m个基站,且第m个基站放在n处的最小值,转移可以枚举上一个放基站的村庄,然后计算两个村庄之间的代价. 仔细思考两个基站之间村庄的 ...

  2. bzoj1835[ZJOI2010]基站选址

    主席树+决策单调,重写一遍比之前短多了……题解:http://www.cnblogs.com/liu-runda/p/6051422.html #include<cstdio> #incl ...

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

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

  4. 【BZOJ1835】基站选址(线段树)

    [BZOJ1835]基站选址(线段树) 题面 BZOJ 题解 考虑一个比较暴力的\(dp\) 设\(f[i][j]\)表示建了\(i\)个基站,最后一个的位置是\(j\)的最小代价 考虑如何转移\(f ...

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

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

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

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

  9. BZOJ1835,LG2605 [ZJOI2010]基站选址

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

  10. Bzoj1835:[ZJOI2010]基站选址

    Sol 设\(f[i][j]\)表示钦定\(i\)建基站,建了\(j\)个基站的最小代价 \(f[i][j]=max(f[l][j-1]+\Sigma_{t=l+1}^{i-1}\)不能影响到的村庄的 ...

随机推荐

  1. B-day5

    1.昨天的困难,今天解决的进度,以及明天要做的事情 昨天的困难:昨天虽然完成了风险数据的图表统计,但是界面风格仍然不太满意,还在抓紧调试中:还有登录页的背景图,在想应该如何设计, 什么样的风格才好. ...

  2. 20145237 《Java程序设计》第九周学习总结

    20145237 <Java程序设计>第九周学习总结 教材学习内容总结 第十六章 整合数据库 JDBC入门 ·数据库本身是个独立运行的应用程序 ·撰写应用程序是利用通信协议对数据库进行指令 ...

  3. Tornado 协程

    同步异步I/O客户端 from tornado.httpclient import HTTPClient,AsyncHTTPClient def ssync_visit(): http_client ...

  4. nyoj 邮票分你一半

    邮票分你一半 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述      小珂最近收集了些邮票,他想把其中的一些给他的好朋友小明.每张邮票上都有分值,他们想把这些邮票分 ...

  5. nyoj 背包问题

    背包问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v,w< ...

  6. Vue.js自己从官网整理的东东

    1.采用简洁的模板语法来声明渲染数据: <div id="app"> {{ message }} </div> var app = new Vue({ el ...

  7. vueJs 源码解析 (三) 具体代码

    vueJs 源码解析 (三) 具体代码 在之前的文章中提到了 vuejs 源码中的 架构部分,以及 谈论到了 vue 源码三要素 vm.compiler.watcher 这三要素,那么今天我们就从这三 ...

  8. 面向对象的PHP(5)

    OOP的好处 封装 封装可以隐藏实现细节,使代码模块化,代码重用 继承 继承可以扩展已存在的代码模块(class),代码重用 多态 为了类在继承和派生的时候,保证实例的某一属性正确调用,接口重用 关键 ...

  9. Android TabLayout 在宽屏幕上tab不能平均分配的问题解决

    当TabLayout 在宽屏幕的设备上,如平板横屏的时候,tab的宽度超过一定值后,就不在平均分配宽度,而是居中显示.此时设置 app:tabMode="fixed"或者 top_ ...

  10. Windows10+Docker搭建分布式Redis集群(一)

    摘要,Docker for Windows 仅支持专业版 目录 第一步:检查系统支持虚拟化 第二步:下载Docker对应版本 第三步:配置镜像加速 第一步:检查系统是否支持虚拟化 Docker前提是需 ...