2026华为OD机试真题 新系统 9月27日【坚果巧克力】

坚果巧克力(Java/Py/C/C++/Js/Go)题解

华为OD机试真题 新系统 华为OD上机考试真题新系统 9月27号 200分题型

华为OD机试新系统真题目录点击查看: 华为OD机试新系统真题题库目录|机考题库 + 算法考点详解

题目内容

有一块 n × m n \times m n×m( 4 ≤ n , m ≤ 50 4 \leq n, m \leq 50 4≤n,m≤50)的矩形巧克力,每个格子有一个正整数权值(权值 ≤ 1000 \leq 1000 ≤1000),代表这一格的坚果数量。

必须沿着格子横切恰好 3 3 3 刀、竖切恰好 3 3 3 刀,将巧克力分成 4 × 4 = 16 4 \times 4 = 16 4×4=16 块,分给 16 16 16 个人。

切分难以保证每个人分到的一样多,因此你想照顾那个分得最少的人 ,请通过合理安排切分方式,使这个"分得最少的人"分到的坚果数量在所有切分方式中最多(即:求一种划分方式,最大化这 16 16 16 块中权值和最小的那一块的权值和,请输出这个最大化的最小权值和。)

输入描述

输入包含一行,格式为 n,m,[[a11,a12,...,a1m],[a21,...,a2m],...,[an1,...,anm]],其中 n n n 为行数, m m m 为列数,后续为 n n n 行 m m m 列的矩阵,表示每个格子的权值。

输出描述

输出一个整数,表示在最优切分方案下, 16 16 16 块巧克力中权值和最小的那一块所能达到的最大权值和。

样例1

输入

复制代码
4 7
2 1 1 1 2 1 1
2 2 2 2 2 2 2
1 2 3 4 5 6 7
7 6 5 4 3 2 1

输出

复制代码
2

说明

  • 只有四行,只能每行都分开
  • 第一行最紧张, 7 7 7 格子分 4 4 4 块,一定会有一块只能分到 1 1 1 格,选择第一列的 2 2 2 分得 1 1 1 格,会导致第三行第一列的和只有 1 1 1,因此想要获得超过 1 1 1 的结果只能选择第 5 5 5 列前后进行划分
  • 在这个基础上,一种可行的划分方式是:
  • 第 1 1 1 行:2,1|1,1|2|1,1
  • 第 2 2 2 行:2,2|2,2|2|2,2
  • 第 3 3 3 行:1,2|3,4|5|6,7
  • 第 4 4 4 行:7,6|5,4|3|2,1
  • 此时第 1 1 1 行的 |1,1|、|2|、|1,1| 三块为最小,但是都有 2 2 2 的权值和

样例2

输入

复制代码
5 6
1 1 1 5 5 5
1 1 1 1 1 1
6 6 6 6 6 6
6 6 6 6 6 6
6 6 6 6 6 6

输出

复制代码
6

说明

  • 一种可行的划分是:
  • 第 1 1 1 行:1,1,1|5|5|5
  • 第 2 2 2 行:1,1,1|1|1|1
  • 第 3 3 3 行:6,6,6|6|6|6
  • 第 4 4 4 行:6,6,6|6|6|6
  • 第 5 5 5 行:6,6,6|6|6|6
  • 这种划分保障了在正确划分的基础上左上角至少获得了 6 6 6 的权值

解题思路

思路:二分 + 贪心 + 前缀和

  1. 题目要求最大化这16块中权值和最小的那一块的权值和, 如果x可以,那么答案至少为x,如果不可以答案一定小于x,所以具备单调性,可以进行二分。
  2. 通过二分枚举确定每个块最小权值和,下界left = 0, 上界设置right = sum(grid) / 16, 每次枚举x = (left + right + 1)/ 2, 然后判断是否能满足16块每块和都不小于x
    • 满足分配的情况下更新left = x
    • 不满足分配更新right = x - 1
  3. 检验是否满足枚举x,采用枚举 + 贪心
    1. 通过枚举确定行切的三刀位置,确定行分块布局,
    2. 然后贪心分配列,当前检查四块的和都大于等于x时,就可以确定列切一到的位置。最终判断是否可以满足列切三刀,对应16块是否都大于等于x
    3. 不同行切位置枚举只有存在一种合法情况,就返回true,否则返回false。

