单调栈模板题 luogu P2659

题目链接:https://www.luogu.org/problem/P2659

实际上就是要我们求出每个数字左右两边第一个小于它的数字位置,然后两个位置所在的开区间长度乘以这个数字,取最大值输出。

因为是求两边第一个小于a[i]的数字,所以我们弄一个递增(其实是不减小就可以了,可以有相同大小的元素)的单调栈,从栈底到栈顶的数字是依次增大的,在求的过程中要始终保持递增的性质。我们每次在数字入栈时求出数字左边第一个小于它的数字位置,在出栈的时候求出右边第一个小于它的数字位置,为什么是这样,看下面,我这里的栈保存的是元素下标,而不是元素值。

L[i]记录左边第一个小于a[i]的元素位置(下标),没有就是0,R[i]记录右边第一个小于a[i]的元素位置,没有就是n+1。

  对于一个a[i],假如a[i]大于栈顶元素(我的栈存的是下标,我们比较是就拿这个下标的值比较),那么如果把a[i]压入栈顶,这个栈还是递增的,这个时候栈顶元素就是第一个小于a[i]的数字,我们直接把L[i]赋值为栈顶元素就行了。

  对于a[i]等于栈顶元素的情况,假如说值都是5好吧,那么其实栈顶的5在它入栈的时候,它的L数组值(它左边第一个小于它的元素位置)我们一定会先得到对吧,那么当前的a[i](也是5),它的L数组值肯定等于栈顶元素的L数组值吧,因为他俩相等,所以直接把a[i]的L数组值赋值为栈顶元素的数组值就可以了,在把a[i]入栈。

  假如a[i]小于栈顶元素,那么如果我们把a[i]压入栈中,那么这个栈里面的元素就不单调递增了,所以说我们需要把栈里面比a[i]大的元素都弹出,假如现在我们要弹出当前栈顶元素,那么其实现在a[i]就是栈顶元素右边的第一个小于栈顶元素的值,所以我们这个时候可以直接把R[s.top()]赋值为i,这样每当我们出栈一个元素,这个元素的左右两边第一个小于它的元素位置就都找到了(左边的在进栈就找到了)。

然后,就没了。

