題目連結:[COI2007] Patrik 音乐会的等待 - 洛谷
一開始看到題目有種逆序對的感覺,但題目說明中間若有比自己高的點就不算一對,這就不關逆序對的事情了。
1. 中間不能有比自己高的人
2. 相鄰兩個人可以算一對
從這個特性我們知道,假設前面有k個人,他們的升高都是降序排好的,如果有一個人進來了,他比這k個人都大,那麼如果第k + 2個人進來,我們可以保證這k + 2個人都不能和這k個人湊成一對,因為第k+1個人比前k個人要高,這就是題目給的條件1。
那這就挺適合用單調棧的了,我們保證單調棧是降序的,一旦有比棧頂高的人進來,那就說明棧內所有比這個人矮的人都能成一對,因為我們的棧是降序的。
那麼考慮一下一樣高的人進來怎麼辦?他不能只對答案貢獻1啊,因為棧內的其他人也有可能和他湊成一對,一會進來的人也能跟他湊成一對,那可以怎麼辦?
想到這裡我就可以用一個結構體,把重複的身高記一下,一會有比當前高的人進來,我們就不用擔心我們把前面的人彈出棧導致正確性不能保證了,並且整個棧都是保證絕對降序,不會有一樣的存在,而且對答案的貢獻是出現的次數。
代碼 很簡單就是普通的棧,加上結構體。
#include <iostream>
#include <vector>
using namespace std;
int n;
long long ans = 0;
struct node{
int val, num;
};
vector<node> s;
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
int a;
cin >> a;
node m = (node){a, 1};
while(!s.empty() && s.back().val <= a){
ans += s.back().num;
if(s.back().val == a){
m.num +=s.back().num;
}
s.pop_back();
}
//reason 1
if(!s.empty())ans++;
s.push_back(m);
}
cout << ans << endl;
return 0;
}
reason 1
如果棧一直被彈出,並且是空的,那麼答案無需匹配,因為最後沒有人可以跟新進來的人進行匹配,但是如果棧不是空,也就是說最後有人可以和新進來的人進行匹配,答案就要加1,不然會少算一對。