题目描述





分析

  • 对于 \(Subtask\ 1\),可以写一个 \(n^3\) 的 \(DP\),\(f[i][j]\) 代表第 \(i\) 个建筑高度为 \(j\) 时的最小花费,随便转移即可

    时间复杂度 \(O(n \times h^2)\)
  • 对于 \(Subtask\ 2\),我们沿用 \(Subtask\ 1\)的思路,记录前缀后缀 \(min\),将复杂度优化至 \(O(n \times h)\)

    但是显然两维的定义无法继续进行优化,我们可以考虑改变一下定义的方式

    设 \(f[i]\) 表示考虑前 \(i\) 个建筑,并且第 \(i\) 个建筑高度不变的最优答案

    可以发现,枚举两个不变的边界,那么中间的建筑必定被提高成相同的小于等于边界的高度

    也就是说我们需要把一些坑填平

    因为增加峰的高度既花人力又不能提高观赏度

    增加坡的高度花人力但不能提高观赏度

    只有增加坑的高度才会有贡献,而且增加的值不能超过边界的高度

    因为超过边界的高度又变成了峰

    因此我们可以枚举边界然后再枚举填平的高度

    转移方程为 \(f[i]=f[j]+(sum2[i-1]-sum2[j])+(i-j-1)*h*h-(sum1[i-1]-sum1[j])*2*h+c*abs(a[i]+a[j]-2*h)\)

    其中 \(sum1[i]\) 为 \(a\) 数组的前缀和,\(sum2[i]\) 为 \(a\) 数组平方的前缀和

    上面的式子是展开后的式子,原式子并不难推

    注意这种做法我们需要把 \(a[0]\) 和 \(a[n+1]\) 置为无穷大,因为我们有可能提高第一个和最后一个建筑的高度

    要特判 \(i,j\) 等于 \(0\)或 \(n+1\) 的情况

    最后的答案为 \(f[n+1]\)

    时间复杂度 \(O(n^2 \times h)\),不知道为什么能过这个子任务
  • 对于 \(Subtask\ 3\),我们把一维 \(DP\) 的状态转移方程化简得到

    \(f[i]=f[j]+(i-j-1)*h*h-2*(sum1[i-1]-sum1[j]+c)*h+(sum2[i-1]-sum2[j])+c*(a[i]+a[j])\)

    我们发现前半部分是一个关于高度 \(h\) 的二次函数

    可以直接由对称轴求出最小值

    时间复杂度 \(O(n^2)\)
  • 对于 \(Subtask\ 4\) 和 \(Subtask\ 5\),我们会发现只有两个高度较大的建筑夹着一堆高度较小的建筑才有贡献

    因此可以用单调队列(栈)维护

    时间复杂度 \(O(n logn)\)

    复杂度的瓶颈在\(ST\) 表查询最值上

