牛客网 保卫方案 单调栈

牛客网的一道题

好像原来是一个笔试题目吧?考点是单调栈。
原题链接:https://www.nowcoder.com/questionTerminal/e1967ae812ea42e7a3ce57ee1f83b686
题意很清楚,一个环形数组 问有多少个a[i],a[j]使得他们中间的数字都小于等于a[i],a[j]
注意因为是环形显然这个“中间”只要一个满足就可以了
这个题难点在可以有重复的数字,那么我们在维护单调栈的时候就要注意时刻进行压缩,不然栈顶和新加进来的元素一样大的时候会没法计算贡献。
值得一提的是因为是环形,最后不要忘记再把栈弹空了计算一下反向构成“山谷”的数目,当然还有当栈只有两个元素时候还有特判一下。
单调栈百度百科:https://baike.baidu.com/item/单调栈

代码:

#include <bits/stdc++.h>
#define X first
#define Y second
#define PB push_back
#define LL long long
#define pii pair<int,int>
#define MEM(x,y) memset(x,y,sizeof(x))
#define bug(x) cout<<"debug "#x" is "<<x<<endl;
#define FIO ios::sync_with_stdio(false);

using namespace std;
const int maxn=100007;
const int mod=1e9+7;
const LL inf=2e18;
int a[maxn];
int main(){
    FIO;
    int n;
    cin>>n;
    deque<pii> Q;
    int st,mx=0;
    for(int i=0;i<n;i++){
        cin>>a[i];
        if(a[i]>=mx)mx=a[i],st=i;
    }
    LL ans=0;
    for(int c=0,i=st;c<n;c++,i=(i+1)%n){
        while(!Q.empty()&&Q.back().X<a[i]){
            ans+=Q.back().Y;
            Q.pop_back();
        }
        int cnt=1;
        if(!Q.empty()&&Q.back().X==a[i]){
            ans+=Q.back().Y;
            cnt+=Q.back().Y;
            Q.pop_back();
        }
        if(!Q.empty()){
            ans+=1;
        }
        Q.push_back({a[i],cnt});
    }
    while(Q.size()>2){
        ans+=Q.back().Y;
        Q.pop_back();
    }
    if(Q.size()==2&&Q.front().Y>1)ans+=Q.back().Y;
    cout<<ans<<endl;
}

posted @ 2019-04-13 15:02  zhangxianlong  阅读(197)  评论(0编辑  收藏  举报