Wannafly挑战赛19-B-矩阵(单调队列)

链接: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
*/

猜你喜欢

转载自blog.csdn.net/haut_ykc/article/details/81713219