首页 > 代码库 > [BZOJ 1057][ZJOI 2007]棋盘制作(最大全0/1子矩阵)
[BZOJ 1057][ZJOI 2007]棋盘制作(最大全0/1子矩阵)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1057
这题好像很早之前就看到过。。。那时候我还只会玩脚丫子,做这题完全像SB一样,记得那时我做了一会就放弃了。
如今看到这题感觉好做多了,此题预处理很巧妙,我们看一个棋盘,它的所有黑点的行标奇偶性都相同,列标的奇偶性也都相同。白点一样。
于是我们就可以预处理下,对于所有行标和列标奇偶性相同的点,保持它们的颜色不变,奇偶性不相同的点,反转它们的颜色,于是预处理后,我们要找的矩形在整个大棋盘中的颜色一定是一样的。
然后直接套用最大全0/1子矩阵就OK了。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #define MAXN 2200 using namespace std; int n,m; int map[MAXN][MAXN]; int h[MAXN],l[MAXN],r[MAXN]; int work1(int clr) //求最大全clr色的子矩阵(必须是正方形) { int maxSqr=0; memset(h,0,sizeof(h)); memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(map[i][j]==clr) h[j]++; else h[j]=0; } for(int j=1;j<=m;j++) { l[j]=j; while(l[j]>1&&h[l[j]-1]>=h[j]) l[j]=l[l[j]-1]; } for(int j=m;j>=1;j--) { r[j]=j; while(r[j]<m&&h[r[j]+1]>=h[j]) r[j]=r[r[j]+1]; } for(int j=1;j<=m;j++) { int nowsqr=min(h[j],r[j]-l[j]+1); nowsqr*=nowsqr; if(nowsqr>maxSqr) maxSqr=nowsqr; } } return maxSqr; } int work2(int clr) //求最大全clr色的子矩阵(不限于正方形) { int maxSqr=0; memset(h,0,sizeof(h)); memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(map[i][j]==clr) h[j]++; else h[j]=0; } for(int j=1;j<=m;j++) { l[j]=j; while(l[j]>1&&h[l[j]-1]>=h[j]) l[j]=l[l[j]-1]; } for(int j=m;j>=1;j--) { r[j]=j; while(r[j]<m&&h[r[j]+1]>=h[j]) r[j]=r[r[j]+1]; } for(int j=1;j<=m;j++) { if(h[j]*(r[j]-l[j]+1)>maxSqr) maxSqr=h[j]*(r[j]-l[j]+1); } } return maxSqr; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int clr; scanf("%d",&clr); if(i%2==j%2) map[i][j]=clr; else map[i][j]=1-clr; } printf("%d\n%d\n",max(work1(1),work1(0)),max(work2(1),work2(0))); return 0; }
[BZOJ 1057][ZJOI 2007]棋盘制作(最大全0/1子矩阵)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。