Evanyou Blog 彩带

洛谷P2422 良好的感觉

题目意思就是:最大化一个区间的和与这个区间的最小值的乘积。

换一个角度看问题,如果我们穷举一个最小值 $ a_i $ ,然后往左右扩展,显然是对的,复杂度 $ O(n^2) $。所以我们要优化一下这个过程。

首先扩展这个过程的原则就是所有加入这个区间的数都必须小于选定的最小值 $ a_i $,那么我们可以把这个过程换一个叙述方法,就是对于每个数我们分别往左右找到第一个比 $ a_i $ 小的数,编号分别记成 $ l_i $ 、 $ r_i $ ,则答案就是 $ sum(l_i+1,r_i-1) \times a_i​ $ 。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100005;

inline int read(){
	char ch = getchar();
	int f = 1 , x = 0;
	while(ch > '9' || ch < '0'){if(ch == '-')f = -1;ch = getchar();}
	while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}
	return x * f;
}

int n,a[maxn];
long long sum[maxn],f[maxn];
int l[maxn],r[maxn];
int stack[maxn],top;

int main(){
	n = read();
	for(int i=1;i<=n;i++){
		a[i] = read();
		sum[i] = sum[i-1] + a[i];
	}
	top = 0;
	for(int i=1;i<=n;i++){
		while(top && a[stack[top]] > a[i])
			r[stack[top--]] = i;
		stack[++top] = i;
	}
	top = 0;
	for(int i=n;i>0;i--){
		while(top && a[stack[top]] > a[i])
			l[stack[top--]] = i;
		stack[++top] = i;
	}
	for(int i=1;i<=n;i++)
		if(r[i] == 0)  r[i] = n + 1;
	long long ans = 0;
	for(int i=1;i<=n;i++)
		ans = max(ans , (long long) a[i] * (sum[r[i] - 1] - sum[l[i]]));
	printf("%lld\n",ans);
	return 0;
}
posted @ 2018-10-29 20:06  Stephen_F  阅读(99)  评论(0编辑  收藏  举报