P1823 [COI2007] Patrik 音乐会的等待 洛谷
很容易分析出边界点是身高比h[i]高的人,单调栈里是形成单调递减栈.能与h[i]形成一对的人h<=h[i],而且h[i]能看到离他最近的比他高的人,所以本题我们需要利用单调栈的边界点和while循环里pop的点,因为要避免重复,所以我们只需要从左边或右边开始计算对数,而且我们还需要统计身高相同的人,因为身高相同的人也会被pop掉。
切入点是top与h[i]的值,如果top>h[i]那么普通地+1即可,如果top<=h[i],我们需要不断pop直到达到左边条件.
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 typedef pair<int,int> pii; 5 const int N = 5e5+10; 6 ll ans; 7 int h; 8 pii p[N];//思路,被pop掉的人都比h[i]矮,因此可以交流, 此前的情况:a,b,c(a.h<b.h<c.h) c可看a但a不可看c,实际在c计算之前b就会把a pop掉 9 //栈内是一个单调递减的序列(h[i]一定可以与栈内比他矮之人交流,h[i]与栈形成的曲线是类似x^2的曲线) 10 //要注意身高相同的情况 ,他会被与他身高相同的人pop掉 11 int main() 12 { 13 stack<pii> stk; 14 int n; scanf("%d",&n); 15 for(int i=1;i<=n;i++){ 16 scanf("%d",&h); 17 p[i] = {h,1}; 18 for(;!stk.empty()&&stk.top().first<=h;stk.pop()){ 19 ans+=stk.top().second; 20 if(stk.top().first==h) p[i].second+=stk.top().second;//之前身高相等的人数 21 } 22 if(!stk.empty()) ans++;//还能与比他高的 最近的交流 23 stk.push(p[i]); 24 } 25 printf("%lld\n",ans); 26 return 0; 27 }