洛谷P1823:音乐会的等待(单调栈)

P1823 [COI2007] Patrik 音乐会的等待

题解:维护一个单调不递增的栈

首先说明一下:由于一个人左边可以看到一些人,右边可以看到一些人,可以我们仅从一边考虑,对于一个人,我们考虑它的左边能看到多少个。两边都考虑会导致重复计算。

tot是当前栈元素的个数

对于新加入单调栈的一个元素,我们分三种情况讨论:

1、新元素比栈顶小:直接加入栈,ans加1

2、新元素与栈顶元素相等:ans加栈中与新元素相等的数的个数,同时若tot不为0,ans还应再加1

3、新元素比栈顶大:不断弹出元素,每弹一个ans加一,一直弹到新元素<=栈顶元素,再同情况2进行判断即可。

我们想想这个为什么是对的,两个人可以相互看见只有它们间没有人比他们高,对于加入栈的新元素,由于栈是不递增的。如果该元素比栈顶小,我们是从左边考虑,那么该元素仅能看到它的左边的第一个元素,也即是栈顶,栈顶左边的人都比栈顶高,这个新元素看不见。

如果新元素和栈顶相等,那么我们就去寻找栈里面有多少和该元素相等的数,找到一个答案就加1,因为相等的元素能够相互看见,对答案的贡献就是1。如果找到最后,tot不为0,那么答案再加1,因为它俩也可以相互看见 比如说

栈内有5 2 2,再加入一个2,答案增加3,因为新加入的2 和 5也可以相互看见

如果新元素比栈顶大,那么就不断弹出元素,直到新元素<=栈顶元素,弹出一个,答案加1,因为弹出的元素比新元素小,因此新元素可以看见它的左边比它小的元素,有些人可能疑惑元素弹出以后对后面的计数有没有什么影响呢,答案是没有。

新元素的身高比弹出的元素的身高大,也就是这些弹出的元素与新元素后面的元素之间不满足能相互看见,新元素的后面任何一个元素都不会看见这些弹出的元素。 到新元素<=栈顶元素时,再考虑新元素是否等于栈顶,这时就回到了情况2

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
int s[maxn],tot,n,tmp,ans;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>tmp;
        if(tmp<s[tot]) ans++,s[++tot]=tmp;
        else //这里情况2和3可以放在一起处理
        {
            int t=0;
            while(tot&&tmp>s[tot]) ans++,tot--;
            while(tot&&tmp==s[tot]) ans++,tot--,t++;
            if(tot) ans++;
            tot+=t;//恢复栈中相同的元素
            s[++tot]=tmp;
        }
    }
    cout<<ans;
    return 0;
}
View Code

这个代码交上去以后最后三个测试点超时了,可以考虑优化,对于元素相同的情况,我们重复的计算栈内相同元素的个数,所以我们可以用一个数组来记录这个相同元素的个数。

// luogu-judger-enable-o2
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
int s[maxn],w[maxn],tot,n,tmp;
long long ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&tmp);
        if(tmp<s[tot]) ans+=1LL,s[++tot]=tmp,w[tot]=1;
        else 
        {
            int width=0;
            while(tot&&tmp>s[tot]) ans+=1LL*w[tot],tot--;
            while(tot&&tmp==s[tot]) ans+=1LL*w[tot],width+=w[tot],tot--;
            if(tot) ans+=1LL;
            s[++tot]=tmp;
            w[tot]=width+1;
        }
    }
    printf("%lld",ans);
    return 0;
}
View Code

还有就是答案一定要用long long,不然最后三个会WA

原文地址:https://www.cnblogs.com/xiaoguapi/p/10364846.html