美团研发岗 5月9号笔试真题 - 正整数矩阵

正整数矩阵(Py/Java/C++/Js/Go)题解

美团研发岗 0509笔试 第二题

题目内容

给定一个 n × mn \times mn × m 的正整数矩阵 AAA,其中第 iii 行第 jjj 列的元素为 Ai,jA_{i,j}Ai,j。

你可以进行若干次操作。每次操作选择两个不同的格子 (x1, y1)(x_1, y_1)(x1, y1) 与 (x2, y2)(x_2, y_2)(x2, y2),执行:

Ax1, y1 ← Ax1, y1 − 1A_{x_1, y_1} \leftarrow A_{x_1, y_1} - 1Ax1, y1 ← Ax1, y1 − 1, Ax2, y2←Ax2, y2+1\ A_{x_2, y_2} \leftarrow A_{x_2, y_2} + 1 Ax2, y2←Ax2, y2+1。

操作过程中矩阵元素必须始终为非负整数,且不允许出现负数。

你希望经过若干次操作后得到一个矩阵 BBB,使得它同时满足"上下对称"和"左右对称",即:

对所有 1 ≤ i ≤ n1 \leq i \leq n1 ≤ i ≤ n,1 ≤ j ≤ m1 \leq j \leq m1 ≤ j ≤ m,都有 Bi,j = Bn+1−i, jB_{i,j} = B_{n+1-i, j}Bi,j = Bn+1−i, j。

对所有 1 ≤ i ≤ n1 \leq i \leq n1 ≤ i ≤ n,1 ≤ j ≤ m1 \leq j \leq m1 ≤ j ≤ m,都有 Bi,j = Bi, m+1−jB_{i,j} = B_{i, m+1-j}Bi,j = Bi, m+1−j。

请你输出任意一个满足条件的矩阵 BBB;如果不存在,输出 −1-1−1。

输入描述

每个测试文件包含多组测试数据。第一行输入一个整数 T(1 ≤ T ≤ 105)T(1 \leq T \leq 10^5)T(1 ≤ T ≤ 105) 代表数据组数,每组测试数据描述如下:

第一行输入两个整数 n, m(1 ≤ n, m ≤ 2 × 105)n, m(1 \leq n, m \leq 2 \times 10^5)n, m(1 ≤ n, m ≤ 2 × 105)。

接下来输入 nnn 行,每行输入 mmm 个整数,第 iii 行第 jjj 列为 Aij (0≤Aij≤109)A_{ij} \ (0 \leq A_{ij} \leq 10^9)Aij (0≤Aij≤109),表示矩阵 AAA。

保证单个测试文件中所有测试数据的 n ⋅ mn \cdot mn ⋅ m 之和不超过 5 × 1055 \times 10^55 × 105。

输出描述

对于每组测试数据:

如果不存在满足条件的矩阵,输出一行 −1-1−1。

否则输出 nnn 行,每行输出 mmm 个非负整数,表示一个合法的矩阵 BBB。

样例1

输入

复制代码
3
2 2
1 2
3 4
1 3
1 5 10
2 2
1 1
1 2

输出

复制代码
-1
5 6 5
-1

题解

思路

逻辑分析

  1. 题目只允许任选两个格子 A[x1][y1]-- A[x2][y2]++操作,本质上是在矩阵内搬运单位价值,其实本质上只限制了最终生成矩阵元素总和不变。所以问题转变为是否存在一个同时上下对称、左右对称的非负整数矩阵 B,使得元素和等于 S
  2. 接下来进行分析n m情况进行讨论:
    1. n 和 m都为偶数情况下: 矩阵会被划分为4个区域,四个区域彼此不会重叠,可以假设每个区域总和为a, 四个区域的总和为4a, 所以要满足S可以划分为四个区域,必须满足s % 4 == 0
    2. n 和 m 区域 存在一奇一偶情况:相比n m 都为偶情况下,增加了中间行,中间行只会影响左右/上下一个方向,可以先考虑不考虑中间行情况,将矩阵划分为四个区域(总和为a),再额外考虑中间行,只会影响一个方向,设置中间行一半为b,所以矩阵总和为4a + 2b,要想满足这个条件S % 2 == 0
    3. n和m区域都为奇数情况:相比n m 一奇 一偶情况,增加中心对称点,可以假设对称点和为c,类似其实可以将和转换为4a + 2b + c, c可以为奇数和偶数,总会存在这样的矩阵。
  3. 按照2的规律可以快速判断出是否存在合法矩阵。可以容易得出 3 处理中心点之后就变为2,2中间边处理之后就变为1情况,为了使得构造简单我们只设置每个区域的边界点,可以只对以下位置设值,其它可以不考虑就行,对应处理
    1. 中间点,设置中心值,使得S总和变为偶数
    2. 中间边两个端点,设置两个端点,S变为4的倍数
    3. 对应四个区域的左上点、右上角、左下角、右下角。设置每个值为S/4

