统计子矩阵

一、题目描述

P8783 [蓝桥杯 2022 省 B] 统计子矩阵

二、算法简析

2.1 二维前缀和

我们知道,只要确定了矩阵的左上顶点和右下顶点,一个矩阵就被固定了。因此,我们可以遍历这两个顶点,达到遍历所有子矩阵的目的,复杂度会达到 O ( N 2 ∗ M 2 ) O(N^2*M^2) O(N2M2)。确定了子矩阵,就要判断子矩阵的值是否不大于 K K K。 如何能高效地得到子矩阵的值呢?答案是二维前缀和
与普通的前缀和不同,二维前缀和 psum[i][j] = \text{psum[i][j]}= psum[i][j]= 左上顶点 ( 1 , 1 ) (1, 1) (1,1)、右下顶点 ( i , j ) (i, j) (i,j) 确定的子矩阵的值。通过以下表达式,可以得到二维前缀和:

psum[i][j] = psum[i][j - 1] + psum[i - 1][j] - psum[i - 1][j - 1] + A[i][j] \text{psum[i][j] = psum[i][j - 1] + psum[i - 1][j] - psum[i - 1][j - 1] + A[i][j]} psum[i][j] = psum[i][j - 1] + psum[i - 1][j] - psum[i - 1][j - 1] + A[i][j]

有了二维前缀和,就可以以 O ( 1 ) O(1) O(1) 确定左上角 ( x 1 , y 1 ) (x1, y1) (x1,y1)、右下角 ( x 2 , y 2 ) (x2, y2) (x2,y2) 的子矩阵的值:

matrix_val = psum[x2][y2] - psum[x1 - 1][y2] - psum[x2][y1 - 1] + psum[x1 - 1][y1 - 1] \text{matrix\_val = psum[x2][y2] - psum[x1 - 1][y2] - psum[x2][y1 - 1] + psum[x1 - 1][y1 - 1]} matrix_val = psum[x2][y2] - psum[x1 - 1][y2] - psum[x2][y1 - 1] + psum[x1 - 1][y1 - 1]

但是,该算法的复杂度仍然有 O ( N 2 ∗ M 2 ) O(N^2*M^2) O(N2M2),会 LTE


2.2 压缩维度 + 双指针

压缩维度:我们可以把二维矩阵压缩至一维:画两条线,high 表示矩阵上界(左上点只能在该行)、low表示矩阵下界(右下点只能在该行)。因此,由 highlow 确定的子矩阵只能由列矩阵组合而成,所以按列压缩,即按列求和。
图1
通过遍历 highlow,我们可以得到所有组成子矩阵的列矩阵。

双指针:通过上文的压缩,我们得到了“子矩阵的零件”。为了得到该情况下的所有子矩阵,肯定要用双指针遍历压缩数组,得到所有组合方式。

int B[4];   // 压缩后的结果for (int i = 0; i < 4; i++)for (int j = i; j < 4; j++)\\ ...

显然,指针 j 发生了回溯,导致复杂度达到了 O ( n 2 ) O(n^2) O(n2)。如何避免发生回溯呢?利用单调性,我们可以把复杂度降为 O ( n ) O(n) O(n)
我们规定 area(left, right) = B[left] + B[left + 1] + ... + B[right] \text{area(left, right) = B[left] + B[left + 1] + ... + B[right]} area(left, right) = B[left] + B[left + 1] + ... + B[right]
area(left, right) <= K \text{area(left, right) <= K} area(left, right) <= K left + 1 <= right \text{left + 1 <= right} left + 1 <= right,则 area(left + 1, right) <= K \text{area(left + 1, right) <= K} area(left + 1, right) <= K
area(left, right) > K \text{area(left, right) > K} area(left, right) > K right + 1 <= M \text{right + 1 <= M} right + 1 <= M,则 area(left, right + 1) > K \text{area(left, right + 1) > K} area(left, right + 1) > K
显然, area(left, right) \text{area(left, right)} area(left, right) left \text{left} left 单调递减,随 right \text{right} right 单调递增

利用单调性,我们可以得到以下结果:

  • 1、随 left \text{left} left 单调递减,若 area(left, right) <= K \text{area(left, right) <= K} area(left, right) <= K,则一共有 right - left + 1 \text{right - left + 1} right - left + 1 种组合方式。
  • 2、我们只需要遍历 right 就能得到所有子矩阵。因为单调性,若 area(left, right) > K \text{area(left, right) > K} area(left, right) > K,只需要 left++ \text{left++} left++,直到 area(left, right) <= K \text{area(left, right) <= K} area(left, right) <= K
int B[4];   // 压缩后的结果int left = 1, right = 1;
ll tmp = 0;
for (; right <= 4; right++)
{tmp += B[right];if (tmp <= K)ans += right - left + 1;else{while (tmp > K){tmp -= B[left];left++;	}ans += right - left + 1;}	
} 

三、AC代码

