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;
}