1 条题解

  • 0
    @ 2022-6-8 17:31:55

    我在洛谷写的这题的题解中有一处小小的笔误,不影响阅读,就不更正了,但在 Hydro 上已经更正。


    题目大意 :给出一个 m×nm \times n 的矩阵,求出这个矩阵的最大子矩阵和。(把题目中的 00 在读入时当做 1-1 处理即可,下文不再赘述)

    具体思路

    1. 求出每一行前 jj 个数的前缀和。即:

      sumi,j=sumi,j1+ai,jsum_{i,j} = sum_{i,j-1} + a_{i,j}

      其中,sumi,jsum_{i,j} 表示第 ii 行前 jj 个数的前缀和。

    2. 进行枚举起始列 ii 与目标列 jj,再把每一行中从 iijj 的和算出来(利用之前的前缀和),我们可以建立一个 临时 数组f,则:

      fk=sumk,jsumk,i1f_k = sum_{k,j} - sum_{k,i-1}

      其中,fkf_k 表示第 kk 行中从 iijj 的和。

    3. 这时,我们已经把每一行(从 iijj)的和存到了数组 ff 中,那么我们就可以把问题转化为 最大子段和 问题了。最大子段和的公式:

      fk=max(fk,fk+fk1)f_k = \max(f_k, f_k + f_{k - 1})

      再用变量 ansans 打擂台求出 fkf_k 的最大值即可。

    AC Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    #define maxn 405
    int m, n, ans;
    int sum[maxn][maxn], f[maxn];
    char c;
    
    signed main() {
        cin >> m >> n;
        //注意不是 n 行 m 列
    
        for (int i = 1; i <= m; i++) 
            for (int j = 1; j <= n; j++) {
                cin >> c;
                if (c == '1') sum[i][j] = sum[i][j - 1] + 1;
                else if (c == '0') sum[i][j] = sum[i][j - 1] - 1;
            }
        //求出每一行的前 j 个数的前缀和
    
        for (int i = 1; i <= n; i++)
            for (int j = i; j <= n; j++) {//枚举第 i 列到第 j 列
                
                for (int k = 1; k <= m; k++) 
                    f[k] = sum[k][j] - sum[k][i - 1];//把每一行的和算出来
    
                for (int k = 1; k <= m; k++) {
                    f[k] = max(f[k], f[k] + f[k - 1]);
                    ans = max(ans, f[k]);
                }//最大子段和问题
    
            }
        cout << ans << endl;
        return 0;
    }
    
    
    • 1

    信息

    ID
    6629
    时间
    1000ms
    内存
    128MiB
    难度
    4
    标签
    递交数
    1
    已通过
    1
    上传者