$ BZOJ1233~ $ 干草堆: (题目特殊性质)



$ solution: $

很妙的一道题目,开始看了一眼觉得是个傻逼贪心,从后往前当前层能多短就多短,尽量节省花费。但是这是DP专题,怎么会有一道小贪心混进来?上网一搜,我果然还是太笨了!

  1. 6
  2. 11 10 7 3 2 6

这组小数据直接把贪心逼上绝路,如果顶层只有6(6-237-1011),只有三层。而如果顶层宽一点(62-37-10-11),就有四层了。什么!我之前好心节省草包,居然办了坏事?

好吧,题目限定了每一个草包都必须用,这样贪心是有后效性的(你节省的草包改变了下一阶段的状态)。于是我们只好DP,可是我们要维护的东西可就多了:(当前是第几个草包)(最下面一层多宽)(整个干草堆的高度)而题目数据范围只允许我们 $ n~logn $ ,这差距还是有点的,所以我们需要研究题目的性质。

性质: 最下面一层最窄的干草堆一定包含高度最高的最优解。

  1. 任意取出一个能使层数最高的方案,设有CA层,把其中从下往上每一层最大的块编号记为Ai;任取一个能使底边最短的方案,设有CB层,把其中从下往上每一层最大的块编号记为Bi。显然A1>=B1,ACB<=BCB,这说明至少存在一个k属于(1,CB),满足Ak-1>=Bk-1Ak<=Bk。也就是说,方案 A K 层完全被方案 B K 层包含。构造一个新方案,第K 层往上按方案 A,往下按方案 B,两边都不要的块放中间当第K 层。新方案的层数与 A 相同,而底边长度与 B 相同。证毕。 -----引用

然后我们就可发现我们的底层宽度和整个干草堆的高度是相关联的,我们可以在DP最下面一层宽度的同时记录一下高度即可。就像我们的题目变成了求干草堆底层最窄的方案(方案包含高度)。而为了更好的求底层最窄,我们可以从后往前DP,我们设 $ f[i] $ 表示到倒数第i个干草堆底层最窄的宽度。然后转移就变成了:

$ f[i]=min{s[i]-s[j] }\quad j>i,s[i]-s[j]>f[j] $

(设 $ s[i] $ ) 表示从i开始到最后一个草包的宽度之和(就是后缀和)

然后我们发现这个东西 $ s[i]-s[j] ,s[i]-s[j]>f[j] $ 很难维护,显然我们需要 $ j $ 尽量小,但是小的 $ j $ 并不一定满足 $ s[i] - s[j]>f[j] $ 于是我们用单调队列来维护。

单调队列的 $ j $ 应该从大到小排序,且只有第一个是满足 $ s[i]-s[j]>f[j] $ (因为如果后一个也满足,它的j又小,一定更优),在DP过程中当第二个也满足时,第一个显然失去最优效果(于是删除对首)。然后小的 $ j $ 在加入优先队列时,可以根据定义式( $ f[i]=min{s[i]-s[j] } $ )从后往前淘汰掉比它不优的 $ j $ (具体见代码)



$ code: $

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<iomanip>
  4. #include<algorithm>
  5. #include<cstring>
  6. #include<cstdlib>
  7. #include<ctime>
  8. #include<cmath>
  9. #include<vector>
  10. #include<queue>
  11. #include<map>
  12. #include<set>
  13. #define ll long long
  14. #define db double
  15. #define rg register int
  16. using namespace std;
  17. int n,tt;
  18. int a[100005];
  19. int s[100005];
  20. int q[100005];
  21. int h[100005];
  22. int f[100005];
  23. inline int qr(){
  24. register char ch; register bool sign=0; rg res=0;
  25. while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
  26. while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
  27. if(sign)return -res; else return res;
  28. }
  29. int main(){
  30. //freopen(".in","r",stdin);
  31. //freopen(".out","w",stdout);
  32. n=qr(); q[++tt]=n+1; rg l=1,r=1;
  33. for(rg i=1;i<=n;++i) a[i]=qr();
  34. for(rg i=n;i>=1;--i) s[i]=s[i+1]+a[i];
  35. for(rg i=n;i>=1;--i){ //注意是从后往前枚举!j 一定大于 i !
  36. while(l<r&&s[i]>=f[q[l+1]]+s[q[l+1]])++l; //后面的j比前面小,比当前这个优,只不过可能不满足s[i]-s[j]>f[j]
  37. (设 $ s[i] $ ) 表示从i开始到最后一个草包的宽
  38. f[i]=s[i]-s[q[l]]; h[i]=h[q[l]]+1;
  39. while(l<=r&&f[q[r]]+s[q[r]]>f[i]+s[i])--r;
  40. q[++r]=i;
  41. }printf("%d\n",h[1]);
  42. return 0;
  43. }

