[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); }