题面描述
问题描述
给出一个长度为n(1<=n<=100 000)的序列,求出一个子序列,使得这个序列中的最小值乘以这个序列的和的值最大。
输入格式
输入数据有2行,第一行正整数n,第2行n个正整数ai。(0<=ai<=10^6)
输出格式
输出有2行,第一行为题目描述中的最大值,第二行2个数字,分别为子序列的起点和终点位置,如果有多个子序列相等,那么选择起点靠前的。
样例输入
6
3 1 6 4 5 2
样例输出
60
3 5
限制与约定
时间限制:1s
空间限制:128MB
题解
我们开两个单调栈l[i]和r[i],从1~n 枚举 每个数,对于数 i,l[i]存 i点左边第一个比a[i]小的数的编号,r[i]存 i点右边第一个比a[i]小的数的编号,显然,l[i] 到 r[i] 这个子序列的最小值为a[i] 。因为序列为正整数序列,所以a[i] 为最小值的子序列能取到的最大值k为 l[i]~r[i] 的和乘上a[i] ,l[i]~r[i] 的和用前缀和处理出来,不断用k更新ans*(注意:ans要开 long long 类型)*,详见代码
代码实现
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
long long a[100005],sum[100005];
int n,ll,rr,l[100005],r[100005];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];//前缀和处理
l[i]=r[i]=i;
}
for(int i=2;i<=n;i++) while(l[i]>1 && a[l[i]-1]>=a[i]) l[i]=l[l[i]-1];
for(int i=n-1;i>=1;i--) while(r[i]<n && a[r[i]+1]>=a[i]) r[i]=r[r[i]+1];
//单调栈处理
long long ans=-1;
for(int i=1;i<=n;i++)
{
long long k=a[i]*(sum[r[i]]-sum[l[i]-1]);
if(k>ans)//若k>ans 更新答案,注意:k==ans 时不要更新答案
{
ans=k;
ll=l[i];
rr=r[i];
}
}
printf("%lld\n%d %d",ans,ll,rr);
return 0;
}
若您觉得此篇博客写得不错,请别忘了关注我哦 >_<