蓝桥集训之子矩阵
-
核心思想:二维单调队列
- 先求每一行中列长为B的区间的最值
- 再在最值数组中求行长为A的区间的最值 –> 区间最值
- 最后遍历所有最大最小值相乘的结果
-
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 1010,MOD = 998244353; typedef long long LL; int w[N][N]; int n,m,A,B; int row_max[N][N],row_min[N][N]; int q[N]; void getmax(int a[],int b[],int tot,int k) //a数组共tot个数中找长度为k的区间最值放入b { 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 getmin(int a[],int b[],int tot,int k) //a数组共tot个数中找长度为k的区间最值放入b { 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() { ios::sync_with_stdio(false);cin.tie(0); cin>>n>>m>>A>>B; for(int i=0;i<n;i++) for(int j=0;j<m;j++) cin>>w[i][j]; for(int i=0;i<n;i++) { getmax(w[i],row_max[i],m,B); //列长B的区间最值 getmin(w[i],row_min[i],m,B); } int ans=0; int a[N],b[N],c[N]; for(int i=B-1;i<m;i++) { for(int j=0;j<n;j++) a[j] = row_max[j][i]; //取出第j列的所有最值 getmax(a,b,n,A); //将区间最大值存入b for(int j=0;j<n;j++) a[j] = row_min[j][i]; getmin(a,c,n,A); //将区间最小值存入c for(int j=A-1;j<n;j++) ans = (ans + (LL) b[j] * c[j] ) %MOD; } cout<<ans<<endl; return 0; }