棋盘制作[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表示黑色)。
输出格式:
包含两行,每行包含一个整数。第一行为可以找到的最大正方形棋盘的面积,第二行为可以找到的最大矩形棋盘的面积(注意正方形和矩形是可以相交或者包含的)。
输入输出样例
说明
对于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贴下去的=-=)