C++

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin >> T;
    while (T--) {
        int n, m;
        cin >> n  >> m;
        long  sum = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                long x;
                cin >> x;
                sum += x;
            }
        }
        
        // 判断是否有解
        bool ok = true;
        if (n % 2  == 0 && m % 2 == 0) {
            ok = (sum % 4) == 0;  
        // 一奇一偶
        }else if ((n % 2) != (m % 2)) {
            ok = (sum % 2 == 0);
        }
        if (!ok) {
            cout << "-1" << endl;
            continue;
        }
        
        // 构造结果
        vector<vector<long>> b(n, vector<long>(m, 0));
        long rem = sum;
        
        if ((n & 1) && (m & 1) && (rem & 1)) {
            b[n / 2][m / 2] = 1;
            rem--;
        }
        
        // 2元组(贡献2)
        if (rem % 4 == 2) {
            if (n & 1) {
                int r = n / 2;
                b[r][0] += 1;
                b[r][m-1] += 1;
                rem -= 2;
            } else {
                int c = m / 2;
                b[0][c] += 1;
                b[n-1][c] += 1;
                rem -= 2;
            }
        }
        
        // 剩下一定是4的倍数
        long v = rem / 4;
        b[0][0] += v;
        b[0][m-1] += v;
        b[n-1][0] += v;
        b[n-1][m-1] += v;
        
        // 输出结果
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (j > 0) {
                    cout << "  ";
                }
                cout << b[i][j];
            }
            cout << endl;
        }
        
    }
    return 0;
}

java

java 复制代码
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder out = new StringBuilder();

        int T = Integer.parseInt(br.readLine().trim());

        while (T-- > 0) {
            String[] parts = br.readLine().trim().split(" ");
            int n = Integer.parseInt(parts[0]);
            int m = Integer.parseInt(parts[1]);

            long sum = 0;

            for (int i = 0; i < n; i++) {
                String[] row = br.readLine().trim().split(" ");
                for (int j = 0; j < m; j++) {
                    long x = Long.parseLong(row[j]);
                    sum += x;
                }
            }

            // 判断是否有解
            boolean ok = true;
            if (n % 2 == 0 && m % 2 == 0) {
                ok = (sum % 4) == 0;
            } else if ((n % 2) != (m % 2)) {
                ok = (sum % 2 == 0);
            }

            if (!ok) {
                out.append("-1\n");
                continue;
            }

            // 构造结果
            long[][] b = new long[n][m];
            long rem = sum;

            if ((n % 2 == 1) && (m % 2 == 1) && (rem % 2 == 1)) {
                b[n / 2][m / 2] = 1;
                rem--;
            }

            // 2元组(贡献2)
            if (rem % 4 == 2) {
                if ((n & 1) == 1) {
                    int r = n / 2;
                    b[r][0] += 1;
                    b[r][m - 1] += 1;
                    rem -= 2;
                } else {
                    int c = m / 2;
                    b[0][c] += 1;
                    b[n - 1][c] += 1;
                    rem -= 2;
                }
            }

            // 剩下一定是4的倍数
            long v = rem / 4;
            b[0][0] += v;
            b[0][m - 1] += v;
            b[n - 1][0] += v;
            b[n - 1][m - 1] += v;

            // 输出结果
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    if (j > 0) out.append("  ");
                    out.append(b[i][j]);
                }
                out.append("\n");
            }
        }

        System.out.print(out.toString());
    }
}

python

python 复制代码
import sys

input = sys.stdin.readline

T = int(input())