BZOJ 1233 干草堆 (单调队列优化DP)的更多相关文章

  1. BZOJ1233 干草堆 - 单调队列优化DP

    问题描述: 若有干个干草, 分别有各自的宽度, 要求将它们按顺序摆放, 并且每层的宽度不大于 它的下面一层 ,  求最多叠几层 题解: zkw神牛证明了: 底边最短, 层数最高         证明: ...

  2. bzoj 2216: Lightning Conductor 单调队列优化dp

    题目大意 已知一个长度为\(n\)的序列\(a_1,a_2,...,a_n\)对于每个\(1\leq i\leq n\),找到最小的非负整数\(p\)满足: 对于任意的\(j\), \(a_j \le ...

  3. BZOJ 1855 股票交易(单调队列优化DP)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1855 题意:最近lxhgww又迷上了投资股票, 通过一段时间的观察和学习,他总结出了股票 ...

  4. BZOJ 2806: [Ctsc2012]Cheat(单调队列优化dp+后缀自动机)

    传送门 解题思路 肯定先要建出来广义后缀自动机.刚开始以为是个二分+贪心,写了一下结果\(20\)分.说一下正解,首先显然\(L_0\)具有单调性,是可以二分的.考虑二分后怎样判合法,对于分割序列很容 ...

  5. BZOJ 1499 [NOI2005] 瑰丽华尔兹 | 单调队列优化DP

    BZOJ 1499 瑰丽华尔兹 | 单调队列优化DP 题意 有一块\(n \times m\)的矩形地面,上面有一些障碍(用'#'表示),其余的是空地(用'.'表示).每时每刻,地面都会向某个方向倾斜 ...

  6. bzoj 1499 [NOI2005]瑰丽华尔兹——单调队列优化dp

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1499 简单的单调队列优化dp.(然而当时却WA得不行.今天总算填了坑) 注意滚动数组赋初值应 ...

  7. 单调队列优化DP || [NOI2005]瑰丽华尔兹 || BZOJ 1499 || Luogu P2254

    题外话:题目极好,做题体验极差 题面:[NOI2005]瑰丽华尔兹 题解: F[t][i][j]表示第t时刻钢琴位于(i,j)时的最大路程F[t][i][j]=max(F[t-1][i][j],F[t ...

  8. P4381 [IOI2008]Island(基环树+单调队列优化dp)

    P4381 [IOI2008]Island 题意:求图中所有基环树的直径和 我们对每棵基环树分别计算答案. 首先我们先bfs找环(dfs易爆栈) 蓝后我们处理直径 直径不在环上,就在环上某点的子树上 ...

  9. 【笔记篇】单调队列优化dp学习笔记&&luogu2569_bzoj1855股票交♂易

    DP颂 DP之神 圣洁美丽 算法光芒照大地 我们怀着 崇高敬意 跪倒在DP神殿里 你的复杂 能让蒟蒻 试图入门却放弃 在你光辉 照耀下面 AC真心不容易 dp大概是最经久不衰 亘古不化的算法了吧. 而 ...

随机推荐

  1. Spring整合Hibernate实现Spring Data JPA (介绍和使用)

    Spring Data JPA是Spring基于Hibernate开发的一个JPA框架.如果用过Hibernate或者MyBatis的话,就会知道对象关系映射(ORM)框架有多么方便. 但是Sprin ...

  2. 【洛谷P1310 表达式的值】

    题目链接 题目描述 对于1 位二进制变量定义两种运算: 运算的优先级是: 先计算括号内的,再计算括号外的. “× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算.例如:计算表达式 ...

  3. 安装U盘启动ferdora-22-fce笔记

    如何格式化为fat? windows图形界面格式化, 选项中没有fat, 只有fat32和exfat两种upan格式 Fat就是 传统的FAT16 要格式化为fat, 需要使用cmd的format命令 ...

  4. 爬虫相关概念和https加密

    一.爬虫的相关概念 1.什么是爬虫 互联网:由网络设备(网线,路由器,交换机,防火墙)和一台台计算机连接而成,像一张网一样. 互联网建立目的:互联网的核心价值在与数据的共享/传递:数据是存放在一台台机 ...

  5. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_05 IO字符流_7_字符输出流的续写和换行

    追加写就是后面参数设置为true 加入换行符

  6. CDN分发

    CDN 是Content Delivery Network,即内容分发网络. 未完待续..

  7. XML读写工具类

    摘要:①读取XML文件,生成pojo对象:②将对象信息保存到xml中. 步骤: ①新建一个普通的java类BasePage: package com.test.selenium.pages; impo ...

  8. delphi开发实例:保存字体设置的方法

    http://blog.csdn.net/delphi308/article/details/9906147 delphi开发实例:保存字体设置的方法 2013-08-11 22:37 446人阅读  ...

  9. [转载]OpenSSL中文手册之命令行详解(未完待续)

     声明:OpenSSL之命令行详解是根据卢队长发布在https://blog.csdn.net/as3luyuan123/article/details/16105475的系列文章整理修改而成,我自己 ...

  10. 字符串中的TOUPPER函数

    std::string& str_toupper(std::string& s) { std::transform(s.begin(), s.end(), s.begin(), []( ...