[VijosP1764]Dual Matrices 题解

时间:2023-03-08 17:27:04
[VijosP1764]Dual Matrices 题解

题目大意:

  一个N行M列的二维矩阵,矩阵的每个位置上是一个绝对值不超过1000的整数。你需要找到两个不相交的A*B的连续子矩形,使得这两个矩形包含的元素之和尽量大。

思路:

  预处理,n2时间算出每个点左上方的数的总和,如此可以O(1)算出一个目标矩阵的和。再预处理出自底向下到每行最大的子矩阵、自右向左到每列最大的子矩阵,再n2枚举一个子矩阵,计算与其右方和下方最大的子矩阵的和即可出答案。

  至于无解虽然数据貌似没有,但只需考虑两个横放或竖放或一横一竖放可不可以即可。

  横竖的处理细节挺多,要dxx。

代码:

 #include<cstdio>
const int M=;
int n,m,x,y,i,j,ans=-,sum[M][M],lmax[M],rmax[M]; int ju(int i,int j,int x,int y){ return sum[i+x-][j]-sum[i-][j]-sum[i+x-][j-y]+sum[i-][j-y]; } void line(int n,int m,int x,int y)
{
int i,j,t;
for (i=n-x+;i;--i)
{
if (lmax[i]<lmax[i+]) lmax[i]=lmax[i+];
for (j=y;j<=m;++j)
{
t=ju(i,j,x,y);
if (t>lmax[i]) lmax[i]=t;
}
}
} void row(int n,int m,int x,int y)
{
int i,j,t;
for (i=n-y+;i;--i)
{
if (rmax[i]<rmax[i+]) rmax[i]=rmax[i+];
for (j=;j+x<m+;++j)
{
t=ju(j,i+y-,x,y);
if (t>rmax[i]) rmax[i]=t;
}
}
} void cal(int x,int y)
{
int i,j,t;
for (i=;i+x<n+;++i)
for (j=y;j<=m;++j)
{
t=ju(i,j,x,y);
if (i+x<=n && t+lmax[i+x]>ans) ans=t+lmax[i+x];
if (j<m && t+rmax[j+]>ans) ans=t+rmax[j+];
}
} int main()
{
scanf("%d%d%d%d",&n,&m,&x,&y);
for (i=;i<=n;++i)
for (j=;j<=m;++j) scanf("%d",&sum[i][j]);
for (i=;i<=n;++i)
for (j=;j<=m;++j) sum[i][j]=sum[i][j-]+sum[i-][j]+sum[i][j]-sum[i-][j-];
for (i=;i<n+;++i) lmax[i]=ans;
for (i=;i<m+;++i) rmax[i]=ans;
line(n,m,x,y),line(n,m,y,x);
row(m,n,x,y),row(m,n,y,x);
cal(x,y),cal(y,x);
if ((x+x>n || y>m) && (y+y>n || x>m) &&
(x+x>m || y>n) && (x+y>n || x>m) &&
(x+y>m || x>n) && (x+y>n || y>m) && (x+y>m || x>n)) puts("Impossible");
else printf("%d\n",ans);
return ;
}