【蓝桥杯每日一题】统计子矩阵

统计子矩阵

2024-12-5 蓝桥杯每日一题 统计子矩阵 前缀和 双指针

题目大意

给定一个 N × M N×M N×M的矩阵 A, 请你统计有多少个子矩阵 (最小 1×1, 最大 N × M N×M N×M) 满足子矩阵中所有数的和不超过给定的整数 K ?

解题思路
  1. 乍一看这个题与矩阵有关,而且又让求子矩阵的总和,那么很自然的就会想到二维前缀和,然后通过四重循环的枚举找出所有符合条件的子矩阵。
  2. 再一看数据范围,四重循环包爆的,那么想怎么缩小这个循环次数呢?
    既然枚举子矩阵的两个顶点行不通,那么枚举子矩阵的两条边行不行?
  3. **先看宽怎么枚举?**可以想到通过求出每一列的前缀和,然后通过双重循环枚举即可,这个枚举的长度就是宽,又由于是前缀和可以通过O(1) 来求出这之间的总和;
  4. **然后再看长度怎么枚举?**首先确定这个长度的枚举是在宽度已经确定的条件下枚举的,也就是说在枚举的时候,长和宽只有一个值在变;那么可以通过双指针的方式枚举长度范围,右指针每次向前加1,然后左指针根据矩阵的大小来改变;那么数量的计算就是左右指针之间的差值。
    对于蓝桥杯来说暴力拿分还是挺重要的
70分
cpp 复制代码
// 二维前缀和

#include <iostream>
using namespace std;

const int N = 510;
typedef long long ll;
int n,m,kk,a[N][N],b[N][N];

int main()
{
    cin>>n>>m>>kk;
    for(int i = 1;i <= n;i++) 
        for(int j = 1;j <= m;j++) 
            cin>>a[i][j];

    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= m;j++) {
            b[i][j] = b[i-1][j] + b[i][j-1] - b[i-1][j-1] + a[i][j];
        } 
    }   

    int res = 0;
    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= m;j++) {
            for(int k = i;k <= n;k++) {
                for(int h = j;h <= m;h ++) {
                    if(b[k][h] - b[k][j-1] - b[i-1][h] + b[i-1][j-1] <= kk) {
                        res ++;
                    } else {
                        break;
                    }
                }
                
            }
        }
    }
    cout<<res<<endl;
    return 0;
}
Accepted
cpp 复制代码
// 列前缀和 + 双指针

#include <iostream>
using namespace std;

const int N = 510;
typedef long long ll;
int n,m,kk,a[N][N],b[N][N];

int main()
{
    cin>>n>>m>>kk;
    for(int i = 1;i <= n;i++) 
        for(int j = 1;j <= m;j++) {
            cin>>a[i][j];
            b[i][j] = b[i-1][j] + a[i][j];  // 处理 列 前缀和
        }

    ll res = 0; // 要开long long
    for(int i = 1;i <= n;i++) {
        for(int j = i;j <= n;j++) { // 前两层循环 枚举矩阵的宽
            for(int l = 1,r = 1,sum = 0;r <= m;r++) {   // 通过双指针枚举矩阵的长
                sum += b[j][r] - b[i-1][r];     // 先斩后奏  先加里面后面再判断
                while(sum > kk) {
                    sum -= b[j][l] - b[i-1][l];    // 从前面缩短矩阵的长
                    l++;
                }
                res += r-l+1;           // 因为这时候矩阵的宽是确定的,那么只需要判断有多少种长度是满足的即可
            }
        }
    }
    cout<<res<<endl;
    return 0;
}
备注

想要一起备赛的小伙伴可以私信加我的联系方式!

相关推荐
夏鹏今天学习了吗25 分钟前
【LeetCode热题100(64/100)】搜索旋转排序数组
算法·leetcode·职场和发展
2301_796512521 小时前
Rust编程学习 - 问号运算符会return一个Result 类型,但是如何使用main函数中使用问号运算符
开发语言·学习·算法·rust
小龙报1 小时前
算法通关指南:数据结构和算法篇 --- 队列相关算法题》--- 1. 【模板】队列,2. 机器翻译
c语言·开发语言·数据结构·c++·算法·学习方法·visual studio
晨非辰1 小时前
【数据结构初阶】--从排序算法原理分析到代码实现操作,参透插入排序的奥秘!
c语言·开发语言·数据结构·c++·算法·面试·排序算法
三川6982 小时前
排序算法介绍
数据结构·算法·排序算法
智驱力人工智能7 小时前
基于视觉分析的人脸联动使用手机检测系统 智能安全管理新突破 人脸与手机行为联动检测 多模态融合人脸与手机行为分析模型
算法·安全·目标检测·计算机视觉·智能手机·视觉检测·边缘计算
2301_764441337 小时前
水星热演化核幔耦合数值模拟
python·算法·数学建模
循环过三天7 小时前
3.4、Python-集合
开发语言·笔记·python·学习·算法
priority_key10 小时前
排序算法:堆排序、快速排序、归并排序
java·后端·算法·排序算法·归并排序·堆排序·快速排序
不染尘.10 小时前
2025_11_7_刷题
开发语言·c++·vscode·算法