2018.10.04【CodeForces1060】C. Maximum Subrectangle(贪心)

本文介绍了一种优化算法,用于解决矩阵元素和的问题。通过将矩阵元素和转化为两个序列的子段和乘积,实现了从O(n^3m^3)到更高效算法的转变。文章详细解释了算法原理,并提供了C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门


解析:

这道题直接模拟是 O ( n 3 m 3 ) O(n^3m^3) O(n3m3)的,怎么乱搞都搞不动。

其实直接模拟的话,有很多状态是显然不够优的

我们实际上可以将矩阵元素和转化一下: ∑ 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 \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 i=x1x2j=y1y2ci,j=i=x1x2j=y1y2ai×bj = ∑ i = x 1 x 2 a i × ∑ j = y 1 y 2 b j =\sum_{i=x_1}^{x_2}a_i\times\sum_{j=y_1}^{y_2} b_j =i=x1x2ai×j=y1y2bj

相当于 a a a的子段和乘上 b b b的子段和。

而我们最后答案只关心区间长度,所以我们可以预处理两个序列不同区间长度对应的最小值,显然这样贪心是对的。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline
ll getint(){
	re ll num;
	re char c;
	re bool f=0;
	while(!isdigit(c=gc()))f^=c=='-';num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return f?-num:num;
}

inline
void outint(ll a){
	static char ch[23];
	if(a==0)pc('0');
	if(a<0)pc('-'),a=-a;
	while(a)ch[++ch[0]]=a-a/10*10,a/=10;
	while(ch[0])pc(ch[ch[0]--]^48);
}

int n,m;
ll a[2003],b[2003];
ll ac[2003],bc[2003];
ll x;
ll ans=0;

signed main(){
	n=getint();
	m=getint();
	memset(ac,0x3f,sizeof ac);
	memset(bc,0x3f,sizeof bc);
	for(int re i=1;i<=n;++i)a[i]=getint()+a[i-1];
	for(int re i=1;i<=m;++i)b[i]=getint()+b[i-1];
	x=getint();
	for(int re i=0;i<n;++i)
	for(int re j=i+1;j<=n;++j)
	ac[j-i]=min(ac[j-i],a[j]-a[i]);
	
	for(int re i=0;i<m;++i)
	for(int re j=i+1;j<=m;++j)
	bc[j-i]=min(bc[j-i],b[j]-b[i]);
	
	for(int re i=1;i<=n;++i)
	for(int re j=1;j<=m;++j)
	if(ac[i]*bc[j]<=x)ans=max(ans,1ll*i*j);
	cout<<ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值