2 条题解

  • 1
    @ 2026-5-30 10:42:36

    这个东西其实是最大子段和的变体

    题目链接

    以及一道和此本题差不多的题,就是数据水一点

    题目链接

    这个题如果用暴力解法的复杂度就是O(n2m2)O(n^2m^2)的,题目的数据范围是n<=500m<=500n<=500且m<=500肯定过不了

    我们先考虑第ii行到第jj行之间的最大子矩阵

    $$\begin{bmatrix} a_{i,1} &a_{i,2} &a_{i,3} &a_{i,4}... & a_{i,m} \\ a_{i+1,1} &a_{i+1,2} &a_{i+1,3} &a_{i+1,4}... & a_{i+1,m}\\ ....& ....& ....& ....& ....\\ a_{j,1} &a_{j,2} &a_{j,3} &a_{j,4}... & a_{j,m} \end{bmatrix}$$

    由于我们子矩阵的上下两行是确定的,假设我们最大子矩阵的左右两行分别是第ll行或者是第rr行可以发现,子矩阵的元素和等于第ll列的第ii行到第jj行的列前缀和到第rr列的第ii行到第jj行的列前缀和

    于是我们可以对某两行之间的矩阵进行压维

    $$\begin{bmatrix} pre_{1}&pre_{2}&pre_{3}&pre_{4}&pre_{5}& \end{bmatrix}$$

    然后这个题就转化成最大子段和了,结束 下面附上代码块 解法就是n2n^2枚举两行并且mm次枚举列 复杂度O(n2m)O(n^2m)提一嘴,一般一秒在cf评测机上可以运行2.5e8的数据

    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    int a[501][501];
    signed main() {
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        int n, m;
        cin >> n >> m;
        vector<vector<int>> s(n + 1, vector<int>(m + 1, 0));
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                int v;
                cin >> v;
                s[i][j] = s[i - 1][j] + v;
            }
        }
        int mx = -2e18;
        for (int i = 1; i <= n; i++) {
            for (int j = i; j <= n; j++) {
                int cur = 0;
                int mi = 0;
                for (int k = 1; k <= m; k++) {
                    int val = s[j][k] - s[i - 1][k];
                    cur += val;
                    mx = max(mx, cur - mi);
                    mi = min(mi, cur);
                }
            }
        }
        cout << mx << endl;
        return 0;
    }
    

    信息

    ID
    127
    时间
    2000ms
    内存
    256MiB
    难度
    7
    标签
    递交数
    162
    已通过
    32
    上传者