POJ 3250 Bad Hair Day(luogu P2866)
http://poj.org/problem?id=3250 https://www.luogu.com.cn/problem/P2866
https://vjudge.net/problem/POJ-3250 https://vjudge.net/problem/%E6%B4%9B%E8%B0%B7-P2866
問題概要
長さ$N$の数列$h_i$が与えられる。以下の値を求めよ。 $$ \sum_{1\leq i<j\leq N}f(i,j) $$ ただし、 $$ f(i,j)=\left{ \begin{array}{ll} 1 & \mathrm{if}\quad h_i>\max(h_{i+1},h_{i+2},\cdots, h_{j}) \ 0 & \mathrm{otherwise} \end{array} \right. $$ とする。
制約
$1\leq h_i\leq 10^9$
解法メモ
-
幾つか解法は考えられ、例えばセグ木+二分探索などでも出来るが、stackを使えば線形時間で解くことができる。
-
$f(i,j)$の$j$を固定するような感じで見ていくとよい。
-
$h_j$を左から順にみていき、$j$番目まで見た時に、$i$の候補としてあり得るものだけをスタックに格納していく。
-
これは狭義単調減少になり、$h_j$を格納する時に末尾からそれ以上のものを削除していけばよい。
実装例
#include <iostream>
#include <stack>
#include <vector>
typedef long long ll;
#define rep(i, n) for (int i = 0, i##_len = (n); i < i##_len; ++i)
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
vector<int> h(n);
rep(i, n) cin >> h[i];
stack<int> st;
ll ans = 0;
rep(j, n) {
while (!st.empty() && st.top() <= h[j]) st.pop();
ans += st.size();
st.push(h[j]);
}
cout << ans << "\n";
}