2017.10.3 国庆清北 D3T3 解迷游戏
题目描述
LYK进了一家古董店,它很想买其中的一幅画。但它带的钱不够买这幅画。
幸运的是,老板正在研究一个问题,他表示如果LYK能帮他解出这个问题的话,就把这幅画送给它。
老板有一个n*m的矩阵,他想找一个和最大的子矩阵,这个子矩阵可以由四个参数x,y,x2,y2(1<=x<=x2<=n,1<=y<=y2<=m)来表示,表示一个左上角为(x,y),右下角为(x2,y2)的矩阵。
为了让游戏更加有趣,老板给了一个常数P,他想将原来这个矩阵中恰好一个数变为P,使得这个矩阵的最大的子矩阵尽可能大。
老板想知道这个最大值是多少。
你能帮帮LYK吗?
输入输出格式
输入格式:
第一行三个数n,m,P。
接下来n行,每行m个数ai,j描述整个矩阵。
输出格式:
输出一个数表示答案。
输入输出样例
输入样例#1:
3 3 3 -100 3 3 3 -4 3 3 3 3
输出样例#1:
20 样例解释 改变左上角那个数。
说明
对于20%的数据n,m<=10。
对于40%的数据n,m<=25。
对于60%的数据n,m<=50。
对于80%的数据n,m<=100。
对于100%的数据1<=n,m<=300,|P|,|ai,j|<=1000。
40分暴力:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /*预处理出二维前缀和,枚举每个矩阵,当前矩阵的元素和tot可以用预处理出来的前缀和算出来,然后找每个矩阵中的最小值minn,如果这个最小值minn小于p,那么就将它改为p,tot=tot-minn+p,否则不改。 Ans=max(ans,tot) 2 时间复杂度O(n^3*m^3)*/ 3 #include<iostream> 4 #include<cmath> 5 #include<cstdio> 6 #include<cstring> 7 #include<algorithm> 8 #include<string> 9 #define N 65 10 using namespace std; 11 12 int n,m,p,ans=-999999999,minn,zuixiao[N][N][N][N]; 13 int sum[N][N],num[N][N],tot; 14 15 inline void read(int &num) 16 { 17 int f=1; 18 char c=getchar(); 19 for(;!isdigit(c);c=getchar()){if(c=='-') f=-1;}; 20 for(;isdigit(c);c=getchar()){num=num*10+c-'0';}; 21 num*=f; 22 } 23 24 inline int _max(int a,int b) 25 { 26 return a>b?a:b; 27 } 28 29 inline int _min(int a,int b) 30 { 31 return a<b?a:b; 32 } 33 34 int main() 35 { 36 freopen("puzzle.in","r",stdin); 37 freopen("puzzle.out","w",stdout); 38 read(n),read(m),read(p); 39 for(int i=1;i<=n;i++) 40 { 41 for(int j=1;j<=m;j++) 42 { 43 read(num[i][j]); 44 } 45 } 46 for(int i=1;i<=n;i++) 47 { 48 for(int j=1;j<=m;j++) 49 { 50 sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+num[i][j]; 51 } 52 } 53 for(int i=1;i<=n;i++) 54 { 55 for(int j=1;j<=m;j++) 56 { 57 for(int k=i;k<=n;k++) 58 { 59 for(int l=j;l<=m;l++) 60 { 61 tot=sum[k][l]-sum[i-1][l]-sum[k][j-1]+sum[i-1][j-1]; 62 minn=999999999; 63 for(int a=i;a<=k;a++) 64 { 65 for(int b=j;b<=l;b++) 66 { 67 minn=_min(minn,num[a][b]); 68 } 69 } 70 if(minn<p) tot=tot-minn+p; 71 ans=_max(ans,tot); 72 } 73 } 74 } 75 } 76 printf("%d",ans); 77 fclose(stdin); 78 fclose(stdout); 79 return 0; 80 }
正解:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 n^2前缀和+n^2预处理矩阵最小值+n^3求解 3 复杂度 O(n^3) 4 */ 5 #include<iostream> 6 #include<cstdio> 7 #include<cmath> 8 #include<cstring> 9 #include<algorithm> 10 #define N 305 11 #define INF -999999999 12 using namespace std; 13 14 int n,m,ans,p; 15 int a[N][N],b[N],minn[N],dp[N][2],sum[N][N]; 16 17 int main() 18 { 19 scanf("%d",&n); 20 ans=INF; 21 scanf("%d%d",&m,&p); 22 for(int i=1;i<=n;i++) 23 { 24 for(int j=1;j<=m;j++) 25 { 26 scanf("%d",&a[i][j]); 27 } 28 } 29 for(int i=1;i<=n;i++) 30 { 31 for(int j=1;j<=m;j++) 32 { 33 sum[i][j]=sum[i-1][j]+a[i][j]; 34 } 35 } 36 for(int i=1;i<=n;i++) 37 { 38 for(int j=1;j<=m;j++) minn[j]=a[i][j]; 39 for(int j=i;j<=n;j++) 40 { 41 for(int k=1;k<=m;k++) minn[k]=min(minn[k],a[j][k]); 42 for(int k=1;k<=m;k++) b[k]=sum[j][k]-sum[i-1][k]; 43 dp[0][1]=INF; 44 for(int k=1;k<=m;k++) 45 { 46 dp[k][0]=max(dp[k-1][0]+b[k],b[k]); 47 dp[k][1]=max(max(dp[k-1][1]+b[k],dp[k-1][0]+b[k]-minn[k]+p),b[k]-minn[k]+p); 48 } 49 for(int k=1;k<m;k++) ans=max(ans,max(dp[k][0],dp[k][1])); 50 if(i==1&&j==n) 51 { 52 ans=max(ans,dp[m][1]); 53 int sum=0; 54 for(int k=m;k>1;k--) 55 { 56 sum+=b[k]; 57 ans=max(ans,sum); 58 } 59 } 60 else ans=max(ans,max(dp[m][0],dp[m][1])); 61 } 62 } 63 printf("%d\n",ans); 64 return 0; 65 }