for _ in range(T):
    n, m = map(int, input().split())

    total = 0
    for _ in range(n):
        row = list(map(int, input().split()))
        total += sum(row)

    # 判断是否有解
    ok = True
    if n % 2 == 0 and m % 2 == 0:
        ok = (total % 4 == 0)
    elif (n % 2) != (m % 2):
        ok = (total % 2 == 0)

    if not ok:
        print(-1)
        continue

    # 构造结果
    b = [[0] * m for _ in range(n)]
    rem = total

    if (n % 2 == 1) and (m % 2 == 1) and (rem % 2 == 1):
        b[n // 2][m // 2] = 1
        rem -= 1

    # 2元组(贡献2)
    if rem % 4 == 2:
        if n % 2 == 1:
            r = n // 2
            b[r][0] += 1
            b[r][m - 1] += 1
            rem -= 2
        else:
            c = m // 2
            b[0][c] += 1
            b[n - 1][c] += 1
            rem -= 2

    # 剩余4的倍数
    v = rem // 4
    b[0][0] += v
    b[0][m - 1] += v
    b[n - 1][0] += v
    b[n - 1][m - 1] += v

    for i in range(n):
        print("  ".join(map(str, b[i])))

javascript

js 复制代码
const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

let input = [];
rl.on("line", (line) => {
    input.push(line.trim());
});

rl.on("close", () => {
    let idx = 0;
    let T = Number(input[idx++]);

    while (T--) {
        let [n, m] = input[idx++].split(" ").map(Number);

        let sum = 0;

        for (let i = 0; i < n; i++) {
            let row = input[idx++].split(" ").map(Number);
            for (let j = 0; j < m; j++) {
                sum += row[j];
            }
        }

        // 判断是否有解
        let ok = true;
        if (n % 2 === 0 && m % 2 === 0) {
            ok = (sum % 4 === 0);
        } else if ((n % 2) !== (m % 2)) {
            ok = (sum % 2 === 0);
        }

        if (!ok) {
            console.log("-1");
            continue;
        }

        // 构造结果
        let b = Array.from({ length: n }, () => Array(m).fill(0));
        let rem = sum;

        if ((n % 2 === 1) && (m % 2 === 1) && (rem % 2 === 1)) {
            b[Math.floor(n / 2)][Math.floor(m / 2)] = 1;
            rem--;
        }

        // 2元组(贡献2)
        if (rem % 4 === 2) {
            if (n % 2 === 1) {
                let r = Math.floor(n / 2);
                b[r][0] += 1;
                b[r][m - 1] += 1;
                rem -= 2;
            } else {
                let c = Math.floor(m / 2);
                b[0][c] += 1;
                b[n - 1][c] += 1;
                rem -= 2;
            }
        }

        // 剩余4的倍数
        let v = Math.floor(rem / 4);
        b[0][0] += v;
        b[0][m - 1] += v;
        b[n - 1][0] += v;
        b[n - 1][m - 1] += v;

        for (let i = 0; i < n; i++) {
            console.log(b[i].join("  "));
        }
    }
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var T int
	fmt.Fscan(in, &T)

	for T > 0 {
		T--

		var n, m int
		fmt.Fscan(in, &n, &m)

		sum := int64(0)

		a := make([][]int64, n)
		for i := 0; i < n; i++ {
			a[i] = make([]int64, m)
			for j := 0; j < m; j++ {
				fmt.Fscan(in, &a[i][j])
				sum += a[i][j]
			}
		}

		// 判断是否有解
		ok := true
		if n%2 == 0 && m%2 == 0 {
			ok = (sum%4 == 0)
		} else if (n%2) != (m%2) {
			ok = (sum%2 == 0)
		}

		if !ok {
			fmt.Fprintln(out, -1)
			continue
		}

		// 构造结果
		b := make([][]int64, n)
		for i := range b {
			b[i] = make([]int64, m)
		}

		rem := sum

		if (n%2 == 1) && (m%2 == 1) && (rem%2 == 1) {
			b[n/2][m/2] = 1
			rem--
		}

		// 2元组(贡献2)
		if rem%4 == 2 {
			if n%2 == 1 {
				r := n / 2
				b[r][0]++
				b[r][m-1]++
				rem -= 2
			} else {
				c := m / 2
				b[0][c]++
				b[n-1][c]++
				rem -= 2
			}
		}

		// 剩余4的倍数
		v := rem / 4
		b[0][0] += v
		b[0][m-1] += v
		b[n-1][0] += v
		b[n-1][m-1] += v

		for i := 0; i < n; i++ {
			for j := 0; j < m; j++ {
				if j > 0 {
					fmt.Fprint(out, "  ")
				}
				fmt.Fprint(out, b[i][j])
			}
			fmt.Fprintln(out)
		}
	}
}
相关推荐
Smilecoc1 小时前
决策树(二):决策树的划分选择
算法·决策树·机器学习
hetao17338371 小时前
2026-05-25~06-11 hetao1733837 的刷题记录
c++·算法
cheems95271 小时前
[算法手记] 滑动窗口最大值
算法
洛水水1 小时前
【力扣100题】82.有效的括号
c++·算法·leetcode
XGeFei1 小时前
时序算法 —— LSTM、ARIMA、随机森林
算法·随机森林·lstm
湖南天硕国产SSD2 小时前
工业存储可靠性进阶:天硕工业固态硬盘动态温控与寿命优化技术实践
网络·数据库·算法·工业存储·天硕存储·工业固态硬盘
legend050709ComeON2 小时前
常见面试题-leetcode
数据结构·算法·leetcode
Smilecoc2 小时前
决策树(一):决策树基本原理
算法·决策树·机器学习
weixin_307779132 小时前
从工具到协作者:AI在后端研发中的流程重构与组织赋能
人工智能·后端·python·算法·自动化