[luogu]P1168:[ZJOI2007]棋盘制作
原题链接
分析
题目有两个问题,一个是要求输出最大的正方形面积,另一个为输出最大的矩形面积。
而且问题要求图必须是黑白相间的,我们需要对图进行预处理。
有两种情况。
- 黑格横纵坐标奇偶性相同,白格不同。
- 白格横纵坐标奇偶性相同,黑格不同。
这样我们就可以处理黑白相间的问题了。我们在跑完第一种之后把图反色,重新跑一遍。
先考虑如何求最大正方形。
f[i][j]表示以i,j为右下点的正方形的最大边长。
状态转移方程很显然,我们要从i,j向四周拓展,而最早被卡住的点应该就是他们的最小值
所以
f[i][j]=min{f[i-1][j],f[i][j-1],f[i-1][j-1]}+1;
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=2009;
int n,m,g[Maxn][Maxn],st[Maxn],t=1,f[Maxn][Maxn];
int pos[Maxn],maxn=0,l[Maxn],r[Maxn],ans=0;
void work(){
memset(g,0,sizeof(g));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!f[i][j])continue;
else g[i][j]=f[i][j]+g[i-1][j];
}
}
for(int i=1;i<=n;i++){
memset(l,0,sizeof(l));t=1;
st[t]=g[i][1];pos[t]=1;l[1]=1;
for(int j=2;j<=m;j++){
while(t>0&&st[t]>=g[i][j])t--;
st[++t]=g[i][j];
pos[t]=j;
l[j]=pos[t]-((t>1)?(pos[t-1]):0);
}
memset(r,0,sizeof(r));t=1;
st[t]=g[i][m];pos[t]=m;r[m]=1;
for(int j=m-1;j>=1;j--){
while(t>0&&st[t]>=g[i][j])t--;
st[++t]=g[i][j];
pos[t]=j;
r[j]=((t>1)?(pos[t-1]):m+1)-pos[t];
}
for(int j=1;j<=m;j++)
maxn=max(maxn,g[i][j]*(r[j]+l[j]-1));
}
}
int main()
{
//freopen("data.in","r",stdin);
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin>>f[i][j];
if ((i & 1) == (j & 1) && f[i][j] || (i & 1) != (j & 1) && !f[i][j])
f[i][j]=1;
else f[i][j]=0;
}
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
g[i][j]=(min(min(g[i-1][j],g[i][j-1]),g[i-1][j-1])+1)*f[i][j],
ans=max(ans,g[i][j]);
work();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=1-f[i][j];
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
g[i][j]=(min(min(g[i-1][j],g[i][j-1]),g[i-1][j-1])+1)*f[i][j],
ans=max(ans,g[i][j]);
work();
printf("%d\n%d\n",ans*ans,maxn);
return 0;
}