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. 小草手把手教你LabVIEW串口仪器控制—安装使用仪器现有驱动

    声明:很多仪器是没有驱动的.所以,具体问题具体分析.另外声明:所谓的驱动,也就是封装好的底层的串口通信程序,也是程序而已,只不过别人帮你做成了子 VI,让自己容易用.所以:不要弄混淆了概念.国外的很多 ...

  2. 5种做法实现table表格中的斜线表头效果

    table表格,这个东西大家肯定都不陌生,代码中我们时常都能碰到,那么给table加一个斜线的表头有时是很有必要的,但是到底该怎么实现这种效果呢? 我总结了以下几种方法: 1.最最最简单的做法 直接去 ...

  3. Python爬虫之urllib模块2

    Python爬虫之urllib模块2 本文来自网友投稿 作者:PG-55,一个待毕业待就业的二流大学生. 看了一下上一节的反馈,有些同学认为这个没什么意义,也有的同学觉得太简单,关于Beautiful ...

  4. python subprocess模块使用总结

    一.subprocess以及常用的封装函数运行python的时候,我们都是在创建并运行一个进程.像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序.在Python ...

  5. 新概念英语(1-113)Small Change

    Lesson 113 Small Change 零钱 Listen to the tape then answer this question. Who has got some change?听录音 ...

  6. python Django之Ajax

    python Django之Ajax AJAX,Asynchronous JavaScript and XML (异步的JavaScript和XML),一种创建交互式网页应用的网页开发技术方案. 异步 ...

  7. Github学习笔记-不定时更新

    最近在搞一个外包项目,有个非常厉害的师兄带我,他写后端,我负责前端部分,项目合作需要用到github,这也是早晚要接触,记录下项目过程中对github/git使用的学习笔记. 1.在网上看了一些教程之 ...

  8. Menubutton按钮弹出菜单

    #按钮弹出菜单 from tkinter import * root =Tk() def callback(): print('我被调用了') m = Menubutton(root,text = ' ...

  9. jacascript DOM变动事件

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! DOM变动事件 变动事件(MutationEvent)能在DOM中的某一部分发生变化时给出提示,这类事件非 ...

  10. Linux下内存问题检测神器:Valgrind

    在写大型C/C++工程时难免会发生内存泄漏现象,系统编程中一个重要的方面就是有效地处理与内存相关的问题.你的工作越接近系统,你就需要面对越多的内存问题.有时这些问题非常琐碎,而更多时候它会演变成一个调 ...