单调队列,栈专题

A题:

A - Largest Rectangle in a Histogram

 HDU - 1506 

题目大意:给你n个点,每一个点代表当前坐标下的矩形的高度,然后问你最大的矩形面积。

具体思路:我们可以用一个栈维护最大值,这个栈内的元素都是保持单调的,如果当前输入的数比栈顶元素小的话,这个时候我们先算一波栈里面的最大值,判断停止的时候是当栈顶元素比当前输入的元素小的时候停就可以了,因为要保持栈内元素的单调性。

AC代码:

#include<iostream>
#include<stack>
#include<iomanip>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
# define ll long long
ll Max(ll t1,ll t2)
{
    if(t1>t2)
        return t1;
    return t2;
}
int main()
{
    ll n;
    while(~scanf("%lld",&n)&&n)
    {
        ll tmp;
        ll maxx=0;
        pair<ll,ll> t;
        stack<pair<ll,ll> >q;
        q.push(make_pair(0,0));
        for(ll i=0; i<n; i++)
        {
            scanf("%lld",&tmp);
            t.first=i;
            while(q.top().second>tmp)//注意,这个地方的位置存储的不是第几个输进来的,而是他在这个栈中最佳的存储位置。
            {
                t=q.top();
                q.pop();
                maxx=Max(maxx,t.second*(i-t.first));
            }
            t.second=tmp;
           // cout<<t.first<<" "<<t.second<<endl;
            q.push(t);
        }
        while(!q.empty())
        {
            t=q.top();
            q.pop();
            maxx=Max(maxx,(n-t.first)*t.second);
        }
        printf("%lld\n",maxx);
    }
    return 0;
}

B题:

B - A Famous City

 HDU - 4252

题目大意:给你n个建筑的高度,问你最少会有多少建筑,判断的条件就是当前这个建筑往左,在碰到比他高的建筑的时候,就会被遮盖住,如果是碰到小于等于的话,就不会被遮盖。

具体思路:用单调栈维护一个递增序列, 如果输入的数有0,那就说明前面的建筑和后后面接下里的建筑没有关系了。

AC代码:

#include<iostream>
#include<stack>
#include<iomanip>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
# define ll long long
int main()
{
    int n;
    int Case=0;
    while(~scanf("%d",&n)&&n)
    {
        int tmp;
        int ans=0;
        stack<int>q;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&tmp);
            if(tmp==0)
            {
                while(!q.empty())
                    q.pop();
            }
            else
            {
                if(q.empty())
                {
                    q.push(tmp);
                    ans++;
                }
                else
                {
                    while(!q.empty()&&q.top()>tmp)
                    {
                        q.pop();
                    }
                    if(q.empty()||q.top()<tmp)
                        ans++;
                    q.push(tmp);
                }
            }
        }
        printf("Case %d: %d\n",++Case,ans);
    }
    return 0;
}

D题:

D - Bad Hair Day

 POJ - 3250 

题目大意:给你n头牛,然后问你从左到右,每头牛能看见的牛的数目的总和。(牛只能往下方看,水平的牛看不见。。(真牛逼))

具体思路: 用单调栈维护一个严格单调递减子序列,每一次放入一个牛,我们先判断当前这个牛的高度和栈顶牛的高度,如果当前牛的高度大于栈顶牛的高度,我们就直接pop到栈顶的元素大于当前牛的高度,这个时候再把栈里面的元素个数加一下,因为这个时候栈里面的元素都能看到新 插入的这头牛。

AC代码:

#include<iostream>
#include<stack>
#include<iomanip>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
# define ll long long
int main()
{
    int n;
    scanf("%d",&n);
    stack<int>q;
    ll sum=0;
    int tmp;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&tmp);
        if(q.empty())
            q.push(tmp);
        else
        {
            while(!q.empty()&&q.top()<=tmp)
            {
                q.pop();
            }
            sum+=q.size();
            q.push(tmp);
        }
    }
    printf("%lld\n",sum);
    return 0;
}

F题:

F - Feel Good

 POJ - 2796 

题目大意:给你n个数,然后定义一种运算,就是限制l,r的范围,然后这一段范围内每个数的和,然后再乘以这个区间内的最小值,问你这种运算的最大值,并且输出此时的l,r。

具体思路:我们首先枚举每一个数,他能到达的左边界和右边界,限制的范围就是这个范围内的数都比当前枚举的这个数大,这个过程可以用单调栈实现,然后枚举每个数找最大就可以了。 

AC代码:

#include<iostream>
#include<cmath>
#include<stack>
#include<algorithm>
#include<queue>
#include<stdio.h>
#include<string>
#include<cstring>
using namespace std;
# define ll long long
const int maxn = 1e5+100;
struct node
{
    int le;
    int ri;
    ll num;
    node() {}
    node ( int xx, int yy)
    {
        le=xx;
        ri=yy;
    }
} wakaka[maxn];
ll  a[maxn],  qan[maxn];
stack<int>q;
int main()
{
    node  t;
    int n;
    scanf("%d",&n);
    for(int i=1 ; i<=n ;  i++)
    {
        scanf("%lld", &wakaka[i].num);
        qan[i] = qan[i-1] + wakaka[i].num;
        wakaka[i].le=i;
        wakaka[i].ri=i;
    }
    int  i = 1 ;
    while( i<=n )
    {
        if(q.empty() || wakaka[q.top()].num<wakaka[i].num)
        {
            q.push(i);
            i++;
        }
        else
        {
            wakaka[i].le=wakaka[q.top()].le;
            q.pop();
        }
    }
    while( !q.empty() )
        q.pop();
    i=n;
    while( i >= 1 )
    {
        if(q.empty() || wakaka[q.top()].num<wakaka[i].num )
        {
            q.push(i);
            i--;
        }
        else
        {
            wakaka[i].ri=wakaka[q.top()].ri;
            q.pop();
        }
    }
    ll maxx=0;
    int l,r;
    ll tmp;
    for(int i=1; i<=n; i++)
    {
        tmp=(qan[wakaka[i].ri]-qan[wakaka[i].le-1])*wakaka[i].num;
        if(tmp>=maxx)
        {
            maxx=tmp;
            l=wakaka[i].le;
            r=wakaka[i].ri;
        }
    }
    printf("%lld\n%d %d\n",maxx,l,r);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值