代码

  1. #include<cstdio>
  2. #include<cmath>
  3. #include<algorithm>
  4. #include<iostream>
  5. #include<cstring>
  6. #define rg register
  7. inline int read(){
  8. rg int x=0,fh=1;
  9. rg char ch=getchar();
  10. while(ch<'0' || ch>'9'){
  11. if(ch=='-') fh=-1;
  12. ch=getchar();
  13. }
  14. while(ch>='0' && ch<='9'){
  15. x=(x<<1)+(x<<3)+(ch^48);
  16. ch=getchar();
  17. }
  18. return x*fh;
  19. }
  20. typedef long long ll;
  21. const int maxn=1e6+5;
  22. int n,c,a[maxn],maxh,lg[maxn],st[maxn][22],head,tail,q[maxn];
  23. ll f[maxn],sum1[maxn],sum2[maxn];
  24. int zhao(ll i,ll j){
  25. if(j==0 && i==n+1) return ((double)(sum1[i-1]-sum1[j])/(double)(i-j-1)+0.5);
  26. else if(j==0 || i==n+1) return ((double)(2*sum1[i-1]-2*sum1[j]+c)/(double)(2.0*(i-j-1))+0.5);
  27. return ((double)(c+sum1[i-1]-sum1[j])/(double)(i-j-1)+0.5);
  28. }
  29. int cx(int l,int r){
  30. rg int k=lg[r-l+1];
  31. return std::max(st[l][k],st[r-(1<<k)+1][k]);
  32. }
  33. int main(){
  34. memset(f,0x3f,sizeof(f));
  35. n=read(),c=read();
  36. for(rg int i=1;i<=n;i++){
  37. a[i]=read();
  38. maxh=std::max(maxh,a[i]);
  39. sum1[i]=sum1[i-1]+a[i];
  40. sum2[i]=sum2[i-1]+1LL*a[i]*a[i];
  41. st[i][0]=a[i];
  42. }
  43. for(rg int i=2;i<=n;i++){
  44. lg[i]=lg[i/2]+1;
  45. }
  46. for(rg int j=1;j<=20;j++){
  47. for(rg int i=1;i+(1<<j)-1<=n;i++){
  48. st[i][j]=std::max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
  49. }
  50. }
  51. a[0]=a[n+1]=0x3f3f3f3f;
  52. f[0]=f[1]=0;
  53. head=1,tail=1;
  54. rg int mmax,mmin,now;
  55. for(rg int i=1;i<=n+1;i++){
  56. while(head<=tail){
  57. if(q[tail]==i-1){
  58. if(i<=n) f[i]=std::min(f[i],f[q[tail]]+1LL*c*std::abs(a[i]-a[i-1]));
  59. else f[i]=f[i-1];
  60. } else {
  61. mmax=cx(q[tail]+1,i-1);
  62. mmin=std::min(a[i],a[q[tail]]);
  63. if(mmin>=mmax){
  64. now=zhao(i,q[tail]);
  65. if(now<mmax) now=mmax;
  66. if(now>mmin) now=mmin;
  67. if(q[tail]==0 && i==n+1) f[i]=std::min(f[i],f[q[tail]]+1LL*(i-q[tail]-1)*now*now-2LL*(sum1[i-1]-sum1[q[tail]])*now+1LL*(sum2[i-1]-sum2[q[tail]]));
  68. else if(q[tail]==0) f[i]=std::min(f[i],f[q[tail]]+1LL*(i-q[tail]-1)*now*now-1LL*(2*sum1[i-1]-2*sum1[q[tail]]+c)*now+1LL*(sum2[i-1]-sum2[q[tail]])+1LL*c*a[i]);
  69. else if(i==n+1) f[i]=std::min(f[i],f[q[tail]]+1LL*(i-q[tail]-1)*now*now-1LL*(2*sum1[i-1]-2*sum1[q[tail]]+c)*now+1LL*(sum2[i-1]-sum2[q[tail]])+1LL*c*a[q[tail]]);
  70. else f[i]=std::min(f[i],f[q[tail]]+1LL*(i-q[tail]-1)*now*now-2LL*(sum1[i-1]-sum1[q[tail]]+c)*now+1LL*(sum2[i-1]-sum2[q[tail]])+1LL*c*(a[i]+a[q[tail]]));
  71. }
  72. }
  73. if(a[i]>=a[q[tail]])tail--;
  74. else break;
  75. }
  76. q[++tail]=i;
  77. }
  78. printf("%lld\n",f[n+1]);
  79. return 0;
  80. }

