首页 > 其他分享 >统计子矩阵

统计子矩阵

时间:2024-02-29 12:23:12浏览次数:27  
标签:right int text 矩阵 psum 统计 left

一、题目描述

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

二、算法简析

2.1 二维前缀和

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

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

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

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

但是,该算法的复杂度仍然有 \(O(N^2*M^2)\),会 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)\)。
我们规定 \(\text{area(left, right) = B[left] + B[left + 1] + ... + B[right]}\)。
若 \(\text{area(left, right) <= K}\) 且 \(\text{left + 1 <= right}\),则 \(\text{area(left + 1, right) <= K}\)。
若 \(\text{area(left, right) > K}\) 且 \(\text{right + 1 <= M}\),则 \(\text{area(left, right + 1) > K}\)。
显然,\(\text{area(left, right)}\) 随 \(\text{left}\) 单调递减,随 \(\text{right}\) 单调递增

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

  • 1、随 \(\text{left}\) 单调递减,若 \(\text{area(left, right) <= K}\),则一共有 \(\text{right - left + 1}\) 种组合方式。
  • 2、我们只需要遍历 right 就能得到所有子矩阵。因为单调性,若 \(\text{area(left, right) > K}\),只需要 \(\text{left++}\),直到 \(\text{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 LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	N = 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;
}

标签:right,int,text,矩阵,psum,统计,left
From: https://www.cnblogs.com/hoyd/p/18043219

相关文章

  • CVPR、ECCV、ICCV三大顶会显著性目标检测近三年发表论文统计
    2021(11篇)CVPR1.CalibratedRGB-DSalientObjectDetectionWeiJi,JingjingLi,ShuangYu,MiaoZhang,YongriPiao,ShunyuYao,QiBi,KaiMa,YefengZheng,HuchuanLu,LiCheng;ProceedingsoftheIEEE/CVFConferenceonComputerVisionandPatternRecogn......
  • P1110 [ZJOI2007] 报表统计 题解
    考察点:STL的熟练运用。记:\(l_i\)表示序列中不超过\(a_i\)的最大数,\(r_i\)表示序列中超过\(a_i\)的最小数。开一个vectorinsert[N]存储\(a_i\)后面插入的所有数字。首先,我们使用一个multisets1来存储相邻元素的差的绝对值,然后再开一个multisets2来存储当前出......
  • R语言逻辑回归、决策树、随机森林、神经网络预测患者心脏病数据混淆矩阵可视化
    全文链接:https://tecdat.cn/?p=33760原文出处:拓端数据部落公众号概述:众所周知,心脏疾病是目前全球最主要的死因。开发一个能够预测患者心脏疾病存在的计算系统将显著降低死亡率并大幅降低医疗保健成本。机器学习在全球许多领域中被广泛应用,尤其在医疗行业中越来越受欢迎。机器......
  • 数据统计埋点需求
    背景随着公司代码的迭代,有一些垃圾代码逻辑冗余在项目中,导致消耗了资源又不好维护。为了保险,需要在线上统计代码使用的频率,剔除无用代码。描述方法便可分为如下几种:对于确定没用的代码,可以先注释掉,并替换为error日志,保证遇到问题及时发现。对疑似无用代码,可以使用统计方法调......
  • 矩阵树定理
    记结论如果有一条\((i,j)\)的边无向图生成树计数设\(D\)为度数矩阵,\(A\)为邻接矩阵。那么令\(L=D-A\)。则生成树为\(L\)去掉任意一行一列的\(Det(L)\)。mat[i][i]++,mat[j][j]++,mat[i][j]--,mat[j][i]--有向图外向树计数设\(D\)为入度矩阵,\(A\)为邻接矩......
  • 矩阵乘法与矩阵快速幂
    矩阵乘法与矩阵快速幂1矩阵乘法1.1定义对于两个矩阵$A,B$,其中$A$大小为$n\timesm$,$B$大小为$m\timesp$,则这两个矩阵可以做乘法,得到的矩阵$C$的大小为$n\timesp$。例如:$$A=\begin{bmatrix}a_{11}&a_{12}&a_{13}\a_{21}&a_{22}&a_{23}\end{bmatrix}......
  • Python|statistics 数学统计函数模块
    方法描述statistics.harmonic_mean()计算给定数据集的调和平均值。是总体内各个变量值倒数1/x的算术平均数的倒数。statistics.mean()计算数据集的平均值statistics.median()计算数据集的中位数statistics.median_grouped()计算给定分组数据集的分组中位数......
  • LoRA 微调和低秩矩阵
    LoRA(Low-RankAdaptation)是一种技术,旨在有效调整大型语言模型,以适应特定任务,而无需重新训练整个模型。在论文《LORA:LOW-RANKADAPTATIONOFLARGELANGUAGEMODELS》(https://arxiv.org/abs/2106.09685)中给出了具体方法:通过对模型中的参数进行低秩更新,来实现对大型预训练语言模......
  • 什么是转换矩阵以及如何使用它
    项目地址:Pdfium.Net:https://github.com/1000374/Pdfium.NetPdfiumViewer:https://github.com/1000374/PdfiumViewer当您使用PDFium库处理PDF文件中的对象时,您可以使用SetMatrix函数以各种方式转换对象(通常是图像,但也包括任何其他嵌入对象)。使用变换矩阵,您可以旋转、平移(移......
  • 迅速的长矩阵乘法
    这个算法被RyanWilliams挖坟挖出来,然后大家反复使用.但是感觉Ryan本人写的有点难读...在这里试图按照我的理解解释一下.令\(T\)是计算如下"打洞"的矩阵乘法的张量:\[\begin{pmatrix}a_{11}&a_{12}&a_{13}\\&a_{22}&a_{23}\end{pmatrix}\begin{pmatrix}......