C++

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

int solve(int n, int m, vector<vector<int>>& grid) {
    // 让枚举三刀的方向尽可能小
    vector<vector<int>> g = grid;

    if (n > m) {
        vector<vector<int>> t(m, vector<int>(n));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                t[j][i] = g[i][j];
            }
        }
        g.swap(t);
        swap(n, m);
    }

    // 此时 n <= m
    // pref[i][j]:第 j 列前 i 行的和
    vector<vector<long long>> pref(n + 1, vector<long long>(m, 0));
    long long total = 0;

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            pref[i + 1][j] = pref[i][j] + g[i][j];
            total += g[i][j];
        }
    }

    auto can = [&](long long mid) -> bool {
        if (mid <= 0) return true;

        // 16 个区域都至少为 mid,则总和至少为 16 * mid
        if (total < 16LL * mid) return false;

        // 枚举 3 条横刀
        for (int a = 1; a <= n - 3; a++) {
            for (int b = a + 1; b <= n - 2; b++) {
                for (int c = b + 1; c <= n - 1; c++) {
                    int j = 0;
                    bool ok = true;

                    // 贪心寻找前 3 个竖向区域
                    for (int gg = 0; gg < 3; gg++) {
                        if (j >= m) {
                            ok = false;
                            break;
                        }

                        long long s0 = 0;
                        long long s1 = 0;
                        long long s2 = 0;
                        long long s3 = 0;

                        // 当前竖向区域只要有一个横向块没有达到 mid
                        // 就继续增加列
                        while (j < m &&
                               (s0 < mid || s1 < mid ||
                                s2 < mid || s3 < mid)) {

                            // 第 1 个横向区域:0 ~ a-1
                            s0 += pref[a][j] - pref[0][j];

                            // 第 2 个横向区域:a ~ b-1
                            s1 += pref[b][j] - pref[a][j];

                            // 第 3 个横向区域:b ~ c-1
                            s2 += pref[c][j] - pref[b][j];

                            // 第 4 个横向区域:c ~ n-1
                            s3 += pref[n][j] - pref[c][j];

                            j++;
                        }

                        // 当前竖向区域无法让 4 个块全部达到 mid
                        if (s0 < mid || s1 < mid ||
                            s2 < mid || s3 < mid) {
                            ok = false;
                            break;
                        }
                    }

                    // 前 3 个竖向区域已经完成
                    // 剩余所有列组成第 4 个竖向区域
                    if (!ok || j >= m) continue;

                    long long s0 = 0;
                    long long s1 = 0;
                    long long s2 = 0;
                    long long s3 = 0;

                    while (j < m) {
                        s0 += pref[a][j] - pref[0][j];
                        s1 += pref[b][j] - pref[a][j];
                        s2 += pref[c][j] - pref[b][j];
                        s3 += pref[n][j] - pref[c][j];

                        j++;
                    }

                    // 4 个横向区域在最后一个竖向区域中
                    // 都达到 mid
                    if (s0 >= mid && s1 >= mid &&
                        s2 >= mid && s3 >= mid) {
                        return true;
                    }
                }
            }
        }

        return false;
    };

    // 最小块的值不可能超过平均值
    long long lo = 0;
    long long hi = total / 16;
    long long ans = 0;

    while (lo <= hi) {
        long long mid = lo + (hi - lo) / 2;

        if (can(mid)) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }

    return (int)ans;
}

int main() {
    int n, m;
    cin >> n >> m;

    vector<vector<int>> grid(n, vector<int>(m));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> grid[i][j];
        }
    }

    cout << solve(n, m, grid);
    return 0;
}

