BZOJ1177 [Apio2009]Oil 二维前缀和 二维前缀最值

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


 题目传送门 - BZOJ1177


 题意概括

  在一个n*m的矩阵中,每一个位置一个数字。

  现在让你选出3个k*k的矩阵,它们互不相交,问最大数值和为多少。

  注意:n,m<=1500


 题解

  一开始总想着dp,发现不大可能。

  暴搜也不行。

  然后突然发现,很简单,情况总数非常的少。

  只有以下6种,从3个区域中各选择一个最大的。

  然后就很简单了,我们只需要预处理矩阵前缀和,左上左下右上右下4个方向的前缀max。

  然后对于前两种,分别枚举一下列号和行号;

  对于后四种,只要枚举中间点就可以了。

  所以复杂度为n2。可以过去了。


 

代码

 

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=1500+5;
int n,m,k,nn,mm;
int a[N][N],sum[N][N],val[N][N],Row[N],Col[N],LU[N][N],RU[N][N],LD[N][N],RD[N][N];
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	memset(sum,0,sizeof sum);
	memset(val,0,sizeof val);
	memset(Row,0,sizeof Row);
	memset(Col,0,sizeof Col);
	memset(LU,0,sizeof LU);
	memset(RU,0,sizeof RU);
	memset(LD,0,sizeof LD);
	memset(RD,0,sizeof RD);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
	nn=n-k+1,mm=m-k+1;
	for (int i=1;i<=nn;i++)
		for (int j=1;j<=mm;j++)
			val[i][j]=sum[i+k-1][j+k-1]-sum[i-1][j+k-1]-sum[i+k-1][j-1]+sum[i-1][j-1];
	for (int i=1;i<=nn;i++)
		for (int j=1;j<=mm;j++)
			Row[i]=max(Row[i],val[i][j]),Col[j]=max(Col[j],val[i][j]);
	for (int i=1;i<=nn;i++)
		for (int j=1;j<=mm;j++)
			LU[i][j]=max(val[i][j],max(LU[i-1][j],LU[i][j-1]));
	for (int i=1;i<=nn;i++)
		for (int j=mm;j>=1;j--)
			RU[i][j]=max(val[i][j],max(RU[i-1][j],RU[i][j+1]));
	for (int i=nn;i>=1;i--)
		for (int j=1;j<=mm;j++)
			LD[i][j]=max(val[i][j],max(LD[i+1][j],LD[i][j-1]));
	for (int i=nn;i>=1;i--)
		for (int j=mm;j>=1;j--)
			RD[i][j]=max(val[i][j],max(RD[i+1][j],RD[i][j+1]));
	int ans=0;
	/*	----  ----   -----  -----  -----  -----
		||||  |--|   | | |  |---|  | |-|  |-| |
		----  |--|   -----  | | |  -----  -----
		      ----   |---|  -----                 */
	for (int i=1;i<=nn;i++){
		int Max=0;
		for (int j=i+k;j<=nn;j++){
			Max=max(Max,Row[j]);
			if (j+k>nn)
				break;
			ans=max(ans,LU[i][mm]+Max+LD[j+k][mm]);
		}
	}
	for (int i=1;i<=mm;i++){
		int Max=0;
		for (int j=i+k;j<=mm;j++){
			Max=max(Max,Col[j]);
			if (j+k>mm)
				break;
			ans=max(ans,LU[nn][i]+Max+RU[nn][j+k]);
		}
	}
	for (int i=k+1;i<=nn;i++)
		for (int j=k+1;j<=mm;j++){
			int lu=LU[i-k][j-k],ru=RU[i-k][j],ld=LD[i][j-k],rd=RD[i][j];
			ans=max(ans,lu+ru+LD[i][mm]);
			ans=max(ans,lu+ld+RU[nn][j]);
			ans=max(ans,ld+rd+LU[i-k][mm]);
			ans=max(ans,rd+ru+LU[nn][j-k]);
		}
	printf("%d",ans);
	return 0;
}

  

posted @ 2017-08-18 15:11  zzd233  阅读(344)  评论(0编辑  收藏  举报