【HihoCoder - 1502】最大子矩阵(二维前缀和,尺取)

题干:

给定一个NxM的矩阵A和一个整数K,小Hi希望你能求出其中最大(元素数目最多)的子矩阵,并且该子矩阵中所有元素的和不超过K。

Input

第一行包含三个整数N、M和K。

以下N行每行包含M个整数,表示A。

对于40%的数据,1 <= N, M <= 10  

对于100%的数据,1 <= N, M <= 250 1 <= K <= 2147483647 1 <= Aij <= 10000

Output

满足条件最大的子矩阵所包含的元素数目。如果没有子矩阵满足条件,输出-1。

Sample Input

3 3 9
1 2 3  
2 3 4  
3 4 5

Sample Output

4 

解题报告:

先预处理一个前缀和,然后枚举每两行,然后行内尺取就行了,总复杂度N^3,。可以尺取的前提是元素都是正数。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
int n,m,k;
ll a[255][255],sum[255][255];
int main()
{
	cin>>n>>m>>k;
	for(int i = 1; i<=n; i++) {
		for(int j = 1; j<=m; j++) {
			scanf("%lld",&a[i][j]);
		}
	}
	for(int i = 1; i<=n; i++) {
		for(int j = 1; j<=m; j++) {
			sum[i][j] = a[i][j] + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1]; 
		}
	}
	int ans = -1;
	for(int i = 1; i<=n; i++) {
		for(int j = i; j<=n; j++) {
			int l = 1,r = 1;
			ll tmp = 0;
			while(r <= m) {
				tmp += sum[j][r] - sum[j][r-1] - sum[i-1][r] + sum[i-1][r-1];
				while(l<=r && tmp > k) {
					tmp -= sum[j][l] - sum[j][l-1] - sum[i-1][l] + sum[i-1][l-1];
					l++;
				}
				if(tmp <= k)
					ans = max(ans,(j-i+1)*(r-l+1));	
				r++;
			}
		}
	}
	if(ans <= 0) printf("-1\n");
	else printf("%d\n",ans);
	return 0 ;
}

 

上一篇:BZOJ 1029 [JSOI2007]建筑抢修 (贪心 + 优先队列)


下一篇:go语言之goto语句和函数和defer语句