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。

解题思路:

一道好题,不过我没时间写题解了,暂且咕在这里。

代码:

 #include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define lll spc<<1
#define rrr spc<<1|1
typedef long long lnt;
const int N=;
struct trnt{
lnt lzt;
lnt minv;
}tr[N<<],stt;
int n,k;
lnt w[N],s[N],d[N],c[N];
int lp[N],rp[N];
lnt dp[N];
std::vector<lnt>lim[N];
void pushup(int spc)
{
tr[spc].minv=std::min(tr[lll].minv,tr[rrr].minv);
return ;
}
void add(int spc,lnt v)
{
tr[spc].minv+=v;
tr[spc].lzt+=v;
return ;
}
void pushdown(int spc)
{
if(tr[spc].lzt)
{
add(lll,tr[spc].lzt);
add(rrr,tr[spc].lzt);
tr[spc].lzt=;
}
return ;
}
void build(int l,int r,int spc)
{
tr[spc]=stt;
if(l==r)
{
tr[spc].minv=dp[l];
return ;
}
int mid=(l+r)>>;
build(l,mid,lll);
build(mid+,r,rrr);
pushup(spc);
return ;
}
void update(int l,int r,int ll,int rr,int spc,lnt v)
{
if(l>rr||ll>r)
return ;
if(ll<=l&&r<=rr)
{
add(spc,v);
return ;
}
int mid=(l+r)>>;
pushdown(spc);
update(l,mid,ll,rr,lll,v);
update(mid+,r,ll,rr,rrr,v);
pushup(spc);
return ;
}
lnt query(int l,int r,int ll,int rr,int spc)
{
if(l>rr||ll>r)
return 0x3f3f3f3f;
if(ll<=l&&r<=rr)
return tr[spc].minv;
int mid=(l+r)>>;
pushdown(spc);
return std::min(query(l,mid,ll,rr,lll),query(mid+,r,ll,rr,rrr));
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)
scanf("%lld",&d[i]);
for(int i=;i<=n;i++)
scanf("%lld",&c[i]);
for(int i=;i<=n;i++)
scanf("%lld",&s[i]);
for(int i=;i<=n;i++)
scanf("%lld",&w[i]);
for(int i=;i<=n;i++)
{
lp[i]=rp[i]=i;
int l=,r=i-;
while(l<=r)
{
int mid=(l+r)>>;
if(d[i]-d[mid]<=s[i])
{
r=mid-;
lp[i]=mid;
}else
l=mid+;
}
l=i+,r=n;
while(l<=r)
{
int mid=(l+r)>>;
if(d[mid]-d[i]<=s[i])
{
l=mid+;
rp[i]=mid;
}else
r=mid-;
}
lim[rp[i]].push_back(i);
}
lnt sum=;
for(int i=;i<=n;i++)
{
dp[i]=c[i]+sum;
for(int j=;j<lim[i].size();j++)
sum+=w[lim[i][j]];
}
lnt ans=sum;
for(int i=;i<=k;i++)
{
build(,n,);
for(int j=;j<=n;j++)
{
dp[j]=query(,n,,j-,)+c[j];
for(int o=;o<lim[j].size();o++)
update(,n,,lp[lim[j][o]]-,,w[lim[j][o]]);
}
ans=std::min(ans,query(,n,,n,));
}
printf("%lld\n",ans);
return ;
}

BZOJ1835: [ZJOI2010]base 基站选址(线段树优化Dp)的更多相关文章

  1. 【BZOJ1835】[ZJOI2010]base 基站选址 线段树+DP

    [BZOJ1835][ZJOI2010]base 基站选址 Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯 ...

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

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

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

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

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

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

  5. BZOJ 1835 [ZJOI2010]基站选址 (线段树优化DP)

    题目大意:略 洛谷题面传送门 BZOJ题面传送门 注意题目的描述,是村庄在一个范围内去覆盖基站,而不是基站覆盖村庄,别理解错了 定义$f[i][k]$表示只考虑前i个村庄,一共建了$k$个基站,最后一 ...

  6. 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中间的不能被满足的村庄的赔偿金之 ...

  7. bzoj1835[ZJOI2010]base基站选址

    据说正解是什么线段树优化DP,但是作为脑子有坑选手,我们需要5k的做法: 主席树+决策单调性..... F[m][i]表示已经放置了m个基站,第m个基站放置在第i个村庄,第i个村庄及之前的村庄的总最少 ...

  8. 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) ...

  9. bzoj1835: [ZJOI2010]base 基站选址

    新的一年新的开始.结果第一题就用了几乎一周.而且感觉很不好. 先检讨自己.最近写的各种数据结构模板基本没打过出来,各种细节崩盘,这题线段树都居然被lazy标记没清零卡挂. DP还是博大精深,这东西感觉 ...

随机推荐

  1. 51Nod 最长的循环节(打表预处理)

    正整数k的倒数1/k,写为10进制的小数如果为无限循环小数,则存在一个循环节,求<=n的数中,倒数循环节长度最长的那个数,假如存在多个最优的答案,输出所有答案中最大的那个数.     1/6= ...

  2. [BJWC2011]禁忌 AC 自动机 概率与期望

    #include<cstdio> #include<algorithm> #include<cstring> #include<string> #inc ...

  3. keytool常用操作

    keytool 秘钥需要存储在秘钥库中,秘钥库可以理解为一个存储了一个或多个秘钥的文件.一个秘钥库可以存储多个密钥对,每个秘钥对你都需要给他们取一个名字. D:\software\Java\jdk1. ...

  4. 【redis】redis命令集

    参考资料: http://www.cnblogs.com/woshimrf/p/5198361.html

  5. 题解 P2610 【[ZJOI2012]旅游】

    今天模拟赛考了这道题,那就来水一篇题解吧...(话说提高组模拟赛考什么省选题啊??) 这道题要我们求一条线段最多能经过的三角形数量. 回想小学学过的奥数,老师告诉过我们这样一件事:`点无大小 线无粗细 ...

  6. POJ 1723 SOLDIERS

    SOLDIERS Time Limit: 1000ms Memory Limit: 10000KB This problem will be judged on PKU. Original ID: 1 ...

  7. STL使用————SET&MULTISET

    SET函数的基本用法 by hhl 使用set的好处 1. 当增加元素后,集合会自动删重并从小到大排列(时间比快排还快)2. 相当于一棵伸展树(能快速求出后继) 使用基础 #include<se ...

  8. BZOJ 1012 单调队列+二分

    思路: 维护一个单减的序列 序号是单增的 每回二分查找第一个比询问的大的值 我手懒 用得lower_bound //By SiriusRen #include <cstdio> #incl ...

  9. SGU 461 Wiki Lists dfs

    不难的题,不过蛮有意思的dfs #include <iostream> #include <cstdio> #include <fstream> #include ...

  10. Python正则表达式初识(九)

    继续分享Python正则表达式的基础知识,今天给大家分享的特殊字符是[\u4E00-\u9FA5],这个特殊字符最好能够记下来,如果记不得的话通过百度也是可以一下子查到的. 该特殊字符是固定的写法,其 ...