题面:BZOJ1057 洛谷1169
首先显然发现合法棋盘的格子,与其相邻的格子全部与它不同色
那么我们可以预处理一下,把它们转成同色
是这样的
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
if((i+j)&1)a[i][j]^=1;//如果横纵坐标和是奇数(偶数也可以)反转颜色
}
这样就变成了求最大同色子矩阵了
我们用单调栈来维护一下,首先维护s[i][j]表示以s[i][j]为头的行内最长同色长度
然后维护一个以s为关键字单调递减的栈,同时记录一下这个属于第几行
每次弹栈时统计答案即可,正方形就是min(现元素与栈顶的行数之差,s[i][j])的平方
矩形就是两个乘起来,ans取最大
#include<bits/stdc++.h>
using namespace std;
struct ppap{int x,k;}s[2001];
int n,m,a[2001][2001],b[2001][2001],ans1,ans2,sum=0;
inline int sqr(int x){return x*x;}
inline void work(int k,int x){
int p=k;
for(;sum&&s[sum].x>x;k=s[sum--].k){
ans2=max(ans2,(p-s[sum].k)*s[sum].x);
ans1=max(ans1,sqr(min(p-s[sum].k,s[sum].x)));
}
s[++sum].k=k;s[sum].x=x;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
if((i+j)&1)a[i][j]^=1;
}
memset(b,0,sizeof b);
for(int i=1;i<=n;i++)
for(int j=m;j;j--)b[i][j]=a[i][j]?b[i][j+1]+1:0;
for(int j=1;j<=m;j++){
work(n+1,0);sum=0;
for(int i=1;i<=n;i++)work(i,b[i][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)a[i][j]^=1;
memset(b,0,sizeof b);
for(int i=1;i<=n;i++)
for(int j=m;j;j--)b[i][j]=a[i][j]?b[i][j+1]+1:0;
for(int j=1;j<=m;j++){
work(n+1,0);sum=0;
for(int i=1;i<=n;i++)work(i,b[i][j]);
}
printf("%d\n%d",ans1,ans2);
return 0;
}