洛谷 P2659 美丽的序列

洛谷 P2659 美丽的序列

洛谷传送门

题目背景

GD是一个热衷于寻求美好事物的人,一天他拿到了一个美丽的序列。

题目描述

为了研究这个序列的美丽程度,GD定义了一个序列的“美丽度”和“美丽系数”:对于这个序列的任意一个区间[l,r],这个区间的“美丽度”就是这个区间的长度与这个区间的最小值的乘积,而整个序列的“美丽系数”就是它的所有区间的“美丽度”的最大值。现在GD想要你帮忙计算这个序列的“美丽系数”。

输入格式

第一行一个整数n,代表序列中的元素个数。 第二行n个整数a1、a2„an,描述这个序列。

输出格式

一行一个整数,代表这个序列的“美丽系数”。


题解:

%%%JZW

如果要用线段树,需要枚举所有区间。

显然是不可的。

那么我们现在要求最大美丽度。我们思考剪去一些无用区间。

什么区间无用呢?贪心地思考,区间长度肯定是越大越好,那么对于一个点来讲,左右同时拓展这个区间,直到找到左右第一个小于它的元素,记作(l,r),那么区间((l,r))一定是这个点能管控到的最大美丽值。因为这个点已经是这个区间中最小的元素。

那么所有点都可以依此维护,显然地,答案一定会在这些值中产生。理由是每个点都已经这样拓展过了,而每个点都是最优的。

至于左右第一个小于它的元素,可以用单调栈来维护,正反各跑一次,然后就是细节的更新了。

代码:

#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=2e6+3;
int n,ans;
int a[maxn];
int s[maxn],top;
int l[maxn],r[maxn];
signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	a[0]=a[n+1]=-1;
	for(int i=1;i<=n+1;i++)
	{
		while(top && a[i]<a[s[top]])
		{
			r[s[top]]=i;
			top--;
		}
		s[++top]=i;
	}
	while(top)
		top--;
	for(int i=n;i>=0;i--)
	{
		while(top && a[i]<a[s[top]])
		{
			l[s[top]]=i;
			top--;
		}
		s[++top]=i;
	}
	for(int i=1;i<=n;i++)
	{
		int len=r[i]-1-l[i];
		int tmp=a[i]*len;
		ans=max(ans,tmp);
	}
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/fusiwei/p/13924661.html