[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 音乐会的等待 解题报告 (单调栈)的主要内容,如果未能解决你的问题,请参考以下文章
Luogu3846 [TJOI2007] 可爱的质数/模板BSGS
Luogu_4329 [COCI2006-2007#1] Bond