文章标题 CSU 1838: Water Pump (单调栈)

23 篇文章 1 订阅
4 篇文章 0 订阅

1838: Water Pump

链接 1838: Water Pump
题意:给出n堵墙(水坝?),已知各个墙的高度hi。 这些墙之间灌满了水,当然这些水都是符合 物理规律的,即不会漂浮在空中。然后问如 果在两堵墙之间开一个洞,那么最多可以流 出多少水?
分析:要求出第i堵墙和i+1堵墙流出的水量,可以计算出左边的前缀和面积dpl[i],然后计算右边的后缀和面积dpr[i],然后用总面积减去两边的面积剩下的就是流出的水量。计算前后缀和用单调栈求,时间复杂度为O(n)
代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<vector>
#include<math.h>
#include<stack>
#include<map>
#include<queue> 
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;

int n;
int hi[100005];
int dpl[100005];//dpl[i]表示前i个水坝所能蓄的水 
int dpr[100005];//dpr[i]表示i~n个水坝蓄的水 
stack<pair<int,int> >st;//单调栈 (下降) 

int main ()
{
    int t;
    scanf ("%d",&t);
    while (t--){
        while (st.size())st.pop();
        scanf ("%d",&n);
        for (int i=1;i<=n;i++){
            scanf ("%d",&hi[i]);
        }
        dpl[1]=0;//左边的前缀和 
        st.push(make_pair(hi[1],1));
        int first,id;
        for (int i=2;i<=n;i++){
            //如果栈顶的高度比当前的高度低就弹出 
            while (st.size()>1&&st.top().first<=hi[i]) st.pop();
            first=st.top().first;
            id=st.top().second;
            if (st.size()==1){
                if (hi[i]<first)dpl[i]=dpl[id]+min(first,hi[i])*(i-id);//如果栈只剩一个点,直接赋值 
                else {
                    dpl[i]=dpl[id]+min(first,hi[i])*(i-id);
                    st.pop();//如果当前的高度比最后一个还高的话,就将弹出去掉 
                }
            }
            else {
                dpl[i]=dpl[id]+(i-id)*hi[i];
            }
            st.push(make_pair(hi[i],i));//放进栈中 
        }
//      for (int i=1;i<=n;i++){
//          cout<<dpl[i]<<" ";
//      }
//      cout<<endl;

        dpr[n]=0;//求右边的前缀和(后缀和) 
        while (st.size()) st.pop();
        st.push(make_pair(hi[n],n));
        for (int i=n-1;i>=1;i--){
            while (st.size()>1&&st.top().first<=hi[i]) st.pop();
            first=st.top().first; id=st.top().second;
            if (st.size()==1){
                if (hi[i]<first){
                    dpr[i]=dpr[id]+min(hi[i],first)*(id-i);
                }
                else {
                    dpr[i]=dpr[id]+min(hi[i],first)*(id-i);
                    st.pop();
                }
            }
            else {
                dpr[i]=dpr[id]+hi[i]*(id-i);
            }
            st.push(make_pair(hi[i],i));
        }

//      for (int i=n;i>=1;i--){
//          cout<<dpr[i]<<" ";
//      }
//      cout<<endl;

        int ans=0;
        int sum=dpl[n];
        for (int i=1;i<=n-1;i++){
            ans=max(ans,sum-(dpl[i]+dpr[i+1]));//用总面积减去两端的前后缀和就少第i个水坝流走的水量 
        }
        printf ("%d\n",ans);
    }   
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值