Atcoder Beginner Contest ABC 140 E - Second Sum
- 問題
- 解法
これと同じ感じでやる。
atcoder.jp
ある数が2番目に大きい区間はどういう特徴があるか考える。
よく考えるとはより大きい数をちょうど1つ含んでいる区間である事がわかる。
より大きく、かつより右側にあるもののうち一番左側にあるものを、その一つ右側の数をとする。
同様により大きく、かつより左側にあるもののうち一番右側にあるものを、その一つ左側の数をとする。
が2番目に大きい区間はを両方含みを含まない区間、またはを両方含みを含まない区間のどちらかとなる。
を両方含みを含まない区間は区間の左端が]、右端がであるような区間であることがわかる。
このような区間の数はの数列中での位置をそれぞれとすれば個ある。
を両方含みを含まない区間の数も同様に求められる。
あとはに対しての位置を求められれば良い。
これはをの順で見ていき、をの位置を求めたのち(これらはlower_boundで求めることができる)、multisetにの位置posを挿入すれば良い。
- 感想
multisetのイテレータを前から見るとmultiset内の要素を昇順に見れることを忘れていました...
#include <iostream> #include <vector> #include <set> using namespace std; typedef long long int ll; #define rep(i,n) for(int i=0;i<(n);++i) int main() { int n; cin>>n; vector<ll> p(n),pos(n+1,0); rep(i,n){ cin>>p[i]; pos[p[i]] = i+1; } ll ans = 0; multiset<ll> s; s.insert(0); s.insert(0); s.insert(n+1); s.insert(n+1); for (ll now = n; now >= 1; now--){ auto it = s.lower_bound(pos[now]); ll pos_r = *it; it++; ll pos_rr = *it; it--; it--; ll pos_l = *it; it--; ll pos_ll = *it; ans += now*(pos_r-pos[now])*(pos_l-pos_ll); ans += now*(pos_rr-pos_r)*(pos[now]-pos_l); s.insert(pos[now]); } cout<<ans<<endl; return 0; }