单调队列和单调栈
引入:
有这样一个问题,给出一组数据,然你找到每个数比他小的第一个数,该怎么实现。
最直接的方法是暴力,从当前位置i开始往前寻找如果a[i]>a[j]则停止。但这种方法复杂度是很高的,稍微思考一下,如果某个数k后面有比k小的数,那么k就不可能作为后面所有数的第一个小的数。所以单调栈就是实现这样一个功能。将不符合条件的元素及时弹出,维护当前栈的单调性。
#define _CRT_SECURE_NO_WARNINGS 1;
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <unordered_map>
#define ll long long
#define off ios::sync_with_stdio(false);
#define INF 0x3f3f3f3f
const int N = 2e5 + 10;
using namespace std;
ll p[N];
ll dp[N];
stack<pair<ll, ll>>s;
int main()
{
off;
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> p[i];
}
s.push({ 0,0 });
ll res = 0;
dp[0] = 0;
for (int i = 1; i <= n; i++) {
while (s.size() && p[i] <= s.top().first)
s.pop();
pair<ll,int> temp = s.top();
s.push({ p[i],i });
dp[i] = dp[temp.second] + (s.top().second - temp.second) * s.top().first;
res = max(res, dp[i]);
}
printf("%lld\n", res);
return 0;
}
单调队列同理,只是进出顺序不同。
#define _CRT_SECURE_NO_WARNINGS 1;
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <unordered_map>
#define ll long long
#define off ios::sync_with_stdio(false);
#define INF 0x3f3f3f3f
const int N = 1e6 + 1;
using namespace std;
int idx[N];
int q[N];
int a[N];
int main() {
off;
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int tail = 0, head = 1;
for (int i = 1; i <= n; i++) {
while (head <= tail && q[tail] >= a[i])
tail--;
q[++tail] = a[i];
idx[tail] = i;
if (idx[head] <= i - k)
head++;
if (i >= k)
cout << q[head] << ' ';
}
cout << endl;
tail = 0, head = 1;
for (int i = 1; i <= n; i++) {
while (head <= tail && q[tail] <= a[i])
tail--;
q[++tail] = a[i];
idx[tail] = i;
if (idx[head] <= i - k)
head++;
if (i >= k)
cout << q[head] << ' ';
}
return 0;
}