原题传送门:P2604 [ZJOI2010]基站选址

看一眼题目,变知道这题一定是dp

设f[i][j]表示在第i个村庄修建第j个基站且不考虑i+1~n个村庄的最小费用

可以得出f[i][j] = Min(f[k][j - 1] + cost[k][i] ) + c[i] (j - 1 <= k < i)

其中cost[k][i]表示i~k之间没有基站所需要的费用

计算复杂度O(N),加上循环,总复杂度O(N^2 K)

看一下数据范围K <= N,K <= 100 , N <= 20000

真棒,TLE

考虑如何优化

首先,我们发现之前的转移方程可以去掉一维j,实际上只要在最外层枚举j就可以了

f[i] = Min( f[k] + cost[k][i] ) + c[i] (j - 1 <= k < i)

主要的时间浪费在计算cost上

我们要找方法来优化

对于任意一个村庄i,记它所能被覆盖的左右边界st[i],ed[i](最左端、最右端可以覆盖到i的基站位置,可用二分查找处理)

然后在用邻接表记录ed值为i的村庄有哪些,在这些村庄之前建立基站就覆盖不到i了。

这样当我们推导i + 1时,若从村庄1~st[k] - 1(ed[k] = i)转移过来则必定要赔偿村庄k的费用,我们就可以考虑用线段树来维护f[k] + cost[k][i]的值

即在区间[1, st[k] - 1]加上村庄k的费用,而转移即在区间[1, i - 1]找f[k] + cost[k][i]的最小值,总复杂度为O(N log N K)。

#pragma GCC optimize("O3")
#include <bits/stdc++.h>
#define N 20005
#define inf 0x3f3f3f3f
using namespace std;
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline int Min(register int a,register int b)
{
return a<b?a:b;
}
int D[N],C[N],S[N],W[N],lr[N],rr[N],f[N];
vector<int> vq[N];
int ql,qr;
struct Segment_tree{
int minn[N<<2],tag[N<<2];
inline void pushup(register int x)
{
minn[x]=Min(minn[x<<1],minn[x<<1|1]);
}
inline void build(register int x,register int l,register int r)
{
tag[x]=0;
if(l==r)
{
minn[x]=f[l];
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
pushup(x);
}
inline void maintain(register int x,register int l,register int r)
{
if(l!=r)
pushup(x);
minn[x]+=tag[x];
}
inline void update(register int x,register int l,register int r,register int v)
{
if(ql<=l&&qr>=r)
tag[x]+=v;
else
{
int mid=(l+r)>>1;
if(ql<=mid)
update(x<<1,l,mid,v);
if(qr>mid)
update(x<<1|1,mid+1,r,v);
}
maintain(x,l,r);
}
inline int query(register int x,register int l,register int r,register int v)
{
if(ql<=l&&qr>=r)
return minn[x]+v;
int ret=inf,mid=(l+r)>>1;
if(ql<=mid)
ret=Min(ret,query(x<<1,l,mid,v+tag[x]));
if(qr>mid)
ret=Min(ret,query(x<<1|1,mid+1,r,v+tag[x]));
return ret;
}
}T;
int main()
{
int n=read(),k=read();
for(register int i=2;i<=n;++i)
D[i]=read();
for(register int i=1;i<=n;++i)
C[i]=read();
for(register int i=1;i<=n;++i)
S[i]=read();
for(register int i=1;i<=n;++i)
W[i]=read();
++n,++k;
D[n]=inf;
for(register int i=1;i<=n;++i)
{
lr[i]=lower_bound(D+1,D+n+1,D[i]-S[i])-D;
rr[i]=lower_bound(D+1,D+n+1,D[i]+S[i])-D;
if(D[i]+S[i]<D[rr[i]])
--rr[i];
vq[rr[i]].push_back(i);
}
int ans=inf;
for(register int j=1;j<=k;++j)
{
if(j==1)
{
int tot=0;
for(register int i=1;i<=n;++i)
{
f[i]=tot+C[i];
for(register int tmp=0;tmp<vq[i].size();++tmp)
tot+=W[vq[i][tmp]];
}
ans=Min(ans,f[n]);
continue;
}
T.build(1,1,n);
for(register int i=1;i<=n;++i)
{
ql=1,qr=i-1;
int add=qr?T.query(1,1,n,0):0;
f[i]=add+C[i];
for(register int tmp=0;tmp<vq[i].size();++tmp)
{
ql=1,qr=lr[vq[i][tmp]]-1;
if(qr>0)
T.update(1,1,n,W[vq[i][tmp]]);
}
}
ans=Min(ans,f[n]);
}
printf("%d",ans);
return 0;
}

【题解】Luogu P2605 [ZJOI2010]基站选址的更多相关文章

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

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