JAVA

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

public class Main {
    static int solve(int n, int m, int[][] grid) {
        // 让枚举三刀的方向尽可能小
        int[][] g = grid;

        if (n > m) {
            int[][] t = new int[m][n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    t[j][i] = g[i][j];
                }
            }
            g = t;

            int tmp = n;
            n = m;
            m = tmp;
        }

        // 此时 n <= m
        // pref[i][j]:第 j 列前 i 行的和
        long[][] pref = new long[n + 1][m];
        long total = 0;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                pref[i + 1][j] = pref[i][j] + g[i][j];
                total += g[i][j];
            }
        }

        long lo = 0;
        long hi = total / 16;
        long ans = 0;

        while (lo <= hi) {
            long mid = lo + (hi - lo) / 2;
            boolean ok = false;

            if (mid <= 0) {
                ok = true;
            } else if (total >= 16L * mid) {
                // 枚举 3 条横刀
                for (int a = 1; a <= n - 3 && !ok; a++) {
                    for (int b = a + 1; b <= n - 2 && !ok; b++) {
                        for (int c = b + 1; c <= n - 1 && !ok; c++) {
                            int j = 0;
                            boolean valid = true;

                            // 贪心寻找前 3 个竖向区域
                            for (int gg = 0; gg < 3; gg++) {
                                if (j >= m) {
                                    valid = false;
                                    break;
                                }

                                long s0 = 0;
                                long s1 = 0;
                                long s2 = 0;
                                long s3 = 0;

                                // 当前竖向区域只要有一个横向块没有达到 mid
                                // 就继续增加列
                                while (j < m &&
                                        (s0 < mid || s1 < mid ||
                                        s2 < mid || s3 < mid)) {

                                    // 第 1 个横向区域:0 ~ a-1
                                    s0 += pref[a][j] - pref[0][j];

                                    // 第 2 个横向区域:a ~ b-1
                                    s1 += pref[b][j] - pref[a][j];

                                    // 第 3 个横向区域:b ~ c-1
                                    s2 += pref[c][j] - pref[b][j];

                                    // 第 4 个横向区域:c ~ n-1
                                    s3 += pref[n][j] - pref[c][j];

                                    j++;
                                }

                                // 当前竖向区域无法让 4 个块全部达到 mid
                                if (s0 < mid || s1 < mid ||
                                        s2 < mid || s3 < mid) {
                                    valid = false;
                                    break;
                                }
                            }

                            // 前 3 个竖向区域已经完成
                            // 剩余所有列组成第 4 个竖向区域
                            if (!valid || j >= m) {
                                continue;
                            }

                            long s0 = 0;
                            long s1 = 0;
                            long s2 = 0;
                            long s3 = 0;

                            while (j < m) {
                                s0 += pref[a][j] - pref[0][j];
                                s1 += pref[b][j] - pref[a][j];
                                s2 += pref[c][j] - pref[b][j];
                                s3 += pref[n][j] - pref[c][j];

                                j++;
                            }

                            // 4 个横向区域在最后一个竖向区域中
                            // 都达到 mid
                            if (s0 >= mid && s1 >= mid &&
                                    s2 >= mid && s3 >= mid) {
                                ok = true;
                            }
                        }
                    }
                }
            }

            if (ok) {
                ans = mid;
                lo = mid + 1;
            } else {
                hi = mid - 1;
            }
        }

        return (int) ans;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        int m = sc.nextInt();

        int[][] grid = new int[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = sc.nextInt();
            }
        }

        System.out.print(solve(n, m, grid));
    }
}

Python

python 复制代码
import sys


