子矩阵
子矩阵
题目描述
给定一个 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
解题思路
采用滑块方法进行计算,参考来源:蓝桥杯笔记-2023年第十四届省赛真题-子矩阵。
例如:下面说这个矩阵
| 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 |
要求其3X3的所有子矩阵的极值乘积和,先求一行b列(1*3)的子矩阵极值乘积和,求出两个列表:
最大值maxL
| 5 | 6 | 6 |
|---|---|---|
| 4 | 7 | 7 |
| 9 | 8 | 8 |
| 7 | 7 | 7 |
| 8 | 9 | 9 |
最小值minL
| 1 | 1 | 1 |
|---|---|---|
| 1 | 2 | 4 |
| 4 | 4 | 4 |
| 1 | 1 | 1 |
| 4 | 5 | 2 |
将矩阵旋转
最大值maxL
| 5 | 4 | 9 | 7 | 8 |
|---|---|---|---|---|
| 5 | 7 | 8 | 7 | 9 |
| 6 | 7 | 8 | 7 | 9 |
最小值minL
| 1 | 1 | 4 | 1 | 4 |
|---|---|---|---|---|
| 1 | 2 | 4 | 1 | 5 |
| 1 | 4 | 4 | 1 | 2 |
根据上面的方法,再次求每行的滑块的最大值和最小值
子矩阵最大值表
| 9 | 9 | 9 |
|---|---|---|
| 8 | 8 | 9 |
| 8 | 8 | 9 |
子矩阵最小值表
| 1 | 1 | 1 |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 1 | 1 |
最后,将两表一一相乘并求和,得到子矩阵的价值的和。
代码
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static final long MOD=998244353;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int a = scanner.nextInt();
int b = scanner.nextInt();
int[][] matrix = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
matrix[i][j] = scanner.nextInt();
}
}
long num=result(matrix,n,m,a,b);
System.out.println(num);
scanner.close();
}
//获得两个最大和最小的列表数组
public static long result(int[][] matrix,int n,int m,int a,int b) {
int col_num=m-b+1;
int row_num=n-a+1;
int[][] matrix_max_copy=new int[n][col_num];
int[][] matrix_min_copy=new int[n][col_num];
//找到最大值的表
for(int i=0;i<n;i++){
matrix_max_copy[i]=find_Max(matrix[i],b);
}
int[][] matrix_max= transpose(matrix_max_copy);
for(int i=0;i<col_num;i++){
matrix_max[i]=find_Max(matrix_max[i],a);
}
//找到最小值
for(int i=0;i<n;i++){
matrix_min_copy[i]=find_Min(matrix[i],b);
}
int[][] matrix_min=transpose(matrix_min_copy);
for(int i=0;i<col_num;i++){
matrix_min[i]=find_Min(matrix_min[i],a);
}
long sum=0,temp=0;
for(int i=0;i<col_num;i++){
for(int j=0;j<row_num;j++){
temp=(matrix_min[i][j]%MOD)*(matrix_max[i][j]%MOD)%MOD;
sum=(sum%MOD+temp)%MOD;
}
}
return sum;
}
//矩阵转置
public static int[][] transpose(int[][] matrix) {
if (matrix == null || matrix.length == 0) return new int[0][0];
int rows = matrix.length;
int cols = matrix[0].length;
int[][] result = new int[cols][rows];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
result[j][i] = matrix[i][j];
}
}
return result;
}
//返回滑动窗口的最小值列表,以数组的形式返回
public static int[] find_Min(int[] nums,int len) {
List<Integer> windows_Min = new ArrayList<>();
List<Integer> windows=new ArrayList<>();
for (int i = 0; i < nums.length; i++){
if(windows.size()<len){
windows.add(nums[i]);
if(windows.size()==len){
int min=Min_number(windows);
windows_Min.add(min);
}
}else{
//删除队列头元素
windows.remove(0);
windows.add(nums[i]);
int min=Min_number(windows);
windows_Min.add(min);
}
}
int[] res=new int[windows_Min.size()];
for(int i=0;i<windows_Min.size();i++){
res[i]=windows_Min.get(i);
}
return res;
}
//返回滑动窗口的最大值列表,以数组的形式返回
public static int[] find_Max(int[] nums,int len) {
List<Integer> windows_Max = new ArrayList<>();
List<Integer> windows=new ArrayList<>();
for (int i = 0; i < nums.length; i++){
if(windows.size()<len){
windows.add(nums[i]);
if(windows.size()==len){
int max=Max_number(windows);
windows_Max.add(max);
}
}else{
//删除队列头元素
windows.remove(0);
windows.add(nums[i]);
int max=Max_number(windows);
windows_Max.add(max);
}
}
int[] res=new int[windows_Max.size()];
for(int i=0;i<windows_Max.size();i++){
res[i]=windows_Max.get(i);
}
return res;
}
//寻找列表最大值
public static int Max_number(List<Integer> nums){
Integer Max=Integer.MIN_VALUE;
for (Integer num : nums) {
if (Max < num) Max = num;
}
return Max;
}
//寻找列表最小值
public static int Min_number(List<Integer> nums){
Integer Min=Integer.MAX_VALUE;
for (Integer num : nums) {
if (Min > num) Min = num;
}
return Min;
}
}

浙公网安备 33010602011771号