A[j] ≧ A[i] である最大のjを求める

A[j] ≧ A[i] である最大の j (ただし j < i)を求めるのであれば簡単にできます。

しかしすべてのiについてjを求めなければならないときに以下のようにするのは効率が悪すぎます。時間計算量は配列の長さを N とすると O(N^2) になってしまいます。

スタックを使うと O(N) でできます。スタックに添字と値をペアにしたものを格納していくのですが、Pushするまえに小さな値があればすべてPopしてしまいます。それによってスタックが空になってしまえば解なし(-1)、空でない場合はPeekで得られる添字が解となります。

このようなメソッドを定義しておくと幸せになれるかもしれません。

本当に幸せになれるのでしょうか?

D – 登山家

D – 登山家

これはすべての i について A[j] > A[i] である最小の j1 と最大の j2 を求めてその間の長さ(i, j1, j2は含めない)を求めればよいという問題です。

上で定義したメソッドを使えば解けそうです。

C – 行列のできるドーナツ屋

C – 行列のできるドーナツ屋

ちょっと考察が必要ですが、これも上で定義したメソッドを使うと解ける問題です。

これは人を三色の棒で表現したものですが、青い人よりも右側にある青い人よりも高い人を探してみると赤い人が見つかります。

人の高さの配列を A、青い人がいる位置を b、赤い人がいる位置を r と置きます。このとき、b と r の間には A[b] を超えるものが存在しないことに気づきます。ここから b + 1 番目から r 番目までの人は青い人を見ることができることがわかります。

そこで解を格納する配列 B を定義して b + 1 番目から r 番目まで 1 を加算します。先頭から最後尾まで i番目が青い人だったらどうなるかを考えれば解を得ることができます。

ただし広い区間に1を追加する処理をそのままやろうとすると時間がかかるので、「imos法」を使います。これは区間[a, b]にvを追加するという処理を繰り返す場合、imos[a] += v, imos[b + 1] -= v とし、最後にimosの累積和(先頭からi番目までの総和)を計算することで高速に処理を行おうとするテクニックです。