CF817D 不平衡序列

1 CF817D 不平衡序列

2 题目描述

时间限制 \(2s\) | 空间限制 \(256M\)

You are given an array a consisting of \(n\) elements. The imbalance value of some subsegment of this array is the difference between the maximum and minimum element from this segment. The imbalance value of the array is the sum of imbalance values of all subsegments of this array.

For example, the imbalance value of array \([1, 4, 1]\) is \(9\), because there are 6 different subsegments of this array:

  • \([1]\) (from index \(1\) to index \(1\)), imbalance value is \(0\);
  • \([1, 4]\) (from index \(1\) to index \(2\)), imbalance value is \(3\);
  • \([1, 4, 1]\) (from index \(1\) to index \(3\)), imbalance value is \(3\);
  • \([4]\) (from index \(2\) to index \(2\)), imbalance value is \(0\);
  • \([4, 1]\) (from index \(2\) to index \(3\)), imbalance value is \(3\);
  • \([1]\) (from index \(3\) to index \(3\)), imbalance value is \(0\);
    You have to determine the imbalance value of the array \(a\).

数据范围: \(1 ≤ n ≤ 10^6\)

3 题解

我们将 \(\sum_{1 \le i < j \le n} \limits \max_{k = i}^j \limits a_k - \min_{k = i}^j \limits a_k\) 这个式子进行化简,可以得到 \(\sum_{1 \le i < j \le n} \limits \max_{k = i}^j \limits a_k - \sum_{1 \le i < j \le n} \limits \min_{k = i}^j \limits a_k\)。也就是说,我们可以考虑每一个数是多少个区间的最大值和最小值,然后计算出差值即可。容易想到,由于区间都是连续的,我们可以利用单调栈求出每一个数左边第一个大于它和第一个小于的它的数的坐标,以及右边第一个大于它和第一个小于它的数的坐标。我们假设这四个坐标分别是 \(Lb, Ls, Rb, Rs\)。那么显然,我们当前这个坐标为 \(i\) 的数对答案的总贡献就是 \((i - Lb) \times (Rb - i) \times a_i - (i - Ls) \times (Rs - i) \times a_i\)。这也可以理解成,我们在 \([Lb+1, i]\) 中任选一个坐标作为左端点,在 \([i, Rb-1]\) 中任选一个坐标作为右端点,一共可以组成的区间数。剩下的另一部分同理。总共的时间复杂度就是 \(O(n)\),可以通过 \(10^6\)

4 代码(空格警告):

#include <iostream>
#include <cstring>
#include <map>
using namespace std;
const int N = 1e6+10;
#define int long long
int n, maxn, minn, top1, top2, ans;
int a[N], Lb[N], Rb[N], Ls[N], Rs[N];
int st1[N], st2[N];
signed main()
{
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    top1 = 0, top2 = 0;
    for (int i = 1; i <= n; i++)
    {
        while (top1 && a[st1[top1]] > a[i]) top1--;
        while (top2 && a[st2[top2]] < a[i]) top2--;
        if (!top1) Ls[i] = 0;
        else Ls[i] = st1[top1];
        if (!top2) Lb[i] = 0;
        else Lb[i] = st2[top2];
        st1[++top1] = i;
        st2[++top2] = i;
    }
    memset(st1, 0, sizeof(st1));
    memset(st2, 0, sizeof(st2));
    top1 = 0, top2 = 0;
    for (int i = n; i >= 1; i--)
    {
        while (top1 && a[st1[top1]] >= a[i]) top1--;
        while (top2 && a[st2[top2]] <= a[i]) top2--;
        if (!top1) Rs[i] = n+1;
        else Rs[i] = st1[top1];
        if (!top2) Rb[i] = n+1;
        else Rb[i] = st2[top2];
        st1[++top1] = i;
        st2[++top2] = i;
    }
    for (int i = 1; i <= n; i++)
    {
        ans += (i - Lb[i]) * (Rb[i] - i) * a[i];
        ans -= (i - Ls[i]) * (Rs[i] - i) * a[i];
    }
    cout << ans;
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-04-06 22:21  David24  阅读(108)  评论(0编辑  收藏  举报