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(1≤i≤N,1≤j≤M),要求找出最大的矩形,使得 ∑ 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=x1∑x2j=y1∑y2Ci,j≤X
思路
如果有读者想了解 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=x1∑x2j=y1∑y2Ci,j=i=x1∑x2j=y1∑y2(Ai×Bj)=i=x1∑x2Ai×i=y1∑y2Bj
不难发现这东西和 ( x 2 − x 1 + 1 ) , ( y 2 − y 1 + 1 ) (x_2-x_1+1),(y_2-y_1+1) (x2−x1+1),(y2−y1+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;
}