zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    一道leetcode题的收获如何比较字符串的大小重写sort中的compare[](string &s,string &t){return s+t>t+s};
    unsigned int表示负数问题
    fork()和printf()几点注意细节
    32位机中数据问题
    C++隐藏机制
    ||,&&,++i解答
    enum忽略知识点
    硬链接与软链接
    20145215实验五 Java网络编程及安全
    证书与keytool
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1177.html
Copyright © 2011-2022 走看看