【題解】[ZJOI2007]棋盤製作
題目描述
國際象棋是世界上最古老的博弈遊戲之一,和中國的圍棋、象棋以及日本的將棋同享盛名。據說國際象棋起源於易經的思想,棋盤是一個 8 × 8 8 \times 8 8×8 大小的黑白相間的方陣,對應八八六十四卦,黑白對應陰陽。
而我們的主人公小Q,正是國際象棋的狂熱愛好者。作為一個頂尖高手,他已不滿足於普通的棋盤與規則,於是他跟他的好朋友小W決定將棋盤擴大以適應他們的新規則。
小Q找到了一張由 N × M N \times M N×M 個正方形的格子組成的矩形紙片,每個格子被塗有黑白兩種顏色之一。小Q想在這種紙中裁減一部分作為新棋盤,當然,他希望這個棋盤儘可能的大。
不過小Q還沒有決定是找一個正方形的棋盤還是一個矩形的棋盤(當然,不管哪種,棋盤必須都黑白相間,即相鄰的格子不同色),所以他希望可以找到最大的正方形棋盤面積和最大的矩形棋盤面積,從而決定哪個更好一些。
於是小Q找到了即將參加全國資訊學競賽的你,你能幫助他麼?
輸入輸出格式
輸入格式:
包含兩個整數 N N N 和 M M M,分別表示矩形紙片的長和寬。接下來的 N N N 行包含一個 N × M N \times M N×M 的 01 01 01 矩陣,表示這張矩形紙片的顏色( 0 0 0 表示白色, 1 1 1 表示黑色)。
輸出格式:
包含兩行,每行包含一個整數。第一行為可以找到的最大正方形棋盤的面積,第二行為可以找到的最大矩形棋盤的面積(注意正方形和矩形是可以相交或者包含的)。
輸入輸出樣例
輸入樣例
3 3
1 0 1
0 1 0
1 0 0
輸出樣例
4
6
說明
對於
20
%
20\%
20% 的資料,
N
,
M
≤
80
N,M≤80
N,M≤80
對於
40
%
40\%
40% 的資料,
N
,
M
≤
400
N, M ≤ 400
N,M≤400
對於
100
%
100\%
100% 的資料,
N
,
M
≤
2000
N, M ≤ 2000
N,M≤2000
思路
標準懸線法,詳見上一篇部落格【學習筆記】最大子矩形問題
程式碼
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <iostream>
#include <cmath>
#define re register long long
#define rep(i,a,b) for(re i=a;i<=b;++i)
#define drep(i,a,b) for(re i=a;i>=b;--i)
typedef long long ll;
using namespace std;
inline ll read(){
ll x=0;bool f=0;char ch=getchar();
while(!isdigit(ch)) f^=!(ch^'-'),ch=getchar();
while(isdigit(ch)) x=((x+(x<<2))<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
ll n,m,height[2050][2050],lft[2050][2050],rit[2050][2050],ansc=0,ansz=0;
bool a[2050][2050];
int main(){
n=read(),m=read();
rep(i,1,n) rep(j,1,m){
a[i][j]=read();
height[i][j]=1;//初始化高度值
if(i!=1 and a[i][j]!=a[i-1][j]) height[i][j]=height[i-1][j]+1;
if(j!=1 and a[i][j]!=a[i][j-1]) lft[i][j]=lft[i][j-1];//遞推找到左障礙點
else if(j!=1 and a[i][j]==a[i][j-1]) lft[i][j]=j-1;
}
rep(i,1,n) drep(j,m,1){
rit[i][j]=j;
if(j!=m and a[i][j]!=a[i][j+1]) rit[i][j]=rit[i][j+1];
else if(j!=m and a[i][j]==a[i][j+1]) rit[i][j]=j;
}
/*
rep(i,1,n){ rep(j,1,m){
printf("%lld ",rit[i][j]);
}
puts("");
}
*/
rep(i,1,n){ rep(j,1,m){
if(i!=1 and a[i][j]!=a[i-1][j]){
lft[i][j]=max(lft[i][j],lft[i-1][j]);//更新左邊界
rit[i][j]=min(rit[i][j],rit[i-1][j]);
}
// printf("%lld ",height[i][j]);
ansc=max(ansc,(rit[i][j]-lft[i][j])*height[i][j]);//長方形面積
ansz=max(ansz,min(rit[i][j]-lft[i][j],height[i][j]));//正方形邊長
}
// puts("");
}
printf("%lld\n%lld\n",ansz*ansz,ansc);
return 0;
}