【USACO 2009 OPen】干草塔

Description

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

Input

第一行:单个整数:N,1 ≤ N ≤ 100000
第二行到N + 1行:第i + 1行有一个整数Wi,1 ≤ Wi≤ 10000

Output

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

Sample Input

3

1 2 3

Sample Output

2

Hint

(将 1 和 2 放在第一层,将 3 放在第二层)

首先肯定想到贪心,但是随手被卡:7 6 2 4,但我们可以感性理解到每一层肯定是越窄越好,所以可以设计出f[i]表示后i个的最窄的宽度,显然f[i]是单调不下降的,于是可以用单调队列优化。

#include<bits/stdc++.h>
using namespace std;
const int Maxn=100005;
int n,a[Maxn],s[Maxn],f[Maxn];
int l,r,q[Maxn];
//if(f[j]<=s[i]-s[j])f[i]=min(f[i],s[i]-s[j]);
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%d",&a[i]);
	for(int i=1;i<=n/2;++i)swap(a[i],a[n-i+1]);
	for(int i=1;i<=n;++i)s[i]=s[i-1]+a[i];
	f[q[l=r=1]=0]=0;
	for(int i=1;i<=n;++i){
		while(l<r&&f[q[l+1]]<=s[i]-s[q[l+1]])++l;
		f[i]=s[i]-s[q[l]];
		while(l<=r&&f[i]+s[i]<=f[q[r]]+s[q[r]])--r;
		q[++r]=i;
	}
	int high=0,wide=f[n];
	for(int i=n;i>=1;--i){
		wide-=a[i];
		if(wide==0)++high,wide=f[i-1];
	}
	cout<<high<<endl;
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值