【BZOJ1835】基站选址(线段树)
【BZOJ1835】基站选址(线段树)
题面
题解
考虑一个比较暴力的\(dp\)
设\(f[i][j]\)表示建了\(i\)个基站,最后一个的位置是\(j\)的最小代价
考虑如何转移\(f[i][j]=min(f[i-1][p]+Cost(p+1,j)+C[j])\)
其中\(Cost\)表示代价,也就是区间内所有没有被覆盖的村庄的\(W\)的和
如果直接暴力\(dp\),复杂度\(O(n^2k)\),这个复杂度还假设了\(Cost\)是\(O(1)\)计算的
转移的时候是枚举建造的个数,显然还可以滚调第一维
但是这个复杂度我们无法接受,我们要思考有没有更快的方法
考虑\(dp\)的转移式子
\(f[i][j]=min(f[i-1][p]+Cost(p+1,j)+C[j])\)
\(f[i][j]=min(f[i-1][p]+Cost(p+1,j))+C[j]\)
相当于我们要找到的就是\(min(f[i-1][p]+Cost(p+1,j))\)
我们不难知道,如果一个村庄不需要贡献他的\(W\)
那么,必须在一个区间内存在一个基站
所以,这个区间我们可以提前预处理出来(二分一下)
然后按照右端点排序,按照右端点结束的位置分类
从左到右这样扫过来,如果过了某个右端点
此时,这些区间的最右端在当前位置的那些村落,
在后面的\(dp\)中必然产生贡献,
会对\([1,left-1]\)的所有区间都产生\(W\)的贡献
因此在线段树上做一次区间加法
每次进行转移的时候从所有的位置中选出区间最小值就行了
然后\(K\)增大,重构线段树即可
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define RG register
#define ll long long
#define MAX 30000
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int f[MAX];
struct Node{int v,tag;}t[MAX<<2];
struct Seg{int l,r;}p[MAX];
vector<int> V[MAX];
int n,K,W[MAX],S[MAX],d[MAX],C[MAX],ans=2e9;
void Build(int now,int l,int r)
{
t[now].tag=0;
if(l==r){t[now].v=f[l];return;}
int mid=(l+r)>>1;
Build(lson,l,mid);Build(rson,mid+1,r);
t[now].v=min(t[lson].v,t[rson].v);
}
void puttag(int now,int w){t[now].v+=w;t[now].tag+=w;}
void pushdown(int now)
{
puttag(lson,t[now].tag);
puttag(rson,t[now].tag);
t[now].tag=0;
}
void Modify(int now,int l,int r,int L,int R,int w)
{
if(L>R)return;
if(L<=l&&r<=R){puttag(now,w);return;}
pushdown(now);
int mid=(l+r)>>1;
if(L<=mid)Modify(lson,l,mid,L,R,w);
if(R>mid)Modify(rson,mid+1,r,L,R,w);
t[now].v=min(t[lson].v,t[rson].v);
}
int Query(int now,int l,int r,int L,int R)
{
if(L>R)return 0;
if(L<=l&&r<=R)return t[now].v;
pushdown(now);
int mid=(l+r)>>1,ret=2e9;
if(L<=mid)ret=min(ret,Query(lson,l,mid,L,R));
if(R>mid)ret=min(ret,Query(rson,mid+1,r,L,R));
return ret;
}
int main()
{
n=read();K=read();
for(int i=2;i<=n;++i)d[i]=read();
for(int i=1;i<=n;++i)C[i]=read();
for(int i=1;i<=n;++i)S[i]=read();
for(int i=1;i<=n;++i)W[i]=read();
for(int i=1,l,r,pos;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])l=mid+1;
else pos=mid,r=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])r=mid-1;
else pos=mid,l=mid+1;
}
p[i].r=pos;
}
for(int i=1;i<=n;++i)
V[p[i].r].push_back(i);
for(int i=1,tmp=0;i<=n+1;++i)
{
f[i]=tmp+C[i];
for(int j=0;j<V[i].size();++j)
tmp+=W[V[i][j]];
}
ans=f[n+1];
for(int i=1;i<=K;++i)
{
Build(1,1,n+1);
for(int j=1;j<=n+1;++j)
{
f[j]=Query(1,1,n+1,1,j-1)+C[j];
for(int k=0;k<V[j].size();++k)
Modify(1,1,n+1,1,p[V[j][k]].l-1,W[V[j][k]]);
}
ans=min(ans,f[n+1]);
}
printf("%d\n",ans);
return 0;
}
【BZOJ1835】基站选址(线段树)的更多相关文章
- 【BZOJ1835】[ZJOI2010]base 基站选址 线段树+DP
[BZOJ1835][ZJOI2010]base 基站选址 Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯 ...
- [ZJOI2010]基站选址,线段树优化DP
G. base 基站选址 内存限制:128 MiB 时间限制:2000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离 ...
- luogu2605 基站选址 (线段树优化dp)
设f[i][j]表示在第i个村庄建第j个基站的花费 那么有$f[i][j]=min\{f[k][j-1]+w[k,i]\}$,其中w[k,i]表示在k,i建基站,k,i中间的不能被满足的村庄的赔偿金之 ...
- BZOJ 1835 [ZJOI2010]基站选址 (线段树优化DP)
题目大意:略 洛谷题面传送门 BZOJ题面传送门 注意题目的描述,是村庄在一个范围内去覆盖基站,而不是基站覆盖村庄,别理解错了 定义$f[i][k]$表示只考虑前i个村庄,一共建了$k$个基站,最后一 ...
- 洛谷$P2605\ [ZJOI2010]$基站选址 线段树优化$dp$
正解:线段树优化$dp$ 解题报告: 传送门$QwQ$ 难受阿,,,本来想做考试题的,我还造了个精妙无比的题面,然后今天讲$dp$的时候被讲到了$kk$ 先考虑暴力$dp$?就设$f_{i,j}$表示 ...
- luogu P2605 [ZJOI2010]基站选址 线段树优化dp
LINK:基站选址 md气死我了l达成1结果一直调 显然一个点只建立一个基站 然后可以从左到右进行dp. \(f_{i,j}\)表示强制在i处建立第j个基站的最小值. 暴力枚举转移 复杂度\(n\cd ...
- BZOJ1835: [ZJOI2010]base 基站选址(线段树优化Dp)
Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...
- P2605 [ZJOI2010]基站选址
题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范 ...
- BZOJ1835 [ZJOI2010] 基站选址 【动态规划】【线段树】
题目分析: 首先想一个DP方程,令f[m][n]表示当前在前n个村庄选了m个基站,且第m个基站放在n处的最小值,转移可以枚举上一个放基站的村庄,然后计算两个村庄之间的代价. 仔细思考两个基站之间村庄的 ...
随机推荐
- L2-016 愿天下有情人都是失散多年的兄妹
L2-016 愿天下有情人都是失散多年的兄妹 (25 分) 呵呵.大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人.父母.祖父母.曾祖父母.高祖父母)则不可通婚.本题就请你 ...
- WebGL之sprite精灵效果显式数字贴图
接着前一篇<WebGL实现sprite精灵效果的GUI控件>,我们继续开发我们的数字系统GUI控件,因为这套数字系统是基于sprite效果的,所以数字随相机转动而旋转(永远面对相机),随场 ...
- 【snaptype nexus】搭建maven私服仓库
搭建本地开发私库,旨在解决本地开始受限于网络环境的问题:具体的搭建步骤主要包含以下几个步骤: 1.私服服务器使用的是ubuntu,首先下载安装包(版本号:2.12),下载地址:http://www.s ...
- Centos 7 安装Zabbix
一.环境准备与说明: 1.zabbix server 版本:3.4.12 ,https://www.zabbix.com/download 2.zabbix agent版本:3.4.14,https: ...
- linux的date命令使用指定时间的加减方法与异常
在一般网页里,date命令减时间方法为: date -d '-100 days' 我的需求是,在指定时间上减8小时.按一般理解来看,命令写成如下样子(有异常错误的写法): date -d " ...
- host命令详解
基础命令学习目录首页 原文链接:https://blog.csdn.net/xin_y/article/details/53924763 分析域名查询工具,测试域名系统工作是否正常 语法: host ...
- 使用Python一年多了,总结八个好用的Python爬虫技巧
用python也差不多一年多了,python应用最多的场景还是web快速开发.爬虫.自动化运维:写过简单网站.写过自动发帖脚本.写过收发邮件脚本.写过简单验证码识别脚本. 爬虫在开发过程中也有很多复用 ...
- bootstrap table的展开行问题
照着网上与api里说的添加detailView属性设置为true,detailFormatter属性为展开后的内容,但是设置之后发现,在表格每一行最前面是多出一列正常该显示"+"的 ...
- 面向对象OO第5-7次作业总结
面向对象OO第5-7次作业总结 学习OO七周了,深切的感受到了这门课程的不友好.前三次作业能够算是勉强地通过了,但是从第五次作业开始就完全GG了.这三次作业,从多线程电梯开始,然后文件监控,然后到出租 ...
- Chapter 6 面向对象基础
面向对象=对象+类+继承+通信,如果一个软件系统采用这些概念来建立模型并给予实现,那么它就是面向对象的.面向对象的软件工程方法是面向对象方法在软件工程领域的全面运用涉及到从面向对象分析.面向对象设计. ...