NC20806 区区区间间间

题目链接

题目链接

题意

给出长度为n的序列a,其中第i个元素为ai,定义区间(l,r)的价值为
Vl,r=max(ai-aj|l<=i,j<=r)
请你计算出 ∑ \sum nl=1 ∑ \sum nr=l+1Vl,r

思路

  • 题意表达式可变换为 ∑ \sum nl=1 ∑ \sum nr=l+1maxal,r- ∑ \sum nl=1 ∑ \sum nr=l+1minal,r
  • maxal,r表示区间l到r的最大值
  • minal,r表示区间l到r的最小值
  • 其中-最小值的和可以取数组的反数的最大值
  • 利用栈可以计算a[i]为最大值的区间的左坐标和右坐标
  • 则a[i]对答案的贡献可以分为两种
  1. a[i]为端点,则另一个端点的个数为r[i]-l[i]+1-1
  2. a[i]不为端点,则左端点的个数为i-l[i]+1-1,右端点的个数为r[i]-i+1-1
  • 综上,a[i]对答案的贡献为a[i]((r[i]-l[i])+(i-l[i])(r[i]-i))

参考代码

#include<bits/stdc++.h>
using namespace std;
set<int> aa;
int main()
{
    #include<bits/stdc++.h>
using namespace std;
long long  aa[100010];
long long  l[100010],r[100010];
int n;
long long js()
{
    memset(l,0,sizeof(l));
    memset(r,0,sizeof(r));
    long long re=0;
    stack<int> st;
    for(int i=0; i<n; i++)
    {
        while(st.size()&&aa[i]>=aa[st.top()])
        {
            st.pop();
        }
        if(st.size()==0)
            l[i]=0;
        else
            l[i]=st.top()+1;
        st.push(i);
    }
    stack<int> st2;
    for(int i=n-1; i>=0; i--)
    {
        while(st2.size()&&aa[i]>aa[st2.top()])
        {
            st2.pop();
        }
        if(st2.size()==0)
            r[i]=n-1;
        else
            r[i]=st2.top()-1;
        st2.push(i);
    }
    for(int i=0;i<n;i++)
    {
        re+=aa[i]*((r[i]-l[i])+(i-l[i])*(r[i]-i));
    }
    return re;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=0; i<n; i++)
            cin>>aa[i];
        long long ans=js();
        for(int i=0; i<n; i++)
            aa[i]=-aa[i];
        ans+=js();
        cout<<ans<<endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hlee-top

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值