I - Max answer 計蒜客 - 38228 單調棧

瑪珈山大萌新發表於2020-11-09

題目:I - Max answer 計蒜客 - 38228

分析:

這個題對於正數我們可以列舉最小值,求左右可擴充套件的最遠處(用單調棧),貢獻答案。
對於負數的情況,可以結合“陣列的最大子陣列和"一題來考慮,即O(n)求子陣列最大/小和。對於這個題,我們在維護MinSum的時候,同時維護對應區間的最小負數min,並利用min * MinSum貢獻答案。

程式碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;//三年競賽一場空,不開long long見祖宗 
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endsl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
#define pb(a) push_back(a)
#define x first
#define y second
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const int maxn = 5e5 + 10;
const int inf = 0x3f3f3f3f;
int l[maxn], r[maxn];
ll a[maxn], sum[maxn];
int n;
stack<int> st;

int main()
{
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i], sum[i] = sum[i - 1] + a[i];
	for(int i = 1; i <= n; i++) l[i] = i, r[i] = n;

	//單調棧模板,求以某一個數為min,可以向延伸的最左和最右
	for(int i = 1; i <= n; i++)
	{
		if(st.empty() || a[i] > a[st.top()]) st.push(i);
		else
		{
			while(!st.empty() && a[i] <= a[st.top()])
			{
				int pos = st.top(); st.pop();
				l[i] = l[pos];//這裡極其容易出錯.
				r[pos] = i - 1;
			}
			st.push(i);
		}
	}
	ll res = -1;
	for(int i = 1; i <= n; i++)
		res = max(res, a[i] * (sum[r[i]] - sum[l[i] - 1]));
	ll sum = 0, minv = 0;
	for(int i = 1; i <= n; i++)
	{
		if(sum > 0) sum = 0, minv = 0;
		sum += a[i];
		minv = min(minv, a[i]);
		res = max(res, sum * minv);
	}
	cout << res << endl;
}

相關文章