CodeForces - 1060C(前缀和+思维)

题意:

有一个长度为 n 的 a 数组和长度为 m 的 b 数组,让这个一维矩阵相乘得到二维的矩阵,求最大子矩阵的和小于或等于 x。

题解:

有一道原题,区间范围是1000,时间复杂度是O(n^3),用在这里会超时。(Hihocoder 1502: 最大子矩阵

我们可以发现一个规律:一个子矩阵的和就是 (a[i]+a[i+1]+...+a[j])*(b[i]+b[i+1]+...+b[j])。

所以我们可以使用前缀和求一个子矩阵的和,我们要求的是子矩阵的大小,所以设一个数组存长度为 1...n 的 a 和 b 的前缀和,再遍历求最大的大小。

#include <algorithm>
#include  <iostream>
#include   <cstdlib>
#include   <cstring>
#include    <cstdio>
#include    <string>
#include    <vector>
#include    <bitset>
#include     <stack>
#include     <cmath>
#include     <deque>
#include     <queue>
#include      <list>
#include       <set>
#include       <map>
#define line printf("---------------------------\n") 
#define mem(a, b) memset(a, b, sizeof(a))
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int maxn = 2000+10;

ll a[maxn], b[maxn], ma[maxn], mb[maxn];

int main(){
	int n, m;
	scanf("%d %d", &n, &m);
	a[0] = b[0] = 0;
	for(int i = 1; i <= n; i++){
		scanf("%d", &a[i]);
		a[i] += a[i-1];
	}
	for(int i = 1; i <= m; i++){
		scanf("%d", &b[i]);
		b[i] += b[i-1];
	}
	mem(ma, inf);
	mem(mb, inf);
	for(int i = 1; i <= n; i++){
		for(int j = i; j <= n; j++){
			ma[j-i+1] = min(ma[j-i+1], a[j]-a[i-1]);
		}
	}
	for(int i = 1; i <= m; i++){
		for(int j = i; j <= m; j++){
			mb[j-i+1] = min(mb[j-i+1], b[j]-b[i-1]);
		}
	}
	ll x;
	scanf("%lld", &x);
	int ans = 0;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			if(ma[i]*mb[j] <= x){
				ans = max(ans, i*j);
			}
		}
	}
	printf("%d\n", ans);
}

猜你喜欢

转载自blog.csdn.net/yanhu6955/article/details/82941671