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. S-Nim POJ - 2960 Nim + SG函数

    Code: #include<cstdio> #include<algorithm> #include<string> #include<cstring> ...

  2. css columns 与overflow结合的问题

    想实现上面这样分栏,并且溢出滚动的效果.可是自己下面的代码只能得到横向滚动条.觉得出现这个情况觉得还蛮有意思的,特地记录一下. <li v-for="(item,index) in s ...

  3. hiho 1055 刷油漆 树形dp

    一个简单的树上的背包问题. 代码: #include <iostream> #include <cstdio> #include <cstring> #includ ...

  4. PKU 3311 Hie with the Pie 状态DP

    Floyd + 状态DP Watashi的板子 #include <cstdio> #include <cstring> #include <iostream> # ...

  5. PatentTips - Supporting heterogeneous virtualization

    BACKGROUND A virtual machine (VM) architecture logically partitions a physical machine, such that th ...

  6. HDU 5373(2015多校7)-The shortest problem(模拟%11)

    题目地址:pid=5373">HDU 5373 题意:给你一个数n和操作次数t,每次操作将n的各位数之和求出来放在n的末尾形成新的n,问t次操作后得到的n能否够被11整除. 思路:就是 ...

  7. oracle之ROWNUM的查询应用

    1 在ORACLE数据库中,ROWNUM是ORACLE数据库为查询结果加入的一个伪列.起始值为1.经常使用来处理查询结果的分页. 2 因为ROWNUM的特殊性,使用时候一般是分三层: 第一层:先进行查 ...

  8. javascript对象如何使用

    javascript对象如何使用 一.总结 一句话总结:JavaScript 中的所有事物都是对象:字符串.数值.数组.函数... 因为函数是对象,所以自定义对象的创建中有种方法就是函数 1.js中的 ...

  9. 123.static静态函数与类模板

    #include <iostream> using namespace std; //静态函数没有this指针,无需创建对象就可以直接调用 template<class T> ...

  10. 99.重载[] * -> ->*

    #include "mainwindow.h" #include <QApplication> #include <QPushButton>> //重 ...