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

传送门


解析:

这道题直接模拟是 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
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;
}

你可能感兴趣的:(贪心)