【蓝桥杯】第十四届省赛真题-子矩阵-Java-详细解

4 篇文章 0 订阅
3 篇文章 0 订阅

终于做出来了!
原题链接:蓝桥杯2023年第十四届省赛真题-子矩阵
解题思路:

吃水不忘挖井人:

参考了大佬Python的思路: Python版本

大佬有数据是错误的, 我已经在评论区指出了, 思路上没有问题

为什么没有用 Scanner?
在输入输出上参考了: 关于输入与输出的占用理解

Java没必要死磕求模算法, 无脑使用 bigInteger就对啦!

我的注释写的很详细, 应该能看懂!

参考代码:

import java.math.BigInteger;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.StringTokenizer;

/*题目描述:
给定一个 n × m (n 行 m 列)的矩阵。
设一个矩阵的价值为其所有数中的最大值和最小值的乘积。
求给定矩阵的所有大小为 a × b (a 行 b 列)的子矩阵的价值的和。
答案可能很大,你只需要输出答案对 998244353 取模后的结果。

输入格式:
输入的第一行包含四个整数分别表示 n, m, a, b ,相邻整数之间使用一个空格分隔。
接下来 n 行每行包含 m 个整数,相邻整数之间使用一个空格分隔,表示矩阵中的每个数 Ai, j 。
输出格式
输出一行包含一个整数表示答案。

样例输入:
2 3 1 2
1 2 3
4 5 6

样例输出:
58

提示
1×2+2×3+4×5+5×6 = 58 。
*/
public class ChildrenMatrix {
	static BigInteger N = new BigInteger("998244353");
	static int n, m, a, b;
	static int matrix[][];
	static int colMaxMatrix[][];
	static int colMinMatrix[][]; // 每个值为 一行b列 矩阵中的最小值
	
	static int rowNum;
	static int colNum;

	static int childMaxMatrix[][]; // 每个值为 一个 a行b列矩阵中的最大值
	static int childMinMatrix[][]; // 每个值为 一个 a行b列矩阵中的最小值

	static BigInteger sum = new BigInteger("0");
	static int max;
	static int min;

	// 输入流
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	// 分割输入流
	static StreamTokenizer st = new StreamTokenizer(br);
	// 输出流
	static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));

	static int nextInt() throws Exception {
		st.nextToken(); // 开始遍历输入流中的数据, 默认标记中 数据为0与null, 以" "或者"\n"为分隔符查找到下一个标记, 然后返回之前的数值
		// nval:
		// 如果当前标记是一个数值,则nval属性将存储该数值的值。如果当前标记不是一个数值,或者如果没有下一个标记可用,则nval将被设置为Double.NaN。
		// sval:
		// 如果当前标记是一个字符串,则sval属性将存储该字符串的值。如果当前标记不是一个字符串,或者如果当前标记不是一个普通标记,则sval将为null。
		return (int) st.nval;
	}

	public static void main(String[] args) throws Exception {
		// 1. 接收尺寸输入
		n = nextInt();
		m = nextInt();
		a = nextInt();
		b = nextInt();

		// 2. 接收矩阵数据输入
		matrix = new int[n][m];
		InputMatrix();

		// 3. 核心: 
		GetColMatrix();
		GetChildMatrix();
		GetSum();
		
		pw.println(sum.mod(N));
		pw.flush(); // 刷新输出流,确保内容被输出到控制台
	}

	private static void InputMatrix() throws Exception {
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < m; ++j) {
				matrix[i][j] = nextInt();
			}
		}

	}

	// 先求每行b列, 得到对应的最大最小
	// 例如: n = m = 5, a = b = 3
	/*
		3 5 1 6 1
		1 2 4 7 6
		9 4 8 4 6
		1 3 7 1 3
		4 5 8 9 2
	*/
	
	// 第一行为: 3 5 1 6 1. 滑块宽度为3
	// 3 5 1 中最大为5, 最小为1
	// colMaxMatrix[1][0]: 5
	// 滑块移动: 5 1 6, 最大为6
	// colMaxMatrix[1][1]: 6
	// 滑块移动: 1 6 1, 最大为6
	// colMaxMatrix[1][2]: 6
	// 滑块无法移动, colMaxMatrix 第一行结束
	
	// 换句话说, colMaxMatrix 每一行与 原 Matrix 一一对应, 列为 每b列的浓缩
	private static void GetColMatrix() {
		// 初始化最大与最小矩阵
		colMaxMatrix = new int[n][m];
		colMinMatrix = new int[n][m];
		
		// 由于是压缩列数, 因此行的数量没有发生改变
		for (int i = 0; i < n; ++i) {
			int col = 0; //  
			for (int j = 0; j + b - 1 < m; ++j) {
				// 每个滑块的最大值与最小值的默认都是第一个
				max = matrix[i][j];
				min = matrix[i][j];
				
				// 在滑块内寻找最大与最小值
				for (int z = j; z < j + b; ++z) {
					if (max < matrix[i][z]) {
						max = matrix[i][z];
					}
					if (min > matrix[i][z]) {
						min = matrix[i][z];
					}
				}

				// 填入最大值与最小值
				colMaxMatrix[i][col] = max;
				colMinMatrix[i][col] = min;
				col++;		
			}
			colNum = col; // 确定新矩阵的有效列数
		}
	}

	// 再结合行数, 方法与之前相同, 只是压缩的方向变为了行, 而不是列, 以此得到的矩阵的对应值 就是 每个a*b矩阵的最大值
	// 例如: 得到的新矩阵: childMaxMatrix[0][0]对应值: 原矩阵中的 MaxMatrix[0-(a-1)][0-(b-1)]中的最大值
	private static void GetChildMatrix() {
		childMaxMatrix = new int[n][m];
		childMinMatrix = new int[n][m];
		// 这次是结合 行数, 因此是从列数开始遍历
		for (int j = 0; j < colNum; ++j) {
			int row = 0;
			for (int i = 0; i + a - 1 < n; ++i) {
				// 填入最大值与最小值记得回归默认值
				max = colMaxMatrix[i][j];
				min = colMinMatrix[i][j];
				for(int z = i; z < i+a; ++z) {
					if (max < colMaxMatrix[z][j]) {
						max = colMaxMatrix[z][j];
					}
					if (min > colMinMatrix[z][j]) {
						min = colMinMatrix[z][j];
					}
				}
				
				// 填入最大值与最小值
				childMaxMatrix[row][j] = max;
				childMinMatrix[row][j] = min;
				row++;
			}
			rowNum = row;
		}
	}

	// 最大与最小一一对应相乘, 相乘最开始越阈了, 使用 BigInteger解决问题
	private static void GetSum() {
		for(int i = 0; i< rowNum; ++i)
		{
			for(int j = 0; j<colNum; ++j)
			{
				BigInteger num1 = new BigInteger(String.valueOf(childMaxMatrix[i][j]));
				BigInteger num2 = new BigInteger(String.valueOf(childMinMatrix[i][j]));
				sum = sum.add(num1.multiply(num2));	
			}
		}
	}
}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值