CF817D Solution

题目链接

题解

⭐:单调栈可以维护\([1,i]\)中大于或小于\(a_i\)的元素。

由于数据范围枚举左右端点并不现实,因此想到求出每个元素对于答案的贡献。设\([1,i)\)中最后一个\(>a_i\)的数为\(l\)\((i,n]\)中第一个\(>a_i\)的数为\(r\)\((r,l)\)即为\(a_i\)作为最大值的最大区间,其中\(l,r\)可用单调栈求出。利用乘法原理可知\(a_i\)作为最大值的区间数\(=(i-l)(r-i)\),而对答案的贡献为区间数\(\times a_i\)。 最小值同理,最终答案即为最大值贡献和\(-\)最小值贡献和。

AC代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int a[N],st[N],lg[N],rg[N],ll[N],rl[N],top;
//ll/lr[i]:a[i]作为最大值的最大区间左/右端点,lg/rg[i]:a[i]作为最小值的最大区间左/右端点
signed main()
{
	int n,sum1=0,sum2=0;//sum1:最大值贡献和,sum2:最小值贡献和
	scanf("%lld",&n);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	for(int i=1;i<=n;i++) 
	{
		while(top && a[st[top]]>=a[i]) top--;
		lg[i]=i-st[top]; st[++top]=i;
	}
	top=0,st[0]=n+1;
	for(int i=n;i>=1;i--) 
	{
		while(top && a[st[top]]>a[i]) top--;
		rg[i]=st[top]-i; st[++top]=i;
	}
	top=0,st[0]=0;
	for(int i=1;i<=n;i++) 
	{
		while(top && a[st[top]]<=a[i]) top--;
		ll[i]=i-st[top]; st[++top]=i;
	}
	top=0,st[0]=n+1;
	for(int i=n;i>=1;i--) 
	{
		while(top && a[st[top]]<a[i]) top--;
		rl[i]=st[top]-i; st[++top]=i;
	}
	for(int i=1;i<=n;i++) {sum1+=ll[i]*rl[i]*a[i]; sum2+=lg[i]*rg[i]*a[i];}
	printf("%lld",sum1-sum2);
	return 0;
}
posted @ 2021-03-13 19:11  violet_holmes  阅读(48)  评论(0编辑  收藏  举报