1057: [ZJOI2007]棋盘制作

1057: [ZJOI2007]棋盘制作

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 2398  Solved: 1191
[Submit][Status][Discuss]

Description

  国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源

于易经的思想,棋盘是一个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

Sample Output

4
6

HINT

N, M ≤ 2000

思路:单调栈;

只要将(i+j)%2==0,的方格反转下,就转变为求最大子矩阵的问题,用单调栈维护下就行,复杂度(n*m);

  1 #include<stdio.h>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<string.h>
  5 #include<queue>
  6 #include<deque>
  7 #include<stack>
  8 #include<math.h>
  9 using namespace std;
 10 int ma[3000][3000];
 11 int a[3000][3000];
 12 int b[3000][3000];
 13 stack<int>stac;
 14 int R[3000];
 15 int L[3000];
 16 int main(void)
 17 {
 18     int n,m;
 19     int i,j;
 20     scanf("%d %d",&n,&m);
 21     {
 22         memset(a,0,sizeof(a));
 23         memset(b,0,sizeof(b));
 24         for(i = 1; i <= n; i++)
 25         {
 26             for(j = 1; j <= m; j++)
 27             {
 28                 scanf("%d",&ma[i][j]);
 29             }
 30         }
 31         for(i = 1; i <= n; i++)
 32         {
 33             for(j = 1; j <= m; j++)
 34             {
 35                 if((i+j)%2)
 36                 {
 37                     ma[i][j]+=1;
 38                     ma[i][j]%=2;
 39                 }
 40                 //printf("%d ",ma[i][j]);
 41             }//printf("\n")
 42         }
 43         for(i = 1; i <= n; i++)
 44         {
 45             for(j = 1; j <= m; j++)
 46             {
 47                 if(ma[i][j])
 48                 {
 49                     a[i][j] = a[i][j-1]+1;
 50                 }
 51                 if(!ma[i][j])
 52                 {
 53                     b[i][j] = b[i][j-1]+1;
 54                 }
 55             }
 56         }
 57         int maxx = 0;
 58         int maxxx = 0;
 59         for(j = 1; j <= m; j++)
 60         {
 61             while(!stac.empty())
 62             {
 63                 stac.pop();
 64             }
 65             for(i = 1; i <= n; i++)
 66             {
 67                 if(stac.empty())
 68                 {
 69                     L[i] = 1;
 70                     stac.push(i);
 71                 }
 72                 else
 73                 {
 74                     while(!stac.empty())
 75                     {
 76                         int x = stac.top();
 77                         if(a[i][j] < a[x][j])
 78                         {
 79                             R[x] = i-1;
 80                             stac.pop();
 81                         }
 82                         else break;
 83                     }
 84                     if(stac.empty())
 85                     {
 86                         L[i] = 1;
 87                         stac.push(i);
 88                     }
 89                     else
 90                     {
 91                         L[i] = stac.top()+1;
 92                         stac.push(i);
 93                     }
 94                 }
 95             }
 96             while(!stac.empty())
 97             {
 98                 int x= stac.top();
 99                 stac.pop();
100                 R[x] = n;
101             }
102             for(i = 1; i <= n; i++)
103             {
104                 maxx = max(maxx,(R[i]-L[i]+1)*a[i][j]);
105                 maxxx = max(maxxx,min((R[i]-L[i]+1),a[i][j])*min((R[i]-L[i]+1),a[i][j]));
106             }
107         }
108         for(j = 1; j <= m; j++)
109         {
110             while(!stac.empty())
111             {
112                 stac.pop();
113             }
114             for(i = 1; i <= n; i++)
115             {
116                 if(stac.empty())
117                 {
118                     L[i] = 1;
119                     stac.push(i);
120                 }
121                 else
122                 {
123                     while(!stac.empty())
124                     {
125                         int x = stac.top();
126                         if(b[i][j] <= b[x][j])
127                         {
128                             R[x] = i-1;
129                             stac.pop();
130                         }
131                         else break;
132                     }
133                     if(stac.empty())
134                     {
135                         L[i] = 1;
136                         stac.push(i);
137                     }
138                     else
139                     {
140                         L[i] = stac.top()+1;
141                         stac.push(i);
142                     }
143                 }
144             }
145             while(!stac.empty())
146             {
147                 int x= stac.top();
148                 stac.pop();
149                 R[x] = n;
150             }
151             for(i = 1; i <= n; i++)
152             {
153                 maxx = max(maxx,(R[i]-L[i]+1)*b[i][j]);
154                 maxxx = max(maxxx,min((R[i]-L[i]+1),b[i][j])*min((R[i]-L[i]+1),b[i][j]));
155             }
156         }
157         printf("%d\n",maxxx);
158         printf("%d\n",maxx);
159     }
160     return 0;
161 }
时间: 2024-08-11 03:37:51

