洛谷 P5788 【模板】单调栈
发布日期:2021-07-01 02:50:25 浏览次数:2 分类:技术文章

本文共 2111 字,大约阅读时间需要 7 分钟。

题目描述

给出项数为 n n n 的整数数列 a 1 … n a_{1 \dots n} a1n

定义函数 f ( i ) f(i) f(i) 代表数列中第 i i i 个元素之后第一个大于 a i a_i ai 的元素的下标,即 f ( i ) = min ⁡ i < j ≤ n ,   a j > a i { j } f(i)=\min_{i<j\leq n,\ a_j > a_i} \{j\} f(i)=mini<jn, aj>ai{

j} 。若不存在,则 f ( i ) = 0 f(i)=0 f(i)=0 。试求出 f ( 1 … n ) f(1\dots n) f(1n)

输入格式

第一行一个正整数 n n n 。第二行 n n n 个正整数 a 1 … n a_{1\dots n} a1n

输出格式

一行 n n n 个整数 f ( 1 … n ) f(1\dots n) f(1n) 的值。

输入输出样例

输入 #1

51 4 2 3 5

输出 #1

2 5 4 5 0

说明/提示

【数据规模与约定】
对于 30 % 30\% 30% 的数据, n ≤ 100 n ≤ 100 n\leq 100n≤100 n100n100
对于 60 % 60\% 60% 的数据, n ≤ 5 × 1 0 3 n\leq 5 \times 10^3 n5×103
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 3 × 1 0 6 1 \le n\leq 3\times 10^6 1n3×106 1 ≤ a i ≤ 1 0 9 1\leq a_i\leq 10^9 1ai109

题目:本题求每个数后第一个大于它的数的下标。


思路:这是一道单调栈的模板题。单调栈维护两条规则:后进先出;栈内元素从栈底到栈顶保持单调性,要么从小到大,要么从大到小。

本题中,我们将这些数据视作 n n n 个人的身高,每个人向右平视时,看不到矮的人,看到的一定是右边身高高于他的第一个人:

根据这一推断,我们看到的人肯定是一个比一个高的,而没看到的(人的数据),留着也没用,直接丢弃。这样就符合单调性。那么什么时候丢弃这些没用的数据?当然是遇到比他高的人的时候。

于是我们可以从前往后遍历,维护一个单调递减栈:对于每个点,如果它的值大于栈顶下标表示的数组值,就依次弹出栈顶元素、并且置这些栈顶下标对应的答案为当前点的下标。如果值小于栈顶下标对应的数组值,就压栈。最后输出答案数组即可。

从前往后的代码如下:

#include 
using namespace std;const int maxn = 3e6 + 10;int arr[maxn], ans[maxn], st[maxn], top = 0; //top==0表示空栈 int main() {
int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &arr[i]); //从栈底到栈顶的下标对应的数组值(优先级)依次递减 for (int i = 1; i <= n; ++i) {
//将先进栈(前面的元素下标)且

或者从后往前遍历,维持一个单调递减栈:对于每个点 arr[i] ,弹出对应的数组值小于等于它的栈顶下标,直到栈顶下标对应的元素值 > arr[i]栈顶下标就是答案。然后将这个元素的下标压栈:

#include 
using namespace std;const int maxn = 3e6 + 10;int arr[maxn], ans[maxn], st[maxn], top = -1; int main() {
int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &arr[i]); //从栈底到栈顶的下标对应的数组值(优先级)依次递减, //后进先出,对应->第i个元素之后第一个大于a_i的元素的下标 for (int i = n; i > 0; --i) {
//将先进栈(后面的)且不大于arr[i]的值的坐标清除掉, //这一过程就是从i+1往后寻找第一个大于a_i的元素下标 while (top != -1 && arr[st[top]] <= arr[i]) --top; ans[i] = (top == -1 ? 0 : st[top]); //top=-1表示之后没有大于arr[i]的值 st[++top] = i; //存储arr的数组下标 } for (int i = 1; i <= n; ++i) {
if (i == 1) printf("%d", ans[i]); else printf(" %d", ans[i]); } return 0;}

提交AC:

在这里插入图片描述

转载地址:https://memcpy0.blog.csdn.net/article/details/108268783 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:LeetCode C++ 455. Assign Cookies【贪心】简单
下一篇:LeetCode C++ 491. Increasing Subsequences【DFS】中等

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月21日 12时42分22秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章