[BZOJ 1057][ZJOI 2007]棋盘制作(最大全0/1子矩阵)
2014-12-04 20:08
405 查看
题目链接: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;
}
这题好像很早之前就看到过。。。那时候我还只会玩脚丫子,做这题完全像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;
}
相关文章推荐
- 【BZOJ1057】[ZJOI2007]棋盘制作【最大全0子矩阵】【单调栈】【悬链法】
- bzoj 1057: [ZJOI2007]棋盘制作 求最大全0/1矩阵(极大扩展矩阵)动态规划
- 【BZOJ1057】【ZJOI2007】棋盘制作 最大01子矩阵/正方形
- bzoj1057 [ZJOI2007]棋盘制作
- [bzoj1057][ZJOI2007]棋盘制作
- BZOJ 1057: [ZJOI2007]棋盘制作
- [bzoj1057][ZJOI2007]棋盘制作
- BZOJ1057 [ZJOI2007]棋盘制作(极大化思想)
- 【BZOJ】1057: [ZJOI2007]棋盘制作(单调栈)
- bzoj1057: [ZJOI2007]棋盘制作
- BZOJ1057: [ZJOI2007]棋盘制作
- [BZOJ1057]ZJOI2007棋盘制作|DP|单调栈
- bzoj 1057: [ZJOI2007]棋盘制作
- [BZOJ]1057: [ZJOI2007]棋盘制作
- 【bzoj1057】[ZJOI2007]棋盘制作
- BZOJ 1057 ZJOI 2007 棋盘制作 DP+悬线法
- BZOJ 1057([ZJOI2007]棋盘制作-悬线法)
- BZOJ 1057 [ZJOI2007]棋盘制作
- [bzoj1057][ZJOI2007]棋盘制作
- bzoj 1057: [ZJOI2007]棋盘制作 (dp+悬线法)