【Hihocoder1634】Puzzle Game(DP)

时间:2021-01-30 23:19:36

题意:有一个n*m的矩阵,每个矩阵里有一个数字a[i][j]。现在要求将其中一个格子的值改为p,使得修改后矩阵的最大子矩阵和最小,求这个最小值

n,m<=150,abs(a[i][j])<=1e3

思路:学习cf,也把这种题叫DP了……

考虑如何快速求出修改后最大子矩阵的值

最大子矩阵有一个O(n^3)的写法:枚举所处的两行或两列,剩下的就当做最大子串做

用这样的方法预处理出上下左右四个方向的最大子矩阵之后,枚举任意一个原最大子矩阵中每个点是否修改

如果有多个最大子矩阵除非枚举到重叠部分否则答案不会改变

枚举后的答案即为原最大子矩阵的值修改后的值与上下左右四个方向的max取max

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<bitset>
typedef long long ll;
using namespace std;
#define N 160
#define oo 10000000
#define MOD 100000073 int s[N][N],a[N][N],U[N],D[N],L[N],R[N]; int calc(int x1,int y1,int x2,int y2)
{
return s[x2][y2]-s[x1-][y2]-s[x2][y1-]+s[x1-][y1-];
} int main()
{
//freopen("hihocoder1634.in","r",stdin);
//freopen("hihocoder1634.out","w",stdout);
int n,m,p;
while(scanf("%d%d%d",&n,&m,&p)!=EOF)
{
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) scanf("%d",&a[i][j]);
memset(s,,sizeof(s));
for(int i=;i<=n+;i++) U[i]=D[i]=-oo;
for(int i=;i<=m+;i++) L[i]=R[i]=-oo;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) s[i][j]=s[i-][j]+s[i][j-]-s[i-][j-]+a[i][j];
int ans=-oo;
for(int i=;i<=n;i++)
{
int tmp=-oo;
for(int j=;j<=i;j++)
{
int t=;
for(int k=;k<=m;k++)
{
t+=calc(j,k,i,k);
tmp=max(tmp,t);
if(t<) t=;
}
}
U[i]=max(U[i-],tmp);
ans=max(ans,U[i]);
} for(int i=n;i>=;i--)
{
int tmp=-oo;
for(int j=i;j<=n;j++)
{
int t=;
for(int k=;k<=m;k++)
{
t+=calc(i,k,j,k);
tmp=max(tmp,t);
if(t<) t=;
}
}
D[i]=max(D[i+],tmp);
} for(int i=;i<=m;i++)
{
int tmp=-oo;
for(int j=;j<=i;j++)
{
int t=;
for(int k=;k<=n;k++)
{
t+=calc(k,j,k,i);
tmp=max(tmp,t);
if(t<) t=;
}
}
L[i]=max(L[i-],tmp);
} for(int i=m;i>=;i--)
{
int tmp=-oo;
for(int j=m;j>=i;j--)
{
int t=;
for(int k=;k<=n;k++)
{
t+=calc(k,i,k,j);
tmp=max(tmp,t);
if(t<) t=;
}
}
R[i]=max(R[i+],tmp);
} int sx=,sy=,ex=,ey=;
for(int i=;i<=n;i++)
for(int j=i;j<=n;j++)
{
if(sx) break;
int tmp=-oo;
int t=;
int st=;
for(int k=;k<=m;k++)
{
t+=calc(i,k,j,k);
tmp=max(tmp,t);
if(tmp==ans)
{
sx=i; ex=j;
sy=st; ey=k;
break;
}
if(t<)
{
t=;
st=k+;
}
}
}
//printf("ans=%d\n",ans);
//printf("%d %d %d %d\n",sx,sy,ex,ey);
int cnt=ans;
for(int i=sx;i<=ex;i++)
for(int j=sy;j<=ey;j++) cnt=min(cnt,max(ans-a[i][j]+p,max(max(max(U[i-],D[i+]),L[j-]),R[j+])));
printf("%d\n",cnt);
}
return ;
}