[USACO09Open] Tower of Hay 干草塔
为了调整电灯亮度,贝西要用干草包堆出一座塔,然后爬到牛棚顶去把灯泡换掉。干草包会从传送带上运来,共会出现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 干草塔的更多相关文章
- USACO 2009 Open 干草塔 Tower of Hay
USACO 2009 Open 干草塔 Tower of Hay Description 为了调整电灯亮度,贝西要用干草包堆出一座塔,然后爬到牛棚顶去把灯泡换掉.干草 包会从传送带上运来,共会出现N包 ...
- USACO 2009 Open 干草塔 Tower of Hay(贪心+单调队列优化DP)
https://ac.nowcoder.com/acm/contest/1072/B Description 为了调整电灯亮度,贝西要用干草包堆出一座塔,然后爬到牛棚顶去把灯泡换掉.干草包会从传送带上 ...
- 1682: [Usaco2005 Mar]Out of Hay 干草危机
1682: [Usaco2005 Mar]Out of Hay 干草危机 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 391 Solved: 258[ ...
- bzoj1682[Usaco2005 Mar]Out of Hay 干草危机*
bzoj1682[Usaco2005 Mar]Out of Hay 干草危机 题意: 给个图,每个节点都和1联通,奶牛要从1到每个节点(可以走回头路),希望经过的最长边最短. 题解: 求最小生成树即可 ...
- 【BZOJ】1682: [Usaco2005 Mar]Out of Hay 干草危机(kruskal)
http://www.lydsy.com/JudgeOnline/problem.php?id=1682 最小生成树裸题.. #include <cstdio> #include < ...
- BZOJ 1682: [Usaco2005 Mar]Out of Hay 干草危机
Description 牛们干草要用完了!贝茜打算去勘查灾情. 有N(2≤N≤2000)个农场,M(≤M≤10000)条双向道路连接着它们,长度不超过10^9.每一个农场均与农场1连通.贝茜要走遍每一 ...
- [Usaco2005 Mar]Out of Hay 干草危机
题目描述 Bessie 计划调查N (2 <= N <= 2,000)个农场的干草情况,它从1号农场出发.农场之间总共有M (1 <= M <= 10,000)条双向道路,所有 ...
- 【最小生成树】BZOJ1682[Usaco2005 Mar]-Out of Hay 干草危机
...最小生成树裸题,9月最后一天刷水刷水. #include<iostream> #include<cstdio> #include<algorithm> usi ...
- bzoj 1682: [Usaco2005 Mar]Out of Hay 干草危机【并查集+二分】
二分答案,把边权小于mid的边的两端点都并起来,看最后是否只剩一个联通块 #include<iostream> #include<cstdio> using namespace ...
随机推荐
- Filter实现字符集统一设置
Filter实现字符集统一设置 其实是对request和response请求进行了拦截 1.创建Filter类,实现javax.Servlet接口 doFilter方法 //设置字符集 request ...
- unittest单元测试框架之测试环境的初始化与还原(fixture)(五)
1.方法一:针对每条测试用例进行初始化与还原 import unittest from UnittestDemo.mathfunc import * class TestMathFunc(unitte ...
- ConfigurationManager.AppSettings方法
一 配置文件概述: 应用程序配置文件是标准的 XML 文件,XML 标记和属性是区分大小写的.它是可以按需要更改的,开发人员可以使用配置文件来更改设置,而不必重编译应用程序.配置文件的根节点是conf ...
- Visual Studio中添加API断点
如:添加 PostMessageA 断点 {,,USER32.DLL}_PostMessageA@16 //判断为WM_CLOSE消息*(int*)(esp + 8) == 0x0010
- 模板——最小生成树kruskal算法+并查集数据结构
并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...
- wps for linux 安装后系统缺失字体安装配置
错误提示: 解决方法: 从http://bbs.wps.cn/thread-22355435-1-1.html下载字体库,离线版本:(链接: https://pan.baidu.com/s/1i5dz ...
- 用VMWare搭建服务器集群不能上外网的三种模式下对应解决办法
前言 决心要花费宝贵时间写下这篇心得,是因为从昨天晚上到今天上午被这个VMWare模拟搭建的服务器集群不能上外网的问题搞得很心烦,最后决定跟它杠上了!上午还通过远程连接得到了“空白”同学的帮助,在此表 ...
- 多用户OFDM系统资源分配研究
首先,OFDMA 是什么? OFDM 技术的基本原理是将无线信道划分为若干互相正交的子信道,把高速串行数据流转化为低速并行子数据流,低速并行子数据流在子信道上独立传输. OFDMA 是LTE的下行多址 ...
- python3.X 安装web.py 失败的解决方法
python2.x 安装python是非常顺利的 但是 在进行 pip3 install web.py 时提示很多错误 例如缺少模块 语法错误...... 最后试了一下web.py 的dev版本 pi ...
- 第3章 Hadoop 2.x分布式集群搭建
目录 3.1 配置各节点SSH无密钥登录 1.将各节点的秘钥加入到同一个授权文件中 2.拷贝授权文件到各个节点 3.测试无秘钥登录 3.2 搭建Hadoop集群 1.上传Hadoop并解压 2.配置H ...