10366 Faucet Flow【贪心】【模拟】

题目大意

传送门

x=0的正上方有一个水龙头,以每秒1单位体积的速度往下滴水。在x = -1 -3 -5 … left 和 x = 1 3 5 … right 处各有一个隔板,高度已知,求经过了多长时间以后,水会流出最左边的挡板或者是右边的挡板。

样例

input

-1 1
3 5
-3 3
4 3 2 1
-3 5
1 2 2 1 1
0 0

output

6 6 8

解释

在第二组样例中:
image
三个挡板的高度分别为4 3 2 1,第六秒之后,水会溢出。

思路

首先从0点开始向左寻找左边的最大值maxl
从0点开始向右寻找右边的最大值maxr

比较maxl和maxr的大小
1. maxl < maxr 那么向右寻找第一个大于maxl的值记作maxr 下标记作indexr 这样水就不会漫过(indexr,maxr) 只会向左漫出场景。
2. maxl > maxr 那么向左寻找第一个大于maxr的值记作maxl 下标记作indexl 这样水就不会漫过(indexl,maxl) 只会向右漫出场景。
3. maxl = maxr 同时考虑向左向右漫 取最小的值乘2。

单纯计算向左或者是向右漫出的方法如下:
比如以下值:
index:
-9 -7 -5 -3
val:
1 3 2 4

这个是向左边漫的,那么开始是一个(indexl,maxl)。
使用栈来存储数据,得到这样一个栈:
1
3
4
保证栈是一个栈顶元素到栈尾是从小到达的顺序。
计算的时候val*(index - index)即可

代码

#include<cstdio>
#include<map>
#include<queue>
#include<cstring>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stdlib.h>
#include <math.h>
#include <stack>
#include <set>
using namespace std;
#define  LL long long
#define maxn 2005

int d[maxn];



int main()
{
    int l,r;
    int maxr = 0;
    int indexr;
    int maxl = 0;
    int indexl;
    while(scanf("%d%d",&l,&r))
    {
        maxr = 0;
        maxl = 0;
        for(int i=(l+1000); i<=(r+1000); i+=2)
        {
            scanf("%d",&d[i]);
        }
        //get max val in right
        for(int i = (1+1000); i<=(r+1000); i+=2)
        {
            if(maxr < d[i])
            {
                maxr = d[i];
                indexr = i;
            }
        }

        //get max val in left
        for(int i = (l+1000); i<=(-1+1000); i+=2)
        {
            if(maxl < d[i])
            {
                maxl = d[i];
                indexl = i;
            }
        }

        //printf("(%d : %d)  (%d : %d)\n",indexl,maxl,indexr,maxr);

        int  ans = 0;


        if(maxr == maxl)
        {
            ans = maxr * (indexr - indexl);

            //left
            int ansl = 0;
            stack< pair<int,int> > Sl;
            Sl.push(make_pair(d[indexl],indexl));
            for(int i = indexl; i>= (l+1000) ; i-=2)
            {
                if(i==indexl) continue;
                while(Sl.top().first < d[i]) Sl.pop();
                Sl.push(make_pair(d[i],i));
            }

            int pre_val = Sl.top().first;
            int pre_index = Sl.top().second;
            Sl.pop();

            while(!Sl.empty())
            {
                ansl += pre_val*(Sl.top().second - pre_index);

                pre_val = Sl.top().first;
                pre_index = Sl.top().second;
                Sl.pop();
            }

            //right
            int ansr = 0;
            stack< pair<int,int> > Sr;
            Sr.push(make_pair(d[indexr],indexr));
            for(int i = indexr; i <= (r+1000) ; i+=2)
            {
                if(i==indexr) continue;
                while(Sr.top().first < d[i]) Sr.pop();
                Sr.push(make_pair(d[i],i));
            }

            pre_val = Sr.top().first;
            pre_index = Sr.top().second;
            Sr.pop();

            while(!Sr.empty())
            {
                ansr += pre_val*(pre_index - Sr.top().second);
                //printf("%d %d %d \n",ans,pre_val,pre_index);

                pre_val = Sr.top().first;
                pre_index = Sr.top().second;
                Sr.pop();
            }

            //printf("ansl:%d ansr:%d\n",ansl,ansr);

            ans += min(ansl,ansr)*2;

        }
        //0 --> r  find the first val >= maxl
        //the water will overflow from left
        else if( maxl < maxr )
        {
            for(int i = (1 + 1000); i<=(r + 1000); i+=2 )
            {
                if(d[i]> maxl)
                {
                    maxr = d[i];
                    indexr = i;
                    break;
                }
            }

            ans = maxl * (indexr - indexl);

            //printf("1 and: %d\n",ans);

            stack< pair<int,int> > S;
            S.push(make_pair(d[indexl],indexl));
            for(int i = indexl; i>= (l+1000) ; i-=2)
            {
                if(i==indexl) continue;
                while(S.top().first < d[i]) S.pop();
                S.push(make_pair(d[i],i));
            }

            int pre_val = S.top().first;
            int pre_index = S.top().second;
            S.pop();

            while(!S.empty())
            {
                ans += pre_val*(S.top().second - pre_index);

                pre_val = S.top().first;
                pre_index = S.top().second;
                S.pop();
            }

        }
        //l <-- 0 find the first val >= maxr
        //the water will overflow from right
        else if(maxl > maxr)
        {
            for(int i = (-1 + 1000); i >= (l+1000); i-=2 )
            {
                if(d[i] > maxr)
                {
                    maxl = d[i];
                    indexl = i;
                    break;
                }
            }
            ans = maxr * (indexr - indexl);

            //printf("2 and: %d\n",ans);

            stack< pair<int,int> > S;
            S.push(make_pair(d[indexr],indexr));
            for(int i = indexr; i <= (r+1000) ; i+=2)
            {
                if(i==indexr) continue;
                while(S.top().first < d[i]) S.pop();
                S.push(make_pair(d[i],i));
            }

            int pre_val = S.top().first;
            int pre_index = S.top().second;
            S.pop();

            while(!S.empty())
            {
                ans += pre_val*(pre_index - S.top().second);
                printf("%d %d %d \n",ans,pre_val,pre_index);

                pre_val = S.top().first;
                pre_index = S.top().second;
                S.pop();
            }

        }

        //printf("(%d : %d)  (%d : %d)\n",indexl,maxl,indexr,maxr);

        printf("ans: %d\n",ans);


    }


}
/*
-1 1
3 5
-3 3
4 3 2 1
-3 5
1 2 2 1 1
0 0

6 6 8


*/

Hit

此博文只提供思路,不保证最后是否正确。
uva我这里找不到这个题目。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值