1057: [ZJOI2007]棋盘制作

1057: [ZJOI2007]棋盘制作

https://www.lydsy.com/JudgeOnline/problem.php?id=1057

分析:

  首先对于(i+j)&1的位置0->1,1->0,然后就是求一遍最大全1子矩形。然后套用悬线法就可以了。

  悬线法:处理出每个点向上的最大高度(悬线),然后处理出这条线往左往右的最大距离。  

  单调栈好像也可以做。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 using namespace std;
 7 typedef long long LL;
 8 
 9 inline int read() {
10     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
11     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
12 }
13 
14 const int N = 2010;
15 
16 int h[N][N], L[N][N], R[N][N], a[N][N];
17 int n, m;
18 LL ans1, ans2;
19 
20 LL sqr(int x) {
21     return 1ll * x * x;
22 }
23 void solve(int f) {
24     memset(h, 0, sizeof(h));
25     memset(L, 0, sizeof(L));
26     memset(R, 0x3f, sizeof(R));
27     for (int i=1; i<=n; ++i) {
28         int last = 0;
29         for (int j=1; j<=m; ++j) {
30             if (a[i][j] == f) 
31                 h[i][j] = h[i-1][j] + 1, L[i][j] = max(L[i-1][j], last);
32             else h[i][j] = 0, last = j;
33         }
34         last = m + 1;
35         for (int j=m; j>=1; --j) {
36             if (a[i][j] == f) {
37                 R[i][j] = min(R[i-1][j], last-1); 
38                 ans1 = max(ans1, sqr(min(h[i][j], R[i][j] - L[i][j])));
39                 ans2 = max(ans2, 1ll * h[i][j] * (R[i][j] - L[i][j]));
40             }
41             else last = j;
42         }
43     }
44 }
45 int main() {
46     n = read(), m = read();
47     for (int i=1; i<=n; ++i) {
48         for (int j=1; j<=m; ++j) {
49             a[i][j] = read();
50             if ((i + j) & 1) a[i][j] ^= 1;
51         }
52     }
53     solve(1), solve(0);
54     cout << ans1 << "
" << ans2;
55     return 0;
56 }
原文地址:https://www.cnblogs.com/mjtcn/p/9605661.html