联赛模拟测试18 A. 施工 单调队列(栈)优化DP的更多相关文章

  1. 单调队列 && 斜率优化dp 专题

    首先得讲一下单调队列,顾名思义,单调队列就是队列中的每个元素具有单调性,如果是单调递增队列,那么每个元素都是单调递增的,反正,亦然. 那么如何对单调队列进行操作呢? 是这样的:对于单调队列而言,队首和 ...

  2. 洛谷P1725 琪露诺 (单调队列/堆优化DP)

    显然的DP题..... 对于位置i,它由i-r~i-l的位置转移过来,容易得到方程 dp[i]=dp[i]+max(dp[i−r],...,dp[i−l]). 第一种:n2的暴力,只能拿部分分. 1 ...

  3. HDU 3507 单调队列 斜率优化

    斜率优化的模板题 给出n个数以及M,你可以将这些数划分成几个区间,每个区间的值是里面数的和的平方+M,问所有区间值总和最小是多少. 如果不考虑平方,那么我们显然可以使用队列维护单调性,优化DP的线性方 ...

  4. csp-s模拟测试50(9.22)「施工(单调栈优化DP)」·「蔬菜(二维莫队???)」·「联盟(树上直径)」

    改了两天,终于将T1,T3毒瘤题改完了... T1 施工(单调栈优化DP) 考场上只想到了n*hmaxn*hmaxn的DP,用线段树优化一下变成n*hmaxn*log但显然不是正解 正解是很**的单调 ...

  5. 【P2422】良好的感觉(单调栈优化DP//奇怪的暴力)

    话说正解是单调栈优化DP,然而貌似根据某种玄学的推算,这个题暴力出解貌似也是可以的.首先,我们枚举所有的点作为最小点,然后横向展开,遇到更小的就停止...然后再操作一下,看上去时间O(N^2),然而由 ...

  6. 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP

    2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] D ...

  7. luogu 2216 理想的正方形 单调队列(其实没有DP)

    #include<bits/stdc++.h> using namespace std; ; ; int a,b,n; int g[A][A],q[A][N],Q[A][N]; int h ...

  8. 洛谷 P2254 [NOI2005]瑰丽华尔兹(单调栈优化DP)

    题目描述 不妨认为舞厅是一个N行M列的矩阵,矩阵中的某些方格上堆放了一些家具,其他的则是空地.钢琴可以在空地上滑动,但不能撞上家具或滑出舞厅,否则会损坏钢琴和家具,引来难缠的船长.每个时刻,钢琴都会随 ...

  9. 联赛模拟测试24 D. 你相信引力吗 单调栈

    题目描述 分析 因为跨过最大值的区间一定是合法的,所以我们人为地把最大值放在最左边 我们要统计的就是在最大值右边单调不降的序列,可以用单调栈维护 需要特殊处理相同的情况 代码 #include< ...

随机推荐

  1. 2019UNCTF

    Easyshellcode: 不说了,都是没有工具的血泪史,直接上exp: from pwn import * from numbers import * from ae64 import AE64 ...

  2. 15个随机图片API

    15个随机图片API 妈妈再也不用担心我网站没图用了呜 请不要重复刷新此页面 ! 找了很久的说,你难道不想收藏一下吗 其中有些 API 速度并不太好,可能会拖慢贵站的速度 我也不能保证这些 API 能 ...

  3. 微信小程序 部署(后台是springboot项目 前后台分流)

    微信小程序的部署需要https 和证书: https 需要反向代理: 这里用 nginx,无论linux,windows 系统都可以安装: 1.安装nginx ,这步自己去做: linux 安装ngi ...

  4. SpringBoot2.0 配置多数据源

    一.简述 配置多数据源意思就是在一个项目中使用多个数据库,在项目使用中可以不用手动切换数据库来实现不同数据库的数据获取和更新. 源码地址: https://github.com/hanguilin/b ...

  5. HA切换失败原因分析

    1. 问题描述 redhat在进行HA切换时,需要先停止service,并释放调当前主机占有的资源,比如说IP Address和Filesystem,但今天我在验证HA切换时,发现service一直停 ...

  6. java里的锁总结(synchronized隐式锁、Lock显式锁、volatile、CAS)

    一.介绍 首先, java 的锁分为两类: 第一类是 synchronized 同步关键字,这个关键字属于隐式的锁,是 jvm 层面实现,使用的时候看不见: 第二类是在 jdk5 后增加的 Lock ...

  7. Java学习预热

    预备知识 什么是计算机 点击进入百度百科(计算机) 计算机硬件组成 主要部件 CPU 内存 主板 IO设备 键盘 鼠标 麦克风 显示器 音箱 冯·诺依曼体系结构 计算机软件 系统软件 DOS wind ...

  8. SpringBoot项目整合Retrofit最佳实践,这才是最优雅的HTTP客户端工具!

    大家都知道okhttp是一款由square公司开源的java版本http客户端工具.实际上,square公司还开源了基于okhttp进一步封装的retrofit工具,用来支持通过接口的方式发起http ...

  9. 解决vue版本不匹配的问题 Vue packages version mismatch:

    解决方式:重新单独安装提示冲突的模块  比如如上的冲突,我重新下载了 npm i vue-template-compiler@2.6.7 --save 再重新启动就可以了 npm run dev

  10. oracle数据库外部连接无法访问

    服务器出现的问题是运行的项目无法访问oracle数据库连接,用plsql输入用户名密码后卡死,无法连接.但是通过命令窗口对oracle数据库操作正常,对oracle服务进行查看并重启,并无异常,运行t ...