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 }

 

posted @ 2020-07-21 19:34  e_e_thinker  阅读(183)  评论(0编辑  收藏  举报