CF817D【Imbalanced Array】

Imbalanced Array

题目

CF817D


解析

学单调栈时偶然看到了这一题,就写掉了
想一下暴力,O(n3),n<=106,神威太湖之光都跑不过去
加个ST表,O(n2),天河二号跑得过去,你谷评测姬就别想了
考虑每个点对结果贡献,得到是左右拓展,最优是O(n),随便构造一个数据就退化为O(n2)了
加上单调栈优化,然后就做到了了传说中的O(n)!
稳稳过掉
附:居然放过去了一位O(nlogn)的,希望早日把n开到107
第一篇题解是同机房的dalao写的,但说错了一点:longlong不会炸,害的我去翻int128

code:

#include<cstdio>
#define int long long
#define rr register int
using namespace std;
inline bool idigit(char x){
    
    return (x<'0'|x>'9')?0:1;}
inline int read()
{
    
    
	int num=0,f=1;
	char c=0;
	while(!idigit(c=getchar())){
    
    if(c=='-')f=-1;}
	while(idigit(c))num=(num<<1)+(num<<3)+(c&15),c=getchar();
	return num*f;
}
inline void write(int x)
{
    
    
	int F[50];
	int tmp=x>0?x:-x;
	if(x<0)putchar('-');
	int cnt=0;
	while(tmp>0){
    
    F[cnt++]=tmp%10+'0';tmp/=10;}
	while(cnt>0)putchar(F[--cnt]);
	if(x==0)putchar('0');
}
int n,st[1000010],tot,a[1000010],lmi[1000010],rmi[1000010],lmx[1000010],rmx[1000010],ans=0;
signed main()
{
    
    
	n=read(),tot=1,st[1]=0;
	for(rr i=1;i<=n;++i)a[i]=read();
	for(rr i=1;i<=n;++i)
	{
    
    
		if(a[st[tot]]<a[i])lmi[i]=i-1,st[++tot]=i;
		else
		{
    
    
			while(tot&&a[st[tot]]>a[i])--tot;
			lmi[i]=st[tot],st[++tot]=i;
		}
	}//求最小左端点
	tot=1,st[1]=n+1;
	for(rr i=n;i;--i)
	{
    
    
		if(a[st[tot]]<a[i])rmi[i]=i+1,st[++tot]=i;
		else
		{
    
    
			while(tot&&a[st[tot]]>=a[i])--tot;
			rmi[i]=st[tot],st[++tot]=i;
		}
	}//求最小右端点
	a[0]=a[n+1]=1e17,tot=1,st[1]=0;
	for(rr i=1;i<=n;++i)
	{
    
    
		if(a[st[tot]]>a[i])lmx[i]=i-1,st[++tot]=i;
		else
		{
    
    
			while(tot&&a[st[tot]]<a[i])--tot;
			lmx[i]=st[tot],st[++tot]=i;
		}
	}//求最大左端点
	tot=1,st[1]=n+1;
	for(rr i=n;i;--i)
	{
    
    
		if(a[st[tot]]>a[i])rmx[i]=i+1,st[++tot]=i;
		else
		{
    
    
			while(tot&&a[st[tot]]<=a[i])--tot;
			rmx[i]=st[tot],st[++tot]=i;
		}
	}//求最大右端点
	for(rr i=1;i<=n;++i)ans=ans+a[i]*((i-lmx[i])*(rmx[i]-i)-(i-lmi[i])*(rmi[i]-i));
	write(ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zhanglili1597895/article/details/113783136