Acwing2024蓝桥杯单调栈+单调队列

一维的单调栈,单调队列:

 AcWing 830. 单调栈

#include<iostream>
using namespace std;
const int N=1e5+5;
int n,a[N],l[N];
int stackk[N];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    a[0]=-1;
    int ttop=0;
    stackk[++ttop]=0;
    for(int i=1;i<=n;i++){
        while(a[stackk[ttop]]>=a[i]) ttop--;
        l[i]=stackk[ttop];
        stackk[++ttop]=i;
    }
    for(int i=1;i<=n;i++) cout<<a[l[i]]<<" ";
    return 0;
}

AcWing 154. 滑动窗口

#include<iostream>
using namespace std;
const int N=1e6+5;
int n,k,a[N];
int que[N];
int main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    //队头存储min值
    int head=0,tail=-1;
    for(int i=1;i<=n;i++){
        while(head<=tail&&que[tail]>a[i]) tail--;
        que[++tail]=a[i];
        if(i-k>=1&&que[head]==a[i-k]) head++;
        if(i>=k) cout<<que[head]<<" ";
    }
    cout<<endl;
    //队头存储max值
    head=0,tail=-1;
    for(int i=1;i<=n;i++){
        while(head<=tail&&que[tail]<a[i]) tail--;
        que[++tail]=a[i];
        if(i-k>=1&&que[head]==a[i-k]) head++;
        if(i>=k) cout<<que[head]<<" ";
    }
    return 0;
}

二维的单调栈,单调队列:

AcWing 1413. 矩形牛棚

#include<iostream>
using namespace std;
const int N=3e3+5;
int n,m,p,ans;
int a[N][N];//地图:0表示未破坏,1表示被破坏
int h[N][N];//h[i][j]表示坐标i,j的向上连续且未被破坏的土地
int stackk[N],top,l[N],r[N];
//有了行的基础,遍历列,求当前行往上的最大矩形土地
int work(int h[]){
    //放置左右边界
    h[0]=h[m+1]=-1;
    //找左边界
    top=0;//初始化
    stackk[++top]=0;//stackk存储的是h数组的下标
    for(int i=1;i<=m;i++){
        //当栈顶元素>=当前元素时出栈
        while(h[stackk[top]]>=h[i]) top--;
        l[i]=stackk[top];//存储下标
        stackk[++top]=i; //入栈
    }
    //找右边界
    top=0;
    stackk[++top]=m+1;
    for(int i=m;i;i--){
        while(h[stackk[top]]>=h[i]) top--;
        r[i]=stackk[top];
        stackk[++top]=i;
    }
    //遍历计算取最值
    int res=0;
    for(int i=1;i<=m;i++) res=max(res,h[i]*(r[i]-l[i]-1));
    return res;
}
int main(){
    cin>>n>>m>>p;
    //破坏土地
    while(p--){
        int x,y;
        cin>>x>>y;
        a[x][y]=1;
    }
    //从(1,1)-->(n,m)递推h数组
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]==0)
                h[i][j]=h[i-1][j]+1;
    //遍历行
    for(int i=1;i<=n;i++) ans=max(ans,work(h[i]));
    cout<<ans<<endl;
    return 0;
}

AcWing 4964. 子矩阵(第十四届省赛)

先按列预处理,分别求得当前的最大值最小值,再按行处理分别求出最后的最大值最小值,最后注意答案的取模处理:

#include<iostream>
using namespace std;
const int N=1e3+5;
const int mod=998244353;
int n,m,a,b,A[N][N],MAX[N][N],MIN[N][N],MAXX[N][N],MINN[N][N];
int que[N];
int main(){
    cin>>n>>m>>a>>b;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>A[i][j];
    for(int j=1;j<=m;j++){
        int head=0,tail=-1;
        for(int i=1;i<=n;i++){
            while(head<=tail&&que[tail]<A[i][j]) tail--;
            que[++tail]=A[i][j];
            if(i-a>=1&&que[head]==A[i-a][j]) head++;
            if(i>=a) MAX[i][j]=que[head];
        }
    }
    for(int j=1;j<=m;j++){
        int head=0,tail=-1;
        for(int i=1;i<=n;i++){
            while(head<=tail&&que[tail]>A[i][j]) tail--;
            que[++tail]=A[i][j];
            if(i-a>=1&&que[head]==A[i-a][j]) head++;
            if(i>=a) MIN[i][j]=que[head];
        }
    }
    for(int i=1;i<=n;i++){
        int head=0,tail=-1;
        for(int j=1;j<=m;j++){
            while(head<=tail&&que[tail]<MAX[i][j]) tail--;
            que[++tail]=MAX[i][j];
            if(j-b>=1&&que[head]==MAX[i][j-b]) head++;
            if(j>=b) MAXX[i][j]=que[head];
        }
    }
    for(int i=1;i<=n;i++){
        int head=0,tail=-1;
        for(int j=1;j<=m;j++){
            while(head<=tail&&que[tail]>MIN[i][j]) tail--;
            que[++tail]=MIN[i][j];
            if(j-b>=1&&que[head]==MIN[i][j-b]) head++;
            if(j>=b) MINN[i][j]=que[head];
        }
    }
    long long ans=0;
    for(int i=a;i<=n;i++){
        for(int j=b;j<=m;j++){
            ans+=((long long)MINN[i][j]*MAXX[i][j])%mod;
            ans%=mod;
        }
    }
    cout<<ans<<endl;
    return 0;
}
  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值