棋盘制作[ZJOI2007]

  题目传送门:https://www.luogu.org/problemnew/show/P1169

 

题目描述

国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳。

而我们的主人公小Q,正是国际象棋的狂热爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则。

小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。

不过小Q还没有决定是找一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。

于是小Q找到了即将参加全国信息学竞赛的你,你能帮助他么?

输入输出格式

输入格式:

 

包含两个整数N和M,分别表示矩形纸片的长和宽。接下来的N行包含一个N * M的01矩阵,表示这张矩形纸片的颜色(0表示白色,1表示黑色)。

 

输出格式:

 

包含两行,每行包含一个整数。第一行为可以找到的最大正方形棋盘的面积,第二行为可以找到的最大矩形棋盘的面积(注意正方形和矩形是可以相交或者包含的)。

 

输入输出样例

输入样例#1: 
3 3
1 0 1
0 1 0
1 0 0
输出样例#1: 
4
6

说明

对于20%的数据,N, M ≤ 80

对于40%的数据,N, M ≤ 400

对于100%的数据,N, M ≤ 2000

 

 题解:

  第一眼这题只会暴力qwq

  正方形复杂度O(n^5),矩形O(n^6)。这是裸暴力,剪枝剪得好会快很多。

 正解:

  先分类讨论棋盘情况,一种是左上角为1时,剩下棋盘的合法情况;另一种是左上角为0时,剩下棋盘的合法情况。这么做有什么好处呢?

  这样的话就可以看做是一个n*m的格子上有若干个障碍点,问最大不覆盖障碍点的子矩形大小。

  那这不就跟玉蟾宫这道题一模一样了吗qwq

  至于正方形,也可以类比矩形来做,具体留给大家思考。(或者看下面的代码qaq

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stack>
 6 #define LL long long
 7 #define RI register int
 8 using namespace std;
 9 const int INF = 0x7ffffff ;
10 const int N = 2000 + 10 ;
11 
12 inline int read() {
13     int k = 0 , f = 1 ; char c = getchar() ;
14     for( ; !isdigit(c) ; c = getchar())
15       if(c == '-') f = -1 ;
16     for( ; isdigit(c) ; c = getchar())
17       k = k*10 + c-'0' ;
18     return k*f ;
19 }
20 int n, m, aans = 0, ans = 0 ; int pos[N][N], hh[N][N], l[N] ;
21 
22 inline void solve(int now) {
23     stack<int>s ;
24     for(int i=1;i<=m;i++) {
25         while(s.size() && pos[now][s.top()] >= pos[now][i]) {
26             ans = max(ans,pos[now][s.top()]*(i-l[s.top()]-1)) ;
27             if((i-l[s.top()]-1) >= pos[now][s.top()]) aans = max(aans,pos[now][s.top()]*pos[now][s.top()]) ;
28             s.pop() ;
29         } 
30         if(s.size()) l[i] = s.top() ; else l[i] = 0 ; 
31         s.push(i) ;
32     }
33     while(s.size()) {
34         ans = max(ans,pos[now][s.top()]*(m-l[s.top()])) ;
35         if(m-l[s.top()] >= pos[now][s.top()]) aans = max(aans,pos[now][s.top()]*pos[now][s.top()]) ;
36         s.pop() ;
37     } 
38 }
39 
40 inline void solve1() {
41     for(int i=1;i<=n;i++) {
42         for(int j=1;j<=m;j++) 
43           if(!hh[i][j]) pos[i][j] = 0 ;  else pos[i][j] = pos[i-1][j]+1 ;
44     }
45     for(int i=1;i<=n;i++) solve(i) ;
46 }
47 
48 inline void solve2() {
49     for(int i=1;i<=n;i++) {
50         for(int j=1;j<=m;j++) hh[i][j] ^= 1 ;
51     }
52     for(int i=1;i<=n;i++) {
53         for(int j=1;j<=m;j++) 
54           if(!hh[i][j]) pos[i][j] = 0 ;  else pos[i][j] = pos[i-1][j]+1 ;
55     }
56     for(int i=1;i<=n;i++) solve(i) ;    
57 }
58 
59 int main() {
60     n = read(), m = read() ;
61     for(int i=1;i<=n;i++)
62       for(int j=1;j<=m;j++) {
63            bool x = read() ;
64            if(!((i+j)&1) && x) hh[i][j] = 1 ;
65            else if((i+j)&1 && !x) hh[i][j] = 1 ;
66       }
67     solve1() ;
68     solve2() ;
69     printf("%d\n%d",aans,ans) ;
70     return 0 ;
71 }

 几个错误:

  •    第34、35行那里又用n去减了=-=,第二次了qwq
  •   solve1里发现个错误,结果solve2里没改...(solve1就是solve2贴下去的=-=) 
posted @ 2018-04-08 19:57  zubizakeli  阅读(152)  评论(0编辑  收藏  举报