牛可乐发红包脱单ACM赛$ C 区区区间间间(单调栈)

链接:https://ac.nowcoder.com/acm/contest/223/C
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

给出长度为n的序列a,其中第i个元素为,定义区间(l,r)的价值为

请你计算出

输入描述:

第一行输入数据组数T
对于每组数据,第一行为一个整数n,表示序列长度
接下来一行有n个数,表示序列内的元素

输出描述:

对于每组数据,输出一个整数表示答案

示例1

输入

复制

3
3
4 2 3
5
1 8 4 3 9
20
2 8 15 1 10 5 19 19 3 5 6 6 2 8 2 12 16 3 8 17 

输出

复制

5
57
2712

说明

对于一组测试数据的解释:
区间[1, 2]的贡献为:4 - 2 = 2
区间[1, 3]的贡献为:4 - 2 = 2
区间[2, 3]的贡献为:3 - 2 = 1
2 + 1 + 2 = 5.

备注:

 

不保证数据随机生成!

单调栈解决;

分两种情况讨论,1,以当前点为端点;2,不以当前点为端点

#include <bits/stdc++.h>
#define maxn 100005
#define inf 0x3f3f3f3f
typedef long long ll;

using namespace std;

ll a[maxn];
stack< pair<ll,ll> > q;
typedef pair<ll,ll> p;
int main()
{
    ll t,n;
    cin >> t;

    while(t--)
    {
        while(!q.empty())q.pop();

        cin >> n;
        for(int i = 1; i <= n; i ++)
        {
            cin >> a[i];
        }
        a[0] = inf + 1; a[n+1] = inf;

        ll sum = 0;
        q.push(make_pair(0,a[0]));
        q.push(make_pair(1,a[1]));
        for(int i = 2; i <= n + 1; i ++)
        {
            p x;
            x = q.top();
            while(x.second <= a[i])
            {
                q.pop();
                sum += (i - x.first - 1) * x.second;
                sum += (i - x.first) * (x.first - q.top().first - 1) * x.second;
                x = q.top();
            }
            q.push(make_pair(i,a[i]));
        }

        while(!q.empty())q.pop();
        a[0] = -inf - 1; a[n+1] = -inf;
        q.push(make_pair(0,a[0]));
        q.push(make_pair(1,a[1]));
        for(int i = 2; i <= n + 1; i ++)
        {
            p x;
            x = q.top();
            while(x.second >= a[i])
            {
                q.pop();
                sum -= (i - x.first - 1) * x.second;
                sum -= (i - x.first) * (x.first - q.top().first - 1) * x.second;
                x = q.top();
            }
            q.push(make_pair(i,a[i]));
        }

        cout << sum << endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值