2019E0_C连续子序列的权值

∥☆過路亽.° 提交于 2019-12-02 10:31:08

连续子序列的权值

题目

知识点:单调栈

我们定义连续序列a[p],a[p+1]…a[q]的权值为max(a[p],a[p+1]…a[q])- min(a[p],a[p+1]…a[q]),给定一个由N个整数组成的序列,请求出所有连续子序列的权值和。

输入

第1行:1个数N,表示数组的长度。(1<=N<=50000)
第2−N+1行:每行1个数,表示数组中的元素(1<=A[p]<=50000)

输出

输出所有连续子序列的权值和。

输入样例

5
1
2
3
4
5

输出样例

20

思路

我们定义连续序列a[p],a[p+1]…a[q]的权值为max(a[p],a[p+1]…a[q)- min(a[p],a[p+1]…a[q]),给定一个由N个整数组成的序列,请求出所有连续子序列的权值和。
首先题目的意思可以转化为求所有的子数组最大值之 和减去所有的子数组最小值之和。
那么我们可以通过两次单调栈求得以每个 a[i]作为最大以最小的左右两端能到达的端点。
然后以每个 a[i]作为贡献的区间的值是多少呢?因为当 a[i]作为贡献时子数组区间必过 a[i],那么我们只需要在 a[i] 作为贡献的左区间和右区间任选 2 个组成区间即为 a[i]的贡 献,所以是 a[i](i-l[i]+1)(r[i]-i+1)。

代码

#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <iostream>
#include <map>
#include <random>
#include <queue>
#include <cstring>
#include <set>
#include <stack>
using namespace std;
typedef long long ll;
const int ms = 50050;
int a[ms], l[ms];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, k;
    cin >> n;
    for (int i = 0; i < n; ++i)
    {
        cin >> a[i];
    }
    ll res = 0;
    stack<int> s;
    for (int i = 0; i < n; ++i)
    {
        while (!s.empty() && a[s.top()] < a[i])
        {
            res += 1ll * (i - s.top())*(s.top() - l[s.top()]) * a[s.top()];
            s.pop();
        }
        if (s.empty()) l[i] = -1;
        else l[i] = s.top();
        s.push(i);
    }
    ll r = n;
    while (!s.empty())
    {
        res += 1ll * (r - s.top())*(s.top() - l[s.top()])* a[s.top()];;
        s.pop();
    }
    for (int i = 0; i < n; ++i)
    {
        while (!s.empty() && a[s.top()] > a[i])
        {
            res -= 1ll * (i - s.top())*(s.top() - l[s.top()])* a[s.top()];;
            s.pop();
        }
        if (s.empty()) l[i] = -1;
        else l[i] = s.top();
        s.push(i);
    }
    r = n;
    while (!s.empty())
    {
        res -= 1ll * (r - s.top())*(s.top() - l[s.top()])* a[s.top()];;
        s.pop();
    }
    cout << res;
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!