  2. luogu P2605 [ZJOI2010]基站选址

    luogu 先考虑朴素dp,设\(f_{i,j}\)表示在第\(i\)个村庄放了基站,一共放了\(j\)次,且只考虑前面村庄影响的答案.这里可以把\(j\)放在外面枚举,然后从\(f_{k,j-1}( ...

  3. P2605 [ZJOI2010]基站选址

    题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范 ...

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

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

  5. 题解 [ZJOI2010]基站选址

    题解 [ZJOI2010]基站选址 题面 解析 首先考虑一个暴力的DP, 设\(f[i][k]\)表示第\(k\)个基站设在第\(i\)个村庄,且不考虑后面的村庄的最小费用. 那么有\(f[i][k] ...

  6. 【LG2605】[ZJOI2010]基站选址

    [LG2605][ZJOI2010]基站选址 题面 洛谷 题解 先考虑一下暴力怎么写,设\(f_{i,j}\)表示当前\(dp\)到\(i\),且强制选\(i\),目前共放置\(j\)个的方案数. 那 ...

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

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

  8. bzoj 1835/luogu P2605 : [ZJOI2010]base 基站选址

    题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范 ...

  9. 题解 P2605 【[ZJOI2010]基站选址】(From luoguBlog)

    线段树优化dp 数组f[i][j]表示在前i个村庄内,第j个基站建在i处的最小费用 根据交线牛逼法和王鹤松式可得方程 f[i][j]=min(f[k][j−1]+cost(k,i)) cost(k,i ...

随机推荐

  1. VS中去掉空格虚点

    Ctrl + R+W 可以在VS中添加或移除 空格虚点.

  2. vue父子组件写法,数据传递,顺便封装 element-ui的弹窗组建

    父组件如下: <template> <div class="print"> <el-button @click="bbclick" ...

  3. AutoMapper.Mapper.CreateMap报“System.NullReferenceException: 未将对象引用设置到对象的实例。”异常复现

    >>Agenda: >>Ⅰ.国庆假期问题出现 >>Ⅱ.双休日异常再次出现 >>Ⅲ.排障 >>Ⅳ.异常复盘 >>Ⅴ.修复后监测 & ...

  4. arrow

    1.c++(OOGP) 与数据结构与算法 1.一定要有一门自己比较熟悉的语言. 我由于使用C++比较多,所以简历上只写了C++.C++的特性要了解,C++11要了解一些,还有STL.面试中常遇到的一些 ...

  5. 47.HTML---frame,iframe,frameset之间的关系与区别

    iframe 是在html页面内嵌入框架 框架内可以连接另一个页面, 如 <html> <head></head> <body> <iframe ...

  6. nodejs发送邮件

    这里我主要使用的是 nodemailer 这个插件 第一步 下载依赖 cnpm install nodemailer --save 第二步 建立email.js 'use strict'; const ...

  7. vue中点击复制粘贴功能

    1.下载clipboard.js cnpm install clipboard --save 2.引入,可以在mian.js中全局引入也可以在单个vue中引入 import Clipboard fro ...

  8. Spark以yarn-client提交任务时报错超时,Connection to 192.168.. /has been quiet forms while there are outstanding requests. Failed to send RPC.....

    报错信息如上,具体是运行FusionInsight给的样例SparkPi,在local环境下是可以的,但是如果以yarn-client模式就会卡住,然后120s以后超时,其实以yarn-cluster ...

  9. javaweb + tomcat + 部署 + 域名绑定 + 默认首页

    ①:把javaweb项目打包成war(不会的自行百度) ②:把war拷贝到服务器的tomcat里面的webapps下 ③:到bin文件夹下.bat文件启动tomcat,启动后会解压war包 ⑤:解压后 ...

  10. caffe在Linux下生成均值文件

    参照博客:https://blog.csdn.net/sinat_28519535/article/details/78533319