昨天做的,今天才想起来,要写个博客,记一下这种矩阵题怎么做。
首先我没有意识到,每个方向上累和,得到两个累和数组,它们的子序列之积,就是子序列对应的矩形区域范围内所有数字之和,说起来有点抽象,但是举个栗子吧,
就像用例里面的这张提示图,横坐标我选子列2,3,则和为5,纵坐标我选子列1,2,则和为3。那么3和5,乘积为15,而把矩阵中对应区域的和相加,也是15,。则这个问题就容易了:只需要枚举一维数组就可以了。但是,如果枚举一维数组,那岂不是要做一个四重循环?其实不然。
题目要我们获得一个不大于限定数值的最大值,在此之前,我们需要对其中一个序列做一个预处理:二重循环枚举所有子列,计算对应子列长度下的最小子列和(最小,才能保证取更多的点,也就是更长的长度,也就是更大的面积)。之后,可以选定两个中的另一个序列,用一个二重循环得到子列和,再用限定数值除以这个和,得到一个目标值。之后,在最初预处理得到的数组中二分查找目标值,返回大于它的第一个值,也就是用upper_bound,求出之后长度减一即可,这样保证长度最长。最后,用查找得到的长度和当前子列长度相乘,得到的结果始终取最大值,循环结束之后,就是答案。
#include <bits/stdc++.h>
#define N 2005
#define INF 0x7fffffff
using namespace std;
typedef long long ll;
int a[N],b[N];
ll ma[N],x;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n,m,ans=0;
fill(ma,ma+N,INF);
cin>>n>>m;
for (int i=1;i<=n;i++) {cin>>a[i];a[i]=a[i-1]+a[i];}
for (int i=1;i<=m;i++) {cin>>b[i];b[i]=b[i-1]+b[i];}
cin>>x;
for (int i=1;i<=n;i++) {
for (int j=i;j<=n;j++) {
ll tsm=a[j]-a[i-1];
int len=j-i+1;
ma[len]=min(ma[len],tsm);
}
}
for (int i=1;i<=m;i++) {
for (int j=i;j<=m;j++) {
ll sc=x/(b[j]-b[i-1]);
int len=j-i+1;
int mxa=upper_bound(ma+1,ma+n+1,sc)-ma-1;
ans=max(ans,len*mxa);
}
}
cout<<ans<<endl;
return 0;
}
原文地址:https://www.cnblogs.com/yichuan-sun/p/9749030.html
时间: 2024-11-05 22:03:16