mayoko’s diary

プロコンとかいろいろ。

Codeforces Round #333 (Div. 1) B. Lipshitz Sequence

解法

i と j が 2 以上離れている整数の組(i, j) について, |h[i]-h[j]|/|i-j| が L(h) として採用されることは無いです。つまり, i と i+1 について, |h[i+1]-h[i]| という値のみ考えれば良く, 他の値は無視して構わないです。

あとやるべきことは, 各区間 [l, r] について, L(h) の値として |h[i+1]-h[i]| が採用されるような部分区間がいくつあるのかを O(N) で求める作業です。これは, 前やった問題に似ています。mayokoex.hatenablog.com
この問題の解法とほとんど同じですが, 一つ注意なのは, 同じ値の扱いです。|h[i+1]-h[i]| の値と |h[j+1]-h[j]| の値が一致している場合, (i, i+1) の方からは (j, j+1) も含むように部分区間をとっても良いですが, その場合(j, j+1) の方から (i, i+1) の区間も含むように 部分区間を取ってはいけません。
i < j の場合は (i, i+1) からだけ (j, j+1) の区間をとっても良いことにすれば OK です。

const int MAXN = 100010;
int a[MAXN];

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; i++) cin >> a[i];
    vector<int> b(n-1);
    for (int i = 0; i < n-1; i++) b[i] = abs(a[i]-a[i+1]);
    while (m--) {
        int l, r;
        cin >> l >> r;
        l--; r--;
        vector<int> c(r-l);
        for (int i = l; i < r; i++) c[i-l] = b[i];
        vector<ll> L(r-l), R(r-l);
        {
            stack<pii> st;
            int cur = 0;
            while (cur < r-l) {
                st.push(pii(c[cur], cur));
                int i = cur+1;
                while (i < r-l && st.top().first >= c[i]) {
                    st.push(pii(c[i], i));
                    i++;
                }
                while (i < r-l && !st.empty() && st.top().first < c[i]) {
                    pii p = st.top(); st.pop();
                    L[p.second] = i-p.second;
                }
                cur = i;
            }
            while (!st.empty()) {
                pii p = st.top(); st.pop();
                L[p.second] = r-l-p.second;
            }
        }
        reverse(c.begin(), c.end());
        {
            stack<pii> st;
            int cur = 0;
            while (cur < r-l) {
                st.push(pii(c[cur], cur));
                int i = cur+1;
                while (i < r-l && st.top().first > c[i]) {
                    st.push(pii(c[i], i));
                    i++;
                }
                while (i < r-l && !st.empty() && st.top().first <= c[i]) {
                    pii p = st.top(); st.pop();
                    R[p.second] = i-p.second;
                }
                cur = i;
            }
            while (!st.empty()) {
                pii p = st.top(); st.pop();
                R[p.second] = r-l-p.second;
            }
        }
        reverse(c.begin(), c.end());
        reverse(R.begin(), R.end());
        ll ans = 0;
        for (int i = 0; i < r-l; i++) {
            ans += c[i] * R[i] * L[i];
        }
        cout << ans << endl;
    }
    return 0;
}