#include <bits/stdc++.h>using namespace std;const int MAX = 505;
typedef long long ll;int A[MAX][MAX], N, M, K;
ll ans, psum[MAX][MAX], B[MAX];int quickin(void)
{int ret = 0;char ch = getchar();while (ch < '0' || ch > '9')ch = getchar();while (ch >= '0' && ch <= '9' && ch != EOF){ret = ret * 10 + ch - '0';ch = getchar();}return ret;
}void init(void)
{for (int i = 1; i <= N; i++)for (int j = 1; j <= M; j++)psum[i][j] = psum[i - 1][j] + A[i][j];
}void solve(void)
{for (int high = 1; high <= N; high++){for (int low = high; low <= N; low++){for (int i = 1; i <= M; i++)B[i] = psum[low][i] - psum[high - 1][i];int left = 1, right = 1;ll tmp = 0;for (; right <= M; right++){tmp += B[right];if (tmp <= K)ans += right - left + 1;else{while (tmp > K){tmp -= B[left];left++;	}ans += right - left + 1;}	} }}cout << ans << endl;
}int main()
{#ifdef LOCALfreopen("test.in", "r", stdin);#endifN = quickin(), M = quickin(), K = quickin();for (int i = 1; i <= N; i++)for (int j = 1; j <= M; j++)A[i][j] = quickin();init();solve();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/499851.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring security oauth2 之GitHub应用注册

前言&#xff1a; 要想使用spring security oauth2 来实现GitHub授权登录&#xff0c;就必须先要有一个GitHub的应用。如果使用gitee也是同理。本文介绍如果注册GitHub应用。 step1:进入到注册应用的页面 注册地址&#xff1a;Sign in to GitHub GitHub step2:填写信息 图中…

【HTML】HTML基础1(第一个网站!)

目录 软件使用 HTML的基本结构 案例示范 用记事本编写网页 软件使用 注释&#xff1a;<!-- -->中的内容是注释内容&#xff0c;自己写代码的时候可以没有&#xff01; HTML的基本结构 <!DOCTYPE html> <!-- 文档声明&#xff0c;位于文档最前面位置 -->…

RK3568平台开发系列讲解(基础篇)文件私有数据

🚀返回专栏总目录 文章目录 一、文件私有数据二、文件私有数据实验沉淀、分享、成长,让自己和他人都能有所收获!😄 一、文件私有数据 Linux 中并没有明确规定要使用文件私有数据,但是在 linux 驱动源码中,广泛使用了文件私有数据,这是 Linux 驱动遵循的“潜规则”,实…

column ‘_id‘ does not exist

最近把 csv 导入 SQLite 给 CursorAdapter 使用出现了这个莫名其妙的错误。 java.lang.IllegalArgumentException: column _id does not exist-CSDN博客 查找资料才明白&#xff1a;CursorAdapter 使用的数据库中必须有 _id 这个字段。 好吧&#xff0c;导入的数据库增加 _i…

搭建LNMP环境并搭建论坛和博客

目录 一、LNMP架构原理 二、编译安装Nginx 三、编译安装MySQL 四、编译安装PHP 五、配置Nginx支持PHP解析 六、安装论坛 七、安装博客 一、LNMP架构原理 LNMP架构&#xff0c;是指在Linux平台下&#xff0c;由运行Nginx的web服务器&#xff0c;运行PHP的动态页面解析程序…

STM32 Cortex-M3 HardFault异常定位

目录 1 Fault类异常 1.1 总线Fault 1.2 存储器管理Fault 1.3 用法Fault 1.4 硬件Fault 2 Core Registers 2.1 R14&#xff08;LR&#xff09;寄存器 2.2 R15&#xff08;PC&#xff09;寄存器 3 HardFault处理原理 4 真实项目调试 1 Fault类异常 Cortex-M3的Fault异…

SQL 行转列

MySQL mysql换行使用\n SELECTpic_business_id,GROUP_CONCAT( \n类型, :, pic_med_type_name, ,金额, pic_cost ) FROMsl_patient_item_cost GROUP BYpic_business_id2. Oracle oracle换行使用CHR( 10 ) SELECTMEDICAL_RECORD_ID,IN_NUMBER,NAME,REPLACE( wmsys.wm_concat …

AI大模型-启航

文章目录 什么是大模型&#xff1f;&#xff08;大体现在参数量巨大&#xff09;大模型将会改变那些行业&#xff08;大模型有哪些作用&#xff1f;&#xff09;如何搞数据训练模型&#xff1f;LangChain带来的技术变革LangChain架构 什么是大模型&#xff1f;&#xff08;大体…

云畅科技携手飞腾打造智慧园区信创低代码综合解决方案

01 方案概述 随着国家对信创产业的日益重视与大力支持&#xff0c;信创行业的产业化进程正在不断加快。智慧园区&#xff0c;作为信创产业蓬勃发展的核心载体与战略平台&#xff0c;正日益凸显其重要性。与此同时&#xff0c;在政策引导和市场需求的双重驱动下&#xff0c;智慧…

函数重载和运算符重载

函数重载和运算符重载 一、函数重载二、运算符重载&#xff08;一&#xff09;运算符重载&#xff08;二&#xff09;运算符重载&#xff08;三&#xff09;运算符重载&#xff08;前置和后置&#xff09;&#xff08;四&#xff09;、运算符重载&#xff08;五&#xff09;<…

【玩转408数据结构】线性表——双链表、循环链表和静态链表(线性表的链式表示 下)

知识回顾 在前面的学习中&#xff0c;我们已经了解到了链表&#xff08;线性表的链式存储&#xff09;的一些基本特点&#xff0c;并且深入的研究探讨了单链表的一些特性&#xff0c;我们知道&#xff0c;单链表在实现插入删除上&#xff0c;是要比顺序表方便的&#xff0c;但是…

为什么推荐使用ref而不是reactive

为什么推荐使用ref而不是reactive 局限性问题&#xff1a; reactive本身存在一些局限性&#xff0c;可能会在开发过程中引发一些问题。这需要额外的注意力和处理&#xff0c;否则可能对开发造成麻烦。数据类型限制&#xff1a; reactive声明的数据类型仅限于对象&#xff0c;而…