题目链接
题意
给出长度为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]对答案的贡献可以分为两种
- a[i]为端点,则另一个端点的个数为r[i]-l[i]+1-1
- 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;
}
}