题目链接: http://codeforces.com/contest/1195/problem/E
题意:
给你一个 n ∗ m n*m n∗m的数字矩阵,要你求出每个 a ∗ b a*b a∗b 的子矩阵中最小值的和。
做法:
我们可以先用一个单调栈来维护一个数组 m i n b [ i ] [ j ] minb[i][j] minb[i][j] ,表示第 i i i 行中 第 j − b + 1 j-b+1 j−b+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 i−a+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;
}