20200721T2 【NOIP2015模拟10.22】最大子矩阵
Description
我们将矩阵A中位于第i行第j列的元素记作A[i,j]。一个矩阵A是酷的仅当它满足下面的条件:
A[1,1]+A[r,s]<=A[1,s]+A[r,1](r,s>1)
其中r为矩阵A的行数,s为矩阵A的列数。
进一步,如果一个矩阵是非常酷的仅当它的每一个至少包含两行两列子矩阵都是酷的。
你的任务是,求出一个矩阵A中的一个非常酷的子矩阵B,使得B包含最多元素。
Input
第一行包含两个整数R,S(2<=R,S<=1000),代表矩阵的行数与列数。
接下来R行每行包括S个整数,代表矩阵中的元素,矩阵中元素的绝对值不大于1000000。
Output
一行一个整数,代表子矩阵B的元素总数。如果没有一个非常酷的子矩阵,输出0。
Sample Input
输入1:
3 3
1 4 10
5 2 6
11 1 3
输入2:
3 3
1 3 1
2 1 2
1 1 1
输入3:
5 6
1 1 4 0 3 3
4 4 9 7 11 13
-3 -1 4 2 8 11
1 5 9 5 9 10
4 8 10 5 8 8
Sample Output
输出1:
9
输出2:
4
输出3:
15
【样例3解释】
在第三个样例中,子矩阵B的左上角为A[3,2],右下角为A[5,6]。
Data Constraint
对于60%的数据,满足R,S<=350。
对于100%的数据,满足2<=R,S<=1000,矩阵中元素的绝对值不大于1000000。
solution
第一眼就像是悬线法,但再一看又不太好处理
想办法把它转化成悬线法 1100 的亚子
可以发现,两个酷的矩阵合并起来还是酷的矩阵
证明
a |
c |
e |
b |
d |
f |
a + d <= b + c
c + f <= d + e
相加得到 a + f <= b + e
证毕
那我们就可以把每个最小的2*2的矩阵缩为一点,是酷的矩阵为1,不是为0,跑一遍悬线法即可
code
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<queue> 7 #include<vector> 8 #include<stack> 9 #include<set> 10 #include<deque> 11 #include<map> 12 using namespace std; 13 14 template <typename T> void read(T &x) { 15 x = 0; int f = 1; char c; 16 for (c = getchar(); c < '0' || c > '9'; c = getchar()) if (c == '-') f = -f; 17 for (; c >= '0' && c <= '9'; c = getchar()) x = 10 * x + c - '0' ; 18 x *= f; 19 } 20 template <typename T> void write(T x){ 21 if (x < 0) putchar('-'), x = -x; 22 if (x > 9) write(x / 10); 23 putchar(x % 10 + '0'); 24 } 25 template <typename T> void writeln(T x) { write(x); putchar('\n'); } 26 template <typename T> void writesn(T x) { write(x); putchar(' '); } 27 28 #define ll long long 29 #define inf 1234567890 30 #define next net 31 #define left zjytql 32 #define right mlgtql 33 #define P 1000000007 34 #define N 1010 35 #define mid ((l+r)>>1) 36 #define lson (o<<1) 37 #define rson (o<<1|1) 38 #define R register 39 40 int n,m ,ans; 41 int a[N ][N ],b[N ][N ],left[N ][N ],right[N ][N ],up[N ][N ]; 42 void into() 43 { 44 read(n);read(m ); 45 for(R int i = 1; i <= n; i++) 46 for(R int j = 1; j <= m; j++) 47 read(a[i][j]); 48 for(R int i = 1; i < n; i++) 49 for(R int j = 1; j < m; j++) 50 { 51 b[i][j] = (a[i][j] + a[i+1][j+1] <= a[i+1][j] + a[i][j+1]); 52 up[i][j]=1; 53 left[i][j]=right[i][j]=j; 54 } 55 } 56 void work() 57 { 58 for(R int i = 1; i < n; i++) 59 for(R int j = 2; j < m ; j++) 60 if(b[i][j] && b[i][j-1])left[i][j] = left[i][j-1]; 61 for(R int i = 1; i < n; i++) 62 for(R int j = m - 1; j >= 1; j--) 63 if(b[i][j] && b[i][j+1])right[i][j] = right[i][j+1]; 64 for(R int i = 2; i < n; i++) 65 for(R int j = 1; j < m ; j++) 66 if(b[i][j] && b[i-1][j]) 67 { 68 up[i][j] = up[i-1][j]+1; 69 left[i][j] = max(left[i][j],left[i-1][j]); 70 right[i][j] = min(right[i][j],right[i-1][j]); 71 } 72 for(R int i = 1; i < n; i++) 73 for(R int j = 1; j < m ; j++) 74 if(b[i][j]) 75 { 76 ans = max(ans,(up[i][j]+1)*(right[i][j]-left[i][j]+2)); 77 } 78 writeln(ans); 79 } 80 signed main() 81 { 82 into(); 83 work(); 84 return 0; 85 }