CodeForces - 817D Imbalanced Array

该博客讨论了CodeForces上的一道编程问题817D,涉及计算数组所有子序列的最大最小值之差的绝对值总和。博主解释了解题思路,即使用单调栈来维护以每个元素为最大值或最小值的区间,并指出在计算过程中需要注意避免重复计数的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CodeForces - 817D 

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 valuesof all subsegments of this array.

For example, the imbalance value of array [1, 4, 1] is 9, because there are 6different 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.

Input

The first line contains one integer n (1 ≤ n ≤ 106) — size of the array a.

The second line contains n integers a1, a2... an (1 ≤ ai ≤ 106) — elements of the array.

Output

Print one integer — the imbalance value of a.

Example

Input

3
1 4 1

Output

9

题目大意:给出一个序列,要求所有子序列的最大最小值只差的绝对值之和。

解题思路:第一反应是按照贡献来算,但是没有具体的思路。正解是对于每个数利用单调栈维护每个数

为最大最小值的区间。

然后最后的答案就是ans=(以a[i]为最大值的区间个数)*a[i]-(以a[i]为最小值的区间个数)*a[i];

其中区间个数可以根据以a为最值得左右区间得出。

然后会发现连样例都过不了。。。。。

这是因为1 4 1

我们算以第一个1为最小值的时候

1 4

1 4 1

算了两次。

算最后一个1为最小值的时候也算了两次。

也就是 1 4 1 重复算了。 

所以我们在我们只要让区间内没有相等的数就可以了。也就是用单调栈维护的时候让左区间为开区间。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define sca(x) scanf("%d",&x)

const int N = 1e6+5;
stack<int>s;
int L[N],R[N];
int L1[N],R1[N];
int a[N];
int main()
{
    int n;
    sca(n);
    for(int i=1; i<=n; i++)
    {
        sca(a[i]);
    }
    for(int i=1; i<=n; i++)
    {
        while(s.size()>0&&a[s.top()]>a[i])s.pop();
        if(s.size()==0)L[i]=1;
        else L[i]=s.top()+1;
        s.push(i);
    }
    while(!s.empty())s.pop();
    for(int i=n; i>=1; i--)
    {
        while(s.size()>0&&a[s.top()]>=a[i])s.pop();
        if(s.size()==0)R[i]=n;
        else R[i]=s.top()-1;
        s.push(i);
    }

    while(!s.empty())s.pop();
    for(int i=1; i<=n; i++)
    {
        while(s.size()>0&&a[s.top()]<a[i])s.pop();
        if(s.size()==0)L1[i]=1;
        else L1[i]=s.top()+1;
        s.push(i);
    }
    while(!s.empty())s.pop();
    for(int i=n; i>=1; i--)
    {
        while(s.size()>0&&a[s.top()]<=a[i])s.pop();
        if(s.size()==0)R1[i]=n;
        else R1[i]=s.top()-1;
        s.push(i);
    }
    LL ans=0;
    for(int i=1;i<=n;i++)
    {
        ans+=((1LL*(i-L1[i]+1)*(R1[i]-i))+i-L1[i])*a[i];
        ans-=((1LL*(i-L[i]+1)*(R[i]-i))+i-L[i])*a[i];
    }
    cout<<ans<<endl;
}
/*
1 4 1
1 3
2 2
1 4 1
1 2 4 1
(i-L[i])*(R[i]-i)+(R[i]-i)+(i-L[i])
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值