def solve(n, m, grid):
    # 让枚举三刀的方向尽可能小
    g = grid

    if n > m:
        t = [[0] * n for _ in range(m)]
        for i in range(n):
            for j in range(m):
                t[j][i] = g[i][j]
        g = t
        n, m = m, n

    # 此时 n <= m
    # pref[i][j]:第 j 列前 i 行的和
    pref = [[0] * m for _ in range(n + 1)]
    total = 0

    for i in range(n):
        for j in range(m):
            pref[i + 1][j] = pref[i][j] + g[i][j]
            total += g[i][j]

    def can(mid):
        if mid <= 0:
            return True

        # 16 个区域都至少为 mid,则总和至少为 16 * mid
        if total < 16 * mid:
            return False

        # 枚举 3 条横刀
        for a in range(1, n - 2):
            for b in range(a + 1, n - 1):
                for c in range(b + 1, n):
                    j = 0
                    ok = True

                    # 贪心寻找前 3 个竖向区域
                    for gg in range(3):
                        if j >= m:
                            ok = False
                            break

                        s0 = 0
                        s1 = 0
                        s2 = 0
                        s3 = 0

                        # 当前竖向区域只要有一个横向块没有达到 mid
                        # 就继续增加列
                        while j < m and (s0 < mid or s1 < mid or
                                         s2 < mid or s3 < mid):

                            # 第 1 个横向区域:0 ~ a-1
                            s0 += pref[a][j] - pref[0][j]

                            # 第 2 个横向区域:a ~ b-1
                            s1 += pref[b][j] - pref[a][j]

                            # 第 3 个横向区域:b ~ c-1
                            s2 += pref[c][j] - pref[b][j]

                            # 第 4 个横向区域:c ~ n-1
                            s3 += pref[n][j] - pref[c][j]

                            j += 1

                        # 当前竖向区域无法让 4 个块全部达到 mid
                        if s0 < mid or s1 < mid or s2 < mid or s3 < mid:
                            ok = False
                            break

                    # 前 3 个竖向区域已经完成
                    # 剩余所有列组成第 4 个竖向区域
                    if not ok or j >= m:
                        continue

                    s0 = 0
                    s1 = 0
                    s2 = 0
                    s3 = 0

                    while j < m:
                        s0 += pref[a][j] - pref[0][j]
                        s1 += pref[b][j] - pref[a][j]
                        s2 += pref[c][j] - pref[b][j]
                        s3 += pref[n][j] - pref[c][j]

                        j += 1

                    # 4 个横向区域在最后一个竖向区域中
                    # 都达到 mid
                    if s0 >= mid and s1 >= mid and s2 >= mid and s3 >= mid:
                        return True

        return False

    # 最小块的值不可能超过平均值
    lo = 0
    hi = total // 16
    ans = 0

    while lo <= hi:
        mid = lo + (hi - lo) // 2

        if can(mid):
            ans = mid
            lo = mid + 1
        else:
            hi = mid - 1

    return int(ans)


def main():
    data = list(map(int, sys.stdin.buffer.read().split()))
    idx = 0

    n = data[idx]
    m = data[idx + 1]
    idx += 2

    grid = []
    for _ in range(n):
        grid.append(data[idx:idx + m])
        idx += m

    print(solve(n, m, grid))


if __name__ == "__main__":
    main()

JavaScript

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

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

const input = [];

rl.on('line', line => {
    input.push(...line.trim().split(/\s+/).filter(Boolean).map(Number));
});

rl.on('close', () => {
    let idx = 0;

    const n0 = input[idx++];
    const m0 = input[idx++];

    const grid = Array.from({ length: n0 }, () => {
        const row = [];
        for (let j = 0; j < m0; j++) {
            row.push(input[idx++]);
        }
        return row;
    });

    console.log(solve(n0, m0, grid));
});


