单调性优化:单调栈与单调队列
单调性优化:单调栈与单调队列
一、单调栈
单调栈,就是要维护一个栈,单调递增或递减。一般地,放入元素时,如果栈顶的元素不符合单调递增(或递减),那就把它弹出,再查栈顶。直到符合或栈空了,再把元素放入。
适用于快速求每个数两侧比它大(或小)的数的位置。
算法
·其实很简单
·在这种方法中,我们维护一个栈。
·一开始,我们把 -1 放进栈的顶部来表示开始。
·按照从左到右的顺序,我们不断将柱子的序号放进栈中,保证栈的单调性。
·当元素出栈时,说明这个新元素是出栈元素向后找第一个比其小的元素
·当元素出栈后,说明新栈顶元素是出栈元素向前找第一个比其小的元素
那么这题就做完了,答案也就很好推了。
加个前缀和优化,就是单调栈的模板题了。
#include<bits/stdc++.h>
using namespace std;
long long a[1000001];
long long sum[1000001];
stack <int> t;
long long ans;
inline long long s(int x,int y)
{
return sum[y]-sum[x-1];
}
int main()
{
int n;
cin >> n;
for (int i=1;i<=n;i++)
{
cin >> a[i];
sum[i]=sum[i-1]+a[i];
}
n++;
a[n]=0;
t.push(0);
for (int i=1;i<=n;i++)
{
while (!t.empty()&&a[t.top()]>a[i])
{
long long res=a[t.top()];
t.pop();
ans=max(ans,s(t.top()+1,i-1)*res);
}
t.push(i);
}
cout << ans;
return 0;
}
二、单调队列
单调队列,就是要维护一个队列,单调递增或递减。一般地,放入元素时,先弹出末尾无效元素。如果队列首的元素不符合单调递增(或递减),那就把它弹出,再查队列首。直到符合或队列空了,再把元素放入。
如果一个oier比你小又比你强,那你就
废了没用了
解决的问题:
\(f(x)=opt_{i=bound[x]}^{x-1}(const[i])\)
对于这样一类动态规划问题,我们可以运用单调队列来解决:
其中\(bound[x]\)随着x单调不降,而\(const[i]\)则是可以根据i在常数时间内确定的唯一的常数。这类问题,一般用单调队列在很优美的时间内解决。
·队列中的元素其对应在原来的列表中的顺序必须是单调递增的。
·队列中元素的大小必须是单调递增(减/甚至是自定义也可以)
·破环成链+单调队列
·简单的推柿子+单调队列