为了调整电灯亮度,贝西要用干草包堆出一座塔,然后爬到牛棚顶去把灯泡换掉。干草包会从传送带上运来,共会出现N包干草,第i包干草的宽度是W i ,高度和长度统一为1。干草塔要从底层开始铺建。贝西会选择最先送来的若干包干草,堆在地上作为第一层,然后再把紧接着送来的几包干草包放在第二层, 再铺建第三层……重复这个过程, 一直到所有的干 草全部用完。每层的干草包必须紧靠在一起,不出现缝隙,而且为了建筑稳定,上层干草的宽度不能超过下层的宽度。 按顺序运来的干草包一定要都用上, 不能将其中几个干草包弃置不用。贝西的目标是建一座最高的塔,请你来帮助她完成这个任务吧。

输入格式

第一行:单个整数:\(N,1≤N≤100000\)第二行到\(N + 1\)行:第\(i + 1\)行有一个整数\(W_i,1 ≤ W_i ≤ 10000\)

输出格式

第一行:单个整数,表示可以建立的最高高度

样例输入

3

1

2

3

样例输出

2

题解

我们考虑贪心的做法。让我们看下面这张图



如图,一个小学生都明白的道理:对于一个三角形,对它进行等面积变换,为了使其越长,其形状必须越瘦。同理,在这道题中我们可以将干草堆抽象为三角形,为了让干草堆更高,我们只能让其更瘦。这里引用ZKW大佬的证明过程。

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

我们的第一种方案即从下往上处理每一层,当可以将当前层的最后一个干草堆放到当前层+1时我们就将其放上去,直到所有层都不满足条件为止。当然,不能只进行一次排布,因为当第h层向上移动后,第h-1层就有可能重新获得向上移动的机会。

