COI2007 Patrik 音乐会的等待 洛谷P1823
Description
N个人正在排队进入一个音乐会。人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人。队列中任意两个人A和B,如果他们是相邻或他们之间没有人比A或B高,那么他们是可以互相看得见的。
写一个程序计算出有多少对人可以互相看见。
Input
输入的第一行包含一个整数N,表示队伍中共有N个人。接下来的N行中,每行包含一个整数,表示人的高度,以毫微米(等于10的-9次方米)为单位,每个人的调度都小于2^31毫微米。这些高度分别表示队伍中人的身高。
Output
输出仅有一行,包含一个数S,表示队伍中共有S对人可以互相看见。
Hint
1≤N≤500000。
Solution
最开先是写的一个很简单的数组模拟单调栈,加了快读Luogu上面专门设置的三个点还是超时了。。。后来看了官方题解,维护了一个数对pair的单调栈。值得注意的是,这里的pair含义是pair<身高,人数>。
由于我们知道,当这个人前后视线里面遇到了一个极其高的B,那么B后面的所有人,这个人都是看不到的。所以单调栈是降序的,当他和一个人聊完天以后就弹出这一个人,弹出后如果栈没空他就可以再聊一个,然后再让这个人进栈。当然,如果两个人身高相同的话,还是能看到这个人后面的人啦quqqq。
TLE了最后三个点的80分代码:
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#define maxn 500005
using namespace std;
int stackk[maxn],cnt;
int n,x,j;
long long ans;
void quickread(int &x){
char c;
while((c=getchar())<'0'||c>'9');
for(x=0;c>='0'&&c<='9';c=getchar()){
x=x*10+c-'0';
}
}
int main(){
quickread(n);
for(int i=1;i<=n;i++){
quickread(x);
j=1;
while(x>stackk[cnt]&&cnt>0){
cnt--;
ans++;
}
while(x==stackk[cnt]&&cnt>0){
cnt--;
ans++;
j++;
}
if(cnt!=0){
ans++;
}
cnt+=j;
stackk[cnt]=x;
}
printf("%lld\n",ans);
}
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<stack>
#define int long long
#define s pair<int,int>
using namespace std;
stack<s>stk;
int n,x,ans;
void quickread(int &x){
char c;
while((c=getchar())<'0'||c>'9');
for(x=0;c>='0'&&c<='9';c=getchar()){
x=x*10+c-'0';
}
}
signed main(){
quickread(n);
for(int i=1;i<=n;i++){
quickread(x);
s p(x,1);
for(;!stk.empty()&&stk.top().first<=x;stk.pop()){
ans+=stk.top().second;
if(stk.top().first==x){
p.second+=stk.top().second;
}
}
if(!stk.empty())ans++;
stk.push(p);
}
printf("%lld",ans);
return 0;
}