# bzoj1057: [ZJOI2007]棋盘制作

dp。方型棋盘不用说，矩形棋盘每个点先维护先上能达到的最大距离v。然后dp找出以自己的v最小时向左向右能达到最大的距离l,r。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 2000 + 10;
int a[maxn][maxn],f[maxn][maxn],v[maxn][maxn],l[maxn][maxn],r[maxn][maxn];
int n,m,res1=0,res2=0;

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)%2) a[i][j]^=1;
//printf("a[%d][%d] = %d\n",i,j,a[i][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
if(i==1&&j==1) f[i][j]=1;
else if(a[i][j]!=a[i][j-1] || a[i][j] != a[i-1][j]) f[i][j]=1;
else f[i][j] = min(f[i-1][j-1],min(f[i-1][j],f[i][j-1]))+1;
res1=max(res1,f[i][j]);
//printf("f[%d][%d] = %d\n",i,j,f[i][j]);
}
printf("%d\n",res1*res1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
if(i==1) v[i][j]=1;
else if(a[i-1][j]!=a[i][j]) v[i][j]=1;
else v[i][j]=v[i-1][j]+1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
if(j==1) l[i][j]=1;
else if(v[i][j]>v[i][j-1] || a[i][j]!=a[i][j-1]) l[i][j]=j;
else {
l[i][j]=l[i][j-1];
while(l[i][j]>1 && v[i][j]<=v[i][l[i][j]-1] && a[i][l[i][j]-1]==a[i][j]) l[i][j]=l[i][l[i][j]-1];
}
}
for(int i=1;i<=n;i++)
for(int j=m;j>=1;j--) {
if(j==m) r[i][j]=m;
else if(v[i][j]>v[i][j+1] || a[i][j] != a[i][j+1]) r[i][j]=j;
else {
r[i][j] = r[i][j+1];
while(r[i][j]<n && v[i][j]<=v[i][r[i][j]+1] && a[i][r[i][j]+1]==a[i][j]) r[i][j]=r[i][r[i][j]+1];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
res2=max(res2,v[i][j]*(r[i][j]-l[i][j]+1));
printf("%d\n",res2);
return 0;
}
posted @ 2016-04-24 09:54  invoid  阅读(170)  评论(0编辑  收藏