题解 P2422 【良好的感觉】
【思路】
单调栈
这不就是单调栈板子题吗?
【前缀思想】
某个区间的总和?
很显然可以用前缀和搞定
嗯,没有问题
区间不定可大可小?
单调队列明显不行,可标签就是单调队列+DP
怀疑自己是自己太弱
继续想单调队列
发现貌似单调栈好像更好写
【中心思想】
因为这是某个大小不定的区间里面的最小值乘以区间总和
总和先不考虑
一个前缀和轻轻松松
考虑区间的最小值
一开始想枚举区间大小
但是区间大小太多种,而且组合方式也很多
所以很麻烦
但是可以这样想
最小值一共有多少种可能 ?
就一共只由n种
那枚举最小值n是多少岂不美哉?
枚举出来最小值之后就需要找区间了
因为没有负数
所以区间越大越好就找最大区间
【最大区间】
最大区间的前提是什么?
里面的值都要大于等于枚举出来的最小值
这是没有任何问题的
那么这个最大区间的两边边界一定是小于这个最小值的数
所以可以用单调栈来解决!!!
【实现】
单调栈单调的过程
如果手中这个元素小于栈顶的话
那栈顶元素当最小值的时候,
他的右边界只能到达手中这个元素位置前面的那一个元素
不然最小值这个称号就会易主了
如果手中这个元素大于栈顶的话
那手中这个元素当最小值的时候,左边的边界只能到达
栈顶元素右边的那个位置
不然同上最小元素的称号也会易主
这样就可以很轻松的求出最大区间
然后用前缀和求出区间总和乘以区间最小元素
比较最大值
输出就好了
【完整代码】
#include<iostream>
#include<cstdio>
#include<stack>
#define int long long
using namespace std;
const int Max = 100005;
int a[Max];
int sum[Max];
int l[Max];
stack<int>s;
signed main()
{
int n;
cin >> n;
for(register int i = 1;i <= n;++ i)
cin >> a[i],sum[i] = sum[i - 1] + a[i];
int M = 0;
for(register int i = 1;i <= n;++ i)
{
while(!s.empty() && a[i] < a[s.top()])
{
M = max(M,(sum[i - 1] - sum[l[s.top()]]) * a[s.top()]);
s.pop();
}
if(!s.empty())
l[i] = s.top();
else
l[i] = 0;
s.push(i);
}
cout << M << endl;
return 0;
}