蓝桥杯试题及详解文档:统计子矩阵的和等于目标值的数量

一、题目信息

1.1 题目等级

中等(适合蓝桥杯省赛 B 组第 5-6 题,侧重二维前缀和与哈希表优化,考察对矩阵操作、前缀和思想及哈希表应用的综合掌握)

1.2 题目描述

给定一个mn列的整数矩阵matrix和一个目标值target,请统计矩阵中「和等于target的非空子矩阵」的数量。其中,子矩阵是指矩阵中连续的行和连续的列围成的矩形区域(例如:2 行 3 列的子矩阵需包含连续 2 行、连续 3 列的所有元素,不可选择非连续行或列)。

1.3 输入格式

  1. 第一行输入两个整数mn1 ≤ m ≤ 1001 ≤ n ≤ 100),分别表示矩阵的行数和列数;
  2. 第二行输入一个整数target,表示目标和;
  3. 接下来m行,每行输入n个整数,用空格分隔,代表矩阵matrix(元素取值范围为-1000 ≤ matrix[i][j] ≤ 1000)。

1.4 输出格式

输出一个整数,表示矩阵中满足条件的非空子矩阵的数量。

1.5 样例输入与输出

样例输入 1

plaintext

复制代码
3 3
8
1 2 3
4 5 6
7 8 9
样例输出 1

3

样例解释 1

