新的一年新的开始。结果第一题就用了几乎一周。而且感觉很不好。

先检讨自己。最近写的各种数据结构模板基本没打过出来,各种细节崩盘,这题线段树都居然被lazy标记没清零卡挂。

DP还是博大精深,这东西感觉没学好啊。

---------------------------------------

很容易想DP的。主要是怎么D,一开始我的想法是f[i][j]表示到第1~i个点被覆盖,建了j个站。但是这题的覆盖是关于当前点的,什么意思,就是可能k1点在k2点前面,但k1受到了很后面的k3覆盖不用补偿,而k2却要,这样就gg。

那改一下,f[i][j]表示在第i个点建站,建了j个。DP方程就是这样的。

f[i][j]=max(f[i][j],f[k][j-1]+(k~x中没被覆盖的点的w和))+c[i];

而这个时间复杂度O(n^2*k)必挂。

膜了题解才发现,这题是一道经典的线段树维护DP,线段树负责区间修改和区间查询。时间复杂度就可以降到O(nlogn*k)

显然维护的就是f[k][j]+(k~x中没被覆盖的点的w和),按照1~k下标即可。

那么难点在于(k~x中没被覆盖的点的w和)

考虑四个点k,p,x,x+1

k表示被继承点,x、x+1可以继承k(当然还有其他,方便起见就不罗列了)

那么对于k和x,若x继承k,那么k、x之间肯定没有点建站,那么f[k][j-1]+(k~x中没被覆盖的点的w和)假设已经预处理了,再假设x这个站建下来,x覆盖了p,并且p和x的距离就是p能被影响的最远距离

然后对于x+1的话,如果x+1要继承k,那么p必定没有覆盖,因为x已经是最远的点了,x+1无论如何也覆盖不了。

由此,我们二分预处理出一个点往后最远可以影响到它的点,然后用邻接表把最远距离相等的点记录,那么当枚举x到x+1的时候,就可以快速把那些与p情况一样的点的w加上就行了。

那么还有一个问题,k也可以覆盖到后面的点呀,假如x+1覆盖不了,但k覆盖得了,那也不应该把w加上。

解决方法是再二分预处理出一个点往前最远可以影响到它的点,当区间修改的时候,就修改那些在它前面的,影响不到它的点,这些点就是1~L[x]-1

PS:实际的操作中j没必要留一维。当j-1的信息记入线段树中时,f就没用了,直接在上面更新

