为了调整电灯亮度,贝西要用干草包堆出一座塔,然后爬到牛棚顶去把灯泡换掉。干草包会从传送带上运来,共会出现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. java GC是何时对什么东西做什么事情

    之前学习了javaGC的原理机制,有了一定的了解,现在做一个整理总结,便于理解记忆,包括三个问题: 1. java GC是什么时候做的? 2. java GC作用的东西是什么? 3. java GC具 ...

  2. qt+vs2005新建配置不自动加载Generated Files进工程(个人备份)

    工程右键Qt Project Settings 的Moc Directory路径删除 确定,再进入将删除路径加上

  3. careercup-扩展性和存储限制10.3

    题目 给你一个文件,里面包含40亿个整数,写一个算法找出该文件中不包含的一个整数, 假设你有1GB内存可用. 如果你只有10MB的内存呢? 解答 我们先来做个算术题,40亿个整数大概有多大? * ^ ...

  4. input和div模仿select,带输入提示

    有时候我们需要select和input的结合体,即可以使用下拉框,同时也可以用来输入,输入的同时显示可选的下拉选项 先上html代码 <div class="input-group i ...

  5. php 将富文本编辑后的内容取出

    背景:项目中用了富文本编辑器,讲写完的内容存入了数据库,但是取出的时候因为有些展示地方并不需要样式,只想获取到内容,所以需要将带了html编码的信息解析出来. 原始信息如下 [task_desc] = ...

  6. django-models 数据库取值

    django.shortcuts import render,HttpResponse from app01.models import * # Create your views here. def ...

  7. C语言实验报告(五) 用自定义函数求2~n之间的素数

    #include<stdio.h>#include <math.h>int main(){  int i,n;  printf("input n:");  ...

  8. 如何将github项目上传至gitlab

    一.修改远程分支关联 删除远程分支关联 将指向github的远程分支关联关系删除 git remote rm origin 添加新的远程分支关联 新的remote地址指向gitlab相应地址 git ...

  9. (数据科学学习手札39)RNN与LSTM基础内容详解

    一.简介 循环神经网络(recurrent neural network,RNN),是一类专门用于处理序列数据(时间序列.文本语句.语音等)的神经网络,尤其是可以处理可变长度的序列:在与传统的时间序列 ...

  10. 机房人民大团结(DP)

    最近,机房出了一个不团结分子:Dr.Weissman.他经常欺骗同学们吃一种“教授糖豆”,使同学们神志不清,殴打他人,砸烂计算机,破坏机房团结.幸运地,一个和谐家认清了Dr.Weissman的本质.机 ...