51nod 2478 小b接水(单调栈)

2478 小b接水

  1. 2 秒
  2.  
  3. 262,144 KB
  4.  
  5. 20 分
  6.  
  7. 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;
}

 

展开阅读全文

没有更多推荐了,返回首页