Codeforces Round #574 (Div. 2) E. OpenStreetMap 单调栈做子矩阵最小和

题目链接: http://codeforces.com/contest/1195/problem/E

题意:

给你一个 n ∗ m n*m nm的数字矩阵,要你求出每个 a ∗ b a*b ab 的子矩阵中最小值的和。

做法:

我们可以先用一个单调栈来维护一个数组 m i n b [ i ] [ j ] minb[i][j] minb[i][j] ,表示第 i i i 行中 第 j − b + 1 j-b+1 jb+1 列到第 j j j 列里面原数组的最小值。然后用同样的方法去用单调栈维护 m i n a [ i ] [ j ] mina[i][j] mina[i][j] 表示第 j j j 列中第 i − a + 1 i-a+1 ia+1 行到第 i i i 行里面数组 m i n b [ i ] [ j ] minb[i][j] minb[i][j] 的最小值,而这个值就是我们要的答案,可以直接加进答案里面去。

代码

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = (int)a;i<=(int)b;i++)
#define pb push_back
#define fi first
#define se second
using namespace std;
const int maxn=3005;
const int maxm=300005;
const int MAX = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
ll ans,g0,x,y,z;
int G[maxn*maxn];
int mat[maxn][maxn],n,m;
int mx[maxn][maxn],a,b;
deque<pii> D;
int main(){
    scanf("%d%d%d%d",&n,&m,&a,&b);
    scanf("%lld%lld%lld%lld",&g0,&x,&y,&z);
    G[0]=g0;
    rep(i,1,n*m-1){
        ll tmp=(ll)(G[i-1]*x+y)%z;
        G[i]=(int)tmp;
    }
    rep(i,1,n)
        rep(j,1,m)
            mat[i][j]=G[(i-1)*m+j-1];

    rep(i,1,n){
        D.clear();
        rep(j,1,b){
            while(D.size()&&D.back().fi>mat[i][j]) D.pop_back();
            D.push_back({mat[i][j],j});
        }
        mx[i][b]=D.front().fi;
        rep(j,b+1,m){
            while(D.size()&&D.back().fi>mat[i][j]) D.pop_back();
            while(D.size()&&D.front().se==j-b) D.pop_front();
            D.push_back({mat[i][j],j});
            mx[i][j]=D.front().fi;
        }
    }

    rep(j,b,m){
        D.clear();
        rep(i,1,a){
            while(D.size()&&D.back().fi>mx[i][j]) D.pop_back();
            D.push_back({mx[i][j],i});
        }
        ans+=D.front().fi;
        rep(i,a+1,n){
            while(D.size()&&D.back().fi>mx[i][j]) D.pop_back();
            while(D.size()&&D.front().se==i-a) D.pop_front();
            D.push_back({mx[i][j],i});
            ans+=D.front().fi;
        }
    }
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值