原题链接
题目大意:
给一个数组,求所有子数组的权值最大值,权值的计算方式:子数组中最小的元素乘子数组所有元素的和。
思路
一个单调栈模型的应用。如果枚举所有子数组的话那一定会超时,所以我们只能枚举每一个数,将这个数作为子数组中最小的元素,然后为了使权值最大,就得使元素的和最大,而每个元素都是正数,所以元素的数量要最大。因此对于第i个数作为最小值时,往左找最近的小于他的数,再往右找最近的小于他的数,这个区间内的数组就是满足i作为最小值的最大权值数组,然后计算每个i的数组的权值,求max即可。
看到这个往左找最近的比他小的数,就想到了单调栈。直接用单调栈模型来求即可。求子数组的和可以直接用前缀和。
ac代码:
class Solution {
public:
int maxSumMinProduct(vector<int>& nums) {
const int N = 100010;
typedef long long LL;
stack<int> q; //单调栈
int n = 0,h[N],l[N],r[N]; //h是数组的值,l是往左找最近的小于h[i]的那个数的位置,r是往右找
LL res = 0,sum[N]; //sum前缀和
for(auto i : nums)
h[++n] = i,sum[n] = sum[n-1]+i; //把num数组转存到h来,sum求前缀和
h[0] = h[n+1] = 0; //处理边界
q.push(0);
for(int i = 1;i <= n;i++) //单调栈模板
{
while(h[q.top()] >= h[i])
q.pop();
l[i] = q.top();
q.push(i);
}
while(q.size()) //清空栈
q.pop();
q.push(n+1);
for(int i = n;i >= 1;i--)
{
while(h[q.top()] >= h[i])
q.pop();
r[i] = q.top();
q.push(i);
}
for(int i = 1;i <= n;i++)
res = max(res,(LL)h[i]*(sum[r[i]-1]-sum[l[i]])); //计算答案
return res%1000000007;
}
};