function solve(n, m, grid) {
    // 让枚举三刀的方向尽可能小
    let g = grid;

    if (n > m) {
        const t = Array.from({ length: m }, () => Array(n).fill(0));

        for (let i = 0; i < n; i++) {
            for (let j = 0; j < m; j++) {
                t[j][i] = g[i][j];
            }
        }

        g = t;
        [n, m] = [m, n];
    }

    // 此时 n <= m
    // pref[i][j]:第 j 列前 i 行的和
    const pref = Array.from({ length: n + 1 }, () => Array(m).fill(0));
    let total = 0;

    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {
            pref[i + 1][j] = pref[i][j] + g[i][j];
            total += g[i][j];
        }
    }

    function can(mid) {
        if (mid <= 0) return true;

        // 16 个区域都至少为 mid,则总和至少为 16 * mid
        if (total < 16 * mid) return false;

        // 枚举 3 条横刀
        for (let a = 1; a <= n - 3; a++) {
            for (let b = a + 1; b <= n - 2; b++) {
                for (let c = b + 1; c <= n - 1; c++) {
                    let j = 0;
                    let ok = true;

                    // 贪心寻找前 3 个竖向区域
                    for (let gg = 0; gg < 3; gg++) {
                        if (j >= m) {
                            ok = false;
                            break;
                        }

                        let s0 = 0;
                        let s1 = 0;
                        let s2 = 0;
                        let s3 = 0;

                        // 当前竖向区域只要有一个横向块没有达到 mid
                        // 就继续增加列
                        while (j < m &&
                            (s0 < mid || s1 < mid ||
                             s2 < mid || s3 < mid)) {

                            // 第 1 个横向区域:0 ~ a-1
                            s0 += pref[a][j] - pref[0][j];

                            // 第 2 个横向区域:a ~ b-1
                            s1 += pref[b][j] - pref[a][j];

                            // 第 3 个横向区域:b ~ c-1
                            s2 += pref[c][j] - pref[b][j];

                            // 第 4 个横向区域:c ~ n-1
                            s3 += pref[n][j] - pref[c][j];

                            j++;
                        }

                        // 当前竖向区域无法让 4 个块全部达到 mid
                        if (s0 < mid || s1 < mid ||
                            s2 < mid || s3 < mid) {
                            ok = false;
                            break;
                        }
                    }

                    // 前 3 个竖向区域已经完成
                    // 剩余所有列组成第 4 个竖向区域
                    if (!ok || j >= m) continue;

                    let s0 = 0;
                    let s1 = 0;
                    let s2 = 0;
                    let s3 = 0;

                    while (j < m) {
                        s0 += pref[a][j] - pref[0][j];
                        s1 += pref[b][j] - pref[a][j];
                        s2 += pref[c][j] - pref[b][j];
                        s3 += pref[n][j] - pref[c][j];

                        j++;
                    }

                    // 4 个横向区域在最后一个竖向区域中
                    // 都达到 mid
                    if (s0 >= mid && s1 >= mid &&
                        s2 >= mid && s3 >= mid) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    // 最小块的值不可能超过平均值
    let lo = 0;
    let hi = Math.floor(total / 16);
    let ans = 0;

    while (lo <= hi) {
        const mid = lo + Math.floor((hi - lo) / 2);

        if (can(mid)) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }

    return ans;
}

Go

go 复制代码
package main

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

func solve(n int, m int, grid [][]int) int {
	// 让枚举三刀的方向尽可能小
	g := grid

	if n > m {
		t := make([][]int, m)
		for i := 0; i < m; i++ {
			t[i] = make([]int, n)
		}

		for i := 0; i < n; i++ {
			for j := 0; j < m; j++ {
				t[j][i] = g[i][j]
			}
		}

		g = t
		n, m = m, n
	}

	// 此时 n <= m
	// pref[i][j]:第 j 列前 i 行的和
	pref := make([][]int64, n+1)
	for i := 0; i <= n; i++ {
		pref[i] = make([]int64, m)
	}

	var total int64

	for i := 0; i < n; i++ {
		for j := 0; j < m; j++ {
			pref[i+1][j] = pref[i][j] + int64(g[i][j])
			total += int64(g[i][j])
		}
	}

	can := func(mid int64) bool {
		if mid <= 0 {
			return true
		}

		// 16 个区域都至少为 mid,则总和至少为 16 * mid
		if total < 16*mid {
			return false
		}

		// 枚举 3 条横刀
		for a := 1; a <= n-3; a++ {
			for b := a + 1; b <= n-2; b++ {
				for c := b + 1; c <= n-1; c++ {
					j := 0
					ok := true

					// 贪心寻找前 3 个竖向区域
					for gg := 0; gg < 3; gg++ {
						if j >= m {
							ok = false
							break
						}

						var s0, s1, s2, s3 int64

						// 当前竖向区域只要有一个横向块没有达到 mid
						// 就继续增加列
						for j < m && (s0 < mid || s1 < mid ||
							s2 < mid || s3 < mid) {

							// 第 1 个横向区域:0 ~ a-1
							s0 += pref[a][j] - pref[0][j]

							// 第 2 个横向区域:a ~ b-1
							s1 += pref[b][j] - pref[a][j]

							// 第 3 个横向区域:b ~ c-1
							s2 += pref[c][j] - pref[b][j]

							// 第 4 个横向区域:c ~ n-1
							s3 += pref[n][j] - pref[c][j]

							j++
						}

						// 当前竖向区域无法让 4 个块全部达到 mid
						if s0 < mid || s1 < mid ||
							s2 < mid || s3 < mid {
							ok = false
							break
						}
					}

					// 前 3 个竖向区域已经完成
					// 剩余所有列组成第 4 个竖向区域
					if !ok || j >= m {
						continue
					}

					var s0, s1, s2, s3 int64

					while := true
					for j < m && while {
						s0 += pref[a][j] - pref[0][j]
						s1 += pref[b][j] - pref[a][j]
						s2 += pref[c][j] - pref[b][j]
						s3 += pref[n][j] - pref[c][j]
						j++
					}

					// 4 个横向区域在最后一个竖向区域中
					// 都达到 mid
					if s0 >= mid && s1 >= mid &&
						s2 >= mid && s3 >= mid {
						return true
					}
				}
			}
		}

		return false
	}

	// 最小块的值不可能超过平均值
	var lo int64 = 0
	hi := total / 16
	var ans int64 = 0

	for lo <= hi {
		mid := lo + (hi-lo)/2

		if can(mid) {
			ans = mid
			lo = mid + 1
		} else {
			hi = mid - 1
		}
	}

	return int(ans)
}

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

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

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

	fmt.Fprint(out, solve(n, m, grid))
}

C语言

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

long long min_ll(long long a, long long b) {
    return a < b ? a : b;
}

int solve(int n, int m, int grid[n][m]) {
    // 让枚举三刀的方向尽可能小
    int **g = (int **)malloc(n * sizeof(int *));
    for (int i = 0; i < n; i++) {
        g[i] = (int *)malloc(m * sizeof(int));
        for (int j = 0; j < m; j++) {
            g[i][j] = grid[i][j];
        }
    }

    if (n > m) {
        int **t = (int **)malloc(m * sizeof(int *));
        for (int i = 0; i < m; i++) {
            t[i] = (int *)malloc(n * sizeof(int));
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                t[j][i] = g[i][j];
            }
        }

        for (int i = 0; i < n; i++) {
            free(g[i]);
        }
        free(g);

        g = t;

        int tmp = n;
        n = m;
        m = tmp;
    }

    // 此时 n <= m
    // pref[i][j]:第 j 列前 i 行的和
    long long **pref = (long long **)malloc((n + 1) * sizeof(long long *));
    for (int i = 0; i <= n; i++) {
        pref[i] = (long long *)calloc(m, sizeof(long long));
    }

    long long total = 0;

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            pref[i + 1][j] = pref[i][j] + g[i][j];
            total += g[i][j];
        }
    }

    // 判断 mid 是否可行
    int can(long long mid) {
        if (mid <= 0) {
            return 1;
        }

        // 16 个区域都至少为 mid,则总和至少为 16 * mid
        if (total < 16LL * mid) {
            return 0;
        }

        // 枚举 3 条横刀
        for (int a = 1; a <= n - 3; a++) {
            for (int b = a + 1; b <= n - 2; b++) {
                for (int c = b + 1; c <= n - 1; c++) {
                    int j = 0;
                    int ok = 1;

                    // 贪心寻找前 3 个竖向区域
                    for (int gg = 0; gg < 3; gg++) {
                        if (j >= m) {
                            ok = 0;
                            break;
                        }

                        long long s0 = 0;
                        long long s1 = 0;
                        long long s2 = 0;
                        long long s3 = 0;

                        // 当前竖向区域只要有一个横向块没有达到 mid
                        // 就继续增加列
                        while (j < m &&
                               (s0 < mid || s1 < mid ||
                                s2 < mid || s3 < mid)) {

                            // 第 1 个横向区域:0 ~ a-1
                            s0 += pref[a][j] - pref[0][j];

                            // 第 2 个横向区域:a ~ b-1
                            s1 += pref[b][j] - pref[a][j];

                            // 第 3 个横向区域:b ~ c-1
                            s2 += pref[c][j] - pref[b][j];

                            // 第 4 个横向区域:c ~ n-1
                            s3 += pref[n][j] - pref[c][j];

                            j++;
                        }

                        // 当前竖向区域无法让 4 个块全部达到 mid
                        if (s0 < mid || s1 < mid ||
                            s2 < mid || s3 < mid) {
                            ok = 0;
                            break;
                        }
                    }

                    // 前 3 个竖向区域已经完成
                    // 剩余所有列组成第 4 个竖向区域
                    if (!ok || j >= m) {
                        continue;
                    }

                    long long s0 = 0;
                    long long s1 = 0;
                    long long s2 = 0;
                    long long s3 = 0;

                    while (j < m) {
                        s0 += pref[a][j] - pref[0][j];
                        s1 += pref[b][j] - pref[a][j];
                        s2 += pref[c][j] - pref[b][j];
                        s3 += pref[n][j] - pref[c][j];

                        j++;
                    }

                    // 4 个横向区域在最后一个竖向区域中
                    // 都达到 mid
                    if (s0 >= mid && s1 >= mid &&
                        s2 >= mid && s3 >= mid) {
                        return 1;
                    }
                }
            }
        }

        return 0;
    }

    // 最小块的值不可能超过平均值
    long long lo = 0;
    long long hi = total / 16;
    long long ans = 0;

    while (lo <= hi) {
        long long mid = lo + (hi - lo) / 2;

        if (can(mid)) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }

    for (int i = 0; i < n; i++) {
        free(g[i]);
    }
    free(g);

    for (int i = 0; i <= n; i++) {
        free(pref[i]);
    }
    free(pref);

    return (int)ans;
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);

    int (*grid)[m] = malloc(n * sizeof(*grid));

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &grid[i][j]);
        }
    }

    printf("%d", solve(n, m, grid));

    free(grid);

    return 0;
}

​

相关推荐
Zane19942 小时前
同样是遍历图,为什么BFS能保证找到最短路径,DFS却不行
算法
samforce2 小时前
叹息之墙——人类认知 AI,终将遇到的一堵同构之墙
人工智能·深度学习·算法·哲学·认知科学
l1t3 小时前
编译测试兼容gzip并行压缩解压工具pigz
c++·算法
代码不停3 小时前
BFS算法解决FloodFill问题
算法·bfs·宽度优先
纪念 2293 小时前
C++算法(一)
开发语言·c++·算法
All for pursuit.3 小时前
【二叉树-10】114.二叉树展开为链表
数据结构·c++·算法·leetcode·链表
叠层归一研究院3 小时前
区分预算与通道诱导:Ω–L叠层体系的观测赋值与定量验证
人工智能·算法
BYSJMG4 小时前
计算机毕业设计选题推荐:基于大数据的快递物流运营数据分析与可视化,Spark与K-Means
大数据·算法·数据分析·spark·课程设计
阳明山水4 小时前
因果一致性正则化实战解析
人工智能·深度学习·算法·机器学习·架构