【CodeForces】【暴力】1060C-Maximum Subrectangle

CodeForces 1060C Maximum Subrectangle

◇题目传送门◆

题目大意

给定两个长度分别为 N , M N,M N,M的两个数列 A , B A,B A,B及一个数 X X X,定义矩阵 C C C,其中 C i , j = A i × B j ( 1 ≤ i ≤ N , 1 ≤ j ≤ M ) C_{i,j}=A_i\times B_j(1\le i\le N,1\le j\le M) Ci,j=Ai×Bj(1iN,1jM),要求找出最大的矩形,使得 ∑ i = x 1 x 2 ∑ j = y 1 y 2 C i , j ≤ X \sum_{i=x_1}^{x_2}{\sum_{j=y_1}^{y_2}{C_{i,j}}}\le X i=x1x2j=y1y2Ci,jX

思路

如果有读者想了解 O ( N 2 log ⁡ 2 N 2 ) O(N^2\log_2 N^2) O(N2log2N2)的算法,请移步至这里(由于那篇文章是整场比赛的部分题解,所以请耐心翻到C题)。

我们先来推一下式子:
∑ i = x 1 x 2 ∑ j = y 1 y 2 C i , j = ∑ i = x 1 x 2 ∑ j = y 1 y 2 ( A i × B j ) = ∑ i = x 1 x 2 A i × ∑ i = y 1 y 2 B j \sum_{i=x_1}^{x_2}{\sum_{j=y_1}^{y_2}{C_{i,j}}}=\sum_{i=x_1}^{x_2}{\sum_{j=y_1}^{y_2}{(A_i\times B_j)}}\\=\sum_{i=x_1}^{x_2}{A_i}\times\sum_{i=y_1}^{y_2}{B_j} i=x1x2j=y1y2Ci,j=i=x1x2j=y1y2(Ai×Bj)=i=x1x2Ai×i=y1y2Bj

不难发现这东西和 ( x 2 − x 1 + 1 ) , ( y 2 − y 1 + 1 ) (x_2-x_1+1),(y_2-y_1+1) (x2x1+1),(y2y1+1)有关,即当有一方长度一定时,这方的值越小,则另一方的值越大,则另一方的长度越长,则面积最大。所以我们可以开一个数组 f [ i ] f[i] f[i],表示长度为 i i i的序列的和的最小值,分别对 A , B A,B A,B进行计算。再加上一个前缀和,时间复杂度为 O ( N 2 ) O(N^2) O(N2)

接下来只需枚举长度,在两个f数组中找出所有的乘积小于 X X X的可能情况,再更新答案,即可在 O ( N 2 ) O(N^2) O(N2)的时间内解决这一问题。

综上,总时间复杂度为 O ( N 2 ) O(N^2) O(N2),显然可以过掉此题。

正解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long ll;
const int Maxn=2000;

ll N,M,X,A[Maxn+5],B[Maxn+5];
ll suma[Maxn+5],sumb[Maxn+5];
ll fa[Maxn+5],fb[Maxn+5];

int main() {
	#ifdef LOACL
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
	scanf("%d %d",&N,&M);
	for(int i=1;i<=N;i++) {
		scanf("%d",&A[i]);
		suma[i]=suma[i-1]+A[i];
	}
	for(int i=1;i<=M;i++) {
		scanf("%d",&B[i]);
		sumb[i]=sumb[i-1]+B[i];
	}
	scanf("%d",&X);
	memset(fa,0x3f,sizeof fa);
	memset(fb,0x3f,sizeof fb);
	for(int l=1;l<=N;l++)
		for(int i=1;i+l-1<=N;i++)
			fa[l]=min(fa[l],suma[i+l-1]-suma[i-1]);
	for(int l=1;l<=M;l++)
		for(int i=1;i+l-1<=M;i++)
			fb[l]=min(fb[l],sumb[i+l-1]-sumb[i-1]);
	int ans=0;
	for(int i=1;i<=N;i++)
		for(int j=1;j<=M;j++)
			if(fa[i]*fb[j]<=X)
				ans=max(ans,i*j);
	printf("%d\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值