还有就是n++,m++,在最后多弄一个d=inf,c=0,s=0,的结束点,由于s=0,所以m++的那个站肯定建在n+1位置,又由于d=inf,不影响其他原来的点,此举旨在将最后答案确定到n+1位置方便取最大,因为对于这个问题,建站不一定要建在n位置,同时判断前面的位置能否覆盖后面也很麻烦。

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<cstdlib>
  5. #include<algorithm>
  6. #include<cmath>
  7. using namespace std;
  8. typedef long long LL;
  9. const int inf=;
  10.  
  11. int n,m;
  12. int d[],c[],w[];
  13. int L[],R[];//表示最远可以影响到当前点的位置
  14. LL f[];
  15.  
  16. struct line
  17. {
  18. int to,next;
  19. }l[];int llen,last[];
  20. void ins(int x,int y)
  21. {
  22. llen++;l[llen].to=y;
  23. l[llen].next=last[x];last[x]=llen;
  24. }
  25.  
  26. int fhj(int k)
  27. {
  28. int l=,r=n,ret;
  29. while(l<=r)
  30. {
  31. int mid=(l+r)/;
  32. if(d[mid]>=k)r=mid-, ret=mid;
  33. else l=mid+;
  34. }
  35. return ret;
  36. }
  37. int fqq(int k)
  38. {
  39. int l=,r=n,ret;
  40. while(l<=r)
  41. {
  42. int mid=(l+r)/;
  43. if(k>=d[mid])l=mid+, ret=mid;
  44. else r=mid-;
  45. }
  46. return ret;
  47. }
  48. void sc()
  49. {
  50. scanf("%d%d",&n,&m);n++;m++;
  51. llen=;memset(last,,sizeof(last));
  52.  
  53. d[]=;
  54. for(int i=;i<n;i++)scanf("%d",&d[i]);
  55. d[n]=inf;
  56. for(int i=;i<n;i++)scanf("%d",&c[i]);
  57. c[n]=;
  58. int x;
  59. for(int i=;i<n;i++)
  60. scanf("%d",&x), L[i]=fhj(d[i]-x), R[i]=fqq(d[i]+x), ins(R[i],i);
  61. L[n]=n;R[n]=n;
  62. for(int i=;i<n;i++)scanf("%d",&w[i]);
  63.  
  64. }
  65.  
  66. //----------sc----------------------
  67.  
  68. struct seq
  69. {
  70. int l,r,lc,rc;LL c,lazy;
  71. }tr[];int trlen;
  72. void bt(int l,int r)
  73. {
  74. trlen++;int now=trlen;
  75. tr[now].l=l;tr[now].r=r;
  76. tr[now].c=;tr[now].lazy=;
  77. tr[now].lc=tr[now].rc=-;
  78. if(l<r)
  79. {
  80. int mid=(l+r)/;
  81. tr[now].lc=trlen+;bt(l,mid);
  82. tr[now].rc=trlen+;bt(mid+,r);
  83. tr[now].c=min(tr[tr[now].lc].c,tr[tr[now].rc].c);
  84. }
  85. else tr[now].c=f[l];
  86. }
  87. LL findmin(int now,int l,int r)
  88. {
  89. if(tr[now].l==l&&tr[now].r==r){return tr[now].c;}
  90. int lc=tr[now].lc,rc=tr[now].rc;
  91. int mid=(tr[now].l+tr[now].r)/;
  92.  
  93. if(tr[now].lazy!=)
  94. {
  95. tr[lc].c+=tr[now].lazy;
  96. tr[rc].c+=tr[now].lazy;
  97. tr[lc].lazy+=tr[now].lazy;
  98. tr[rc].lazy+=tr[now].lazy;
  99. tr[now].lazy=;
  100. }
  101.  
  102. if(r<=mid)return findmin(lc,l,r);
  103. else if(mid+<=l)return findmin(rc,l,r);
  104. else return min(findmin(lc,l,mid),findmin(rc,mid+,r));
  105. }
  106. void change(int now,int l,int r,int k)
  107. {
  108. if(l>r)return ;
  109. if(tr[now].l==l&&tr[now].r==r){tr[now].c+=k;tr[now].lazy+=k;return ;}
  110. int lc=tr[now].lc,rc=tr[now].rc;
  111. int mid=(tr[now].l+tr[now].r)/;
  112.  
  113. if(tr[now].lazy!=)
  114. {
  115. tr[lc].c+=tr[now].lazy;
  116. tr[rc].c+=tr[now].lazy;
  117. tr[lc].lazy+=tr[now].lazy;
  118. tr[rc].lazy+=tr[now].lazy;
  119. tr[now].lazy=;
  120. }
  121.  
  122. if(r<=mid)change(lc,l,r,k);
  123. else if(mid+<=l)change(rc,l,r,k);
  124. else change(lc,l,mid,k), change(rc,mid+,r,k);
  125.  
  126. tr[now].c=min(tr[lc].c,tr[rc].c);
  127. }
  128.  
  129. //-------seq----------------
  130.  
  131. int main()
  132. {
  133. freopen("base.in","r",stdin);
  134. freopen("base.out","w",stdout);
  135. sc();
  136.  
  137. int tre=;
  138. for(int i=;i<=n;i++)
  139. {
  140. f[i]=tre+c[i];
  141. for(int k=last[i];k;k=l[k].next)
  142. {
  143. int to=l[k].to;
  144. tre+=w[to];
  145. }
  146. }
  147. //yu j=1
  148. LL ans=f[n];
  149. for(int j=;j<=m;j++)
  150. {
  151. trlen=;bt(,n);
  152. for(int i=j;i<=n;i++)
  153. {
  154. f[i]=findmin(,j-,i-)+c[i];
  155. for(int k=last[i];k;k=l[k].next)
  156. {
  157. int to=l[k].to;
  158. change(,,L[to]-,w[to]);
  159. }
  160. }
  161. ans=min(ans,f[n]);
  162. }
  163. printf("%lld\n",ans);
  164. return ;
  165. }

