蓝桥杯-统计子矩阵(前缀和+双指针)

这篇具有很好参考价值的文章主要介绍了蓝桥杯-统计子矩阵(前缀和+双指针)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、问题描述

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

输入格式

  第一行包含三个整数 ,N,MK.

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

输出格式

  一个整数代表答案。

样例输入

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

样例输出

19

样例说明

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

  大小为 1×11×1 的有 10 个。

  大小为 1×21×2 的有 3 个。

  大小为 1×31×3 的有 2 个。

  大小为 1×41×4 的有 1 个。

  大小为 2×12×1 的有 3 个。

评测用例规模与约定

  对于 30% 的数据, N,M≤20.

  对于 70% 的数据, N,M≤100.

  对于 100% 的数据, 1≤N,M≤500;0≤ A i j A_{ij} Aij≤1000;1≤K≤250000000.

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

2、解题思路

2.1 思路一:二维前缀和(超时)

  看到这个矩阵求和的题目,我们要马上想到二维数组的前缀和。

  这里对二维数组前缀和做简单介绍,这些都是算法竞赛的必备知识了。

  求 s [ i , j ] s[i,j] s[i,j],看下图,

蓝桥杯-统计子矩阵(前缀和+双指针)

  假设此时的矩阵用二维数组a[][]表示,而前缀和用s[][]表示,那么前缀和用下面的式子表示:

s [ i ] [ j ] = s [ i ] [ j − 1 ] + s [ i − 1 ] [ j ] − s [ i − 1 ] [ j − 1 ] + a [ i ] [ j ] s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+a[i][j] s[i][j]=s[i][j1]+s[i1][j]s[i1][j1]+a[i][j]

  还有一种方式是给你左上角坐标和右下角坐标,让你求子矩阵的和,比如下图:

蓝桥杯-统计子矩阵(前缀和+双指针)

  求阴影部分的子矩阵和,可以用如下式子表示:

s [ x 1 ∼ x 2 ] [ y 1 ∼ y 2 ] = s [ x 2 ] [ y 2 ] − s [ x 2 ] [ y 1 − 1 ] − s [ x 1 − 1 ] [ y 2 ] + s [ x 1 − 1 ] [ y 1 − 1 ] s[x1\sim x2][y1 \sim y2]=s[x_2][y_2]-s[x_2][y_1-1]-s[x_1-1][y_2]+s[x_1-1][y_1-1] s[x1x2][y1y2]=s[x2][y2]s[x2][y11]s[x11][y2]+s[x11][y11]

  知道了上面这些基础知识,我们很容易的想到我们只需要枚举矩阵的左上角坐标和右下角的两个坐标就能计算出子矩阵的和了。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;

public class Main {
    public static int[][] a;
    public static int[][] s;
    public static long ans;
    public static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static void main(String[] args) throws IOException{
        int n = nextInt();
        int m = nextInt();
        int k = nextInt();
        a = new int[n+1][m+1];
        s = new int[n+1][m+1];  //二维数组前缀和
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                a[i][j]=nextInt();
                s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+a[i][j];    //计算前缀和
            }
        }
        for (int i = 1; i <=n; i++) {
            for (int j = 1; j <=m ; j++) {
                for (int l = i; l <=n; l++) {
                    for (int o = j; o <=m ; o++) {
                        if(matrixSum(i,j,l,o)<=k){
                            ans++;
                        }
                    }
                }
            }
        }
        System.out.println(ans);
    }
    public static int nextInt() throws IOException{
        st.nextToken();
        return (int)st.nval;
    }
    //求子矩阵的和
    public static long matrixSum(int x1,int y1,int x2,int y2){
        return s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];
    }

}

  经过测试,这种方法只能通过60%的数据。

  上面的代码中前两重循环确定左上角坐标,后两重循环确定右下角坐标,然后用我们计算前缀和的公式去算就行。

2.2 思路二:二维前缀和+双指针(AC)

  方案二同样需要使用前缀和来实现,不过我们需要优化。

  这里关于 x 1 x_1 x1 x 2 x_2 x2我们仍然使用暴力枚举的方式,我们用L表示 y 1 y_1 y1,R表示 y 2 y_2 y2,由于数组没有辅助,在R指针右移的过程中,L也一定会右移(否则求和会超出k的范围),这样我们将问题转化成了一个一维数组的子数组和 ≤ k \le k k的计数问题。

  这里通过枚举右边界来实现,此时矩阵左上角坐标为 ( x 1 , L ) (x_1,L) (x1,L),右下角坐标为 ( x 2 , R ) (x_2,R) (x2,R),如果求和结果大于K,那么L指针右移,统计当前R作为右边界的符合条件的数量为 R − L + 1 R-L+1 RL+1。(因为如果当前的L和R满足条件,那么L到R这一段区间都是满足条件的)。

