[COI2007] Patrik

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.
設計一個程序,求出人羣中有多少對人能夠互相看見。

隨機的題。。題目第一眼看起來就是個單調棧。。
考慮 A 怎麼看到左邊的人:
1.A 一定能互相看到左邊第一個比他高的人。
2.A 可以看到左邊單調遞減區間的人。

這個東西維護一個單調遞減的單調棧就好了。
然後對於相同高度的,我們可以縮點分類討論一下記錄塊中的 size
只有 A 這個塊中最左邊的人能向左一覽無餘單調遞減區間。而遇到比他高的人 A 整塊都會看到。
如果碰到高度相同的人,顯然兩兩都能看到,然後最後合併 size

#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
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章