[COI2007] [luogu P1823] Patrik 音乐会的等待 解题报告 (单调栈)

Posted xxzh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[COI2007] [luogu P1823] Patrik 音乐会的等待 解题报告 (单调栈)相关的知识,希望对你有一定的参考价值。

题目链接:https://www.luogu.org/problemnew/show/P1823

题目:

N个人正在排队进入一个音乐会。人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人。

队列中任意两个人A和B,如果他们是相邻或他们之间没有人比A或B高,那么他们是可以互相看得见的。

写一个程序计算出有多少对人可以互相看见。

题解:

我们发现,其实就是算每个人向前看能看到多少个人之和对吧?

发现如果1号既比2号,又比2号靠后,后面的人就不可能看得到2号

于是我们考虑维护一个单调递减的栈,在不含重复大小元素的情况下,发现弹出的元素的数目就可以直接累加进ans里,特判一下如果这个时候还有元素在栈里那么显然也是看得到的,ans++

但是怎么处理重复的元素呢?我们考虑把重复的元素合并起来一起处理,具体实现就是开个pair,first记录高度,second记录人数

luogu上别忘了开long long

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
typedef long long ll;

using std::pair;
const int N=5e5+15;
int n,r;
ll ans;
ll a[N];
pair <int,int> q[N];
inline ll read()
{
    char ch=getchar();
    ll s=0,f=1;
    while (ch<0||ch>9) {if (ch==-) f=-1;ch=getchar();}
    while (ch>=0&&ch<=9) {s=(s<<3)+(s<<1)+ch-0;ch=getchar();}
    return s*f;
}
int main()
{
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<=n;i++)
    {
        pair <int,int> p(a[i],1);
        while (r&&q[r].first<=a[i]) 
        {
            ans+=q[r].second;
            if (q[r].first==a[i]) p.second+=q[r].second;
            r--;
        }
        if (r) ans++;
        q[++r]=p;
    }
    printf("%lld
",ans);
    return 0;
}

 

以上是关于[COI2007] [luogu P1823] Patrik 音乐会的等待 解题报告 (单调栈)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P1823 音乐会的等待 题解

Luogu3846 [TJOI2007] 可爱的质数/模板BSGS

luogu P2215 [HAOI2007]上升序列

Luogu_4329 [COCI2006-2007#1] Bond

[树形DP]Luogu P1131 [ZJOI2007]时态同步

SCOI2007压缩