bzoj1835[ZJOI2010]base基站选址
据说正解是什么线段树优化DP,但是作为脑子有坑选手,我们需要5k的做法:
主席树+决策单调性.....
F[m][i]表示已经放置了m个基站,第m个基站放置在第i个村庄,第i个村庄及之前的村庄的总最少花费(包括建立基站的花费和赔偿的花费),转移的时候,F[m][i]=min(F[m-1][j]+cost(j,i))+ci
Cost(j,i)表示在点j和点i各建立一个基站,j和i之间不建立基站时,j和i之间需要的总赔偿。
考虑如何快速求出cost(j,i).对于每个村庄k我们可以在位置坐标轴上二分查找,预处理出一个区间[Lk,Rk],表示如果在[Lk,Rk]放一个基站就可以覆盖村庄k。那么只有[Lk,Rk]完全被[j,i]包含的时候才会产生花费.也就是说,问题转化成给定数轴上一堆带权区间,查询被某一个区间完全包含的所有区间的总权值。
某一个区间被另一个区间完全包含,当且仅当这个区间的左右端点都被包含。所以查询可以等价于:对于右端点在查询范围内的区间,有多少对应的左端点大于查询范围的左端点。我们对每个位置建一棵权值线段树,存储从第一个位置到这个位置的所有区间的左端点,在对应的左端点的位置插入这个区间的权值。总之这个cost可以用主席树logn求。
然后考虑分层转移。每次由设置了i个基站的dp数组推出一共设置i+1个基站的DP数组。
接下来我们发现,这个东西有决策单调性(别问我怎么证,我打的表...),于是上单调栈。然后!考试的时候我的DP数组两维的大小开反了,成功炸掉80分。交换数组的两维大小之后A了,真是悲伤的故事….
标算到底是啥
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
template<typename T>inline void read(T &x){
char ch;while(ch=getchar(),!isdigit(ch));
x=ch-'';
while(ch=getchar(),isdigit(ch))x=x*+ch-'';
} const int maxn=,maxk=;
int f[maxk][maxn];
int d[maxn],c[maxn],s[maxn],w[maxn];
int l[maxn],r[maxn],seq[maxn];
int n,k;
struct node{
int sum;node *lch,*rch;
}t[maxn*];int cnt=;//11mb
node *root[maxn];
void Insert(node *rt1,node* &rt2,const int &k,const int &w,int l,int r){
++cnt;rt2=t+cnt;
if(l==r){
rt2->sum=rt1->sum+w;
return;
}
int mid=(l+r)>>;
if(k<=mid){
rt2->rch=rt1->rch;
Insert(rt1->lch,rt2->lch,k,w,l,mid);
}else{
rt2->lch=rt1->lch;
Insert(rt1->rch,rt2->rch,k,w,mid+,r);
}
rt2->sum=rt2->lch->sum+rt2->rch->sum;
}
void build_all(){
root[]=t+;root[]->lch=root[]->rch=t+;
int cur=;
for(int i=;i<=n;++i){
if(r[seq[i]]>cur){
while(cur!=r[seq[i]]){
root[cur+]=root[cur];
++cur;
}
}
Insert(root[cur],root[cur],l[seq[i]],w[seq[i]],,n);
}
for(int i=cur+;i<=n;++i)root[i]=root[i-];
}
int query(node *rt1,node *rt2,int k,int l,int r){//有多少数字比k大
// printf("q%d %d",l,r);
if(l>k){
return rt2->sum-rt1->sum;
}
int mid=(l+r)>>;
if(k<mid)return query(rt1->lch,rt2->lch,k,l,mid)+query(rt1->rch,rt2->rch,k,mid+,r);
else return query(rt1->rch,rt2->rch,k,mid+,r);
}
int qsum(int l,int r){//l,r各自有一个基站
return query(root[l],root[r-],l,,n);
}
bool cmp(const int &a,const int &b){
return r[a]<r[b];
}
bool cmp2(const int &a,const int &b){
return l[a]<l[b];
}
int s1[maxn],s2[maxn];
int st[maxn];int top=,mk=;//st:单调栈
int L[maxn],R[maxn];//每个决策对应的左右区间
inline bool inside(int i,int x){
return L[x]<=i&&i<=R[x];
}
int binary(int l,int r,int x,int a,int b){//在f[l]..f[r]找出第一个决策b比决策a优的位置
while(l<=r){
int mid=(l+r)>>;
if(f[x-][a]+qsum(a,mid)<f[x-][b]+qsum(b,mid))l=mid+;
else r=mid-;
}
return r+;
}
void work(int x){//x-1 -> x
//使用x个基站,那么至少已经建到了x
top=;mk=;
/* st[++top]=x-1;mk=1;
L[top]=x;R[top]=n;*/
for(int i=x;i<=n;++i){
while(top!=&&(i-)<L[top]&&((f[x-][st[top]]+qsum(st[top],L[top]))>(f[x-][i-]+qsum(i-,L[top])))){
top--;
}
//binary
if(top!=){
int tmp;
if(i-<L[top])tmp=binary(L[top],R[top],x,st[top],i-);
else tmp=binary(i,R[top],x,st[top],i-);
R[top]=tmp-;
}
st[++top]=i-;L[top]=R[top-]+;R[top]=n;
while(!inside(i,mk))mk++;
f[x][i]=c[i]+f[x-][st[mk]]+qsum(st[mk],i);//printf("%d %d %d %d %d\n",mk,x-1,st[mk],x,i);
}
}
int main(){
// freopen("base.in","r",stdin);
// freopen("base.out","w",stdout);
memset(f,0x7f,sizeof(f));
read(n);read(k);
for(int i=;i<=n;++i){
read(d[i]);
}
for(int i=;i<=n;++i){
read(c[i]);
}
for(int i=;i<=n;++i){
read(s[i]);
l[i]=lower_bound(d+,d+n+,d[i]-s[i])-d;r[i]=upper_bound(d+,d+n+,d[i]+s[i])-d-;
}
for(int i=;i<=n;++i)read(w[i]);
for(int i=;i<=n;++i)seq[i]=i;
int sum=;
for(int i=;i<=n;++i){
sum+=w[i];
}
if(k==){
printf("%d\n",sum);
}else{
sort(seq+,seq+n+,cmp);
build_all();
for(int i=;i<=n;++i){
s1[r[i]]+=w[i];
}
for(int i=;i<=n;++i){
s1[i]+=s1[i-];
}sort(seq+,seq+n+,cmp2);
for(int i=;i<=n;++i){
s2[l[i]]+=w[i];
}
for(int i=n;i>=;--i){
s2[i]+=s2[i+];
}
int ans=sum;
for(int i=;i<=n;++i){
f[][i]=s1[i-]+c[i];
int tmp=f[][i]+s2[i+];
if(tmp<ans)ans=tmp;
}
for(int j=;j<=k&&j<=n;++j){
work(j);
}
for(int i=;i<=n;++i){
for(int j=;j<=k&&j<=n;++j){
if(f[j][i]+s2[i+]<ans)ans=f[j][i]+s2[i+];
}
}
printf("%d\n",ans);
}//while(1);
// fclose(stdin);fclose(stdout);
return ;
}
bzoj1835[ZJOI2010]base基站选址的更多相关文章
- BZOJ1835: [ZJOI2010]base 基站选址【线段树优化DP】
Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...
- BZOJ1835: [ZJOI2010]base 基站选址(线段树优化Dp)
Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...
- bzoj1835: [ZJOI2010]base 基站选址
新的一年新的开始.结果第一题就用了几乎一周.而且感觉很不好. 先检讨自己.最近写的各种数据结构模板基本没打过出来,各种细节崩盘,这题线段树都居然被lazy标记没清零卡挂. DP还是博大精深,这东西感觉 ...
- 2018.11.06 bzoj1835: [ZJOI2010]base 基站选址(线段树优化dp)
传送门 二分出每个点不需要付www贡献的范围,然后可以推出转移式子: f[i][j]=f[i−1][k]+value(k+1,j)+c[i]f[i][j]=f[i-1][k]+value(k+1,j) ...
- 【BZOJ1835】[ZJOI2010]base 基站选址 线段树+DP
[BZOJ1835][ZJOI2010]base 基站选址 Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯 ...
- BZOJ 1835: [ZJOI2010]base 基站选址 [序列DP 线段树]
1835: [ZJOI2010]base 基站选址 题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立 ...
- bzoj 1835: [ZJOI2010]base 基站选址
Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...
- bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1835 [题意] 有n个村庄,每个村庄位于d[i],要求建立不多于k个基站,在第i个村庄 ...
- BZOJ 1835 [ZJOI2010]base 基站选址:线段树优化dp
传送门 题意 有 $ n $ 个村庄在一排直线上,现在要建造不超过 $ K $ 个通讯基站,基站只能造在村庄处. 第 $ i $ 个村庄距离第 $ 1 $ 个村庄的距离为 $ D_i $ .在此建造基 ...
随机推荐
- Appfuse:起步
在众多开源的Java开源CMS中探索了很久,终于选定了appfuse,理由如下: 1. 简洁:只搭建了框架,没有做多余的事 2. 完成了基本的用户管理:用户.角色.权限的定义很清晰 3. 符合预期的架 ...
- jacascript中的原型链以原型
今地铁上看慕课网js课程,又学习到关于原型的一些知识,记录如下.如有偏差欢迎指正: 三张图要连起来看哦~ 图解: 1.创建一个函数foo. 2.运用函数的prototype属性(这个属性就是实例对象的 ...
- AEAI Portal V3.5.4升级说明,门户集成平台
1 总体说明 本次升级是AEAI Portal的一次重要升级,主要扩展了开发社区(论坛).移动门户功能,同时修正一些功能BUG等,具体内容如下: 2 升级内容 功能扩展: 扩展开发社区导航 扩展移动门 ...
- GConf error:Failed to contact configuration server
Linux系统运行一直正常,但是图形界面使用root账号登录时遇到下面错误,第一次遇到这么怪异的状况 具体错误信息如下所示: GConf error:Failed to contact configu ...
- Linux Bond 技术学习资料
Bond 技术原理 Bond 就是将多块网卡虚拟成为一块网卡的技术,通过 bond 技术让多块网卡看起来是一个单独的以太网接口设备并具有相同的 IP 地址. Bond 的原理是网卡在混杂 (promi ...
- 为什么忘记commit也会造成select查询的性能问题
今天遇到一个很有意思的问题,一个开发人员反馈在测试服务器ORACLE数据库执行的一条简单SQL语句非常缓慢,他写的一个SQL没有返回任何数据,但是耗费了几分钟的时间.让我检查分析一下原因,分析解决过后 ...
- SSH之免密码登录
我的虚拟机: 192.168.91.130 test1 192.168.91.131 test2 192.168.91.132 test3 1.首先在test1上生成秘钥对 之后会生成.shh/ ...
- [Java入门笔记] Java语言基础(三):运算符
简介 运算符是一种特殊的符号,运算符是通过一定的运算规则操作一个或多个操作数,并生成结果的特定符号,运算符和操作数的有效组合称为表达式. Java中运算符主要分为以下几类: 赋值运算符 算术运算符 关 ...
- java实现批量下载百度图片搜索到的图片
就是写的个小程序,用于记录一下,方便后续查看,首先感谢下面这个博客,从这篇文章衍生的吧,大家可以学习下: http://www.cnblogs.com/lichenwei/p/4610298.html ...
- 【小白的CFD之旅】10 敲门实例
按黄师姐的说法,做好第一个案例很重要.第一个案例既可以帮助理解CFD的工作流程,还可以帮助熟悉软件的操作界面. 黄师姐推荐的入门案例来自于ANSYS官方提供的培训教程,是一个关于交叉管内流动混合的案例 ...