矩阵(前缀和)

题目链接

题目描述:

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

Input:

第一行输入五个整数 R,C,X,Y,Z。

接下来 R行,每行输入 C 个整数,第 i 行第 j 列的整数表示 Mi,j
1 ≤ R,C ≤ 500.

1 ≤ X ≤ R.
1 ≤ Y ≤ C.
1 ≤ Z ≤ R x C.
-10≤ Mi,j  ≤ 109

Output:

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

 

Example:

input1:

5 2 0
2 1 1 1
2 1 1 1
3 2 1 1
4 3 1 1
5 4 1 1

output1:

82

input2:

2 2 2 2 2
-1 -1
-1 -1

output2:

0

思路:统计每列数的0的个数的前缀和,以及每列数的前缀和,3重循环,第3重循环内求满足条件的矩阵的和,具体操作见代码。

#include<bits/stdc++.h>
#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
typedef unsigned long long ull;
typedef  long long ll;
typedef pair<ll,ll> pi;
#define IOS std::ios::sync_with_stdio(false)
#define ls p<<1
#define rs p<<1|1
#define mod 1000000000 + 7
#define PI acos(-1.0)
#define INF   1e18
#define N 666 + 5
/*********************Code*********************/
ll n,m,x,y,z,ans,a[N][N],q[N],l,r,sum[N],res[N],c[N][N];
int main(void){
    IOS;
    cin>>n>>m>>x>>y>>z;
    for(ll i = 1;i <=n;i++)
    for(ll j = 1;j <=m;j++){
        cin>>a[i][j];
    }
    for(ll j = 1;j <=m;j++)
        for(ll i = 1;i <=n;i++)
        c[i][j] = c[i-1][j] +(a[i][j]==0);  //求每一列数的0的个数的前缀和
    for(ll i = 1;i <=n;i++)
        for(ll j = 1;j <=m;j++)
        a[i][j] +=a[i-1][j];  //求每一列数的前缀和
    for(ll i = 0;i < n;i++){
        for(ll j = i + 1;j <=min(n,i+x);j++){  //j表示从第i行开始计数,能计到多少行
            q[l=r=1] = 0,sum[0] = res[0] = 0;  //q[i]表示可取的列,q[l]表示当前是第几列
            for(ll k = 1;k <=m;k++){
                sum[k] = sum[k-1]+a[j][k] - a[i][k];   //sum[k]表示取k列,第j-i行矩阵的前缀和
                res[k] = res[k-1]+c[j][k] -c[i][k];    //res[k]表示取k列,第j-i行的0的个数
                while(l<=r&&(k-q[l]>y||res[k]-res[q[l]]>z))  //如果在l小于、等于r的情况下,第k列到第q[l]列的列数差大于y,或者k列到q[l]列的0的个数大于z,l++,从第l列开始计数
                    l++;
                if(l<=r)  //如果当前列可取
                    ans = max(ans,sum[k]-sum[q[l]]);
                while(l<=r&&sum[k]<=sum[q[r]]) //如果去第k列后,矩阵和减少,就将r--,重新记录可取的列,保证求最大值时,求得的值为正数
                    r--;
                q[++r] = k;  //q[r]记录已经到达第几列
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

 

posted @ 2021-02-20 17:08  阿涅—Rachel  阅读(240)  评论(0)    收藏  举报