版权声明:本文为博主原创文章,不管你喜不喜欢都请在注明作者后转载~( ̄▽ ̄~) https://blog.csdn.net/C20190102/article/details/82942156
题目
题目大意
给出分别有 个元素的序列 ,定义一个乘积矩阵,其中的元素 ,找到它的一个最大面积子矩阵,使得这个子矩阵的元素之和不大于给定的 。所有数都是正数, 。
思路
比赛的时候第一次
分钟内切掉前
题,剧烈膨胀,结果大脑抽筋死在第
题。
设这个矩阵左上角为
,右下角为
,那么它的元素之和为:
化简一下得:
记录一下
的前缀和记为
,于是得到:
相当于是从
中分别找一段元素之和乘起来不大于
。
以上内容是比赛时想到的。
然后先想了个
,写着写着发现是错的。
然后想了个用set
乱搞
的,交上去只过了样例,WA
了三次后发现思路还是错的。
我直到比赛结束都觉得是个二分搜索。
于是我颓废了。
接下来是正解。
可以用
和
时间处理出
中长度为len
的一段区间的最小元素和
。
然后再用 枚举从 中选长度为 , 中选长度为 的一段,它们乘积之和最小为 ,如果这个值不大于 ,说明可以,就更新答案。
我突然觉得自己不够贪心啊= =
代码
早上起来赶的,写得丑不要介意。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 2000
#define LL long long
int N[2],X,Ans;
LL Sum[2][MAXN+5],MinSum[3][MAXN+5];
int main(){
scanf("%d%d",&N[0],&N[1]);
for(int i=0;i<=1;i++)
for(int j=1;j<=N[i];j++){
int t;scanf("%d",&t);
Sum[i][j]=Sum[i][j-1]+t;
}
scanf("%d",&X);
memset(MinSum,0x7f,sizeof MinSum);
for(int i=0;i<=1;i++)
for(int len=1;len<=N[i];len++)
for(int j=len;j<=N[i];j++)
MinSum[i][len]=min(MinSum[i][len],Sum[i][j]-Sum[i][j-len]);
for(int i=1;i<=N[0];i++)
for(int j=1;j<=N[1];j++)
if(MinSum[0][i]*MinSum[1][j]<=X)
Ans=max(Ans,i*j);
printf("%d",Ans);
}