思路:可用单调队列解决,将二维数组先按行求出最大值、最小值,然后在此基础上按列再求最大值、最小值,则所得二维数组每一位[i,j]的元素就表示,以[i,j]为右下角的子矩阵的最大值/最小值。最后求解即可。
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 1010,MOD = 998244353;
int n,m,A,B;
int w[N][N];
int rmax[N][N];
int rmin[N][N];
int q[N];
//单调队列求最大值
void get_max(int a[],int b[],int tot,int k)
{
int hh = 0,tt = -1;
for(int i = 0;i < tot;i++)
{
//队不为空 且 滑动窗口向后,队首元素越界 则队首元素出队
//保证单调队列中存放的是滑动窗口内元素的下标
if(hh <= tt && q[hh] < i-k+1)hh++;
//求滑动窗口内的最大值,则只要保证单调队列递增,取队首元素即可
//队不为空 且 队尾元素大于等于下一等待进队元素 则队尾出队
//循环直到队尾元素小于等待进队元素(保证队列单调)
while(hh <= tt && a[q[tt]] >= a[i])tt--;
//进队
q[++tt] = i;
//输出队首元素
b[i] = a[q[hh]];
}
//单调队列求最小值
void get_min(int a[],int b[],int tot,int k)
{
int hh = 0,tt = -1;
for(int i = 0;i < tot;i++)
{
if(hh <= tt && q[hh] < i-k+1)hh++;
//求滑动窗口内的最大值,则只要保证单调队列递减,取队首元素即可
//队不为空 且 队尾元素小于等于下一等待进队元素 则队尾出队
//循环直到队尾元素小于等待进队元素(保证队列单调)
while(hh <= tt && a[q[tt]] >= a[i])tt--;
q[++tt] = i;
b[i] = a[q[hh]];
}
}
int main(){
scanf("%d%d%d%d",&n,&m,&A,&B);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
scanf("%d",&w[i][j]);
}
for(int i = 0;i < n;i++)
{
get_max(w[i],rmax[i],m,B);
get_min(w[i],rmin[i],m,B);
}
int a[N],b[N],c[N];
LL res = 0;
//分别对所得行的最大值、最小值 按列再求一遍
for(int i = B-1;i < m;i++)
{
for(int j = 0;j < n;j++)a[j] = rmax[j][i];
get_max(a,b,n,A);
for(int j = 0;j < n;j++)a[j] = rmin[j][i];
get_min(a,c,n,A);
for(int j = A-1;j < n;j++)
res =(res + (LL)c[j]*b[j]) % MOD;
}
printf("%d",res);
return 0;
}