AmazingCounters.com
随笔- 138  评论- 7  文章- 0 

[BZOJ]1057: [ZJOI2007]棋盘制作

FallDream dalao随手切 赶紧上他博客学习了一个。

 

题目大意:给出一个n*m的01矩阵,求最大的子正方形/矩形,满足任意相邻格子不同。(n,m<=2000)

思路:把行列坐标相加为偶数的异或上1,题目变成求最大的全为0或1的子正方形/矩形,我们分别处理,预处理出每个格子向右有多少连续的0/1,枚举列,用个单调栈维护和统计答案(维护上升序列),复杂度O(nm)。

#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
    int x;char c;
    while((c=getchar())<'0'||c>'9');
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
    return x;
}
#define MN 2000
int n,m,a[MN+5][MN+5],f[MN+5][MN+5],ans1,ans2,q[MN+5],qx[MN+5],qn;
inline int sqr(int x){return x*x;}
void solve(int x)
{
    int i,j;
    for(i=1;i<=n;++i)for(j=m;j;--j)f[i][j]=a[i][j]==x?f[i][j+1]+1:0;
    for(i=1;i<=m;++i)for(j=qn=0;j++<=n;qx[++qn]=f[j][i])
        for(q[qn+1]=j;qn&&f[j][i]<qx[qn];--qn)
            ans1=max(ans1,sqr(min(j-q[qn],qx[qn]))),
            ans2=max(ans2,(j-q[qn])*qx[qn]);
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)a[i][j]=read()^((i+j)&1);
    solve(0);solve(1);
    printf("%d\n%d",ans1,ans2);
}

 

posted on 2017-03-14 08:31  ditoly  阅读(...)  评论(... 编辑 收藏