农田灌溉最大化作物产量问题解题笔记 | 豆包MarsCode AI刷题

134 阅读3分钟

前置知识

前缀和二维前缀和是常用的算法技巧,用于快速求解区间和问题,尤其在处理高频查询时表现出色。


前缀和(Prefix Sum)

前缀和是一种针对一维数组的技巧,主要用于高效求解数组中某个区间元素之和。核心思想是通过预处理,将每个位置的累积和保存起来,后续查询可以在常数时间内完成。

  • 构造过程: 构造前缀和数组时,第i个位置存储的是数组从开始到第i个元素的累加和。即:

    S[i]=A[0]+A[1]++A[i]S[i] = A[0] + A[1] + \dots + A[i]

    其中 S[i]S[i] 表示前缀和数组,AA 表示原始数组。

  • 求区间和: 对于区间 [l,r][l, r] 的和,只需用公式:

    sum(l,r)=S[r]S[l1]sum(l,r)=S[r]−S[l−1]

    l=0l=0 时,直接为 S[r]S[r]

  • 常用场景

    • 求多次区间和问题,例如统计成绩、数据分析。
    • 判断连续子数组是否满足特定条件,如最大子数组和问题。
    • 快速统计数组中满足条件的子数组个数。

二维前缀和(2D Prefix Sum)

二维前缀和是前缀和在二维数组中的扩展,用于快速求解矩阵中某个子矩形区域的元素之和。

  • 构造过程: 构造二维前缀和矩阵时,第(i, j)位置存储的是矩阵从左上角 (0,0) 到当前点 (i,j) 所有元素的和。即:

    S[i][j]=0xi,0yjA[x][y]S[i][j] = \sum_{0 \leq x \leq i, 0 \leq y \leq j} A[x][y]

    通过动态规划公式计算:

    S[i][j]=A[i][j]+S[i1][j]+S[i][j1]S[i1][j1]S[i][j] = A[i][j] + S[i-1][j] + S[i][j-1] - S[i-1][j-1]

    最后一项是因为左上区域被重复计算。

  • 求子矩形和: 对于矩形区域 (x1, y1) 到 (x2, y2),矩形和可以快速通过公式求得:

    sum(x1,y1,x2,y2)=S[x2][y2]S[x11][y2]S[x2][y11]+S[x11][y11]\text{sum}(x1, y1, x2, y2) = S[x2][y2] - S[x1-1][y2] - S[x2][y1-1] + S[x1-1][y1-1]

    处理边界时特别注意。

  • 常用场景

    • 图像处理:如统计某块区域的像素强度。
    • 游戏开发:快速统计地图上某区域的资源分布。
    • 数据挖掘:例如统计二维表格中某范围内数据的总和。

总结

前缀和和二维前缀和极大优化了区间和的查询速度,将原本需要线性或平方复杂度的计算降低到常数时间,非常适合高频查询的场景。同时,它们的思想还可以延展到更高维问题或与其他算法结合,广泛用于竞赛编程和实际开发中。

农田灌溉最大化作物产量问题 - MarsCode

回到这个问题,如果我们会普通的一维前缀和,我们很容易就可以想到,提前通过前缀和计算好每一行和每一列的和,然后枚举灌溉的行和列即可,需要特别注意的是一行和一列会有一个交叉点,那个点会被灌溉两次,我们需要减去其中一次灌溉的影响。 不过这个题目不给数据范围,为了保险起见我开了long long,总复杂度为 O(nm)O(nm)

参考代码

int solution(int m, int n, vector<vector<int>>& a) {
    // n 行 m 列
    typedef long long ll;
    // 计算每一行和每一列的总和
    vector<ll> row(n, 0);
    vector<ll> col(m, 0);
    ll sum = 0;
    for(int i = 0 ; i < n ; i ++) 
        for(int j = 0 ; j < m ; j ++) {
            row[i] += a[i][j];
            col[j] += a[i][j];
            sum += a[i][j];
        }
    ll ans = 0;
    // 枚举灌溉的行和列,注意减去相交点,因为不能灌溉两次
    for(int i = 0 ; i < n ; i ++) 
        for(int j = 0 ; j < m ; j ++) {
            ans = max(ans, sum + row[i] + col[j] - a[i][j]);
        }
    return ans;
}