いかにも stack が登場しそうな問題!
問題概要
下の図のように、高さが の仕切りが等間隔に並んでいて、その間と両端の
カ所のスペースを表す番号を
とする。これらは幅が等しい。
今、スペース 0 に水を入れていく。1 個分のスペースについて、水位は 1 秒で 1 だけ上昇する量の水である。
このとき、各 について、スペース
に水が入り始める瞬間の時刻 + 1 の値を求めよ。

制約
考えたこと
スペース に水が入り始めるのは、スペース
の水位が
になった瞬間である。その瞬間の水の量を求めればよい。今、次のように配列
dp を定義しよう。
dp[i] ← スペース に水が入り始める瞬間の時刻
すると、下図のように となる最大の [tex j] (
) をとったとき、
dp[i] = dp[j] + H[i] * (i - j)
と表せる。なお、ここで としておく。

あとは、各 に対して、
となる最大の [tex j] (
) を求める必要がある。これはよく知られた有名問題で、stack を使って
の計算量で求められる。詳しくは次の問題の解説(鉄則本にある)を参照。
全体として配列 dp を求める計算量は と評価できる。
コード
#include <bits/stdc++.h> using namespace std; const long long INF = 1LL<<60; int main() { long long N; cin >> N; vector<long long> H(N + 1, INF); for (int i = 1; i <= N; i++) cin >> H[i]; // H[j] > H[i] となる最大の j を求める vector<long long> prev(N+ 1); vector<pair<long long, int>> stac; for (int i = 0; i <= N; i++) { while (!stac.empty() && stac.back().first <= H[i]) stac.pop_back(); if (stac.empty()) prev[i] = 0; else prev[i] = stac.back().second; stac.emplace_back(H[i], i); } // DP vector<long long> dp(N+1, 0); for (int i = 1; i <= N; i++) { dp[i] = dp[prev[i]] + H[i] * (i - prev[i]); cout << dp[i]+1 << " "; } cout << endl; }