#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
inline char get(){
static char buf[3000],*p1=buf,*p2=buf;
return p1==p2 && (p2=(p1=buf)+fread(buf,1,3000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
register char c=get();register int f=1,_=0;
while(c>'9' || c<'0')f=(c=='-')?-1:1,c=get();
while(c<='9' && c>='0')_=(_<<3)+(_<<1)+(c^48),c=get();
return _*f;
}
struct edge{
deque<int> u;
int w=0;
bool up=1;
}E[maxn];
int n;
int h;
void exchange(){
h=1;
while(true){
E[h].up=1;
while(E[h].up){
//cout<<h<<":";
if(E[h].w-E[h].u.back() >= E[h+1].w+E[h].u.back()){
E[h].w-=E[h].u.back();
E[h+1].w+=E[h].u.back();
E[h+1].u.push_front(E[h].u.back());
E[h].u.pop_back();
//cout<<E[h+1].u.front()<<endl;
}
else E[h].up=0;
}
h++;
if(E[h].w==0)break;
}
}
int main(){
//freopen("1.txt","r",stdin);
n=read();
for(register int i=1;i<=n;i++)E[1].u.push_back(read()),E[1].w+=E[1].u.back();
for(register int i=1;i<=500000;i++)exchange();
cout<<h;
return 0;
}

但是此时我们发现时间复杂度过大,虽然方案本身是正确的却依然因为时限问题而TLE。甚至在数据比较严苛的时候我们甚至无法通过这种方案获得最终答案。

此时只能考虑另外的思路。

这时我们选择枚举最底层的组成,设\(f[i]\)表示从\(n到i\)中最底层的宽度,则可知\(f[i]=min(sum[j-1到i])\)。由于上一层的宽度永远小于下一层的宽度,所以\(f[j]<=sum[j-1到i]\)

再观察一下,由于所有的干草堆要全部使用且对于第\(i-1\)个干草堆放在第\(h\)层时,第\(i\)个必然放在第\(h\)层或第\(h+1\)层,我们可以令\(sum[i]\)表示宽度的前缀和,而\(sum[i]\)是随i的增大而增大的,所以从\(i到n\)一旦发现一个符合条件的决策\(j\),便将其取出来更新\(f[i]\)。但是因为这样做的复杂度较大,仍不能通过所有数据。

再次分析,发现所有的决策的值(例如对于决策\(j\)值即为\(sum[j-1])由n\)往前都是单调递减的,也就是一个比一个优。因此决定性的因素则是他们的生效时间。

#include <bits/stdc++.h>
#define maxn 100009
using namespace std;
inline char get(){
static char buf[3000],*p1=buf,*p2=buf;
return p1==p2 && (p2=(p1=buf)+fread(buf,1,3000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
register char c=get();register int f=1,_=0;
while(c>'9' || c<'0')f=(c=='-')?-1:1,c=get();
while(c<='9' && c>='0')_=(_<<3)+(_<<1)+(c^48),c=get();
return _*f;
}
int num[maxn],dp[maxn],f[maxn],sum[maxn],w[maxn];
int n;
int main(){
//freopen("1.txt","r",stdin);
n=read();
for(register int i=1;i<=n;i++){
w[i]=read();
sum[i]=sum[i-1]+w[i];
}
num[1]=n+1;
int h=1,t=1;
for(register int i=n;i;i--){
while(h<t && f[num[h+1]]<=sum[num[h+1]-1]-sum[i-1]) ++h;
f[i]=sum[num[h]-1]-sum[i-1];
dp[i]=dp[num[h]]+1;
num[++t]=i;
while((t>h) && (f[num[t-1]]-sum[num[t-1]-1]+sum[num[t]-1]>f[num[t]]))t--,num[t]=num[t+1];
}
cout<<dp[1];
return 0;
}

[USACO09Open] Tower of Hay 干草塔的更多相关文章

  1. USACO 2009 Open 干草塔 Tower of Hay

    USACO 2009 Open 干草塔 Tower of Hay Description 为了调整电灯亮度,贝西要用干草包堆出一座塔,然后爬到牛棚顶去把灯泡换掉.干草 包会从传送带上运来,共会出现N包 ...

  2. USACO 2009 Open 干草塔 Tower of Hay(贪心+单调队列优化DP)

    https://ac.nowcoder.com/acm/contest/1072/B Description 为了调整电灯亮度,贝西要用干草包堆出一座塔,然后爬到牛棚顶去把灯泡换掉.干草包会从传送带上 ...

  3. 1682: [Usaco2005 Mar]Out of Hay 干草危机

    1682: [Usaco2005 Mar]Out of Hay 干草危机 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 391  Solved: 258[ ...

  4. bzoj1682[Usaco2005 Mar]Out of Hay 干草危机*

    bzoj1682[Usaco2005 Mar]Out of Hay 干草危机 题意: 给个图,每个节点都和1联通,奶牛要从1到每个节点(可以走回头路),希望经过的最长边最短. 题解: 求最小生成树即可 ...

  5. 【BZOJ】1682: [Usaco2005 Mar]Out of Hay 干草危机(kruskal)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1682 最小生成树裸题.. #include <cstdio> #include < ...

  6. BZOJ 1682: [Usaco2005 Mar]Out of Hay 干草危机

    Description 牛们干草要用完了!贝茜打算去勘查灾情. 有N(2≤N≤2000)个农场,M(≤M≤10000)条双向道路连接着它们,长度不超过10^9.每一个农场均与农场1连通.贝茜要走遍每一 ...

  7. [Usaco2005 Mar]Out of Hay 干草危机

    题目描述 Bessie 计划调查N (2 <= N <= 2,000)个农场的干草情况,它从1号农场出发.农场之间总共有M (1 <= M <= 10,000)条双向道路,所有 ...

  8. 【最小生成树】BZOJ1682[Usaco2005 Mar]-Out of Hay 干草危机

    ...最小生成树裸题,9月最后一天刷水刷水. #include<iostream> #include<cstdio> #include<algorithm> usi ...

  9. bzoj 1682: [Usaco2005 Mar]Out of Hay 干草危机【并查集+二分】

    二分答案,把边权小于mid的边的两端点都并起来,看最后是否只剩一个联通块 #include<iostream> #include<cstdio> using namespace ...

随机推荐

  1. 【绝迹篇】RSA加密算法(私钥加签公钥验签)

    对于上上篇博客中我讲的一个故事,本文引用: https://www.cnblogs.com/ButterflyEffect/p/9851403.html 故事中提到的关于加密会出现,私钥加密,公钥解密 ...

  2. 使用nuget 打包并上传 nuget.org

    一. 准备工作 1 下载  Download NuGet.exe 2  windows 系统下设置环境变量 path中 或者 在dos 命令窗口下转到 nuget.exe 所在目录 3 在www.nu ...

  3. admin源码解析及自定义stark组件

    admin源码解析 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单 ...

  4. 如何在Mac中创建MiniKube

    转载请标明出处: http://blog.csdn.net/forezp/article/details/82563153 本文出自方志朋的博客 这篇文章介绍了如何在Mac系统中创建MiniKube. ...

  5. Python 学习笔记(十一)Python语句(一)

    运算符和条件语句 算术运算符 运算符 描述 实例 + 加 - 两个对象相加 a + b 输出结果 30 - 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -10 * 乘 - 两个数相乘 ...

  6. Java九阳真经论述及愿景

    Java九阳真经论述及愿景 “他强由他强,清风拂山冈,他横由他横,明月照大江.” <倚天屠龙记>中张无忌被玄冥二老的玄冥神掌打伤后,体寒难耐,到处求解决之法.一次被韦蝠王打下山谷后,偶遇一 ...

  7. grid 布局的使用

    grid 布局的使用 css 网格布局,是一种二维布局系统. 浏览器支持情况:老旧浏览器不支持, 概念: 网格容器.元素应用dispalay:grid,它是所有网格项的父元素. <div cla ...

  8. 【2018 ICPC亚洲区域赛徐州站 A】Rikka with Minimum Spanning Trees(求最小生成树个数与总权值的乘积)

    Hello everyone! I am your old friend Rikka. Welcome to Xuzhou. This is the first problem, which is a ...

  9. 如何在tornado中以异步的方式调用同步函数

    问题 如何在tornado的coroutine中调用同步阻塞的函数 解决方案 使用python内置标准库的concurrent.futures.ThreadPoolExecutor和tornado.c ...

  10. C#获取本地磁盘信息

    直接上干货简单易懂 //磁盘监控(远程/本地) //需要引用System.Management.dll public class RemoteMonitoring { private static s ...