良好的感觉——题解

题目描述

image

分析

题目意思就是找子区间的和乘区间最小值的最小值;

1.纯暴力。。。肯定TLE.

2.枚举最小值,找两边第一个比它小的,求区间和。

(肯定第二种)。。。

实现

纯循环的话肯定不行,这时候需要一点小优化——单调栈;

既然枚举最小值的话,复杂度只要 O(n),可以用前缀和求区间和,接下来就是如何用单调栈实现了

如果这个数小于栈顶元素,且这个数一定在栈顶元素后出现,那么以栈顶元素为最小值的区间一定在这个数左边一个数,用一个数组记录一下下标,这就是栈顶元素区间的右边界,然后pop掉,当栈顶元素小于这个数时,那么以这个数为最小值的区间左边界即为栈顶元素右,这同时也保证了求栈顶元素答案时左边界的提前处理。

下面放代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e7;
int n,m,a[maxn],l[maxn],ans,sum[maxn];
stack<int>q;
signed main() {
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i]; 
    a[n+1]=0,sum[n+1]=sum[n];
    ans=0;
    for(int i=1;i<=n+1;i++){
    	while(!q.empty()&&a[i]<a[q.top()]){
    		ans=max(ans,(sum[i-1]-sum[l[q.top()]])*a[q.top()]);
    		q.pop();
		}
		if(!q.empty()) l[i]=q.top();//i这个数左边界处理
		else l[i]=0;
		q.push(i);
	}
    printf("%lld",ans);
    return 0;
}
posted @ 2024-02-21 08:35  _君の名は  阅读(56)  评论(0)    收藏  举报