题目大意:
一个N行M列的二维矩阵,矩阵的每个位置上是一个绝对值不超过1000的整数。你需要找到两个不相交的A*B的连续子矩形,使得这两个矩形包含的元素之和尽量大。
思路:
预处理,n2时间算出每个点左上方的数的总和,如此可以O(1)算出一个目标矩阵的和。再预处理出自底向下到每行最大的子矩阵、自右向左到每列最大的子矩阵,再n2枚举一个子矩阵,计算与其右方和下方最大的子矩阵的和即可出答案。
至于无解虽然数据貌似没有,但只需考虑两个横放或竖放或一横一竖放可不可以即可。
横竖的处理细节挺多,要dxx。
代码:
1 #include<cstdio> 2 const int M=1001; 3 int n,m,x,y,i,j,ans=-2000000000,sum[M][M],lmax[M],rmax[M]; 4 5 int ju(int i,int j,int x,int y){ return sum[i+x-1][j]-sum[i-1][j]-sum[i+x-1][j-y]+sum[i-1][j-y]; } 6 7 void line(int n,int m,int x,int y) 8 { 9 int i,j,t; 10 for (i=n-x+1;i;--i) 11 { 12 if (lmax[i]<lmax[i+1]) lmax[i]=lmax[i+1]; 13 for (j=y;j<=m;++j) 14 { 15 t=ju(i,j,x,y); 16 if (t>lmax[i]) lmax[i]=t; 17 } 18 } 19 } 20 21 void row(int n,int m,int x,int y) 22 { 23 int i,j,t; 24 for (i=n-y+1;i;--i) 25 { 26 if (rmax[i]<rmax[i+1]) rmax[i]=rmax[i+1]; 27 for (j=1;j+x<m+2;++j) 28 { 29 t=ju(j,i+y-1,x,y); 30 if (t>rmax[i]) rmax[i]=t; 31 } 32 } 33 } 34 35 void cal(int x,int y) 36 { 37 int i,j,t; 38 for (i=1;i+x<n+2;++i) 39 for (j=y;j<=m;++j) 40 { 41 t=ju(i,j,x,y); 42 if (i+x<=n && t+lmax[i+x]>ans) ans=t+lmax[i+x]; 43 if (j<m && t+rmax[j+1]>ans) ans=t+rmax[j+1]; 44 } 45 } 46 47 int main() 48 { 49 scanf("%d%d%d%d",&n,&m,&x,&y); 50 for (i=1;i<=n;++i) 51 for (j=1;j<=m;++j) scanf("%d",&sum[i][j]); 52 for (i=1;i<=n;++i) 53 for (j=1;j<=m;++j) sum[i][j]=sum[i][j-1]+sum[i-1][j]+sum[i][j]-sum[i-1][j-1]; 54 for (i=1;i<n+2;++i) lmax[i]=ans; 55 for (i=1;i<m+2;++i) rmax[i]=ans; 56 line(n,m,x,y),line(n,m,y,x); 57 row(m,n,x,y),row(m,n,y,x); 58 cal(x,y),cal(y,x); 59 if ((x+x>n || y>m) && (y+y>n || x>m) && 60 (x+x>m || y>n) && (x+y>n || x>m) && 61 (x+y>m || x>n) && (x+y>n || y>m) && (x+y>m || x>n)) puts("Impossible"); 62 else printf("%d ",ans); 63 return 0; 64 }