bzoj1835: [ZJOI2010]base 基站选址的更多相关文章

  1. bzoj1835[ZJOI2010]base基站选址

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

  2. BZOJ1835: [ZJOI2010]base 基站选址【线段树优化DP】

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

  3. BZOJ1835: [ZJOI2010]base 基站选址(线段树优化Dp)

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

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

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

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

  6. BZOJ 1835: [ZJOI2010]base 基站选址 [序列DP 线段树]

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

  7. bzoj 1835: [ZJOI2010]base 基站选址

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

  8. bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1835 [题意] 有n个村庄,每个村庄位于d[i],要求建立不多于k个基站,在第i个村庄 ...

  9. BZOJ 1835 [ZJOI2010]base 基站选址:线段树优化dp

    传送门 题意 有 $ n $ 个村庄在一排直线上,现在要建造不超过 $ K $ 个通讯基站,基站只能造在村庄处. 第 $ i $ 个村庄距离第 $ 1 $ 个村庄的距离为 $ D_i $ .在此建造基 ...

随机推荐

  1. PS学习笔记(04)

    Photoshop滤镜的安装 Photoshop滤镜的默认格式为.8bf(也有些滤镜为exe格式的可执行文件),如果你下载的是压缩包,请解压之后再安装. 方法一: 如果你下载的滤镜为exe的可执行文件 ...

  2. PyMySQL操作mysql数据库(py3必学)

    一,安装PyMySQL Python是编程语言,MySQL是数据库,它们是两种不同的技术:要想使Python操作MySQL数据库需要使用驱动.这里选用PyMySQL驱动. 安装方式还是使用pip命令. ...

  3. HDU 4821 字符串hash

    题目大意: 希望找到连续的长为m*l的子串,使得m个l长的子串每一个都不一样,问能找到多少个这样的子串 简单的字符串hash,提前预处理出每一个长度为l的字符串的hash值 #include < ...

  4. hust 1017 dancing links 精确覆盖模板题

    最基础的dancing links的精确覆盖题目 #include <iostream> #include <cstring> #include <cstdio> ...

  5. 关闭spring整合kafka时,消费者一直打印kafka日志

    在log4j.properties中添加如下代码 log4j.logger.org.apache.kafka.common.metrics.Metrics=OFF log4j.logger.org.a ...

  6. 匿名函数--lambda函数

    匿名函数 匿名函数:为了解决一些功能很简单的需求而设计的一句话函数 (python对匿名函数支持有限,只有一些简单的条件下可以用匿名函数) 匿名函数固定格式: func = lambda *args: ...

  7. Swift 了解

    本篇仅于个人小记,记录个人不熟悉的知识点儿.如若要了解更全,请前往如下网址:http://www.runoob.com/swift/swift-arrays.html 1.Swift 标记 分号:Sw ...

  8. 2015轻院校赛 D 社交网络(排列组合)

    http://acm.zznu.edu.cn/problem.php?id=1964 题目描述 输入 输出 样例输入 2 2 1 0 1 1 0 3 1 0 1 1 1 0 1 1 1 0 样例输出 ...

  9. linux下查看哪个进程占用内存多

    1.用top命令 1.top top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器 可以直接使用top命令后,查看%MEM的内容.可以 ...

  10. ext.net 2.5 导出excel的使用方法

    前台页面的导入,导出 <ext:FileUploadField ID="FileUploadField_Import" runat="server" Bu ...