链接: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.
-109 ≤ Mi,j ≤ 109
输出描述:
输出满足以上条件的最大子矩阵和。
示例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<string.h>
#include<algorithm>
using namespace std;
#define ll long long
int r,c,x,y,z;
ll sum1[505][505],sum2[505][505],ans,sm[505],q[505],sm1[505];
int main(void)
{
scanf("%d%d%d%d%d",&r,&c,&x,&y,&z);
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
{
scanf("%lld",&sum1[i][j]);
if(sum1[i][j]==0)
sum2[i][j]=sum2[i-1][j]+1;
else
sum2[i][j]=sum2[i-1][j];
sum1[i][j]+=sum1[i-1][j];
}
for(int i=1;i<=r;i++)
for(int j=i;j<=i+x-1 && j<=r;j++)
{
int head=0,rear=0;
memset(q,0,sizeof(q));
memset(sm,0,sizeof(sm));
memset(sm1,0,sizeof(sm1));
q[rear++]=0;
for(int k=1;k<=c;k++)
{
sm[k]=sum1[j][k]-sum1[i-1][k]+sm[k-1];
sm1[k]=sum2[j][k]-sum2[i-1][k]+sm1[k-1];
while(head<rear && (k-q[head]>y || sm1[k]-sm1[q[head]]>z)) head++;
if(head<rear) ans=max(ans,sm[k]-sm[q[head]]);
while(head<rear && sm[k]<sm[q[rear-1]]) rear--;
q[rear++]=k;
}
}
printf("%lld\n",ans);
return 0;
}
/*
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
*/