题意:
有一个长度为 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);
}