0
点赞
收藏
分享

微信扫一扫

最大子矩阵

流计算Alink 2022-04-03 阅读 90

给定一个长度为 nn 的整数数组 a1,a2,…,an 和一个长度为 m 的整数数组 b1,b2,…,bm。

设 cc 是一个 n×m的矩阵,其中 ci,j=ai×bj。

请你找到矩阵 c 的一个子矩阵,要求:该子矩阵所包含的所有元素之和不超过 x,并且其面积(包含元素的数量)应尽可能大。

输出满足条件的子矩阵的最大可能面积(即包含元素的最大可能数量)。

输入格式

第一行包含两个整数 n,m。

第二行包含 nn 个整数 a1,a2,…,an。

第三行包含 mm 个整数 b1,b2,…,bm。

第四行包含一个整数 x。

输出格式

一个整数,表示满足条件的子矩阵的最大可能面积(即包含元素的最大可能数量)。

如果不存在满足条件的子矩阵,则输出 0。

数据范围

前三个测试点满足 1≤n,m≤5。
所有测试点满足 1≤n,m≤2000,1≤ai,bi≤2000,1≤x≤2×1e9。

输入样例1:

3 3
1 2 3
1 2 3
9

输出样例1:

4

输入样例2:

5 1
5 4 2 4 5
2
5

输出样例2:

1

 分析:

首先我们可以将题目所求的子矩阵元素和转换为求a b数组的一段子区间和的乘积
如下如果知道这一点。后面的内容就很简单:
a1 * b1 + a2 * b1 + a3 * b1
a1 * b2 + a2 * b2 + a3 * b2  = (a1 + a2 + a3) * (b1 + b2 + b3)
a1 * b3 + a2 * b3 + a3 * b3

为了使我们的区间很大,我们就使每一个区间越小就可以了,因此我们可以求出lena[N]数组,第i个数组的值表示a区间长度为i时的最小和是多少,lenab[N]同理
区间和可以用前缀和实现
记录a b数组长度为1~n /m的最小区间和
然后暴力枚举a的区间长度和b的区间长度进行判断比较即可

代码如下:

#include <bits/stdc++.h>

using namespace std;
const int N=2010;
long long a[N],b[N],lena[N],lenb[N];
long long x,sum;
int m,n;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i],a[i]+=a[i-1];
    for(int i=1;i<=m;i++) cin>>b[i],b[i]+=b[i-1];
    cin>>x;
    for(int len=1;len<=n;len++)
    {
        long long minn=4e6+10;
        for(int i=1;i<=n-len+1;i++)
        {
            int r=i+len-1;
            minn=min(minn,a[r]-a[i-1]);
        }
        lena[len]=minn;
//        cout<<len<<" a: "<<lena[len]<<endl;
    }
    for(int len=1;len<=m;len++)
    {
        long long minn=4e6+10;
        for(int i=1;i<=m-len+1;i++)
        {
            int r=i+len-1;
            minn=min(minn,b[r]-b[i-1]);
        }
        lenb[len]=minn;
//        cout<<len<<" b: "<<lenb[len]<<endl;
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(lena[i]*lenb[j]<=x)
            {
//            	cout<<lena[i]<<" "<<lenb[j]<<endl;
                ans=max(ans,i*j);
            }
        }
    }
    cout<<ans;
}
举报

相关推荐

0 条评论