1. 程式人生 > 實用技巧 >20200721T2 【NOIP2015模擬10.22】最大子矩陣

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:
33
1410
526
1113
輸入2:
33
131
212
111
輸入3:
56
114033
44971113
-3-142811
1595910
4810588

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 }