有一個長度為 nn 的陣列 hih_i,有如下兩個操作:

  1. 任選一個 ii,令 hihi1h_i \gets h_i - 1,代價為 11
  2. 任選一個 i,xi, x,令 hihixh_i \gets h_i - x,代價為 xx。 如果操作 2 使得 hi=0h_i = 0 了,那麼就會接著對相鄰的兩個 hi1h_{i-1}hi+1h_{i+1} 進行 x=hi1x = h_i - 1 的操作 2,如此遞迴下去。

只能使用一次操作 2,且操作 2 要能把所有非 0 的 hh 變成 0,問最小代價。

由於要一口氣使所有 hih_i 變成 0,則操作 2 之前必須用操作 1 把 hh 陣列變成單峰的,即存在一個 ii 使得 h0h_0hih_i 嚴格單調遞增,hih_ihn1h_{n-1} 嚴格單調遞減。令 preipre_i 表示 00ii 單調遞增的代價,backiback_i 表示 iin1n-1 單調遞減的代價,則答案就是 min{prei+backi+hi}\min\{pre_i + back_i + h_i\}

hih_i 好求,preipre_ibackiback_i 求法一致,所以只用考慮如何求 preipre_i

容易想到單調棧,我們用一個二元組 (h,w)(h, w) 來表示一個最高高度為 hh、寬度為 ww、相鄰兩數高差為 11 的階梯。列舉 ii,如果棧頂的 htoph_{top} 大於 hiwih_i - w_i,則不單調,需要累加答案,並彈出棧頂,並使 wiwi+wtopw_i \gets w_i + w_top

struct node_t
{
    int h, w;
    node_t() {}
    node_t(int h, int w) : h(h), w(std::min(h, w)) {}
    long long maxsize(int h)
    {
        return (long long)h * (h + 1) / 2;
    }
    long long size()
    {
        if (h <= w) return maxsize(h);
        return maxsize(h) - maxsize(h - w);
    }
};
 
void solve()
{
    int n;
    cin >> n;
    vector<int> h(n);
    for (auto &i : h) cin >> i;
 
    auto calc_pre = [](const std::vector<int> &h) -> std::vector<long long>
    {
        int n = h.size();
        std::vector<long long> res(n);
        std::stack<node_t> s;
        long long ans = 0;
        for (int i = 0; i < n; i++) {
            node_t cur(h[i], 1);
            while (!s.empty() && cur.h - cur.w < s.top().h) {
                node_t tmp = s.top();
                s.pop();
                node_t new_cur = node_t(cur.h, cur.w + tmp.w);
                ans += cur.size() + tmp.size() - new_cur.size();
                cur = new_cur;
            }
            s.emplace(cur);
            res[i] = ans;
        }
        return res;
    };
    auto pre = calc_pre(h);
    std::ranges::reverse(h);
    auto back = calc_pre(h);
    std::ranges::reverse(h);
    std::ranges::reverse(back);
    auto ans = std::numeric_limits<long long>::max();
    for (int i = 0; i < n; i++) {
        ans = std::min(ans, pre[i] + back[i] + h[i]);
    }
    cout << ans << endl;
}