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

统计子矩阵

时间:2023-10-20 10:11:18浏览次数:41  
标签:10 边界 int 样例 矩阵 整数 统计

统计子矩阵

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

输入格式

第一行包含三个整数 $N, M$ 和 $K$。

之后 $N$ 行每行包含 $M$ 个整数,代表矩阵 $A$。

输出格式

一个整数代表答案。

数据范围

对于 $30\%$ 的数据,$N, M ≤ 20$,
对于 $70\%$ 的数据,$N, M ≤ 100$,
对于 $100\%$ 的数据,$1 ≤ N, M ≤ 500; 0 ≤ A_{ij} ≤ 1000; 1 ≤ K ≤ 2.5 \times 10^8$。

输入样例:

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12

输出样例:

19

样例解释

满足条件的子矩阵一共有 $19$,包含:

  • 大小为 $1 × 1$ 的有 $10$ 个。
  • 大小为 $1 × 2$ 的有 $3$ 个。
  • 大小为 $1 × 3$ 的有 $2$ 个。
  • 大小为 $1 × 4$ 的有 $1$ 个。
  • 大小为 $2 × 1$ 的有 $3$ 个。

 

解题思路

  参考 [COCI2021-2022#6] Zemljište 中枚举子矩阵的方法,即枚举子矩阵的上边界、下边界、右边界,然后通过二分或双指针来确定左边界,这样时间复杂度就能做到 $O(n^3 \log{n})$ 或 $O(n^3)$。记录这两题主要想告诉自己,枚举子矩阵不要总是那么死板去想着枚举左上角和右下角两个坐标。

  下面给出双指针做法的正确性证明就可以了。首先矩阵中的元素均是非负整数,因此当确定了子矩阵的上边界 $x_1$,下边界 $x_2$,右边界 $y_2$ 后,随着 $y_1$ 增加(向右移动),那么构成的矩阵 $(x_1, y_1, x_2, y_2)$ 的和也会递减,因此满足单调性。假设此时左边界 $y_1$ 是满足构成矩阵和不超过 $k$ 的最靠左的位置,那么当 $y_2$ 向右移动到 $y_2'$,$y_1$ 只会向右移动。否则假设 $y_1$ 向左移动到 $y_1'$,由于矩阵 $(x_1, y_1', x_2, y_2')$ 的和不超过 $k$,因此矩阵 $(x_1, y_1', x_2, y_2)$ 的和也不超过 $k$,而 $y_1' < y_1$,这就与假设矛盾了。

  AC 代码如下,时间复杂度为 $O(n^3)$:

#include <bits/stdc++.h>
using namespace std;

const int N = 510;

typedef long long LL;

int s[N][N];

int main() {
    int n, m, k;
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            scanf("%d", &s[i][j]);
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
        }
    }
    LL ret = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = i; j <= n; j++) {
            for (int u = 1, v = 1; u <= m; u++) {
                while (v <= u && s[j][u] - s[i - 1][u] - s[j][v - 1] + s[i - 1][v - 1] > k) {
                    v++;
                }
                ret += u - v + 1;
            }
        }
    }
    printf("%lld", ret);
    
    return 0;
}

 

参考资料

  AcWing 4405. 统计子矩阵(秋招每日一题):https://www.acwing.com/video/4234/

标签:10,边界,int,样例,矩阵,整数,统计
From: https://www.cnblogs.com/onlyblues/p/17776389.html

相关文章

  • VS Code 统计代码行数
    安装插件VSCode可以通过安装VSCodeCounter插件来很方便的统计代码行数。使用Shift+Ctrl+X快捷键打开扩展界面,搜索VSCodeCounter并安装,如下使用插件统计代码点击顶部'查看>命令面板'菜单,如下:工作区选择VscodeCounter:Countlinesindirectory点击回车......
  • git 统计代码行数
    统计指定分支下的所有作者的代码数目gitlog--format='%aN'|sort-u|whilereadname;doecho-en"$name\t";gitlog--author="$name"--pretty=tformat:--numstat|awk'{add+=$1;subs+=$2;loc+=$1-$2}END{printf"adde......
  • 3D游戏开发中的数学知识矩阵详解
    矩阵很多同学没有接触过,所以感觉很难,很复杂,其实只要学过矩阵的同学都知道,矩阵运算并不难。今天我们给大家讲讲游戏开发中的矩阵的运算。1:矩阵是什么?矩阵是描述线性变换的一种数学工具,线性变换指的是使用一次函数从一个空间变换到另外一个空间。例如在空间A中的一个2维向量(xa......
  • 函数性能统计
    函数性能统计https://superfastpython.com/benchmark-python-code/#Benchmark_with_cProfile第五章详细阅读,能够列出每个函数的时间,以及函数中调用的函数的性能 profile模块使用参考Python性能分析工具Profile--零-博客园(cnblogs.com)函数支持保存日志参数cProfil......
  • 子矩阵的和(二维前缀和)
    一、算法描述上一篇文章介绍了一维前缀和,也就是一个数组的前n项和,这篇文章来介绍一下什么是二维前缀和。含义一维的是前n项的和,那么二维的情况下,表示的则是与左上角形成的矩形和。怎么求一维的递推关系式是s[i]=s[i-1]+a[i];,我们根据含义来思考二维的递推关系式,读......
  • 证明反对称矩阵的秩是偶数
    对反对称矩阵消元,如果有非零元素,不妨假设\(a_{1,2}\neq0\)。定义对\((i,j,k)\)使用操作1表示,第\(i\)行\(\timesk\)加到第\(j\)行然后第\(i\)列\(\timesk\)后加到第\(j\)列。注意到操作完仍是反对称矩阵。可以使用操作1把所有第一行第二行,第一列第二列除了......
  • 2023-10-18:用go语言,给定一个数组arr,长度为n,表示有0~n-1号设备, arr[i]表示i号设备的型
    2023-10-18:用go语言,给定一个数组arr,长度为n,表示有0~n-1号设备,arr[i]表示i号设备的型号,型号的种类从0~k-1,一共k种型号,给定一个k*k的矩阵map,来表示型号之间的兼容情况,map[a][b]==1,表示a型号兼容b型号,map[a][b]==0,表示a型号不兼容b型号,兼容关系是有向图,也就是a型号兼容b型号......
  • 小白学算法-什么是矩阵数据结构以及有哪些应用?
    什么是矩阵数据结构以及有哪些应用矩阵表示按行和列的顺序排列的数字的集合。必须将矩阵的元素括在圆括号或方括号中。例如:具有9个元素的矩阵如下所示。该矩阵M有3行和3列。矩阵M的每个元素都可以通过其行号和列号来引用。例如,M[2][3]=6。矩阵是由行和列组成的二维数组。......
  • 邻接矩阵
    邻接矩阵(AdjacencyMatrix)是表示顶点之间相邻关系的矩阵。  设一个图G=(V,E)逻辑结构分为两部分:V和E集合,其中,V是顶点,E是边。用一个一维数组存放图中所有顶点数据;用一个二维数组存放顶点间关系(边或弧)的数据,这个二维数组称为邻接矩阵。......
  • 矩阵求导笔记
    1.标量对矩阵的求导考虑一个标量函数\(f(A)\),其输入是一个\(m\timesn\)矩阵。函数关于矩阵的导数定义为:\[\frac{\partialf}{\partialA}=\begin{bmatrix}\frac{\partialf}{\partialA_{11}}&\cdots&\frac{\partialf}{\partialA_{1n}}\\\vdots&\d......