蓝桥杯23年第十四届省赛-子矩阵 |暴力、滑动窗口单调队列

题目链接:

蓝桥杯2023年第十四届省赛真题-子矩阵 - C语言网 (dotcpp.com)

6.子矩阵 - 蓝桥云课 (lanqiao.cn)

说明:

单调队列、滑动窗口模板。 先求每行的滑动窗口(最大值和最小值都求),再对求出来的滑动窗口再求每列的。 参考学习链接:https://blog.csdn.net/weixin_72060925/article/details/127952750

对于固定大小 的子矩阵, 又是求子矩阵里的最值 ,那么就要考虑用滑动窗口来做,因为子矩阵大小固定,即行和列大小固定,滑动窗口大小也是在窗口大小固定时使用的。

可以想象一下一个子矩阵,先求每行的滑动窗口(最大值和最小值都求),那么这个子矩阵每行(共a行)的b个(列)元素,都变成一个最值表示,a*b个变成了a个,再对求出来的滑动窗口再求每列的滑动窗口,就是这a行上面的a个元素变成一个最值,也就是一个子矩阵"浓缩"成了一个最值。

如果大小不确定 的子矩阵问题,且涉及的是子矩阵的元素和 ,就要考虑前缀和降维。

代码:

正解:

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e3+10;
int ans=0;
int mod=998244353;
int g[N][N];
int q[N];
int line_max[N][N];int line_min[N][N];
int minv[N][N];int maxv[N][N];
//四重循环暴力
signed main() {
 
   ios::sync_with_stdio(0);
   cin.tie(0);
   cout.tie(0);
   
   int n,m,a,b;
   cin>>n>>m>>a>>b;
   
   for(int i=0;i<n;i++){
   	for(int j=0;j<m;j++)
   	cin>>g[i][j];
   }
   
   
    //每行求滑动窗口 对该行的某个起点(j)求出窗口里的最大值 
   for(int i=0;i<n;i++){
     int h=0,t=-1;//注意h和t写在第一层里 ,每行的滑动窗口不相关 
	 for(int j=0;j<m;j++){
	 	if(h<=t&&q[h]<j-b+1){
	 		h++;
		 }
		 while(h<=t&&g[i][q[t]]<=g[i][j]){
		 	t--;
		 }
	 	q[++t]=j;
	 	if(j-b+1>=0) line_max[i][j-b+1]=g[i][q[h]];
	 }	
   } 
   

    //每行求滑动窗口 对该行的某个起点(j)求出窗口里的最小值 
   for(int i=0;i<n;i++){
     int h=0,t=-1;//注意h和t写在第一层里 ,每行的滑动窗口不相关 
	 for(int j=0;j<m;j++){
	 	if(h<=t&&q[h]<j-b+1){
	 		h++;
		 }
		 while(h<=t&&g[i][q[t]]>=g[i][j]){
		 	t--;
		 }
	 	q[++t]=j;
	 	if(j-b+1>=0) line_min[i][j-b+1]=g[i][q[h]];
	 }	
   } 
   
   
   //对已经求出的行滑动窗口(每行的每个窗口变成由最大值代表的一个数)最大值矩阵 求每列的滑动窗口最大值 
   for(int j=0;j<m-b+1;j++){
   	int h=0,t=-1;
   	for(int i=0;i<n;i++){
   		if(h<=t&&q[h]<i-a+1)
   		h++;
   		while(h<=t&&line_max[q[t]][j]<=line_max[i][j])
   		t--;
   		q[++t]=i;
   		//第j列上的 第i-a+1个窗口 保存对应最大值 
   		if(i-a+1>=0) maxv[i-a+1][j]=line_max[q[h]][j];
   		
	   }
   }
   
    for(int j=0;j<m-b+1;j++){
   	int h=0,t=-1;
   	for(int i=0;i<n;i++){
   		if(h<=t&&q[h]<i-a+1)
   		h++;
   		while(h<=t&&line_min[q[t]][j]>=line_min[i][j])
   		t--;
   		q[++t]=i;
   		//第j列上的 第i-a+1个窗口 保存对应最大值 
   		if(i-a+1>=0) minv[i-a+1][j]=line_min[q[h]][j];
   		
	   }
   }
   
   
   for(int i=0;i<n-a+1;i++){
   	for(int j=0;j<m-b+1;j++){
   		ans=(ans+minv[i][j]*maxv[i][j]%mod)%mod;
	   }
   }
   
  cout<<ans;
  return 0;
}

暴力(70%蓝桥官网测试点):

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e3+10;
int ans=0;
int mod=998244353;
int g[N][N];
//四重循环暴力
signed main() {
 
   ios::sync_with_stdio(0);
   cin.tie(0);
   cout.tie(0);
   
   int n,m,a,b;
   cin>>n>>m>>a>>b;
   
   for(int i=0;i<n;i++){
       for(int j=0;j<m;j++)
       cin>>g[i][j];
   }
   
    for(int i=0;i<n-a+1;i++){
       for(int j=0;j<m-b+1;j++){
           int mx=0,mn=1e9;
           
           for(int k=0;k<a;k++){
               for(int l=0;l<b;l++){
                   mx=max(mx,g[i+k][j+l]);
                   mn=min(mn,g[i+k][j+l]);
               }
           }
           ans=(ans+mx*mn%mod)%mod;
       }
   
   }
   
  cout<<ans;
  return 0;
}
相关推荐
池央3 小时前
ops-nn 算子库中的数据布局与混合精度策略:卷积、矩阵乘法与 RNN 的优化实践
rnn·线性代数·矩阵
HY小宝F4 小时前
职场沟通的深层智慧:从对抗到协作的自我修炼
职场和发展
AI职业加油站5 小时前
职业提升之路:我的大数据分析师学习与备考分享
大数据·人工智能·经验分享·学习·职场和发展·数据分析
_OP_CHEN5 小时前
【算法基础篇】(五十六)容斥原理指南:从集合计数到算法实战,解决组合数学的 “重叠难题”!
算法·蓝桥杯·c/c++·组合数学·容斥原理·算法竞赛·acm/icpc
深鱼~6 小时前
大模型底层算力支撑:ops-math在矩阵乘法上的优化
人工智能·线性代数·矩阵·cann
Zfox_6 小时前
CANN PyPTO 编程范式深度解析:并行张量与 Tile 分块操作的架构原理、内存控制与流水线调度机制
线性代数·矩阵·架构
TechWJ6 小时前
catlass深度解析:Ascend平台的高性能矩阵运算模板库
线性代数·矩阵·ascend·cann·catlass
草履虫建模12 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
学历真的很重要21 小时前
【系统架构师】第二章 操作系统知识 - 第二部分:进程管理(详解版)
学习·职场和发展·系统架构·系统架构师