2478 小b接水
- 2 秒
- 262,144 KB
- 20 分
- 3 级题
小b将n个宽度相同的积木顺序摆在一起,如下图所示。
现在她告诉你每个积木的高度(可能为0)。
她想知道如果她从高处倒下一杯水,最多有多少单位的水能被积木接住?
假设每个积木的宽度都为1。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,最多可以接 6 个单位的水(蓝色部分表示水)。
收起
输入
第一行一个正整数n,其中0<n≤50000; 第二行n个数表示从左到右每个积木的高度,以空格隔开,每个数不超过10000。
输出
一个数,表示最多可以接的水量
输入样例
12 0 1 0 2 1 0 1 3 2 1 2 1
输出样例
6
题意:中文题题意略。
思路:
如果考虑nlogn的做法的话,直接按高度从高到低排序,然后依次取高的,看是否在两个更高的之间,或者和更高的组成一个盛水的容器即可。按照n<=5e4的数据范围的话是可以通过的。
但是,作为平时的练习题,要尽量追求最高效的解法。
考虑使用维护一个递减的单调栈,注意0不能作为边界,所以不能作为队头;把水按高度分层,每次计算答案时计算最低的一层的水的体积,然后更新水的高度。
注意,计算完入栈的时候可能当前高度和栈顶高度中间还可以盛水,需要特判一下。
代码:
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3fLL
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dep(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int maxn=1e6+100;
int n,m,k;
int c[maxn];
int stk[maxn],tail;
int main()
{
scanf("%d",&n);
ll ans=0;
tail=-1;
ll mi=0;
rep(i,1,n)
{
int x;
scanf("%d",&x);
c[i]=x;
if((x&&tail==-1)||x<c[stk[tail]])
{stk[++tail]=i;}
else if(x)
{
mi=c[stk[tail]];
int pos=1;
while(tail!=-1&&x>=c[stk[tail]])
{
if(c[stk[tail]]==0) {tail--;continue;}
ans+=((ll)c[stk[tail]]-mi)*(ll)(i-stk[tail]-1);
mi=c[stk[tail]];
tail--;
}
if(tail!=-1) ans+=(ll)(min(x,c[stk[tail]])-mi)*(ll)(i-stk[tail]-1);
stk[++tail]=i;
}
}
printf("%lld\n",ans);
return 0;
}