【计蒜客 - 2019南昌邀请赛网络赛 - I】Max answer(单调栈,RMQ)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/89422855

题干:

Alice has a magic array. She suggests that the value of a interval is equal to the sum of the values in the interval, multiplied by the smallest value in the interval.

Now she is planning to find the max value of the intervals in her array. Can you help her?

Input

First line contains an integer n(1 \le n \le 5 \times 10 ^5n(1≤n≤5×105).

Second line contains nn integers represent the array a (-10^5 \le a_i \le 10^5)a(−105≤ai​≤105).

Output

One line contains an integer represent the answer of the array.

样例输入复制

5
1 2 3 4 5

样例输出复制

36

题目大意:

   给你n个数,每个数范围 -1e5~1e5,让你选定一个区间,val=区间和*区间最小值,现在让你输出最大的val。

解题报告:

  如果都是正数那就可以直接枚举最小值+单调栈。时间复杂度O(n).

  但是这题有负数,所以不能用这种贪心的方法。考虑以正数当最小值,并不影响第一种做法的正确性。考虑负数当最小值,此时可能会出现多选了一些正数的情况,但是我们深知,我们现在想要的是区间和最小,所以我们找区间最小值就可以了。但是这个最小值不能是必须以某一个数开始。考虑先求出前缀和,然后对前缀和求RMQ问题,最终得到最小值。

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<stack>
using namespace std;
typedef long long ll;
const int MAX = 5e5 + 5;
int n, l,r;
ll maxx=-1e18;
int a[MAX], L[MAX], R[MAX],qq[MAX];
ll sum[MAX],suf[MAX],dp1[MAX][25],dp2[MAX][25];
stack<int > sk;
void ST() {
	for(int i = 1; i<=n; i++) {
		dp1[i][0] = sum[i];
		dp2[i][0] = suf[i];
	}
	for(int j = 1; (1<<j) <= n; j++) {
		for(int i = 1; i+(1<<j)-1 <= n; i++) {
			dp1[i][j] = min(dp1[i][j-1] , dp1[i + (1<<(j-1))][j-1]);
			dp2[i][j] = min(dp2[i][j-1] , dp2[i + (1<<(j-1))][j-1]);
		}
	}
	for(int i = 1; i<=n; i++) {
		int k = 0;
		while(1<<(k+1) <= i) k++;
		qq[i] = k;
	}
}
ll cala(int l,int r) {
	if(l>r) return sum[l-1];
	int k = qq[r-l+1];
	return min(dp1[l][k],dp1[r- (1<<k) + 1][k]);
}
ll calb(int l,int r) {
	if(l>r) return suf[r+1];
	int k = qq[r-l+1];
	return min(dp2[l][k],dp2[r- (1<<k) + 1][k]);
}
int main()
{
	int t,i,j,k;
	ll tl,tr;
	cin>>n;
	for(i = 1; i<=n; i++) {
		scanf("%d",&a[i]);
		sum[i] = sum[i-1] + a[i];
	}
	for(i=n;i>=1;i--)
		suf[i]=suf[i+1]+a[i];
		
	for(int i = 1; i<=n; i++) {
		while(!sk.empty() && a[sk.top()] >= a[i]) sk.pop();
		if(sk.empty() ) L[i] = 0;
		else L[i] = sk.top();
		sk.push(i);
	}
	while(!sk.empty() ) sk.pop();
	for(int i = n; i>=1; i--) {
		while(!sk.empty() && a[sk.top() ] >= a[i]) sk.pop();
		if(sk.empty() ) R[i] = n+1;
		else R[i] = sk.top();
		sk.push(i);
	}
	ST();
	for(i=1;i<=n;i++){
		if(a[i]>=0)
			maxx=max(maxx,a[i]*(sum[R[i]-1]-sum[L[i]]));
		else {
			
			tl=cala(i+1,R[i]-1)-sum[i];
			tr=calb(L[i]+1,i-1)-suf[i];
			if(tl>0) tl=0;
			if(tr>0) tr=0;
			maxx=max(maxx,a[i]*(tl+tr+a[i]));
		}
	}
	printf("%lld\n",maxx);
	return 0 ;
}

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/89422855