蓝桥杯-统计子矩阵(前缀和+双指针)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
//二维前缀和+双指针
public class Final {
    public static int[][] a;
    public static int[][] s;
    public static long ans;
    public static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static void main(String[] args) throws IOException{
        int n = nextInt();
        int m = nextInt();
        int k = nextInt();
        a = new int[n+1][m+1];
        s = new int[n+1][m+1];  //二维数组前缀和
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                a[i][j]=nextInt();
                s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+a[i][j];    //计算前缀和
            }
        }
        //左上角坐标(x1,L),右下角坐标(x2,R)
        //枚举R为右边界
        for (int i = 1; i <=n; i++) {   //x1
            for (int j = i; j <=n ; j++) {//x2
                for (int l=1,r=1; r<=m; r++) {//L表示y1,R表示y2
                    while(l<=r&&matrixSum(i,l,j,r)>k){
                        l++;    //如果总和大于k,l右移
                    }
                    ans+=r-l+1; //统计当前R作为右边界的答案数量
                }
            }
        }
        System.out.println(ans);
    }
    public static int nextInt() throws IOException{
        st.nextToken();
        return (int)st.nval;
    }
    //求子矩阵的和
    public static long matrixSum(int x1,int y1,int x2,int y2){
        return s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];
    }

}

蓝桥杯-统计子矩阵(前缀和+双指针)文章来源地址https://www.toymoban.com/news/detail-452441.html

到了这里,关于蓝桥杯-统计子矩阵(前缀和+双指针)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

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

    给定一个 N times MN×M 的矩阵 AA,请你统计有多少个子矩阵 (最小 1 times 11×1, 最大 N times M)N×M) 满足子矩阵中所有数的和不超过给定的整数 KK。 第一行包含三个整数 N, MN,M 和 KK。 之后 NN 行每行包含 MM 个整数, 代表矩阵 AA。 一个整数代表答案。 输入 #1 复制 输出

    2023年04月09日
    浏览(35)
  • 【算法设计与分析】拉丁矩阵问题——对于给定的m和n,计算出不同的宝石排列方案数。

    问题描述   现有n种不同形状的宝石,每种宝石有足够多颗。欲将这些宝石排列成m行n列的一个矩阵,m≤n,使矩阵中每行和每列的宝石都没有相同的形状。试设计一个算法,计算出对于给定的m和n,有多少种不同的宝石排列方案。 数据输入   由文件input.txt给出输入数据。

    2024年02月04日
    浏览(40)
  • 【第 46 天】给定 q 个询问查询任意子数组的和 | 前缀和初体验

    本文已收录于专栏 🌸《Java入门一百练》🌸

    2023年04月10日
    浏览(41)
  • 给定N个正整数,请统计奇数和偶数各有多少个?

    输入格式: 输入第一行给出一个正整 N (≤1000);第2行给出 N 个非负整数,以空格分隔。 输出格式: 在一行中先后输出奇数的个数、偶数的个数。中间以1个空格分隔。 输入样例: 输出样例:   运行结果:    

    2024年02月06日
    浏览(41)
  • 「PAT乙级真题解析」Basic Level 1097 矩阵行平移 (问题分析+完整步骤+伪代码描述+提交通过代码)

    乙级的题目训练主要用来熟悉编程语言的语法和形成良好的编码习惯和编码规范。从小白开始逐步掌握用编程解决问题。 PAT (Basic Level) Practice 1097 矩阵行平移 题设给定了明确的步骤, 要求按照给定方式进行\\\"平移\\\"操作, 然后计算各行元素的和并输出。 \\\"计算各行元素之和\\\"以及

    2023年04月10日
    浏览(95)
  • 数理统计SPSS软件实验报告一--描述性统计

    实验报告内容: 1 、实验目的: 熟练掌握利用SPSS进行描述性统计分析的基本技能。 2 、实验要求: (1) 利用SPSS软件计算常用统计量(样本均值、中位数、众数、分位数;最大值、最小值、极差、总和、样本方差、样本标准差、变异系数;偏度系数、峰度系数等)的值; (2)

    2023年04月12日
    浏览(58)
  • 描述性统计图表——散点图

    适用范围:当估计两个变量之间存在相关关系时,用散点图进行确认,并观察和确定两者的关系强度。还可以用散点图分析坐标点的分布模式,如“风险机遇评估矩阵”。 即便自变量为连续性变量,仍然可以使用散点图。也就是说散点图通过散点的疏密程度和变化趋势表示二

    2024年02月01日
    浏览(89)
  • 【SAS应用统计分析】数据的描述性统计分析

    声明:本文知识参考内容来自网络,如有侵权请联系删除。本文还参照了B站up主庄7的课程内容【公开课】数据分析与SAS【15课】 目录 实验原理 描述性统计量 1.反映数据集中趋势的特征量 2.反映数据离散程度的特征量 3.反映数据分布形状的特征量 数据的图形描述 直方图 箱线

    2024年02月01日
    浏览(49)
  • c++--智能指针简单描述

    1.什么是智能指针 智能指针,指该指针用于确保程序不存在内存和资源泄漏且是异常安全的。 智能指针是你在堆栈上声明的类模板,并可通过使用指向某个堆分配的对象的原始指针进行初始化。 在初始化智能指针后,它将拥有原始的指针。 这意味着智能指针负责删除原始指

    2024年02月12日
    浏览(39)
  • 蓝桥杯刷题015——最少刷题数(二分法+前缀和)

    问题描述 小蓝老师教的编程课有  N 名学生 , 编号依次是 1…N  。 第 i 号学生这学期刷题的数量是 Ai​  。 对于每一名学生, 请你计算他 至少 还要再刷多少道题 , 才能使得 全班刷题比他多的学生数不超过刷题比他少的学生数。 输入格式 第一行包含一个正整数 N 。 第二

    2023年04月14日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包