链接:https://www.nowcoder.com/acm/contest/131/B
来源:牛客网

题目描述

矩阵 M 包含 R 行 C 列,第 i 行第 j 列的值为 Mi,j
请寻找一个子矩阵,使得这个子矩阵的和最大,且满足以下三个条件:
子矩阵的行数不能超过 X 行。
子矩阵的列数不能超过 Y 列。
子矩阵中 0 的个数不能超过 Z 个。
请输出满足以上条件的最大子矩阵和。

输入描述:

第一行输入五个整数 R,C,X,Y,Z。
接下来 N 行,每行输入 M 个整数,第 i 行第 j 列的整数表示 Mi,j
1 ≤ R,C ≤ 500.
1 ≤ X ≤ R.
1 ≤ Y ≤ C.
1 ≤ Z ≤ R x C.
-10
≤  M
i,j  
≤ 10
9

输出描述:

输出满足以上条件的最大子矩阵和。
示例1

输入

复制
5 5 3 3 4
0 0 10 0 0
3 4 0 2 3
-1 3 0 -8 3
0 0 32 -9 3
3 0 45 3 0

输出

复制
82
示例2

输入

复制
2 2 2 2 2
-1 -1
-1 -1

输出

复制
0
#include<stdio.h>
#include<algorithm>
using namespace std;
#define LL long long
LL a[505][505], sum[505][505], q[505], s0[505][505], ts[505], t1[505];
int main(void)
{
    LL now, ans, zero;
    int n, m, i, j, c, d, e, k, L, R;
    scanf("%d%d%d%d%d", &n, &m, &c, &d, &e);
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            scanf("%lld", &a[i][j]);
            sum[i][j] = sum[i][j-1]+a[i][j];
            s0[i][j] = s0[i][j-1];
            if(a[i][j]==0)
                s0[i][j]++;
        }
    }
    ans = 0;
    for(i=1;i<=m;i++)
    {
        for(j=i;j<=m;j++)
        {
            if(j-i+1>=d+1)
                continue;
            now = zero = 0;
            L = R = 0;
            q[R++] = 0;
            for(k=1;k<=n;k++)
            {
                now += sum[k][j]-sum[k][i-1];
                zero += s0[k][j]-s0[k][i-1];
                ts[k] = now;
                t1[k] = zero;
                while(L<R && q[L]+c<k)
                    L++;
                while(L<R && zero-t1[q[L]]>e)
                    L++;
                ans = max(ans, now-ts[q[L]]);
                while(L<R && ts[q[R-1]]>=now)
                    R--;
                q[R++] = k;
            }
        }
    }
    printf("%lld\n", ans);
    return 0;
}