(luogu)
悬线的定义是这样的:
从每一个点向上走,知道遇到障碍点或顶边界。
那么我们可以轻松地得到悬线的一些性质:
- 每一个点对应一根悬线
- 每一根悬线都对应了一个高度等于悬线高度,宽度大于0的矩形
所以悬线法的步骤就是:找出每一个点对应的悬线的高度,然后向左右分别找出该悬线能拓展出的矩形的宽度。
题面:
小Q
找到了一张由N×M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一。
小Q
想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。
当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色,
所以他希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。
棋盘制作
#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; int n,m; const int N=2003; int d[N][N]; int ll[N][N],rr[N][N],up[N][N]; int main() { //输入 scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&d[i][j]), up[i][j]=1,ll[i][j]=rr[i][j]=j; //悬线法 for(int i=1;i<=n;i++) for(int j=2;j<=m;j++) if(d[i][j]^d[i][j-1]) ll[i][j]=ll[i][j-1]; for(int i=1;i<=n;i++) for(int j=m-1;j;j--) if(d[i][j]^d[i][j+1]) rr[i][j]=rr[i][j+1]; for(int j=1;j<=m;j++) for(int i=2;i<=n;i++) if(d[i][j]^d[i-1][j]) up[i][j]=up[i-1][j]+1, ll[i][j]=max(ll[i][j],ll[i-1][j]), rr[i][j]=min(rr[i][j],rr[i-1][j]); //统计答案 int s1=0,s2=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { int len=rr[i][j]-ll[i][j]+1; s1=max(s1,min(len,up[i][j])); s2=max(s2,len*up[i][j]); } printf("%d %d ",s1*s1,s2); return 0; }