N people are waiting in line to enter a concert. People get bored waiting so they turn and look for someone familiar in the line.
n个人排队等待进入音乐会。人们无聊地看看队伍里有没有自己熟悉的人。
Two persons A and B standing in line can see each other if they’re standing right next to each other or if no person between them is strictly taller than person A or person B.
A和B两个人如果能够互相看见,他们要么挨着,要么他们两人之间没有人严格高于A或B。
Write a program that determines the number of pairs of people that can see each other.
设计一个程序,求出人群中有多少对人能够互相看见。
随机的题。。题目第一眼看起来就是个单调栈。。
考虑 AA 怎么看到左边的人
1.A1.A 一定能互相看到左边第一个比他高的人。
2.A2.A 可以看到左边单调递减区间的人。
这个东西维护一个单调递减的单调栈就好了。
然后对于相同高度的,我们可以缩点分类讨论一下记录块中的 sizesize。
只有 AA 这个块中最左边的人能向左一览无余单调递减区间。而遇到比他高的人 整块都会看到。
如果碰到高度相同的人,显然两两都能看到,然后最后合并 sizesize。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>par;
typedef pair<par,ll>pii;
const ll INF=2e18;
const int MAXN=8e5+5;
#define mp make_pair
par a[MAXN];
pii sta[MAXN];
ll cnt=0,n,top=0,ans=0,recalc=0;
int main(){
scanf("%lld",&n);
recalc=n-1;
for(int i=1;i<=n;i++){
ll tmp;
scanf("%lld",&tmp);
if(tmp!=a[cnt].first)a[++cnt]=mp(tmp,1);
else a[cnt].second++;
}
for(int i=1;i<=cnt;i++)if(a[i].second>2)recalc+=(a[i].second-1)*(a[i].second-2)/2;
// a[0]=mp(INF,1);
// sta[++top]=mp(a[0],0);
for(int i=1;i<=cnt;i++){
//cout<<ans<<endl;
int flag=0;
while(top&&sta[top].first.first<=a[i].first){
if(sta[top].first.first==a[i].first){
ans+=sta[top].first.second*a[i].second;
flag=sta[top].first.second;top--;
break;
}
ans+=sta[top].first.second;
if(i>1&&i-1==sta[top].second)ans--;
top--;
}
if(top)ans+=a[i].second;
if(top&&sta[top].second==i-1)ans--;
if(flag)a[i].second+=flag;
sta[++top]=mp(a[i],i);
}
printf("%lld\n",ans+recalc);
return 0;
}
/*
6
3
2
2
1
2
2
*/