我自己写的板子,应该木有问题,就是慢了点:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 2000005
stack<int>q;
int n,m,k,t;
int a[maxn];
int L[maxn],R[maxn];
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==‘-‘)f=-1;}while(ch<‘0‘||ch>‘9‘);
    do{x=x*10+ch-‘0‘;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘);
    return f*x;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    a[i]=read();
    for(int i=1;i<=n;i++){//线性扫一遍
        while(!q.empty()&&a[q.top()]>a[i]){//先检查栈顶元素大于a[i]的情况
            int s=q.top();    //保存一下栈顶元素值(下标)
            R[s]=i;            //得到栈顶元素右边第一个小于它的元素下标
            q.pop();        //出栈
        }

        if(q.empty())        //假如栈为空
        L[i]=0;
        else if(a[q.top()]==a[i])    //假如栈顶元素等于a[i],那么L[i]就赋值为栈顶元素的L数组值
        L[i]=L[q.top()];
        else                        //栈顶元素小于a[i],把a[i]入栈
        L[i]=q.top();

        q.push(i);
    }
    while(!q.empty()){//最后栈顶可能还有元素没有出栈,这个时候他们的R数组值都是n+1,因为右边没有比他们小的值了
        int s=q.top();
        R[s]=n+1;
        q.pop();
    }
    LL ans=0;
    for(int i=1;i<=n;i++)
    ans=max(ans,(LL)a[i]*(R[i]-L[i]-1));
    printf("%lld\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/6262369sss/p/11257259.html

时间: 2024-08-29 20:09:43

单调栈模板题 luogu P2659的相关文章

Sliding Window POJ - 2823 单调队列模板题

Sliding Window POJ - 2823 单调队列模板题 题意 给出一个数列 并且给出一个数m 问每个连续的m中的最小\最大值是多少,并输出 思路 使用单调队列来写,拿最小值来举例 要求区间最小值 就是维护一个单调递增的序列 对于样例 8 3 1 3 -1 -3 5 3 6 7 我们先模拟一遍 1.队列为空 1 进队 队列:1 2.3>队尾元素 3 进队 队列: 1 3 3.-1小于队尾元素,一直从尾部出队知道找到比-1小的元素或者队列为空 队列:-1 当队列中元素大于m的时候从队头删

海报PLA (HYSBZ - 1113)单调栈模板

N个矩形,排成一排. 现在希望用尽量少的矩形海报Cover住它们. Input 第一行给出数字N,代表有N个矩形.N在[1,250000] 下面N行,每行给出矩形的长与宽.其值在[1,1000000000]2 1/2 Postering Output 最少数量的海报数. Sample Input 5 1 2 1 3 2 2 2 5 1 4 Sample Output 4                               先解释下题意,题目说的不是很清楚 看上面两幅图,是样例的排列方式,

Maximum Xor Secondary(单调栈好题)

Maximum Xor Secondary CodeForces - 280B Bike loves looking for the second maximum element in the sequence. The second maximum element in the sequence of distinct numbers x1,?x2,?...,?xk (k?>?1) is such maximum element xj, that the following inequalit

[leetcode 85. 最大矩形] 单调栈--84题的简单扩展

题目描述 给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积. 示例: 输入: [ ["1","0","1","0","0"], ["1","0","1","1","1"], ["1","1","1","

[51nod1102]面积最大的矩形(单调栈||预处理)

题意:求序列上某区间最小值乘区间长度的最大值. 解题关键:很早就在<挑战程序设计竞赛>中见过了,单调栈模板题,注意弹栈时如何处理后面的元素. 法一:单调栈 #include<bits/stdc++.h> using namespace std; typedef long long ll; stack<int>s; ll a[50002]; int main(){ int n; cin>>n; for(int i=0;i<n;i++) cin>&g

模板题+进阶

模板题:2500 后面第一个大于 一般要正着看不出来,反着想,有的人也叫做正难则反. 有思维的一道题:1279 扔盘子 暴力会TLE 数据有点水,反着写的可以拿95% 1 //垃圾数据从井底倒着网上数盘子居然能过19个测试点 2 //但是提供给我们一种思路就是,明知道正着肯定会错时逆向解题也许能拿更多的分 3 #include<bits/stdc++.h> 4 using namespace std; 5 const int maxN=50005; 6 int n, m; 7 int w[ma

[poj3250]单调栈 Bad Hair Day

解题关键:将每头牛看到的牛头数总和转化为每头牛被看到的次数,然后用单调栈求解,其实做这道题的目的只是熟悉下单调栈 此题为递减栈 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<stack> 6 #include<iostream> 7 using namespace std; 8 typedef lo

poj2796 Feel Good 单调栈

题意:给定一个序列,需要找出某个子序列S使得Min(a[i])*Σa[i] (i属于S序列)最大 正解:单调栈 这题的暴力还是很好想的,只需3分钟的事就可以码完,以每个点拓展即可,但这样的复杂度是O(n^2)的,肯定会TLE 以暴力的思想作为基础,再进行深层次思考,考虑每个点往周围拓展的时候,都要走到最远的地方停下来,也就是说会有一个左上限,一个右上限(命名为:pre.next),不难发现再枚举5.4.3.2.1这个序列的时候,每次都要往左扫描到最左边,显然这是做了重复的事情,于是机智的我马上想

[luoguP2659] 美丽的序列(单调栈)

传送门 单调栈大水题 l[i] 表示 i 能扩展到的左边 r[i] 表示 i 能扩展到的右边 ——代码 1 #include <cstdio> 2 #include <iostream> 3 #define LL long long 4 5 const int MAXN = 2000002; 6 int n, t; 7 LL ans, a[MAXN], s[MAXN], l[MAXN], r[MAXN]; 8 9 inline int read() 10 { 11 int x =