1057: [ZJOI2007]棋盘制作的相关文章

BZOJ 1057: [ZJOI2007]棋盘制作 悬线法求最大子矩阵+dp

1057: [ZJOI2007]棋盘制作 Description 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳.而我们的主人公小Q,正是国际象棋的狂热爱好者.作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则.小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一.小Q想在这种纸中裁减

BZOJ 1057: [ZJOI2007]棋盘制作( dp + 悬线法 )

对于第一问, 简单的dp. f(i, j)表示以(i, j)为左上角的最大正方形, f(i, j) = min( f(i + 1, j), f(i, j + 1), f(i + 1, j + 1)) + 1 (假如(i, j)和右边和下边不冲突) 第二问就是经典的悬线法解决最大子矩阵了, 维护悬线H[i][j], 左边右边延伸的最长距离.先一行一行求出这一行的L, R, 然后再从上往下扫, 维护H, L, R 写完我才发现我脑残了...最大的正方形一定是在最大子矩阵里面啊...所以其实不用dp.

BZOJ 1057: [ZJOI2007]棋盘制作

Decsription 给你一个矩阵,求最大了 01相间 的矩阵. Sol DP+悬线法. 这是一个论文啊 <浅谈用极大化思想解决最大子矩形问题>--王知昆. 枚举每一根悬线,记录最左/右/上能到达的点,统计答案. Code /************************************************************** Problem: 1057 User: BeiYu Language: C++ Result: Accepted Time:1384 ms Me

BZOJ 1057 ZJOI2007 棋盘制作 单调栈

题目大意:给定一个黑白两色的矩阵,求最大的黑白相间的子正方形和子矩阵 将奇数位置的点反色,然后就是求纯色的最大子正方形和子矩阵 将矩阵一层层剖分,每层上方是一段类似于▆▃▇▂▉的东西,用单调栈跑出每个点向左向右能拓展到的最大距离,更新答案即可 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 2020 using namespace

BZOJ 1057 [ZJOI2007]棋盘制作 最大子矩阵

题意:链接 方法:最大子矩阵 解析: 这题很水- - 显然最大子正方形是在最大子矩阵之中的,所以没有什么卵区别.极大子矩阵的较小边长即为极大子正方形的边长,最长边长的极大子正方形即为最大子正方形. 然后呢,这题有个小小的区别,就是他要黑白相间的?- - 有什么区别呢?并没有,只需要求le,ri的时候改一下判断就OK了,非常的水. 代码: #include <cstdio> #include <cstring> #include <iostream> #include &

【BZOJ 1057】 [ZJOI2007]棋盘制作

1057: [ZJOI2007]棋盘制作 Time Limit: 20 Sec  Memory Limit: 162 MB Submit: 1496  Solved: 753 [Submit][Status] Description 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳.而我们的主人公小Q,正是国际象棋的狂热爱好者.作为一个顶尖高手,他已不满足于普通的棋盘

bzoj1057: [ZJOI2007]棋盘制作

一直想不通为什么最后要push(i+1,0)然后发现没有被pop掉的肯定没有被计算过.所以最后是来计算这些的... #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>

BZOJ1057 [ZJOI2007]棋盘制作(极大化思想)

1057: [ZJOI2007]棋盘制作 Time Limit: 20 Sec  Memory Limit: 162 MB Submit: 1848  Solved: 936 [Submit][Status][Discuss] Description 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳.而我们的主人公小Q,正是国际象棋的狂热爱好者.作为一个顶尖高手,他已

洛谷 P1169 [ZJOI2007]棋盘制作

2016-05-31 14:56:17 题目链接: 洛谷 P1169 [ZJOI2007]棋盘制作 题目大意: 给定一块矩形,求出满足棋盘式黑白间隔的最大矩形大小和最大正方形大小 解法: 神犇王知昆的悬线法 论文:浅谈用极大化思想解决最大子矩形问题 H[i][j]表示(i,j)向上最长连续多少距离不出现障碍点(悬线) L[i][j]表示H[i][j]这根悬线最多可以向左移到什么位置 R[i][j]表示H[i][j]这根悬线最多可以向右移到什么位置 递推方式看代码吧,很好理解的 1 //棋盘制作