题目链接:Codeforces - 817D - Imbalanced Array
题意是求
∑max([i,j])−∑min([i,j])
。即求所有连续子区间的最大值之和减所有连续子区间最小值之和。
先求连续子区间最小值之和。一个区间有唯一一个 最左最小元素,因此对于区间的每个元素,求它在哪些区间内是最左最小元素,就能将它的贡献算出来了。
a[j]
是
[l,r]
的最左最小元素当且仅当
a[j]=min([l,r])
且对于所有
k<j
,
a[k]>a[j]
。
因此我们可以设置数组
l[i]
表示
a[i]
的左边第一个小于等于它的数的下标,
r[i]
表示
a[i]
的右边第一个小于它的数的下标。可以用单调栈来求出。
求最大值之和可以用类似的方法。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+7;
int l[N],r[N],a[N],n,st[N],top=0;
void read(int &k)
{
k=0;
int ch=0;
while((ch=getchar())>='0'&&ch<='9')
k=k*10+ch-'0';
}
int main()
{
int n;
read(n);
for(int i=1;i<=n;++i)
read(a[i]);
top=0;
for(int i=1;i<=n;++i)
{
while(top>0&&a[st[top]]>a[i]) --top;
l[i]=top?st[top]:0;
if(top&&a[st[top]]==a[i]) --top;
st[++top]=i;
}
top=0;
for(int i=n;i>=1;--i)
{
while(top>0&&a[st[top]]>=a[i]) --top;
r[i]=top?st[top]:n+1;
st[++top]=i;
}
ll minsum=0;
for(int i=1;i<=n;++i)
minsum+=a[i]*1LL*(r[i]-l[i]-1+(r[i]-i-1LL)*(i-l[i]-1));
top=0;
for(int i=1;i<=n;++i)
{
while(top>0&&a[st[top]]<a[i]) --top;
l[i]=top?st[top]:0;
if(top&&a[st[top]]==a[i]) --top;
st[++top]=i;
}
top=0;
for(int i=n;i>=1;--i)
{
while(top>0&&a[st[top]]<=a[i]) --top;
r[i]=top?st[top]:n+1;
st[++top]=i;
}
ll maxsum=0;
for(int i=1;i<=n;++i)
maxsum+=a[i]*1LL*(r[i]-l[i]-1+(r[i]-i-1LL)*(i-l[i]-1));
printf("%I64d\n",maxsum-minsum);
return 0;
}