1. 程式人生 > >【CodeForces】【暴力】1060C-Maximum Subrectangle

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

CodeForces 1060C Maximum Subrectangle

題目大意

給定兩個長度分別為N,MN,M的兩個數列A,BA,B及一個數XX,定義矩陣CC,其中Ci,j=Ai×Bj(1iN,1jM)C_{i,j}=A_i\times B_j(1\le i\le N,1\le j\le M),要求找出最大的矩形,使得i=x1x2j=y1y2Ci,jX\sum_{i=x_1}^{x_2}{\sum_{j=y_1}^{y_2}{C_{i,j}}}\le X

思路

如果有讀者想了解O(N2log2N2)O(N^2\log_2 N^2)的演算法,請移步至這裡(由於那篇文章是整場比賽的部分題解,所以請耐心翻到C題)。

我們先來推一下式子: i=x1x2j=y1y2Ci,j=i=x1x2j=y1y2(Ai×Bj)=i=x1x2Ai×i=y1y2Bj\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}

不難發現這東西和(x2x1+1),(y2y1+1)(x_2-x_1+1),(y_2-y_1+1)有關,即當有一方長度一定時,這方的值越小,則另一方的值越大,則另一方的長度越長,則面積最大。所以我們可以開一個數組f[i]f[i],表示長度為ii的序列的和的最小值,分別對A,BA,B進行計算。再加上一個字首和,時間複雜度為O(N2)O(N^2)

接下來只需列舉長度,在兩個f陣列中找出所有的乘積小於X

X的可能情況,再更新答案,即可在O(N2)O(N^2)的時間內解決這一問題。

綜上,總時間複雜度為O(N2)O(N^2),顯然可以過掉此題。

正解程式碼

#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;
}