题意:有一个n*m的矩阵,每个矩阵里有一个数字a[i][j]。现在要求将其中一个格子的值改为p,使得修改后矩阵的最大子矩阵和最小,求这个最小值
n,m<=150,abs(a[i][j])<=1e3
思路:学习cf,也把这种题叫DP了……
考虑如何快速求出修改后最大子矩阵的值
最大子矩阵有一个O(n^3)的写法:枚举所处的两行或两列,剩下的就当做最大子串做
用这样的方法预处理出上下左右四个方向的最大子矩阵之后,枚举任意一个原最大子矩阵中每个点是否修改
如果有多个最大子矩阵除非枚举到重叠部分否则答案不会改变
枚举后的答案即为原最大子矩阵的值修改后的值与上下左右四个方向的max取max
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<bitset> 7 typedef long long ll; 8 using namespace std; 9 #define N 160 10 #define oo 10000000 11 #define MOD 100000073 12 13 int s[N][N],a[N][N],U[N],D[N],L[N],R[N]; 14 15 int calc(int x1,int y1,int x2,int y2) 16 { 17 return s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]; 18 } 19 20 int main() 21 { 22 //freopen("hihocoder1634.in","r",stdin); 23 //freopen("hihocoder1634.out","w",stdout); 24 int n,m,p; 25 while(scanf("%d%d%d",&n,&m,&p)!=EOF) 26 { 27 for(int i=1;i<=n;i++) 28 for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); 29 memset(s,0,sizeof(s)); 30 for(int i=0;i<=n+1;i++) U[i]=D[i]=-oo; 31 for(int i=0;i<=m+1;i++) L[i]=R[i]=-oo; 32 for(int i=1;i<=n;i++) 33 for(int j=1;j<=m;j++) s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]; 34 int ans=-oo; 35 for(int i=1;i<=n;i++) 36 { 37 int tmp=-oo; 38 for(int j=1;j<=i;j++) 39 { 40 int t=0; 41 for(int k=1;k<=m;k++) 42 { 43 t+=calc(j,k,i,k); 44 tmp=max(tmp,t); 45 if(t<0) t=0; 46 } 47 } 48 U[i]=max(U[i-1],tmp); 49 ans=max(ans,U[i]); 50 } 51 52 for(int i=n;i>=1;i--) 53 { 54 int tmp=-oo; 55 for(int j=i;j<=n;j++) 56 { 57 int t=0; 58 for(int k=1;k<=m;k++) 59 { 60 t+=calc(i,k,j,k); 61 tmp=max(tmp,t); 62 if(t<0) t=0; 63 } 64 } 65 D[i]=max(D[i+1],tmp); 66 } 67 68 for(int i=1;i<=m;i++) 69 { 70 int tmp=-oo; 71 for(int j=1;j<=i;j++) 72 { 73 int t=0; 74 for(int k=1;k<=n;k++) 75 { 76 t+=calc(k,j,k,i); 77 tmp=max(tmp,t); 78 if(t<0) t=0; 79 } 80 } 81 L[i]=max(L[i-1],tmp); 82 } 83 84 for(int i=m;i>=1;i--) 85 { 86 int tmp=-oo; 87 for(int j=m;j>=i;j--) 88 { 89 int t=0; 90 for(int k=1;k<=n;k++) 91 { 92 t+=calc(k,i,k,j); 93 tmp=max(tmp,t); 94 if(t<0) t=0; 95 } 96 } 97 R[i]=max(R[i+1],tmp); 98 } 99 100 int sx=0,sy=0,ex=0,ey=0; 101 for(int i=1;i<=n;i++) 102 for(int j=i;j<=n;j++) 103 { 104 if(sx) break; 105 int tmp=-oo; 106 int t=0; 107 int st=1; 108 for(int k=1;k<=m;k++) 109 { 110 t+=calc(i,k,j,k); 111 tmp=max(tmp,t); 112 if(tmp==ans) 113 { 114 sx=i; ex=j; 115 sy=st; ey=k; 116 break; 117 } 118 if(t<0) 119 { 120 t=0; 121 st=k+1; 122 } 123 } 124 } 125 //printf("ans=%d ",ans); 126 //printf("%d %d %d %d ",sx,sy,ex,ey); 127 int cnt=ans; 128 for(int i=sx;i<=ex;i++) 129 for(int j=sy;j<=ey;j++) cnt=min(cnt,max(ans-a[i][j]+p,max(max(max(U[i-1],D[i+1]),L[j-1]),R[j+1]))); 130 printf("%d ",cnt); 131 } 132 return 0; 133 } 134