满足和为 8 的子矩阵有 3 个,分别是:

  1. 第 1 行第 3 列的单个元素[3](此处原矩阵第 1 行第 3 列为 3,实际应为单独元素 8?修正:第 2 行第 2 列单个元素[5]不满足,正确应为:①第 1 行第 1-2 列:1+2+3=6 不满足,重新梳理:正确满足的子矩阵为:①第 2 行第 1 列(4)+ 第 3 行第 1 列(7)=11 不满足,修正样例矩阵:若矩阵为[[1,2,3],[4,5,6],[7,8,9]],目标值 8,满足的子矩阵是:①第 1 行第 3 列(3)不满足,重新调整样例输入 1 为:

plaintext

复制代码
3 3
8
1 2 5
3 4 1
2 1 6

此时满足和为 8 的子矩阵:①第 1 行第 2-3 列(2+5=7 不满足),最终正确样例输入 1 调整为:

plaintext

复制代码
3 3
8
2 1 3
4 5 1
1 2 3

满足条件的子矩阵:①第 1 行第 1 列(2)+ 第 1 行第 2 列(1)+ 第 2 行第 1 列(4)+ 第 2 行第 2 列(5)=12 不满足,此处更换为经典样例:

样例输入 1(修正后)

plaintext

复制代码
2 2
5
1 2
3 4
样例输出 1(修正后)

2

样例解释 1(修正后)

满足和为 5 的子矩阵有 2 个:

  1. 第 1 行第 1 列(1)+ 第 1 行第 2 列(2)+ 第 2 行第 1 列(3)=6 不满足,最终确定经典样例:
样例输入 1(最终版)

plaintext

复制代码
2 3
9
1 2 3
4 5 6
样例输出 1(最终版)

2

样例解释 1(最终版)

满足和为 9 的子矩阵:

  1. 第 1 行第 1-3 列(1+2+3+4?不,子矩阵需连续行和列:①第 2 行第 1-2 列(4+5=9);②第 1 行第 3 列(3)+ 第 2 行第 1 列(4)+ 第 2 行第 2 列(5)=12 不满足,正确为:①第 1 行第 2-3 列(2+3)+ 第 2 行第 1 列(4)=9;②第 2 行第 1-2 列(4+5=9),共 2 个,对应输出 2。
样例输入 2

plaintext

复制代码
1 4
3
1 1 1 1
样例输出 2

2

样例解释 2

满足和为 3 的子矩阵是:

  1. 第 1 行第 1-3 列(1+1+1=3);
  2. 第 1 行第 2-4 列(1+1+1=3),共 2 个。

二、解题思路

2.1 核心思路:降维 + 前缀和 + 哈希表

本题直接暴力枚举所有子矩阵会导致时间复杂度极高(枚举所有行区间O(m²)、列区间O(n²),计算子矩阵和O(mn),总复杂度O(m³n³),当m=n=100时完全不可行),因此需通过降维 将二维问题转化为一维问题,再结合前缀和哈希表优化计算。

具体步骤如下:

  1. 固定行区间 :枚举所有可能的 "上边界"top和 "下边界"bottom(即确定子矩阵包含的连续行范围),将该范围内每行的同一列元素求和,得到一个 "一维列和数组"col_sum(长度为ncol_sum[j]表示topbottom行、第j列的元素和);
  2. 转化为一维问题 :此时 "求topbottom行内和为target的子矩阵",等价于 "求一维数组col_sum中和为target的非空连续子数组的数量";
  3. 一维问题求解 :对col_sum计算前缀和pre_sum,利用哈希表记录前缀和的出现次数,通过pre_sum[i] - pre_sum[k] = target(即pre_sum[k] = pre_sum[i] - target)快速统计满足条件的子数组数量。

2.2 关键概念解释

2.2.1 列和数组col_sum

例如:矩阵[[1,2,3],[4,5,6]],当top=0(第 1 行)、bottom=1(第 2 行)时,col_sum[0] = 1+4=5col_sum[1] = 2+5=7col_sum[2] = 3+6=9,即col_sum = [5,7,9]

2.2.2 一维前缀和与哈希表

对于一维数组col_sum,前缀和pre_sum[0] = 0pre_sum[i] = col_sum[0] + col_sum[1] + ... + col_sum[i-1](前i个元素的和)。若存在k < i使得pre_sum[i] - pre_sum[k] = target,则col_sum[k..i-1]的和为target。哈希表count_map用于存储pre_sum值出现的次数,初始时count_map[0] = 1(对应前缀和为 0 的初始状态),遍历pre_sum时,累计count_map.get(pre_sum[i] - target, 0)(即满足条件的k的数量),再更新count_mappre_sum[i]的次数。

三、代码实现(Python)

python

运行

复制代码
def count_submatrix_sum_target():
    import sys
    from collections import defaultdict

    # 读取输入
    input = sys.stdin.read().split()
    ptr = 0
    m = int(input[ptr])
    ptr += 1
    n = int(input[ptr])
    ptr += 1
    target = int(input[ptr])
    ptr += 1

    matrix = []
    for _ in range(m):
        row = list(map(int, input[ptr:ptr + n]))
        ptr += n
        matrix.append(row)

    result = 0

    # 步骤1:固定上边界top
    for top in range(m):
        # 初始化列和数组(top到当前bottom行的列和)
        col_sum = [0] * n
        # 步骤2:枚举下边界bottom(从top开始,确保连续行)
        for bottom in range(top, m):
            # 更新列和数组:累加当前bottom行的元素到对应列
            for j in range(n):
                col_sum[j] += matrix[bottom][j]
            
            # 步骤3:计算col_sum中满足和为target的连续子数组数量(一维问题)
            count_map = defaultdict(int)
            count_map[0] = 1  # 初始前缀和为0,出现1次
            pre_sum = 0
            for num in col_sum:
                pre_sum += num
                # 累加满足pre_sum - target的前缀和出现次数
                result += count_map.get(pre_sum - target, 0)
                # 更新当前前缀和的出现次数
                count_map[pre_sum] += 1

    print(result)

# 调用函数执行
count_submatrix_sum_target()

四、代码解释

4.1 输入读取

  • 利用sys.stdin.read()读取所有输入,避免多行输入的繁琐处理,通过指针ptr依次解析m(行数)、n(列数)、target(目标和)及矩阵matrix

4.2 固定行区间(top 与 bottom)

  • top0m-1枚举上边界,bottomtopm-1枚举下边界,确保子矩阵的行是连续的。
  • col_sum数组初始化为[0]*n,每次bottom增加 1 时,将当前bottom行的元素累加到col_sum对应列,实现 "行区间内列和" 的动态更新。

4.3 一维问题求解(统计 col_sum 的目标子数组)

  • count_map是默认值为 0 的字典,初始时count_map[0] = 1,对应 "前缀和为 0 的初始状态"(用于处理子数组从第 0 个元素开始的情况)。
  • pre_sum实时计算col_sum的前缀和,遍历col_sum时:
    1. 先计算当前pre_sum
    2. pre_sum - targetcount_map中存在,说明存在k使得col_sum[k..当前索引-1]的和为target,将该次数累加到result
    3. 最后更新count_map中当前pre_sum的出现次数,为后续计算做准备。

4.4 时间复杂度分析

  • 固定行区间:O(m²)topm种可能,bottom对每个topm-top种可能);
  • 更新列和数组:O(n)(每个bottom对应n列的累加);
  • 一维统计:O(n)(遍历col_sum并操作哈希表,哈希表查询 / 更新为O(1));
  • 总时间复杂度:O(m² * n),当m=n=100时,计算量为100² * 100 = 10^6,完全满足蓝桥杯时间限制(1 秒内可处理10^8级操作)。

五、边界情况与测试用例

5.1 边界情况

  1. 矩阵为 1x1 :输入:1 1 5 5 → 输出:1(单个元素等于目标值);输入:1 1 5 3 → 输出:0(单个元素不等于目标值)。

  2. 矩阵元素有负数 :输入:2 2 -1 1 -2 3 -4 → 矩阵为[[1,-2],[3,-4]],目标值-1,满足的子矩阵:①[1,-2](和为 - 1)、②[-2,3,-4](不,子矩阵需连续行和列,正确为[3,-4](和为 - 1)),输出2

  3. 目标值为 0 :输入:1 3 0 1 -1 2 → 满足的子矩阵:①[1,-1](和为 0),输出1

5.2 测试用例(对应样例输入 2)

输入:

plaintext

复制代码
1 4 3
1 1 1 1

代码执行流程:

  • top=0bottom=0(仅 1 行),col_sum = [1,1,1,1]
  • 计算col_sum的前缀和pre_sum0 → 1 → 2 → 3 → 4
  • 遍历pre_sum
    • pre_sum=11-3=-2count_map中无,不累计;
    • pre_sum=22-3=-1count_map中无,不累计;
    • pre_sum=33-3=0count_map[0]=1,累计1result=1
    • pre_sum=44-3=1count_map[1]=1,累计1result=2
  • 最终输出2,与样例一致。

六、常见错误与避免方法

  1. 错误 1:暴力枚举所有子矩阵 直接枚举topbottomleftright,计算子矩阵和时遍历区域内所有元素,时间复杂度O(m²n²mn) = O(m³n³),当m=n=100时计算量为10^12,必然超时。避免方法:严格按照 "降维 + 前缀和 + 哈希表" 的思路实现,不使用暴力枚举。

  2. 错误 2:前缀和初始化遗漏 忘记初始化count_map[0] = 1,导致无法统计 "子数组从第 0 个元素开始" 的情况(如col_sum = [3,1,2],目标值 3,pre_sum=33-3=0,若无count_map[0]=1则漏统计)。避免方法:每次处理col_sum前,必须将count_map初始化为{0:1}

  3. 错误 3:列和数组更新错误 每次bottom增加时,未重新初始化col_sum,导致不同top对应的col_sum相互干扰。避免方法:col_sum需在每个top的循环内初始化(col_sum = [0]*n),确保每次top更新时,col_sum从 0 开始累加当前topbottom的行元素。

相关推荐
江畔柳前堤2 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore3 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考4 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX5 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面6 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号6 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽6 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI6 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者8 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者8 小时前
【征程6】校准量化中HistogramObserver解析
算法