bzoj 1057[ZJOI2007]棋盘制作 - 垂线法
1057: [ZJOI2007]棋盘制作
Time Limit: 20 Sec Memory Limit: 162 MBDescription
国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源
于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳。而我们的主人公小Q,
正是国际象棋的狂热爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定
将棋盘扩大以适应他们的新规则。小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种
颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。不过小Q还没有决定是找
一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他
希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。于是小Q找到了即将参加全
国信息学竞赛的你,你能帮助他么?
Input
第一行包含两个整数N和M,分别表示矩形纸片的长和宽。接下来的N行包含一个N * M的01矩阵,表示这张矩形
纸片的颜色(0表示白色,1表示黑色)。
Output
包含两行,每行包含一个整数。第一行为可以找到的最大正方形棋盘的面积,第二行为可以找到的最大矩形棋
盘的面积(注意正方形和矩形是可以相交或者包含的)。
Sample Input
3 3
1 0 1
0 1 0
1 0 0
1 0 1
0 1 0
1 0 0
Sample Output
4
6
6
HINT
N, M ≤ 2000
首先有一个很奇妙的变换, 因为题目要求的是黑白相间的,我们对 横坐标与纵坐标和为偶数的格子颜色取反
这样题目就转化为了颜色相同
我们可以n * m 的时间预处理出 le[i][j] 和 ri[i][j] (分别表示 在第 i 行 第 j 列的格子向左和向右延伸所有格子颜色相同的最远处)
然后对于每列从上往下扫
l[i][j] = min(l[i - 1][j], le[i][j]), r[i][j] = min(r[i - 1][j], ri[i][j])
表示当前这个上边界固定的矩形最左端和最右端
如果一个矩形的面积是最大的,它的上边界一定会触碰到一个障碍,所以从每个障碍往下计算一定不会漏解
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define LL long long 6 7 using namespace std; 8 9 const int MAXN = 2e3 + 10; 10 int N, M; 11 int ans1 = 0, ans2 = 0; 12 int map[MAXN][MAXN]; 13 int le[MAXN][MAXN], ri[MAXN][MAXN], h[MAXN][MAXN]; 14 int l[MAXN][MAXN], r[MAXN][MAXN]; 15 inline LL read() 16 { 17 LL x = 0, w = 1; char ch = 0; 18 while(ch < '0' || ch > '9') { 19 if(ch == '-') { 20 w = -1; 21 } 22 ch = getchar(); 23 } 24 while(ch >= '0' && ch <= '9') { 25 x = x * 10 + ch - '0'; 26 ch = getchar(); 27 } 28 return x * w; 29 } 30 31 void work(int x) 32 { 33 for(int i = 1; i <= N; i++) { 34 int last = 0; 35 for(int j = 1; j <= M; j++) { 36 if(map[i][j] == x) { 37 last = j; 38 } 39 le[i][j] = last; 40 } 41 last = M + 1; 42 for(int j = M; j >= 1; j--) { 43 if(map[i][j] == x) { 44 last = j; 45 } 46 ri[i][j] = last; 47 } 48 } 49 /*for(int i = 1; i <= N; i++) { 50 for(int j = 1; j <= M; j++) { 51 cout<<le[i][j]<<" "<<ri[i][j]<<" "; 52 } 53 cout<<endl; 54 } 55 cout<<endl<<endl;*/ 56 for(int j = 1; j <= M; j++) { 57 r[0][j] = M + 1; 58 } 59 for(int j = 1; j <= M; j++) { 60 for(int i = 1; i <= N; i++) { 61 if(map[i][j] == x) { 62 h[i][j] = 0; 63 l[i][j] = 0, r[i][j] = M + 1; 64 } else { 65 h[i][j] = h[i - 1][j] + 1; 66 l[i][j] = max(le[i][j], l[i - 1][j]); 67 r[i][j] = min(ri[i][j], r[i - 1][j]); 68 int w = r[i][j] - l[i][j] - 1; 69 //cout<<h[i][j]<<" "<<l[i][j]<<" "<<r[i][j]<<" "; 70 ans1 = max(ans1, min(w, h[i][j]) * min(w, h[i][j])); 71 ans2 = max(ans2, h[i][j] * w); 72 } 73 } 74 //cout<<endl; 75 } 76 //cout<<endl; 77 } 78 int main() 79 { 80 N = read(), M = read(); 81 for(int i = 1; i <= N; i++) { 82 for(int j = 1; j <= M; j++) { 83 map[i][j] = read(); 84 if((i + j) % 2 == 0) { 85 map[i][j] = map[i][j] ^ 1; 86 } 87 } 88 } 89 /*for(int i = 1; i <= N; i++) { 90 for(int j = 1; j <= M; j++) { 91 cout<<map[i][j]<<" "; 92 } 93 cout<<endl; 94 }*/ 95 work(1); 96 work(0); 97 printf("%d\n%d\n", ans1, ans2); 98 return 0; 99 } 100 101 102 /* 103 104 3 3 105 1 0 1 106 0 1 0 107 1 0 0 108 109 110 */